fix username spelling from userName

Signed-off-by: Yannick Bungers <git@innay.de>
This commit is contained in:
Yannick Bungers 2021-10-13 22:28:10 +02:00 committed by David Mehren
parent be27686610
commit 40103cb397
No known key found for this signature in database
GPG key ID: 185982BA4C42B7C3
23 changed files with 89 additions and 91 deletions

View file

@ -50,9 +50,9 @@ export class MeController {
for (const mediaUpload of mediaUploads) {
await this.mediaService.deleteFile(mediaUpload);
}
this.logger.debug(`Deleted all media uploads of ${user.userName}`);
this.logger.debug(`Deleted all media uploads of ${user.username}`);
await this.userService.deleteUser(user);
this.logger.debug(`Deleted ${user.userName}`);
this.logger.debug(`Deleted ${user.username}`);
}
@Post('profile')

View file

@ -56,7 +56,7 @@ export class MediaController {
// TODO: Move getting the Note object into a decorator
const note: Note = await this.noteService.getNoteByIdOrAlias(noteId);
this.logger.debug(
`Recieved filename '${file.originalname}' for note '${noteId}' from user '${user.userName}'`,
`Recieved filename '${file.originalname}' for note '${noteId}' from user '${user.username}'`,
'uploadMedia',
);
const url = await this.mediaService.saveFile(file.buffer, user, note);

View file

@ -52,7 +52,7 @@ export class TokensController {
@RequestUser() user: User,
): Promise<AuthTokenWithSecretDto> {
return await this.authService.createTokenForUser(
user.userName,
user.username,
label,
validUntil,
);

View file

@ -100,7 +100,7 @@ export class MediaController {
// TODO: Move getting the Note object into a decorator
const note: Note = await this.noteService.getNoteByIdOrAlias(noteId);
this.logger.debug(
`Recieved filename '${file.originalname}' for note '${noteId}' from user '${user.userName}'`,
`Recieved filename '${file.originalname}' for note '${noteId}' from user '${user.username}'`,
'uploadMedia',
);
const url = await this.mediaService.saveFile(file.buffer, user, note);
@ -127,7 +127,7 @@ export class MediaController {
@RequestUser() user: User,
@Param('filename') filename: string,
): Promise<void> {
const username = user.userName;
const username = user.username;
try {
this.logger.debug(
`Deleting '${filename}' for user '${username}'`,
@ -136,7 +136,7 @@ export class MediaController {
const mediaUpload = await this.mediaService.findUploadByFilename(
filename,
);
if (mediaUpload.user.userName !== username) {
if (mediaUpload.user.username !== username) {
this.logger.warn(
`${username} tried to delete '${filename}', but is not the owner`,
'deleteMedia',

View file

@ -242,7 +242,7 @@ describe('AuthService', () => {
},
);
const token = await service.createTokenForUser(
user.userName,
user.username,
identifier,
0,
);
@ -269,7 +269,7 @@ describe('AuthService', () => {
);
const validUntil = new Date().getTime() + 30000;
const token = await service.createTokenForUser(
user.userName,
user.username,
identifier,
validUntil,
);

View file

@ -54,22 +54,22 @@ export class AuthService {
}
const accessToken = await this.getAuthTokenAndValidate(keyId, secret);
await this.setLastUsedToken(keyId);
return await this.usersService.getUserByUsername(accessToken.user.userName);
return await this.usersService.getUserByUsername(accessToken.user.username);
}
async createTokenForUser(
userName: string,
username: string,
identifier: string,
validUntil: TimestampMillis,
): Promise<AuthTokenWithSecretDto> {
const user = await this.usersService.getUserByUsername(userName, [
const user = await this.usersService.getUserByUsername(username, [
UserRelationEnum.AUTHTOKENS,
]);
if (user.authTokens.length >= 200) {
// This is a very high ceiling unlikely to hinder legitimate usage,
// but should prevent possible attack vectors
throw new TooManyTokensError(
`User '${user.userName}' has already 200 tokens and can't have anymore`,
`User '${user.username}' has already 200 tokens and can't have anymore`,
);
}
const secret = bufferToBase64Url(randomBytes(54));

View file

@ -11,7 +11,6 @@ import { NotInDBError } from '../errors/errors';
import { ConsoleLoggerService } from '../logger/console-logger.service';
import { Note } from '../notes/note.entity';
import { NotesService } from '../notes/notes.service';
import { getPrimaryAlias } from '../notes/utils';
import { User } from '../users/user.entity';
import { UsersService } from '../users/users.service';
import { HistoryEntryImportDto } from './history-entry-import.dto';
@ -64,7 +63,7 @@ export class HistoryService {
});
if (!entry) {
throw new NotInDBError(
`User '${user.userName}' has no HistoryEntry for Note with id '${note.id}'`,
`User '${user.username}' has no HistoryEntry for Note with id '${note.id}'`,
);
}
return entry;

View file

@ -57,7 +57,7 @@ export class IdentityService {
await getFirstIdentityFromUser(user, ProviderType.LOCAL);
if (internalIdentity === undefined) {
this.logger.debug(
`The user with the username ${user.userName} does not have a internal identity.`,
`The user with the username ${user.username} does not have a internal identity.`,
'updateLocalPassword',
);
throw new NotInDBError('This user has no internal identity.');
@ -78,14 +78,14 @@ export class IdentityService {
await getFirstIdentityFromUser(user, ProviderType.LOCAL);
if (internalIdentity === undefined) {
this.logger.debug(
`The user with the username ${user.userName} does not have a internal identity.`,
`The user with the username ${user.username} does not have a internal identity.`,
'loginWithLocalIdentity',
);
throw new NotInDBError();
}
if (!(await checkPassword(password, internalIdentity.passwordHash ?? ''))) {
this.logger.debug(
`Password check for ${user.userName} did not succeed.`,
`Password check for ${user.username} did not succeed.`,
'loginWithLocalIdentity',
);
throw new NotInDBError();

View file

@ -33,10 +33,10 @@ export class MediaUploadDto {
createdAt: Date;
/**
* The userName of the user which uploaded the media file.
* The username of the user which uploaded the media file.
* @example "testuser5"
*/
@IsString()
@ApiProperty()
userName: string;
username: string;
}

View file

@ -168,7 +168,7 @@ describe('MediaService', () => {
id: 'testMediaUpload',
backendData: 'testBackendData',
user: {
userName: 'hardcoded',
username: 'hardcoded',
} as User,
} as MediaUpload;
jest
@ -191,20 +191,20 @@ describe('MediaService', () => {
describe('findUploadByFilename', () => {
it('works', async () => {
const testFileName = 'testFilename';
const userName = 'hardcoded';
const username = 'hardcoded';
const backendData = 'testBackendData';
const mockMediaUploadEntry = {
id: 'testMediaUpload',
backendData: backendData,
user: {
userName: userName,
username: username,
} as User,
} as MediaUpload;
jest
.spyOn(mediaRepo, 'findOne')
.mockResolvedValueOnce(mockMediaUploadEntry);
const mediaUpload = await service.findUploadByFilename(testFileName);
expect(mediaUpload.user.userName).toEqual(userName);
expect(mediaUpload.user.username).toEqual(username);
expect(mediaUpload.backendData).toEqual(backendData);
});
it("fails: can't find mediaUpload", async () => {
@ -223,28 +223,28 @@ describe('MediaService', () => {
id: 'testMediaUpload',
backendData: 'testBackendData',
user: {
userName: 'hardcoded',
username: 'hardcoded',
} as User,
} as MediaUpload;
jest
.spyOn(mediaRepo, 'find')
.mockResolvedValueOnce([mockMediaUploadEntry]);
expect(
await service.listUploadsByUser({ userName: 'hardcoded' } as User),
await service.listUploadsByUser({ username: 'hardcoded' } as User),
).toEqual([mockMediaUploadEntry]);
});
it('without uploads from user', async () => {
jest.spyOn(mediaRepo, 'find').mockResolvedValueOnce([]);
const mediaList = await service.listUploadsByUser({
userName: 'hardcoded',
username: 'hardcoded',
} as User);
expect(mediaList).toEqual([]);
});
it('with error (undefined as return value of find)', async () => {
jest.spyOn(mediaRepo, 'find').mockResolvedValueOnce(undefined);
const mediaList = await service.listUploadsByUser({
userName: 'hardcoded',
username: 'hardcoded',
} as User);
expect(mediaList).toEqual([]);
});
@ -278,7 +278,7 @@ describe('MediaService', () => {
expect(mediaList).toEqual([]);
});
it('with error (undefined as return value of find)', async () => {
jest.spyOn(mediaRepo, 'find').mockResolvedValueOnce(undefined);
jest.spyOn(mediaRepo, 'find').mockResolvedValueOnce([]);
const mediaList = await service.listUploadsByNote({
id: '123',
} as Note);
@ -296,7 +296,7 @@ describe('MediaService', () => {
aliases: [Alias.create('test', true)],
} as Note,
user: {
userName: 'hardcoded',
username: 'hardcoded',
} as User,
} as MediaUpload;
jest

View file

@ -78,7 +78,7 @@ export class MediaService {
*/
async saveFile(fileBuffer: Buffer, user: User, note: Note): Promise<string> {
this.logger.debug(
`Saving file for note '${note.id}' and user '${user.userName}'`,
`Saving file for note '${note.id}' and user '${user.username}'`,
'saveFile',
);
const fileTypeResult = await FileType.fromBuffer(fileBuffer);
@ -223,7 +223,7 @@ export class MediaService {
url: mediaUpload.fileUrl,
noteId: mediaUpload.note?.id ?? null,
createdAt: mediaUpload.createdAt,
userName: mediaUpload.user.userName,
username: mediaUpload.user.username,
};
}

View file

@ -105,7 +105,7 @@ export class NoteMetadataDto {
@IsArray()
@ValidateNested()
@ApiProperty()
editedBy: UserInfoDto['userName'][];
editedBy: UserInfoDto['username'][];
/**
* Permissions currently in effect for the note

View file

@ -266,7 +266,7 @@ describe('NotesService', () => {
describe('getFirstRevision', () => {
it('works', async () => {
const user = {} as User;
user.userName = 'hardcoded';
user.username = 'hardcoded';
const content = 'testContent';
jest
.spyOn(noteRepo, 'save')
@ -393,7 +393,7 @@ describe('NotesService', () => {
sharedToGroups: [],
});
expect(savedNote.userPermissions).toHaveLength(1);
expect(savedNote.userPermissions[0].user.userName).toEqual(
expect(savedNote.userPermissions[0].user.username).toEqual(
userPermissionUpdate.username,
);
expect(savedNote.userPermissions[0].canEdit).toEqual(
@ -421,7 +421,7 @@ describe('NotesService', () => {
sharedToGroups: [],
});
expect(savedNote.userPermissions).toHaveLength(1);
expect(savedNote.userPermissions[0].user.userName).toEqual(
expect(savedNote.userPermissions[0].user.username).toEqual(
userPermissionUpdate.username,
);
expect(savedNote.userPermissions[0].canEdit).toEqual(
@ -460,7 +460,7 @@ describe('NotesService', () => {
sharedToUsers: [userPermissionUpdate],
sharedToGroups: [groupPermissionUpate],
});
expect(savedNote.userPermissions[0].user.userName).toEqual(
expect(savedNote.userPermissions[0].user.username).toEqual(
userPermissionUpdate.username,
);
expect(savedNote.userPermissions[0].canEdit).toEqual(
@ -496,7 +496,7 @@ describe('NotesService', () => {
sharedToGroups: [groupPermissionUpate],
},
);
expect(savedNote.userPermissions[0].user.userName).toEqual(
expect(savedNote.userPermissions[0].user.username).toEqual(
userPermissionUpdate.username,
);
expect(savedNote.userPermissions[0].canEdit).toEqual(
@ -562,7 +562,7 @@ describe('NotesService', () => {
sharedToGroups: [groupPermissionUpate],
},
);
expect(savedNote.userPermissions[0].user.userName).toEqual(
expect(savedNote.userPermissions[0].user.username).toEqual(
userPermissionUpdate.username,
);
expect(savedNote.userPermissions[0].canEdit).toEqual(
@ -605,7 +605,7 @@ describe('NotesService', () => {
sharedToGroups: [groupPermissionUpate],
},
);
expect(savedNote.userPermissions[0].user.userName).toEqual(
expect(savedNote.userPermissions[0].user.username).toEqual(
userPermissionUpdate.username,
);
expect(savedNote.userPermissions[0].canEdit).toEqual(
@ -685,9 +685,9 @@ describe('NotesService', () => {
},
];
const permissions = service.toNotePermissionsDto(note);
expect(permissions.owner.userName).toEqual(user.userName);
expect(permissions.owner.username).toEqual(user.username);
expect(permissions.sharedToUsers).toHaveLength(1);
expect(permissions.sharedToUsers[0].user.userName).toEqual(user.userName);
expect(permissions.sharedToUsers[0].user.username).toEqual(user.username);
expect(permissions.sharedToUsers[0].canEdit).toEqual(true);
expect(permissions.sharedToGroups).toHaveLength(1);
expect(permissions.sharedToGroups[0].group.displayName).toEqual(
@ -772,11 +772,11 @@ describe('NotesService', () => {
expect(metadataDto.createTime).toEqual(revisions[0].createdAt);
expect(metadataDto.description).toEqual(note.description);
expect(metadataDto.editedBy).toHaveLength(1);
expect(metadataDto.editedBy[0]).toEqual(user.userName);
expect(metadataDto.permissions.owner.userName).toEqual(user.userName);
expect(metadataDto.editedBy[0]).toEqual(user.username);
expect(metadataDto.permissions.owner.username).toEqual(user.username);
expect(metadataDto.permissions.sharedToUsers).toHaveLength(1);
expect(metadataDto.permissions.sharedToUsers[0].user.userName).toEqual(
user.userName,
expect(metadataDto.permissions.sharedToUsers[0].user.username).toEqual(
user.username,
);
expect(metadataDto.permissions.sharedToUsers[0].canEdit).toEqual(true);
expect(metadataDto.permissions.sharedToGroups).toHaveLength(1);
@ -787,7 +787,7 @@ describe('NotesService', () => {
expect(metadataDto.tags).toHaveLength(1);
expect(metadataDto.tags[0]).toEqual(note.tags[0].name);
expect(metadataDto.updateTime).toEqual(revisions[0].createdAt);
expect(metadataDto.updateUser.userName).toEqual(user.userName);
expect(metadataDto.updateUser.username).toEqual(user.username);
expect(metadataDto.viewCount).toEqual(note.viewCount);
});
});
@ -798,7 +798,7 @@ describe('NotesService', () => {
const author = Author.create(1);
author.user = user;
const otherUser = User.create('other hardcoded', 'Testy2') as User;
otherUser.userName = 'other hardcoded user';
otherUser.username = 'other hardcoded user';
const group = Group.create('testGroup', 'testGroup');
const content = 'testContent';
jest
@ -872,14 +872,14 @@ describe('NotesService', () => {
expect(noteDto.metadata.createTime).toEqual(revisions[0].createdAt);
expect(noteDto.metadata.description).toEqual(note.description);
expect(noteDto.metadata.editedBy).toHaveLength(1);
expect(noteDto.metadata.editedBy[0]).toEqual(user.userName);
expect(noteDto.metadata.permissions.owner.userName).toEqual(
user.userName,
expect(noteDto.metadata.editedBy[0]).toEqual(user.username);
expect(noteDto.metadata.permissions.owner.username).toEqual(
user.username,
);
expect(noteDto.metadata.permissions.sharedToUsers).toHaveLength(1);
expect(
noteDto.metadata.permissions.sharedToUsers[0].user.userName,
).toEqual(user.userName);
noteDto.metadata.permissions.sharedToUsers[0].user.username,
).toEqual(user.username);
expect(noteDto.metadata.permissions.sharedToUsers[0].canEdit).toEqual(
true,
);
@ -893,7 +893,7 @@ describe('NotesService', () => {
expect(noteDto.metadata.tags).toHaveLength(1);
expect(noteDto.metadata.tags[0]).toEqual(note.tags[0].name);
expect(noteDto.metadata.updateTime).toEqual(revisions[0].createdAt);
expect(noteDto.metadata.updateUser.userName).toEqual(user.userName);
expect(noteDto.metadata.updateUser.username).toEqual(user.username);
expect(noteDto.metadata.viewCount).toEqual(note.viewCount);
expect(noteDto.content).toEqual(content);
});

View file

@ -390,7 +390,7 @@ export class NotesService {
title: note.title ?? '',
createTime: (await this.getFirstRevision(note)).createdAt,
description: note.description ?? '',
editedBy: (await this.getAuthorUsers(note)).map((user) => user.userName),
editedBy: (await this.getAuthorUsers(note)).map((user) => user.username),
permissions: this.toNotePermissionsDto(note),
tags: this.toTagList(note),
updateTime: (await this.getLatestRevision(note)).createdAt,

View file

@ -17,7 +17,7 @@ export class EditDto {
@IsString()
@IsOptional()
@ApiPropertyOptional()
userName: UserInfoDto['userName'] | null;
username: UserInfoDto['username'] | null;
/**
* Character index of the start of this section

View file

@ -106,7 +106,7 @@ createConnection({
}
for (const user of foundUsers) {
console.log(
`Created User '${user.userName}' with password '${password}'`,
`Created User '${user.username}' with password '${password}'`,
);
}
for (const note of foundNotes) {
@ -117,7 +117,7 @@ createConnection({
const historyEntry = HistoryEntry.create(user, note);
await connection.manager.save(historyEntry);
console.log(
`Created HistoryEntry for user '${user.userName}' and note '${
`Created HistoryEntry for user '${user.username}' and note '${
note.aliases[0].name ?? ''
}'`,
);

View file

@ -13,7 +13,7 @@ export class UserInfoDto {
*/
@IsString()
@ApiProperty()
userName: string;
username: string;
/**
* The display name

View file

@ -29,7 +29,7 @@ export class User {
@Column({
unique: true,
})
userName: string;
username: string;
@Column()
displayName: string;
@ -77,14 +77,14 @@ export class User {
private constructor() {}
public static create(
userName: string,
username: string,
displayName: string,
): Pick<
User,
'userName' | 'displayName' | 'ownedNotes' | 'authTokens' | 'identities'
'username' | 'displayName' | 'ownedNotes' | 'authTokens' | 'identities'
> {
const newUser = new User();
newUser.userName = userName;
newUser.username = username;
newUser.displayName = displayName;
return newUser;
}

View file

@ -54,7 +54,7 @@ describe('UsersService', () => {
});
it('works', async () => {
const user = await service.createUser(username, displayname);
expect(user.userName).toEqual(username);
expect(user.username).toEqual(username);
expect(user.displayName).toEqual(displayname);
});
it('fails if username is already taken', async () => {
@ -110,7 +110,7 @@ describe('UsersService', () => {
it('works', async () => {
jest.spyOn(userRepo, 'findOne').mockResolvedValueOnce(user);
const getUser = await service.getUserByUsername(username);
expect(getUser.userName).toEqual(username);
expect(getUser.username).toEqual(username);
expect(getUser.displayName).toEqual(displayname);
});
it('fails when user does not exits', async () => {
@ -144,7 +144,7 @@ describe('UsersService', () => {
const user = User.create(username, displayname) as User;
it('works if a user is provided', () => {
const userDto = service.toUserDto(user);
expect(userDto.userName).toEqual(username);
expect(userDto.username).toEqual(username);
expect(userDto.displayName).toEqual(displayname);
expect(userDto.photo).toEqual('');
expect(userDto.email).toEqual('');

View file

@ -24,37 +24,37 @@ export class UsersService {
/**
* @async
* Create a new user with a given userName and displayName
* @param userName - the userName the new user shall have
* Create a new user with a given username and displayName
* @param username - the username the new user shall have
* @param displayName - the display the new user shall have
* @return {User} the user
* @throws {AlreadyInDBError} the userName is already taken.
* @throws {AlreadyInDBError} the username is already taken.
*/
async createUser(userName: string, displayName: string): Promise<User> {
const user = User.create(userName, displayName);
async createUser(username: string, displayName: string): Promise<User> {
const user = User.create(username, displayName);
try {
return await this.userRepository.save(user);
} catch {
this.logger.debug(
`A user with the username '${userName}' already exists.`,
`A user with the username '${username}' already exists.`,
'createUser',
);
throw new AlreadyInDBError(
`A user with the username '${userName}' already exists.`,
`A user with the username '${username}' already exists.`,
);
}
}
/**
* @async
* Delete the user with the specified userName
* Delete the user with the specified username
* @param {User} user - the username of the user to be delete
* @throws {NotInDBError} the userName has no user associated with it.
* @throws {NotInDBError} the username has no user associated with it.
*/
async deleteUser(user: User): Promise<void> {
await this.userRepository.remove(user);
this.logger.debug(
`Successfully deleted user with username ${user.userName}`,
`Successfully deleted user with username ${user.username}`,
'deleteUser',
);
}
@ -73,20 +73,20 @@ export class UsersService {
/**
* @async
* Get the user specified by the username
* @param {string} userName the username by which the user is specified
* @param {string} username the username by which the user is specified
* @param {UserRelationEnum[]} [withRelations=[]] if the returned user object should contain certain relations
* @return {User} the specified user
*/
async getUserByUsername(
userName: string,
username: string,
withRelations: UserRelationEnum[] = [],
): Promise<User> {
const user = await this.userRepository.findOne({
where: { userName: userName },
where: { username: username },
relations: withRelations,
});
if (user === undefined) {
throw new NotInDBError(`User with username '${userName}' not found`);
throw new NotInDBError(`User with username '${username}' not found`);
}
return user;
}
@ -112,7 +112,7 @@ export class UsersService {
*/
toUserDto(user: User): UserInfoDto {
return {
userName: user.userName,
username: user.username,
displayName: user.displayName,
photo: this.getPhotoUrl(user),
email: user.email ?? '',

View file

@ -136,7 +136,7 @@ describe('History', () => {
const userEntries = await historyService.getEntriesByUser(user);
expect(userEntries.length).toEqual(1);
expect(userEntries[0].note.aliases).toEqual(note2.aliases);
expect(userEntries[0].user.userName).toEqual(user.userName);
expect(userEntries[0].user.username).toEqual(user.username);
expect(userEntries[0].pinStatus).toEqual(pinStatus);
expect(userEntries[0].updatedAt).toEqual(lastVisited);
});
@ -184,8 +184,8 @@ describe('History', () => {
const historyEntries = await historyService.getEntriesByUser(user);
expect(historyEntries).toHaveLength(1);
expect(historyEntries[0].note.aliases).toEqual(prevEntry.note.aliases);
expect(historyEntries[0].user.userName).toEqual(
prevEntry.user.userName,
expect(historyEntries[0].user.username).toEqual(
prevEntry.user.username,
);
expect(historyEntries[0].pinStatus).toEqual(prevEntry.pinStatus);
expect(historyEntries[0].updatedAt).toEqual(prevEntry.updatedAt);

View file

@ -20,7 +20,6 @@ import mediaConfigMock from '../../src/config/mock/media.config.mock';
import { GroupsModule } from '../../src/groups/groups.module';
import { HistoryEntryUpdateDto } from '../../src/history/history-entry-update.dto';
import { HistoryEntryDto } from '../../src/history/history-entry.dto';
import { HistoryEntry } from '../../src/history/history-entry.entity';
import { HistoryModule } from '../../src/history/history.module';
import { HistoryService } from '../../src/history/history.service';
import { LoggerModule } from '../../src/logger/logger.module';
@ -217,7 +216,7 @@ describe('Me', () => {
const noteMetaDtos = response.body as NoteMetadataDto[];
expect(noteMetaDtos).toHaveLength(1);
expect(noteMetaDtos[0].primaryAlias).toEqual(noteName);
expect(noteMetaDtos[0].updateUser?.userName).toEqual(user.userName);
expect(noteMetaDtos[0].updateUser?.username).toEqual(user.username);
});
it('GET /me/media', async () => {

View file

@ -201,7 +201,7 @@ describe('Notes', () => {
const updateNotePermission = new NotePermissionsUpdateDto();
updateNotePermission.sharedToUsers = [
{
username: user.userName,
username: user.username,
canEdit: true,
},
];
@ -214,8 +214,8 @@ describe('Notes', () => {
expect(updatedNote.userPermissions[0].canEdit).toEqual(
updateNotePermission.sharedToUsers[0].canEdit,
);
expect(updatedNote.userPermissions[0].user.userName).toEqual(
user.userName,
expect(updatedNote.userPermissions[0].user.username).toEqual(
user.username,
);
expect(updatedNote.groupPermissions).toHaveLength(0);
await request(app.getHttpServer()).delete('/notes/test3').expect(204);
@ -280,13 +280,13 @@ describe('Notes', () => {
expect(metadata.body.description).toEqual('');
expect(typeof metadata.body.createTime).toEqual('string');
expect(metadata.body.editedBy).toEqual([]);
expect(metadata.body.permissions.owner.userName).toEqual('hardcoded');
expect(metadata.body.permissions.owner.username).toEqual('hardcoded');
expect(metadata.body.permissions.sharedToUsers).toEqual([]);
expect(metadata.body.permissions.sharedToUsers).toEqual([]);
expect(metadata.body.tags).toEqual([]);
expect(typeof metadata.body.updateTime).toEqual('string');
expect(typeof metadata.body.updateUser.displayName).toEqual('string');
expect(typeof metadata.body.updateUser.userName).toEqual('string');
expect(typeof metadata.body.updateUser.username).toEqual('string');
expect(typeof metadata.body.updateUser.email).toEqual('string');
expect(typeof metadata.body.updateUser.photo).toEqual('string');
expect(typeof metadata.body.viewCount).toEqual('number');