mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-28 22:15:12 -04:00
Merge pull request #1794 from hedgedoc/addSpecialGroups
This commit is contained in:
commit
bb7561b9ad
9 changed files with 139 additions and 17 deletions
|
@ -9,7 +9,7 @@ import { getRepositoryToken } from '@nestjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
|
|
||||||
import appConfigMock from '../config/mock/app.config.mock';
|
import appConfigMock from '../config/mock/app.config.mock';
|
||||||
import { NotInDBError } from '../errors/errors';
|
import { AlreadyInDBError, NotInDBError } from '../errors/errors';
|
||||||
import { LoggerModule } from '../logger/logger.module';
|
import { LoggerModule } from '../logger/logger.module';
|
||||||
import { Group } from './group.entity';
|
import { Group } from './group.entity';
|
||||||
import { GroupsService } from './groups.service';
|
import { GroupsService } from './groups.service';
|
||||||
|
@ -46,6 +46,33 @@ describe('GroupsService', () => {
|
||||||
expect(service).toBeDefined();
|
expect(service).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('createGroup', () => {
|
||||||
|
const groupName = 'testGroup';
|
||||||
|
const displayname = 'Group Test';
|
||||||
|
beforeEach(() => {
|
||||||
|
jest
|
||||||
|
.spyOn(groupRepo, 'save')
|
||||||
|
.mockImplementationOnce(async (group: Group): Promise<Group> => group);
|
||||||
|
});
|
||||||
|
it('successfully creates a group', async () => {
|
||||||
|
const user = await service.createGroup(groupName, displayname);
|
||||||
|
expect(user.name).toEqual(groupName);
|
||||||
|
expect(user.displayName).toEqual(displayname);
|
||||||
|
});
|
||||||
|
it('fails if group name is already taken', async () => {
|
||||||
|
// add additional mock implementation for failure
|
||||||
|
jest.spyOn(groupRepo, 'save').mockImplementationOnce(() => {
|
||||||
|
throw new Error();
|
||||||
|
});
|
||||||
|
// create first group with group name
|
||||||
|
await service.createGroup(groupName, displayname);
|
||||||
|
// attempt to create second group with group name
|
||||||
|
await expect(service.createGroup(groupName, displayname)).rejects.toThrow(
|
||||||
|
AlreadyInDBError,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('getGroupByName', () => {
|
describe('getGroupByName', () => {
|
||||||
it('works', async () => {
|
it('works', async () => {
|
||||||
jest.spyOn(groupRepo, 'findOne').mockResolvedValueOnce(group);
|
jest.spyOn(groupRepo, 'findOne').mockResolvedValueOnce(group);
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { Injectable } from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
|
|
||||||
import { NotInDBError } from '../errors/errors';
|
import { AlreadyInDBError, NotInDBError } from '../errors/errors';
|
||||||
import { ConsoleLoggerService } from '../logger/console-logger.service';
|
import { ConsoleLoggerService } from '../logger/console-logger.service';
|
||||||
import { GroupInfoDto } from './group-info.dto';
|
import { GroupInfoDto } from './group-info.dto';
|
||||||
import { Group } from './group.entity';
|
import { Group } from './group.entity';
|
||||||
|
@ -21,6 +21,35 @@ export class GroupsService {
|
||||||
this.logger.setContext(GroupsService.name);
|
this.logger.setContext(GroupsService.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @async
|
||||||
|
* Create a new group with a given name and displayName
|
||||||
|
* @param name - the group name the new group shall have
|
||||||
|
* @param displayName - the display name the new group shall have
|
||||||
|
* @param special - if the group is special or not
|
||||||
|
* @return {Group} the group
|
||||||
|
* @throws {AlreadyInDBError} the group name is already taken.
|
||||||
|
*/
|
||||||
|
async createGroup(
|
||||||
|
name: string,
|
||||||
|
displayName: string,
|
||||||
|
special = false,
|
||||||
|
): Promise<Group> {
|
||||||
|
const group = Group.create(name, displayName);
|
||||||
|
group.special = special;
|
||||||
|
try {
|
||||||
|
return await this.groupRepository.save(group);
|
||||||
|
} catch {
|
||||||
|
this.logger.debug(
|
||||||
|
`A group with the name '${name}' already exists.`,
|
||||||
|
'createGroup',
|
||||||
|
);
|
||||||
|
throw new AlreadyInDBError(
|
||||||
|
`A group with the name '${name}' already exists.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @async
|
* @async
|
||||||
* Get a group by their name.
|
* Get a group by their name.
|
||||||
|
|
10
src/groups/groups.special.ts
Normal file
10
src/groups/groups.special.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
export enum SpecialGroup {
|
||||||
|
LOGGED_IN = '_LOGGED_IN',
|
||||||
|
EVERYONE = '_EVERYONE',
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ import { AuthConfig } from './config/auth.config';
|
||||||
import { MediaConfig } from './config/media.config';
|
import { MediaConfig } from './config/media.config';
|
||||||
import { ConsoleLoggerService } from './logger/console-logger.service';
|
import { ConsoleLoggerService } from './logger/console-logger.service';
|
||||||
import { BackendType } from './media/backends/backend-type.enum';
|
import { BackendType } from './media/backends/backend-type.enum';
|
||||||
|
import { setupSpecialGroups } from './utils/createSpecialGroups';
|
||||||
import { setupFrontendProxy } from './utils/frontend-integration';
|
import { setupFrontendProxy } from './utils/frontend-integration';
|
||||||
import { setupSessionMiddleware } from './utils/session';
|
import { setupSessionMiddleware } from './utils/session';
|
||||||
import { setupValidationPipe } from './utils/setup-pipes';
|
import { setupValidationPipe } from './utils/setup-pipes';
|
||||||
|
@ -51,6 +52,8 @@ async function bootstrap(): Promise<void> {
|
||||||
setupFrontendProxy(app, logger);
|
setupFrontendProxy(app, logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await setupSpecialGroups(app);
|
||||||
|
|
||||||
setupSessionMiddleware(app, authConfig);
|
setupSessionMiddleware(app, authConfig);
|
||||||
|
|
||||||
app.enableCors({
|
app.enableCors({
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { AuthToken } from '../auth/auth-token.entity';
|
||||||
import { Author } from '../authors/author.entity';
|
import { Author } from '../authors/author.entity';
|
||||||
import appConfigMock from '../config/mock/app.config.mock';
|
import appConfigMock from '../config/mock/app.config.mock';
|
||||||
import { Group } from '../groups/group.entity';
|
import { Group } from '../groups/group.entity';
|
||||||
|
import { SpecialGroup } from '../groups/groups.special';
|
||||||
import { Identity } from '../identity/identity.entity';
|
import { Identity } from '../identity/identity.entity';
|
||||||
import { LoggerModule } from '../logger/logger.module';
|
import { LoggerModule } from '../logger/logger.module';
|
||||||
import { Alias } from '../notes/alias.entity';
|
import { Alias } from '../notes/alias.entity';
|
||||||
|
@ -134,7 +135,7 @@ describe('PermissionsService', () => {
|
||||||
note7.userPermissions.push(noteUserPermission2);
|
note7.userPermissions.push(noteUserPermission2);
|
||||||
|
|
||||||
const everybody = {} as Group;
|
const everybody = {} as Group;
|
||||||
everybody.name = 'everybody';
|
everybody.name = SpecialGroup.EVERYONE;
|
||||||
everybody.special = true;
|
everybody.special = true;
|
||||||
const noteEverybodyRead = createNote(user1);
|
const noteEverybodyRead = createNote(user1);
|
||||||
|
|
||||||
|
@ -261,13 +262,19 @@ describe('PermissionsService', () => {
|
||||||
function createGroups(): { [id: string]: Group } {
|
function createGroups(): { [id: string]: Group } {
|
||||||
const result: { [id: string]: Group } = {};
|
const result: { [id: string]: Group } = {};
|
||||||
|
|
||||||
const everybody: Group = Group.create('everybody', 'Everybody');
|
const everybody: Group = Group.create(
|
||||||
|
SpecialGroup.EVERYONE,
|
||||||
|
SpecialGroup.EVERYONE,
|
||||||
|
);
|
||||||
everybody.special = true;
|
everybody.special = true;
|
||||||
result['everybody'] = everybody;
|
result[SpecialGroup.EVERYONE] = everybody;
|
||||||
|
|
||||||
const loggedIn = Group.create('loggedIn', 'loggedIn');
|
const loggedIn = Group.create(
|
||||||
|
SpecialGroup.LOGGED_IN,
|
||||||
|
SpecialGroup.LOGGED_IN,
|
||||||
|
);
|
||||||
loggedIn.special = true;
|
loggedIn.special = true;
|
||||||
result['loggedIn'] = loggedIn;
|
result[SpecialGroup.LOGGED_IN] = loggedIn;
|
||||||
|
|
||||||
const user1group = Group.create('user1group', 'user1group');
|
const user1group = Group.create('user1group', 'user1group');
|
||||||
user1group.members = [user1];
|
user1group.members = [user1];
|
||||||
|
@ -304,11 +311,23 @@ describe('PermissionsService', () => {
|
||||||
return NoteGroupPermission.create(group, write);
|
return NoteGroupPermission.create(group, write);
|
||||||
}
|
}
|
||||||
|
|
||||||
const everybodyRead = createNoteGroupPermission(groups['everybody'], false);
|
const everybodyRead = createNoteGroupPermission(
|
||||||
const everybodyWrite = createNoteGroupPermission(groups['everybody'], true);
|
groups[SpecialGroup.EVERYONE],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
const everybodyWrite = createNoteGroupPermission(
|
||||||
|
groups[SpecialGroup.EVERYONE],
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
const loggedInRead = createNoteGroupPermission(groups['loggedIn'], false);
|
const loggedInRead = createNoteGroupPermission(
|
||||||
const loggedInWrite = createNoteGroupPermission(groups['loggedIn'], true);
|
groups[SpecialGroup.LOGGED_IN],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
const loggedInWrite = createNoteGroupPermission(
|
||||||
|
groups[SpecialGroup.LOGGED_IN],
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
const user1groupRead = createNoteGroupPermission(
|
const user1groupRead = createNoteGroupPermission(
|
||||||
groups['user1group'],
|
groups['user1group'],
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
*/
|
*/
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { SpecialGroup } from '../groups/groups.special';
|
||||||
import { Note } from '../notes/note.entity';
|
import { Note } from '../notes/note.entity';
|
||||||
import { User } from '../users/user.entity';
|
import { User } from '../users/user.entity';
|
||||||
|
|
||||||
|
@ -102,16 +103,14 @@ export class PermissionsService {
|
||||||
if (groupPermission.canEdit || !wantEdit) {
|
if (groupPermission.canEdit || !wantEdit) {
|
||||||
// Handle special groups
|
// Handle special groups
|
||||||
if (groupPermission.group.special) {
|
if (groupPermission.group.special) {
|
||||||
if (groupPermission.group.name == 'loggedIn') {
|
if (groupPermission.group.name == SpecialGroup.LOGGED_IN) {
|
||||||
// TODO: Name of group for logged in users
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
groupPermission.group.name == 'everybody' &&
|
groupPermission.group.name == SpecialGroup.EVERYONE &&
|
||||||
(groupPermission.canEdit || !wantEdit) &&
|
(groupPermission.canEdit || !wantEdit) &&
|
||||||
guestsAllowed
|
guestsAllowed
|
||||||
) {
|
) {
|
||||||
// TODO: Name of group in which everybody even guests can edit
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -52,12 +52,13 @@ describe('UsersService', () => {
|
||||||
.spyOn(userRepo, 'save')
|
.spyOn(userRepo, 'save')
|
||||||
.mockImplementationOnce(async (user: User): Promise<User> => user);
|
.mockImplementationOnce(async (user: User): Promise<User> => user);
|
||||||
});
|
});
|
||||||
it('works', async () => {
|
it('successfully creates a user', async () => {
|
||||||
const user = await service.createUser(username, displayname);
|
const user = await service.createUser(username, displayname);
|
||||||
expect(user.username).toEqual(username);
|
expect(user.username).toEqual(username);
|
||||||
expect(user.displayName).toEqual(displayname);
|
expect(user.displayName).toEqual(displayname);
|
||||||
});
|
});
|
||||||
it('fails if username is already taken', async () => {
|
it('fails if username is already taken', async () => {
|
||||||
|
// add additional mock implementation for failure
|
||||||
jest.spyOn(userRepo, 'save').mockImplementationOnce(() => {
|
jest.spyOn(userRepo, 'save').mockImplementationOnce(() => {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
});
|
});
|
||||||
|
|
|
@ -26,7 +26,7 @@ export class UsersService {
|
||||||
* @async
|
* @async
|
||||||
* Create a new user with a given username and displayName
|
* Create a new user with a given username and displayName
|
||||||
* @param username - the username the new user shall have
|
* @param username - the username the new user shall have
|
||||||
* @param displayName - the display the new user shall have
|
* @param displayName - the display name the new user shall have
|
||||||
* @return {User} the user
|
* @return {User} the user
|
||||||
* @throws {AlreadyInDBError} the username is already taken.
|
* @throws {AlreadyInDBError} the username is already taken.
|
||||||
*/
|
*/
|
||||||
|
|
34
src/utils/createSpecialGroups.ts
Normal file
34
src/utils/createSpecialGroups.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
import { NestExpressApplication } from '@nestjs/platform-express';
|
||||||
|
|
||||||
|
import { AlreadyInDBError } from '../errors/errors';
|
||||||
|
import { GroupsService } from '../groups/groups.service';
|
||||||
|
import { SpecialGroup } from '../groups/groups.special';
|
||||||
|
|
||||||
|
export async function setupSpecialGroups(
|
||||||
|
app: NestExpressApplication,
|
||||||
|
): Promise<void> {
|
||||||
|
const groupService = app.get<GroupsService>(GroupsService);
|
||||||
|
try {
|
||||||
|
await groupService.createGroup(
|
||||||
|
SpecialGroup.EVERYONE,
|
||||||
|
SpecialGroup.EVERYONE,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
await groupService.createGroup(
|
||||||
|
SpecialGroup.LOGGED_IN,
|
||||||
|
SpecialGroup.LOGGED_IN,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof AlreadyInDBError) {
|
||||||
|
// It's no problem if the special groups already exist
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue