Add relation between User and Group

This represents the users which are members of this group

Signed-off-by: Yannick Bungers <git@innay.de>
This commit is contained in:
Yannick Bungers 2021-01-27 22:58:55 +01:00 committed by David Mehren
parent 8a33f75cf9
commit 68cbb5a9c2
No known key found for this signature in database
GPG key ID: 185982BA4C42B7C3
12 changed files with 103 additions and 16 deletions

View file

@ -119,6 +119,11 @@ entity "note_group_permission" {
*canEdit : boolean
}
entity "group_members_user" {
*group : number <<FK group>>
*member : uuid <<FK user>>
}
entity "tag" {
*id: number <<generated>>
*name: text
@ -144,16 +149,16 @@ entity "history_entry" {
user "1" -- "0..*" note: owner
user "1" -u- "1..*" identity
user "1" - "1..*" auth_token: authTokens
user "1" -l- "1..*" session
user "1" - "0..*" media_upload
user "1" -l- "1..*" auth_token: authTokens
user "1" -r- "1..*" session
user "1" -- "0..*" media_upload
user "1" - "0..*" history_entry
user "0..*" -- "0..*" note
user "1" - "0..*" authorship
user "1" -- "0..*" authorship
(user, note) . author_colors
revision "0..*" - "0..*" authorship
revision "0..*" -- "0..*" authorship
(revision, authorship) .. revision_authorship
media_upload "0..*" -- "1" note
@ -161,9 +166,11 @@ note "1" - "1..*" revision
note "1" - "0..*" history_entry
note "0..*" -l- "0..*" tag
note "0..*" -- "0..*" group
user "1..*" -- "0..*" group
user "0..*" -- "0..*" note
(user, note) . note_user_permission
(note, group) . note_group_permission
(user, group) . group_members_user
@enduml

View file

@ -20,6 +20,8 @@ import { User } from '../../../users/user.entity';
import { UsersModule } from '../../../users/users.module';
import { MeController } from './me.controller';
import { HistoryEntry } from '../../../history/history-entry.entity';
import { NoteGroupPermission } from '../../../permissions/note-group-permission.entity';
import { NoteUserPermission } from '../../../permissions/note-user-permission.entity';
describe('Me Controller', () => {
let controller: MeController;
@ -47,6 +49,10 @@ describe('Me Controller', () => {
.useValue({})
.overrideProvider(getRepositoryToken(HistoryEntry))
.useValue({})
.overrideProvider(getRepositoryToken(NoteGroupPermission))
.useValue({})
.overrideProvider(getRepositoryToken(NoteUserPermission))
.useValue({})
.compile();
controller = module.get<MeController>(MeController);

View file

@ -22,6 +22,8 @@ import { AuthToken } from '../../../auth/auth-token.entity';
import { Identity } from '../../../users/identity.entity';
import { User } from '../../../users/user.entity';
import { MediaController } from './media.controller';
import { NoteGroupPermission } from '../../../permissions/note-group-permission.entity';
import { NoteUserPermission } from '../../../permissions/note-user-permission.entity';
describe('Media Controller', () => {
let controller: MediaController;
@ -57,6 +59,10 @@ describe('Media Controller', () => {
.useValue({})
.overrideProvider(getRepositoryToken(Tag))
.useValue({})
.overrideProvider(getRepositoryToken(NoteGroupPermission))
.useValue({})
.overrideProvider(getRepositoryToken(NoteUserPermission))
.useValue({})
.compile();
controller = module.get<MediaController>(MediaController);

View file

@ -19,8 +19,11 @@ import { Identity } from '../../../users/identity.entity';
import { User } from '../../../users/user.entity';
import { UsersModule } from '../../../users/users.module';
import { NotesController } from './notes.controller';
import { PermissionsModule } from '../../../permissions/permissions.module';
import { HistoryModule } from '../../../history/history.module';
import { HistoryEntry } from '../../../history/history-entry.entity';
import { NoteGroupPermission } from '../../../permissions/note-group-permission.entity';
import { NoteUserPermission } from '../../../permissions/note-user-permission.entity';
describe('Notes Controller', () => {
let controller: NotesController;
@ -39,7 +42,13 @@ describe('Notes Controller', () => {
useValue: {},
},
],
imports: [RevisionsModule, UsersModule, LoggerModule, HistoryModule],
imports: [
RevisionsModule,
UsersModule,
LoggerModule,
PermissionsModule,
HistoryModule,
],
})
.overrideProvider(getRepositoryToken(Note))
.useValue({})
@ -61,6 +70,10 @@ describe('Notes Controller', () => {
.useValue({})
.overrideProvider(getRepositoryToken(HistoryEntry))
.useValue({})
.overrideProvider(getRepositoryToken(NoteGroupPermission))
.useValue({})
.overrideProvider(getRepositoryToken(NoteUserPermission))
.useValue({})
.compile();
controller = module.get<NotesController>(NotesController);

View file

@ -4,7 +4,14 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
import {
Column,
Entity,
JoinTable,
ManyToMany,
PrimaryGeneratedColumn,
} from 'typeorm';
import { User } from '../users/user.entity';
@Entity()
export class Group {
@ -26,4 +33,11 @@ export class Group {
*/
@Column()
special: boolean;
@ManyToMany((_) => User, (user) => user.groups, {
eager: true,
cascade: true,
})
@JoinTable()
members: User[];
}

View file

@ -21,6 +21,8 @@ import { AuthToken } from '../auth/auth-token.entity';
import { Revision } from '../revisions/revision.entity';
import { Repository } from 'typeorm';
import { NotInDBError } from '../errors/errors';
import { NoteGroupPermission } from '../permissions/note-group-permission.entity';
import { NoteUserPermission } from '../permissions/note-user-permission.entity';
describe('HistoryService', () => {
let service: HistoryService;
@ -54,6 +56,10 @@ describe('HistoryService', () => {
.useClass(Repository)
.overrideProvider(getRepositoryToken(Tag))
.useValue({})
.overrideProvider(getRepositoryToken(NoteGroupPermission))
.useValue({})
.overrideProvider(getRepositoryToken(NoteUserPermission))
.useValue({})
.compile();
service = module.get<HistoryService>(HistoryService);
@ -99,7 +105,7 @@ describe('HistoryService', () => {
describe('createOrUpdateHistoryEntry', () => {
describe('works', () => {
it('without an preexisting entry', async () => {
const user = new User();
const user = {} as User;
const alias = 'alias';
jest.spyOn(historyRepo, 'findOne').mockResolvedValueOnce(undefined);
jest
@ -118,7 +124,7 @@ describe('HistoryService', () => {
});
it('with an preexisting entry', async () => {
const user = new User();
const user = {} as User;
const alias = 'alias';
const historyEntry = HistoryEntry.create(
user,
@ -148,7 +154,7 @@ describe('HistoryService', () => {
describe('updateHistoryEntry', () => {
describe('works', () => {
it('with an entry', async () => {
const user = new User();
const user = {} as User;
const alias = 'alias';
const note = Note.create(user, alias);
const historyEntry = HistoryEntry.create(user, note);
@ -173,7 +179,7 @@ describe('HistoryService', () => {
});
it('without an entry', async () => {
const user = new User();
const user = {} as User;
const alias = 'alias';
const note = Note.create(user, alias);
jest.spyOn(historyRepo, 'findOne').mockResolvedValueOnce(undefined);
@ -192,7 +198,7 @@ describe('HistoryService', () => {
describe('deleteHistoryEntry', () => {
describe('works', () => {
it('with an entry', async () => {
const user = new User();
const user = {} as User;
const alias = 'alias';
const note = Note.create(user, alias);
const historyEntry = HistoryEntry.create(user, note);
@ -208,7 +214,7 @@ describe('HistoryService', () => {
});
it('without an entry', async () => {
const user = new User();
const user = {} as User;
const alias = 'alias';
const note = Note.create(user, alias);
jest.spyOn(historyRepo, 'findOne').mockResolvedValueOnce(undefined);
@ -225,7 +231,7 @@ describe('HistoryService', () => {
describe('toHistoryEntryDto', () => {
describe('works', () => {
it('with aliased note', async () => {
const user = new User();
const user = {} as User;
const alias = 'alias';
const title = 'title';
const tags = ['tag1', 'tag2'];
@ -247,7 +253,7 @@ describe('HistoryService', () => {
});
it('with regular note', async () => {
const user = new User();
const user = {} as User;
const title = 'title';
const id = 'id';
const tags = ['tag1', 'tag2'];

View file

@ -25,6 +25,8 @@ import { MediaService } from './media.service';
import { Repository } from 'typeorm';
import { promises as fs } from 'fs';
import { ClientError, NotInDBError, PermissionError } from '../errors/errors';
import { NoteGroupPermission } from '../permissions/note-group-permission.entity';
import { NoteUserPermission } from '../permissions/note-user-permission.entity';
describe('MediaService', () => {
let service: MediaService;
@ -70,6 +72,10 @@ describe('MediaService', () => {
.useClass(Repository)
.overrideProvider(getRepositoryToken(Tag))
.useValue({})
.overrideProvider(getRepositoryToken(NoteGroupPermission))
.useValue({})
.overrideProvider(getRepositoryToken(NoteUserPermission))
.useValue({})
.overrideProvider(getRepositoryToken(MediaUpload))
.useClass(Repository)
.compile();

View file

@ -13,10 +13,18 @@ import { AuthorColor } from './author-color.entity';
import { Note } from './note.entity';
import { NotesService } from './notes.service';
import { Tag } from './tag.entity';
import { NoteGroupPermission } from '../permissions/note-group-permission.entity';
import { NoteUserPermission } from '../permissions/note-user-permission.entity';
@Module({
imports: [
TypeOrmModule.forFeature([Note, AuthorColor, Tag]),
TypeOrmModule.forFeature([
Note,
AuthorColor,
Tag,
NoteGroupPermission,
NoteUserPermission,
]),
forwardRef(() => RevisionsModule),
UsersModule,
LoggerModule,

View file

@ -18,6 +18,8 @@ import { AuthorColor } from './author-color.entity';
import { Note } from './note.entity';
import { NotesService } from './notes.service';
import { Tag } from './tag.entity';
import { NoteGroupPermission } from '../permissions/note-group-permission.entity';
import { NoteUserPermission } from '../permissions/note-user-permission.entity';
describe('NotesService', () => {
let service: NotesService;
@ -53,6 +55,10 @@ describe('NotesService', () => {
.useValue({})
.overrideProvider(getRepositoryToken(Tag))
.useValue({})
.overrideProvider(getRepositoryToken(NoteGroupPermission))
.useValue({})
.overrideProvider(getRepositoryToken(NoteUserPermission))
.useValue({})
.compile();
service = module.get<NotesService>(NotesService);
});

View file

@ -159,6 +159,7 @@ export class NotesService {
historyEntries: [],
updatedAt: new Date(),
userName: 'Testy',
groups: [],
},
description: 'Very descriptive text.',
userPermissions: [],

View file

@ -17,6 +17,8 @@ import { Authorship } from './authorship.entity';
import { Revision } from './revision.entity';
import { RevisionsService } from './revisions.service';
import { Tag } from '../notes/tag.entity';
import { NoteGroupPermission } from '../permissions/note-group-permission.entity';
import { NoteUserPermission } from '../permissions/note-user-permission.entity';
describe('RevisionsService', () => {
let service: RevisionsService;
@ -48,6 +50,10 @@ describe('RevisionsService', () => {
.useValue({})
.overrideProvider(getRepositoryToken(Tag))
.useValue({})
.overrideProvider(getRepositoryToken(NoteGroupPermission))
.useValue({})
.overrideProvider(getRepositoryToken(NoteUserPermission))
.useValue({})
.compile();
service = module.get<RevisionsService>(RevisionsService);

View file

@ -7,6 +7,7 @@
import {
CreateDateColumn,
Entity,
ManyToMany,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
@ -14,6 +15,7 @@ import { Column, OneToMany } from 'typeorm';
import { Note } from '../notes/note.entity';
import { AuthToken } from '../auth/auth-token.entity';
import { Identity } from './identity.entity';
import { Group } from '../groups/group.entity';
import { HistoryEntry } from '../history/history-entry.entity';
@Entity()
@ -52,9 +54,15 @@ export class User {
@OneToMany((_) => Identity, (identity) => identity.user)
identities: Identity[];
@ManyToMany((_) => Group, (group) => group.members)
groups: Group[];
@OneToMany((_) => HistoryEntry, (historyEntry) => historyEntry.user)
historyEntries: HistoryEntry[];
// eslint-disable-next-line @typescript-eslint/no-empty-function
private constructor() {}
public static create(
userName: string,
displayName: string,