mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-25 19:26:31 -05:00
refactor(group): lazy-load relations
Signed-off-by: David Mehren <git@herrmehren.de>
This commit is contained in:
parent
5d7b544e1f
commit
0c5fdf4201
5 changed files with 64 additions and 75 deletions
|
@ -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';
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue