refactor(note): lazy-load relations

Signed-off-by: David Mehren <git@herrmehren.de>
This commit is contained in:
David Mehren 2021-11-30 16:46:07 +01:00
parent d761ff7f4f
commit 235e4f647c
No known key found for this signature in database
GPG key ID: 185982BA4C42B7C3
23 changed files with 343 additions and 284 deletions

View file

@ -56,7 +56,7 @@ export class AliasController {
const note = await this.noteService.getNoteByIdOrAlias(
newAliasDto.noteIdOrAlias,
);
if (!this.permissionsService.isOwner(user, note)) {
if (!(await this.permissionsService.isOwner(user, note))) {
throw new UnauthorizedException('Reading note denied!');
}
const updatedAlias = await this.aliasService.addAlias(
@ -88,7 +88,7 @@ export class AliasController {
}
try {
const note = await this.noteService.getNoteByIdOrAlias(alias);
if (!this.permissionsService.isOwner(user, note)) {
if (!(await this.permissionsService.isOwner(user, note))) {
throw new UnauthorizedException('Reading note denied!');
}
const updatedAlias = await this.aliasService.makeAliasPrimary(
@ -115,7 +115,7 @@ export class AliasController {
): Promise<void> {
try {
const note = await this.noteService.getNoteByIdOrAlias(alias);
if (!this.permissionsService.isOwner(user, note)) {
if (!(await this.permissionsService.isOwner(user, note))) {
throw new UnauthorizedException('Reading note denied!');
}
await this.aliasService.removeAlias(note, alias);

View file

@ -45,8 +45,10 @@ export class HistoryController {
async getHistory(@RequestUser() user: User): Promise<HistoryEntryDto[]> {
try {
const foundEntries = await this.historyService.getEntriesByUser(user);
return foundEntries.map((entry) =>
this.historyService.toHistoryEntryDto(entry),
return await Promise.all(
foundEntries.map((entry) =>
this.historyService.toHistoryEntryDto(entry),
),
);
} catch (e) {
if (e instanceof NotInDBError) {
@ -96,7 +98,7 @@ export class HistoryController {
user,
entryUpdateDto,
);
return this.historyService.toHistoryEntryDto(newEntry);
return await this.historyService.toHistoryEntryDto(newEntry);
} catch (e) {
if (e instanceof NotInDBError) {
throw new NotFoundException(e.message);

View file

@ -69,7 +69,7 @@ export class AliasController {
const note = await this.noteService.getNoteByIdOrAlias(
newAliasDto.noteIdOrAlias,
);
if (!this.permissionsService.isOwner(user, note)) {
if (!(await this.permissionsService.isOwner(user, note))) {
throw new UnauthorizedException('Reading note denied!');
}
const updatedAlias = await this.aliasService.addAlias(
@ -107,7 +107,7 @@ export class AliasController {
}
try {
const note = await this.noteService.getNoteByIdOrAlias(alias);
if (!this.permissionsService.isOwner(user, note)) {
if (!(await this.permissionsService.isOwner(user, note))) {
throw new UnauthorizedException('Reading note denied!');
}
const updatedAlias = await this.aliasService.makeAliasPrimary(
@ -139,7 +139,7 @@ export class AliasController {
): Promise<void> {
try {
const note = await this.noteService.getNoteByIdOrAlias(alias);
if (!this.permissionsService.isOwner(user, note)) {
if (!(await this.permissionsService.isOwner(user, note))) {
throw new UnauthorizedException('Reading note denied!');
}
await this.aliasService.removeAlias(note, alias);

View file

@ -101,7 +101,7 @@ export class MeController {
): Promise<HistoryEntryDto> {
try {
const foundEntry = await this.historyService.getEntryByNote(note, user);
return this.historyService.toHistoryEntryDto(foundEntry);
return await this.historyService.toHistoryEntryDto(foundEntry);
} catch (e) {
if (e instanceof NotInDBError) {
throw new NotFoundException(e.message);
@ -126,7 +126,7 @@ export class MeController {
): Promise<HistoryEntryDto> {
// ToDo: Check if user is allowed to pin this history entry
try {
return this.historyService.toHistoryEntryDto(
return await this.historyService.toHistoryEntryDto(
await this.historyService.updateHistoryEntry(
note,
user,

View file

@ -16,7 +16,7 @@ import {
Post,
Put,
UseGuards,
UseInterceptors
UseInterceptors,
} from '@nestjs/common';
import {
ApiCreatedResponse,
@ -26,17 +26,24 @@ import {
ApiProduces,
ApiSecurity,
ApiTags,
ApiUnauthorizedResponse
ApiUnauthorizedResponse,
} from '@nestjs/swagger';
import { TokenAuthGuard } from '../../../auth/token.strategy';
import { AlreadyInDBError, ForbiddenIdError, NotInDBError } from '../../../errors/errors';
import {
AlreadyInDBError,
ForbiddenIdError,
NotInDBError,
} from '../../../errors/errors';
import { HistoryService } from '../../../history/history.service';
import { ConsoleLoggerService } from '../../../logger/console-logger.service';
import { MediaUploadDto } from '../../../media/media-upload.dto';
import { MediaService } from '../../../media/media.service';
import { NoteMetadataDto } from '../../../notes/note-metadata.dto';
import { NotePermissionsDto, NotePermissionsUpdateDto } from '../../../notes/note-permissions.dto';
import {
NotePermissionsDto,
NotePermissionsUpdateDto,
} from '../../../notes/note-permissions.dto';
import { NoteDto } from '../../../notes/note.dto';
import { Note } from '../../../notes/note.entity';
import { NoteMediaDeletionDto } from '../../../notes/note.media-deletion.dto';
@ -50,7 +57,7 @@ import { User } from '../../../users/user.entity';
import {
forbiddenDescription,
successfullyDeletedDescription,
unauthorizedDescription
unauthorizedDescription,
} from '../../utils/descriptions';
import { FullApi } from '../../utils/fullapi-decorator';
import { GetNoteInterceptor } from '../../utils/get-note.interceptor';
@ -230,7 +237,7 @@ export class NotesController {
@RequestNote() note: Note,
@Body() updateDto: NotePermissionsUpdateDto,
): Promise<NotePermissionsDto> {
return this.noteService.toNotePermissionsDto(
return await this.noteService.toNotePermissionsDto(
await this.noteService.updateNotePermissions(note, updateDto),
);
}

View file

@ -159,9 +159,9 @@ describe('HistoryService', () => {
Note.create(user, alias) as Note,
user,
);
expect(createHistoryEntry.note.aliases).toHaveLength(1);
expect(createHistoryEntry.note.aliases[0].name).toEqual(alias);
expect(createHistoryEntry.note.owner).toEqual(user);
expect(await createHistoryEntry.note.aliases).toHaveLength(1);
expect((await createHistoryEntry.note.aliases)[0].name).toEqual(alias);
expect(await createHistoryEntry.note.owner).toEqual(user);
expect(createHistoryEntry.user).toEqual(user);
expect(createHistoryEntry.pinStatus).toEqual(false);
});
@ -177,9 +177,9 @@ describe('HistoryService', () => {
Note.create(user, alias) as Note,
user,
);
expect(createHistoryEntry.note.aliases).toHaveLength(1);
expect(createHistoryEntry.note.aliases[0].name).toEqual(alias);
expect(createHistoryEntry.note.owner).toEqual(user);
expect(await createHistoryEntry.note.aliases).toHaveLength(1);
expect((await createHistoryEntry.note.aliases)[0].name).toEqual(alias);
expect(await createHistoryEntry.note.owner).toEqual(user);
expect(createHistoryEntry.user).toEqual(user);
expect(createHistoryEntry.pinStatus).toEqual(false);
expect(createHistoryEntry.updatedAt.getTime()).toBeGreaterThanOrEqual(
@ -223,9 +223,9 @@ describe('HistoryService', () => {
pinStatus: true,
},
);
expect(updatedHistoryEntry.note.aliases).toHaveLength(1);
expect(updatedHistoryEntry.note.aliases[0].name).toEqual(alias);
expect(updatedHistoryEntry.note.owner).toEqual(user);
expect(await updatedHistoryEntry.note.aliases).toHaveLength(1);
expect((await updatedHistoryEntry.note.aliases)[0].name).toEqual(alias);
expect(await updatedHistoryEntry.note.owner).toEqual(user);
expect(updatedHistoryEntry.user).toEqual(user);
expect(updatedHistoryEntry.pinStatus).toEqual(true);
});
@ -371,11 +371,13 @@ describe('HistoryService', () => {
const mockedManager = {
find: jest.fn().mockResolvedValueOnce([historyEntry]),
createQueryBuilder: () => createQueryBuilder,
remove: jest.fn().mockImplementationOnce((entry: HistoryEntry) => {
expect(entry.note.aliases).toHaveLength(1);
expect(entry.note.aliases[0].name).toEqual(alias);
expect(entry.pinStatus).toEqual(false);
}),
remove: jest
.fn()
.mockImplementationOnce(async (entry: HistoryEntry) => {
expect(await entry.note.aliases).toHaveLength(1);
expect((await entry.note.aliases)[0].name).toEqual(alias);
expect(entry.pinStatus).toEqual(false);
}),
save: jest.fn().mockImplementationOnce((entry: HistoryEntry) => {
expect(entry.note.aliases).toEqual(
newlyCreatedHistoryEntry.note.aliases,
@ -402,11 +404,13 @@ describe('HistoryService', () => {
const tags = ['tag1', 'tag2'];
const note = Note.create(user, alias) as Note;
note.title = title;
note.tags = tags.map((tag) => {
const newTag = new Tag();
newTag.name = tag;
return newTag;
});
note.tags = Promise.resolve(
tags.map((tag) => {
const newTag = new Tag();
newTag.name = tag;
return newTag;
}),
);
const historyEntry = HistoryEntry.create(user, note) as HistoryEntry;
historyEntry.pinStatus = true;
const createQueryBuilder = {
@ -420,7 +424,7 @@ describe('HistoryService', () => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
.mockImplementation(() => createQueryBuilder);
const historyEntryDto = service.toHistoryEntryDto(historyEntry);
const historyEntryDto = await service.toHistoryEntryDto(historyEntry);
expect(historyEntryDto.pinStatus).toEqual(true);
expect(historyEntryDto.identifier).toEqual(alias);
expect(historyEntryDto.tags).toEqual(tags);

View file

@ -186,11 +186,11 @@ export class HistoryService {
* @param {HistoryEntry} entry - the history entry to use
* @return {HistoryEntryDto} the built HistoryEntryDto
*/
toHistoryEntryDto(entry: HistoryEntry): HistoryEntryDto {
async toHistoryEntryDto(entry: HistoryEntry): Promise<HistoryEntryDto> {
return {
identifier: getIdentifier(entry),
identifier: await getIdentifier(entry),
lastVisited: entry.updatedAt,
tags: this.notesService.toTagList(entry.note),
tags: await this.notesService.toTagList(entry.note),
title: entry.note.title ?? '',
pinStatus: entry.pinStatus,
};

View file

@ -18,19 +18,19 @@ describe('getIdentifier', () => {
note = Note.create(user, alias) as Note;
entry = HistoryEntry.create(user, note) as HistoryEntry;
});
it('returns the publicId if there are no aliases', () => {
note.aliases = undefined as unknown as Alias[];
expect(getIdentifier(entry)).toEqual(note.publicId);
it('returns the publicId if there are no aliases', async () => {
note.aliases = Promise.resolve(undefined as unknown as Alias[]);
expect(await getIdentifier(entry)).toEqual(note.publicId);
});
it('returns the publicId, if the alias array is empty', () => {
note.aliases = [];
expect(getIdentifier(entry)).toEqual(note.publicId);
it('returns the publicId, if the alias array is empty', async () => {
note.aliases = Promise.resolve([]);
expect(await getIdentifier(entry)).toEqual(note.publicId);
});
it('returns the publicId, if the only alias is not primary', () => {
note.aliases[0].primary = false;
expect(getIdentifier(entry)).toEqual(note.publicId);
it('returns the publicId, if the only alias is not primary', async () => {
(await note.aliases)[0].primary = false;
expect(await getIdentifier(entry)).toEqual(note.publicId);
});
it('returns the primary alias, if one exists', () => {
expect(getIdentifier(entry)).toEqual(note.aliases[0].name);
it('returns the primary alias, if one exists', async () => {
expect(await getIdentifier(entry)).toEqual((await note.aliases)[0].name);
});
});

View file

@ -6,11 +6,12 @@
import { getPrimaryAlias } from '../notes/utils';
import { HistoryEntry } from './history-entry.entity';
export function getIdentifier(entry: HistoryEntry): string {
if (!entry.note.aliases || entry.note.aliases.length === 0) {
export async function getIdentifier(entry: HistoryEntry): Promise<string> {
const aliases = await entry.note.aliases;
if (!aliases || aliases.length === 0) {
return entry.note.publicId;
}
const primaryAlias = getPrimaryAlias(entry.note);
const primaryAlias = await getPrimaryAlias(entry.note);
if (primaryAlias === undefined) {
return entry.note.publicId;
}

View file

@ -291,7 +291,9 @@ describe('MediaService', () => {
describe('removeNoteFromMediaUpload', () => {
it('works', async () => {
const mockNote = {} as Note;
mockNote.aliases = [Alias.create('test', mockNote, true) as Alias];
mockNote.aliases = Promise.resolve([
Alias.create('test', mockNote, true) as Alias,
]);
const mockMediaUploadEntry = {
id: 'testMediaUpload',
backendData: 'testBackendData',

View file

@ -158,8 +158,11 @@ describe('AliasService', () => {
const alias2 = 'testAlias2';
const user = User.create('hardcoded', 'Testy') as User;
describe('removes one alias correctly', () => {
const note = Note.create(user, alias) as Note;
note.aliases.push(Alias.create(alias2, note, false) as Alias);
let note: Note;
beforeAll(async () => {
note = Note.create(user, alias) as Note;
(await note.aliases).push(Alias.create(alias2, note, false) as Alias);
});
it('with two aliases', async () => {
jest
.spyOn(noteRepo, 'save')
@ -170,9 +173,10 @@ describe('AliasService', () => {
async (alias: Alias): Promise<Alias> => alias,
);
const savedNote = await service.removeAlias(note, alias2);
expect(savedNote.aliases).toHaveLength(1);
expect(savedNote.aliases[0].name).toEqual(alias);
expect(savedNote.aliases[0].primary).toBeTruthy();
const aliases = await savedNote.aliases;
expect(aliases).toHaveLength(1);
expect(aliases[0].name).toEqual(alias);
expect(aliases[0].primary).toBeTruthy();
});
it('with one alias, that is primary', async () => {
jest
@ -184,12 +188,15 @@ describe('AliasService', () => {
async (alias: Alias): Promise<Alias> => alias,
);
const savedNote = await service.removeAlias(note, alias);
expect(savedNote.aliases).toHaveLength(0);
expect(await savedNote.aliases).toHaveLength(0);
});
});
describe('does not remove one alias', () => {
const note = Note.create(user, alias) as Note;
note.aliases.push(Alias.create(alias2, note, false) as Alias);
let note: Note;
beforeEach(async () => {
note = Note.create(user, alias) as Note;
(await note.aliases).push(Alias.create(alias2, note, false) as Alias);
});
it('if the alias is unknown', async () => {
await expect(service.removeAlias(note, 'non existent')).rejects.toThrow(
NotInDBError,
@ -206,10 +213,18 @@ describe('AliasService', () => {
describe('makeAliasPrimary', () => {
const user = User.create('hardcoded', 'Testy') as User;
const aliasName = 'testAlias';
const note = Note.create(user, aliasName) as Note;
const alias = Alias.create(aliasName, note, true) as Alias;
const alias2 = Alias.create('testAlias2', note, false) as Alias;
note.aliases.push(alias2);
let note: Note;
let alias: Alias;
let alias2: Alias;
beforeEach(async () => {
note = Note.create(user, aliasName) as Note;
alias = Alias.create(aliasName, note, true) as Alias;
alias2 = Alias.create('testAlias2', note, false) as Alias;
(await note.aliases).push(
Alias.create('testAlias2', note, false) as Alias,
);
});
it('mark the alias as primary', async () => {
jest
.spyOn(aliasRepo, 'findOne')
@ -224,10 +239,10 @@ describe('AliasService', () => {
where: () => createQueryBuilder,
orWhere: () => createQueryBuilder,
setParameter: () => createQueryBuilder,
getOne: () => {
getOne: async () => {
return {
...note,
aliases: note.aliases.map((anAlias) => {
aliases: (await note.aliases).map((anAlias) => {
if (anAlias.primary) {
anAlias.primary = false;
}

View file

@ -62,13 +62,13 @@ export class AliasService {
);
}
let newAlias;
if (note.aliases.length === 0) {
if ((await note.aliases).length === 0) {
// the first alias is automatically made the primary alias
newAlias = Alias.create(alias, note, true);
} else {
newAlias = Alias.create(alias, note, false);
}
note.aliases.push(newAlias as Alias);
(await note.aliases).push(newAlias as Alias);
await this.noteRepository.save(note);
return newAlias as Alias;
@ -87,7 +87,7 @@ export class AliasService {
let oldPrimaryId = '';
let newPrimaryId = '';
for (const anAlias of note.aliases) {
for (const anAlias of await note.aliases) {
// found old primary
if (anAlias.primary) {
oldPrimaryId = anAlias.id;
@ -134,9 +134,9 @@ export class AliasService {
* @throws {PrimaryAliasDeletionForbiddenError} the primary alias can only be deleted if it's the only alias
*/
async removeAlias(note: Note, alias: string): Promise<Note> {
const primaryAlias = getPrimaryAlias(note);
const primaryAlias = await getPrimaryAlias(note);
if (primaryAlias === alias && note.aliases.length !== 1) {
if (primaryAlias === alias && (await note.aliases).length !== 1) {
this.logger.debug(
`The alias '${alias}' is the primary alias, which can only be removed if it's the only alias.`,
'removeAlias',
@ -146,10 +146,10 @@ export class AliasService {
);
}
const filteredAliases = note.aliases.filter(
const filteredAliases = (await note.aliases).filter(
(anAlias) => anAlias.name !== alias,
);
if (note.aliases.length === filteredAliases.length) {
if ((await note.aliases).length === filteredAliases.length) {
this.logger.debug(
`The alias '${alias}' is not used by this note or is the primary alias, which can't be removed.`,
'removeAlias',
@ -158,13 +158,13 @@ export class AliasService {
`The alias '${alias}' is not used by this note or is the primary alias, which can't be removed.`,
);
}
const aliasToDelete = note.aliases.find(
const aliasToDelete = (await note.aliases).find(
(anAlias) => anAlias.name === alias,
);
if (aliasToDelete !== undefined) {
await this.aliasRepository.remove(aliasToDelete);
}
note.aliases = filteredAliases;
note.aliases = Promise.resolve(filteredAliases);
return await this.noteRepository.save(note);
}

View file

@ -36,21 +36,21 @@ export class Note {
(alias) => alias.note,
{ cascade: true }, // This ensures that embedded Aliases are automatically saved to the database
)
aliases: Alias[];
aliases: Promise<Alias[]>;
@OneToMany(
(_) => NoteGroupPermission,
(groupPermission) => groupPermission.note,
{ cascade: true }, // This ensures that embedded NoteGroupPermissions are automatically saved to the database
)
groupPermissions: NoteGroupPermission[];
groupPermissions: Promise<NoteGroupPermission[]>;
@OneToMany(
(_) => NoteUserPermission,
(userPermission) => userPermission.note,
{ cascade: true }, // This ensures that embedded NoteUserPermission are automatically saved to the database
)
userPermissions: NoteUserPermission[];
userPermissions: Promise<NoteUserPermission[]>;
@Column({
nullable: false,
@ -62,16 +62,16 @@ export class Note {
onDelete: 'CASCADE', // This deletes the Note, when the associated User is deleted
nullable: true,
})
owner: User | null;
owner: Promise<User | null>;
@OneToMany((_) => Revision, (revision) => revision.note, { cascade: true })
revisions: Promise<Revision[]>;
@OneToMany((_) => HistoryEntry, (historyEntry) => historyEntry.user)
historyEntries: HistoryEntry[];
historyEntries: Promise<HistoryEntry[]>;
@OneToMany((_) => MediaUpload, (mediaUpload) => mediaUpload.note)
mediaUploads: MediaUpload[];
mediaUploads: Promise<MediaUpload[]>;
@Column({
nullable: true,
@ -87,7 +87,7 @@ export class Note {
@ManyToMany((_) => Tag, (tag) => tag.notes, { eager: true, cascade: true })
@JoinTable()
tags: Tag[];
tags: Promise<Tag[]>;
// eslint-disable-next-line @typescript-eslint/no-empty-function
private constructor() {}
@ -101,18 +101,18 @@ export class Note {
const newNote = new Note();
newNote.publicId = generatePublicId();
newNote.aliases = alias
? [Alias.create(alias, newNote, true) as Alias]
: [];
newNote.userPermissions = [];
newNote.groupPermissions = [];
? Promise.resolve([Alias.create(alias, newNote, true) as Alias])
: Promise.resolve([]);
newNote.userPermissions = Promise.resolve([]);
newNote.groupPermissions = Promise.resolve([]);
newNote.viewCount = 0;
newNote.owner = owner;
newNote.owner = Promise.resolve(owner);
newNote.revisions = Promise.resolve([]);
newNote.historyEntries = [];
newNote.mediaUploads = [];
newNote.historyEntries = Promise.resolve([]);
newNote.mediaUploads = Promise.resolve([]);
newNote.description = null;
newNote.title = null;
newNote.tags = [];
newNote.tags = Promise.resolve([]);
return newNote;
}
}

View file

@ -168,51 +168,51 @@ describe('NotesService', () => {
const revisions = await newNote.revisions;
expect(revisions).toHaveLength(1);
expect(revisions[0].content).toEqual(content);
expect(newNote.historyEntries).toHaveLength(0);
expect(newNote.userPermissions).toHaveLength(0);
expect(newNote.groupPermissions).toHaveLength(0);
expect(newNote.tags).toHaveLength(0);
expect(newNote.owner).toBeNull();
expect(newNote.aliases).toHaveLength(0);
expect(await newNote.historyEntries).toHaveLength(0);
expect(await newNote.userPermissions).toHaveLength(0);
expect(await newNote.groupPermissions).toHaveLength(0);
expect(await newNote.tags).toHaveLength(0);
expect(await newNote.owner).toBeNull();
expect(await newNote.aliases).toHaveLength(0);
});
it('without alias, with owner', async () => {
const newNote = await service.createNote(content, user);
const revisions = await newNote.revisions;
expect(revisions).toHaveLength(1);
expect(revisions[0].content).toEqual(content);
expect(newNote.historyEntries).toHaveLength(1);
expect(newNote.historyEntries[0].user).toEqual(user);
expect(newNote.userPermissions).toHaveLength(0);
expect(newNote.groupPermissions).toHaveLength(0);
expect(newNote.tags).toHaveLength(0);
expect(newNote.owner).toEqual(user);
expect(newNote.aliases).toHaveLength(0);
expect(await newNote.historyEntries).toHaveLength(1);
expect((await newNote.historyEntries)[0].user).toEqual(user);
expect(await newNote.userPermissions).toHaveLength(0);
expect(await newNote.groupPermissions).toHaveLength(0);
expect(await newNote.tags).toHaveLength(0);
expect(await newNote.owner).toEqual(user);
expect(await newNote.aliases).toHaveLength(0);
});
it('with alias, without owner', async () => {
const newNote = await service.createNote(content, null, alias);
const revisions = await newNote.revisions;
expect(revisions).toHaveLength(1);
expect(revisions[0].content).toEqual(content);
expect(newNote.historyEntries).toHaveLength(0);
expect(newNote.userPermissions).toHaveLength(0);
expect(newNote.groupPermissions).toHaveLength(0);
expect(newNote.tags).toHaveLength(0);
expect(newNote.owner).toBeNull();
expect(newNote.aliases).toHaveLength(1);
expect(await newNote.historyEntries).toHaveLength(0);
expect(await newNote.userPermissions).toHaveLength(0);
expect(await newNote.groupPermissions).toHaveLength(0);
expect(await newNote.tags).toHaveLength(0);
expect(await newNote.owner).toBeNull();
expect(await newNote.aliases).toHaveLength(1);
});
it('with alias, with owner', async () => {
const newNote = await service.createNote(content, user, alias);
const revisions = await newNote.revisions;
expect(revisions).toHaveLength(1);
expect(revisions[0].content).toEqual(content);
expect(newNote.historyEntries).toHaveLength(1);
expect(newNote.historyEntries[0].user).toEqual(user);
expect(newNote.userPermissions).toHaveLength(0);
expect(newNote.groupPermissions).toHaveLength(0);
expect(newNote.tags).toHaveLength(0);
expect(newNote.owner).toEqual(user);
expect(newNote.aliases).toHaveLength(1);
expect(newNote.aliases[0].name).toEqual(alias);
expect(await newNote.historyEntries).toHaveLength(1);
expect((await newNote.historyEntries)[0].user).toEqual(user);
expect(await newNote.userPermissions).toHaveLength(0);
expect(await newNote.groupPermissions).toHaveLength(0);
expect(await newNote.tags).toHaveLength(0);
expect(await newNote.owner).toEqual(user);
expect(await newNote.aliases).toHaveLength(1);
expect((await newNote.aliases)[0].name).toEqual(alias);
});
});
describe('fails:', () => {
@ -379,8 +379,8 @@ describe('NotesService', () => {
sharedToUsers: [],
sharedToGroups: [],
});
expect(savedNote.userPermissions).toHaveLength(0);
expect(savedNote.groupPermissions).toHaveLength(0);
expect(await savedNote.userPermissions).toHaveLength(0);
expect(await savedNote.groupPermissions).toHaveLength(0);
});
it('with empty GroupPermissions and with new UserPermissions', async () => {
jest
@ -393,24 +393,24 @@ describe('NotesService', () => {
sharedToUsers: [userPermissionUpdate],
sharedToGroups: [],
});
expect(savedNote.userPermissions).toHaveLength(1);
expect(savedNote.userPermissions[0].user.username).toEqual(
expect(await savedNote.userPermissions).toHaveLength(1);
expect((await savedNote.userPermissions)[0].user.username).toEqual(
userPermissionUpdate.username,
);
expect(savedNote.userPermissions[0].canEdit).toEqual(
expect((await savedNote.userPermissions)[0].canEdit).toEqual(
userPermissionUpdate.canEdit,
);
expect(savedNote.groupPermissions).toHaveLength(0);
expect(await savedNote.groupPermissions).toHaveLength(0);
});
it('with empty GroupPermissions and with existing UserPermissions', async () => {
const noteWithPreexistingPermissions: Note = { ...note };
noteWithPreexistingPermissions.userPermissions = [
noteWithPreexistingPermissions.userPermissions = Promise.resolve([
{
note: noteWithPreexistingPermissions,
user: user,
canEdit: !userPermissionUpdate.canEdit,
},
];
]);
jest
.spyOn(noteRepo, 'save')
.mockImplementationOnce(async (entry: Note) => {
@ -421,14 +421,14 @@ describe('NotesService', () => {
sharedToUsers: [userPermissionUpdate],
sharedToGroups: [],
});
expect(savedNote.userPermissions).toHaveLength(1);
expect(savedNote.userPermissions[0].user.username).toEqual(
expect(await savedNote.userPermissions).toHaveLength(1);
expect((await savedNote.userPermissions)[0].user.username).toEqual(
userPermissionUpdate.username,
);
expect(savedNote.userPermissions[0].canEdit).toEqual(
expect((await savedNote.userPermissions)[0].canEdit).toEqual(
userPermissionUpdate.canEdit,
);
expect(savedNote.groupPermissions).toHaveLength(0);
expect(await savedNote.groupPermissions).toHaveLength(0);
});
it('with new GroupPermissions and with empty UserPermissions', async () => {
jest
@ -441,11 +441,11 @@ describe('NotesService', () => {
sharedToUsers: [],
sharedToGroups: [groupPermissionUpate],
});
expect(savedNote.userPermissions).toHaveLength(0);
expect(savedNote.groupPermissions[0].group.name).toEqual(
expect(await savedNote.userPermissions).toHaveLength(0);
expect((await savedNote.groupPermissions)[0].group.name).toEqual(
groupPermissionUpate.groupname,
);
expect(savedNote.groupPermissions[0].canEdit).toEqual(
expect((await savedNote.groupPermissions)[0].canEdit).toEqual(
groupPermissionUpate.canEdit,
);
});
@ -461,28 +461,28 @@ describe('NotesService', () => {
sharedToUsers: [userPermissionUpdate],
sharedToGroups: [groupPermissionUpate],
});
expect(savedNote.userPermissions[0].user.username).toEqual(
expect((await savedNote.userPermissions)[0].user.username).toEqual(
userPermissionUpdate.username,
);
expect(savedNote.userPermissions[0].canEdit).toEqual(
expect((await savedNote.userPermissions)[0].canEdit).toEqual(
userPermissionUpdate.canEdit,
);
expect(savedNote.groupPermissions[0].group.name).toEqual(
expect((await savedNote.groupPermissions)[0].group.name).toEqual(
groupPermissionUpate.groupname,
);
expect(savedNote.groupPermissions[0].canEdit).toEqual(
expect((await savedNote.groupPermissions)[0].canEdit).toEqual(
groupPermissionUpate.canEdit,
);
});
it('with new GroupPermissions and with existing UserPermissions', async () => {
const noteWithUserPermission: Note = { ...note };
noteWithUserPermission.userPermissions = [
noteWithUserPermission.userPermissions = Promise.resolve([
{
note: noteWithUserPermission,
user: user,
canEdit: !userPermissionUpdate.canEdit,
},
];
]);
jest
.spyOn(noteRepo, 'save')
.mockImplementationOnce(async (entry: Note) => {
@ -497,28 +497,28 @@ describe('NotesService', () => {
sharedToGroups: [groupPermissionUpate],
},
);
expect(savedNote.userPermissions[0].user.username).toEqual(
expect((await savedNote.userPermissions)[0].user.username).toEqual(
userPermissionUpdate.username,
);
expect(savedNote.userPermissions[0].canEdit).toEqual(
expect((await savedNote.userPermissions)[0].canEdit).toEqual(
userPermissionUpdate.canEdit,
);
expect(savedNote.groupPermissions[0].group.name).toEqual(
expect((await savedNote.groupPermissions)[0].group.name).toEqual(
groupPermissionUpate.groupname,
);
expect(savedNote.groupPermissions[0].canEdit).toEqual(
expect((await savedNote.groupPermissions)[0].canEdit).toEqual(
groupPermissionUpate.canEdit,
);
});
it('with existing GroupPermissions and with empty UserPermissions', async () => {
const noteWithPreexistingPermissions: Note = { ...note };
noteWithPreexistingPermissions.groupPermissions = [
noteWithPreexistingPermissions.groupPermissions = Promise.resolve([
{
note: noteWithPreexistingPermissions,
group: group,
canEdit: !groupPermissionUpate.canEdit,
},
];
]);
jest.spyOn(groupRepo, 'findOne').mockResolvedValueOnce(group);
jest
.spyOn(noteRepo, 'save')
@ -532,23 +532,23 @@ describe('NotesService', () => {
sharedToGroups: [groupPermissionUpate],
},
);
expect(savedNote.userPermissions).toHaveLength(0);
expect(savedNote.groupPermissions[0].group.name).toEqual(
expect(await savedNote.userPermissions).toHaveLength(0);
expect((await savedNote.groupPermissions)[0].group.name).toEqual(
groupPermissionUpate.groupname,
);
expect(savedNote.groupPermissions[0].canEdit).toEqual(
expect((await savedNote.groupPermissions)[0].canEdit).toEqual(
groupPermissionUpate.canEdit,
);
});
it('with existing GroupPermissions and with new UserPermissions', async () => {
const noteWithPreexistingPermissions: Note = { ...note };
noteWithPreexistingPermissions.groupPermissions = [
noteWithPreexistingPermissions.groupPermissions = Promise.resolve([
{
note: noteWithPreexistingPermissions,
group: group,
canEdit: !groupPermissionUpate.canEdit,
},
];
]);
jest
.spyOn(noteRepo, 'save')
.mockImplementationOnce(async (entry: Note) => {
@ -563,35 +563,35 @@ describe('NotesService', () => {
sharedToGroups: [groupPermissionUpate],
},
);
expect(savedNote.userPermissions[0].user.username).toEqual(
expect((await savedNote.userPermissions)[0].user.username).toEqual(
userPermissionUpdate.username,
);
expect(savedNote.userPermissions[0].canEdit).toEqual(
expect((await savedNote.userPermissions)[0].canEdit).toEqual(
userPermissionUpdate.canEdit,
);
expect(savedNote.groupPermissions[0].group.name).toEqual(
expect((await savedNote.groupPermissions)[0].group.name).toEqual(
groupPermissionUpate.groupname,
);
expect(savedNote.groupPermissions[0].canEdit).toEqual(
expect((await savedNote.groupPermissions)[0].canEdit).toEqual(
groupPermissionUpate.canEdit,
);
});
it('with existing GroupPermissions and with existing UserPermissions', async () => {
const noteWithPreexistingPermissions: Note = { ...note };
noteWithPreexistingPermissions.groupPermissions = [
noteWithPreexistingPermissions.groupPermissions = Promise.resolve([
{
note: noteWithPreexistingPermissions,
group: group,
canEdit: !groupPermissionUpate.canEdit,
},
];
noteWithPreexistingPermissions.userPermissions = [
]);
noteWithPreexistingPermissions.userPermissions = Promise.resolve([
{
note: noteWithPreexistingPermissions,
user: user,
canEdit: !userPermissionUpdate.canEdit,
},
];
]);
jest
.spyOn(noteRepo, 'save')
.mockImplementationOnce(async (entry: Note) => {
@ -606,16 +606,16 @@ describe('NotesService', () => {
sharedToGroups: [groupPermissionUpate],
},
);
expect(savedNote.userPermissions[0].user.username).toEqual(
expect((await savedNote.userPermissions)[0].user.username).toEqual(
userPermissionUpdate.username,
);
expect(savedNote.userPermissions[0].canEdit).toEqual(
expect((await savedNote.userPermissions)[0].canEdit).toEqual(
userPermissionUpdate.canEdit,
);
expect(savedNote.groupPermissions[0].group.name).toEqual(
expect((await savedNote.groupPermissions)[0].group.name).toEqual(
groupPermissionUpate.groupname,
);
expect(savedNote.groupPermissions[0].canEdit).toEqual(
expect((await savedNote.groupPermissions)[0].canEdit).toEqual(
groupPermissionUpate.canEdit,
);
});
@ -653,16 +653,16 @@ describe('NotesService', () => {
describe('toTagList', () => {
it('works', async () => {
const note = {} as Note;
note.tags = [
note.tags = Promise.resolve([
{
id: 1,
name: 'testTag',
notes: [note],
},
];
const tagList = service.toTagList(note);
]);
const tagList = await service.toTagList(note);
expect(tagList).toHaveLength(1);
expect(tagList[0]).toEqual(note.tags[0].name);
expect(tagList[0]).toEqual((await note.tags)[0].name);
});
});
@ -671,21 +671,21 @@ describe('NotesService', () => {
const user = User.create('hardcoded', 'Testy') as User;
const group = Group.create('testGroup', 'testGroup', false) as Group;
const note = Note.create(user) as Note;
note.userPermissions = [
note.userPermissions = Promise.resolve([
{
note: note,
user: user,
canEdit: true,
},
];
note.groupPermissions = [
]);
note.groupPermissions = Promise.resolve([
{
note: note,
group: group,
canEdit: true,
},
];
const permissions = service.toNotePermissionsDto(note);
]);
const permissions = await service.toNotePermissionsDto(note);
expect(permissions.owner).not.toEqual(null);
expect(permissions.owner?.username).toEqual(user.username);
expect(permissions.sharedToUsers).toHaveLength(1);
@ -740,36 +740,38 @@ describe('NotesService', () => {
// @ts-ignore
.mockImplementation(() => createQueryBuilder);
note.publicId = 'testId';
note.aliases = [Alias.create('testAlias', note, true) as Alias];
note.aliases = Promise.resolve([
Alias.create('testAlias', note, true) as Alias,
]);
note.title = 'testTitle';
note.description = 'testDescription';
note.owner = user;
note.userPermissions = [
note.owner = Promise.resolve(user);
note.userPermissions = Promise.resolve([
{
note: note,
user: user,
canEdit: true,
},
];
note.groupPermissions = [
]);
note.groupPermissions = Promise.resolve([
{
note: note,
group: group,
canEdit: true,
},
];
note.tags = [
]);
note.tags = Promise.resolve([
{
id: 1,
name: 'testTag',
notes: [note],
},
];
]);
note.viewCount = 1337;
const metadataDto = await service.toNoteMetadataDto(note);
expect(metadataDto.id).toEqual(note.publicId);
expect(metadataDto.aliases).toHaveLength(1);
expect(metadataDto.aliases[0]).toEqual(note.aliases[0].name);
expect(metadataDto.aliases[0]).toEqual((await note.aliases)[0].name);
expect(metadataDto.title).toEqual(note.title);
expect(metadataDto.createTime).toEqual(revisions[0].createdAt);
expect(metadataDto.description).toEqual(note.description);
@ -787,7 +789,7 @@ describe('NotesService', () => {
).toEqual(group.displayName);
expect(metadataDto.permissions.sharedToGroups[0].canEdit).toEqual(true);
expect(metadataDto.tags).toHaveLength(1);
expect(metadataDto.tags[0]).toEqual(note.tags[0].name);
expect(metadataDto.tags[0]).toEqual((await note.tags)[0].name);
expect(metadataDto.updateTime).toEqual(revisions[0].createdAt);
expect(metadataDto.updateUser.username).toEqual(user.username);
expect(metadataDto.viewCount).toEqual(note.viewCount);
@ -840,36 +842,38 @@ describe('NotesService', () => {
// @ts-ignore
.mockImplementation(() => createQueryBuilder);
note.publicId = 'testId';
note.aliases = [Alias.create('testAlias', note, true) as Alias];
note.aliases = Promise.resolve([
Alias.create('testAlias', note, true) as Alias,
]);
note.title = 'testTitle';
note.description = 'testDescription';
note.owner = user;
note.userPermissions = [
note.owner = Promise.resolve(user);
note.userPermissions = Promise.resolve([
{
note: note,
user: user,
canEdit: true,
},
];
note.groupPermissions = [
]);
note.groupPermissions = Promise.resolve([
{
note: note,
group: group,
canEdit: true,
},
];
note.tags = [
]);
note.tags = Promise.resolve([
{
id: 1,
name: 'testTag',
notes: [note],
},
];
]);
note.viewCount = 1337;
const noteDto = await service.toNoteDto(note);
expect(noteDto.metadata.id).toEqual(note.publicId);
expect(noteDto.metadata.aliases).toHaveLength(1);
expect(noteDto.metadata.aliases[0]).toEqual(note.aliases[0].name);
expect(noteDto.metadata.aliases[0]).toEqual((await note.aliases)[0].name);
expect(noteDto.metadata.title).toEqual(note.title);
expect(noteDto.metadata.createTime).toEqual(revisions[0].createdAt);
expect(noteDto.metadata.description).toEqual(note.description);
@ -893,7 +897,7 @@ describe('NotesService', () => {
true,
);
expect(noteDto.metadata.tags).toHaveLength(1);
expect(noteDto.metadata.tags[0]).toEqual(note.tags[0].name);
expect(noteDto.metadata.tags[0]).toEqual((await note.tags)[0].name);
expect(noteDto.metadata.updateTime).toEqual(revisions[0].createdAt);
expect(noteDto.metadata.updateUser.username).toEqual(user.username);
expect(noteDto.metadata.viewCount).toEqual(note.viewCount);

View file

@ -100,9 +100,9 @@ export class NotesService {
Revision.create(noteContent, noteContent, newNote as Note) as Revision,
]);
if (owner) {
newNote.historyEntries = [
newNote.historyEntries = Promise.resolve([
HistoryEntry.create(owner, newNote as Note) as HistoryEntry,
];
]);
}
try {
return await this.noteRepository.save(newNote);
@ -262,8 +262,8 @@ export class NotesService {
//TODO: Calculate patch
revisions.push(Revision.create(noteContent, noteContent, note) as Revision);
note.revisions = Promise.resolve(revisions);
note.userPermissions = [];
note.groupPermissions = [];
note.userPermissions = Promise.resolve([]);
note.groupPermissions = Promise.resolve([]);
return await this.noteRepository.save(note);
}
@ -298,8 +298,8 @@ export class NotesService {
);
}
note.userPermissions = [];
note.groupPermissions = [];
note.userPermissions = Promise.resolve([]);
note.groupPermissions = Promise.resolve([]);
// Create new userPermissions
for (const newUserPermission of newPermissions.sharedToUsers) {
@ -312,7 +312,7 @@ export class NotesService {
newUserPermission.canEdit,
);
createdPermission.note = note;
note.userPermissions.push(createdPermission);
(await note.userPermissions).push(createdPermission);
}
// Create groupPermissions
@ -326,7 +326,7 @@ export class NotesService {
newGroupPermission.canEdit,
);
createdPermission.note = note;
note.groupPermissions.push(createdPermission);
(await note.groupPermissions).push(createdPermission);
}
return await this.noteRepository.save(note);
@ -348,7 +348,7 @@ export class NotesService {
)[0].author.user;
}
// If there are no Edits, the owner is the updateUser
return note.owner;
return await note.owner;
}
/**
@ -356,8 +356,8 @@ export class NotesService {
* @param {Note} note - the note to use
* @return {string[]} string array of tags names
*/
toTagList(note: Note): string[] {
return note.tags.map((tag) => tag.name);
async toTagList(note: Note): Promise<string[]> {
return (await note.tags).map((tag) => tag.name);
}
/**
@ -365,14 +365,17 @@ export class NotesService {
* @param {Note} note - the note to use
* @return {NotePermissionsDto} the built NotePermissionDto
*/
toNotePermissionsDto(note: Note): NotePermissionsDto {
async toNotePermissionsDto(note: Note): Promise<NotePermissionsDto> {
const owner = await note.owner;
const userPermissions = await note.userPermissions;
const groupPermissions = await note.groupPermissions;
return {
owner: note.owner ? this.usersService.toUserDto(note.owner) : null,
sharedToUsers: note.userPermissions.map((noteUserPermission) => ({
owner: owner ? this.usersService.toUserDto(owner) : null,
sharedToUsers: userPermissions.map((noteUserPermission) => ({
user: this.usersService.toUserDto(noteUserPermission.user),
canEdit: noteUserPermission.canEdit,
})),
sharedToGroups: note.groupPermissions.map((noteGroupPermission) => ({
sharedToGroups: groupPermissions.map((noteGroupPermission) => ({
group: this.groupsService.toGroupDto(noteGroupPermission.group),
canEdit: noteGroupPermission.canEdit,
})),
@ -389,14 +392,16 @@ export class NotesService {
const updateUser = await this.calculateUpdateUser(note);
return {
id: note.publicId,
aliases: note.aliases.map((alias) => alias.name),
primaryAlias: getPrimaryAlias(note) ?? null,
aliases: await Promise.all(
(await note.aliases).map((alias) => alias.name),
),
primaryAlias: (await getPrimaryAlias(note)) ?? null,
title: note.title ?? '',
createTime: (await this.getFirstRevision(note)).createdAt,
description: note.description ?? '',
editedBy: (await this.getAuthorUsers(note)).map((user) => user.username),
permissions: this.toNotePermissionsDto(note),
tags: this.toTagList(note),
permissions: await this.toNotePermissionsDto(note),
tags: await this.toTagList(note),
updateTime: (await this.getLatestRevision(note)).createdAt,
updateUser: updateUser ? this.usersService.toUserDto(updateUser) : null,
viewCount: note.viewCount,

View file

@ -29,12 +29,12 @@ describe('getPrimaryAlias', () => {
const user = User.create('hardcoded', 'Testy') as User;
note = Note.create(user, alias) as Note;
});
it('finds correct primary alias', () => {
note.aliases.push(Alias.create('annother', note, false) as Alias);
expect(getPrimaryAlias(note)).toEqual(alias);
it('finds correct primary alias', async () => {
(await note.aliases).push(Alias.create('annother', note, false) as Alias);
expect(await getPrimaryAlias(note)).toEqual(alias);
});
it('returns undefined if there is no alias', () => {
note.aliases[0].primary = false;
expect(getPrimaryAlias(note)).toEqual(undefined);
it('returns undefined if there is no alias', async () => {
(await note.aliases)[0].primary = false;
expect(await getPrimaryAlias(note)).toEqual(undefined);
});
});

View file

@ -22,8 +22,8 @@ export function generatePublicId(): string {
* Extract the primary alias from a aliases of a note
* @param {Note} note - the note from which the primary alias should be extracted
*/
export function getPrimaryAlias(note: Note): string | undefined {
const listWithPrimaryAlias = note.aliases.filter(
export async function getPrimaryAlias(note: Note): Promise<string | undefined> {
const listWithPrimaryAlias = (await note.aliases).filter(
(alias: Alias) => alias.primary,
);
if (listWithPrimaryAlias.length !== 1) {

View file

@ -30,6 +30,7 @@ import { GuestPermission, PermissionsService } from './permissions.service';
describe('PermissionsService', () => {
let permissionsService: PermissionsService;
let notes: Note[];
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
@ -73,6 +74,7 @@ describe('PermissionsService', () => {
.useValue({})
.compile();
permissionsService = module.get<PermissionsService>(PermissionsService);
notes = await createNoteUserPermissionNotes();
});
// The two users we test with:
@ -87,16 +89,16 @@ describe('PermissionsService', () => {
function createNote(owner: User): Note {
const note = {} as Note;
note.userPermissions = [];
note.groupPermissions = [];
note.owner = owner;
note.userPermissions = Promise.resolve([]);
note.groupPermissions = Promise.resolve([]);
note.owner = Promise.resolve(owner);
return note;
}
/*
* Creates the permission objects for UserPermission for two users with write and with out write permission
*/
function createNoteUserPermissionNotes(): Note[] {
async function createNoteUserPermissionNotes(): Promise<Note[]> {
const note0 = createNote(user1);
const note1 = createNote(user2);
const note2 = createNote(user2);
@ -116,23 +118,23 @@ describe('PermissionsService', () => {
noteUserPermission4.user = user2;
noteUserPermission4.canEdit = true;
note1.userPermissions.push(noteUserPermission1);
(await note1.userPermissions).push(noteUserPermission1);
note2.userPermissions.push(noteUserPermission1);
note2.userPermissions.push(noteUserPermission2);
(await note2.userPermissions).push(noteUserPermission1);
(await note2.userPermissions).push(noteUserPermission2);
note3.userPermissions.push(noteUserPermission2);
note3.userPermissions.push(noteUserPermission1);
(await note3.userPermissions).push(noteUserPermission2);
(await note3.userPermissions).push(noteUserPermission1);
note4.userPermissions.push(noteUserPermission3);
(await note4.userPermissions).push(noteUserPermission3);
note5.userPermissions.push(noteUserPermission3);
note5.userPermissions.push(noteUserPermission4);
(await note5.userPermissions).push(noteUserPermission3);
(await note5.userPermissions).push(noteUserPermission4);
note6.userPermissions.push(noteUserPermission4);
note6.userPermissions.push(noteUserPermission3);
(await note6.userPermissions).push(noteUserPermission4);
(await note6.userPermissions).push(noteUserPermission3);
note7.userPermissions.push(noteUserPermission2);
(await note7.userPermissions).push(noteUserPermission2);
const everybody = {} as Group;
everybody.name = SpecialGroup.EVERYONE;
@ -143,7 +145,9 @@ describe('PermissionsService', () => {
noteGroupPermissionRead.group = everybody;
noteGroupPermissionRead.canEdit = false;
noteGroupPermissionRead.note = noteEverybodyRead;
noteEverybodyRead.groupPermissions = [noteGroupPermissionRead];
noteEverybodyRead.groupPermissions = Promise.resolve([
noteGroupPermissionRead,
]);
const noteEverybodyWrite = createNote(user1);
@ -151,7 +155,9 @@ describe('PermissionsService', () => {
noteGroupPermissionWrite.group = everybody;
noteGroupPermissionWrite.canEdit = true;
noteGroupPermissionWrite.note = noteEverybodyWrite;
noteEverybodyWrite.groupPermissions = [noteGroupPermissionWrite];
noteEverybodyWrite.groupPermissions = Promise.resolve([
noteGroupPermissionWrite,
]);
return [
note0,
@ -167,8 +173,6 @@ describe('PermissionsService', () => {
];
}
const notes = createNoteUserPermissionNotes();
describe('mayRead works with', () => {
it('Owner', async () => {
permissionsService.guestPermission = GuestPermission.DENY;
@ -501,7 +505,7 @@ describe('PermissionsService', () => {
let i = 0;
for (const permission of permissions) {
const note = createNote(user2);
note.groupPermissions = permission.permissions;
note.groupPermissions = Promise.resolve(permission.permissions);
let permissionString = '';
for (const perm of permission.permissions) {
permissionString += ` ${perm.group.name}:${String(perm.canEdit)}`;
@ -550,13 +554,13 @@ describe('PermissionsService', () => {
});
describe('isOwner works', () => {
it('for positive case', () => {
it('for positive case', async () => {
permissionsService.guestPermission = GuestPermission.DENY;
expect(permissionsService.isOwner(user1, notes[0])).toBeTruthy();
expect(await permissionsService.isOwner(user1, notes[0])).toBeTruthy();
});
it('for negative case', () => {
it('for negative case', async () => {
permissionsService.guestPermission = GuestPermission.DENY;
expect(permissionsService.isOwner(user1, notes[1])).toBeFalsy();
expect(await permissionsService.isOwner(user1, notes[1])).toBeFalsy();
});
});
});

View file

@ -22,9 +22,9 @@ export enum GuestPermission {
export class PermissionsService {
public guestPermission: GuestPermission; // TODO change to configOption
async mayRead(user: User | null, note: Note): Promise<boolean> {
if (this.isOwner(user, note)) return true;
if (await this.isOwner(user, note)) return true;
if (this.hasPermissionUser(user, note, false)) return true;
if (await this.hasPermissionUser(user, note, false)) return true;
// noinspection RedundantIfStatementJS
if (await this.hasPermissionGroup(user, note, false)) return true;
@ -33,9 +33,9 @@ export class PermissionsService {
}
async mayWrite(user: User | null, note: Note): Promise<boolean> {
if (this.isOwner(user, note)) return true;
if (await this.isOwner(user, note)) return true;
if (this.hasPermissionUser(user, note, true)) return true;
if (await this.hasPermissionUser(user, note, true)) return true;
// noinspection RedundantIfStatementJS
if (await this.hasPermissionGroup(user, note, true)) return true;
@ -58,21 +58,22 @@ export class PermissionsService {
return false;
}
isOwner(user: User | null, note: Note): boolean {
async isOwner(user: User | null, note: Note): Promise<boolean> {
if (!user) return false;
if (!note.owner) return false;
return note.owner.id === user.id;
const owner = await note.owner;
if (!owner) return false;
return owner.id === user.id;
}
private hasPermissionUser(
private async hasPermissionUser(
user: User | null,
note: Note,
wantEdit: boolean,
): boolean {
): Promise<boolean> {
if (!user) {
return false;
}
for (const userPermission of note.userPermissions) {
for (const userPermission of await note.userPermissions) {
if (
userPermission.user.id === user.id &&
(userPermission.canEdit || !wantEdit)
@ -99,7 +100,7 @@ export class PermissionsService {
case GuestPermission.READ:
guestsAllowed = !wantEdit;
}
for (const groupPermission of note.groupPermissions) {
for (const groupPermission of await note.groupPermissions) {
if (groupPermission.canEdit || !wantEdit) {
// Handle special groups
if (groupPermission.group.special) {

View file

@ -76,8 +76,8 @@ createConnection({
const edit = Edit.create(author, 1, 42) as Edit;
revision.edits = [edit];
notes[i].revisions = Promise.all([revision]);
notes[i].userPermissions = [];
notes[i].groupPermissions = [];
notes[i].userPermissions = Promise.resolve([]);
notes[i].groupPermissions = Promise.resolve([]);
user.ownedNotes = [notes[i]];
await connection.manager.save([
notes[i],
@ -99,7 +99,7 @@ createConnection({
throw new Error('Could not find freshly seeded notes. Aborting.');
}
for (const note of foundNotes) {
if (!note.aliases[0]) {
if (!(await note.aliases)[0]) {
throw new Error(
'Could not find alias of freshly seeded notes. Aborting.',
);
@ -111,7 +111,7 @@ createConnection({
);
}
for (const note of foundNotes) {
console.log(`Created Note '${note.aliases[0].name ?? ''}'`);
console.log(`Created Note '${(await note.aliases)[0].name ?? ''}'`);
}
for (const user of foundUsers) {
for (const note of foundNotes) {
@ -119,7 +119,7 @@ createConnection({
await connection.manager.save(historyEntry);
console.log(
`Created HistoryEntry for user '${user.username}' and note '${
note.aliases[0].name ?? ''
(await note.aliases)[0].name ?? ''
}'`,
);
}

View file

@ -69,7 +69,7 @@ describe('History', () => {
note,
user,
);
const entryDto = testSetup.historyService.toHistoryEntryDto(entry);
const entryDto = await testSetup.historyService.toHistoryEntryDto(entry);
const response = await agent
.get('/api/private/me/history')
.expect('Content-Type', /json/)
@ -92,7 +92,7 @@ describe('History', () => {
const pinStatus = true;
const lastVisited = new Date('2020-12-01 12:23:34');
const postEntryDto = new HistoryEntryImportDto();
postEntryDto.note = note2.aliases.filter(
postEntryDto.note = (await note2.aliases).filter(
(alias) => alias.primary,
)[0].name;
postEntryDto.pinStatus = pinStatus;
@ -104,13 +104,15 @@ describe('History', () => {
.expect(201);
const userEntries = await testSetup.historyService.getEntriesByUser(user);
expect(userEntries.length).toEqual(1);
expect(userEntries[0].note.aliases[0].name).toEqual(
note2.aliases[0].name,
expect((await userEntries[0].note.aliases)[0].name).toEqual(
(await note2.aliases)[0].name,
);
expect(userEntries[0].note.aliases[0].primary).toEqual(
note2.aliases[0].primary,
expect((await userEntries[0].note.aliases)[0].primary).toEqual(
(await note2.aliases)[0].primary,
);
expect((await userEntries[0].note.aliases)[0].id).toEqual(
(await note2.aliases)[0].id,
);
expect(userEntries[0].note.aliases[0].id).toEqual(note2.aliases[0].id);
expect(userEntries[0].user.username).toEqual(user.username);
expect(userEntries[0].pinStatus).toEqual(pinStatus);
expect(userEntries[0].updatedAt).toEqual(lastVisited);
@ -129,7 +131,7 @@ describe('History', () => {
pinStatus = !previousHistory[0].pinStatus;
lastVisited = new Date('2020-12-01 23:34:45');
postEntryDto = new HistoryEntryImportDto();
postEntryDto.note = note2.aliases.filter(
postEntryDto.note = (await note2.aliases).filter(
(alias) => alias.primary,
)[0].name;
postEntryDto.pinStatus = pinStatus;
@ -188,7 +190,8 @@ describe('History', () => {
user,
);
expect(entry.pinStatus).toBeFalsy();
const alias = entry.note.aliases.filter((alias) => alias.primary)[0].name;
const alias = (await entry.note.aliases).filter((alias) => alias.primary)[0]
.name;
await agent
.put(`/api/private/me/history/${alias || 'undefined'}`)
.send({ pinStatus: true })
@ -201,15 +204,16 @@ describe('History', () => {
it('DELETE /me/history/:note', async () => {
const entry = await historyService.updateHistoryEntryTimestamp(note2, user);
const alias = entry.note.aliases.filter((alias) => alias.primary)[0].name;
const alias = (await entry.note.aliases).filter((alias) => alias.primary)[0]
.name;
const entry2 = await historyService.updateHistoryEntryTimestamp(note, user);
const entryDto = historyService.toHistoryEntryDto(entry2);
const entryDto = await historyService.toHistoryEntryDto(entry2);
await agent
.delete(`/api/private/me/history/${alias || 'undefined'}`)
.expect(200);
const userEntries = await historyService.getEntriesByUser(user);
expect(userEntries.length).toEqual(1);
const userEntryDto = historyService.toHistoryEntryDto(userEntries[0]);
const userEntryDto = await historyService.toHistoryEntryDto(userEntries[0]);
expect(userEntryDto.identifier).toEqual(entryDto.identifier);
expect(userEntryDto.title).toEqual(entryDto.title);
expect(userEntryDto.tags).toEqual(entryDto.tags);

View file

@ -51,8 +51,9 @@ describe('Me', () => {
.expect(200);
const history: HistoryEntryDto[] = response.body;
expect(history.length).toEqual(1);
const historyDto =
testSetup.historyService.toHistoryEntryDto(createdHistoryEntry);
const historyDto = await testSetup.historyService.toHistoryEntryDto(
createdHistoryEntry,
);
for (const historyEntry of history) {
expect(historyEntry.identifier).toEqual(historyDto.identifier);
expect(historyEntry.title).toEqual(historyDto.title);
@ -75,8 +76,9 @@ describe('Me', () => {
.expect('Content-Type', /json/)
.expect(200);
const historyEntry: HistoryEntryDto = response.body;
const historyEntryDto =
testSetup.historyService.toHistoryEntryDto(createdHistoryEntry);
const historyEntryDto = await testSetup.historyService.toHistoryEntryDto(
createdHistoryEntry,
);
expect(historyEntry.identifier).toEqual(historyEntryDto.identifier);
expect(historyEntry.title).toEqual(historyEntryDto.title);
expect(historyEntry.tags).toEqual(historyEntryDto.tags);
@ -109,8 +111,12 @@ describe('Me', () => {
expect(historyEntry.pinStatus).toEqual(true);
let theEntry: HistoryEntryDto;
for (const entry of history) {
if (entry.note.aliases.find((element) => element.name === noteName)) {
theEntry = testSetup.historyService.toHistoryEntryDto(entry);
if (
(await entry.note.aliases).find(
(element) => element.name === noteName,
)
) {
theEntry = await testSetup.historyService.toHistoryEntryDto(entry);
}
}
expect(theEntry.pinStatus).toEqual(true);
@ -134,7 +140,11 @@ describe('Me', () => {
expect(response.body).toEqual({});
const history = await testSetup.historyService.getEntriesByUser(user);
for (const entry of history) {
if (entry.note.aliases.find((element) => element.name === noteName)) {
if (
(await entry.note.aliases).find(
(element) => element.name === noteName,
)
) {
throw new Error('Deleted history entry still in history');
}
}

View file

@ -200,16 +200,16 @@ describe('Notes', () => {
updateNotePermission,
);
const updatedNote = await testSetup.notesService.getNoteByIdOrAlias(
note.aliases.filter((alias) => alias.primary)[0].name,
(await note.aliases).filter((alias) => alias.primary)[0].name,
);
expect(updatedNote.userPermissions).toHaveLength(1);
expect(updatedNote.userPermissions[0].canEdit).toEqual(
expect(await updatedNote.userPermissions).toHaveLength(1);
expect((await updatedNote.userPermissions)[0].canEdit).toEqual(
updateNotePermission.sharedToUsers[0].canEdit,
);
expect(updatedNote.userPermissions[0].user.username).toEqual(
expect((await updatedNote.userPermissions)[0].user.username).toEqual(
user.username,
);
expect(updatedNote.groupPermissions).toHaveLength(0);
expect(await updatedNote.groupPermissions).toHaveLength(0);
await request(testSetup.app.getHttpServer())
.delete('/api/v2/notes/test3')
.expect(204);