refactor(group): lazy-load relations

Signed-off-by: David Mehren <git@herrmehren.de>
This commit is contained in:
David Mehren 2021-11-16 19:05:28 +01:00
parent 5d7b544e1f
commit 0c5fdf4201
No known key found for this signature in database
GPG key ID: 185982BA4C42B7C3
5 changed files with 64 additions and 75 deletions

View file

@ -14,14 +14,10 @@ import {
Param, Param,
Post, Post,
UseGuards, UseGuards,
UseInterceptors, UseInterceptors
} from '@nestjs/common'; } from '@nestjs/common';
import { import { AlreadyInDBError, ForbiddenIdError, NotInDBError } from '../../../errors/errors';
AlreadyInDBError,
ForbiddenIdError,
NotInDBError,
} from '../../../errors/errors';
import { HistoryService } from '../../../history/history.service'; import { HistoryService } from '../../../history/history.service';
import { SessionGuard } from '../../../identity/session.guard'; import { SessionGuard } from '../../../identity/session.guard';
import { ConsoleLoggerService } from '../../../logger/console-logger.service'; import { ConsoleLoggerService } from '../../../logger/console-logger.service';

View file

@ -16,7 +16,7 @@ import {
Post, Post,
Put, Put,
UseGuards, UseGuards,
UseInterceptors, UseInterceptors
} from '@nestjs/common'; } from '@nestjs/common';
import { import {
ApiCreatedResponse, ApiCreatedResponse,
@ -26,24 +26,17 @@ import {
ApiProduces, ApiProduces,
ApiSecurity, ApiSecurity,
ApiTags, ApiTags,
ApiUnauthorizedResponse, ApiUnauthorizedResponse
} from '@nestjs/swagger'; } from '@nestjs/swagger';
import { TokenAuthGuard } from '../../../auth/token.strategy'; import { TokenAuthGuard } from '../../../auth/token.strategy';
import { import { AlreadyInDBError, ForbiddenIdError, NotInDBError } from '../../../errors/errors';
AlreadyInDBError,
ForbiddenIdError,
NotInDBError,
} from '../../../errors/errors';
import { HistoryService } from '../../../history/history.service'; import { HistoryService } from '../../../history/history.service';
import { ConsoleLoggerService } from '../../../logger/console-logger.service'; import { ConsoleLoggerService } from '../../../logger/console-logger.service';
import { MediaUploadDto } from '../../../media/media-upload.dto'; import { MediaUploadDto } from '../../../media/media-upload.dto';
import { MediaService } from '../../../media/media.service'; import { MediaService } from '../../../media/media.service';
import { NoteMetadataDto } from '../../../notes/note-metadata.dto'; import { NoteMetadataDto } from '../../../notes/note-metadata.dto';
import { import { NotePermissionsDto, NotePermissionsUpdateDto } from '../../../notes/note-permissions.dto';
NotePermissionsDto,
NotePermissionsUpdateDto,
} from '../../../notes/note-permissions.dto';
import { NoteDto } from '../../../notes/note.dto'; import { NoteDto } from '../../../notes/note.dto';
import { Note } from '../../../notes/note.entity'; import { Note } from '../../../notes/note.entity';
import { NoteMediaDeletionDto } from '../../../notes/note.media-deletion.dto'; import { NoteMediaDeletionDto } from '../../../notes/note.media-deletion.dto';
@ -57,7 +50,7 @@ import { User } from '../../../users/user.entity';
import { import {
forbiddenDescription, forbiddenDescription,
successfullyDeletedDescription, successfullyDeletedDescription,
unauthorizedDescription, unauthorizedDescription
} from '../../utils/descriptions'; } from '../../utils/descriptions';
import { FullApi } from '../../utils/fullapi-decorator'; import { FullApi } from '../../utils/fullapi-decorator';
import { GetNoteInterceptor } from '../../utils/get-note.interceptor'; import { GetNoteInterceptor } from '../../utils/get-note.interceptor';

View file

@ -38,7 +38,7 @@ export class Group {
eager: true, eager: true,
}) })
@JoinTable() @JoinTable()
members: User[]; members: Promise<User[]>;
// eslint-disable-next-line @typescript-eslint/no-empty-function // eslint-disable-next-line @typescript-eslint/no-empty-function
private constructor() {} private constructor() {}
@ -52,7 +52,7 @@ export class Group {
newGroup.name = name; newGroup.name = name;
newGroup.displayName = displayName; newGroup.displayName = displayName;
newGroup.special = special; // this attribute should only be true for the two special groups newGroup.special = special; // this attribute should only be true for the two special groups
newGroup.members = []; newGroup.members = Promise.resolve([]);
return newGroup; return newGroup;
} }
} }

View file

@ -170,79 +170,79 @@ describe('PermissionsService', () => {
const notes = createNoteUserPermissionNotes(); const notes = createNoteUserPermissionNotes();
describe('mayRead works with', () => { describe('mayRead works with', () => {
it('Owner', () => { it('Owner', async () => {
permissionsService.guestPermission = GuestPermission.DENY; permissionsService.guestPermission = GuestPermission.DENY;
expect(permissionsService.mayRead(user1, notes[0])).toBeTruthy(); expect(await permissionsService.mayRead(user1, notes[0])).toBeTruthy();
expect(permissionsService.mayRead(user1, notes[7])).toBeFalsy(); expect(await permissionsService.mayRead(user1, notes[7])).toBeFalsy();
}); });
it('userPermission read', () => { it('userPermission read', async () => {
permissionsService.guestPermission = GuestPermission.DENY; permissionsService.guestPermission = GuestPermission.DENY;
expect(permissionsService.mayRead(user1, notes[1])).toBeTruthy(); expect(await permissionsService.mayRead(user1, notes[1])).toBeTruthy();
expect(permissionsService.mayRead(user1, notes[2])).toBeTruthy(); expect(await permissionsService.mayRead(user1, notes[2])).toBeTruthy();
expect(permissionsService.mayRead(user1, notes[3])).toBeTruthy(); expect(await permissionsService.mayRead(user1, notes[3])).toBeTruthy();
}); });
it('userPermission write', () => { it('userPermission write', async () => {
permissionsService.guestPermission = GuestPermission.DENY; permissionsService.guestPermission = GuestPermission.DENY;
expect(permissionsService.mayRead(user1, notes[4])).toBeTruthy(); expect(await permissionsService.mayRead(user1, notes[4])).toBeTruthy();
expect(permissionsService.mayRead(user1, notes[5])).toBeTruthy(); expect(await permissionsService.mayRead(user1, notes[5])).toBeTruthy();
expect(permissionsService.mayRead(user1, notes[6])).toBeTruthy(); expect(await permissionsService.mayRead(user1, notes[6])).toBeTruthy();
expect(permissionsService.mayRead(user1, notes[7])).toBeFalsy(); expect(await permissionsService.mayRead(user1, notes[7])).toBeFalsy();
}); });
describe('guest permission', () => { describe('guest permission', () => {
it('CREATE_ALIAS', () => { it('CREATE_ALIAS', async () => {
permissionsService.guestPermission = GuestPermission.CREATE_ALIAS; permissionsService.guestPermission = GuestPermission.CREATE_ALIAS;
expect(permissionsService.mayRead(null, notes[8])).toBeTruthy(); expect(await permissionsService.mayRead(null, notes[8])).toBeTruthy();
}); });
it('CREATE', () => { it('CREATE', async () => {
permissionsService.guestPermission = GuestPermission.CREATE; permissionsService.guestPermission = GuestPermission.CREATE;
expect(permissionsService.mayRead(null, notes[8])).toBeTruthy(); expect(await permissionsService.mayRead(null, notes[8])).toBeTruthy();
}); });
it('WRITE', () => { it('WRITE', async () => {
permissionsService.guestPermission = GuestPermission.WRITE; permissionsService.guestPermission = GuestPermission.WRITE;
expect(permissionsService.mayRead(null, notes[8])).toBeTruthy(); expect(await permissionsService.mayRead(null, notes[8])).toBeTruthy();
}); });
it('READ', () => { it('READ', async () => {
permissionsService.guestPermission = GuestPermission.READ; permissionsService.guestPermission = GuestPermission.READ;
expect(permissionsService.mayRead(null, notes[8])).toBeTruthy(); expect(await permissionsService.mayRead(null, notes[8])).toBeTruthy();
}); });
}); });
}); });
describe('mayWrite works with', () => { describe('mayWrite works with', () => {
it('Owner', () => { it('Owner', async () => {
permissionsService.guestPermission = GuestPermission.DENY; permissionsService.guestPermission = GuestPermission.DENY;
expect(permissionsService.mayWrite(user1, notes[0])).toBeTruthy(); expect(await permissionsService.mayWrite(user1, notes[0])).toBeTruthy();
expect(permissionsService.mayWrite(user1, notes[7])).toBeFalsy(); expect(await permissionsService.mayWrite(user1, notes[7])).toBeFalsy();
}); });
it('userPermission read', () => { it('userPermission read', async () => {
permissionsService.guestPermission = GuestPermission.DENY; permissionsService.guestPermission = GuestPermission.DENY;
expect(permissionsService.mayWrite(user1, notes[1])).toBeFalsy(); expect(await permissionsService.mayWrite(user1, notes[1])).toBeFalsy();
expect(permissionsService.mayWrite(user1, notes[2])).toBeFalsy(); expect(await permissionsService.mayWrite(user1, notes[2])).toBeFalsy();
expect(permissionsService.mayWrite(user1, notes[3])).toBeFalsy(); expect(await permissionsService.mayWrite(user1, notes[3])).toBeFalsy();
}); });
it('userPermission write', () => { it('userPermission write', async () => {
permissionsService.guestPermission = GuestPermission.DENY; permissionsService.guestPermission = GuestPermission.DENY;
expect(permissionsService.mayWrite(user1, notes[4])).toBeTruthy(); expect(await permissionsService.mayWrite(user1, notes[4])).toBeTruthy();
expect(permissionsService.mayWrite(user1, notes[5])).toBeTruthy(); expect(await permissionsService.mayWrite(user1, notes[5])).toBeTruthy();
expect(permissionsService.mayWrite(user1, notes[6])).toBeTruthy(); expect(await permissionsService.mayWrite(user1, notes[6])).toBeTruthy();
expect(permissionsService.mayWrite(user1, notes[7])).toBeFalsy(); expect(await permissionsService.mayWrite(user1, notes[7])).toBeFalsy();
}); });
describe('guest permission', () => { describe('guest permission', () => {
it('CREATE_ALIAS', () => { it('CREATE_ALIAS', async () => {
permissionsService.guestPermission = GuestPermission.CREATE_ALIAS; permissionsService.guestPermission = GuestPermission.CREATE_ALIAS;
expect(permissionsService.mayWrite(null, notes[9])).toBeTruthy(); expect(await permissionsService.mayWrite(null, notes[9])).toBeTruthy();
}); });
it('CREATE', () => { it('CREATE', async () => {
permissionsService.guestPermission = GuestPermission.CREATE; permissionsService.guestPermission = GuestPermission.CREATE;
expect(permissionsService.mayWrite(null, notes[9])).toBeTruthy(); expect(await permissionsService.mayWrite(null, notes[9])).toBeTruthy();
}); });
it('WRITE', () => { it('WRITE', async () => {
permissionsService.guestPermission = GuestPermission.WRITE; permissionsService.guestPermission = GuestPermission.WRITE;
expect(permissionsService.mayWrite(null, notes[9])).toBeTruthy(); expect(await permissionsService.mayWrite(null, notes[9])).toBeTruthy();
}); });
it('READ', () => { it('READ', async () => {
permissionsService.guestPermission = GuestPermission.READ; permissionsService.guestPermission = GuestPermission.READ;
expect(permissionsService.mayWrite(null, notes[9])).toBeFalsy(); expect(await permissionsService.mayWrite(null, notes[9])).toBeFalsy();
}); });
}); });
}); });
@ -277,11 +277,11 @@ describe('PermissionsService', () => {
result[SpecialGroup.LOGGED_IN] = loggedIn; result[SpecialGroup.LOGGED_IN] = loggedIn;
const user1group = Group.create('user1group', 'user1group', false) as Group; const user1group = Group.create('user1group', 'user1group', false) as Group;
user1group.members = [user1]; user1group.members = Promise.resolve([user1]);
result['user1group'] = user1group; result['user1group'] = user1group;
const user2group = Group.create('user2group', 'user2group', false) as Group; const user2group = Group.create('user2group', 'user2group', false) as Group;
user2group.members = [user2]; user2group.members = Promise.resolve([user2]);
result['user2group'] = user2group; result['user2group'] = user2group;
const user1and2group = Group.create( const user1and2group = Group.create(
@ -289,7 +289,7 @@ describe('PermissionsService', () => {
'user1and2group', 'user1and2group',
false, false,
) as Group; ) as Group;
user1and2group.members = [user1, user2]; user1and2group.members = Promise.resolve([user1, user2]);
result['user1and2group'] = user1and2group; result['user1and2group'] = user1and2group;
const user2and1group = Group.create( const user2and1group = Group.create(
@ -297,7 +297,7 @@ describe('PermissionsService', () => {
'user2and1group', 'user2and1group',
false, false,
) as Group; ) as Group;
user2and1group.members = [user2, user1]; user2and1group.members = Promise.resolve([user2, user1]);
result['user2and1group'] = user2and1group; result['user2and1group'] = user2and1group;
return result; return result;
@ -506,15 +506,15 @@ describe('PermissionsService', () => {
for (const perm of permission.permissions) { for (const perm of permission.permissions) {
permissionString += ` ${perm.group.name}:${String(perm.canEdit)}`; permissionString += ` ${perm.group.name}:${String(perm.canEdit)}`;
} }
it(`mayWrite - test #${i}:${permissionString}`, () => { it(`mayWrite - test #${i}:${permissionString}`, async () => {
permissionsService.guestPermission = guestPermission; permissionsService.guestPermission = guestPermission;
expect(permissionsService.mayWrite(user1, note)).toEqual( expect(await permissionsService.mayWrite(user1, note)).toEqual(
permission.allowsWrite, permission.allowsWrite,
); );
}); });
it(`mayRead - test #${i}:${permissionString}`, () => { it(`mayRead - test #${i}:${permissionString}`, async () => {
permissionsService.guestPermission = guestPermission; permissionsService.guestPermission = guestPermission;
expect(permissionsService.mayRead(user1, note)).toEqual( expect(await permissionsService.mayRead(user1, note)).toEqual(
permission.allowsRead, permission.allowsRead,
); );
}); });

View file

@ -21,24 +21,24 @@ export enum GuestPermission {
@Injectable() @Injectable()
export class PermissionsService { export class PermissionsService {
public guestPermission: GuestPermission; // TODO change to configOption public guestPermission: GuestPermission; // TODO change to configOption
mayRead(user: User | null, note: Note): boolean { async mayRead(user: User | null, note: Note): Promise<boolean> {
if (this.isOwner(user, note)) return true; if (this.isOwner(user, note)) return true;
if (this.hasPermissionUser(user, note, false)) return true; if (this.hasPermissionUser(user, note, false)) return true;
// noinspection RedundantIfStatementJS // noinspection RedundantIfStatementJS
if (this.hasPermissionGroup(user, note, false)) return true; if (await this.hasPermissionGroup(user, note, false)) return true;
return false; return false;
} }
mayWrite(user: User | null, note: Note): boolean { async mayWrite(user: User | null, note: Note): Promise<boolean> {
if (this.isOwner(user, note)) return true; if (this.isOwner(user, note)) return true;
if (this.hasPermissionUser(user, note, true)) return true; if (this.hasPermissionUser(user, note, true)) return true;
// noinspection RedundantIfStatementJS // noinspection RedundantIfStatementJS
if (this.hasPermissionGroup(user, note, true)) return true; if (await this.hasPermissionGroup(user, note, true)) return true;
return false; return false;
} }
@ -83,11 +83,11 @@ export class PermissionsService {
return false; return false;
} }
private hasPermissionGroup( private async hasPermissionGroup(
user: User | null, user: User | null,
note: Note, note: Note,
wantEdit: boolean, wantEdit: boolean,
): boolean { ): Promise<boolean> {
// TODO: Get real config value // TODO: Get real config value
let guestsAllowed = false; let guestsAllowed = false;
switch (this.guestPermission) { switch (this.guestPermission) {
@ -116,7 +116,7 @@ export class PermissionsService {
} else { } else {
// Handle normal groups // Handle normal groups
if (user) { if (user) {
for (const member of groupPermission.group.members) { for (const member of await groupPermission.group.members) {
if (member.id === user.id) return true; if (member.id === user.id) return true;
} }
} }