From 029dc0d7d62eaeb8a87192e643ab555a2b875bc8 Mon Sep 17 00:00:00 2001 From: Philip Molares Date: Wed, 17 Mar 2021 10:26:42 +0100 Subject: [PATCH 1/4] Permissions: Add cascade This makes it possible to create permissions by setting them in the note entity and delete them when either the user or note is deleted. Signed-off-by: Philip Molares --- src/notes/note.entity.ts | 7 ++++++- src/permissions/note-group-permission.entity.ts | 10 ++++++++-- src/permissions/note-user-permission.entity.ts | 10 ++++++++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/notes/note.entity.ts b/src/notes/note.entity.ts index 1adcef9cb..538af568b 100644 --- a/src/notes/note.entity.ts +++ b/src/notes/note.entity.ts @@ -39,9 +39,14 @@ export class Note { @OneToMany( (_) => NoteGroupPermission, (groupPermission) => groupPermission.note, + { cascade: true }, // This ensures that embedded NoteGroupPermissions are automatically saved to the database ) groupPermissions: NoteGroupPermission[]; - @OneToMany((_) => NoteUserPermission, (userPermission) => userPermission.note) + @OneToMany( + (_) => NoteUserPermission, + (userPermission) => userPermission.note, + { cascade: true }, // This ensures that embedded NoteUserPermission are automatically saved to the database + ) userPermissions: NoteUserPermission[]; @Column({ nullable: false, diff --git a/src/permissions/note-group-permission.entity.ts b/src/permissions/note-group-permission.entity.ts index d1e94112c..364c2991d 100644 --- a/src/permissions/note-group-permission.entity.ts +++ b/src/permissions/note-group-permission.entity.ts @@ -10,10 +10,16 @@ import { Note } from '../notes/note.entity'; @Entity() export class NoteGroupPermission { - @ManyToOne((_) => Group, { primary: true }) + @ManyToOne((_) => Group, { + primary: true, + onDelete: 'CASCADE', // This deletes the NoteGroupPermission, when the associated Group is deleted + }) group: Group; - @ManyToOne((_) => Note, (note) => note.groupPermissions, { primary: true }) + @ManyToOne((_) => Note, (note) => note.groupPermissions, { + primary: true, + onDelete: 'CASCADE', // This deletes the NoteGroupPermission, when the associated Note is deleted + }) note: Note; @Column() diff --git a/src/permissions/note-user-permission.entity.ts b/src/permissions/note-user-permission.entity.ts index 0bad0d41d..06e94d0af 100644 --- a/src/permissions/note-user-permission.entity.ts +++ b/src/permissions/note-user-permission.entity.ts @@ -10,10 +10,16 @@ import { User } from '../users/user.entity'; @Entity() export class NoteUserPermission { - @ManyToOne((_) => User, { primary: true }) + @ManyToOne((_) => User, { + primary: true, + onDelete: 'CASCADE', // This deletes the NoteUserPermission, when the associated Note is deleted + }) user: User; - @ManyToOne((_) => Note, (note) => note.userPermissions, { primary: true }) + @ManyToOne((_) => Note, (note) => note.userPermissions, { + primary: true, + onDelete: 'CASCADE', // This deletes the NoteUserPermission, when the associated Note is deleted + }) note: Note; @Column() From 85ed00e2c27b2eced34bd8baf75323648fff6e85 Mon Sep 17 00:00:00 2001 From: Philip Molares Date: Wed, 17 Mar 2021 10:27:29 +0100 Subject: [PATCH 2/4] NotesService: Set Permissions Set the necessary information for the permissions to be correctly inserted into the db. Signed-off-by: Philip Molares --- src/notes/notes.service.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/notes/notes.service.ts b/src/notes/notes.service.ts index a1b1ecfdf..231d6082a 100644 --- a/src/notes/notes.service.ts +++ b/src/notes/notes.service.ts @@ -224,6 +224,8 @@ export class NotesService { //TODO: Calculate patch revisions.push(Revision.create(noteContent, noteContent)); note.revisions = Promise.resolve(revisions); + note.userPermissions = []; + note.groupPermissions = []; return await this.noteRepository.save(note); } @@ -270,6 +272,7 @@ export class NotesService { user, newUserPermission.canEdit, ); + createdPermission.note = note; note.userPermissions.push(createdPermission); } @@ -282,6 +285,7 @@ export class NotesService { group, newGroupPermission.canEdit, ); + createdPermission.note = note; note.groupPermissions.push(createdPermission); } From 1aa9b5f9152c7d7748e265bc837b5f1fcbf579c0 Mon Sep 17 00:00:00 2001 From: Philip Molares Date: Fri, 2 Apr 2021 20:46:34 +0200 Subject: [PATCH 3/4] NotesService: Get user and group of the permission This also fetches to user and group of permissions and not only the `canEdit` property. Signed-off-by: Philip Molares --- src/notes/notes.service.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/notes/notes.service.ts b/src/notes/notes.service.ts index 231d6082a..b21dba99c 100644 --- a/src/notes/notes.service.ts +++ b/src/notes/notes.service.ts @@ -183,7 +183,9 @@ export class NotesService { 'authorColors', 'owner', 'groupPermissions', + 'groupPermissions.group', 'userPermissions', + 'userPermissions.user', 'tags', ], }); From c6612f55c7a87688d88f60e1f33a3350223a0d3f Mon Sep 17 00:00:00 2001 From: Philip Molares Date: Wed, 17 Mar 2021 10:30:37 +0100 Subject: [PATCH 4/4] PublicNotesE2E: Add extra test for note deletion This test checks if permission are correctly set and no error is thrown if the note is deleted. Signed-off-by: Philip Molares --- test/public-api/notes.e2e-spec.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/public-api/notes.e2e-spec.ts b/test/public-api/notes.e2e-spec.ts index b86d187fd..03aeda5df 100644 --- a/test/public-api/notes.e2e-spec.ts +++ b/test/public-api/notes.e2e-spec.ts @@ -31,6 +31,7 @@ import { User } from '../../src/users/user.entity'; import { UsersModule } from '../../src/users/users.module'; import { promises as fs } from 'fs'; import { MediaService } from '../../src/media/media.service'; +import { NotePermissionsUpdateDto } from '../../src/notes/note-permissions.dto'; import { join } from 'path'; describe('Notes', () => { @@ -160,6 +161,31 @@ describe('Notes', () => { new NotInDBError("Note with id/alias 'test3' not found."), ); }); + it('works with an existing alias with permissions', async () => { + const note = await notesService.createNote(content, 'test3', user); + const updateNotePermission = new NotePermissionsUpdateDto(); + updateNotePermission.sharedToUsers = [ + { + username: user.userName, + canEdit: true, + }, + ]; + updateNotePermission.sharedToGroups = []; + await notesService.updateNotePermissions(note, updateNotePermission); + const updatedNote = await notesService.getNoteByIdOrAlias(note.alias); + expect(updatedNote.userPermissions).toHaveLength(1); + expect(updatedNote.userPermissions[0].canEdit).toEqual( + updateNotePermission.sharedToUsers[0].canEdit, + ); + expect(updatedNote.userPermissions[0].user.userName).toEqual( + user.userName, + ); + expect(updatedNote.groupPermissions).toHaveLength(0); + await request(app.getHttpServer()).delete('/notes/test3').expect(204); + await expect(notesService.getNoteByIdOrAlias('test3')).rejects.toEqual( + new NotInDBError("Note with id/alias 'test3' not found."), + ); + }); it('fails with a forbidden alias', async () => { await request(app.getHttpServer()) .delete(`/notes/${forbiddenNoteId}`)