From a6db175995e5e7c0b8119b75cf44d9c4c26062ac Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Mon, 11 Nov 2024 17:39:37 +0100 Subject: [PATCH 01/60] add schoolId to room --- .../room/api/dto/request/create-room.body.params.ts | 2 +- .../room/api/dto/response/room-details.response.ts | 4 ++++ .../room/api/dto/response/room-item.response.ts | 4 ++++ apps/server/src/modules/room/api/mapper/room.mapper.ts | 2 ++ apps/server/src/modules/room/api/room.uc.ts | 10 ++++++---- .../src/modules/room/api/test/room-get.api.spec.ts | 1 + .../src/modules/room/api/test/room-index.api.spec.ts | 2 ++ apps/server/src/modules/room/domain/do/room.do.ts | 9 +++++++-- .../server/src/modules/room/repo/entity/room.entity.ts | 5 +++++ .../src/modules/room/testing/room-entity.factory.ts | 1 + apps/server/src/modules/room/testing/room.factory.ts | 1 + 11 files changed, 34 insertions(+), 7 deletions(-) diff --git a/apps/server/src/modules/room/api/dto/request/create-room.body.params.ts b/apps/server/src/modules/room/api/dto/request/create-room.body.params.ts index 286abeba50c..d21d64fd10a 100644 --- a/apps/server/src/modules/room/api/dto/request/create-room.body.params.ts +++ b/apps/server/src/modules/room/api/dto/request/create-room.body.params.ts @@ -4,7 +4,7 @@ import { RoomCreateProps } from '@src/modules/room/domain'; import { RoomColor } from '@src/modules/room/domain/type'; import { IsDate, IsEnum, IsOptional, IsString, MaxLength, MinLength } from 'class-validator'; -export class CreateRoomBodyParams implements RoomCreateProps { +export class CreateRoomBodyParams implements Omit { @ApiProperty({ description: 'The name of the room', required: true, diff --git a/apps/server/src/modules/room/api/dto/response/room-details.response.ts b/apps/server/src/modules/room/api/dto/response/room-details.response.ts index f0d39b68284..197c1763206 100644 --- a/apps/server/src/modules/room/api/dto/response/room-details.response.ts +++ b/apps/server/src/modules/room/api/dto/response/room-details.response.ts @@ -13,6 +13,9 @@ export class RoomDetailsResponse { @IsEnum(RoomColor) color: RoomColor; + @ApiProperty() + schoolId: string; + @ApiPropertyOptional({ type: Date }) startDate?: Date; @@ -29,6 +32,7 @@ export class RoomDetailsResponse { this.id = room.id; this.name = room.name; this.color = room.color; + this.schoolId = room.schoolId; this.startDate = room.startDate; this.endDate = room.endDate; diff --git a/apps/server/src/modules/room/api/dto/response/room-item.response.ts b/apps/server/src/modules/room/api/dto/response/room-item.response.ts index 88b13ec3dab..3c8bffded23 100644 --- a/apps/server/src/modules/room/api/dto/response/room-item.response.ts +++ b/apps/server/src/modules/room/api/dto/response/room-item.response.ts @@ -13,6 +13,9 @@ export class RoomItemResponse { @IsEnum(RoomColor) color: RoomColor; + @ApiProperty() + schoolId: string; + @ApiPropertyOptional({ type: Date }) startDate?: Date; @@ -29,6 +32,7 @@ export class RoomItemResponse { this.id = room.id; this.name = room.name; this.color = room.color; + this.schoolId = room.schoolId; this.startDate = room.startDate; this.endDate = room.endDate; diff --git a/apps/server/src/modules/room/api/mapper/room.mapper.ts b/apps/server/src/modules/room/api/mapper/room.mapper.ts index 02fd43a659f..4b69e2a34ef 100644 --- a/apps/server/src/modules/room/api/mapper/room.mapper.ts +++ b/apps/server/src/modules/room/api/mapper/room.mapper.ts @@ -14,6 +14,7 @@ export class RoomMapper { id: room.id, name: room.name, color: room.color, + schoolId: room.schoolId, startDate: room.startDate, endDate: room.endDate, createdAt: room.createdAt, @@ -37,6 +38,7 @@ export class RoomMapper { id: room.id, name: room.name, color: room.color, + schoolId: room.schoolId, startDate: room.startDate, endDate: room.endDate, createdAt: room.createdAt, diff --git a/apps/server/src/modules/room/api/room.uc.ts b/apps/server/src/modules/room/api/room.uc.ts index 1691df897a9..d7b5ef8e3a1 100644 --- a/apps/server/src/modules/room/api/room.uc.ts +++ b/apps/server/src/modules/room/api/room.uc.ts @@ -8,8 +8,10 @@ import { Page, UserDO } from '@shared/domain/domainobject'; import { IFindOptions, Permission, RoleName, RoomRole } from '@shared/domain/interface'; import { EntityId } from '@shared/domain/types'; import { BoardExternalReferenceType, ColumnBoard, ColumnBoardService } from '@src/modules/board'; -import { Room, RoomCreateProps, RoomService, RoomUpdateProps } from '../domain'; +import { Room, RoomService } from '../domain'; import { RoomConfig } from '../room.config'; +import { CreateRoomBodyParams } from './dto/request/create-room.body.params'; +import { UpdateRoomBodyParams } from './dto/request/update-room.body.params'; import { RoomMemberResponse } from './dto/response/room-member.response'; @Injectable() @@ -31,11 +33,11 @@ export class RoomUc { return rooms; } - public async createRoom(userId: EntityId, props: RoomCreateProps): Promise { + public async createRoom(userId: EntityId, props: CreateRoomBodyParams): Promise { this.checkFeatureEnabled(); const user = await this.authorizationService.getUserWithPermissions(userId); - const room = await this.roomService.createRoom(props); + const room = await this.roomService.createRoom({ ...props, schoolId: user.school.id }); // NOTE: currently only teacher are allowed to create rooms. Could not find simpler way to check this. this.authorizationService.checkOneOfPermissions(user, [Permission.COURSE_CREATE]); await this.roomMemberService @@ -72,7 +74,7 @@ export class RoomUc { return boards; } - public async updateRoom(userId: EntityId, roomId: EntityId, props: RoomUpdateProps): Promise { + public async updateRoom(userId: EntityId, roomId: EntityId, props: UpdateRoomBodyParams): Promise { this.checkFeatureEnabled(); const room = await this.roomService.getSingleRoom(roomId); diff --git a/apps/server/src/modules/room/api/test/room-get.api.spec.ts b/apps/server/src/modules/room/api/test/room-get.api.spec.ts index fe842db3d7f..ef4b1462ebb 100644 --- a/apps/server/src/modules/room/api/test/room-get.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-get.api.spec.ts @@ -114,6 +114,7 @@ describe('Room Controller (API)', () => { id: room.id, name: room.name, color: room.color, + schoolId: room.schoolId, startDate: room.startDate?.toISOString(), endDate: room.endDate?.toISOString(), createdAt: room.createdAt.toISOString(), diff --git a/apps/server/src/modules/room/api/test/room-index.api.spec.ts b/apps/server/src/modules/room/api/test/room-index.api.spec.ts index ca0a1c22658..e43d1ef113f 100644 --- a/apps/server/src/modules/room/api/test/room-index.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-index.api.spec.ts @@ -86,6 +86,7 @@ describe('Room Controller (API)', () => { id: room.id, name: room.name, color: room.color, + schoolId: room.schoolId, startDate: room.startDate?.toISOString(), endDate: room.endDate?.toISOString(), createdAt: room.createdAt.toISOString(), @@ -152,6 +153,7 @@ describe('Room Controller (API)', () => { id: room.id, name: room.name, color: room.color, + schoolId: room.schoolId, startDate: room.startDate?.toISOString(), endDate: room.endDate?.toISOString(), createdAt: room.createdAt.toISOString(), diff --git a/apps/server/src/modules/room/domain/do/room.do.ts b/apps/server/src/modules/room/domain/do/room.do.ts index 05feb9d07d4..e5ee61ad6da 100644 --- a/apps/server/src/modules/room/domain/do/room.do.ts +++ b/apps/server/src/modules/room/domain/do/room.do.ts @@ -9,12 +9,13 @@ export interface RoomProps extends AuthorizableObject { color: RoomColor; startDate?: Date; endDate?: Date; + schoolId: EntityId; createdAt: Date; updatedAt: Date; } -export type RoomCreateProps = Pick; -export type RoomUpdateProps = RoomCreateProps; // will probably change in the future +export type RoomCreateProps = Pick; +export type RoomUpdateProps = Omit; export class Room extends DomainObject { public constructor(props: RoomProps) { @@ -48,6 +49,10 @@ export class Room extends DomainObject { this.props.color = value; } + public get schoolId(): EntityId { + return this.props.schoolId; + } + public get startDate(): Date | undefined { return this.props.startDate; } diff --git a/apps/server/src/modules/room/repo/entity/room.entity.ts b/apps/server/src/modules/room/repo/entity/room.entity.ts index 3a174be1d9d..a44cf367482 100644 --- a/apps/server/src/modules/room/repo/entity/room.entity.ts +++ b/apps/server/src/modules/room/repo/entity/room.entity.ts @@ -1,5 +1,7 @@ import { Entity, Property } from '@mikro-orm/core'; import { BaseEntityWithTimestamps } from '@shared/domain/entity/base.entity'; +import { EntityId } from '@shared/domain/types'; +import { ObjectIdType } from '@shared/repo/types/object-id.type'; import { Room, RoomProps } from '../../domain/do/room.do'; import { RoomColor } from '../../domain/type'; @@ -11,6 +13,9 @@ export class RoomEntity extends BaseEntityWithTimestamps implements RoomProps { @Property({ nullable: false }) color!: RoomColor; + @Property({ type: ObjectIdType, nullable: false }) + schoolId!: EntityId; + @Property({ nullable: true }) startDate?: Date; diff --git a/apps/server/src/modules/room/testing/room-entity.factory.ts b/apps/server/src/modules/room/testing/room-entity.factory.ts index fee0b2c80b0..ad2e979750e 100644 --- a/apps/server/src/modules/room/testing/room-entity.factory.ts +++ b/apps/server/src/modules/room/testing/room-entity.factory.ts @@ -9,6 +9,7 @@ export const roomEntityFactory = EntityFactory.define(Roo id: new ObjectId().toHexString(), name: `room #${sequence}`, color: [RoomColor.BLUE, RoomColor.RED, RoomColor.GREEN, RoomColor.MAGENTA][Math.floor(Math.random() * 4)], + schoolId: new ObjectId().toHexString(), startDate: new Date(), endDate: new Date(Date.now() + 1000 * 60 * 60 * 24 * 7), createdAt: new Date(), diff --git a/apps/server/src/modules/room/testing/room.factory.ts b/apps/server/src/modules/room/testing/room.factory.ts index 099c98b831c..7f1ef879488 100644 --- a/apps/server/src/modules/room/testing/room.factory.ts +++ b/apps/server/src/modules/room/testing/room.factory.ts @@ -8,6 +8,7 @@ export const roomFactory = BaseFactory.define(Room, ({ sequence id: new ObjectId().toHexString(), name: `room #${sequence}`, color: [RoomColor.BLUE, RoomColor.RED, RoomColor.GREEN, RoomColor.MAGENTA][Math.floor(Math.random() * 4)], + schoolId: new ObjectId().toHexString(), startDate: new Date(), createdAt: new Date(), updatedAt: new Date(), From b320a19eac98f2981b88793c1345c79727d6bb7e Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Mon, 11 Nov 2024 18:04:28 +0100 Subject: [PATCH 02/60] rename room roles - remove underscore --- .../mikro-orm/Migration202411111604124.ts | 27 +++++++++++++++++++ .../shared/domain/interface/rolename.enum.ts | 4 +-- backup/setup/migrations.json | 27 +++++++++++++++++++ backup/setup/roles.json | 4 +-- 4 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 apps/server/src/migrations/mikro-orm/Migration202411111604124.ts diff --git a/apps/server/src/migrations/mikro-orm/Migration202411111604124.ts b/apps/server/src/migrations/mikro-orm/Migration202411111604124.ts new file mode 100644 index 00000000000..e642e195e69 --- /dev/null +++ b/apps/server/src/migrations/mikro-orm/Migration202411111604124.ts @@ -0,0 +1,27 @@ +import { Migration } from '@mikro-orm/migrations-mongodb'; + +export class Migration20241111160412 extends Migration { + async up(): Promise { + // Rename ROOM_VIEWER role from room_viewer to roomviewer + await this.getCollection('roles').updateMany({ name: 'room_viewer' }, { $set: { name: 'roomviewer' } }); + + console.info('Renamed ROOM_VIEWER role from room_viewer to roomviewer'); + + // Rename ROOM_EDITOR role from room_editor to roomeditor + await this.getCollection('roles').updateMany({ name: 'room_editor' }, { $set: { name: 'roomeditor' } }); + + console.info('Renamed ROOM_EDITOR role from room_editor to roomeditor'); + } + + async down(): Promise { + // Rename ROOM_VIEWER role from roomviewer to room_viewer + await this.getCollection('roles').updateMany({ name: 'roomviewer' }, { $set: { name: 'room_viewer' } }); + + console.info('Rollback: Renamed ROOM_VIEWER role from roomviewer to room_viewer'); + + // Rename ROOM_EDITOR role from roomeditor to room_editor + await this.getCollection('roles').updateMany({ name: 'roomeditor' }, { $set: { name: 'room_editor' } }); + + console.info('Rollback: Renamed ROOM_EDITOR role from roomeditor to room_editor'); + } +} diff --git a/apps/server/src/shared/domain/interface/rolename.enum.ts b/apps/server/src/shared/domain/interface/rolename.enum.ts index cd54427d653..1d06a0207ac 100644 --- a/apps/server/src/shared/domain/interface/rolename.enum.ts +++ b/apps/server/src/shared/domain/interface/rolename.enum.ts @@ -9,8 +9,8 @@ export enum RoleName { DEMOTEACHER = 'demoTeacher', EXPERT = 'expert', HELPDESK = 'helpdesk', - ROOM_VIEWER = 'room_viewer', - ROOM_EDITOR = 'room_editor', + ROOM_VIEWER = 'roomviewer', + ROOM_EDITOR = 'roomeditor', STUDENT = 'student', SUPERHERO = 'superhero', TEACHER = 'teacher', diff --git a/backup/setup/migrations.json b/backup/setup/migrations.json index f748b3a1c23..820e08a4efa 100644 --- a/backup/setup/migrations.json +++ b/backup/setup/migrations.json @@ -259,5 +259,32 @@ "created_at": { "$date": "2024-10-30T17:03:31.473Z" } + }, + { + "_id": { + "$oid": "673237e9b0955dcff4cde3d9" + }, + "name": "Migration20241111160412", + "created_at": { + "$date": "2024-11-11T16:59:21.768Z" + } + }, + { + "_id": { + "$oid": "673237e9b0955dcff4cde3da" + }, + "name": "Migration202411111604124", + "created_at": { + "$date": "2024-11-11T16:59:21.774Z" + } + }, + { + "_id": { + "$oid": "673237e9b0955dcff4cde3db" + }, + "name": "Migration2024111116041242", + "created_at": { + "$date": "2024-11-11T16:59:21.776Z" + } } ] diff --git a/backup/setup/roles.json b/backup/setup/roles.json index 243ac2ca7ad..9dc1595c2b6 100644 --- a/backup/setup/roles.json +++ b/backup/setup/roles.json @@ -586,7 +586,7 @@ "_id": { "$oid": "6720b8621b61c9dd7ebd193b" }, - "name": "room_viewer", + "name": "roomviewer", "permissions": [ "ROOM_VIEW" ] @@ -595,7 +595,7 @@ "_id": { "$oid": "6720b8621b61c9dd7ebd193c" }, - "name": "room_editor", + "name": "roomeditor", "permissions": [ "ROOM_VIEW", "ROOM_EDIT" From b290e4a127a9af4cce373f0c1cf1207d8958a773 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 12 Nov 2024 17:15:50 +0100 Subject: [PATCH 03/60] fix test --- .../server/src/modules/room/repo/room-domain.mapper.spec.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/server/src/modules/room/repo/room-domain.mapper.spec.ts b/apps/server/src/modules/room/repo/room-domain.mapper.spec.ts index 22f25ad841c..8de67527eed 100644 --- a/apps/server/src/modules/room/repo/room-domain.mapper.spec.ts +++ b/apps/server/src/modules/room/repo/room-domain.mapper.spec.ts @@ -1,3 +1,4 @@ +import { ObjectId } from '@mikro-orm/mongodb'; import { Room, RoomProps } from '../domain/do/room.do'; import { RoomColor } from '../domain/type'; import { roomEntityFactory } from '../testing'; @@ -32,6 +33,7 @@ describe('RoomDomainMapper', () => { id: '1', name: 'Existing Room', color: RoomColor.GREEN, + schoolId: new ObjectId().toHexString(), startDate: new Date('2023-01-01'), endDate: new Date('2023-12-31'), createdAt: new Date('2023-01-01'), @@ -42,6 +44,7 @@ describe('RoomDomainMapper', () => { id: '2', name: 'Test Room', color: RoomColor.RED, + schoolId: new ObjectId().toHexString(), startDate: new Date('2023-02-01'), endDate: new Date('2023-11-30'), domainObject: existingRoom, @@ -55,6 +58,7 @@ describe('RoomDomainMapper', () => { id: '1', name: 'Existing Room', color: RoomColor.GREEN, + schoolId: existingRoom.schoolId, startDate: new Date('2023-01-01'), endDate: new Date('2023-12-31'), createdAt: new Date('2023-01-01'), @@ -69,6 +73,7 @@ describe('RoomDomainMapper', () => { id: '1', name: 'Test Room', color: RoomColor.RED, + schoolId: new ObjectId().toHexString(), startDate: new Date('2023-01-01'), endDate: new Date('2023-12-31'), } as RoomEntity; @@ -99,6 +104,7 @@ describe('RoomDomainMapper', () => { id: '66d581c3ef74c548a4efea1d', name: 'Test Room #1', color: RoomColor.RED, + schoolId: new ObjectId().toHexString(), startDate: new Date('2023-01-01'), endDate: new Date('2023-12-31'), createdAt: new Date('2024-10-1'), From 6198f5021393c8eefe699bd43db7f706460ad8bd Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 12 Nov 2024 17:16:14 +0100 Subject: [PATCH 04/60] rename school field --- apps/server/src/modules/room/repo/entity/room.entity.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/server/src/modules/room/repo/entity/room.entity.ts b/apps/server/src/modules/room/repo/entity/room.entity.ts index a44cf367482..0539f7c469c 100644 --- a/apps/server/src/modules/room/repo/entity/room.entity.ts +++ b/apps/server/src/modules/room/repo/entity/room.entity.ts @@ -13,7 +13,7 @@ export class RoomEntity extends BaseEntityWithTimestamps implements RoomProps { @Property({ nullable: false }) color!: RoomColor; - @Property({ type: ObjectIdType, nullable: false }) + @Property({ type: ObjectIdType, fieldName: 'school', nullable: false }) schoolId!: EntityId; @Property({ nullable: true }) From 834a059bfb5f2a5459be43ec9d9d71c2d2227d7c Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 12 Nov 2024 17:54:36 +0100 Subject: [PATCH 05/60] fix entity fields --- .../mikro-orm/Migration202411121635382.ts | 31 +++++++++++++++++++ .../repo/entity/room-member.entity.ts | 5 ++- 2 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 apps/server/src/migrations/mikro-orm/Migration202411121635382.ts diff --git a/apps/server/src/migrations/mikro-orm/Migration202411121635382.ts b/apps/server/src/migrations/mikro-orm/Migration202411121635382.ts new file mode 100644 index 00000000000..26e50089fd7 --- /dev/null +++ b/apps/server/src/migrations/mikro-orm/Migration202411121635382.ts @@ -0,0 +1,31 @@ +import { Migration } from '@mikro-orm/migrations-mongodb'; + +export class Migration20241112163538 extends Migration { + async up(): Promise { + const collection = this.getCollection('room-members'); + + await collection.updateMany({ roomId: { $type: 'string' } }, [ + { + $set: { + roomId: { + $convert: { + input: '$roomId', + to: 'objectId', + onError: '$roomId', // Keep the original value if conversion fails + onNull: '$roomId', // Keep the original value if the input is null + }, + }, + }, + }, + ]); + console.info('Converted roomId from string to ObjectId'); + + await collection.updateMany({}, { $rename: { roomId: 'room' } }); + console.info('Renamed roomId to room'); + } + + async down(): Promise { + await Promise.resolve(); + console.error(`Migration down not implemented. You might need to restore database from backup!`); + } +} diff --git a/apps/server/src/modules/room-member/repo/entity/room-member.entity.ts b/apps/server/src/modules/room-member/repo/entity/room-member.entity.ts index 95cbf802452..3aacb3f1069 100644 --- a/apps/server/src/modules/room-member/repo/entity/room-member.entity.ts +++ b/apps/server/src/modules/room-member/repo/entity/room-member.entity.ts @@ -16,12 +16,11 @@ export interface RoomMemberEntityProps extends AuthorizableObject { @Entity({ tableName: 'room-members' }) @Unique({ properties: ['roomId', 'userGroupId'] }) export class RoomMemberEntity extends BaseEntityWithTimestamps implements RoomMemberEntityProps { - @Property() @Unique() - @Property({ type: ObjectIdType }) + @Property({ type: ObjectIdType, fieldName: 'room' }) roomId!: EntityId; - @Property({ type: ObjectIdType }) + @Property({ type: ObjectIdType, fieldName: 'userGroup' }) userGroupId!: EntityId; @Property({ persist: false }) From 4066cd56a2344fafd6d146e6ca83d6faa6534062 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 12 Nov 2024 18:10:20 +0100 Subject: [PATCH 06/60] update migrations seed --- backup/setup/migrations.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backup/setup/migrations.json b/backup/setup/migrations.json index 820e08a4efa..579adf6fd7b 100644 --- a/backup/setup/migrations.json +++ b/backup/setup/migrations.json @@ -280,11 +280,11 @@ }, { "_id": { - "$oid": "673237e9b0955dcff4cde3db" + "$oid": "673387c13aba1e283484119d" }, - "name": "Migration2024111116041242", + "name": "Migration202411121635382", "created_at": { - "$date": "2024-11-11T16:59:21.776Z" + "$date": "2024-11-12T16:52:17.292Z" } } ] From 902d21e8af068c78c3c397cd34879e148c0b4d6e Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Wed, 13 Nov 2024 12:00:06 +0100 Subject: [PATCH 07/60] add ROOM_CREATE and ROOM_DELETE permissions --- .../mikro-orm/Migration202411131005352.ts | 67 +++++++++++++++++++ apps/server/src/modules/room/api/room.uc.ts | 15 +++-- .../domain/interface/permission.enum.ts | 2 + .../shared/testing/user-role-permissions.ts | 1 + backup/setup/migrations.json | 36 ++++++++++ backup/setup/roles.json | 8 ++- 6 files changed, 121 insertions(+), 8 deletions(-) create mode 100644 apps/server/src/migrations/mikro-orm/Migration202411131005352.ts diff --git a/apps/server/src/migrations/mikro-orm/Migration202411131005352.ts b/apps/server/src/migrations/mikro-orm/Migration202411131005352.ts new file mode 100644 index 00000000000..4d515538360 --- /dev/null +++ b/apps/server/src/migrations/mikro-orm/Migration202411131005352.ts @@ -0,0 +1,67 @@ +import { Migration } from '@mikro-orm/migrations-mongodb'; + +export class Migration20241113100535 extends Migration { + async up(): Promise { + const teacherRoleUpdate = await this.getCollection('roles').updateOne( + { name: 'teacher' }, + { + $addToSet: { + permissions: { + $each: ['ROOM_CREATE'], + }, + }, + } + ); + + if (teacherRoleUpdate.modifiedCount > 0) { + console.info('Permissions ROOM_CREATE added to role teacher.'); + } + + const roomEditorRoleUpdate = await this.getCollection('roles').updateOne( + { name: 'roomeditor' }, + { + $addToSet: { + permissions: { + $each: ['ROOM_DELETE'], + }, + }, + } + ); + + if (roomEditorRoleUpdate.modifiedCount > 0) { + console.info('Permissions ROOM_DELETE added to role roomeditor.'); + } + } + + async down(): Promise { + const teacherRoleUpdate = await this.getCollection('roles').updateOne( + { name: 'teacher' }, + { + $pull: { + permissions: { + $in: ['ROOM_CREATE'], + }, + }, + } + ); + + if (teacherRoleUpdate.modifiedCount > 0) { + console.info('Rollback: Permission ROOM_CREATE added to role teacher.'); + } + + const roomEditorRoleUpdate = await this.getCollection('roles').updateOne( + { name: 'roomeditor' }, + { + $pull: { + permissions: { + $in: ['ROOM_DELETE'], + }, + }, + } + ); + + if (teacherRoleUpdate.modifiedCount > 0) { + console.info('Rollback: Permission ROOM_DELETE added to role roomeditor.'); + } + } +} diff --git a/apps/server/src/modules/room/api/room.uc.ts b/apps/server/src/modules/room/api/room.uc.ts index d7b5ef8e3a1..bdc7094dedd 100644 --- a/apps/server/src/modules/room/api/room.uc.ts +++ b/apps/server/src/modules/room/api/room.uc.ts @@ -38,8 +38,8 @@ export class RoomUc { const user = await this.authorizationService.getUserWithPermissions(userId); const room = await this.roomService.createRoom({ ...props, schoolId: user.school.id }); - // NOTE: currently only teacher are allowed to create rooms. Could not find simpler way to check this. - this.authorizationService.checkOneOfPermissions(user, [Permission.COURSE_CREATE]); + // NOTE: currently only teachers are allowed to create rooms. Could not find simpler way to check this. + this.authorizationService.checkOneOfPermissions(user, [Permission.ROOM_CREATE]); await this.roomMemberService .addMembersToRoom(room.id, [{ userId: user.id, roleName: RoleName.ROOM_EDITOR }], user.school.id) .catch(async (err) => { @@ -88,7 +88,7 @@ export class RoomUc { this.checkFeatureEnabled(); const room = await this.roomService.getSingleRoom(roomId); - await this.checkRoomAuthorization(userId, roomId, Action.write); + await this.checkRoomAuthorization(userId, roomId, Action.write, [Permission.ROOM_DELETE]); await this.roomService.deleteRoom(room); } @@ -153,10 +153,15 @@ export class RoomUc { return authorizedRoomIds.map((item) => item.roomId); } - private async checkRoomAuthorization(userId: EntityId, roomId: EntityId, action: Action): Promise { + private async checkRoomAuthorization( + userId: EntityId, + roomId: EntityId, + action: Action, + requiredPermissions: Permission[] = [] + ): Promise { const roomMemberAuthorizable = await this.roomMemberService.getRoomMemberAuthorizable(roomId); const user = await this.authorizationService.getUserWithPermissions(userId); - this.authorizationService.checkPermission(user, roomMemberAuthorizable, { action, requiredPermissions: [] }); + this.authorizationService.checkPermission(user, roomMemberAuthorizable, { action, requiredPermissions }); } private checkFeatureEnabled(): void { diff --git a/apps/server/src/shared/domain/interface/permission.enum.ts b/apps/server/src/shared/domain/interface/permission.enum.ts index 125e027653f..c5bed37ad11 100644 --- a/apps/server/src/shared/domain/interface/permission.enum.ts +++ b/apps/server/src/shared/domain/interface/permission.enum.ts @@ -100,8 +100,10 @@ export enum Permission { ROLE_CREATE = 'ROLE_CREATE', ROLE_EDIT = 'ROLE_EDIT', ROLE_VIEW = 'ROLE_VIEW', + ROOM_CREATE = 'ROOM_CREATE', ROOM_EDIT = 'ROOM_EDIT', ROOM_VIEW = 'ROOM_VIEW', + ROOM_DELETE = 'ROOM_DELETE', SCHOOL_CHAT_MANAGE = 'SCHOOL_CHAT_MANAGE', SCHOOL_CREATE = 'SCHOOL_CREATE', SCHOOL_EDIT = 'SCHOOL_EDIT', diff --git a/apps/server/src/shared/testing/user-role-permissions.ts b/apps/server/src/shared/testing/user-role-permissions.ts index 378ba8859d1..e8e49a85dc2 100644 --- a/apps/server/src/shared/testing/user-role-permissions.ts +++ b/apps/server/src/shared/testing/user-role-permissions.ts @@ -103,6 +103,7 @@ export const teacherPermissions = [ Permission.TOPIC_EDIT, Permission.START_MEETING, Permission.CONTEXT_TOOL_ADMIN, + Permission.ROOM_CREATE, ]; export const adminPermissions = [ diff --git a/backup/setup/migrations.json b/backup/setup/migrations.json index 579adf6fd7b..159b27f4dda 100644 --- a/backup/setup/migrations.json +++ b/backup/setup/migrations.json @@ -286,5 +286,41 @@ "created_at": { "$date": "2024-11-12T16:52:17.292Z" } + }, + { + "_id": { + "$oid": "67347bb8b1bcb78aecbab90d" + }, + "name": "Migration2024111116041242", + "created_at": { + "$date": "2024-11-13T10:13:12.402Z" + } + }, + { + "_id": { + "$oid": "67347bb8b1bcb78aecbab90e" + }, + "name": "Migration20241112163538", + "created_at": { + "$date": "2024-11-13T10:13:12.409Z" + } + }, + { + "_id": { + "$oid": "67347bb8b1bcb78aecbab90f" + }, + "name": "Migration20241113100535", + "created_at": { + "$date": "2024-11-13T10:13:12.411Z" + } + }, + { + "_id": { + "$oid": "6734805b32785b5d369ed96a" + }, + "name": "Migration202411131005352", + "created_at": { + "$date": "2024-11-13T10:32:59.991Z" + } } ] diff --git a/backup/setup/roles.json b/backup/setup/roles.json index 9dc1595c2b6..05b0f613fc2 100644 --- a/backup/setup/roles.json +++ b/backup/setup/roles.json @@ -214,7 +214,7 @@ }, "name": "teacher", "updatedAt": { - "$date": "2024-04-19T10:32:51.070Z" + "$date": "2024-11-12T16:35:53.763Z" }, "createdAt": { "$date": "2017-01-01T00:06:37.148Z" @@ -263,7 +263,8 @@ "USERGROUP_CREATE", "USERGROUP_EDIT", "USER_CHANGE_OWN_NAME", - "USER_CREATE" + "USER_CREATE", + "ROOM_CREATE" ], "__v": 2 }, @@ -598,7 +599,8 @@ "name": "roomeditor", "permissions": [ "ROOM_VIEW", - "ROOM_EDIT" + "ROOM_EDIT", + "ROOM_DELETE" ] } ] From 0c9b4302019f292f1a3d8bf9b95391175098be89 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Wed, 13 Nov 2024 16:57:16 +0100 Subject: [PATCH 08/60] add migration to infer room school from room memberships --- .../mikro-orm/Migration202411131520015.ts | 102 ++++++++++++++++++ backup/setup/migrations.json | 9 ++ 2 files changed, 111 insertions(+) create mode 100644 apps/server/src/migrations/mikro-orm/Migration202411131520015.ts diff --git a/apps/server/src/migrations/mikro-orm/Migration202411131520015.ts b/apps/server/src/migrations/mikro-orm/Migration202411131520015.ts new file mode 100644 index 00000000000..9914935c0a9 --- /dev/null +++ b/apps/server/src/migrations/mikro-orm/Migration202411131520015.ts @@ -0,0 +1,102 @@ +import { Migration } from '@mikro-orm/migrations-mongodb'; + +export class Migration20241113152001 extends Migration { + async up(): Promise { + const roomsToSchoolView = [ + { + $lookup: { + from: 'rooms', + localField: 'room', + foreignField: '_id', + as: 'roomDetails', + }, + }, + { + $unwind: '$roomDetails', + }, + { + $match: { + 'roomDetails.school': { $exists: false, $eq: null }, + }, + }, + { + $lookup: { + from: 'groups', + localField: 'userGroup', + foreignField: '_id', + as: 'groupDetails', + }, + }, + { + $unwind: '$groupDetails', + }, + { + $unwind: '$groupDetails.users', + }, + { + $lookup: { + from: 'roles', + localField: 'groupDetails.users.role', + foreignField: '_id', + as: 'roleDetails', + }, + }, + { + $unwind: '$roleDetails', + }, + { + $match: { + 'roleDetails.name': 'roomeditor', + }, + }, + { + $lookup: { + from: 'users', + localField: 'groupDetails.users.user', + foreignField: '_id', + as: 'userDetails', + }, + }, + { + $unwind: '$userDetails', + }, + { + $group: { + _id: '$userDetails.schoolId', + rooms: { $push: '$roomDetails._id' }, + }, + }, + { + $project: { + _id: 0, + school: '$_id', + rooms: 1, + }, + }, + ]; + + const mappings = await this.driver.aggregate('room-members', roomsToSchoolView); + + for await (const mapping of mappings) { + const schoolUpdate = await this.driver.nativeUpdate( + 'rooms', + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-member-access + { _id: { $in: mapping.rooms } }, + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-member-access + { $set: { school: mapping.school } } + ); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access, @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-unsafe-call + console.info(`Updated ${schoolUpdate.affectedRows} rooms with school ${mapping.school.toHexString()}`); + } + + if (mappings.length === 0) { + console.info(`No rooms without school to update`); + } + } + + async down(): Promise { + await Promise.resolve(); + console.error(`Migration down not implemented. You might need to restore database from backup!`); + } +} diff --git a/backup/setup/migrations.json b/backup/setup/migrations.json index 159b27f4dda..5f8b081438d 100644 --- a/backup/setup/migrations.json +++ b/backup/setup/migrations.json @@ -322,5 +322,14 @@ "created_at": { "$date": "2024-11-13T10:32:59.991Z" } + }, + { + "_id": { + "$oid": "6734cb1d7b04e799e79c1ec1" + }, + "name": "Migration202411131520015", + "created_at": { + "$date": "2024-11-13T15:51:57.334Z" + } } ] From 22a222452ef0459793036c8d9300f7c8416bf310 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Thu, 14 Nov 2024 16:45:07 +0100 Subject: [PATCH 09/60] update seeds --- .../src/migrations/mikro-orm/Migration202411131005352.ts | 2 +- backup/setup/migrations.json | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/server/src/migrations/mikro-orm/Migration202411131005352.ts b/apps/server/src/migrations/mikro-orm/Migration202411131005352.ts index 4d515538360..d233b984596 100644 --- a/apps/server/src/migrations/mikro-orm/Migration202411131005352.ts +++ b/apps/server/src/migrations/mikro-orm/Migration202411131005352.ts @@ -60,7 +60,7 @@ export class Migration20241113100535 extends Migration { } ); - if (teacherRoleUpdate.modifiedCount > 0) { + if (roomEditorRoleUpdate.modifiedCount > 0) { console.info('Rollback: Permission ROOM_DELETE added to role roomeditor.'); } } diff --git a/backup/setup/migrations.json b/backup/setup/migrations.json index 5f8b081438d..211631c68b9 100644 --- a/backup/setup/migrations.json +++ b/backup/setup/migrations.json @@ -331,5 +331,14 @@ "created_at": { "$date": "2024-11-13T15:51:57.334Z" } + }, + { + "_id": { + "$oid": "67361aa7776f2f3e5a519735" + }, + "name": "Migration20241113152001", + "created_at": { + "$date": "2024-11-14T15:43:35.024Z" + } } ] From f5340a5ed7ed3ac1f34db774d0970fbdc9d15ed7 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Thu, 14 Nov 2024 17:06:13 +0100 Subject: [PATCH 10/60] extend api to return room permissions --- .../api/dto/response/room-details.response.ts | 6 ++++ .../modules/room/api/mapper/room.mapper.ts | 4 ++- .../src/modules/room/api/room.controller.ts | 8 ++--- apps/server/src/modules/room/api/room.uc.ts | 35 ++++++++++++++----- .../room/api/test/room-get.api.spec.ts | 1 + 5 files changed, 41 insertions(+), 13 deletions(-) diff --git a/apps/server/src/modules/room/api/dto/response/room-details.response.ts b/apps/server/src/modules/room/api/dto/response/room-details.response.ts index 197c1763206..00b37e38236 100644 --- a/apps/server/src/modules/room/api/dto/response/room-details.response.ts +++ b/apps/server/src/modules/room/api/dto/response/room-details.response.ts @@ -1,4 +1,5 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +import { Permission } from '@shared/domain/interface'; import { RoomColor } from '@src/modules/room/domain/type'; import { IsEnum } from 'class-validator'; @@ -28,6 +29,9 @@ export class RoomDetailsResponse { @ApiProperty({ type: Date }) updatedAt: Date; + @ApiProperty({ enum: Permission, isArray: true, enumName: 'Permission' }) + permissions: Permission[]; + constructor(room: RoomDetailsResponse) { this.id = room.id; this.name = room.name; @@ -38,5 +42,7 @@ export class RoomDetailsResponse { this.endDate = room.endDate; this.createdAt = room.createdAt; this.updatedAt = room.updatedAt; + + this.permissions = room.permissions; } } diff --git a/apps/server/src/modules/room/api/mapper/room.mapper.ts b/apps/server/src/modules/room/api/mapper/room.mapper.ts index 4b69e2a34ef..cd5772fbd49 100644 --- a/apps/server/src/modules/room/api/mapper/room.mapper.ts +++ b/apps/server/src/modules/room/api/mapper/room.mapper.ts @@ -7,6 +7,7 @@ import { RoomBoardListResponse } from '../dto/response/room-board-list.response' import { RoomDetailsResponse } from '../dto/response/room-details.response'; import { RoomItemResponse } from '../dto/response/room-item.response'; import { RoomListResponse } from '../dto/response/room-list.response'; +import { Permission } from '@shared/domain/interface'; export class RoomMapper { static mapToRoomItemResponse(room: Room): RoomItemResponse { @@ -33,7 +34,7 @@ export class RoomMapper { return response; } - static mapToRoomDetailsResponse(room: Room): RoomDetailsResponse { + static mapToRoomDetailsResponse(room: Room, permissions: Permission[]): RoomDetailsResponse { const response = new RoomDetailsResponse({ id: room.id, name: room.name, @@ -43,6 +44,7 @@ export class RoomMapper { endDate: room.endDate, createdAt: room.createdAt, updatedAt: room.updatedAt, + permissions, }); return response; diff --git a/apps/server/src/modules/room/api/room.controller.ts b/apps/server/src/modules/room/api/room.controller.ts index 2f54d0f65a8..8a57be144df 100644 --- a/apps/server/src/modules/room/api/room.controller.ts +++ b/apps/server/src/modules/room/api/room.controller.ts @@ -89,9 +89,9 @@ export class RoomController { @CurrentUser() currentUser: ICurrentUser, @Param() urlParams: RoomUrlParams ): Promise { - const room = await this.roomUc.getSingleRoom(currentUser.userId, urlParams.roomId); + const { room, permissions } = await this.roomUc.getSingleRoom(currentUser.userId, urlParams.roomId); - const response = RoomMapper.mapToRoomDetailsResponse(room); + const response = RoomMapper.mapToRoomDetailsResponse(room, permissions); return response; } @@ -128,9 +128,9 @@ export class RoomController { @Param() urlParams: RoomUrlParams, @Body() updateRoomParams: UpdateRoomBodyParams ): Promise { - const room = await this.roomUc.updateRoom(currentUser.userId, urlParams.roomId, updateRoomParams); + const { room, permissions } = await this.roomUc.updateRoom(currentUser.userId, urlParams.roomId, updateRoomParams); - const response = RoomMapper.mapToRoomDetailsResponse(room); + const response = RoomMapper.mapToRoomDetailsResponse(room, permissions); return response; } diff --git a/apps/server/src/modules/room/api/room.uc.ts b/apps/server/src/modules/room/api/room.uc.ts index bdc7094dedd..e426c47d24b 100644 --- a/apps/server/src/modules/room/api/room.uc.ts +++ b/apps/server/src/modules/room/api/room.uc.ts @@ -1,5 +1,5 @@ import { Action, AuthorizationService } from '@modules/authorization'; -import { RoomMemberService, UserWithRoomRoles } from '@modules/room-member'; +import { RoomMemberAuthorizable, RoomMemberService, UserWithRoomRoles } from '@modules/room-member'; import { UserService } from '@modules/user'; import { Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; @@ -49,12 +49,14 @@ export class RoomUc { return room; } - public async getSingleRoom(userId: EntityId, roomId: EntityId): Promise { + public async getSingleRoom(userId: EntityId, roomId: EntityId): Promise<{ room: Room; permissions: Permission[] }> { this.checkFeatureEnabled(); const room = await this.roomService.getSingleRoom(roomId); - await this.checkRoomAuthorization(userId, roomId, Action.read); - return room; + const roomMemberAuthorizable = await this.checkRoomAuthorization(userId, roomId, Action.read); + const permissions = this.getPermissions(userId, roomMemberAuthorizable); + + return { room, permissions }; } public async getRoomBoards(userId: EntityId, roomId: EntityId): Promise { @@ -74,14 +76,20 @@ export class RoomUc { return boards; } - public async updateRoom(userId: EntityId, roomId: EntityId, props: UpdateRoomBodyParams): Promise { + public async updateRoom( + userId: EntityId, + roomId: EntityId, + props: UpdateRoomBodyParams + ): Promise<{ room: Room; permissions: Permission[] }> { this.checkFeatureEnabled(); const room = await this.roomService.getSingleRoom(roomId); - await this.checkRoomAuthorization(userId, roomId, Action.write); + const roomMemberAuthorizable = await this.checkRoomAuthorization(userId, roomId, Action.write); + const permissions = this.getPermissions(userId, roomMemberAuthorizable); + await this.roomService.updateRoom(room, props); - return room; + return { room, permissions }; } public async deleteRoom(userId: EntityId, roomId: EntityId): Promise { @@ -158,10 +166,21 @@ export class RoomUc { roomId: EntityId, action: Action, requiredPermissions: Permission[] = [] - ): Promise { + ): Promise { const roomMemberAuthorizable = await this.roomMemberService.getRoomMemberAuthorizable(roomId); const user = await this.authorizationService.getUserWithPermissions(userId); this.authorizationService.checkPermission(user, roomMemberAuthorizable, { action, requiredPermissions }); + + return roomMemberAuthorizable; + } + + private getPermissions(userId: EntityId, roomMemberAuthorizable: RoomMemberAuthorizable): Permission[] { + const permissions = roomMemberAuthorizable.members + .filter((member) => member.userId === userId) + .flatMap((member) => member.roles) + .flatMap((role) => role.permissions ?? []); + + return permissions; } private checkFeatureEnabled(): void { diff --git a/apps/server/src/modules/room/api/test/room-get.api.spec.ts b/apps/server/src/modules/room/api/test/room-get.api.spec.ts index ef4b1462ebb..2dbc4fce6e8 100644 --- a/apps/server/src/modules/room/api/test/room-get.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-get.api.spec.ts @@ -119,6 +119,7 @@ describe('Room Controller (API)', () => { endDate: room.endDate?.toISOString(), createdAt: room.createdAt.toISOString(), updatedAt: room.updatedAt.toISOString(), + permissions: [Permission.ROOM_VIEW], }; return { loggedInClient, room, expectedResponse }; From fa3d01ea2d0f635042ac8f1c962d20e36334e1cc Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Fri, 15 Nov 2024 16:07:45 +0100 Subject: [PATCH 11/60] refactor board copy to using room storage id --- .../src/modules/board/board-api.module.ts | 3 +- .../board/service/column-board.service.ts | 11 +- .../internal/board-node-copy-context.ts | 19 +-- .../internal/column-board-copy.service.ts | 55 +++++---- apps/server/src/modules/board/uc/board.uc.ts | 42 +++++-- .../learnroom/service/board-copy.service.ts | 21 +++- .../learnroom/service/course-copy.service.ts | 7 +- .../src/modules/server/server.module.ts | 2 +- .../dto/share-token-import.body.params.ts | 26 +++- .../controller/share-token.controller.ts | 2 +- .../src/modules/sharing/sharing-api.module.ts | 31 +++++ .../src/modules/sharing/sharing.module.ts | 33 +---- .../src/modules/sharing/uc/share-token.uc.ts | 113 +++++++++++++++--- 13 files changed, 248 insertions(+), 117 deletions(-) create mode 100644 apps/server/src/modules/sharing/sharing-api.module.ts diff --git a/apps/server/src/modules/board/board-api.module.ts b/apps/server/src/modules/board/board-api.module.ts index 98d6de3acfc..93cdca3aa7e 100644 --- a/apps/server/src/modules/board/board-api.module.ts +++ b/apps/server/src/modules/board/board-api.module.ts @@ -13,9 +13,10 @@ import { BoardModule } from './board.module'; import { BoardNodePermissionService } from './service'; import { BoardUc, CardUc, ColumnUc, ElementUc, SubmissionItemUc } from './uc'; import { RoomMemberModule } from '../room-member'; +import { RoomModule } from '../room'; @Module({ - imports: [BoardModule, LoggerModule, RoomMemberModule, forwardRef(() => AuthorizationModule)], + imports: [BoardModule, LoggerModule, RoomMemberModule, RoomModule, forwardRef(() => AuthorizationModule)], controllers: [BoardController, ColumnController, CardController, ElementController, BoardSubmissionController], providers: [BoardUc, BoardNodePermissionService, ColumnUc, CardUc, ElementUc, SubmissionItemUc, CourseRepo], }) diff --git a/apps/server/src/modules/board/service/column-board.service.ts b/apps/server/src/modules/board/service/column-board.service.ts index 3985af9bd17..3f225cb5285 100644 --- a/apps/server/src/modules/board/service/column-board.service.ts +++ b/apps/server/src/modules/board/service/column-board.service.ts @@ -4,7 +4,7 @@ import { EntityId } from '@shared/domain/types'; import { BoardExternalReference, BoardExternalReferenceType, ColumnBoard, isColumnBoard } from '../domain'; import { BoardNodeRepo } from '../repo'; import { BoardNodeService } from './board-node.service'; -import { ColumnBoardCopyService, ColumnBoardLinkService } from './internal'; +import { ColumnBoardCopyService, ColumnBoardLinkService, CopyColumnBoardParams } from './internal'; @Injectable() export class ColumnBoardService { @@ -44,13 +44,8 @@ export class ColumnBoardService { await this.boardNodeRepo.delete(boardNodes); } - async copyColumnBoard(props: { - originalColumnBoardId: EntityId; - destinationExternalReference: BoardExternalReference; - userId: EntityId; - copyTitle?: string; - }): Promise { - const copyStatus = await this.columnBoardCopyService.copyColumnBoard(props); + async copyColumnBoard(params: CopyColumnBoardParams): Promise { + const copyStatus = await this.columnBoardCopyService.copyColumnBoard(params); return copyStatus; } diff --git a/apps/server/src/modules/board/service/internal/board-node-copy-context.ts b/apps/server/src/modules/board/service/internal/board-node-copy-context.ts index e9cab871c79..f32fe232534 100644 --- a/apps/server/src/modules/board/service/internal/board-node-copy-context.ts +++ b/apps/server/src/modules/board/service/internal/board-node-copy-context.ts @@ -5,12 +5,15 @@ import { EntityId } from '@shared/domain/types'; import { FileRecordParentType } from '@src/infra/rabbitmq'; import { CopyContext } from './board-node-copy.service'; +export type StorageLocationReference = { + id: EntityId; + type: StorageLocation; +}; + export type BoardNodeCopyContextProps = { - sourceStorageLocationId: EntityId; - targetStorageLocationId: EntityId; + sourceStorageLocationReference: StorageLocationReference; + targetStorageLocationReference: StorageLocationReference; userId: EntityId; - sourceStorageLocation: StorageLocation; - targetStorageLocation: StorageLocation; filesStorageClientAdapterService: FilesStorageClientAdapterService; }; @@ -22,14 +25,14 @@ export class BoardNodeCopyContext implements CopyContext { source: { parentId: sourceParentId, parentType: FileRecordParentType.BoardNode, - storageLocationId: this.props.sourceStorageLocationId, - storageLocation: this.props.sourceStorageLocation, + storageLocationId: this.props.sourceStorageLocationReference.id, + storageLocation: this.props.sourceStorageLocationReference.type, }, target: { parentId: targetParentId, parentType: FileRecordParentType.BoardNode, - storageLocationId: this.props.targetStorageLocationId, - storageLocation: this.props.targetStorageLocation, + storageLocationId: this.props.targetStorageLocationReference.id, + storageLocation: this.props.targetStorageLocationReference.type, }, userId: this.props.userId, }); diff --git a/apps/server/src/modules/board/service/internal/column-board-copy.service.ts b/apps/server/src/modules/board/service/internal/column-board-copy.service.ts index 80136e2f832..99eb21b92e0 100644 --- a/apps/server/src/modules/board/service/internal/column-board-copy.service.ts +++ b/apps/server/src/modules/board/service/internal/column-board-copy.service.ts @@ -1,48 +1,40 @@ import { CopyStatus } from '@modules/copy-helper'; import { FilesStorageClientAdapterService } from '@modules/files-storage-client'; -import { StorageLocation } from '@modules/files-storage/interface'; -import { UserService } from '@modules/user'; import { Injectable, InternalServerErrorException, NotImplementedException } from '@nestjs/common'; import { EntityId } from '@shared/domain/types'; -import { CourseRepo } from '@shared/repo'; import { BoardExternalReference, BoardExternalReferenceType, ColumnBoard, isColumnBoard } from '../../domain'; import { BoardNodeService } from '../board-node.service'; -import { BoardNodeCopyContext } from './board-node-copy-context'; +import { BoardNodeCopyContext, StorageLocationReference } from './board-node-copy-context'; import { BoardNodeCopyService } from './board-node-copy.service'; import { ColumnBoardTitleService } from './column-board-title.service'; +export type CopyColumnBoardParams = { + originalColumnBoardId: EntityId; + targetExternalReference: BoardExternalReference; + sourceStorageLocationReference: StorageLocationReference; + targetStorageLocationReference: StorageLocationReference; + userId: EntityId; + copyTitle?: string; +}; + @Injectable() export class ColumnBoardCopyService { constructor( private readonly boardNodeService: BoardNodeService, private readonly columnBoardTitleService: ColumnBoardTitleService, - private readonly courseRepo: CourseRepo, - private readonly userService: UserService, private readonly boardNodeCopyService: BoardNodeCopyService, private readonly filesStorageClientAdapterService: FilesStorageClientAdapterService ) {} - async copyColumnBoard(props: { - originalColumnBoardId: EntityId; - destinationExternalReference: BoardExternalReference; - userId: EntityId; - copyTitle?: string; - }): Promise { - const originalBoard = await this.boardNodeService.findByClassAndId(ColumnBoard, props.originalColumnBoardId); + async copyColumnBoard(params: CopyColumnBoardParams): Promise { + const originalBoard = await this.boardNodeService.findByClassAndId(ColumnBoard, params.originalColumnBoardId); - const user = await this.userService.findById(props.userId); - /* istanbul ignore next */ - if (originalBoard.context.type !== BoardExternalReferenceType.Course) { - throw new NotImplementedException('only courses are supported as board parents'); - } - const course = await this.courseRepo.findById(originalBoard.context.id); // TODO: get rid of this + this.checkSupportedExternalReferenceType(params.targetExternalReference.type); const copyContext = new BoardNodeCopyContext({ - sourceStorageLocationId: course.school.id, - targetStorageLocationId: user.schoolId, - sourceStorageLocation: StorageLocation.SCHOOL, - targetStorageLocation: StorageLocation.SCHOOL, - userId: props.userId, + sourceStorageLocationReference: params.sourceStorageLocationReference, + targetStorageLocationReference: params.targetStorageLocationReference, + userId: params.userId, filesStorageClientAdapterService: this.filesStorageClientAdapterService, }); @@ -53,18 +45,25 @@ export class ColumnBoardCopyService { throw new InternalServerErrorException('expected copy of columnboard to be a columnboard'); } - if (props.copyTitle) { - copyStatus.copyEntity.title = props.copyTitle; + if (params.copyTitle) { + copyStatus.copyEntity.title = params.copyTitle; } else { copyStatus.copyEntity.title = await this.columnBoardTitleService.deriveColumnBoardTitle( originalBoard.title, - props.destinationExternalReference + params.targetExternalReference ); } - copyStatus.copyEntity.context = props.destinationExternalReference; + copyStatus.copyEntity.context = params.targetExternalReference; await this.boardNodeService.addRoot(copyStatus.copyEntity); copyStatus.originalEntity = originalBoard; return copyStatus; } + + private checkSupportedExternalReferenceType(type: BoardExternalReferenceType) { + /* istanbul ignore next */ + if (type !== BoardExternalReferenceType.Course && type !== BoardExternalReferenceType.Room) { + throw new NotImplementedException('Only room and course external reference types are supported'); + } + } } diff --git a/apps/server/src/modules/board/uc/board.uc.ts b/apps/server/src/modules/board/uc/board.uc.ts index 6a766370f74..e2fb11b937b 100644 --- a/apps/server/src/modules/board/uc/board.uc.ts +++ b/apps/server/src/modules/board/uc/board.uc.ts @@ -5,10 +5,13 @@ import { Permission } from '@shared/domain/interface'; import { EntityId } from '@shared/domain/types'; import { CourseRepo } from '@shared/repo'; import { LegacyLogger } from '@src/core/logger'; +import { StorageLocation } from '@src/modules/files-storage/interface'; +import { RoomService } from '@src/modules/room'; import { RoomMemberService } from '@src/modules/room-member'; import { CreateBoardBodyParams } from '../controller/dto'; import { BoardExternalReference, BoardExternalReferenceType, BoardNodeFactory, Column, ColumnBoard } from '../domain'; import { BoardNodePermissionService, BoardNodeService, ColumnBoardService } from '../service'; +import { StorageLocationReference } from '../service/internal'; @Injectable() export class BoardUc { @@ -21,6 +24,7 @@ export class BoardUc { private readonly columnBoardService: ColumnBoardService, private readonly logger: LegacyLogger, private readonly courseRepo: CourseRepo, + private readonly roomService: RoomService, private readonly boardNodeFactory: BoardNodeFactory ) { this.logger.setContext(BoardUc.name); @@ -29,7 +33,7 @@ export class BoardUc { async createBoard(userId: EntityId, params: CreateBoardBodyParams): Promise { this.logger.debug({ action: 'createBoard', userId, title: params.title }); - await this.checkParentWritePermission(userId, { type: params.parentType, id: params.parentId }); + await this.checkReferenceWritePermission(userId, { type: params.parentType, id: params.parentId }); const board = this.boardNodeFactory.buildColumnBoard({ context: { type: params.parentType, id: params.parentId }, @@ -115,22 +119,18 @@ export class BoardUc { async copyBoard(userId: EntityId, boardId: EntityId): Promise { this.logger.debug({ action: 'copyBoard', userId, boardId }); - const user = await this.authorizationService.getUserWithPermissions(userId); const board = await this.boardNodeService.findByClassAndId(ColumnBoard, boardId); - // TODO - should not use course repo - const course = await this.courseRepo.findById(board.context.id); + await this.checkReferenceWritePermission(userId, board.context); - await this.boardPermissionService.checkPermission(userId, board, Action.read); - this.authorizationService.checkPermission(user, course, { - action: Action.write, - requiredPermissions: [], // TODO - what permissions are required? COURSE_EDIT? - }); + const storageLocationReference = await this.getStorageLocationReference(board.context); const copyStatus = await this.columnBoardService.copyColumnBoard({ - userId, originalColumnBoardId: boardId, - destinationExternalReference: board.context, + targetExternalReference: board.context, + sourceStorageLocationReference: storageLocationReference, + targetStorageLocationReference: storageLocationReference, + userId, }); return copyStatus; @@ -144,7 +144,9 @@ export class BoardUc { return board; } - private async checkParentWritePermission(userId: EntityId, context: BoardExternalReference) { + // ---- Move to shared service? (see apps/server/src/modules/sharing/uc/share-token.uc.ts) + + private async checkReferenceWritePermission(userId: EntityId, context: BoardExternalReference) { const user = await this.authorizationService.getUserWithPermissions(userId); if (context.type === BoardExternalReferenceType.Course) { @@ -165,4 +167,20 @@ export class BoardUc { throw new Error(`Unsupported context type ${context.type as string}`); } } + + private async getStorageLocationReference(context: BoardExternalReference): Promise { + if (context.type === BoardExternalReferenceType.Course) { + const course = await this.courseRepo.findById(context.id); + + return { id: course.school.id, type: StorageLocation.SCHOOL }; + } + + if (context.type === BoardExternalReferenceType.Room) { + const room = await this.roomService.getSingleRoom(context.id); + + return { id: room.schoolId, type: StorageLocation.SCHOOL }; + } + + throw new Error(`Cannot get storage location reference for context type ${context.type as string}`); + } } diff --git a/apps/server/src/modules/learnroom/service/board-copy.service.ts b/apps/server/src/modules/learnroom/service/board-copy.service.ts index b77dd910e6f..2678f13d3e4 100644 --- a/apps/server/src/modules/learnroom/service/board-copy.service.ts +++ b/apps/server/src/modules/learnroom/service/board-copy.service.ts @@ -22,11 +22,13 @@ import { import { EntityId } from '@shared/domain/types'; import { LegacyBoardRepo } from '@shared/repo'; import { LegacyLogger } from '@src/core/logger'; +import { StorageLocation } from '@src/modules/files-storage/interface'; import { sortBy } from 'lodash'; import { ColumnBoardNodeRepo } from '../repo'; -type BoardCopyParams = { +export type BoardCopyParams = { originalBoard: LegacyBoard; + originalCourse: Course; destinationCourse: Course; user: User; }; @@ -45,10 +47,10 @@ export class BoardCopyService { ) {} async copyBoard(params: BoardCopyParams): Promise { - const { originalBoard, user, destinationCourse } = params; + const { originalBoard, user, originalCourse, destinationCourse } = params; const boardElements: LegacyBoardElement[] = originalBoard.getElements(); - const elements: CopyStatus[] = await this.copyBoardElements(boardElements, user, destinationCourse); + const elements: CopyStatus[] = await this.copyBoardElements(boardElements, user, originalCourse, destinationCourse); const references: LegacyBoardElement[] = await this.extractReferences(elements); @@ -82,6 +84,7 @@ export class BoardCopyService { private async copyBoardElements( boardElements: LegacyBoardElement[], user: User, + originalCourse: Course, destinationCourse: Course ): Promise { const promises: Promise<[number, CopyStatus]>[] = boardElements.map((element, pos) => { @@ -101,7 +104,10 @@ export class BoardCopyService { element.boardElementType === LegacyBoardElementType.ColumnBoard && element.target instanceof ColumnBoardNode ) { - return this.copyColumnBoard(element.target, user, destinationCourse).then((status) => [pos, status]); + return this.copyColumnBoard(element.target, user, originalCourse, destinationCourse).then((status) => [ + pos, + status, + ]); } /* istanbul ignore next */ @@ -135,15 +141,18 @@ export class BoardCopyService { private async copyColumnBoard( columnBoard: ColumnBoardNode, user: User, + originalCourse: Course, destinationCourse: Course ): Promise { return this.columnBoardService.copyColumnBoard({ originalColumnBoardId: columnBoard.id, - userId: user.id, - destinationExternalReference: { + targetExternalReference: { id: destinationCourse.id, type: BoardExternalReferenceType.Course, }, + sourceStorageLocationReference: { id: originalCourse.school.id, type: StorageLocation.SCHOOL }, + targetStorageLocationReference: { id: destinationCourse.school.id, type: StorageLocation.SCHOOL }, + userId: user.id, }); } diff --git a/apps/server/src/modules/learnroom/service/course-copy.service.ts b/apps/server/src/modules/learnroom/service/course-copy.service.ts index 5edb0937621..66da0757f29 100644 --- a/apps/server/src/modules/learnroom/service/course-copy.service.ts +++ b/apps/server/src/modules/learnroom/service/course-copy.service.ts @@ -70,7 +70,12 @@ export class CourseCopyService { ); } - const boardStatus = await this.boardCopyService.copyBoard({ originalBoard, destinationCourse: courseCopy, user }); + const boardStatus = await this.boardCopyService.copyBoard({ + originalBoard, + originalCourse, + destinationCourse: courseCopy, + user, + }); const finishedCourseCopy = await this.finishCourseCopying(courseCopy); const courseStatus = this.deriveCourseStatus(originalCourse, finishedCourseCopy, boardStatus); diff --git a/apps/server/src/modules/server/server.module.ts b/apps/server/src/modules/server/server.module.ts index 46cafe9c2e7..dc4685ca082 100644 --- a/apps/server/src/modules/server/server.module.ts +++ b/apps/server/src/modules/server/server.module.ts @@ -30,7 +30,7 @@ import { RocketChatModule } from '@modules/rocketchat'; import { RoomApiModule } from '@modules/room/room-api.module'; import { RosterModule } from '@modules/roster/roster.module'; import { SchoolApiModule } from '@modules/school/school-api.module'; -import { SharingApiModule } from '@modules/sharing/sharing.module'; +import { SharingApiModule } from '@modules/sharing/sharing-api.module'; import { ShdApiModule } from '@modules/shd/shd.api.module'; import { SystemApiModule } from '@modules/system/system-api.module'; import { TaskApiModule } from '@modules/task/task-api.module'; diff --git a/apps/server/src/modules/sharing/controller/dto/share-token-import.body.params.ts b/apps/server/src/modules/sharing/controller/dto/share-token-import.body.params.ts index 420d00c3758..4484b671087 100644 --- a/apps/server/src/modules/sharing/controller/dto/share-token-import.body.params.ts +++ b/apps/server/src/modules/sharing/controller/dto/share-token-import.body.params.ts @@ -1,6 +1,25 @@ import { ApiProperty } from '@nestjs/swagger'; import { SanitizeHtml } from '@shared/controller'; import { IsOptional, IsString } from 'class-validator'; +import { ImportDestination, ImportDestinationType } from '../../uc'; + +export class ImportDestinationBodyParams { + @IsString() + @ApiProperty({ + description: 'The id of the destination object.', + required: true, + nullable: false, + }) + id!: string; + + @ApiProperty({ + enum: ImportDestinationType, + description: 'The type of the destination object.', + required: true, + nullable: false, + }) + type!: ImportDestinationType; +} export class ShareTokenImportBodyParams { @IsString() @@ -13,11 +32,12 @@ export class ShareTokenImportBodyParams { newName!: string; @IsOptional() - @IsString() @ApiProperty({ - description: 'Id of the course to which the lesson/task will be added', + type: ImportDestinationBodyParams, + name: 'ImportDestination', + description: 'Destination of the share token import', required: false, nullable: true, }) - destinationCourseId?: string; + destination?: ImportDestination; } diff --git a/apps/server/src/modules/sharing/controller/share-token.controller.ts b/apps/server/src/modules/sharing/controller/share-token.controller.ts index 5320c5578f9..8417da758b6 100644 --- a/apps/server/src/modules/sharing/controller/share-token.controller.ts +++ b/apps/server/src/modules/sharing/controller/share-token.controller.ts @@ -90,7 +90,7 @@ export class ShareTokenController { currentUser.userId, urlParams.token, body.newName, - body.destinationCourseId + body.destination ); const response = CopyMapper.mapToResponse(copyStatus); diff --git a/apps/server/src/modules/sharing/sharing-api.module.ts b/apps/server/src/modules/sharing/sharing-api.module.ts new file mode 100644 index 00000000000..e81e4a8b48e --- /dev/null +++ b/apps/server/src/modules/sharing/sharing-api.module.ts @@ -0,0 +1,31 @@ +import { Module } from '@nestjs/common'; +import { LoggerModule } from '@src/core/logger'; +import { AuthorizationModule } from '../authorization'; +import { BoardModule } from '../board'; +import { LearnroomModule } from '../learnroom'; +import { LessonModule } from '../lesson'; +import { RoomModule } from '../room'; +import { RoomMemberModule } from '../room-member'; +import { SchoolModule } from '../school'; +import { TaskModule } from '../task'; +import { ShareTokenController } from './controller/share-token.controller'; +import { SharingModule } from './sharing.module'; +import { ShareTokenUC } from './uc'; + +@Module({ + imports: [ + SharingModule, + AuthorizationModule, + LearnroomModule, + LessonModule, + TaskModule, + BoardModule, + RoomMemberModule, + RoomModule, + SchoolModule, + LoggerModule, + ], + controllers: [ShareTokenController], + providers: [ShareTokenUC], +}) +export class SharingApiModule {} diff --git a/apps/server/src/modules/sharing/sharing.module.ts b/apps/server/src/modules/sharing/sharing.module.ts index 71773a87a6f..df417337f1e 100644 --- a/apps/server/src/modules/sharing/sharing.module.ts +++ b/apps/server/src/modules/sharing/sharing.module.ts @@ -1,46 +1,17 @@ -import { AuthorizationModule } from '@modules/authorization'; -import { AuthorizationReferenceModule } from '@modules/authorization-reference/authorization-reference.module'; import { BoardModule } from '@modules/board'; import { LearnroomModule } from '@modules/learnroom'; import { LessonModule } from '@modules/lesson'; -import { SchoolModule } from '@modules/school'; import { TaskModule } from '@modules/task'; import { Module } from '@nestjs/common'; import { LoggerModule } from '@src/core/logger'; -import { ShareTokenController } from './controller/share-token.controller'; +import { RoomModule } from '../room'; import { ShareTokenRepo } from './repo/share-token.repo'; import { ShareTokenService, TokenGenerator } from './service'; -import { ShareTokenUC } from './uc'; @Module({ - imports: [ - AuthorizationModule, - AuthorizationReferenceModule, - LoggerModule, - LearnroomModule, - LessonModule, - TaskModule, - BoardModule, - ], + imports: [LoggerModule, LearnroomModule, LessonModule, TaskModule, BoardModule, RoomModule], controllers: [], providers: [ShareTokenService, TokenGenerator, ShareTokenRepo], exports: [ShareTokenService], }) export class SharingModule {} - -@Module({ - imports: [ - SharingModule, - AuthorizationModule, - AuthorizationReferenceModule, - LearnroomModule, - LessonModule, - TaskModule, - LoggerModule, - BoardModule, - SchoolModule, - ], - controllers: [ShareTokenController], - providers: [ShareTokenUC], -}) -export class SharingApiModule {} diff --git a/apps/server/src/modules/sharing/uc/share-token.uc.ts b/apps/server/src/modules/sharing/uc/share-token.uc.ts index e8e0babd7bf..5550bf935ff 100644 --- a/apps/server/src/modules/sharing/uc/share-token.uc.ts +++ b/apps/server/src/modules/sharing/uc/share-token.uc.ts @@ -1,15 +1,24 @@ import { Configuration } from '@hpi-schul-cloud/commons/lib'; import { AuthorizationContextBuilder, AuthorizationService } from '@modules/authorization'; +import { + BoardExternalReference, + BoardExternalReferenceType, + BoardNodeAuthorizableService, + ColumnBoardService, +} from '@modules/board'; import { CopyStatus } from '@modules/copy-helper'; import { CourseCopyService, CourseService } from '@modules/learnroom'; import { LessonCopyService, LessonService } from '@modules/lesson'; import { TaskCopyService, TaskService } from '@modules/task'; import { BadRequestException, Injectable, InternalServerErrorException, NotImplementedException } from '@nestjs/common'; -import { BoardNodeAuthorizableService, BoardExternalReferenceType, ColumnBoardService } from '@modules/board'; import { Course, User } from '@shared/domain/entity'; import { Permission } from '@shared/domain/interface'; import { EntityId } from '@shared/domain/types'; import { LegacyLogger } from '@src/core/logger'; +import { StorageLocationReference } from '@src/modules/board/service/internal'; +import { StorageLocation } from '@src/modules/files-storage/interface'; +import { RoomService } from '@src/modules/room'; +import { RoomMemberService } from '@src/modules/room-member'; import { SchoolService } from '@src/modules/school'; import { ShareTokenContext, @@ -21,6 +30,16 @@ import { import { ShareTokenService } from '../service'; import { ShareTokenInfoDto } from './dto'; +export enum ImportDestinationType { + 'Course' = 'course', + 'Room' = 'room', +} + +export type ImportDestination = { + type: ImportDestinationType; + id: EntityId; +}; + @Injectable() export class ShareTokenUC { constructor( @@ -29,10 +48,12 @@ export class ShareTokenUC { private readonly courseCopyService: CourseCopyService, private readonly lessonCopyService: LessonCopyService, private readonly taskCopyService: TaskCopyService, - private readonly columnBoardService: ColumnBoardService, private readonly courseService: CourseService, private readonly lessonService: LessonService, private readonly taskService: TaskService, + private readonly roomService: RoomService, + private readonly roomMemberService: RoomMemberService, + private readonly columnBoardService: ColumnBoardService, private readonly schoolService: SchoolService, private readonly boardNodeAuthorizableService: BoardNodeAuthorizableService, private readonly logger: LegacyLogger @@ -94,7 +115,7 @@ export class ShareTokenUC { userId: EntityId, token: string, newName: string, - destinationCourseId?: string + destination?: ImportDestination ): Promise { this.logger.debug({ action: 'importShareToken', userId, token, newName }); @@ -115,22 +136,31 @@ export class ShareTokenUC { result = await this.copyCourse(user, shareToken.payload.parentId, newName); break; case ShareTokenParentType.Lesson: - if (destinationCourseId === undefined) { - throw new BadRequestException('Destination course id is required to copy lesson'); + if (destination?.type !== ImportDestinationType.Course) { + throw new BadRequestException('Cannot copy lesson without destination course reference'); } - result = await this.copyLesson(user, shareToken.payload.parentId, destinationCourseId, newName); + result = await this.copyLesson(user, shareToken.payload.parentId, destination.id, newName); break; case ShareTokenParentType.Task: - if (destinationCourseId === undefined) { - throw new BadRequestException('Destination course id is required to copy task'); + if (destination?.type !== ImportDestinationType.Course) { + throw new BadRequestException('Cannot copy task without destination course reference'); } - result = await this.copyTask(user, shareToken.payload.parentId, destinationCourseId, newName); + result = await this.copyTask(user, shareToken.payload.parentId, destination.id, newName); break; case ShareTokenParentType.ColumnBoard: - if (destinationCourseId === undefined) { - throw new BadRequestException('Destination course id is required to copy task'); + { + if (destination?.type !== ImportDestinationType.Course && destination?.type !== ImportDestinationType.Room) { + throw new BadRequestException('Cannot copy board without destination course or room reference'); + } + const targetExternalReference: BoardExternalReference = { + id: destination.id, + type: + destination.type === ImportDestinationType.Course + ? BoardExternalReferenceType.Course + : BoardExternalReferenceType.Room, + }; + result = await this.copyColumnBoard(user, shareToken.payload.parentId, targetExternalReference, newName); } - result = await this.copyColumnBoard(user, shareToken.payload.parentId, destinationCourseId, newName); break; } @@ -180,14 +210,25 @@ export class ShareTokenUC { private async copyColumnBoard( user: User, originalColumnBoardId: string, - courseId: string, + targetExternalReference: BoardExternalReference, copyTitle?: string ): Promise { - await this.checkCourseWritePermission(user, courseId, Permission.COURSE_EDIT); + await this.checkBoardReferenceWritePermission(user, targetExternalReference); + + const originalBoard = await this.columnBoardService.findById(originalColumnBoardId); + const sourceStorageLocationReference = await this.getStorageLocationReference(originalBoard.context); + const targetStorageLocationReference = await this.getStorageLocationReference(targetExternalReference); + + // Maybe this check is not needed + // if (originalBoard.context.type !== targetExternalReference.type) { + // throw new BadRequestException('Cannot copy column board between different reference types'); + // } const copyStatus = this.columnBoardService.copyColumnBoard({ originalColumnBoardId, - destinationExternalReference: { type: BoardExternalReferenceType.Course, id: courseId }, + targetExternalReference, + sourceStorageLocationReference, + targetStorageLocationReference, userId: user.id, copyTitle, }); @@ -225,6 +266,16 @@ export class ShareTokenUC { }; } + private async checkRoomWritePermission(user: User, roomId: EntityId, permissions: Permission[] = []) { + const roomMemberAuthorizable = await this.roomMemberService.getRoomMemberAuthorizable(roomId); + + this.authorizationService.checkPermission( + user, + roomMemberAuthorizable, + AuthorizationContextBuilder.write(permissions) + ); + } + private async checkLessonWritePermission(user: User, lessonId: EntityId, permission: Permission) { const lesson = await this.lessonService.findById(lessonId); this.authorizationService.checkPermission(user, lesson, AuthorizationContextBuilder.write([permission])); @@ -237,11 +288,11 @@ export class ShareTokenUC { private async checkColumnBoardWritePermission(user: User, boardNodeId: EntityId, permission: Permission) { const columBoard = await this.columnBoardService.findById(boardNodeId); - const boardNodeAuthorizableService = await this.boardNodeAuthorizableService.getBoardAuthorizable(columBoard); + const boardNodeAuthorizable = await this.boardNodeAuthorizableService.getBoardAuthorizable(columBoard); this.authorizationService.checkPermission( user, - boardNodeAuthorizableService, + boardNodeAuthorizable, AuthorizationContextBuilder.write([permission]) ); } @@ -320,4 +371,32 @@ export class ShareTokenUC { throw new NotImplementedException('Import Feature not implemented'); } } + + // ---- Move to shared service? (see apps/server/src/modules/board/uc/board.uc.ts) + + private async checkBoardReferenceWritePermission(user: User, boardExternalReference: BoardExternalReference) { + if (boardExternalReference.type === BoardExternalReferenceType.Course) { + await this.checkCourseWritePermission(user, boardExternalReference.id, Permission.COURSE_EDIT); + } else if (boardExternalReference.type === BoardExternalReferenceType.Room) { + await this.checkRoomWritePermission(user, boardExternalReference.id); + } else { + throw new Error(`Unsupported target reference type ${boardExternalReference.type as string}`); + } + } + + private async getStorageLocationReference(context: BoardExternalReference): Promise { + if (context.type === BoardExternalReferenceType.Course) { + const course = await this.courseService.findById(context.id); + + return { id: course.school.id, type: StorageLocation.SCHOOL }; + } + + if (context.type === BoardExternalReferenceType.Room) { + const room = await this.roomService.getSingleRoom(context.id); + + return { id: room.schoolId, type: StorageLocation.SCHOOL }; + } + + throw new Error(`Cannot get storage location reference for context type ${context.type as string}`); + } } From 5dc2227ea80727519a78a47b0a1f9d577357bb13 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Fri, 15 Nov 2024 16:12:27 +0100 Subject: [PATCH 12/60] remove comment --- apps/server/src/modules/room/api/room.uc.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/server/src/modules/room/api/room.uc.ts b/apps/server/src/modules/room/api/room.uc.ts index e426c47d24b..526d06fd6bd 100644 --- a/apps/server/src/modules/room/api/room.uc.ts +++ b/apps/server/src/modules/room/api/room.uc.ts @@ -35,17 +35,18 @@ export class RoomUc { public async createRoom(userId: EntityId, props: CreateRoomBodyParams): Promise { this.checkFeatureEnabled(); - const user = await this.authorizationService.getUserWithPermissions(userId); const room = await this.roomService.createRoom({ ...props, schoolId: user.school.id }); - // NOTE: currently only teachers are allowed to create rooms. Could not find simpler way to check this. + this.authorizationService.checkOneOfPermissions(user, [Permission.ROOM_CREATE]); + await this.roomMemberService .addMembersToRoom(room.id, [{ userId: user.id, roleName: RoleName.ROOM_EDITOR }], user.school.id) .catch(async (err) => { await this.roomService.deleteRoom(room); throw err; }); + return room; } From a50cfd00092c72b305aee0545b8ead04f086a8d0 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Sun, 17 Nov 2024 20:56:56 +0100 Subject: [PATCH 13/60] simplify destination reference for sahre token import --- .../dto/share-token-import.body.params.ts | 26 ++-------- .../controller/share-token.controller.ts | 2 +- .../src/modules/sharing/uc/share-token.uc.ts | 52 ++++++------------- 3 files changed, 19 insertions(+), 61 deletions(-) diff --git a/apps/server/src/modules/sharing/controller/dto/share-token-import.body.params.ts b/apps/server/src/modules/sharing/controller/dto/share-token-import.body.params.ts index 4484b671087..28453a6a4c7 100644 --- a/apps/server/src/modules/sharing/controller/dto/share-token-import.body.params.ts +++ b/apps/server/src/modules/sharing/controller/dto/share-token-import.body.params.ts @@ -1,25 +1,6 @@ import { ApiProperty } from '@nestjs/swagger'; import { SanitizeHtml } from '@shared/controller'; import { IsOptional, IsString } from 'class-validator'; -import { ImportDestination, ImportDestinationType } from '../../uc'; - -export class ImportDestinationBodyParams { - @IsString() - @ApiProperty({ - description: 'The id of the destination object.', - required: true, - nullable: false, - }) - id!: string; - - @ApiProperty({ - enum: ImportDestinationType, - description: 'The type of the destination object.', - required: true, - nullable: false, - }) - type!: ImportDestinationType; -} export class ShareTokenImportBodyParams { @IsString() @@ -32,12 +13,11 @@ export class ShareTokenImportBodyParams { newName!: string; @IsOptional() + @IsString() @ApiProperty({ - type: ImportDestinationBodyParams, - name: 'ImportDestination', - description: 'Destination of the share token import', + description: 'Id of the parent to which the imported object will be added.', required: false, nullable: true, }) - destination?: ImportDestination; + destinationId?: string; } diff --git a/apps/server/src/modules/sharing/controller/share-token.controller.ts b/apps/server/src/modules/sharing/controller/share-token.controller.ts index 8417da758b6..d85937cbb62 100644 --- a/apps/server/src/modules/sharing/controller/share-token.controller.ts +++ b/apps/server/src/modules/sharing/controller/share-token.controller.ts @@ -90,7 +90,7 @@ export class ShareTokenController { currentUser.userId, urlParams.token, body.newName, - body.destination + body.destinationId ); const response = CopyMapper.mapToResponse(copyStatus); diff --git a/apps/server/src/modules/sharing/uc/share-token.uc.ts b/apps/server/src/modules/sharing/uc/share-token.uc.ts index 5550bf935ff..a8ed696fdfb 100644 --- a/apps/server/src/modules/sharing/uc/share-token.uc.ts +++ b/apps/server/src/modules/sharing/uc/share-token.uc.ts @@ -30,16 +30,6 @@ import { import { ShareTokenService } from '../service'; import { ShareTokenInfoDto } from './dto'; -export enum ImportDestinationType { - 'Course' = 'course', - 'Room' = 'room', -} - -export type ImportDestination = { - type: ImportDestinationType; - id: EntityId; -}; - @Injectable() export class ShareTokenUC { constructor( @@ -115,7 +105,7 @@ export class ShareTokenUC { userId: EntityId, token: string, newName: string, - destination?: ImportDestination + destinationId?: EntityId ): Promise { this.logger.debug({ action: 'importShareToken', userId, token, newName }); @@ -136,31 +126,22 @@ export class ShareTokenUC { result = await this.copyCourse(user, shareToken.payload.parentId, newName); break; case ShareTokenParentType.Lesson: - if (destination?.type !== ImportDestinationType.Course) { + if (destinationId === undefined) { throw new BadRequestException('Cannot copy lesson without destination course reference'); } - result = await this.copyLesson(user, shareToken.payload.parentId, destination.id, newName); + result = await this.copyLesson(user, shareToken.payload.parentId, destinationId, newName); break; case ShareTokenParentType.Task: - if (destination?.type !== ImportDestinationType.Course) { + if (destinationId === undefined) { throw new BadRequestException('Cannot copy task without destination course reference'); } - result = await this.copyTask(user, shareToken.payload.parentId, destination.id, newName); + result = await this.copyTask(user, shareToken.payload.parentId, destinationId, newName); break; case ShareTokenParentType.ColumnBoard: - { - if (destination?.type !== ImportDestinationType.Course && destination?.type !== ImportDestinationType.Room) { - throw new BadRequestException('Cannot copy board without destination course or room reference'); - } - const targetExternalReference: BoardExternalReference = { - id: destination.id, - type: - destination.type === ImportDestinationType.Course - ? BoardExternalReferenceType.Course - : BoardExternalReferenceType.Room, - }; - result = await this.copyColumnBoard(user, shareToken.payload.parentId, targetExternalReference, newName); + if (destinationId === undefined) { + throw new BadRequestException('Cannot copy board without destination course or room reference'); } + result = await this.copyColumnBoard(user, shareToken.payload.parentId, destinationId, newName); break; } @@ -210,23 +191,20 @@ export class ShareTokenUC { private async copyColumnBoard( user: User, originalColumnBoardId: string, - targetExternalReference: BoardExternalReference, + destinationId: EntityId, copyTitle?: string ): Promise { - await this.checkBoardReferenceWritePermission(user, targetExternalReference); + const originalBoard = await this.columnBoardService.findById(originalColumnBoardId, 0); + const destinationBoard = await this.columnBoardService.findById(destinationId, 0); - const originalBoard = await this.columnBoardService.findById(originalColumnBoardId); - const sourceStorageLocationReference = await this.getStorageLocationReference(originalBoard.context); - const targetStorageLocationReference = await this.getStorageLocationReference(targetExternalReference); + await this.checkBoardReferenceWritePermission(user, destinationBoard.context); - // Maybe this check is not needed - // if (originalBoard.context.type !== targetExternalReference.type) { - // throw new BadRequestException('Cannot copy column board between different reference types'); - // } + const sourceStorageLocationReference = await this.getStorageLocationReference(originalBoard.context); + const targetStorageLocationReference = await this.getStorageLocationReference(destinationBoard.context); const copyStatus = this.columnBoardService.copyColumnBoard({ originalColumnBoardId, - targetExternalReference, + targetExternalReference: destinationBoard.context, sourceStorageLocationReference, targetStorageLocationReference, userId: user.id, From c776afa888aa3190f39a6d4c85b4f0ecca8ebef3 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 19 Nov 2024 08:58:03 +0100 Subject: [PATCH 14/60] refactor share import destination --- .../models/copy-api-response.ts | 168 +++++++++-------- .../models/copy-api-response.ts | 170 +++++++++--------- .../modules/copy-helper/dto/copy.response.ts | 4 +- .../modules/copy-helper/mapper/copy.mapper.ts | 8 +- .../modules/sharing/uc/share-token.uc.spec.ts | 4 +- .../src/modules/sharing/uc/share-token.uc.ts | 12 +- 6 files changed, 184 insertions(+), 182 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/board-client/board-api-client/models/copy-api-response.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/board-client/board-api-client/models/copy-api-response.ts index 4921f0d6484..3c78d846edc 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/board-client/board-api-client/models/copy-api-response.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/board-client/board-api-client/models/copy-api-response.ts @@ -5,110 +5,106 @@ * This is v3 of Schulcloud-Verbund-Software Server. Checkout /docs for v1. * * The version of the OpenAPI document: 3.0 - * + * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). * https://openapi-generator.tech * Do not edit the class manually. */ - - /** - * + * * @export * @interface CopyApiResponse */ export interface CopyApiResponse { - /** - * Id of copied element - * @type {string} - * @memberof CopyApiResponse - */ - 'id'?: string; - /** - * Title of copied element - * @type {string} - * @memberof CopyApiResponse - */ - 'title'?: string; - /** - * Type of copied element - * @type {string} - * @memberof CopyApiResponse - */ - 'type': CopyApiResponseType; - /** - * Id of destination course - * @type {string} - * @memberof CopyApiResponse - */ - 'destinationCourseId'?: string; - /** - * Copy progress status of copied element - * @type {string} - * @memberof CopyApiResponse - */ - 'status': CopyApiResponseStatus; - /** - * List of included sub elements with recursive type structure - * @type {Array} - * @memberof CopyApiResponse - */ - 'elements'?: Array; + /** + * Id of copied element + * @type {string} + * @memberof CopyApiResponse + */ + id?: string; + /** + * Title of copied element + * @type {string} + * @memberof CopyApiResponse + */ + title?: string; + /** + * Type of copied element + * @type {string} + * @memberof CopyApiResponse + */ + type: CopyApiResponseType; + /** + * Id of destination parent reference + * @type {string} + * @memberof CopyApiResponse + */ + destinationId?: string; + /** + * Copy progress status of copied element + * @type {string} + * @memberof CopyApiResponse + */ + status: CopyApiResponseStatus; + /** + * List of included sub elements with recursive type structure + * @type {Array} + * @memberof CopyApiResponse + */ + elements?: Array; } export const CopyApiResponseType = { - BOARD: 'BOARD', - CARD: 'CARD', - COLLABORATIVE_TEXT_EDITOR_ELEMENT: 'COLLABORATIVE_TEXT_EDITOR_ELEMENT', - COLUMN: 'COLUMN', - COLUMNBOARD: 'COLUMNBOARD', - CONTENT: 'CONTENT', - COURSE: 'COURSE', - COURSEGROUP_GROUP: 'COURSEGROUP_GROUP', - EXTERNAL_TOOL: 'EXTERNAL_TOOL', - EXTERNAL_TOOL_ELEMENT: 'EXTERNAL_TOOL_ELEMENT', - FILE: 'FILE', - FILE_ELEMENT: 'FILE_ELEMENT', - DRAWING_ELEMENT: 'DRAWING_ELEMENT', - FILE_GROUP: 'FILE_GROUP', - LEAF: 'LEAF', - LESSON: 'LESSON', - LESSON_CONTENT_ETHERPAD: 'LESSON_CONTENT_ETHERPAD', - LESSON_CONTENT_GEOGEBRA: 'LESSON_CONTENT_GEOGEBRA', - LESSON_CONTENT_GROUP: 'LESSON_CONTENT_GROUP', - LESSON_CONTENT_LERNSTORE: 'LESSON_CONTENT_LERNSTORE', - LESSON_CONTENT_NEXBOARD: 'LESSON_CONTENT_NEXBOARD', - LESSON_CONTENT_TASK: 'LESSON_CONTENT_TASK', - LESSON_CONTENT_TEXT: 'LESSON_CONTENT_TEXT', - LERNSTORE_MATERIAL: 'LERNSTORE_MATERIAL', - LERNSTORE_MATERIAL_GROUP: 'LERNSTORE_MATERIAL_GROUP', - LINK_ELEMENT: 'LINK_ELEMENT', - LTITOOL_GROUP: 'LTITOOL_GROUP', - MEDIA_BOARD: 'MEDIA_BOARD', - MEDIA_LINE: 'MEDIA_LINE', - MEDIA_EXTERNAL_TOOL_ELEMENT: 'MEDIA_EXTERNAL_TOOL_ELEMENT', - METADATA: 'METADATA', - RICHTEXT_ELEMENT: 'RICHTEXT_ELEMENT', - SUBMISSION_CONTAINER_ELEMENT: 'SUBMISSION_CONTAINER_ELEMENT', - SUBMISSION_ITEM: 'SUBMISSION_ITEM', - SUBMISSION_GROUP: 'SUBMISSION_GROUP', - TASK: 'TASK', - TASK_GROUP: 'TASK_GROUP', - TIME_GROUP: 'TIME_GROUP', - USER_GROUP: 'USER_GROUP' + BOARD: 'BOARD', + CARD: 'CARD', + COLLABORATIVE_TEXT_EDITOR_ELEMENT: 'COLLABORATIVE_TEXT_EDITOR_ELEMENT', + COLUMN: 'COLUMN', + COLUMNBOARD: 'COLUMNBOARD', + CONTENT: 'CONTENT', + COURSE: 'COURSE', + COURSEGROUP_GROUP: 'COURSEGROUP_GROUP', + EXTERNAL_TOOL: 'EXTERNAL_TOOL', + EXTERNAL_TOOL_ELEMENT: 'EXTERNAL_TOOL_ELEMENT', + FILE: 'FILE', + FILE_ELEMENT: 'FILE_ELEMENT', + DRAWING_ELEMENT: 'DRAWING_ELEMENT', + FILE_GROUP: 'FILE_GROUP', + LEAF: 'LEAF', + LESSON: 'LESSON', + LESSON_CONTENT_ETHERPAD: 'LESSON_CONTENT_ETHERPAD', + LESSON_CONTENT_GEOGEBRA: 'LESSON_CONTENT_GEOGEBRA', + LESSON_CONTENT_GROUP: 'LESSON_CONTENT_GROUP', + LESSON_CONTENT_LERNSTORE: 'LESSON_CONTENT_LERNSTORE', + LESSON_CONTENT_NEXBOARD: 'LESSON_CONTENT_NEXBOARD', + LESSON_CONTENT_TASK: 'LESSON_CONTENT_TASK', + LESSON_CONTENT_TEXT: 'LESSON_CONTENT_TEXT', + LERNSTORE_MATERIAL: 'LERNSTORE_MATERIAL', + LERNSTORE_MATERIAL_GROUP: 'LERNSTORE_MATERIAL_GROUP', + LINK_ELEMENT: 'LINK_ELEMENT', + LTITOOL_GROUP: 'LTITOOL_GROUP', + MEDIA_BOARD: 'MEDIA_BOARD', + MEDIA_LINE: 'MEDIA_LINE', + MEDIA_EXTERNAL_TOOL_ELEMENT: 'MEDIA_EXTERNAL_TOOL_ELEMENT', + METADATA: 'METADATA', + RICHTEXT_ELEMENT: 'RICHTEXT_ELEMENT', + SUBMISSION_CONTAINER_ELEMENT: 'SUBMISSION_CONTAINER_ELEMENT', + SUBMISSION_ITEM: 'SUBMISSION_ITEM', + SUBMISSION_GROUP: 'SUBMISSION_GROUP', + TASK: 'TASK', + TASK_GROUP: 'TASK_GROUP', + TIME_GROUP: 'TIME_GROUP', + USER_GROUP: 'USER_GROUP', } as const; export type CopyApiResponseType = typeof CopyApiResponseType[keyof typeof CopyApiResponseType]; export const CopyApiResponseStatus = { - SUCCESS: 'success', - FAILURE: 'failure', - NOT_DOING: 'not-doing', - NOT_IMPLEMENTED: 'not-implemented', - PARTIAL: 'partial' + SUCCESS: 'success', + FAILURE: 'failure', + NOT_DOING: 'not-doing', + NOT_IMPLEMENTED: 'not-implemented', + PARTIAL: 'partial', } as const; export type CopyApiResponseStatus = typeof CopyApiResponseStatus[keyof typeof CopyApiResponseStatus]; - - diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/room-api-client/models/copy-api-response.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/room-api-client/models/copy-api-response.ts index dd356d1e871..a4b72536f13 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/room-api-client/models/copy-api-response.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/room-api-client/models/copy-api-response.ts @@ -5,111 +5,107 @@ * This is v3 of Schulcloud-Verbund-Software Server. Checkout /docs for v1. * * The version of the OpenAPI document: 3.0 - * + * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). * https://openapi-generator.tech * Do not edit the class manually. */ - - /** - * + * * @export * @interface CopyApiResponse */ export interface CopyApiResponse { - /** - * Id of copied element - * @type {string} - * @memberof CopyApiResponse - */ - 'id'?: string; - /** - * Title of copied element - * @type {string} - * @memberof CopyApiResponse - */ - 'title'?: string; - /** - * Type of copied element - * @type {string} - * @memberof CopyApiResponse - */ - 'type': CopyApiResponseType; - /** - * Id of destination course - * @type {string} - * @memberof CopyApiResponse - */ - 'destinationCourseId'?: string; - /** - * Copy progress status of copied element - * @type {string} - * @memberof CopyApiResponse - */ - 'status': CopyApiResponseStatus; - /** - * List of included sub elements with recursive type structure - * @type {Array} - * @memberof CopyApiResponse - */ - 'elements'?: Array; + /** + * Id of copied element + * @type {string} + * @memberof CopyApiResponse + */ + id?: string; + /** + * Title of copied element + * @type {string} + * @memberof CopyApiResponse + */ + title?: string; + /** + * Type of copied element + * @type {string} + * @memberof CopyApiResponse + */ + type: CopyApiResponseType; + /** + * Id of destination parent reference + * @type {string} + * @memberof CopyApiResponse + */ + destinationId?: string; + /** + * Copy progress status of copied element + * @type {string} + * @memberof CopyApiResponse + */ + status: CopyApiResponseStatus; + /** + * List of included sub elements with recursive type structure + * @type {Array} + * @memberof CopyApiResponse + */ + elements?: Array; } export const CopyApiResponseType = { - BOARD: 'BOARD', - CARD: 'CARD', - COLLABORATIVE_TEXT_EDITOR_ELEMENT: 'COLLABORATIVE_TEXT_EDITOR_ELEMENT', - COLUMN: 'COLUMN', - COLUMNBOARD: 'COLUMNBOARD', - CONTENT: 'CONTENT', - COURSE: 'COURSE', - COURSEGROUP_GROUP: 'COURSEGROUP_GROUP', - DELETED_ELEMENT: 'DELETED_ELEMENT', - EXTERNAL_TOOL: 'EXTERNAL_TOOL', - EXTERNAL_TOOL_ELEMENT: 'EXTERNAL_TOOL_ELEMENT', - FILE: 'FILE', - FILE_ELEMENT: 'FILE_ELEMENT', - DRAWING_ELEMENT: 'DRAWING_ELEMENT', - FILE_GROUP: 'FILE_GROUP', - LEAF: 'LEAF', - LESSON: 'LESSON', - LESSON_CONTENT_ETHERPAD: 'LESSON_CONTENT_ETHERPAD', - LESSON_CONTENT_GEOGEBRA: 'LESSON_CONTENT_GEOGEBRA', - LESSON_CONTENT_GROUP: 'LESSON_CONTENT_GROUP', - LESSON_CONTENT_LERNSTORE: 'LESSON_CONTENT_LERNSTORE', - LESSON_CONTENT_NEXBOARD: 'LESSON_CONTENT_NEXBOARD', - LESSON_CONTENT_TASK: 'LESSON_CONTENT_TASK', - LESSON_CONTENT_TEXT: 'LESSON_CONTENT_TEXT', - LERNSTORE_MATERIAL: 'LERNSTORE_MATERIAL', - LERNSTORE_MATERIAL_GROUP: 'LERNSTORE_MATERIAL_GROUP', - LINK_ELEMENT: 'LINK_ELEMENT', - LTITOOL_GROUP: 'LTITOOL_GROUP', - MEDIA_BOARD: 'MEDIA_BOARD', - MEDIA_LINE: 'MEDIA_LINE', - MEDIA_EXTERNAL_TOOL_ELEMENT: 'MEDIA_EXTERNAL_TOOL_ELEMENT', - METADATA: 'METADATA', - RICHTEXT_ELEMENT: 'RICHTEXT_ELEMENT', - SUBMISSION_CONTAINER_ELEMENT: 'SUBMISSION_CONTAINER_ELEMENT', - SUBMISSION_ITEM: 'SUBMISSION_ITEM', - SUBMISSION_GROUP: 'SUBMISSION_GROUP', - TASK: 'TASK', - TASK_GROUP: 'TASK_GROUP', - TIME_GROUP: 'TIME_GROUP', - USER_GROUP: 'USER_GROUP' + BOARD: 'BOARD', + CARD: 'CARD', + COLLABORATIVE_TEXT_EDITOR_ELEMENT: 'COLLABORATIVE_TEXT_EDITOR_ELEMENT', + COLUMN: 'COLUMN', + COLUMNBOARD: 'COLUMNBOARD', + CONTENT: 'CONTENT', + COURSE: 'COURSE', + COURSEGROUP_GROUP: 'COURSEGROUP_GROUP', + DELETED_ELEMENT: 'DELETED_ELEMENT', + EXTERNAL_TOOL: 'EXTERNAL_TOOL', + EXTERNAL_TOOL_ELEMENT: 'EXTERNAL_TOOL_ELEMENT', + FILE: 'FILE', + FILE_ELEMENT: 'FILE_ELEMENT', + DRAWING_ELEMENT: 'DRAWING_ELEMENT', + FILE_GROUP: 'FILE_GROUP', + LEAF: 'LEAF', + LESSON: 'LESSON', + LESSON_CONTENT_ETHERPAD: 'LESSON_CONTENT_ETHERPAD', + LESSON_CONTENT_GEOGEBRA: 'LESSON_CONTENT_GEOGEBRA', + LESSON_CONTENT_GROUP: 'LESSON_CONTENT_GROUP', + LESSON_CONTENT_LERNSTORE: 'LESSON_CONTENT_LERNSTORE', + LESSON_CONTENT_NEXBOARD: 'LESSON_CONTENT_NEXBOARD', + LESSON_CONTENT_TASK: 'LESSON_CONTENT_TASK', + LESSON_CONTENT_TEXT: 'LESSON_CONTENT_TEXT', + LERNSTORE_MATERIAL: 'LERNSTORE_MATERIAL', + LERNSTORE_MATERIAL_GROUP: 'LERNSTORE_MATERIAL_GROUP', + LINK_ELEMENT: 'LINK_ELEMENT', + LTITOOL_GROUP: 'LTITOOL_GROUP', + MEDIA_BOARD: 'MEDIA_BOARD', + MEDIA_LINE: 'MEDIA_LINE', + MEDIA_EXTERNAL_TOOL_ELEMENT: 'MEDIA_EXTERNAL_TOOL_ELEMENT', + METADATA: 'METADATA', + RICHTEXT_ELEMENT: 'RICHTEXT_ELEMENT', + SUBMISSION_CONTAINER_ELEMENT: 'SUBMISSION_CONTAINER_ELEMENT', + SUBMISSION_ITEM: 'SUBMISSION_ITEM', + SUBMISSION_GROUP: 'SUBMISSION_GROUP', + TASK: 'TASK', + TASK_GROUP: 'TASK_GROUP', + TIME_GROUP: 'TIME_GROUP', + USER_GROUP: 'USER_GROUP', } as const; export type CopyApiResponseType = typeof CopyApiResponseType[keyof typeof CopyApiResponseType]; export const CopyApiResponseStatus = { - SUCCESS: 'success', - FAILURE: 'failure', - NOT_DOING: 'not-doing', - NOT_IMPLEMENTED: 'not-implemented', - PARTIAL: 'partial' + SUCCESS: 'success', + FAILURE: 'failure', + NOT_DOING: 'not-doing', + NOT_IMPLEMENTED: 'not-implemented', + PARTIAL: 'partial', } as const; export type CopyApiResponseStatus = typeof CopyApiResponseStatus[keyof typeof CopyApiResponseStatus]; - - diff --git a/apps/server/src/modules/copy-helper/dto/copy.response.ts b/apps/server/src/modules/copy-helper/dto/copy.response.ts index 549dcac7014..3f4cd8cebac 100644 --- a/apps/server/src/modules/copy-helper/dto/copy.response.ts +++ b/apps/server/src/modules/copy-helper/dto/copy.response.ts @@ -29,9 +29,9 @@ export class CopyApiResponse { type: CopyElementType; @ApiPropertyOptional({ - description: 'Id of destination course', + description: 'Id of destination parent reference', }) - destinationCourseId?: string; + destinationId?: string; @ApiProperty({ type: 'string', diff --git a/apps/server/src/modules/copy-helper/mapper/copy.mapper.ts b/apps/server/src/modules/copy-helper/mapper/copy.mapper.ts index 581e33161bd..94d0c7d75d9 100644 --- a/apps/server/src/modules/copy-helper/mapper/copy.mapper.ts +++ b/apps/server/src/modules/copy-helper/mapper/copy.mapper.ts @@ -4,6 +4,7 @@ import { TaskCopyApiParams } from '@modules/task/controller/dto/task-copy.params import { TaskCopyParentParams } from '@modules/task/types'; import { LessonEntity, Task } from '@shared/domain/entity'; import { EntityId } from '@shared/domain/types'; +import { ColumnBoard } from '@src/modules/board'; import { CopyApiResponse } from '../dto/copy.response'; import { CopyStatus, CopyStatusEnum } from '../types/copy.types'; @@ -18,7 +19,12 @@ export class CopyMapper { if (copyStatus.copyEntity) { const copyEntity = copyStatus.copyEntity as LessonEntity | Task; dto.id = copyEntity.id; - dto.destinationCourseId = copyEntity.course?.id; + if (copyEntity instanceof LessonEntity || copyEntity instanceof Task) { + dto.destinationId = copyEntity.course?.id; + } + if (copyEntity instanceof ColumnBoard) { + dto.destinationId = copyEntity.context?.id; + } } if (copyStatus.status !== CopyStatusEnum.SUCCESS && copyStatus.elements) { dto.elements = copyStatus.elements diff --git a/apps/server/src/modules/sharing/uc/share-token.uc.spec.ts b/apps/server/src/modules/sharing/uc/share-token.uc.spec.ts index 4b33a73d438..c8692d3ac40 100644 --- a/apps/server/src/modules/sharing/uc/share-token.uc.spec.ts +++ b/apps/server/src/modules/sharing/uc/share-token.uc.spec.ts @@ -926,7 +926,7 @@ describe('ShareTokenUC', () => { ); }); - it('should throw if the destinationCourseId is not passed', async () => { + it('should throw if the destinationId is not passed', async () => { const { user, shareToken } = setup(); await expect(uc.importShareToken(user.id, shareToken.token, 'NewName')).rejects.toThrowError( @@ -1012,7 +1012,7 @@ describe('ShareTokenUC', () => { ); }); - it('should throw if the destinationCourseId is not passed', async () => { + it('should throw if the destinationId is not passed', async () => { const { user, shareToken } = setupTask(); await expect(uc.importShareToken(user.id, shareToken.token, 'NewName')).rejects.toThrowError( diff --git a/apps/server/src/modules/sharing/uc/share-token.uc.ts b/apps/server/src/modules/sharing/uc/share-token.uc.ts index a8ed696fdfb..60312fd0ec6 100644 --- a/apps/server/src/modules/sharing/uc/share-token.uc.ts +++ b/apps/server/src/modules/sharing/uc/share-token.uc.ts @@ -195,16 +195,20 @@ export class ShareTokenUC { copyTitle?: string ): Promise { const originalBoard = await this.columnBoardService.findById(originalColumnBoardId, 0); - const destinationBoard = await this.columnBoardService.findById(destinationId, 0); - await this.checkBoardReferenceWritePermission(user, destinationBoard.context); + const targetExternalReference: BoardExternalReference = { + id: destinationId, + type: originalBoard.context.type, + }; + + await this.checkBoardReferenceWritePermission(user, targetExternalReference); const sourceStorageLocationReference = await this.getStorageLocationReference(originalBoard.context); - const targetStorageLocationReference = await this.getStorageLocationReference(destinationBoard.context); + const targetStorageLocationReference = await this.getStorageLocationReference(targetExternalReference); const copyStatus = this.columnBoardService.copyColumnBoard({ originalColumnBoardId, - targetExternalReference: destinationBoard.context, + targetExternalReference, sourceStorageLocationReference, targetStorageLocationReference, userId: user.id, From c26af4281dc515a247530ab01a4d9e90682b5027 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 19 Nov 2024 16:20:24 +0100 Subject: [PATCH 15/60] rename room role enum keys --- .../mikro-orm/Migration202410041210124.ts | 20 +++++++++---------- .../mikro-orm/Migration202411111604124.ts | 16 +++++++-------- .../board-context-in-rooms.api.spec.ts | 4 ++-- .../api-test/board-create-in-room.api.spec.ts | 6 +++--- .../api-test/board-delete-in-room.api.spec.ts | 4 ++-- .../api-test/board-lookup-in-room.api.spec.ts | 4 ++-- .../board-update-title-in-room.api.spec.ts | 4 ++-- .../board-visibility-in-room.api.spec.ts | 4 ++-- .../internal/board-context.service.spec.ts | 4 ++-- .../service/room-member.service.spec.ts | 6 +++--- .../service/room-member.service.ts | 4 ++-- apps/server/src/modules/room/api/room.uc.ts | 2 +- .../api/test/room-add-members.api.spec.ts | 4 ++-- .../room/api/test/room-create.api.spec.ts | 2 +- .../room/api/test/room-delete.api.spec.ts | 2 +- .../room/api/test/room-get-boards.api.spec.ts | 2 +- .../room/api/test/room-get.api.spec.ts | 2 +- .../room/api/test/room-index.api.spec.ts | 2 +- .../room/api/test/room-members.api.spec.ts | 4 ++-- .../api/test/room-remove-members.api.spec.ts | 4 ++-- .../room/api/test/room-update.api.spec.ts | 2 +- .../shared/domain/interface/rolename.enum.ts | 6 +++--- 22 files changed, 54 insertions(+), 54 deletions(-) diff --git a/apps/server/src/migrations/mikro-orm/Migration202410041210124.ts b/apps/server/src/migrations/mikro-orm/Migration202410041210124.ts index c18d21eb11c..ff244c257c2 100644 --- a/apps/server/src/migrations/mikro-orm/Migration202410041210124.ts +++ b/apps/server/src/migrations/mikro-orm/Migration202410041210124.ts @@ -2,28 +2,28 @@ import { Migration } from '@mikro-orm/migrations-mongodb'; export class Migration202410041210124 extends Migration { async up(): Promise { - // Add ROOM_VIEWER role + // Add ROOMVIEWER role await this.getCollection('roles').insertOne({ name: 'room_viewer', permissions: ['ROOM_VIEW'], }); - console.info('Added ROOM_VIEWER role with ROOM_VIEW permission'); + console.info('Added ROOMVIEWER role with ROOM_VIEW permission'); - // Add ROOM_EDITOR role + // Add ROOMEDITOR role await this.getCollection('roles').insertOne({ name: 'room_editor', permissions: ['ROOM_VIEW', 'ROOM_EDIT'], }); - console.info('Added ROOM_EDITOR role with ROOM_VIEW and ROOM_EDIT permissions'); + console.info('Added ROOMEDITOR role with ROOM_VIEW and ROOM_EDIT permissions'); } async down(): Promise { - // Remove ROOM_VIEWER role - await this.getCollection('roles').deleteOne({ name: 'ROOM_VIEWER' }); - console.info('Rollback: Removed ROOM_VIEWER role'); + // Remove ROOMVIEWER role + await this.getCollection('roles').deleteOne({ name: 'room_viewer' }); + console.info('Rollback: Removed ROOMVIEWER role'); - // Remove ROOM_EDITOR role - await this.getCollection('roles').deleteOne({ name: 'ROOM_EDITOR' }); - console.info('Rollback: Removed ROOM_EDITOR role'); + // Remove ROOMEDITOR role + await this.getCollection('roles').deleteOne({ name: 'room_editor' }); + console.info('Rollback: Removed ROOMEDITOR role'); } } diff --git a/apps/server/src/migrations/mikro-orm/Migration202411111604124.ts b/apps/server/src/migrations/mikro-orm/Migration202411111604124.ts index e642e195e69..e74aaa59473 100644 --- a/apps/server/src/migrations/mikro-orm/Migration202411111604124.ts +++ b/apps/server/src/migrations/mikro-orm/Migration202411111604124.ts @@ -2,26 +2,26 @@ import { Migration } from '@mikro-orm/migrations-mongodb'; export class Migration20241111160412 extends Migration { async up(): Promise { - // Rename ROOM_VIEWER role from room_viewer to roomviewer + // Rename ROOMVIEWER role from room_viewer to roomviewer await this.getCollection('roles').updateMany({ name: 'room_viewer' }, { $set: { name: 'roomviewer' } }); - console.info('Renamed ROOM_VIEWER role from room_viewer to roomviewer'); + console.info('Renamed ROOMVIEWER role from room_viewer to roomviewer'); - // Rename ROOM_EDITOR role from room_editor to roomeditor + // Rename ROOMEDITOR role from room_editor to roomeditor await this.getCollection('roles').updateMany({ name: 'room_editor' }, { $set: { name: 'roomeditor' } }); - console.info('Renamed ROOM_EDITOR role from room_editor to roomeditor'); + console.info('Renamed ROOMEDITOR role from room_editor to roomeditor'); } async down(): Promise { - // Rename ROOM_VIEWER role from roomviewer to room_viewer + // Rename ROOMVIEWER role from roomviewer to room_viewer await this.getCollection('roles').updateMany({ name: 'roomviewer' }, { $set: { name: 'room_viewer' } }); - console.info('Rollback: Renamed ROOM_VIEWER role from roomviewer to room_viewer'); + console.info('Rollback: Renamed ROOMVIEWER role from roomviewer to room_viewer'); - // Rename ROOM_EDITOR role from roomeditor to room_editor + // Rename ROOMEDITOR role from roomeditor to room_editor await this.getCollection('roles').updateMany({ name: 'roomeditor' }, { $set: { name: 'room_editor' } }); - console.info('Rollback: Renamed ROOM_EDITOR role from roomeditor to room_editor'); + console.info('Rollback: Renamed ROOMEDITOR role from roomeditor to room_editor'); } } diff --git a/apps/server/src/modules/board/controller/api-test/board-context-in-rooms.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-context-in-rooms.api.spec.ts index 1d701b7a157..1461f141013 100644 --- a/apps/server/src/modules/board/controller/api-test/board-context-in-rooms.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-context-in-rooms.api.spec.ts @@ -48,11 +48,11 @@ describe('board get context in room (api)', () => { const noAccessAccount = accountFactory.withUser(noAccessUser).build(); const roleRoomEdit = roleFactory.buildWithId({ - name: RoleName.ROOM_EDITOR, + name: RoleName.ROOMEDITOR, permissions: [Permission.ROOM_EDIT], }); const roleRoomView = roleFactory.buildWithId({ - name: RoleName.ROOM_VIEWER, + name: RoleName.ROOMVIEWER, permissions: [Permission.ROOM_VIEW], }); diff --git a/apps/server/src/modules/board/controller/api-test/board-create-in-room.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-create-in-room.api.spec.ts index 50d573674ef..3da8c8240da 100644 --- a/apps/server/src/modules/board/controller/api-test/board-create-in-room.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-create-in-room.api.spec.ts @@ -45,7 +45,7 @@ describe(`create board in room (api)`, () => { const user = userFactory.buildWithId(); const account = accountFactory.withUser(user).build(); - const role = roleFactory.buildWithId({ name: RoleName.ROOM_EDITOR, permissions: [Permission.ROOM_EDIT] }); + const role = roleFactory.buildWithId({ name: RoleName.ROOMEDITOR, permissions: [Permission.ROOM_EDIT] }); const userGroup = groupEntityFactory.buildWithId({ type: GroupEntityTypes.ROOM, @@ -161,7 +161,7 @@ describe(`create board in room (api)`, () => { const user = userFactory.buildWithId(); const account = accountFactory.withUser(user).build(); - const role = roleFactory.buildWithId({ name: RoleName.ROOM_EDITOR, permissions: [Permission.ROOM_VIEW] }); + const role = roleFactory.buildWithId({ name: RoleName.ROOMEDITOR, permissions: [Permission.ROOM_VIEW] }); const userGroup = groupEntityFactory.buildWithId({ type: GroupEntityTypes.ROOM, @@ -229,7 +229,7 @@ describe(`create board in room (api)`, () => { const user = userFactory.buildWithId(); const account = accountFactory.withUser(user).build(); - const role = roleFactory.buildWithId({ name: RoleName.ROOM_EDITOR, permissions: [Permission.ROOM_EDIT] }); + const role = roleFactory.buildWithId({ name: RoleName.ROOMEDITOR, permissions: [Permission.ROOM_EDIT] }); const userGroup = groupEntityFactory.buildWithId({ type: GroupEntityTypes.ROOM, diff --git a/apps/server/src/modules/board/controller/api-test/board-delete-in-room.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-delete-in-room.api.spec.ts index 59d819352c8..30f05f7953f 100644 --- a/apps/server/src/modules/board/controller/api-test/board-delete-in-room.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-delete-in-room.api.spec.ts @@ -48,8 +48,8 @@ describe(`board delete in room (api)`, () => { const noAccessUser = userFactory.buildWithId(); const noAccessAccount = accountFactory.withUser(noAccessUser).build(); - const roleRoomEdit = roleFactory.buildWithId({ name: RoleName.ROOM_EDITOR, permissions: [Permission.ROOM_EDIT] }); - const roleRoomView = roleFactory.buildWithId({ name: RoleName.ROOM_VIEWER, permissions: [Permission.ROOM_VIEW] }); + const roleRoomEdit = roleFactory.buildWithId({ name: RoleName.ROOMEDITOR, permissions: [Permission.ROOM_EDIT] }); + const roleRoomView = roleFactory.buildWithId({ name: RoleName.ROOMVIEWER, permissions: [Permission.ROOM_VIEW] }); const userGroup = groupEntityFactory.buildWithId({ type: GroupEntityTypes.ROOM, diff --git a/apps/server/src/modules/board/controller/api-test/board-lookup-in-room.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-lookup-in-room.api.spec.ts index c6701f81c94..952140cc19e 100644 --- a/apps/server/src/modules/board/controller/api-test/board-lookup-in-room.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-lookup-in-room.api.spec.ts @@ -49,8 +49,8 @@ describe(`board lookup in room (api)`, () => { const noAccessUser = userFactory.buildWithId(); const noAccessAccount = accountFactory.withUser(noAccessUser).build(); - const roleRoomEdit = roleFactory.buildWithId({ name: RoleName.ROOM_EDITOR, permissions: [Permission.ROOM_EDIT] }); - const roleRoomView = roleFactory.buildWithId({ name: RoleName.ROOM_VIEWER, permissions: [Permission.ROOM_VIEW] }); + const roleRoomEdit = roleFactory.buildWithId({ name: RoleName.ROOMEDITOR, permissions: [Permission.ROOM_EDIT] }); + const roleRoomView = roleFactory.buildWithId({ name: RoleName.ROOMVIEWER, permissions: [Permission.ROOM_VIEW] }); const userGroup = groupEntityFactory.buildWithId({ type: GroupEntityTypes.ROOM, diff --git a/apps/server/src/modules/board/controller/api-test/board-update-title-in-room.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-update-title-in-room.api.spec.ts index d5988437838..8cf0930de8a 100644 --- a/apps/server/src/modules/board/controller/api-test/board-update-title-in-room.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-update-title-in-room.api.spec.ts @@ -50,11 +50,11 @@ describe(`board update title with room relation (api)`, () => { const noAccessAccount = accountFactory.withUser(noAccessUser).build(); const roleRoomEdit = roleFactory.buildWithId({ - name: RoleName.ROOM_EDITOR, + name: RoleName.ROOMEDITOR, permissions: [Permission.ROOM_EDIT], }); const roleRoomView = roleFactory.buildWithId({ - name: RoleName.ROOM_VIEWER, + name: RoleName.ROOMVIEWER, permissions: [Permission.ROOM_VIEW], }); diff --git a/apps/server/src/modules/board/controller/api-test/board-visibility-in-room.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-visibility-in-room.api.spec.ts index c9a6aec631a..56a0e52e71e 100644 --- a/apps/server/src/modules/board/controller/api-test/board-visibility-in-room.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-visibility-in-room.api.spec.ts @@ -49,11 +49,11 @@ describe(`board update visibility with room relation (api)`, () => { const noAccessAccount = accountFactory.withUser(noAccessUser).build(); const roleRoomEdit = roleFactory.buildWithId({ - name: RoleName.ROOM_EDITOR, + name: RoleName.ROOMEDITOR, permissions: [Permission.ROOM_EDIT], }); const roleRoomView = roleFactory.buildWithId({ - name: RoleName.ROOM_VIEWER, + name: RoleName.ROOMVIEWER, permissions: [Permission.ROOM_VIEW], }); diff --git a/apps/server/src/modules/board/service/internal/board-context.service.spec.ts b/apps/server/src/modules/board/service/internal/board-context.service.spec.ts index c14ec70c1e1..b1a3be99840 100644 --- a/apps/server/src/modules/board/service/internal/board-context.service.spec.ts +++ b/apps/server/src/modules/board/service/internal/board-context.service.spec.ts @@ -218,7 +218,7 @@ describe(`${BoardContextService.name}`, () => { describe('when user with editor role is associated with the room', () => { const setup = () => { const user = userFactory.buildWithId(); - const role = roleFactory.build({ name: RoleName.ROOM_EDITOR, permissions: [Permission.ROOM_EDIT] }); + const role = roleFactory.build({ name: RoleName.ROOMEDITOR, permissions: [Permission.ROOM_EDIT] }); const group = groupFactory.build({ type: GroupTypes.ROOM, users: [{ userId: user.id, roleId: role.id }] }); const room = roomFactory.build(); roomMemberFactory.build({ roomId: room.id, userGroupId: group.id }); @@ -253,7 +253,7 @@ describe(`${BoardContextService.name}`, () => { describe('when user with view role is associated with the room', () => { const setup = () => { const user = userFactory.buildWithId(); - const role = roleFactory.build({ name: RoleName.ROOM_VIEWER, permissions: [Permission.ROOM_VIEW] }); + const role = roleFactory.build({ name: RoleName.ROOMVIEWER, permissions: [Permission.ROOM_VIEW] }); const group = groupFactory.build({ type: GroupTypes.ROOM, users: [{ userId: user.id, roleId: role.id }] }); const room = roomFactory.build(); roomMemberFactory.build({ roomId: room.id, userGroupId: group.id }); diff --git a/apps/server/src/modules/room-member/service/room-member.service.spec.ts b/apps/server/src/modules/room-member/service/room-member.service.spec.ts index 69ba478a901..148d4b8f0bb 100644 --- a/apps/server/src/modules/room-member/service/room-member.service.spec.ts +++ b/apps/server/src/modules/room-member/service/room-member.service.spec.ts @@ -74,7 +74,7 @@ describe('RoomMemberService', () => { it('should create new room member when not exists', async () => { const { user, room } = setup(); - await service.addMembersToRoom(room.id, [{ userId: user.id, roleName: RoleName.ROOM_EDITOR }]); + await service.addMembersToRoom(room.id, [{ userId: user.id, roleName: RoleName.ROOMEDITOR }]); expect(roomMemberRepo.save).toHaveBeenCalled(); }); @@ -110,10 +110,10 @@ describe('RoomMemberService', () => { it('should add user to existing room member', async () => { const { user, room, group } = setup(); - await service.addMembersToRoom(room.id, [{ userId: user.id, roleName: RoleName.ROOM_EDITOR }]); + await service.addMembersToRoom(room.id, [{ userId: user.id, roleName: RoleName.ROOMEDITOR }]); expect(groupService.addUsersToGroup).toHaveBeenCalledWith(group.id, [ - { userId: user.id, roleName: RoleName.ROOM_EDITOR }, + { userId: user.id, roleName: RoleName.ROOMEDITOR }, ]); }); }); diff --git a/apps/server/src/modules/room-member/service/room-member.service.ts b/apps/server/src/modules/room-member/service/room-member.service.ts index 4fdd5933e16..8ac26bdbe15 100644 --- a/apps/server/src/modules/room-member/service/room-member.service.ts +++ b/apps/server/src/modules/room-member/service/room-member.service.ts @@ -19,7 +19,7 @@ export class RoomMemberService { private async createNewRoomMember( roomId: EntityId, userId: EntityId, - roleName: RoleName.ROOM_EDITOR | RoleName.ROOM_VIEWER, + roleName: RoleName.ROOMEDITOR | RoleName.ROOMVIEWER, schoolId?: EntityId ) { const group = await this.groupService.createGroup(`Room Members for Room ${roomId}`, GroupTypes.ROOM, schoolId); @@ -64,7 +64,7 @@ export class RoomMemberService { public async addMembersToRoom( roomId: EntityId, - userIdsAndRoles: Array<{ userId: EntityId; roleName: RoleName.ROOM_EDITOR | RoleName.ROOM_VIEWER }>, + userIdsAndRoles: Array<{ userId: EntityId; roleName: RoleName.ROOMEDITOR | RoleName.ROOMVIEWER }>, schoolId?: EntityId ): Promise { const roomMember = await this.roomMembersRepo.findByRoomId(roomId); diff --git a/apps/server/src/modules/room/api/room.uc.ts b/apps/server/src/modules/room/api/room.uc.ts index 526d06fd6bd..0fe0cea00cf 100644 --- a/apps/server/src/modules/room/api/room.uc.ts +++ b/apps/server/src/modules/room/api/room.uc.ts @@ -41,7 +41,7 @@ export class RoomUc { this.authorizationService.checkOneOfPermissions(user, [Permission.ROOM_CREATE]); await this.roomMemberService - .addMembersToRoom(room.id, [{ userId: user.id, roleName: RoleName.ROOM_EDITOR }], user.school.id) + .addMembersToRoom(room.id, [{ userId: user.id, roleName: RoleName.ROOMEDITOR }], user.school.id) .catch(async (err) => { await this.roomService.deleteRoom(room); throw err; diff --git a/apps/server/src/modules/room/api/test/room-add-members.api.spec.ts b/apps/server/src/modules/room/api/test/room-add-members.api.spec.ts index 40f46dd24f1..7ba93b377e0 100644 --- a/apps/server/src/modules/room/api/test/room-add-members.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-add-members.api.spec.ts @@ -50,7 +50,7 @@ describe('Room Controller (API)', () => { const { teacherAccount: otherTeacherAccount, teacherUser: otherTeacherUser } = UserAndAccountTestFactory.buildTeacher({ school: teacherUser.school }); const role = roleFactory.buildWithId({ - name: RoleName.ROOM_EDITOR, + name: RoleName.ROOMEDITOR, permissions: [Permission.ROOM_VIEW, Permission.ROOM_EDIT], }); // TODO: add more than one user @@ -120,7 +120,7 @@ describe('Room Controller (API)', () => { const { loggedInClient, room, otherTeacherUser } = await setupRoomWithMembers(); const response = await loggedInClient.patch(`/${room.id}/members/add`, { - userIdsAndRoles: [{ userId: otherTeacherUser.id, roleName: RoleName.ROOM_EDITOR }], + userIdsAndRoles: [{ userId: otherTeacherUser.id, roleName: RoleName.ROOMEDITOR }], }); expect(response.status).toBe(HttpStatus.OK); diff --git a/apps/server/src/modules/room/api/test/room-create.api.spec.ts b/apps/server/src/modules/room/api/test/room-create.api.spec.ts index a2a44adc20a..48c93c5b4c6 100644 --- a/apps/server/src/modules/room/api/test/room-create.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-create.api.spec.ts @@ -69,7 +69,7 @@ describe('Room Controller (API)', () => { const setup = async () => { const { teacherAccount, teacherUser } = UserAndAccountTestFactory.buildTeacher(); const role = roleFactory.buildWithId({ - name: RoleName.ROOM_EDITOR, + name: RoleName.ROOMEDITOR, permissions: [Permission.ROOM_EDIT, Permission.ROOM_VIEW], }); await em.persistAndFlush([teacherAccount, teacherUser, role]); diff --git a/apps/server/src/modules/room/api/test/room-delete.api.spec.ts b/apps/server/src/modules/room/api/test/room-delete.api.spec.ts index b19d523f752..cd290922e6c 100644 --- a/apps/server/src/modules/room/api/test/room-delete.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-delete.api.spec.ts @@ -95,7 +95,7 @@ describe('Room Controller (API)', () => { const setup = async () => { const room = roomEntityFactory.build(); const role = roleFactory.buildWithId({ - name: RoleName.ROOM_EDITOR, + name: RoleName.ROOMEDITOR, permissions: [Permission.ROOM_EDIT], }); const { teacherAccount, teacherUser } = UserAndAccountTestFactory.buildTeacher(); diff --git a/apps/server/src/modules/room/api/test/room-get-boards.api.spec.ts b/apps/server/src/modules/room/api/test/room-get-boards.api.spec.ts index b727b66355a..ff14ce174e9 100644 --- a/apps/server/src/modules/room/api/test/room-get-boards.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-get-boards.api.spec.ts @@ -100,7 +100,7 @@ describe('Room Controller (API)', () => { }); const { studentAccount, studentUser } = UserAndAccountTestFactory.buildStudent(); const role = roleFactory.buildWithId({ - name: RoleName.ROOM_VIEWER, + name: RoleName.ROOMVIEWER, permissions: [Permission.ROOM_VIEW], }); const userGroupEntity = groupEntityFactory.buildWithId({ diff --git a/apps/server/src/modules/room/api/test/room-get.api.spec.ts b/apps/server/src/modules/room/api/test/room-get.api.spec.ts index 2dbc4fce6e8..54961eb25eb 100644 --- a/apps/server/src/modules/room/api/test/room-get.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-get.api.spec.ts @@ -95,7 +95,7 @@ describe('Room Controller (API)', () => { const room = roomEntityFactory.build(); const { studentAccount, studentUser } = UserAndAccountTestFactory.buildStudent(); const role = roleFactory.buildWithId({ - name: RoleName.ROOM_VIEWER, + name: RoleName.ROOMVIEWER, permissions: [Permission.ROOM_VIEW], }); const userGroupEntity = groupEntityFactory.buildWithId({ diff --git a/apps/server/src/modules/room/api/test/room-index.api.spec.ts b/apps/server/src/modules/room/api/test/room-index.api.spec.ts index e43d1ef113f..26b0cd141ad 100644 --- a/apps/server/src/modules/room/api/test/room-index.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-index.api.spec.ts @@ -131,7 +131,7 @@ describe('Room Controller (API)', () => { const rooms = roomEntityFactory.buildListWithId(2); const { studentAccount, studentUser } = UserAndAccountTestFactory.buildStudent(); const role = roleFactory.buildWithId({ - name: RoleName.ROOM_VIEWER, + name: RoleName.ROOMVIEWER, permissions: [Permission.ROOM_VIEW], }); const userGroupEntity = groupEntityFactory.buildWithId({ diff --git a/apps/server/src/modules/room/api/test/room-members.api.spec.ts b/apps/server/src/modules/room/api/test/room-members.api.spec.ts index 9e6663109b3..80334fbaa08 100644 --- a/apps/server/src/modules/room/api/test/room-members.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-members.api.spec.ts @@ -50,11 +50,11 @@ describe('Room Controller (API)', () => { const room = roomEntityFactory.buildWithId(); const { teacherAccount, teacherUser } = UserAndAccountTestFactory.buildTeacher(); const editRole = roleFactory.buildWithId({ - name: RoleName.ROOM_EDITOR, + name: RoleName.ROOMEDITOR, permissions: [Permission.ROOM_VIEW, Permission.ROOM_EDIT], }); const viewerRole = roleFactory.buildWithId({ - name: RoleName.ROOM_VIEWER, + name: RoleName.ROOMVIEWER, permissions: [Permission.ROOM_VIEW], }); const students = userFactory.buildList(2); diff --git a/apps/server/src/modules/room/api/test/room-remove-members.api.spec.ts b/apps/server/src/modules/room/api/test/room-remove-members.api.spec.ts index f470f25c3d5..6829f3f5cd9 100644 --- a/apps/server/src/modules/room/api/test/room-remove-members.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-remove-members.api.spec.ts @@ -46,11 +46,11 @@ describe('Room Controller (API)', () => { describe('PATCH /rooms/:roomId/members/remove', () => { const setupRoomRoles = () => { const editorRole = roleFactory.buildWithId({ - name: RoleName.ROOM_EDITOR, + name: RoleName.ROOMEDITOR, permissions: [Permission.ROOM_VIEW, Permission.ROOM_EDIT], }); const viewerRole = roleFactory.buildWithId({ - name: RoleName.ROOM_VIEWER, + name: RoleName.ROOMVIEWER, permissions: [Permission.ROOM_VIEW], }); return { editorRole, viewerRole }; diff --git a/apps/server/src/modules/room/api/test/room-update.api.spec.ts b/apps/server/src/modules/room/api/test/room-update.api.spec.ts index a756962f5af..08ed5847d21 100644 --- a/apps/server/src/modules/room/api/test/room-update.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-update.api.spec.ts @@ -99,7 +99,7 @@ describe('Room Controller (API)', () => { endDate: new Date('2024-10-20'), }); const role = roleFactory.buildWithId({ - name: RoleName.ROOM_EDITOR, + name: RoleName.ROOMEDITOR, permissions: [Permission.ROOM_EDIT], }); const { teacherAccount, teacherUser } = UserAndAccountTestFactory.buildTeacher(); diff --git a/apps/server/src/shared/domain/interface/rolename.enum.ts b/apps/server/src/shared/domain/interface/rolename.enum.ts index 1d06a0207ac..0278ce48d09 100644 --- a/apps/server/src/shared/domain/interface/rolename.enum.ts +++ b/apps/server/src/shared/domain/interface/rolename.enum.ts @@ -9,8 +9,8 @@ export enum RoleName { DEMOTEACHER = 'demoTeacher', EXPERT = 'expert', HELPDESK = 'helpdesk', - ROOM_VIEWER = 'roomviewer', - ROOM_EDITOR = 'roomeditor', + ROOMVIEWER = 'roomviewer', + ROOMEDITOR = 'roomeditor', STUDENT = 'student', SUPERHERO = 'superhero', TEACHER = 'teacher', @@ -30,5 +30,5 @@ export type IUserRoleName = | RoleName.DEMOSTUDENT | RoleName.DEMOTEACHER; -export const RoomRoleArray = [RoleName.ROOM_EDITOR, RoleName.ROOM_VIEWER] as const; +export const RoomRoleArray = [RoleName.ROOMEDITOR, RoleName.ROOMVIEWER] as const; export type RoomRole = typeof RoomRoleArray[number]; From c716fdd3a6be3500008b1756420693dc7f0246ec Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 19 Nov 2024 16:20:43 +0100 Subject: [PATCH 16/60] add missing module import --- apps/server/src/modules/board/board-ws-api.module.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/server/src/modules/board/board-ws-api.module.ts b/apps/server/src/modules/board/board-ws-api.module.ts index 4a0bfe63cd4..77f042f5816 100644 --- a/apps/server/src/modules/board/board-ws-api.module.ts +++ b/apps/server/src/modules/board/board-ws-api.module.ts @@ -9,9 +9,10 @@ import { BoardCollaborationGateway } from './gateway/board-collaboration.gateway import { MetricsService } from './metrics/metrics.service'; import { BoardNodePermissionService } from './service'; import { BoardUc, CardUc, ColumnUc, ElementUc } from './uc'; +import { RoomModule } from '../room'; @Module({ - imports: [BoardModule, forwardRef(() => AuthorizationModule), LoggerModule, UserModule, RoomMemberModule], + imports: [BoardModule, forwardRef(() => AuthorizationModule), LoggerModule, UserModule, RoomMemberModule, RoomModule], providers: [ BoardCollaborationGateway, BoardNodePermissionService, From b26f9e1c6b89cc116acd8f1db2c9d296e3e2b4b7 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Mon, 25 Nov 2024 14:34:46 +0100 Subject: [PATCH 17/60] adapt share token create and lookup auth --- .../src/modules/sharing/uc/share-token.uc.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/server/src/modules/sharing/uc/share-token.uc.ts b/apps/server/src/modules/sharing/uc/share-token.uc.ts index 60312fd0ec6..e856003e3be 100644 --- a/apps/server/src/modules/sharing/uc/share-token.uc.ts +++ b/apps/server/src/modules/sharing/uc/share-token.uc.ts @@ -86,7 +86,7 @@ export class ShareTokenUC { this.checkFeatureEnabled(shareToken.payload.parentType); - await this.checkLookupPermission(userId, shareToken.payload.parentType); + await this.checkTokenLookupPermission(userId, shareToken.payload.parentType); if (shareToken.context) { await this.checkContextReadPermission(userId, shareToken.context); @@ -229,7 +229,7 @@ export class ShareTokenUC { await this.checkTaskWritePermission(user, payload.parentId, Permission.HOMEWORK_CREATE); break; case ShareTokenParentType.ColumnBoard: - await this.checkColumnBoardWritePermission(user, payload.parentId, Permission.COURSE_EDIT); + await this.checkColumnBoardSharePermission(user, payload.parentId); break; default: } @@ -268,14 +268,15 @@ export class ShareTokenUC { this.authorizationService.checkPermission(user, task, AuthorizationContextBuilder.write([permission])); } - private async checkColumnBoardWritePermission(user: User, boardNodeId: EntityId, permission: Permission) { - const columBoard = await this.columnBoardService.findById(boardNodeId); + private async checkColumnBoardSharePermission(user: User, boardNodeId: EntityId) { + const columBoard = await this.columnBoardService.findById(boardNodeId, 0); const boardNodeAuthorizable = await this.boardNodeAuthorizableService.getBoardAuthorizable(columBoard); + const permissions = columBoard.context.type === BoardExternalReferenceType.Course ? [Permission.COURSE_EDIT] : []; this.authorizationService.checkPermission( user, boardNodeAuthorizable, - AuthorizationContextBuilder.write([permission]) + AuthorizationContextBuilder.write(permissions) ); } @@ -296,7 +297,7 @@ export class ShareTokenUC { } } - private async checkLookupPermission(userId: EntityId, parentType: ShareTokenParentType) { + private async checkTokenLookupPermission(userId: EntityId, parentType: ShareTokenParentType) { const user = await this.authorizationService.getUserWithPermissions(userId); let requiredPermissions: Permission[] = []; // eslint-disable-next-line default-case @@ -311,6 +312,7 @@ export class ShareTokenUC { requiredPermissions = [Permission.HOMEWORK_CREATE]; break; case ShareTokenParentType.ColumnBoard: + // TODO: check room permission requiredPermissions = [Permission.COURSE_EDIT]; break; } From eb7ba3ebcdc3c81688b768645fda293b1dbe7887 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Mon, 25 Nov 2024 14:34:57 +0100 Subject: [PATCH 18/60] fix unit test --- .../modules/sharing/uc/share-token.uc.spec.ts | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/apps/server/src/modules/sharing/uc/share-token.uc.spec.ts b/apps/server/src/modules/sharing/uc/share-token.uc.spec.ts index c8692d3ac40..44cc689b951 100644 --- a/apps/server/src/modules/sharing/uc/share-token.uc.spec.ts +++ b/apps/server/src/modules/sharing/uc/share-token.uc.spec.ts @@ -23,6 +23,10 @@ import { userFactory, } from '@shared/testing'; import { LegacyLogger } from '@src/core/logger'; +import { CopyColumnBoardParams } from '@src/modules/board/service/internal'; +import { StorageLocation } from '@src/modules/files-storage/interface'; +import { RoomService } from '@src/modules/room'; +import { RoomMemberService } from '@src/modules/room-member'; import { ShareTokenContextType, ShareTokenParentType, ShareTokenPayload } from '../domainobject/share-token.do'; import { ShareTokenService } from '../service'; import { ShareTokenUC } from './share-token.uc'; @@ -82,6 +86,14 @@ describe('ShareTokenUC', () => { provide: TaskService, useValue: createMock(), }, + { + provide: RoomService, + useValue: createMock(), + }, + { + provide: RoomMemberService, + useValue: createMock(), + }, { provide: ColumnBoardService, useValue: createMock(), @@ -1070,9 +1082,10 @@ describe('ShareTokenUC', () => { const school = schoolEntityFactory.buildWithId(); const user = userFactory.buildWithId({ school }); const course = courseFactory.buildWithId(); - courseService.findById.mockResolvedValueOnce(course); + courseService.findById.mockResolvedValue(course); const columnBoard = columnBoardFactory.build(); + columnBoardService.findById.mockResolvedValue(columnBoard); authorizationService.getUserWithPermissions.mockResolvedValueOnce(user); const payload: ShareTokenPayload = { parentType: ShareTokenParentType.ColumnBoard, parentId: columnBoard.id }; @@ -1116,9 +1129,11 @@ describe('ShareTokenUC', () => { const { user, shareToken, course, columnBoard } = setup(); const newName = 'NewName'; await uc.importShareToken(user.id, shareToken.token, newName, course.id); - expect(columnBoardService.copyColumnBoard).toHaveBeenCalledWith({ + expect(columnBoardService.copyColumnBoard).toHaveBeenCalledWith({ originalColumnBoardId: columnBoard.id, - destinationExternalReference: { type: BoardExternalReferenceType.Course, id: course.id }, + targetExternalReference: { type: BoardExternalReferenceType.Course, id: course.id }, + sourceStorageLocationReference: { type: StorageLocation.SCHOOL, id: course.school.id }, + targetStorageLocationReference: { type: StorageLocation.SCHOOL, id: course.school.id }, userId: user.id, copyTitle: newName, }); From f7080d20ad79e7d82be552169a591feac3031522 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Mon, 25 Nov 2024 15:00:19 +0100 Subject: [PATCH 19/60] fix tests --- .../controller/api-test/sharing-import-token.api.spec.ts | 3 ++- .../src/modules/sharing/entity/share-token.entity.spec.ts | 2 +- .../modules/sharing/repo/share-token.repo.integration.spec.ts | 3 ++- .../src/modules/sharing/service/share-token.service.spec.ts | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/server/src/modules/sharing/controller/api-test/sharing-import-token.api.spec.ts b/apps/server/src/modules/sharing/controller/api-test/sharing-import-token.api.spec.ts index 9386b965857..782c1b52ff8 100644 --- a/apps/server/src/modules/sharing/controller/api-test/sharing-import-token.api.spec.ts +++ b/apps/server/src/modules/sharing/controller/api-test/sharing-import-token.api.spec.ts @@ -1,7 +1,8 @@ import { Configuration } from '@hpi-schul-cloud/commons/lib'; import { ICurrentUser, JwtAuthGuard } from '@infra/auth-guard'; import { EntityManager } from '@mikro-orm/mongodb'; -import { CopyApiResponse, CopyElementType, CopyStatusEnum } from '@modules/copy-helper'; +import { CopyApiResponse } from '@modules/copy-helper/dto/copy.response'; +import { CopyElementType, CopyStatusEnum } from '@modules/copy-helper/types/copy.types'; import { ServerTestModule } from '@modules/server'; import { ExecutionContext, HttpStatus, INestApplication } from '@nestjs/common'; import { Test, TestingModule } from '@nestjs/testing'; diff --git a/apps/server/src/modules/sharing/entity/share-token.entity.spec.ts b/apps/server/src/modules/sharing/entity/share-token.entity.spec.ts index 6d822ba8c8e..1ef018ea0fd 100644 --- a/apps/server/src/modules/sharing/entity/share-token.entity.spec.ts +++ b/apps/server/src/modules/sharing/entity/share-token.entity.spec.ts @@ -1,4 +1,4 @@ -import { setupEntities } from '@shared/testing'; +import { setupEntities } from '@shared/testing/setup-entities'; import { ObjectId } from '@mikro-orm/mongodb'; import { ShareTokenContextType, ShareTokenParentType } from '../domainobject/share-token.do'; import { ShareToken } from './share-token.entity'; diff --git a/apps/server/src/modules/sharing/repo/share-token.repo.integration.spec.ts b/apps/server/src/modules/sharing/repo/share-token.repo.integration.spec.ts index dc0f03f1d49..fe550324f89 100644 --- a/apps/server/src/modules/sharing/repo/share-token.repo.integration.spec.ts +++ b/apps/server/src/modules/sharing/repo/share-token.repo.integration.spec.ts @@ -2,7 +2,8 @@ import { createMock } from '@golevelup/ts-jest'; import { MongoMemoryDatabaseModule } from '@infra/database'; import { EntityManager } from '@mikro-orm/mongodb'; import { Test, TestingModule } from '@nestjs/testing'; -import { cleanupCollections, schoolEntityFactory, shareTokenFactory } from '@shared/testing'; +import { cleanupCollections } from '@shared/testing/cleanup-collections'; +import { schoolEntityFactory, shareTokenFactory } from '@shared/testing/factory'; import { LegacyLogger } from '@src/core/logger'; import { ShareTokenContextType } from '../domainobject/share-token.do'; import { ShareTokenRepo } from './share-token.repo'; diff --git a/apps/server/src/modules/sharing/service/share-token.service.spec.ts b/apps/server/src/modules/sharing/service/share-token.service.spec.ts index 1f721e7a00b..1d7ae179284 100644 --- a/apps/server/src/modules/sharing/service/share-token.service.spec.ts +++ b/apps/server/src/modules/sharing/service/share-token.service.spec.ts @@ -1,7 +1,8 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { NotFoundException } from '@nestjs/common'; import { Test, TestingModule } from '@nestjs/testing'; -import { courseFactory, lessonFactory, setupEntities, shareTokenFactory, taskFactory } from '@shared/testing'; +import { setupEntities } from '@shared/testing/setup-entities'; +import { courseFactory, lessonFactory, shareTokenFactory, taskFactory } from '@shared/testing/factory'; import { columnBoardFactory } from '@modules/board/testing'; import { CourseService } from '@modules/learnroom/service'; import { ColumnBoardService } from '@modules/board/service'; From 0a0783a5cdfd6b682a1b8b099170833efd593174 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Mon, 25 Nov 2024 15:40:22 +0100 Subject: [PATCH 20/60] adapt token lookup permission --- .../src/modules/sharing/uc/share-token.uc.spec.ts | 2 ++ .../src/modules/sharing/uc/share-token.uc.ts | 14 ++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/apps/server/src/modules/sharing/uc/share-token.uc.spec.ts b/apps/server/src/modules/sharing/uc/share-token.uc.spec.ts index 44cc689b951..52fe2e0c9b9 100644 --- a/apps/server/src/modules/sharing/uc/share-token.uc.spec.ts +++ b/apps/server/src/modules/sharing/uc/share-token.uc.spec.ts @@ -685,6 +685,8 @@ describe('ShareTokenUC', () => { const shareToken = shareTokenFactory.build({ payload }); service.lookupTokenWithParentName.mockResolvedValueOnce({ shareToken, parentName: columnBoard.title }); + columnBoardService.findById.mockResolvedValueOnce(columnBoard); + return { user, shareToken, columnBoard, course }; }; diff --git a/apps/server/src/modules/sharing/uc/share-token.uc.ts b/apps/server/src/modules/sharing/uc/share-token.uc.ts index e856003e3be..fbc655190e8 100644 --- a/apps/server/src/modules/sharing/uc/share-token.uc.ts +++ b/apps/server/src/modules/sharing/uc/share-token.uc.ts @@ -86,7 +86,7 @@ export class ShareTokenUC { this.checkFeatureEnabled(shareToken.payload.parentType); - await this.checkTokenLookupPermission(userId, shareToken.payload.parentType); + await this.checkTokenLookupPermission(userId, shareToken.payload); if (shareToken.context) { await this.checkContextReadPermission(userId, shareToken.context); @@ -297,11 +297,11 @@ export class ShareTokenUC { } } - private async checkTokenLookupPermission(userId: EntityId, parentType: ShareTokenParentType) { + private async checkTokenLookupPermission(userId: EntityId, payload: ShareTokenPayload) { const user = await this.authorizationService.getUserWithPermissions(userId); let requiredPermissions: Permission[] = []; // eslint-disable-next-line default-case - switch (parentType) { + switch (payload.parentType) { case ShareTokenParentType.Course: requiredPermissions = [Permission.COURSE_CREATE]; break; @@ -311,10 +311,12 @@ export class ShareTokenUC { case ShareTokenParentType.Task: requiredPermissions = [Permission.HOMEWORK_CREATE]; break; - case ShareTokenParentType.ColumnBoard: - // TODO: check room permission - requiredPermissions = [Permission.COURSE_EDIT]; + case ShareTokenParentType.ColumnBoard: { + const columnBoard = await this.columnBoardService.findById(payload.parentId, 0); + requiredPermissions = + columnBoard.context.type === BoardExternalReferenceType.Course ? [Permission.COURSE_EDIT] : []; break; + } } this.authorizationService.checkAllPermissions(user, requiredPermissions); } From d8fb5244b612f6042765899a20acca66255c5d8e Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Mon, 25 Nov 2024 16:47:43 +0100 Subject: [PATCH 21/60] fix room tests --- apps/server/src/modules/room/api/room.uc.spec.ts | 3 ++- .../room/api/test/room-add-members.api.spec.ts | 12 +++++------- .../modules/room/api/test/room-create.api.spec.ts | 11 +++++++---- .../modules/room/api/test/room-delete.api.spec.ts | 12 +++++------- .../room/api/test/room-get-boards.api.spec.ts | 12 +++++------- .../src/modules/room/api/test/room-get.api.spec.ts | 14 ++++++-------- .../modules/room/api/test/room-index.api.spec.ts | 12 +++++------- .../modules/room/api/test/room-members.api.spec.ts | 14 ++++++-------- .../room/api/test/room-remove-members.api.spec.ts | 12 +++++------- .../modules/room/api/test/room-update.api.spec.ts | 14 ++++++-------- .../src/modules/room/domain/do/room.do.spec.ts | 5 ++++- .../room/domain/service/room.service.spec.ts | 2 ++ .../server/src/modules/room/repo/room.repo.spec.ts | 2 +- .../src/modules/room/testing/room.factory.ts | 2 +- 14 files changed, 60 insertions(+), 67 deletions(-) diff --git a/apps/server/src/modules/room/api/room.uc.spec.ts b/apps/server/src/modules/room/api/room.uc.spec.ts index ab0e958ae6c..0ee8c381d5e 100644 --- a/apps/server/src/modules/room/api/room.uc.spec.ts +++ b/apps/server/src/modules/room/api/room.uc.spec.ts @@ -7,7 +7,8 @@ import { Test, TestingModule } from '@nestjs/testing'; import { FeatureDisabledLoggableException } from '@shared/common/loggable-exception'; import { Page } from '@shared/domain/domainobject'; import { IFindOptions } from '@shared/domain/interface'; -import { setupEntities, userFactory } from '@shared/testing'; +import { setupEntities } from '@shared/testing/setup-entities'; +import { userFactory } from '@shared/testing/factory'; import { ColumnBoardService } from '@src/modules/board'; import { Room, RoomService } from '../domain'; import { RoomColor } from '../domain/type'; diff --git a/apps/server/src/modules/room/api/test/room-add-members.api.spec.ts b/apps/server/src/modules/room/api/test/room-add-members.api.spec.ts index 7ba93b377e0..9a414dddc5e 100644 --- a/apps/server/src/modules/room/api/test/room-add-members.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-add-members.api.spec.ts @@ -3,13 +3,11 @@ import { HttpStatus, INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { Permission } from '@shared/domain/interface/permission.enum'; import { RoleName } from '@shared/domain/interface/rolename.enum'; -import { - TestApiClient, - UserAndAccountTestFactory, - cleanupCollections, - groupEntityFactory, - roleFactory, -} from '@shared/testing'; +import { cleanupCollections } from '@shared/testing/cleanup-collections'; +import { groupEntityFactory } from '@shared/testing/factory/group-entity.factory'; +import { roleFactory } from '@shared/testing/factory/role.factory'; +import { UserAndAccountTestFactory } from '@shared/testing/factory/user-and-account.test.factory'; +import { TestApiClient } from '@shared/testing/test-api-client'; import { GroupEntityTypes } from '@src/modules/group/entity/group.entity'; import { roomMemberEntityFactory } from '@src/modules/room-member/testing/room-member-entity.factory'; import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; diff --git a/apps/server/src/modules/room/api/test/room-create.api.spec.ts b/apps/server/src/modules/room/api/test/room-create.api.spec.ts index 48c93c5b4c6..c9b315fca97 100644 --- a/apps/server/src/modules/room/api/test/room-create.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-create.api.spec.ts @@ -1,11 +1,14 @@ import { EntityManager } from '@mikro-orm/mongodb'; import { HttpStatus, INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; -import { TestApiClient, UserAndAccountTestFactory, cleanupCollections, roleFactory } from '@shared/testing'; -import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; -import { RoomMemberEntity } from '@src/modules/room-member'; -import { GroupEntity } from '@src/modules/group/entity'; import { Permission, RoleName } from '@shared/domain/interface'; +import { cleanupCollections } from '@shared/testing/cleanup-collections'; +import { roleFactory } from '@shared/testing/factory/role.factory'; +import { UserAndAccountTestFactory } from '@shared/testing/factory/user-and-account.test.factory'; +import { TestApiClient } from '@shared/testing/test-api-client'; +import { GroupEntity } from '@src/modules/group/entity'; +import { RoomMemberEntity } from '@src/modules/room-member'; +import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; import { RoomEntity } from '../../repo'; describe('Room Controller (API)', () => { diff --git a/apps/server/src/modules/room/api/test/room-delete.api.spec.ts b/apps/server/src/modules/room/api/test/room-delete.api.spec.ts index cd290922e6c..4afca6d37e2 100644 --- a/apps/server/src/modules/room/api/test/room-delete.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-delete.api.spec.ts @@ -2,13 +2,11 @@ import { EntityManager, ObjectId } from '@mikro-orm/mongodb'; import { HttpStatus, INestApplication, NotFoundException } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { Permission, RoleName } from '@shared/domain/interface'; -import { - TestApiClient, - UserAndAccountTestFactory, - cleanupCollections, - groupEntityFactory, - roleFactory, -} from '@shared/testing'; +import { cleanupCollections } from '@shared/testing/cleanup-collections'; +import { groupEntityFactory } from '@shared/testing/factory/group-entity.factory'; +import { roleFactory } from '@shared/testing/factory/role.factory'; +import { UserAndAccountTestFactory } from '@shared/testing/factory/user-and-account.test.factory'; +import { TestApiClient } from '@shared/testing/test-api-client'; import { GroupEntityTypes } from '@src/modules/group/entity/group.entity'; import { roomMemberEntityFactory } from '@src/modules/room-member/testing/room-member-entity.factory'; import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; diff --git a/apps/server/src/modules/room/api/test/room-get-boards.api.spec.ts b/apps/server/src/modules/room/api/test/room-get-boards.api.spec.ts index ff14ce174e9..0cd9750c467 100644 --- a/apps/server/src/modules/room/api/test/room-get-boards.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-get-boards.api.spec.ts @@ -2,13 +2,11 @@ import { EntityManager, ObjectId } from '@mikro-orm/mongodb'; import { HttpStatus, INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { Permission, RoleName } from '@shared/domain/interface'; -import { - cleanupCollections, - groupEntityFactory, - roleFactory, - TestApiClient, - UserAndAccountTestFactory, -} from '@shared/testing'; +import { cleanupCollections } from '@shared/testing/cleanup-collections'; +import { groupEntityFactory } from '@shared/testing/factory/group-entity.factory'; +import { roleFactory } from '@shared/testing/factory/role.factory'; +import { UserAndAccountTestFactory } from '@shared/testing/factory/user-and-account.test.factory'; +import { TestApiClient } from '@shared/testing/test-api-client'; import { BoardExternalReferenceType } from '@src/modules/board'; import { columnBoardEntityFactory } from '@src/modules/board/testing'; import { GroupEntityTypes } from '@src/modules/group/entity'; diff --git a/apps/server/src/modules/room/api/test/room-get.api.spec.ts b/apps/server/src/modules/room/api/test/room-get.api.spec.ts index 54961eb25eb..3b7da2cc71f 100644 --- a/apps/server/src/modules/room/api/test/room-get.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-get.api.spec.ts @@ -2,15 +2,13 @@ import { EntityManager, ObjectId } from '@mikro-orm/mongodb'; import { HttpStatus, INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { Permission, RoleName } from '@shared/domain/interface'; -import { - TestApiClient, - UserAndAccountTestFactory, - cleanupCollections, - groupEntityFactory, - roleFactory, -} from '@shared/testing'; +import { cleanupCollections } from '@shared/testing/cleanup-collections'; +import { groupEntityFactory } from '@shared/testing/factory/group-entity.factory'; +import { roleFactory } from '@shared/testing/factory/role.factory'; +import { UserAndAccountTestFactory } from '@shared/testing/factory/user-and-account.test.factory'; +import { TestApiClient } from '@shared/testing/test-api-client'; import { GroupEntityTypes } from '@src/modules/group/entity/group.entity'; -import { roomMemberEntityFactory } from '@src/modules/room-member/testing'; +import { roomMemberEntityFactory } from '@src/modules/room-member/testing/room-member-entity.factory'; import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; import { roomEntityFactory } from '../../testing/room-entity.factory'; diff --git a/apps/server/src/modules/room/api/test/room-index.api.spec.ts b/apps/server/src/modules/room/api/test/room-index.api.spec.ts index 26b0cd141ad..06b4a394d6c 100644 --- a/apps/server/src/modules/room/api/test/room-index.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-index.api.spec.ts @@ -3,13 +3,11 @@ import { HttpStatus, INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { Permission } from '@shared/domain/interface/permission.enum'; import { RoleName } from '@shared/domain/interface/rolename.enum'; -import { - TestApiClient, - UserAndAccountTestFactory, - cleanupCollections, - groupEntityFactory, - roleFactory, -} from '@shared/testing'; +import { cleanupCollections } from '@shared/testing/cleanup-collections'; +import { groupEntityFactory } from '@shared/testing/factory/group-entity.factory'; +import { roleFactory } from '@shared/testing/factory/role.factory'; +import { UserAndAccountTestFactory } from '@shared/testing/factory/user-and-account.test.factory'; +import { TestApiClient } from '@shared/testing/test-api-client'; import { GroupEntityTypes } from '@src/modules/group/entity/group.entity'; import { roomMemberEntityFactory } from '@src/modules/room-member/testing/room-member-entity.factory'; import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; diff --git a/apps/server/src/modules/room/api/test/room-members.api.spec.ts b/apps/server/src/modules/room/api/test/room-members.api.spec.ts index 80334fbaa08..7d2bd40fbfd 100644 --- a/apps/server/src/modules/room/api/test/room-members.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-members.api.spec.ts @@ -3,14 +3,12 @@ import { HttpStatus, INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { Permission } from '@shared/domain/interface/permission.enum'; import { RoleName } from '@shared/domain/interface/rolename.enum'; -import { - TestApiClient, - UserAndAccountTestFactory, - cleanupCollections, - groupEntityFactory, - roleFactory, - userFactory, -} from '@shared/testing'; +import { TestApiClient } from '@shared/testing/test-api-client'; +import { cleanupCollections } from '@shared/testing/cleanup-collections'; +import { UserAndAccountTestFactory } from '@shared/testing/factory/user-and-account.test.factory'; +import { groupEntityFactory } from '@shared/testing/factory/group-entity.factory'; +import { roleFactory } from '@shared/testing/factory/role.factory'; +import { userFactory } from '@shared/testing/factory/user.factory'; import { GroupEntityTypes } from '@src/modules/group/entity/group.entity'; import { roomMemberEntityFactory } from '@src/modules/room-member/testing/room-member-entity.factory'; import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; diff --git a/apps/server/src/modules/room/api/test/room-remove-members.api.spec.ts b/apps/server/src/modules/room/api/test/room-remove-members.api.spec.ts index 6829f3f5cd9..977ab77638e 100644 --- a/apps/server/src/modules/room/api/test/room-remove-members.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-remove-members.api.spec.ts @@ -3,13 +3,11 @@ import { HttpStatus, INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { Permission } from '@shared/domain/interface/permission.enum'; import { RoleName } from '@shared/domain/interface/rolename.enum'; -import { - TestApiClient, - UserAndAccountTestFactory, - cleanupCollections, - groupEntityFactory, - roleFactory, -} from '@shared/testing'; +import { cleanupCollections } from '@shared/testing/cleanup-collections'; +import { groupEntityFactory } from '@shared/testing/factory/group-entity.factory'; +import { roleFactory } from '@shared/testing/factory/role.factory'; +import { UserAndAccountTestFactory } from '@shared/testing/factory/user-and-account.test.factory'; +import { TestApiClient } from '@shared/testing/test-api-client'; import { GroupEntityTypes } from '@src/modules/group/entity/group.entity'; import { roomMemberEntityFactory } from '@src/modules/room-member/testing/room-member-entity.factory'; import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; diff --git a/apps/server/src/modules/room/api/test/room-update.api.spec.ts b/apps/server/src/modules/room/api/test/room-update.api.spec.ts index 08ed5847d21..164765a8b3f 100644 --- a/apps/server/src/modules/room/api/test/room-update.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-update.api.spec.ts @@ -2,14 +2,12 @@ import { EntityManager, ObjectId } from '@mikro-orm/mongodb'; import { HttpStatus, INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { Permission, RoleName } from '@shared/domain/interface'; -import { - TestApiClient, - UserAndAccountTestFactory, - cleanupCollections, - groupEntityFactory, - roleFactory, -} from '@shared/testing'; -import { roomMemberEntityFactory } from '@src/modules/room-member/testing'; +import { TestApiClient } from '@shared/testing/test-api-client'; +import { cleanupCollections } from '@shared/testing/cleanup-collections'; +import { UserAndAccountTestFactory } from '@shared/testing/factory/user-and-account.test.factory'; +import { groupEntityFactory } from '@shared/testing/factory/group-entity.factory'; +import { roleFactory } from '@shared/testing/factory/role.factory'; +import { roomMemberEntityFactory } from '@src/modules/room-member/testing/room-member-entity.factory'; import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; import { RoomEntity } from '../../repo'; import { roomEntityFactory } from '../../testing'; diff --git a/apps/server/src/modules/room/domain/do/room.do.spec.ts b/apps/server/src/modules/room/domain/do/room.do.spec.ts index bd213e52259..8ff3d847d42 100644 --- a/apps/server/src/modules/room/domain/do/room.do.spec.ts +++ b/apps/server/src/modules/room/domain/do/room.do.spec.ts @@ -1,6 +1,7 @@ +import { ObjectId } from '@mikro-orm/mongodb'; import { ValidationError } from '@shared/common'; import { EntityId } from '@shared/domain/types'; -import { roomFactory } from '../../testing'; +import { roomFactory } from '../../testing/room.factory'; import { RoomColor } from '../type'; import { Room, RoomProps } from './room.do'; @@ -13,6 +14,7 @@ describe('Room', () => { color: RoomColor.BLUE, startDate: new Date('2024-01-01'), endDate: new Date('2024-12-31'), + schoolId: new ObjectId().toHexString(), createdAt: new Date('2024-01-01'), updatedAt: new Date('2024-01-01'), }; @@ -80,6 +82,7 @@ describe('Room', () => { color: RoomColor.BLUE, startDate: new Date('2024-01-01'), endDate: new Date('2024-12-31'), + schoolId: new ObjectId().toHexString(), createdAt: new Date('2024-01-01'), updatedAt: new Date('2024-01-01'), }; diff --git a/apps/server/src/modules/room/domain/service/room.service.spec.ts b/apps/server/src/modules/room/domain/service/room.service.spec.ts index 5edb5710a03..4b7c7083c54 100644 --- a/apps/server/src/modules/room/domain/service/room.service.spec.ts +++ b/apps/server/src/modules/room/domain/service/room.service.spec.ts @@ -1,4 +1,5 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; +import { ObjectId } from '@mikro-orm/mongodb'; import { Test, TestingModule } from '@nestjs/testing'; import { Page } from '@shared/domain/domainobject'; import { EntityId } from '@shared/domain/types'; @@ -69,6 +70,7 @@ describe('RoomService', () => { const props: RoomCreateProps = { name: 'room #1', color: RoomColor.ORANGE, + schoolId: new ObjectId().toHexString(), }; return { props }; }; diff --git a/apps/server/src/modules/room/repo/room.repo.spec.ts b/apps/server/src/modules/room/repo/room.repo.spec.ts index d89fd630b4e..69f461d872e 100644 --- a/apps/server/src/modules/room/repo/room.repo.spec.ts +++ b/apps/server/src/modules/room/repo/room.repo.spec.ts @@ -3,7 +3,7 @@ import { NotFoundError } from '@mikro-orm/core'; import { EntityManager } from '@mikro-orm/mongodb'; import { Test, TestingModule } from '@nestjs/testing'; import { Page } from '@shared/domain/domainobject'; -import { cleanupCollections } from '@shared/testing'; +import { cleanupCollections } from '@shared/testing/cleanup-collections'; import { Room } from '../domain/do/room.do'; import { roomEntityFactory, roomFactory } from '../testing'; import { RoomEntity } from './entity'; diff --git a/apps/server/src/modules/room/testing/room.factory.ts b/apps/server/src/modules/room/testing/room.factory.ts index 7f1ef879488..d1821d62de5 100644 --- a/apps/server/src/modules/room/testing/room.factory.ts +++ b/apps/server/src/modules/room/testing/room.factory.ts @@ -1,4 +1,4 @@ -import { BaseFactory } from '@shared/testing'; +import { BaseFactory } from '@shared/testing/factory/base.factory'; import { ObjectId } from '@mikro-orm/mongodb'; import { Room, RoomProps } from '../domain/do/room.do'; import { RoomColor } from '../domain/type'; From 7f6221e2c36e6ac17caf1a32194375f8620ddcb9 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Mon, 25 Nov 2024 18:07:30 +0100 Subject: [PATCH 22/60] fix board tests --- .../board/repo/board-node.repo.spec.ts | 6 ++-- .../board-node-authorizable.service.spec.ts | 5 +-- .../board-node-copy-specific.service.spec.ts | 15 ++++---- .../internal/board-node-copy.service.ts | 3 +- .../src/modules/board/testing/card.factory.ts | 2 +- .../board/testing/column-board.factory.ts | 2 +- .../modules/board/testing/column.factory.ts | 2 +- .../testing/external-tool-element.factory.ts | 2 +- .../src/modules/board/uc/board.uc.spec.ts | 34 +++++++++++++------ apps/server/src/modules/board/uc/board.uc.ts | 1 + .../src/modules/board/uc/column.uc.spec.ts | 7 ++-- 11 files changed, 49 insertions(+), 30 deletions(-) diff --git a/apps/server/src/modules/board/repo/board-node.repo.spec.ts b/apps/server/src/modules/board/repo/board-node.repo.spec.ts index 3a6cf173d23..067523b8b6f 100644 --- a/apps/server/src/modules/board/repo/board-node.repo.spec.ts +++ b/apps/server/src/modules/board/repo/board-node.repo.spec.ts @@ -1,10 +1,12 @@ import { EntityManager } from '@mikro-orm/mongodb'; import { Test, TestingModule } from '@nestjs/testing'; import { BaseEntityWithTimestamps } from '@shared/domain/entity'; -import { cleanupCollections } from '@shared/testing'; +import { cleanupCollections } from '@shared/testing/cleanup-collections'; import { MongoMemoryDatabaseModule } from '@src/infra/database'; import { ColumnBoard } from '../domain'; -import { cardFactory, columnBoardFactory, columnFactory } from '../testing'; +import { cardFactory } from '../testing/card.factory'; +import { columnBoardFactory } from '../testing/column-board.factory'; +import { columnFactory } from '../testing/column.factory'; import { BoardNodeRepo } from './board-node.repo'; import { BoardNodeEntity } from './entity/board-node.entity'; diff --git a/apps/server/src/modules/board/service/board-node-authorizable.service.spec.ts b/apps/server/src/modules/board/service/board-node-authorizable.service.spec.ts index 10d768d1c73..190dda401ee 100644 --- a/apps/server/src/modules/board/service/board-node-authorizable.service.spec.ts +++ b/apps/server/src/modules/board/service/board-node-authorizable.service.spec.ts @@ -1,8 +1,9 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Test, TestingModule } from '@nestjs/testing'; -import { setupEntities } from '@shared/testing'; +import { setupEntities } from '@shared/testing/setup-entities'; import { AuthorizableReferenceType, AuthorizationInjectionService } from '@modules/authorization'; -import { columnBoardFactory, columnFactory } from '../testing'; +import { columnBoardFactory } from '../testing/column-board.factory'; +import { columnFactory } from '../testing/column.factory'; import { BoardNodeAuthorizable, BoardRoles, UserWithBoardRoles } from '../domain'; import { BoardNodeRepo } from '../repo'; import { BoardContextService } from './internal/board-context.service'; diff --git a/apps/server/src/modules/board/service/internal/board-node-copy-specific.service.spec.ts b/apps/server/src/modules/board/service/internal/board-node-copy-specific.service.spec.ts index 1a82f545a59..7926eb15cdb 100644 --- a/apps/server/src/modules/board/service/internal/board-node-copy-specific.service.spec.ts +++ b/apps/server/src/modules/board/service/internal/board-node-copy-specific.service.spec.ts @@ -1,12 +1,13 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { ObjectId } from '@mikro-orm/mongodb'; -import { CopyElementType, CopyHelperService, CopyStatus, CopyStatusEnum } from '@modules/copy-helper'; +import { CopyHelperService } from '@modules/copy-helper/service/copy-helper.service'; +import { CopyElementType, CopyStatus, CopyStatusEnum } from '@modules/copy-helper/types/copy.types'; import { StorageLocation } from '@modules/files-storage/interface'; import { ContextExternalToolService } from '@modules/tool/context-external-tool/service'; import { ToolConfig } from '@modules/tool/tool-config'; import { ConfigService } from '@nestjs/config'; import { Test, TestingModule } from '@nestjs/testing'; -import { setupEntities } from '@shared/testing'; +import { setupEntities } from '@shared/testing/setup-entities'; import { FilesStorageClientAdapterService } from '@src/modules/files-storage-client'; import { CopyFileDto } from '@src/modules/files-storage-client/dto'; import { contextExternalToolFactory } from '@src/modules/tool/context-external-tool/testing'; @@ -40,7 +41,7 @@ import { submissionContainerElementFactory, submissionItemFactory, } from '../../testing'; -import { BoardNodeCopyContext } from './board-node-copy-context'; +import { BoardNodeCopyContext, BoardNodeCopyContextProps } from './board-node-copy-context'; import { BoardNodeCopyService } from './board-node-copy.service'; describe(BoardNodeCopyService.name, () => { @@ -97,11 +98,9 @@ describe(BoardNodeCopyService.name, () => { }); const setupContext = () => { - const contextProps = { - sourceStorageLocationId: new ObjectId().toHexString(), - sourceStorageLocation: StorageLocation.SCHOOL, - targetStorageLocationId: new ObjectId().toHexString(), - targetStorageLocation: StorageLocation.SCHOOL, + const contextProps: BoardNodeCopyContextProps = { + sourceStorageLocationReference: { id: new ObjectId().toHexString(), type: StorageLocation.SCHOOL }, + targetStorageLocationReference: { id: new ObjectId().toHexString(), type: StorageLocation.SCHOOL }, userId: new ObjectId().toHexString(), filesStorageClientAdapterService: createMock(), }; diff --git a/apps/server/src/modules/board/service/internal/board-node-copy.service.ts b/apps/server/src/modules/board/service/internal/board-node-copy.service.ts index 3870411bac9..3309d31b760 100644 --- a/apps/server/src/modules/board/service/internal/board-node-copy.service.ts +++ b/apps/server/src/modules/board/service/internal/board-node-copy.service.ts @@ -1,5 +1,6 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { CopyElementType, CopyHelperService, CopyStatus, CopyStatusEnum } from '@modules/copy-helper'; +import { CopyHelperService } from '@modules/copy-helper/service/copy-helper.service'; +import { CopyElementType, CopyStatus, CopyStatusEnum } from '@modules/copy-helper/types/copy.types'; import { CopyFileDto } from '@modules/files-storage-client/dto'; import { ContextExternalToolService } from '@modules/tool/context-external-tool'; import { ContextExternalTool } from '@modules/tool/context-external-tool/domain'; diff --git a/apps/server/src/modules/board/testing/card.factory.ts b/apps/server/src/modules/board/testing/card.factory.ts index 71999aef7e8..5a7497fb66f 100644 --- a/apps/server/src/modules/board/testing/card.factory.ts +++ b/apps/server/src/modules/board/testing/card.factory.ts @@ -1,6 +1,6 @@ /* istanbul ignore file */ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing'; +import { BaseFactory } from '@shared/testing/factory/base.factory'; import { Card, CardProps, ROOT_PATH } from '../domain'; export const cardFactory = BaseFactory.define(Card, ({ sequence }) => { diff --git a/apps/server/src/modules/board/testing/column-board.factory.ts b/apps/server/src/modules/board/testing/column-board.factory.ts index 48c925dcaf6..dff17ffde1c 100644 --- a/apps/server/src/modules/board/testing/column-board.factory.ts +++ b/apps/server/src/modules/board/testing/column-board.factory.ts @@ -1,6 +1,6 @@ /* istanbul ignore file */ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing'; +import { BaseFactory } from '@shared/testing/factory/base.factory'; import { BoardExternalReferenceType, BoardLayout, ColumnBoard, ColumnBoardProps, ROOT_PATH } from '../domain'; class ColumnBoardFactory extends BaseFactory { diff --git a/apps/server/src/modules/board/testing/column.factory.ts b/apps/server/src/modules/board/testing/column.factory.ts index 9de33a2765a..802a025fe7c 100644 --- a/apps/server/src/modules/board/testing/column.factory.ts +++ b/apps/server/src/modules/board/testing/column.factory.ts @@ -1,6 +1,6 @@ /* istanbul ignore file */ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing'; +import { BaseFactory } from '@shared/testing/factory/base.factory'; import { Column, ColumnProps, ROOT_PATH } from '../domain'; export const columnFactory = BaseFactory.define(Column, ({ sequence }) => { diff --git a/apps/server/src/modules/board/testing/external-tool-element.factory.ts b/apps/server/src/modules/board/testing/external-tool-element.factory.ts index 06e6ec4f5ea..aabef73fe8e 100644 --- a/apps/server/src/modules/board/testing/external-tool-element.factory.ts +++ b/apps/server/src/modules/board/testing/external-tool-element.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing'; +import { BaseFactory } from '@shared/testing/factory/base.factory'; import { ExternalToolElement, ExternalToolElementProps, ROOT_PATH } from '../domain'; export const externalToolElementFactory = BaseFactory.define( diff --git a/apps/server/src/modules/board/uc/board.uc.spec.ts b/apps/server/src/modules/board/uc/board.uc.spec.ts index 84e64021289..114f7c7523c 100644 --- a/apps/server/src/modules/board/uc/board.uc.spec.ts +++ b/apps/server/src/modules/board/uc/board.uc.spec.ts @@ -4,9 +4,11 @@ import { Action, AuthorizationService } from '@modules/authorization'; import { Test, TestingModule } from '@nestjs/testing'; import { Permission } from '@shared/domain/interface'; import { CourseRepo } from '@shared/repo'; -import { setupEntities, userFactory } from '@shared/testing'; -import { courseFactory } from '@shared/testing/factory'; +import { courseFactory } from '@shared/testing/factory/course.factory'; +import { userFactory } from '@shared/testing/factory/user.factory'; +import { setupEntities } from '@shared/testing/setup-entities'; import { LegacyLogger } from '@src/core/logger'; +import { RoomService } from '@src/modules/room'; import { RoomMemberService } from '@src/modules/room-member'; import { CopyElementType, CopyStatus, CopyStatusEnum } from '../../copy-helper'; import { BoardExternalReferenceType, BoardLayout, BoardNodeFactory, Column, ColumnBoard } from '../domain'; @@ -48,6 +50,10 @@ describe(BoardUc.name, () => { provide: CourseRepo, useValue: createMock(), }, + { + provide: RoomService, + useValue: createMock(), + }, { provide: BoardNodeFactory, useValue: createMock(), @@ -427,8 +433,15 @@ describe(BoardUc.name, () => { }); describe('copyBoard', () => { + const setup = () => { + const { user, board, boardId } = globalSetup(); + boardNodeService.findByClassAndId.mockResolvedValueOnce(board); + + return { user, board, boardId }; + }; + it('should call the service to find the user', async () => { - const { user, boardId } = globalSetup(); + const { user, boardId } = setup(); await uc.copyBoard(user.id, boardId); @@ -436,7 +449,7 @@ describe(BoardUc.name, () => { }); it('should call the service to find the board', async () => { - const { user, boardId } = globalSetup(); + const { user, boardId } = setup(); await uc.copyBoard(user.id, boardId); @@ -444,7 +457,7 @@ describe(BoardUc.name, () => { }); it('[deprecated] should call course repo to find the course', async () => { - const { user, boardId } = globalSetup(); + const { user, boardId } = setup(); await uc.copyBoard(user.id, boardId); @@ -452,8 +465,7 @@ describe(BoardUc.name, () => { }); it('should call Board Permission Service to check permission', async () => { - const { user, board } = globalSetup(); - boardNodeService.findByClassAndId.mockResolvedValueOnce(board); + const { user, board } = setup(); await uc.copyBoard(user.id, board.id); @@ -461,7 +473,7 @@ describe(BoardUc.name, () => { }); it('should call authorization to check course permissions', async () => { - const { user, boardId } = globalSetup(); + const { user, boardId } = setup(); const course = courseFactory.build(); // TODO should not use course repo @@ -471,12 +483,12 @@ describe(BoardUc.name, () => { expect(authorizationService.checkPermission).toHaveBeenCalledWith(user, course, { action: Action.write, - requiredPermissions: [], + requiredPermissions: ['COURSE_EDIT'], }); }); it('should call the service to copy the board', async () => { - const { user, boardId } = globalSetup(); + const { user, boardId } = setup(); await uc.copyBoard(user.id, boardId); @@ -486,7 +498,7 @@ describe(BoardUc.name, () => { }); it('should return the copy status', async () => { - const { user, boardId } = globalSetup(); + const { user, boardId } = setup(); const copyStatus: CopyStatus = { type: CopyElementType.BOARD, diff --git a/apps/server/src/modules/board/uc/board.uc.ts b/apps/server/src/modules/board/uc/board.uc.ts index e2fb11b937b..7ab86383917 100644 --- a/apps/server/src/modules/board/uc/board.uc.ts +++ b/apps/server/src/modules/board/uc/board.uc.ts @@ -121,6 +121,7 @@ export class BoardUc { const board = await this.boardNodeService.findByClassAndId(ColumnBoard, boardId); + await this.boardPermissionService.checkPermission(userId, board, Action.read); await this.checkReferenceWritePermission(userId, board.context); const storageLocationReference = await this.getStorageLocationReference(board.context); diff --git a/apps/server/src/modules/board/uc/column.uc.spec.ts b/apps/server/src/modules/board/uc/column.uc.spec.ts index 3c80734550e..5c1a6c1d39e 100644 --- a/apps/server/src/modules/board/uc/column.uc.spec.ts +++ b/apps/server/src/modules/board/uc/column.uc.spec.ts @@ -1,12 +1,15 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Action } from '@modules/authorization'; import { Test, TestingModule } from '@nestjs/testing'; -import { setupEntities, userFactory } from '@shared/testing'; +import { setupEntities } from '@shared/testing/setup-entities'; +import { userFactory } from '@shared/testing/factory/user.factory'; import { LegacyLogger } from '@src/core/logger'; import { BoardNodeFactory, Card, Column, ContentElementType } from '../domain'; import { BoardNodeService } from '../service'; import { BoardNodePermissionService } from '../service/board-node-permission.service'; -import { cardFactory, columnBoardFactory, columnFactory } from '../testing'; +import { cardFactory } from '../testing/card.factory'; +import { columnBoardFactory } from '../testing/column-board.factory'; +import { columnFactory } from '../testing/column.factory'; import { ColumnUc } from './column.uc'; describe(ColumnUc.name, () => { From 76c3843e2d16d984c5466e696295d02eb2aaaf25 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Mon, 25 Nov 2024 18:34:27 +0100 Subject: [PATCH 23/60] fix board tests --- .../board/service/board-node.service.spec.ts | 14 ++++++-------- .../board/testing/deleted-element.factory.ts | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/apps/server/src/modules/board/service/board-node.service.spec.ts b/apps/server/src/modules/board/service/board-node.service.spec.ts index 77449a10034..784246702eb 100644 --- a/apps/server/src/modules/board/service/board-node.service.spec.ts +++ b/apps/server/src/modules/board/service/board-node.service.spec.ts @@ -2,16 +2,14 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { ObjectId } from '@mikro-orm/mongodb'; import { NotFoundException } from '@nestjs/common'; import { Test, TestingModule } from '@nestjs/testing'; -import { setupEntities } from '@shared/testing'; +import { setupEntities } from '@shared/testing/setup-entities'; import { Card, ColumnBoard } from '../domain'; import { BoardNodeRepo } from '../repo'; -import { - cardFactory, - columnBoardFactory, - deletedElementFactory, - externalToolElementFactory, - richTextElementFactory, -} from '../testing'; +import { cardFactory } from '../testing/card.factory'; +import { columnBoardFactory } from '../testing/column-board.factory'; +import { deletedElementFactory } from '../testing/deleted-element.factory'; +import { externalToolElementFactory } from '../testing/external-tool-element.factory'; +import { richTextElementFactory } from '../testing/rich-text-element.factory'; import { BoardNodeService } from './board-node.service'; import { BoardNodeDeleteHooksService, ContentElementUpdateService } from './internal'; diff --git a/apps/server/src/modules/board/testing/deleted-element.factory.ts b/apps/server/src/modules/board/testing/deleted-element.factory.ts index 23a682bd3c8..4e66a375e2b 100644 --- a/apps/server/src/modules/board/testing/deleted-element.factory.ts +++ b/apps/server/src/modules/board/testing/deleted-element.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing'; +import { BaseFactory } from '@shared/testing/factory/base.factory'; import { ContentElementType, DeletedElement, DeletedElementProps, ROOT_PATH } from '../domain'; export const deletedElementFactory = BaseFactory.define( From bd256874e9f855d668650625a12bf54b5750fa69 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Mon, 25 Nov 2024 18:39:07 +0100 Subject: [PATCH 24/60] fix board tests --- apps/server/src/modules/board/metrics/metrics.service.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/server/src/modules/board/metrics/metrics.service.spec.ts b/apps/server/src/modules/board/metrics/metrics.service.spec.ts index 9da48af0baa..7724b0a5d7f 100644 --- a/apps/server/src/modules/board/metrics/metrics.service.spec.ts +++ b/apps/server/src/modules/board/metrics/metrics.service.spec.ts @@ -2,7 +2,8 @@ import { DeepMocked, createMock } from '@golevelup/ts-jest'; import { Test, TestingModule } from '@nestjs/testing'; import { UserService } from '@src/modules/user'; import { RoleName } from '@shared/domain/interface'; -import { roleFactory, userDoFactory } from '@shared/testing'; +import { roleFactory } from '@shared/testing/factory/role.factory'; +import { userDoFactory } from '@shared/testing/factory/user.do.factory'; import { MetricsService } from './metrics.service'; describe(MetricsService.name, () => { From 0dbe7cccef86fa1bc7a3897323095584ee2306af Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Mon, 25 Nov 2024 18:48:56 +0100 Subject: [PATCH 25/60] fix board tests --- .../board-node-delete-hooks.service.spec.ts | 24 +++++++++---------- .../collaborative-text-editor.factory.ts | 2 +- .../board/testing/drawing-element.factory.ts | 2 +- .../board/testing/file-element.factory.ts | 2 +- .../board/testing/link-element.factory.ts | 2 +- 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/apps/server/src/modules/board/service/internal/board-node-delete-hooks.service.spec.ts b/apps/server/src/modules/board/service/internal/board-node-delete-hooks.service.spec.ts index 7134dad1ad0..10fb8ca11c7 100644 --- a/apps/server/src/modules/board/service/internal/board-node-delete-hooks.service.spec.ts +++ b/apps/server/src/modules/board/service/internal/board-node-delete-hooks.service.spec.ts @@ -1,18 +1,16 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Test, TestingModule } from '@nestjs/testing'; -import { setupEntities } from '@shared/testing'; -import { CollaborativeTextEditorService } from '@src/modules/collaborative-text-editor'; -import { FilesStorageClientAdapterService } from '@src/modules/files-storage-client'; -import { DrawingElementAdapterService } from '@src/modules/tldraw-client'; -import { ContextExternalToolService } from '@src/modules/tool/context-external-tool'; -import { contextExternalToolFactory } from '@src/modules/tool/context-external-tool/testing'; -import { - collaborativeTextEditorFactory, - drawingElementFactory, - externalToolElementFactory, - fileElementFactory, - linkElementFactory, -} from '../../testing'; +import { setupEntities } from '@shared/testing/setup-entities'; +import { CollaborativeTextEditorService } from '@src/modules/collaborative-text-editor/service/collaborative-text-editor.service'; +import { FilesStorageClientAdapterService } from '@src/modules/files-storage-client/service/files-storage-client.service'; +import { DrawingElementAdapterService } from '@src/modules/tldraw-client/service/drawing-element-adapter.service'; +import { ContextExternalToolService } from '@src/modules/tool/context-external-tool/service/context-external-tool.service'; +import { contextExternalToolFactory } from '@src/modules/tool/context-external-tool/testing/context-external-tool.factory'; +import { collaborativeTextEditorFactory } from '../../testing/collaborative-text-editor.factory'; +import { drawingElementFactory } from '../../testing/drawing-element.factory'; +import { externalToolElementFactory } from '../../testing/external-tool-element.factory'; +import { fileElementFactory } from '../../testing/file-element.factory'; +import { linkElementFactory } from '../../testing/link-element.factory'; import { BoardNodeDeleteHooksService } from './board-node-delete-hooks.service'; describe(BoardNodeDeleteHooksService.name, () => { diff --git a/apps/server/src/modules/board/testing/collaborative-text-editor.factory.ts b/apps/server/src/modules/board/testing/collaborative-text-editor.factory.ts index 1bc197060a3..d9a7c473fcf 100644 --- a/apps/server/src/modules/board/testing/collaborative-text-editor.factory.ts +++ b/apps/server/src/modules/board/testing/collaborative-text-editor.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing'; +import { BaseFactory } from '@shared/testing/factory/base.factory'; import { CollaborativeTextEditorElement, CollaborativeTextEditorElementProps, ROOT_PATH } from '../domain'; export const collaborativeTextEditorFactory = BaseFactory.define< diff --git a/apps/server/src/modules/board/testing/drawing-element.factory.ts b/apps/server/src/modules/board/testing/drawing-element.factory.ts index 678a23384bc..21a8b1875c7 100644 --- a/apps/server/src/modules/board/testing/drawing-element.factory.ts +++ b/apps/server/src/modules/board/testing/drawing-element.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing'; +import { BaseFactory } from '@shared/testing/factory/base.factory'; import { DrawingElement, DrawingElementProps, ROOT_PATH } from '../domain'; export const drawingElementFactory = BaseFactory.define( diff --git a/apps/server/src/modules/board/testing/file-element.factory.ts b/apps/server/src/modules/board/testing/file-element.factory.ts index 5599de53251..8a20b1583ef 100644 --- a/apps/server/src/modules/board/testing/file-element.factory.ts +++ b/apps/server/src/modules/board/testing/file-element.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing'; +import { BaseFactory } from '@shared/testing/factory/base.factory'; import { FileElement, FileElementProps, ROOT_PATH } from '../domain'; export const fileElementFactory = BaseFactory.define(FileElement, ({ sequence }) => { diff --git a/apps/server/src/modules/board/testing/link-element.factory.ts b/apps/server/src/modules/board/testing/link-element.factory.ts index 257d1f23f72..acb879703d6 100644 --- a/apps/server/src/modules/board/testing/link-element.factory.ts +++ b/apps/server/src/modules/board/testing/link-element.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing'; +import { BaseFactory } from '@shared/testing/factory/base.factory'; import { LinkElement, LinkElementProps, ROOT_PATH } from '../domain'; export const linkElementFactory = BaseFactory.define(LinkElement, ({ sequence }) => { From 4d602f0c7817daae95f28642f4cd0c351a84d778 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Mon, 25 Nov 2024 18:50:35 +0100 Subject: [PATCH 26/60] fix board tests --- apps/server/src/modules/board/uc/submission-item.uc.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/server/src/modules/board/uc/submission-item.uc.spec.ts b/apps/server/src/modules/board/uc/submission-item.uc.spec.ts index a516784b6fe..483319efdd9 100644 --- a/apps/server/src/modules/board/uc/submission-item.uc.spec.ts +++ b/apps/server/src/modules/board/uc/submission-item.uc.spec.ts @@ -2,7 +2,8 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Action } from '@modules/authorization'; import { BadRequestException, ForbiddenException } from '@nestjs/common'; import { Test, TestingModule } from '@nestjs/testing'; -import { setupEntities, userFactory } from '@shared/testing'; +import { setupEntities } from '@shared/testing/setup-entities'; +import { userFactory } from '@shared/testing/factory/user.factory'; import { BoardNodeAuthorizable, BoardNodeFactory, From 754352648aaaa2ef68f998bdbfd960a5be82c297 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 26 Nov 2024 10:16:21 +0100 Subject: [PATCH 27/60] fix board tests --- .../modules/board/testing/board-node-authorizable.factory.ts | 2 +- .../board/testing/media-available-line-element.factory.ts | 2 +- .../src/modules/board/testing/media-available-line.factory.ts | 2 +- apps/server/src/modules/board/testing/media-board.factory.ts | 2 +- .../board/testing/media-external-tool-element.factory.ts | 2 +- apps/server/src/modules/board/testing/media-line.factory.ts | 2 +- .../board/testing/submission-container-element.factory.ts | 2 +- .../src/modules/board/testing/submission-item.factory.ts | 2 +- .../src/modules/board/uc/media-board/media-board.uc.spec.ts | 3 ++- 9 files changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/server/src/modules/board/testing/board-node-authorizable.factory.ts b/apps/server/src/modules/board/testing/board-node-authorizable.factory.ts index e34d399b5c7..c3ea7c19b7c 100644 --- a/apps/server/src/modules/board/testing/board-node-authorizable.factory.ts +++ b/apps/server/src/modules/board/testing/board-node-authorizable.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { DomainObjectFactory } from '@shared/testing'; +import { DomainObjectFactory } from '@shared/testing/factory/domainobject/domain-object.factory'; import { BoardNodeAuthorizable, BoardNodeAuthorizableProps } from '../domain'; import { columnBoardFactory } from './column-board.factory'; import { columnFactory } from './column.factory'; diff --git a/apps/server/src/modules/board/testing/media-available-line-element.factory.ts b/apps/server/src/modules/board/testing/media-available-line-element.factory.ts index d1615fc2239..c6b9fe706fc 100644 --- a/apps/server/src/modules/board/testing/media-available-line-element.factory.ts +++ b/apps/server/src/modules/board/testing/media-available-line-element.factory.ts @@ -1,5 +1,5 @@ -import { BaseFactory } from '@shared/testing'; import { ObjectId } from '@mikro-orm/mongodb'; +import { BaseFactory } from '@shared/testing/factory/base.factory'; import { MediaAvailableLineElement, MediaAvailableLineElementProps } from '../domain'; export const mediaAvailableLineElementFactory = BaseFactory.define< diff --git a/apps/server/src/modules/board/testing/media-available-line.factory.ts b/apps/server/src/modules/board/testing/media-available-line.factory.ts index ba9ee9e716b..31d71be64a2 100644 --- a/apps/server/src/modules/board/testing/media-available-line.factory.ts +++ b/apps/server/src/modules/board/testing/media-available-line.factory.ts @@ -1,5 +1,5 @@ import { DeepPartial } from 'fishery'; -import { BaseFactory } from '@shared/testing'; +import { BaseFactory } from '@shared/testing/factory/base.factory'; import { MediaBoardColors, MediaAvailableLine, MediaAvailableLineElement, MediaAvailableLineProps } from '../domain'; class MediaAvailableLineFactory extends BaseFactory { diff --git a/apps/server/src/modules/board/testing/media-board.factory.ts b/apps/server/src/modules/board/testing/media-board.factory.ts index 3bbd8a705a0..a62609a899f 100644 --- a/apps/server/src/modules/board/testing/media-board.factory.ts +++ b/apps/server/src/modules/board/testing/media-board.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing'; +import { BaseFactory } from '@shared/testing/factory/base.factory'; import { BoardExternalReferenceType, BoardLayout, diff --git a/apps/server/src/modules/board/testing/media-external-tool-element.factory.ts b/apps/server/src/modules/board/testing/media-external-tool-element.factory.ts index cb1dbf4c2fc..26d8bef7fed 100644 --- a/apps/server/src/modules/board/testing/media-external-tool-element.factory.ts +++ b/apps/server/src/modules/board/testing/media-external-tool-element.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing'; +import { BaseFactory } from '@shared/testing/factory/base.factory'; import { MediaExternalToolElement, MediaExternalToolElementProps, ROOT_PATH } from '../domain'; export const mediaExternalToolElementFactory = BaseFactory.define< diff --git a/apps/server/src/modules/board/testing/media-line.factory.ts b/apps/server/src/modules/board/testing/media-line.factory.ts index 2f2c7bf3395..2b6f0af5999 100644 --- a/apps/server/src/modules/board/testing/media-line.factory.ts +++ b/apps/server/src/modules/board/testing/media-line.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing'; +import { BaseFactory } from '@shared/testing/factory/base.factory'; import { MediaLine, MediaLineProps, ROOT_PATH } from '../domain'; import { MediaBoardColors } from '../domain/media-board/types'; diff --git a/apps/server/src/modules/board/testing/submission-container-element.factory.ts b/apps/server/src/modules/board/testing/submission-container-element.factory.ts index 42d67af9176..f8911326bb6 100644 --- a/apps/server/src/modules/board/testing/submission-container-element.factory.ts +++ b/apps/server/src/modules/board/testing/submission-container-element.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing'; +import { BaseFactory } from '@shared/testing/factory/base.factory'; import { ROOT_PATH, SubmissionContainerElement, SubmissionContainerElementProps } from '../domain'; export const submissionContainerElementFactory = BaseFactory.define< diff --git a/apps/server/src/modules/board/testing/submission-item.factory.ts b/apps/server/src/modules/board/testing/submission-item.factory.ts index cc01e1cb114..4f9066ec880 100644 --- a/apps/server/src/modules/board/testing/submission-item.factory.ts +++ b/apps/server/src/modules/board/testing/submission-item.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing'; +import { BaseFactory } from '@shared/testing/factory/base.factory'; import { ROOT_PATH, SubmissionItem, SubmissionItemProps } from '../domain'; export const submissionItemFactory = BaseFactory.define(SubmissionItem, () => { diff --git a/apps/server/src/modules/board/uc/media-board/media-board.uc.spec.ts b/apps/server/src/modules/board/uc/media-board/media-board.uc.spec.ts index 8d1b231cb98..2849a8da315 100644 --- a/apps/server/src/modules/board/uc/media-board/media-board.uc.spec.ts +++ b/apps/server/src/modules/board/uc/media-board/media-board.uc.spec.ts @@ -3,7 +3,8 @@ import { Action, AuthorizationContextBuilder, AuthorizationService } from '@modu import { ConfigService } from '@nestjs/config'; import { Test, TestingModule } from '@nestjs/testing'; import { FeatureDisabledLoggableException } from '@shared/common/loggable-exception'; -import { setupEntities, userFactory as userEntityFactory } from '@shared/testing'; +import { setupEntities } from '@shared/testing/setup-entities'; +import { userFactory as userEntityFactory } from '@shared/testing/factory/user.factory'; import type { MediaBoardConfig } from '../../media-board.config'; import { BoardNodePermissionService, BoardNodeService, MediaBoardService } from '../../service'; import { mediaBoardFactory, mediaLineFactory } from '../../testing'; From 62d3b008b54b83c6425e5b87fbd472a6d4c3e59a Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 26 Nov 2024 10:45:39 +0100 Subject: [PATCH 28/60] fix board tests --- .../src/modules/board/uc/media-board/media-line.uc.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/server/src/modules/board/uc/media-board/media-line.uc.spec.ts b/apps/server/src/modules/board/uc/media-board/media-line.uc.spec.ts index 96732a1e4dd..31e49679c0a 100644 --- a/apps/server/src/modules/board/uc/media-board/media-line.uc.spec.ts +++ b/apps/server/src/modules/board/uc/media-board/media-line.uc.spec.ts @@ -3,7 +3,8 @@ import { Action } from '@modules/authorization'; import { ConfigService } from '@nestjs/config'; import { Test, TestingModule } from '@nestjs/testing'; import { FeatureDisabledLoggableException } from '@shared/common/loggable-exception'; -import { setupEntities, userFactory as userEntityFactory } from '@shared/testing'; +import { setupEntities } from '@shared/testing/setup-entities'; +import { userFactory as userEntityFactory } from '@shared/testing/factory'; import type { MediaBoardConfig } from '../../media-board.config'; import { BoardNodePermissionService, BoardNodeService, MediaBoardService } from '../../service'; import { mediaBoardFactory, mediaLineFactory } from '../../testing'; From 7465d5a6ad755ee5acb6f99736e8e2e0bd139a9d Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 26 Nov 2024 11:04:44 +0100 Subject: [PATCH 29/60] fix board tests --- .../modules/board/service/board-common-tool.service.spec.ts | 2 +- apps/server/src/modules/board/uc/card.uc.spec.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/server/src/modules/board/service/board-common-tool.service.spec.ts b/apps/server/src/modules/board/service/board-common-tool.service.spec.ts index 5895d3eb0b9..165d1afc2f3 100644 --- a/apps/server/src/modules/board/service/board-common-tool.service.spec.ts +++ b/apps/server/src/modules/board/service/board-common-tool.service.spec.ts @@ -1,7 +1,7 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Test, TestingModule } from '@nestjs/testing'; import { NotFoundException } from '@nestjs/common'; -import { contextExternalToolFactory } from '@modules/tool/context-external-tool/testing'; +import { contextExternalToolFactory } from '@modules/tool/context-external-tool/testing/context-external-tool.factory'; import { BoardCommonToolService } from './board-common-tool.service'; import { BoardNodeRepo } from '../repo'; import { BoardNodeService } from './board-node.service'; diff --git a/apps/server/src/modules/board/uc/card.uc.spec.ts b/apps/server/src/modules/board/uc/card.uc.spec.ts index be5bba4afa8..29eb4bedd4f 100644 --- a/apps/server/src/modules/board/uc/card.uc.spec.ts +++ b/apps/server/src/modules/board/uc/card.uc.spec.ts @@ -1,7 +1,8 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Action, AuthorizationService } from '@modules/authorization'; import { Test, TestingModule } from '@nestjs/testing'; -import { setupEntities, userFactory } from '@shared/testing'; +import { setupEntities } from '@shared/testing/setup-entities'; +import { userFactory } from '@shared/testing/factory'; import { LegacyLogger } from '@src/core/logger'; import { BoardNodeAuthorizable, BoardNodeFactory, Card, ContentElementType } from '../domain'; import { BoardNodeAuthorizableService, BoardNodePermissionService, BoardNodeService } from '../service'; From 97612fc8913a187c291463ad1c99ac94889499dd Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 26 Nov 2024 11:21:55 +0100 Subject: [PATCH 30/60] fix board tests --- .../uc/media-board/media-available-line.uc.spec.ts | 11 ++++++----- apps/server/src/shared/domain/types/task.types.ts | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/server/src/modules/board/uc/media-board/media-available-line.uc.spec.ts b/apps/server/src/modules/board/uc/media-board/media-available-line.uc.spec.ts index 534e5b133c0..445a25e44db 100644 --- a/apps/server/src/modules/board/uc/media-board/media-available-line.uc.spec.ts +++ b/apps/server/src/modules/board/uc/media-board/media-available-line.uc.spec.ts @@ -1,16 +1,17 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { ObjectId } from '@mikro-orm/mongodb'; import { Action, AuthorizationService } from '@modules/authorization'; -import { ExternalTool } from '@modules/tool/external-tool/domain'; -import { SchoolExternalTool } from '@modules/tool/school-external-tool/domain'; -import { schoolExternalToolFactory } from '@modules/tool/school-external-tool/testing'; +import { ExternalTool } from '@modules/tool/external-tool/domain/external-tool.do'; +import { SchoolExternalTool } from '@modules/tool/school-external-tool/domain/school-external-tool.do'; +import { schoolExternalToolFactory } from '@modules/tool/school-external-tool/testing/school-external-tool.factory'; import { MediaUserLicense, mediaUserLicenseFactory, MediaUserLicenseService } from '@modules/user-license'; import { ConfigService } from '@nestjs/config'; import { Test, TestingModule } from '@nestjs/testing'; import { FeatureDisabledLoggableException } from '@shared/common/loggable-exception'; import { User } from '@shared/domain/entity'; -import { setupEntities, userFactory as userEntityFactory, userFactory } from '@shared/testing'; -import { externalToolFactory } from '@modules/tool/external-tool/testing'; +import { setupEntities } from '@shared/testing/setup-entities'; +import { userFactory as userEntityFactory, userFactory } from '@shared/testing/factory'; +import { externalToolFactory } from '@modules/tool/external-tool/testing/external-tool.factory'; import { MediaAvailableLine, MediaAvailableLineElement, diff --git a/apps/server/src/shared/domain/types/task.types.ts b/apps/server/src/shared/domain/types/task.types.ts index c9ce4ebb698..a5812f5e522 100644 --- a/apps/server/src/shared/domain/types/task.types.ts +++ b/apps/server/src/shared/domain/types/task.types.ts @@ -1,5 +1,5 @@ -import type { Course, LessonEntity, SchoolEntity, Submission, User } from '@shared/domain/entity'; -import type { InputFormat } from '@shared/domain/types'; +import type { Course, LessonEntity, SchoolEntity, Submission, User } from '../entity'; +import type { InputFormat } from './input-format.types'; interface ITask { name: string; From cf6c434a7174da7dfd3be5fd424d35724204c8aa Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 26 Nov 2024 11:59:37 +0100 Subject: [PATCH 31/60] fix board tests --- .../board/metrics/metrics.service.spec.ts | 3 +-- .../board/repo/board-node.repo.spec.ts | 4 +--- .../board-node-authorizable.service.spec.ts | 3 +-- .../board/service/board-node.service.spec.ts | 12 +++++----- .../internal/board-node-copy-context.spec.ts | 18 +++++++-------- .../board-node-delete-hooks.service.spec.ts | 22 ++++++++++--------- .../src/modules/board/uc/board.uc.spec.ts | 7 +++--- .../src/modules/board/uc/column.uc.spec.ts | 6 ++--- .../src/modules/board/uc/element.uc.spec.ts | 3 ++- .../uc/media-board/media-board.uc.spec.ts | 2 +- .../board/uc/submission-item.uc.spec.ts | 2 +- 11 files changed, 39 insertions(+), 43 deletions(-) diff --git a/apps/server/src/modules/board/metrics/metrics.service.spec.ts b/apps/server/src/modules/board/metrics/metrics.service.spec.ts index 7724b0a5d7f..48e01153526 100644 --- a/apps/server/src/modules/board/metrics/metrics.service.spec.ts +++ b/apps/server/src/modules/board/metrics/metrics.service.spec.ts @@ -2,8 +2,7 @@ import { DeepMocked, createMock } from '@golevelup/ts-jest'; import { Test, TestingModule } from '@nestjs/testing'; import { UserService } from '@src/modules/user'; import { RoleName } from '@shared/domain/interface'; -import { roleFactory } from '@shared/testing/factory/role.factory'; -import { userDoFactory } from '@shared/testing/factory/user.do.factory'; +import { roleFactory, userDoFactory } from '@shared/testing/factory'; import { MetricsService } from './metrics.service'; describe(MetricsService.name, () => { diff --git a/apps/server/src/modules/board/repo/board-node.repo.spec.ts b/apps/server/src/modules/board/repo/board-node.repo.spec.ts index 067523b8b6f..2be0cbb5324 100644 --- a/apps/server/src/modules/board/repo/board-node.repo.spec.ts +++ b/apps/server/src/modules/board/repo/board-node.repo.spec.ts @@ -4,9 +4,7 @@ import { BaseEntityWithTimestamps } from '@shared/domain/entity'; import { cleanupCollections } from '@shared/testing/cleanup-collections'; import { MongoMemoryDatabaseModule } from '@src/infra/database'; import { ColumnBoard } from '../domain'; -import { cardFactory } from '../testing/card.factory'; -import { columnBoardFactory } from '../testing/column-board.factory'; -import { columnFactory } from '../testing/column.factory'; +import { cardFactory, columnBoardFactory, columnFactory } from '../testing'; import { BoardNodeRepo } from './board-node.repo'; import { BoardNodeEntity } from './entity/board-node.entity'; diff --git a/apps/server/src/modules/board/service/board-node-authorizable.service.spec.ts b/apps/server/src/modules/board/service/board-node-authorizable.service.spec.ts index 190dda401ee..b92520c1d58 100644 --- a/apps/server/src/modules/board/service/board-node-authorizable.service.spec.ts +++ b/apps/server/src/modules/board/service/board-node-authorizable.service.spec.ts @@ -2,8 +2,7 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Test, TestingModule } from '@nestjs/testing'; import { setupEntities } from '@shared/testing/setup-entities'; import { AuthorizableReferenceType, AuthorizationInjectionService } from '@modules/authorization'; -import { columnBoardFactory } from '../testing/column-board.factory'; -import { columnFactory } from '../testing/column.factory'; +import { columnBoardFactory, columnFactory } from '../testing'; import { BoardNodeAuthorizable, BoardRoles, UserWithBoardRoles } from '../domain'; import { BoardNodeRepo } from '../repo'; import { BoardContextService } from './internal/board-context.service'; diff --git a/apps/server/src/modules/board/service/board-node.service.spec.ts b/apps/server/src/modules/board/service/board-node.service.spec.ts index 784246702eb..9da714b7309 100644 --- a/apps/server/src/modules/board/service/board-node.service.spec.ts +++ b/apps/server/src/modules/board/service/board-node.service.spec.ts @@ -5,11 +5,13 @@ import { Test, TestingModule } from '@nestjs/testing'; import { setupEntities } from '@shared/testing/setup-entities'; import { Card, ColumnBoard } from '../domain'; import { BoardNodeRepo } from '../repo'; -import { cardFactory } from '../testing/card.factory'; -import { columnBoardFactory } from '../testing/column-board.factory'; -import { deletedElementFactory } from '../testing/deleted-element.factory'; -import { externalToolElementFactory } from '../testing/external-tool-element.factory'; -import { richTextElementFactory } from '../testing/rich-text-element.factory'; +import { + cardFactory, + columnBoardFactory, + deletedElementFactory, + externalToolElementFactory, + richTextElementFactory, +} from '../testing'; import { BoardNodeService } from './board-node.service'; import { BoardNodeDeleteHooksService, ContentElementUpdateService } from './internal'; diff --git a/apps/server/src/modules/board/service/internal/board-node-copy-context.spec.ts b/apps/server/src/modules/board/service/internal/board-node-copy-context.spec.ts index 412c4e83ecb..a65ef01e651 100644 --- a/apps/server/src/modules/board/service/internal/board-node-copy-context.spec.ts +++ b/apps/server/src/modules/board/service/internal/board-node-copy-context.spec.ts @@ -3,16 +3,14 @@ import { ObjectId } from '@mikro-orm/mongodb'; import { StorageLocation } from '@modules/files-storage/interface'; import { FileRecordParentType } from '@src/infra/rabbitmq'; import { FilesStorageClientAdapterService } from '@src/modules/files-storage-client'; -import { BoardNodeCopyContext } from './board-node-copy-context'; +import { BoardNodeCopyContext, BoardNodeCopyContextProps } from './board-node-copy-context'; describe(BoardNodeCopyContext.name, () => { describe('copyFilesOfParent', () => { const setup = () => { - const contextProps = { - sourceStorageLocationId: new ObjectId().toHexString(), - targetStorageLocationId: new ObjectId().toHexString(), - sourceStorageLocation: StorageLocation.SCHOOL, - targetStorageLocation: StorageLocation.SCHOOL, + const contextProps: BoardNodeCopyContextProps = { + sourceStorageLocationReference: { id: new ObjectId().toHexString(), type: StorageLocation.SCHOOL }, + targetStorageLocationReference: { id: new ObjectId().toHexString(), type: StorageLocation.SCHOOL }, userId: new ObjectId().toHexString(), filesStorageClientAdapterService: createMock(), }; @@ -34,14 +32,14 @@ describe(BoardNodeCopyContext.name, () => { source: { parentId: sourceParentId, parentType: FileRecordParentType.BoardNode, - storageLocationId: contextProps.sourceStorageLocationId, - storageLocation: contextProps.sourceStorageLocation, + storageLocationId: contextProps.sourceStorageLocationReference.id, + storageLocation: contextProps.sourceStorageLocationReference.type, }, target: { parentId: targetParentId, parentType: FileRecordParentType.BoardNode, - storageLocationId: contextProps.targetStorageLocationId, - storageLocation: contextProps.targetStorageLocation, + storageLocationId: contextProps.targetStorageLocationReference.id, + storageLocation: contextProps.targetStorageLocationReference.type, }, userId: contextProps.userId, }); diff --git a/apps/server/src/modules/board/service/internal/board-node-delete-hooks.service.spec.ts b/apps/server/src/modules/board/service/internal/board-node-delete-hooks.service.spec.ts index 10fb8ca11c7..8a20814fae8 100644 --- a/apps/server/src/modules/board/service/internal/board-node-delete-hooks.service.spec.ts +++ b/apps/server/src/modules/board/service/internal/board-node-delete-hooks.service.spec.ts @@ -1,16 +1,18 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Test, TestingModule } from '@nestjs/testing'; import { setupEntities } from '@shared/testing/setup-entities'; -import { CollaborativeTextEditorService } from '@src/modules/collaborative-text-editor/service/collaborative-text-editor.service'; -import { FilesStorageClientAdapterService } from '@src/modules/files-storage-client/service/files-storage-client.service'; -import { DrawingElementAdapterService } from '@src/modules/tldraw-client/service/drawing-element-adapter.service'; -import { ContextExternalToolService } from '@src/modules/tool/context-external-tool/service/context-external-tool.service'; -import { contextExternalToolFactory } from '@src/modules/tool/context-external-tool/testing/context-external-tool.factory'; -import { collaborativeTextEditorFactory } from '../../testing/collaborative-text-editor.factory'; -import { drawingElementFactory } from '../../testing/drawing-element.factory'; -import { externalToolElementFactory } from '../../testing/external-tool-element.factory'; -import { fileElementFactory } from '../../testing/file-element.factory'; -import { linkElementFactory } from '../../testing/link-element.factory'; +import { CollaborativeTextEditorService } from '@modules/collaborative-text-editor/service/collaborative-text-editor.service'; +import { FilesStorageClientAdapterService } from '@modules/files-storage-client/service/files-storage-client.service'; +import { DrawingElementAdapterService } from '@modules/tldraw-client/service/drawing-element-adapter.service'; +import { ContextExternalToolService } from '@modules/tool/context-external-tool/service/context-external-tool.service'; +import { contextExternalToolFactory } from '@modules/tool/context-external-tool/testing/context-external-tool.factory'; +import { + collaborativeTextEditorFactory, + drawingElementFactory, + externalToolElementFactory, + fileElementFactory, + linkElementFactory, +} from '../../testing'; import { BoardNodeDeleteHooksService } from './board-node-delete-hooks.service'; describe(BoardNodeDeleteHooksService.name, () => { diff --git a/apps/server/src/modules/board/uc/board.uc.spec.ts b/apps/server/src/modules/board/uc/board.uc.spec.ts index 114f7c7523c..a44fa1aedd5 100644 --- a/apps/server/src/modules/board/uc/board.uc.spec.ts +++ b/apps/server/src/modules/board/uc/board.uc.spec.ts @@ -4,12 +4,11 @@ import { Action, AuthorizationService } from '@modules/authorization'; import { Test, TestingModule } from '@nestjs/testing'; import { Permission } from '@shared/domain/interface'; import { CourseRepo } from '@shared/repo'; -import { courseFactory } from '@shared/testing/factory/course.factory'; -import { userFactory } from '@shared/testing/factory/user.factory'; +import { courseFactory, userFactory } from '@shared/testing/factory'; import { setupEntities } from '@shared/testing/setup-entities'; import { LegacyLogger } from '@src/core/logger'; -import { RoomService } from '@src/modules/room'; -import { RoomMemberService } from '@src/modules/room-member'; +import { RoomService } from '@modules/room'; +import { RoomMemberService } from '@modules/room-member'; import { CopyElementType, CopyStatus, CopyStatusEnum } from '../../copy-helper'; import { BoardExternalReferenceType, BoardLayout, BoardNodeFactory, Column, ColumnBoard } from '../domain'; import { BoardNodePermissionService, BoardNodeService, ColumnBoardService } from '../service'; diff --git a/apps/server/src/modules/board/uc/column.uc.spec.ts b/apps/server/src/modules/board/uc/column.uc.spec.ts index 5c1a6c1d39e..47f6f4b52f0 100644 --- a/apps/server/src/modules/board/uc/column.uc.spec.ts +++ b/apps/server/src/modules/board/uc/column.uc.spec.ts @@ -2,14 +2,12 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Action } from '@modules/authorization'; import { Test, TestingModule } from '@nestjs/testing'; import { setupEntities } from '@shared/testing/setup-entities'; -import { userFactory } from '@shared/testing/factory/user.factory'; +import { userFactory } from '@shared/testing/factory'; import { LegacyLogger } from '@src/core/logger'; import { BoardNodeFactory, Card, Column, ContentElementType } from '../domain'; import { BoardNodeService } from '../service'; import { BoardNodePermissionService } from '../service/board-node-permission.service'; -import { cardFactory } from '../testing/card.factory'; -import { columnBoardFactory } from '../testing/column-board.factory'; -import { columnFactory } from '../testing/column.factory'; +import { cardFactory, columnBoardFactory, columnFactory } from '../testing'; import { ColumnUc } from './column.uc'; describe(ColumnUc.name, () => { diff --git a/apps/server/src/modules/board/uc/element.uc.spec.ts b/apps/server/src/modules/board/uc/element.uc.spec.ts index 471be5363a4..fc2d5437235 100644 --- a/apps/server/src/modules/board/uc/element.uc.spec.ts +++ b/apps/server/src/modules/board/uc/element.uc.spec.ts @@ -2,7 +2,8 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { HttpService } from '@nestjs/axios'; import { Test, TestingModule } from '@nestjs/testing'; import { InputFormat } from '@shared/domain/types'; -import { setupEntities, userFactory } from '@shared/testing'; +import { setupEntities } from '@shared/testing/setup-entities'; +import { userFactory } from '@shared/testing/factory'; import { Logger } from '@src/core/logger'; import { Action } from '@modules/authorization'; import { ElementUc } from './element.uc'; diff --git a/apps/server/src/modules/board/uc/media-board/media-board.uc.spec.ts b/apps/server/src/modules/board/uc/media-board/media-board.uc.spec.ts index 2849a8da315..c083570dfc8 100644 --- a/apps/server/src/modules/board/uc/media-board/media-board.uc.spec.ts +++ b/apps/server/src/modules/board/uc/media-board/media-board.uc.spec.ts @@ -4,7 +4,7 @@ import { ConfigService } from '@nestjs/config'; import { Test, TestingModule } from '@nestjs/testing'; import { FeatureDisabledLoggableException } from '@shared/common/loggable-exception'; import { setupEntities } from '@shared/testing/setup-entities'; -import { userFactory as userEntityFactory } from '@shared/testing/factory/user.factory'; +import { userFactory as userEntityFactory } from '@shared/testing/factory'; import type { MediaBoardConfig } from '../../media-board.config'; import { BoardNodePermissionService, BoardNodeService, MediaBoardService } from '../../service'; import { mediaBoardFactory, mediaLineFactory } from '../../testing'; diff --git a/apps/server/src/modules/board/uc/submission-item.uc.spec.ts b/apps/server/src/modules/board/uc/submission-item.uc.spec.ts index 483319efdd9..d8cc588fd9c 100644 --- a/apps/server/src/modules/board/uc/submission-item.uc.spec.ts +++ b/apps/server/src/modules/board/uc/submission-item.uc.spec.ts @@ -3,7 +3,7 @@ import { Action } from '@modules/authorization'; import { BadRequestException, ForbiddenException } from '@nestjs/common'; import { Test, TestingModule } from '@nestjs/testing'; import { setupEntities } from '@shared/testing/setup-entities'; -import { userFactory } from '@shared/testing/factory/user.factory'; +import { userFactory } from '@shared/testing/factory'; import { BoardNodeAuthorizable, BoardNodeFactory, From 871e8e44daf35053bc06015b625f385b73fbcf27 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 26 Nov 2024 15:36:02 +0100 Subject: [PATCH 32/60] fix board tests --- .../column-board-copy.service.spec.ts | 149 ++++++------------ .../internal/column-board-copy.service.ts | 2 +- .../src/modules/learnroom/learnroom.module.ts | 2 - 3 files changed, 47 insertions(+), 106 deletions(-) diff --git a/apps/server/src/modules/board/service/internal/column-board-copy.service.spec.ts b/apps/server/src/modules/board/service/internal/column-board-copy.service.spec.ts index 0a6792bdc46..bcf4d270493 100644 --- a/apps/server/src/modules/board/service/internal/column-board-copy.service.spec.ts +++ b/apps/server/src/modules/board/service/internal/column-board-copy.service.spec.ts @@ -1,26 +1,23 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { ObjectId } from '@mikro-orm/mongodb'; -import { UserService } from '@modules/user/service/user.service'; import { Test, TestingModule } from '@nestjs/testing'; -import { CourseRepo } from '@shared/repo/course/course.repo'; -import { courseFactory, setupEntities, userDoFactory } from '@shared/testing'; +import { courseFactory } from '@shared/testing/factory'; +import { setupEntities } from '@shared/testing/setup-entities'; import { CopyElementType, CopyStatus, CopyStatusEnum } from '@src/modules/copy-helper'; import { FilesStorageClientAdapterService } from '@src/modules/files-storage-client/service/files-storage-client.service'; +import { StorageLocation } from '@src/modules/files-storage/interface'; import { BoardExternalReferenceType } from '../../domain'; import { columnBoardFactory } from '../../testing'; import { BoardNodeService } from '../board-node.service'; -import { ColumnBoardCopyService } from './column-board-copy.service'; -import { ColumnBoardTitleService } from './column-board-title.service'; -// Important: Don't move the BoardNodeCopyService import up to prevent import cycle! import { BoardNodeCopyService } from './board-node-copy.service'; +import { ColumnBoardCopyService, CopyColumnBoardParams } from './column-board-copy.service'; +import { ColumnBoardTitleService } from './column-board-title.service'; describe(ColumnBoardCopyService.name, () => { let module: TestingModule; let service: ColumnBoardCopyService; let boardNodeService: DeepMocked; - let courseRepo: DeepMocked; - let userService: DeepMocked; let boardNodeCopyService: DeepMocked; let columnBoardTitleService: DeepMocked; @@ -36,14 +33,6 @@ describe(ColumnBoardCopyService.name, () => { provide: ColumnBoardTitleService, useValue: createMock(), }, - { - provide: CourseRepo, - useValue: createMock(), - }, - { - provide: UserService, - useValue: createMock(), - }, { provide: BoardNodeCopyService, useValue: createMock(), @@ -52,17 +41,11 @@ describe(ColumnBoardCopyService.name, () => { provide: FilesStorageClientAdapterService, useValue: createMock(), }, - { - provide: ColumnBoardTitleService, - useValue: createMock(), - }, ], }).compile(); service = module.get(ColumnBoardCopyService); boardNodeService = module.get(BoardNodeService); - courseRepo = module.get(CourseRepo); - userService = module.get(UserService); boardNodeCopyService = module.get(BoardNodeCopyService); columnBoardTitleService = module.get(ColumnBoardTitleService); @@ -80,10 +63,7 @@ describe(ColumnBoardCopyService.name, () => { describe('copyColumnBoard', () => { const setup = () => { const userId = new ObjectId().toHexString(); - const user = userDoFactory.build({ id: userId }); - userService.findById.mockResolvedValueOnce(user); const course = courseFactory.buildWithId(); - courseRepo.findById.mockResolvedValueOnce(course); const originalBoard = columnBoardFactory.build({ context: { id: course.id, type: BoardExternalReferenceType.Course }, }); @@ -99,66 +79,40 @@ describe(ColumnBoardCopyService.name, () => { }; boardNodeCopyService.copy.mockResolvedValueOnce(status); - return { originalBoard, userId }; - }; - - it('should find the original board', async () => { - const { originalBoard, userId } = setup(); - - await service.copyColumnBoard({ + const copyParams: CopyColumnBoardParams = { originalColumnBoardId: originalBoard.id, - destinationExternalReference: originalBoard.context, + targetExternalReference: originalBoard.context, + sourceStorageLocationReference: { id: course.school.id, type: StorageLocation.SCHOOL }, + targetStorageLocationReference: { id: course.school.id, type: StorageLocation.SCHOOL }, userId, - }); - - expect(boardNodeService.findByClassAndId).toHaveBeenCalled(); - }); - - it('should find the user', async () => { - const { originalBoard, userId } = setup(); + copyTitle: 'Board Copy', + }; - await service.copyColumnBoard({ - originalColumnBoardId: originalBoard.id, - destinationExternalReference: originalBoard.context, - userId, - }); + return { originalBoard, userId, copyParams }; + }; - expect(userService.findById).toHaveBeenCalled(); - }); + it('should find the original board', async () => { + const { copyParams } = setup(); - it('should find the course', async () => { - const { originalBoard, userId } = setup(); + await service.copyColumnBoard(copyParams); - await service.copyColumnBoard({ - originalColumnBoardId: originalBoard.id, - destinationExternalReference: originalBoard.context, - userId, - }); - - expect(courseRepo.findById).toHaveBeenCalled(); + expect(boardNodeService.findByClassAndId).toHaveBeenCalled(); }); it('should call service to copy the board', async () => { - const { originalBoard, userId } = setup(); + const { copyParams } = setup(); - await service.copyColumnBoard({ - originalColumnBoardId: originalBoard.id, - destinationExternalReference: originalBoard.context, - userId, - copyTitle: 'Another Title', - }); + await service.copyColumnBoard(copyParams); expect(boardNodeCopyService.copy).toHaveBeenCalled(); }); it('should set the title of the copied board', async () => { - const { originalBoard, userId } = setup(); + const { copyParams } = setup(); const copyTitle = 'Another Title'; await service.copyColumnBoard({ - originalColumnBoardId: originalBoard.id, - destinationExternalReference: originalBoard.context, - userId, + ...copyParams, copyTitle, }); @@ -166,56 +120,43 @@ describe(ColumnBoardCopyService.name, () => { }); it('should derive the title of the copied board', async () => { - const { originalBoard, userId } = setup(); + const { copyParams } = setup(); const derivedTitle = 'Derived Title'; columnBoardTitleService.deriveColumnBoardTitle.mockResolvedValueOnce(derivedTitle); await service.copyColumnBoard({ - originalColumnBoardId: originalBoard.id, - destinationExternalReference: originalBoard.context, - userId, + ...copyParams, + copyTitle: undefined, }); expect(boardNodeService.addRoot).toHaveBeenCalledWith(expect.objectContaining({ title: derivedTitle })); }); it('should set the context of the copied board', async () => { - const { originalBoard, userId } = setup(); - const destinationExternalReference = { + const { copyParams } = setup(); + const targetExternalReference = { id: new ObjectId().toHexString(), type: BoardExternalReferenceType.Course, }; - await service.copyColumnBoard({ - originalColumnBoardId: originalBoard.id, - destinationExternalReference, - userId, - }); + await service.copyColumnBoard({ ...copyParams, targetExternalReference }); expect(boardNodeService.addRoot).toHaveBeenCalledWith( - expect.objectContaining({ context: destinationExternalReference }) + expect.objectContaining({ context: targetExternalReference }) ); }); it('should return the copy status', async () => { - const { originalBoard, userId } = setup(); - const copyStatus = await service.copyColumnBoard({ - originalColumnBoardId: originalBoard.id, - destinationExternalReference: originalBoard.context, - userId, - }); + const { copyParams } = setup(); + const copyStatus = await service.copyColumnBoard(copyParams); expect(copyStatus).toBeDefined(); expect(copyStatus.copyEntity).toBeDefined(); }); it('should not affect the original board', async () => { - const { originalBoard, userId } = setup(); - const copyStatus = await service.copyColumnBoard({ - originalColumnBoardId: originalBoard.id, - destinationExternalReference: originalBoard.context, - userId, - }); + const { copyParams, originalBoard } = setup(); + const copyStatus = await service.copyColumnBoard(copyParams); expect(copyStatus.originalEntity).toBe(originalBoard); }); @@ -224,20 +165,26 @@ describe(ColumnBoardCopyService.name, () => { describe('when the copy response is not a ColumnBoard', () => { const setup = () => { const userId = new ObjectId().toHexString(); - const user = userDoFactory.build({ id: userId }); - userService.findById.mockResolvedValueOnce(user); const course = courseFactory.buildWithId(); - courseRepo.findById.mockResolvedValueOnce(course); const originalBoard = columnBoardFactory.build({ context: { id: course.id, type: BoardExternalReferenceType.Course }, }); boardNodeService.findByClassAndId.mockResolvedValueOnce(originalBoard); - return { originalBoard, userId }; + const copyParams: CopyColumnBoardParams = { + originalColumnBoardId: originalBoard.id, + targetExternalReference: originalBoard.context, + sourceStorageLocationReference: { id: course.school.id, type: StorageLocation.SCHOOL }, + targetStorageLocationReference: { id: course.school.id, type: StorageLocation.SCHOOL }, + userId, + copyTitle: 'Board Copy', + }; + + return { originalBoard, userId, copyParams }; }; it('should throw an error if the board is not a column board', async () => { - const { originalBoard, userId } = setup(); + const { originalBoard, copyParams } = setup(); const boardCopy = { ...originalBoard, id: new ObjectId().toHexString(), type: 'not-a-column-board' }; const status: CopyStatus = { @@ -247,13 +194,9 @@ describe(ColumnBoardCopyService.name, () => { }; boardNodeCopyService.copy.mockResolvedValueOnce(status); - await expect( - service.copyColumnBoard({ - originalColumnBoardId: originalBoard.id, - destinationExternalReference: originalBoard.context, - userId, - }) - ).rejects.toThrowError('expected copy of columnboard to be a columnboard'); + await expect(service.copyColumnBoard(copyParams)).rejects.toThrowError( + 'expected copy of columnboard to be a columnboard' + ); }); }); }); diff --git a/apps/server/src/modules/board/service/internal/column-board-copy.service.ts b/apps/server/src/modules/board/service/internal/column-board-copy.service.ts index 99eb21b92e0..785694734f9 100644 --- a/apps/server/src/modules/board/service/internal/column-board-copy.service.ts +++ b/apps/server/src/modules/board/service/internal/column-board-copy.service.ts @@ -1,5 +1,5 @@ import { CopyStatus } from '@modules/copy-helper'; -import { FilesStorageClientAdapterService } from '@modules/files-storage-client'; +import { FilesStorageClientAdapterService } from '@modules/files-storage-client/service'; import { Injectable, InternalServerErrorException, NotImplementedException } from '@nestjs/common'; import { EntityId } from '@shared/domain/types'; import { BoardExternalReference, BoardExternalReferenceType, ColumnBoard, isColumnBoard } from '../../domain'; diff --git a/apps/server/src/modules/learnroom/learnroom.module.ts b/apps/server/src/modules/learnroom/learnroom.module.ts index a8bdcbeba4c..c06158e4a38 100644 --- a/apps/server/src/modules/learnroom/learnroom.module.ts +++ b/apps/server/src/modules/learnroom/learnroom.module.ts @@ -20,7 +20,6 @@ import { UserRepo, } from '@shared/repo'; import { LoggerModule } from '@src/core/logger'; -import { BoardNodeRepo } from '../board/repo'; import { COURSE_REPO } from './domain'; import { CommonCartridgeExportMapper } from './mapper/common-cartridge-export.mapper'; import { CommonCartridgeImportMapper } from './mapper/common-cartridge-import.mapper'; @@ -66,7 +65,6 @@ import { CommonCartridgeFileValidatorPipe } from './utils'; useClass: DashboardRepo, }, BoardCopyService, - BoardNodeRepo, CommonCartridgeExportService, CommonCartridgeFileValidatorPipe, CommonCartridgeImportService, From ffbb39cd75a258947774e163fac0500c4698e08c Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 26 Nov 2024 16:06:09 +0100 Subject: [PATCH 33/60] fix board tests --- ...ext-external-tool-deleted-event-handler.service.spec.ts | 3 ++- .../event/user-deleted-event-handler.service.spec.ts | 7 ++++--- .../service/internal/column-board-link.service.spec.ts | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/server/src/modules/board/service/event/context-external-tool-deleted-event-handler.service.spec.ts b/apps/server/src/modules/board/service/event/context-external-tool-deleted-event-handler.service.spec.ts index 9e32bb622cb..71e1dedc449 100644 --- a/apps/server/src/modules/board/service/event/context-external-tool-deleted-event-handler.service.spec.ts +++ b/apps/server/src/modules/board/service/event/context-external-tool-deleted-event-handler.service.spec.ts @@ -4,8 +4,9 @@ import { Test, TestingModule } from '@nestjs/testing'; import { ContextExternalToolDeletedEvent } from '../../../tool/context-external-tool/domain'; import { ContentElementType, DeletedElement, ROOT_PATH } from '../../domain'; import { externalToolElementFactory } from '../../testing'; -import { BoardNodeService } from '../board-node.service'; import { ContextExternalToolDeletedEventHandlerService } from './context-external-tool-deleted-event-handler.service'; +// Warning: do not move the BoardNodeService import up. Otherwise the import will lead to dependency cycles. +import { BoardNodeService } from '../board-node.service'; describe(ContextExternalToolDeletedEventHandlerService.name, () => { let module: TestingModule; diff --git a/apps/server/src/modules/board/service/event/user-deleted-event-handler.service.spec.ts b/apps/server/src/modules/board/service/event/user-deleted-event-handler.service.spec.ts index d8482bcad0e..6876920dabb 100644 --- a/apps/server/src/modules/board/service/event/user-deleted-event-handler.service.spec.ts +++ b/apps/server/src/modules/board/service/event/user-deleted-event-handler.service.spec.ts @@ -11,12 +11,13 @@ import { } from '@modules/deletion'; import { EventBus } from '@nestjs/cqrs'; import { Test, TestingModule } from '@nestjs/testing'; -import { setupEntities } from '@shared/testing'; +import { setupEntities } from '@shared/testing/setup-entities'; import { Logger } from '@src/core/logger'; import { mediaBoardFactory } from '../../testing'; -import { BoardNodeService } from '../board-node.service'; -import { MediaBoardService } from '../media-board'; import { UserDeletedEventHandlerService } from './user-deleted-event-handler.service'; +import { BoardNodeService } from '../board-node.service'; +// Warning: do not move the MediaBoardService import up. Otherwise the import will lead to dependency cycles. +import { MediaBoardService } from '../media-board/media-board.service'; describe(UserDeletedEventHandlerService.name, () => { let module: TestingModule; diff --git a/apps/server/src/modules/board/service/internal/column-board-link.service.spec.ts b/apps/server/src/modules/board/service/internal/column-board-link.service.spec.ts index aca7d8ea204..db75dc884d9 100644 --- a/apps/server/src/modules/board/service/internal/column-board-link.service.spec.ts +++ b/apps/server/src/modules/board/service/internal/column-board-link.service.spec.ts @@ -2,7 +2,7 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { ObjectId } from '@mikro-orm/mongodb'; import { Test, TestingModule } from '@nestjs/testing'; import { EntityId } from '@shared/domain/types'; -import { setupEntities } from '@shared/testing'; +import { setupEntities } from '@shared/testing/setup-entities'; import { ColumnBoard, LinkElement } from '../../domain'; import { BoardNodeRepo } from '../../repo'; import { @@ -12,8 +12,9 @@ import { linkElementFactory, richTextElementFactory, } from '../../testing'; -import { BoardNodeService } from '../board-node.service'; import { ColumnBoardLinkService } from './column-board-link.service'; +// Warning: do not move the BoardNodeService import up. Otherwise the import will lead to dependency cycles. +import { BoardNodeService } from '../board-node.service'; describe(ColumnBoardLinkService.name, () => { let module: TestingModule; From 871e37b5d17a2ffb7b0c7a13cf7a568a8ec49e15 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 26 Nov 2024 16:34:43 +0100 Subject: [PATCH 34/60] fix board tests --- .../board-node-permission.service.spec.ts | 3 ++- .../board/service/column-board.service.spec.ts | 16 +++++++++------- .../internal/board-context.service.spec.ts | 11 ++++++----- .../board-node-copy-general.service.spec.ts | 6 ++---- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/apps/server/src/modules/board/service/board-node-permission.service.spec.ts b/apps/server/src/modules/board/service/board-node-permission.service.spec.ts index 3d636d1561c..e837bc568e8 100644 --- a/apps/server/src/modules/board/service/board-node-permission.service.spec.ts +++ b/apps/server/src/modules/board/service/board-node-permission.service.spec.ts @@ -1,7 +1,8 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Action, AuthorizationContext, AuthorizationService } from '@modules/authorization'; import { Test, TestingModule } from '@nestjs/testing'; -import { setupEntities, userFactory } from '@shared/testing'; +import { setupEntities } from '@shared/testing/setup-entities'; +import { userFactory } from '@shared/testing/factory'; import { BoardNodeAuthorizable, BoardRoles, UserWithBoardRoles } from '../domain'; import { BoardNodeAuthorizableService } from './board-node-authorizable.service'; import { BoardNodePermissionService } from './board-node-permission.service'; diff --git a/apps/server/src/modules/board/service/column-board.service.spec.ts b/apps/server/src/modules/board/service/column-board.service.spec.ts index a514242ea97..ac2986ff473 100644 --- a/apps/server/src/modules/board/service/column-board.service.spec.ts +++ b/apps/server/src/modules/board/service/column-board.service.spec.ts @@ -1,14 +1,14 @@ +import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Test, TestingModule } from '@nestjs/testing'; import { EntityId } from '@shared/domain/types'; -import { createMock, DeepMocked } from '@golevelup/ts-jest'; -import { ColumnBoardService } from './column-board.service'; +import { StorageLocation } from '@src/modules/files-storage/interface'; +import { CopyElementType, CopyStatus, CopyStatusEnum } from '../../copy-helper'; +import { BoardExternalReference, BoardExternalReferenceType, ColumnBoard } from '../domain'; import { BoardNodeRepo } from '../repo'; +import { columnBoardFactory } from '../testing'; import { BoardNodeService } from './board-node.service'; +import { ColumnBoardService } from './column-board.service'; import { ColumnBoardCopyService, ColumnBoardLinkService } from './internal'; -import { ColumnBoard, BoardExternalReference, BoardExternalReferenceType } from '../domain'; - -import { columnBoardFactory } from '../testing'; -import { CopyElementType, CopyStatus, CopyStatusEnum } from '../../copy-helper'; describe('ColumnBoardService', () => { let module: TestingModule; @@ -107,10 +107,12 @@ describe('ColumnBoardService', () => { columnBoardCopyService.copyColumnBoard.mockResolvedValueOnce(copyStatus); const result = await service.copyColumnBoard({ originalColumnBoardId: '1', - destinationExternalReference: { + targetExternalReference: { type: BoardExternalReferenceType.Course, id: '1', }, + sourceStorageLocationReference: { id: '1', type: StorageLocation.SCHOOL }, + targetStorageLocationReference: { id: '1', type: StorageLocation.SCHOOL }, userId: '1', }); diff --git a/apps/server/src/modules/board/service/internal/board-context.service.spec.ts b/apps/server/src/modules/board/service/internal/board-context.service.spec.ts index b1a3be99840..b2cd5165b1d 100644 --- a/apps/server/src/modules/board/service/internal/board-context.service.spec.ts +++ b/apps/server/src/modules/board/service/internal/board-context.service.spec.ts @@ -1,15 +1,16 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { ObjectId } from '@mikro-orm/mongodb'; import { Test, TestingModule } from '@nestjs/testing'; -import { CourseRepo } from '@shared/repo'; -import { courseFactory, groupFactory, roleFactory, setupEntities, userFactory } from '@shared/testing'; -import { RoomMemberService } from '@src/modules/room-member'; -import { roomFactory } from '@src/modules/room/testing'; import { Permission, RoleName } from '@shared/domain/interface'; +import { CourseRepo } from '@shared/repo'; +import { courseFactory, groupFactory, roleFactory, userFactory } from '@shared/testing/factory'; +import { setupEntities } from '@shared/testing/setup-entities'; import { GroupTypes } from '@src/modules/group'; +import { RoomMemberService } from '@src/modules/room-member'; import { roomMemberFactory } from '@src/modules/room-member/testing'; -import { columnFactory, columnBoardFactory } from '../../testing'; +import { roomFactory } from '@src/modules/room/testing'; import { BoardExternalReferenceType, BoardRoles, UserWithBoardRoles } from '../../domain'; +import { columnBoardFactory, columnFactory } from '../../testing'; import { BoardContextService } from './board-context.service'; describe(`${BoardContextService.name}`, () => { diff --git a/apps/server/src/modules/board/service/internal/board-node-copy-general.service.spec.ts b/apps/server/src/modules/board/service/internal/board-node-copy-general.service.spec.ts index 1c6c4bfafe9..71ea6f8ab56 100644 --- a/apps/server/src/modules/board/service/internal/board-node-copy-general.service.spec.ts +++ b/apps/server/src/modules/board/service/internal/board-node-copy-general.service.spec.ts @@ -66,10 +66,8 @@ describe(BoardNodeCopyService.name, () => { const setup = () => { const contextProps: BoardNodeCopyContextProps = { - sourceStorageLocationId: new ObjectId().toHexString(), - sourceStorageLocation: StorageLocation.SCHOOL, - targetStorageLocationId: new ObjectId().toHexString(), - targetStorageLocation: StorageLocation.SCHOOL, + sourceStorageLocationReference: { id: new ObjectId().toHexString(), type: StorageLocation.SCHOOL }, + targetStorageLocationReference: { id: new ObjectId().toHexString(), type: StorageLocation.SCHOOL }, userId: new ObjectId().toHexString(), filesStorageClientAdapterService: createMock(), }; From 15e59c68b12fe509466289350177599ccdb417c7 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 26 Nov 2024 16:52:36 +0100 Subject: [PATCH 35/60] fix board tests --- .../api-test/board-copy-in-course.api.spec.ts | 11 ++++++++--- .../api-test/board-collaboration.gateway.spec.ts | 11 ++++++----- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/apps/server/src/modules/board/controller/api-test/board-copy-in-course.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-copy-in-course.api.spec.ts index 51a5cf227c1..e7407e7e453 100644 --- a/apps/server/src/modules/board/controller/api-test/board-copy-in-course.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-copy-in-course.api.spec.ts @@ -1,12 +1,16 @@ import { EntityManager } from '@mikro-orm/mongodb'; +import { CopyApiResponse } from '@modules/copy-helper/dto/copy.response'; +import { CopyElementType, CopyStatusEnum } from '@modules/copy-helper/types/copy.types'; import { ServerTestModule } from '@modules/server/server.module'; import { INestApplication } from '@nestjs/common'; import { Test, TestingModule } from '@nestjs/testing'; -import { TestApiClient, UserAndAccountTestFactory, cleanupCollections, courseFactory } from '@shared/testing'; -import { CopyApiResponse, CopyElementType, CopyStatusEnum } from '@modules/copy-helper'; +import { cleanupCollections } from '@shared/testing/cleanup-collections'; +import { courseFactory } from '@shared/testing/factory/course.factory'; +import { UserAndAccountTestFactory } from '@shared/testing/factory/user-and-account.test.factory'; +import { TestApiClient } from '@shared/testing/test-api-client'; +import { BoardExternalReferenceType } from '../../domain'; import { BoardNodeEntity } from '../../repo'; import { columnBoardEntityFactory } from '../../testing'; -import { BoardExternalReferenceType } from '../../domain'; const baseRouteName = '/boards'; @@ -71,6 +75,7 @@ describe(`board copy with course relation (api)`, () => { id: expect.any(String), type: CopyElementType.COLUMNBOARD, status: CopyStatusEnum.SUCCESS, + destinationId: columnBoardNode.context?.id, }; expect(body).toEqual(expectedBody); diff --git a/apps/server/src/modules/board/gateway/api-test/board-collaboration.gateway.spec.ts b/apps/server/src/modules/board/gateway/api-test/board-collaboration.gateway.spec.ts index 1d35a9d10c8..ab8f66184b8 100644 --- a/apps/server/src/modules/board/gateway/api-test/board-collaboration.gateway.spec.ts +++ b/apps/server/src/modules/board/gateway/api-test/board-collaboration.gateway.spec.ts @@ -1,20 +1,21 @@ +import { MongoIoAdapter } from '@infra/socketio'; import { EntityManager } from '@mikro-orm/mongodb'; import { INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; - -import { MongoIoAdapter } from '@infra/socketio'; import { InputFormat } from '@shared/domain/types'; -import { cleanupCollections, courseFactory, userFactory } from '@shared/testing'; +import { cleanupCollections } from '@shared/testing/cleanup-collections'; +import { courseFactory } from '@shared/testing/factory/course.factory'; +import { userFactory } from '@shared/testing/factory/user.factory'; import { getSocketApiClient, waitForEvent } from '@shared/testing/test-socket-api-client'; import { Socket } from 'socket.io-client'; +import { BoardCollaborationTestingModule } from '../../board-collaboration.testing.module'; +import { BoardExternalReferenceType, CardProps, ContentElementType } from '../../domain'; import { cardEntityFactory, columnBoardEntityFactory, columnEntityFactory, richTextElementEntityFactory, } from '../../testing'; -import { BoardExternalReferenceType, CardProps, ContentElementType } from '../../domain'; -import { BoardCollaborationTestingModule } from '../../board-collaboration.testing.module'; import { BoardCollaborationGateway } from '../board-collaboration.gateway'; describe(BoardCollaborationGateway.name, () => { From 574ed91977801080cbe9dc982cc18a00ffc6d08b Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 26 Nov 2024 17:00:59 +0100 Subject: [PATCH 36/60] fix board tests --- .../controller/api-test/content-element-delete.api.spec.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/server/src/modules/board/controller/api-test/content-element-delete.api.spec.ts b/apps/server/src/modules/board/controller/api-test/content-element-delete.api.spec.ts index 8f4619fa0b0..ee223a2fc58 100644 --- a/apps/server/src/modules/board/controller/api-test/content-element-delete.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/content-element-delete.api.spec.ts @@ -1,13 +1,16 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { ICurrentUser, JwtAuthGuard } from '@infra/auth-guard'; import { EntityManager } from '@mikro-orm/mongodb'; -import { FilesStorageClientAdapterService } from '@modules/files-storage-client'; +import { FilesStorageClientAdapterService } from '@modules/files-storage-client/service/files-storage-client.service'; import { ServerTestModule } from '@modules/server/server.module'; import { DrawingElementAdapterService } from '@modules/tldraw-client'; import { ExecutionContext, INestApplication } from '@nestjs/common'; import { Test, TestingModule } from '@nestjs/testing'; import { ApiValidationError } from '@shared/common'; -import { cleanupCollections, courseFactory, mapUserToCurrentUser, userFactory } from '@shared/testing'; +import { cleanupCollections } from '@shared/testing/cleanup-collections'; +import { courseFactory } from '@shared/testing/factory/course.factory'; +import { userFactory } from '@shared/testing/factory/user.factory'; +import { mapUserToCurrentUser } from '@shared/testing/map-user-to-current-user'; import { Request } from 'express'; import request from 'supertest'; import { BoardExternalReferenceType } from '../../domain'; From ea66c6f8fd1dcddde765dc33840d63f0478ad3ec Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 26 Nov 2024 17:18:21 +0100 Subject: [PATCH 37/60] fix room-member tests --- .../room-member/authorization/room-member.rule.spec.ts | 3 ++- .../src/modules/room-member/repo/room-member.repo.spec.ts | 2 +- .../room-member/service/room-member.service.spec.ts | 8 ++++---- .../modules/room-member/testing/room-member.factory.ts | 2 +- apps/server/src/modules/room/index.ts | 1 + 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/apps/server/src/modules/room-member/authorization/room-member.rule.spec.ts b/apps/server/src/modules/room-member/authorization/room-member.rule.spec.ts index 1ca26adb941..07f39836cfa 100644 --- a/apps/server/src/modules/room-member/authorization/room-member.rule.spec.ts +++ b/apps/server/src/modules/room-member/authorization/room-member.rule.spec.ts @@ -1,6 +1,7 @@ import { Test, TestingModule } from '@nestjs/testing'; import { Permission } from '@shared/domain/interface'; -import { roleDtoFactory, setupEntities, userFactory } from '@shared/testing'; +import { setupEntities } from '@shared/testing/setup-entities'; +import { roleDtoFactory, userFactory } from '@shared/testing/factory'; import { Action, AuthorizationHelper, AuthorizationInjectionService } from '@src/modules/authorization'; import { RoomMemberAuthorizable } from '../do/room-member-authorizable.do'; import { RoomMemberRule } from './room-member.rule'; diff --git a/apps/server/src/modules/room-member/repo/room-member.repo.spec.ts b/apps/server/src/modules/room-member/repo/room-member.repo.spec.ts index 3cf9364019e..8242bbcd101 100644 --- a/apps/server/src/modules/room-member/repo/room-member.repo.spec.ts +++ b/apps/server/src/modules/room-member/repo/room-member.repo.spec.ts @@ -2,7 +2,7 @@ import { MongoMemoryDatabaseModule } from '@infra/database'; import { NotFoundError } from '@mikro-orm/core'; import { EntityManager, ObjectId } from '@mikro-orm/mongodb'; import { Test, TestingModule } from '@nestjs/testing'; -import { cleanupCollections } from '@shared/testing'; +import { cleanupCollections } from '@shared/testing/cleanup-collections'; import { RoomMember } from '../do/room-member.do'; import { roomMemberEntityFactory, roomMemberFactory } from '../testing'; import { RoomMemberEntity } from './entity'; diff --git a/apps/server/src/modules/room-member/service/room-member.service.spec.ts b/apps/server/src/modules/room-member/service/room-member.service.spec.ts index 148d4b8f0bb..f94d67a68b9 100644 --- a/apps/server/src/modules/room-member/service/room-member.service.spec.ts +++ b/apps/server/src/modules/room-member/service/room-member.service.spec.ts @@ -2,11 +2,11 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { BadRequestException } from '@nestjs/common/exceptions'; import { Test, TestingModule } from '@nestjs/testing'; import { RoleName } from '@shared/domain/interface'; -import { groupFactory, roleDtoFactory, userFactory } from '@shared/testing'; +import { groupFactory, roleDtoFactory, userFactory } from '@shared/testing/factory'; import { MongoMemoryDatabaseModule } from '@src/infra/database'; -import { GroupService, GroupTypes } from '@src/modules/group'; -import { RoleService } from '@src/modules/role'; -import { roomFactory } from '@src/modules/room/testing'; +import { GroupService, GroupTypes } from '@modules/group'; +import { RoleService } from '@modules/role'; +import { roomFactory } from '@modules/room'; import { RoomMemberAuthorizable } from '../do/room-member-authorizable.do'; import { RoomMemberRepo } from '../repo/room-member.repo'; import { roomMemberFactory } from '../testing'; diff --git a/apps/server/src/modules/room-member/testing/room-member.factory.ts b/apps/server/src/modules/room-member/testing/room-member.factory.ts index 829f0f1708c..4e9c561918a 100644 --- a/apps/server/src/modules/room-member/testing/room-member.factory.ts +++ b/apps/server/src/modules/room-member/testing/room-member.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing'; +import { BaseFactory } from '@shared/testing/factory/base.factory'; import { RoomMember, RoomMemberProps } from '../do/room-member.do'; export const roomMemberFactory = BaseFactory.define(RoomMember, () => { diff --git a/apps/server/src/modules/room/index.ts b/apps/server/src/modules/room/index.ts index 7be3bdc7474..31c66bccfac 100644 --- a/apps/server/src/modules/room/index.ts +++ b/apps/server/src/modules/room/index.ts @@ -2,3 +2,4 @@ export * from './domain'; export { RoomConfig } from './room.config'; export * from './room.module'; export * from './repo/entity'; +export { roomFactory } from './testing'; From 285a465fcdfbb05d28b7df5d55f52c6b9473522b Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Wed, 27 Nov 2024 13:46:01 +0100 Subject: [PATCH 38/60] fix board-copy-service.spec --- .../service/board-copy.service.spec.ts | 124 ++++++++++++++---- 1 file changed, 99 insertions(+), 25 deletions(-) diff --git a/apps/server/src/modules/learnroom/service/board-copy.service.spec.ts b/apps/server/src/modules/learnroom/service/board-copy.service.spec.ts index 7fd621811db..0f82cd9f790 100644 --- a/apps/server/src/modules/learnroom/service/board-copy.service.spec.ts +++ b/apps/server/src/modules/learnroom/service/board-copy.service.spec.ts @@ -22,7 +22,9 @@ import { userFactory, } from '@shared/testing'; import { LegacyLogger } from '@src/core/logger'; +import { CopyColumnBoardParams } from '@src/modules/board/service/internal'; import { columnBoardFactory } from '@src/modules/board/testing'; +import { StorageLocation } from '@src/modules/files-storage/interface'; import { ColumnBoardNodeRepo } from '../repo'; import { BoardCopyService } from './board-copy.service'; @@ -101,28 +103,48 @@ describe('board copy service', () => { it('should return copy type "board"', async () => { const { destinationCourse, originalBoard, user } = setup(); - const status = await copyService.copyBoard({ originalBoard, user, destinationCourse }); + const status = await copyService.copyBoard({ + originalBoard, + user, + originalCourse: destinationCourse, + destinationCourse, + }); expect(status.type).toEqual(CopyElementType.BOARD); }); it('should set title copy status to "board"', async () => { const { destinationCourse, originalBoard, user } = setup(); - const status = await copyService.copyBoard({ originalBoard, user, destinationCourse }); + const status = await copyService.copyBoard({ + originalBoard, + user, + originalCourse: destinationCourse, + destinationCourse, + }); expect(status.title).toEqual('board'); }); it('should set original entity in status', async () => { const { destinationCourse, originalBoard, user } = setup(); - const status = await copyService.copyBoard({ originalBoard, user, destinationCourse }); + const status = await copyService.copyBoard({ + originalBoard, + user, + originalCourse: destinationCourse, + destinationCourse, + }); expect(status.originalEntity).toEqual(originalBoard); }); it('should create a copy', async () => { const { destinationCourse, originalBoard, user } = setup(); - const status = await copyService.copyBoard({ originalBoard, user, destinationCourse }); + const status = await copyService.copyBoard({ + originalBoard, + user, + originalCourse: destinationCourse, + destinationCourse, + }); const board = status.copyEntity as LegacyBoard; expect(board.id).not.toEqual(originalBoard.id); }); @@ -130,7 +152,12 @@ describe('board copy service', () => { it('should set destination course of copy', async () => { const { destinationCourse, originalBoard, user } = setup(); - const status = await copyService.copyBoard({ originalBoard, user, destinationCourse }); + const status = await copyService.copyBoard({ + originalBoard, + user, + originalCourse: destinationCourse, + destinationCourse, + }); const board = status.copyEntity as LegacyBoard; expect(board.course.id).toEqual(destinationCourse.id); }); @@ -158,7 +185,7 @@ describe('board copy service', () => { it('should call taskCopyService with original task', async () => { const { destinationCourse, originalBoard, user, originalTask } = setup(); - await copyService.copyBoard({ originalBoard, user, destinationCourse }); + await copyService.copyBoard({ originalBoard, user, originalCourse: destinationCourse, destinationCourse }); expect(taskCopyService.copyTask).toHaveBeenCalledWith({ originalTaskId: originalTask.id, destinationCourse, @@ -169,14 +196,19 @@ describe('board copy service', () => { it('should call copyHelperService', async () => { const { destinationCourse, originalBoard, user } = setup(); - await copyService.copyBoard({ originalBoard, user, destinationCourse }); + await copyService.copyBoard({ originalBoard, user, originalCourse: destinationCourse, destinationCourse }); expect(copyHelperService.deriveStatusFromElements).toHaveBeenCalledTimes(1); }); it('should add copy of task to board copy', async () => { const { destinationCourse, originalBoard, user } = setup(); - const status = await copyService.copyBoard({ originalBoard, user, destinationCourse }); + const status = await copyService.copyBoard({ + originalBoard, + user, + originalCourse: destinationCourse, + destinationCourse, + }); const board = status.copyEntity as LegacyBoard; expect(board.getElements().length).toEqual(1); }); @@ -184,7 +216,12 @@ describe('board copy service', () => { it('should add status of copying task to board copy status', async () => { const { destinationCourse, originalBoard, user, originalTask } = setup(); - const status = await copyService.copyBoard({ originalBoard, user, destinationCourse }); + const status = await copyService.copyBoard({ + originalBoard, + user, + originalCourse: destinationCourse, + destinationCourse, + }); const taskStatus = status.elements?.find( (el) => el.type === CopyElementType.TASK && el.title === originalTask.name ); @@ -221,13 +258,18 @@ describe('board copy service', () => { user, }; - await copyService.copyBoard({ originalBoard, user, destinationCourse }); + await copyService.copyBoard({ originalBoard, user, originalCourse: destinationCourse, destinationCourse }); expect(lessonCopyService.copyLesson).toHaveBeenCalledWith(expected); }); it('should add lessonCopy to board copy', async () => { const { destinationCourse, originalBoard, user } = setup(); - const status = await copyService.copyBoard({ originalBoard, user, destinationCourse }); + const status = await copyService.copyBoard({ + originalBoard, + user, + originalCourse: destinationCourse, + destinationCourse, + }); const board = status.copyEntity as LegacyBoard; expect(board.getElements().length).toEqual(1); @@ -235,7 +277,12 @@ describe('board copy service', () => { it('should add status of lessonCopy to board copy status', async () => { const { destinationCourse, originalBoard, user } = setup(); - const status = await copyService.copyBoard({ originalBoard, user, destinationCourse }); + const status = await copyService.copyBoard({ + originalBoard, + user, + originalCourse: destinationCourse, + destinationCourse, + }); const lessonStatus = status.elements?.find((el) => el.type === CopyElementType.LESSON); expect(lessonStatus).toBeDefined(); @@ -268,22 +315,29 @@ describe('board copy service', () => { it('should call columnBoardCopyService with original columnBoard', async () => { const { destinationCourse, originalBoard, user, columnBoardTarget } = setup(); - const expected = { + const expected: CopyColumnBoardParams = { originalColumnBoardId: columnBoardTarget.id, - destinationExternalReference: { + targetExternalReference: { type: BoardExternalReferenceType.Course, id: destinationCourse.id, }, + sourceStorageLocationReference: { id: destinationCourse.school.id, type: StorageLocation.SCHOOL }, + targetStorageLocationReference: { id: destinationCourse.school.id, type: StorageLocation.SCHOOL }, userId: user.id, }; - await copyService.copyBoard({ originalBoard, user, destinationCourse }); + await copyService.copyBoard({ originalBoard, user, originalCourse: destinationCourse, destinationCourse }); expect(columnBoardService.copyColumnBoard).toHaveBeenCalledWith(expected); }); it('should add columnBoard copy to board copy', async () => { const { destinationCourse, originalBoard, user } = setup(); - const status = await copyService.copyBoard({ originalBoard, user, destinationCourse }); + const status = await copyService.copyBoard({ + originalBoard, + originalCourse: destinationCourse, + user, + destinationCourse, + }); const board = status.copyEntity as LegacyBoard; expect(board.getElements().length).toEqual(1); @@ -291,7 +345,12 @@ describe('board copy service', () => { it('should add status of columnBoard copy to board copy status', async () => { const { destinationCourse, originalBoard, user } = setup(); - const status = await copyService.copyBoard({ originalBoard, user, destinationCourse }); + const status = await copyService.copyBoard({ + originalBoard, + originalCourse: destinationCourse, + user, + destinationCourse, + }); const lessonStatus = status.elements?.find((el) => el.type === CopyElementType.COLUMNBOARD); expect(lessonStatus).toBeDefined(); @@ -365,14 +424,14 @@ describe('board copy service', () => { it('should trigger swapping ids for board', async () => { const { destinationCourse, originalBoard, user, columnBoardCopy } = setup(); - await copyService.copyBoard({ originalBoard, user, destinationCourse }); + await copyService.copyBoard({ originalBoard, user, originalCourse: destinationCourse, destinationCourse }); expect(columnBoardService.swapLinkedIds).toHaveBeenCalledWith(columnBoardCopy.id, expect.anything()); }); it('should pass task for swapping ids', async () => { const { destinationCourse, originalBoard, user, originalTask, taskCopy } = setup(); - await copyService.copyBoard({ originalBoard, user, destinationCourse }); + await copyService.copyBoard({ originalBoard, user, originalCourse: destinationCourse, destinationCourse }); const map = columnBoardService.swapLinkedIds.mock.calls[0][1]; expect(map.get(originalTask.id)).toEqual(taskCopy.id); @@ -380,7 +439,7 @@ describe('board copy service', () => { it('should pass lesson for swapping ids', async () => { const { destinationCourse, originalBoard, user, originalLesson, lessonCopy } = setup(); - await copyService.copyBoard({ originalBoard, user, destinationCourse }); + await copyService.copyBoard({ originalBoard, user, originalCourse: destinationCourse, destinationCourse }); const map = columnBoardService.swapLinkedIds.mock.calls[0][1]; expect(map.get(originalLesson.id)).toEqual(lessonCopy.id); @@ -388,7 +447,7 @@ describe('board copy service', () => { it('should pass course for swapping ids', async () => { const { originalCourse, destinationCourse, originalBoard, user } = setup(); - await copyService.copyBoard({ originalBoard, user, destinationCourse }); + await copyService.copyBoard({ originalBoard, user, originalCourse: destinationCourse, destinationCourse }); const map = columnBoardService.swapLinkedIds.mock.calls[0][1]; expect(map.get(originalCourse.id)).toEqual(destinationCourse.id); @@ -417,7 +476,7 @@ describe('board copy service', () => { it('should call deriveStatusFromElements', async () => { const { destinationCourse, originalBoard, user } = setup(); - await copyService.copyBoard({ originalBoard, user, destinationCourse }); + await copyService.copyBoard({ originalBoard, user, originalCourse: destinationCourse, destinationCourse }); expect(copyHelperService.deriveStatusFromElements).toHaveBeenCalled(); }); @@ -425,7 +484,12 @@ describe('board copy service', () => { it('should use returned value from deriveStatusFromElements', async () => { const { destinationCourse, originalBoard, user } = setup(); copyHelperService.deriveStatusFromElements.mockReturnValue(CopyStatusEnum.PARTIAL); - const status = await copyService.copyBoard({ originalBoard, user, destinationCourse }); + const status = await copyService.copyBoard({ + originalBoard, + user, + originalCourse: destinationCourse, + destinationCourse, + }); expect(status.status).toEqual(CopyStatusEnum.PARTIAL); }); @@ -458,7 +522,12 @@ describe('board copy service', () => { it('should skip boardelements that contain a corrupted reference', async () => { const { destinationCourse, originalBoard, user } = setup(); - const status = await copyService.copyBoard({ originalBoard, user, destinationCourse }); + const status = await copyService.copyBoard({ + originalBoard, + user, + originalCourse: destinationCourse, + destinationCourse, + }); const board = status.copyEntity as LegacyBoard; expect(board.references).toHaveLength(0); @@ -489,7 +558,12 @@ describe('board copy service', () => { it('should return status fail', async () => { const { destinationCourse, originalBoard, user } = setup(); - const status = await copyService.copyBoard({ originalBoard, user, destinationCourse }); + const status = await copyService.copyBoard({ + originalBoard, + user, + originalCourse: destinationCourse, + destinationCourse, + }); expect(status.status).toEqual(CopyStatusEnum.FAIL); }); From aec3e576e9841edd5a98086c7952c0fc2ecbc284 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Wed, 27 Nov 2024 13:46:33 +0100 Subject: [PATCH 39/60] fix dependency cycle --- .../board/service/internal/board-node-copy.service.ts | 3 +-- apps/server/src/modules/copy-helper/dto/copy.response.ts | 2 +- .../server/src/modules/copy-helper/mapper/copy.mapper.ts | 9 +++++---- .../files-storage-client/files-storage-client.module.ts | 2 +- .../files-storage-client/service/copy-files.service.ts | 3 ++- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/server/src/modules/board/service/internal/board-node-copy.service.ts b/apps/server/src/modules/board/service/internal/board-node-copy.service.ts index 3309d31b760..3870411bac9 100644 --- a/apps/server/src/modules/board/service/internal/board-node-copy.service.ts +++ b/apps/server/src/modules/board/service/internal/board-node-copy.service.ts @@ -1,6 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { CopyHelperService } from '@modules/copy-helper/service/copy-helper.service'; -import { CopyElementType, CopyStatus, CopyStatusEnum } from '@modules/copy-helper/types/copy.types'; +import { CopyElementType, CopyHelperService, CopyStatus, CopyStatusEnum } from '@modules/copy-helper'; import { CopyFileDto } from '@modules/files-storage-client/dto'; import { ContextExternalToolService } from '@modules/tool/context-external-tool'; import { ContextExternalTool } from '@modules/tool/context-external-tool/domain'; diff --git a/apps/server/src/modules/copy-helper/dto/copy.response.ts b/apps/server/src/modules/copy-helper/dto/copy.response.ts index 3f4cd8cebac..f255432eb1e 100644 --- a/apps/server/src/modules/copy-helper/dto/copy.response.ts +++ b/apps/server/src/modules/copy-helper/dto/copy.response.ts @@ -1,5 +1,5 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; -import { CopyElementType, CopyStatusEnum } from '@modules/copy-helper/types/copy.types'; +import { CopyElementType, CopyStatusEnum } from '../types/copy.types'; /** * DTO for returning a copy status document via api. diff --git a/apps/server/src/modules/copy-helper/mapper/copy.mapper.ts b/apps/server/src/modules/copy-helper/mapper/copy.mapper.ts index 94d0c7d75d9..aa5e8d44af0 100644 --- a/apps/server/src/modules/copy-helper/mapper/copy.mapper.ts +++ b/apps/server/src/modules/copy-helper/mapper/copy.mapper.ts @@ -1,10 +1,11 @@ import { LessonCopyApiParams } from '@modules/learnroom/controller/dto/lesson/lesson-copy.params'; -import { LessonCopyParentParams } from '@modules/lesson/types'; +import { LessonCopyParentParams } from '@modules/lesson/types/lesson-copy-parent.params'; import { TaskCopyApiParams } from '@modules/task/controller/dto/task-copy.params'; -import { TaskCopyParentParams } from '@modules/task/types'; -import { LessonEntity, Task } from '@shared/domain/entity'; +import { TaskCopyParentParams } from '@modules/task/types/task-copy-parent.params'; +import { LessonEntity } from '@shared/domain/entity/lesson.entity'; +import { Task } from '@shared/domain/entity/task.entity'; import { EntityId } from '@shared/domain/types'; -import { ColumnBoard } from '@src/modules/board'; +import { ColumnBoard } from '@modules/board/domain/colum-board.do'; import { CopyApiResponse } from '../dto/copy.response'; import { CopyStatus, CopyStatusEnum } from '../types/copy.types'; diff --git a/apps/server/src/modules/files-storage-client/files-storage-client.module.ts b/apps/server/src/modules/files-storage-client/files-storage-client.module.ts index 0c6095fc206..185654114c7 100644 --- a/apps/server/src/modules/files-storage-client/files-storage-client.module.ts +++ b/apps/server/src/modules/files-storage-client/files-storage-client.module.ts @@ -1,7 +1,7 @@ import { Module } from '@nestjs/common'; import { LoggerModule } from '@src/core/logger'; // The files-storage-client should not know the copy-helper -import { CopyHelperModule } from '@modules/copy-helper'; +import { CopyHelperModule } from '@modules/copy-helper/copy-helper.module'; import { CqrsModule } from '@nestjs/cqrs'; import { CopyFilesService, FilesStorageClientAdapterService, FilesStorageProducer } from './service'; diff --git a/apps/server/src/modules/files-storage-client/service/copy-files.service.ts b/apps/server/src/modules/files-storage-client/service/copy-files.service.ts index 2ca2466f1a5..8003065f094 100644 --- a/apps/server/src/modules/files-storage-client/service/copy-files.service.ts +++ b/apps/server/src/modules/files-storage-client/service/copy-files.service.ts @@ -1,4 +1,5 @@ -import { CopyElementType, CopyHelperService, CopyStatus, CopyStatusEnum } from '@modules/copy-helper'; +import { CopyHelperService } from '@modules/copy-helper/service/copy-helper.service'; +import { CopyElementType, CopyStatus, CopyStatusEnum } from '@modules/copy-helper/types/copy.types'; import { StorageLocation } from '@modules/files-storage/interface'; import { Injectable } from '@nestjs/common'; import { EntityId } from '@shared/domain/types'; From fc6fdd9134cfecf82a716d6fcbb839cd5f8858f9 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Wed, 27 Nov 2024 13:56:14 +0100 Subject: [PATCH 40/60] reset sharing test changes --- .../controller/api-test/sharing-import-token.api.spec.ts | 3 +-- .../src/modules/sharing/entity/share-token.entity.spec.ts | 2 +- .../modules/sharing/repo/share-token.repo.integration.spec.ts | 3 +-- .../src/modules/sharing/service/share-token.service.spec.ts | 3 +-- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/apps/server/src/modules/sharing/controller/api-test/sharing-import-token.api.spec.ts b/apps/server/src/modules/sharing/controller/api-test/sharing-import-token.api.spec.ts index 782c1b52ff8..9386b965857 100644 --- a/apps/server/src/modules/sharing/controller/api-test/sharing-import-token.api.spec.ts +++ b/apps/server/src/modules/sharing/controller/api-test/sharing-import-token.api.spec.ts @@ -1,8 +1,7 @@ import { Configuration } from '@hpi-schul-cloud/commons/lib'; import { ICurrentUser, JwtAuthGuard } from '@infra/auth-guard'; import { EntityManager } from '@mikro-orm/mongodb'; -import { CopyApiResponse } from '@modules/copy-helper/dto/copy.response'; -import { CopyElementType, CopyStatusEnum } from '@modules/copy-helper/types/copy.types'; +import { CopyApiResponse, CopyElementType, CopyStatusEnum } from '@modules/copy-helper'; import { ServerTestModule } from '@modules/server'; import { ExecutionContext, HttpStatus, INestApplication } from '@nestjs/common'; import { Test, TestingModule } from '@nestjs/testing'; diff --git a/apps/server/src/modules/sharing/entity/share-token.entity.spec.ts b/apps/server/src/modules/sharing/entity/share-token.entity.spec.ts index 1ef018ea0fd..6d822ba8c8e 100644 --- a/apps/server/src/modules/sharing/entity/share-token.entity.spec.ts +++ b/apps/server/src/modules/sharing/entity/share-token.entity.spec.ts @@ -1,4 +1,4 @@ -import { setupEntities } from '@shared/testing/setup-entities'; +import { setupEntities } from '@shared/testing'; import { ObjectId } from '@mikro-orm/mongodb'; import { ShareTokenContextType, ShareTokenParentType } from '../domainobject/share-token.do'; import { ShareToken } from './share-token.entity'; diff --git a/apps/server/src/modules/sharing/repo/share-token.repo.integration.spec.ts b/apps/server/src/modules/sharing/repo/share-token.repo.integration.spec.ts index fe550324f89..dc0f03f1d49 100644 --- a/apps/server/src/modules/sharing/repo/share-token.repo.integration.spec.ts +++ b/apps/server/src/modules/sharing/repo/share-token.repo.integration.spec.ts @@ -2,8 +2,7 @@ import { createMock } from '@golevelup/ts-jest'; import { MongoMemoryDatabaseModule } from '@infra/database'; import { EntityManager } from '@mikro-orm/mongodb'; import { Test, TestingModule } from '@nestjs/testing'; -import { cleanupCollections } from '@shared/testing/cleanup-collections'; -import { schoolEntityFactory, shareTokenFactory } from '@shared/testing/factory'; +import { cleanupCollections, schoolEntityFactory, shareTokenFactory } from '@shared/testing'; import { LegacyLogger } from '@src/core/logger'; import { ShareTokenContextType } from '../domainobject/share-token.do'; import { ShareTokenRepo } from './share-token.repo'; diff --git a/apps/server/src/modules/sharing/service/share-token.service.spec.ts b/apps/server/src/modules/sharing/service/share-token.service.spec.ts index 1d7ae179284..1f721e7a00b 100644 --- a/apps/server/src/modules/sharing/service/share-token.service.spec.ts +++ b/apps/server/src/modules/sharing/service/share-token.service.spec.ts @@ -1,8 +1,7 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { NotFoundException } from '@nestjs/common'; import { Test, TestingModule } from '@nestjs/testing'; -import { setupEntities } from '@shared/testing/setup-entities'; -import { courseFactory, lessonFactory, shareTokenFactory, taskFactory } from '@shared/testing/factory'; +import { courseFactory, lessonFactory, setupEntities, shareTokenFactory, taskFactory } from '@shared/testing'; import { columnBoardFactory } from '@modules/board/testing'; import { CourseService } from '@modules/learnroom/service'; import { ColumnBoardService } from '@modules/board/service'; From a8507c33f6359143c98cb3ccfbd8a654f405412f Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Wed, 27 Nov 2024 14:18:27 +0100 Subject: [PATCH 41/60] reset room test changes --- apps/server/src/modules/room/api/room.uc.spec.ts | 3 +-- .../room/api/test/room-add-members.api.spec.ts | 12 +++++++----- .../modules/room/api/test/room-create.api.spec.ts | 11 ++++------- .../modules/room/api/test/room-delete.api.spec.ts | 12 +++++++----- .../room/api/test/room-get-boards.api.spec.ts | 12 +++++++----- .../src/modules/room/api/test/room-get.api.spec.ts | 14 ++++++++------ .../modules/room/api/test/room-index.api.spec.ts | 12 +++++++----- .../modules/room/api/test/room-members.api.spec.ts | 14 ++++++++------ .../room/api/test/room-remove-members.api.spec.ts | 12 +++++++----- .../modules/room/api/test/room-update.api.spec.ts | 14 ++++++++------ .../src/modules/room/domain/do/room.do.spec.ts | 2 +- .../server/src/modules/room/repo/room.repo.spec.ts | 2 +- .../src/modules/room/testing/room.factory.ts | 2 +- 13 files changed, 67 insertions(+), 55 deletions(-) diff --git a/apps/server/src/modules/room/api/room.uc.spec.ts b/apps/server/src/modules/room/api/room.uc.spec.ts index 0ee8c381d5e..ab0e958ae6c 100644 --- a/apps/server/src/modules/room/api/room.uc.spec.ts +++ b/apps/server/src/modules/room/api/room.uc.spec.ts @@ -7,8 +7,7 @@ import { Test, TestingModule } from '@nestjs/testing'; import { FeatureDisabledLoggableException } from '@shared/common/loggable-exception'; import { Page } from '@shared/domain/domainobject'; import { IFindOptions } from '@shared/domain/interface'; -import { setupEntities } from '@shared/testing/setup-entities'; -import { userFactory } from '@shared/testing/factory'; +import { setupEntities, userFactory } from '@shared/testing'; import { ColumnBoardService } from '@src/modules/board'; import { Room, RoomService } from '../domain'; import { RoomColor } from '../domain/type'; diff --git a/apps/server/src/modules/room/api/test/room-add-members.api.spec.ts b/apps/server/src/modules/room/api/test/room-add-members.api.spec.ts index 9a414dddc5e..7ba93b377e0 100644 --- a/apps/server/src/modules/room/api/test/room-add-members.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-add-members.api.spec.ts @@ -3,11 +3,13 @@ import { HttpStatus, INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { Permission } from '@shared/domain/interface/permission.enum'; import { RoleName } from '@shared/domain/interface/rolename.enum'; -import { cleanupCollections } from '@shared/testing/cleanup-collections'; -import { groupEntityFactory } from '@shared/testing/factory/group-entity.factory'; -import { roleFactory } from '@shared/testing/factory/role.factory'; -import { UserAndAccountTestFactory } from '@shared/testing/factory/user-and-account.test.factory'; -import { TestApiClient } from '@shared/testing/test-api-client'; +import { + TestApiClient, + UserAndAccountTestFactory, + cleanupCollections, + groupEntityFactory, + roleFactory, +} from '@shared/testing'; import { GroupEntityTypes } from '@src/modules/group/entity/group.entity'; import { roomMemberEntityFactory } from '@src/modules/room-member/testing/room-member-entity.factory'; import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; diff --git a/apps/server/src/modules/room/api/test/room-create.api.spec.ts b/apps/server/src/modules/room/api/test/room-create.api.spec.ts index c9b315fca97..48c93c5b4c6 100644 --- a/apps/server/src/modules/room/api/test/room-create.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-create.api.spec.ts @@ -1,14 +1,11 @@ import { EntityManager } from '@mikro-orm/mongodb'; import { HttpStatus, INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; -import { Permission, RoleName } from '@shared/domain/interface'; -import { cleanupCollections } from '@shared/testing/cleanup-collections'; -import { roleFactory } from '@shared/testing/factory/role.factory'; -import { UserAndAccountTestFactory } from '@shared/testing/factory/user-and-account.test.factory'; -import { TestApiClient } from '@shared/testing/test-api-client'; -import { GroupEntity } from '@src/modules/group/entity'; -import { RoomMemberEntity } from '@src/modules/room-member'; +import { TestApiClient, UserAndAccountTestFactory, cleanupCollections, roleFactory } from '@shared/testing'; import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; +import { RoomMemberEntity } from '@src/modules/room-member'; +import { GroupEntity } from '@src/modules/group/entity'; +import { Permission, RoleName } from '@shared/domain/interface'; import { RoomEntity } from '../../repo'; describe('Room Controller (API)', () => { diff --git a/apps/server/src/modules/room/api/test/room-delete.api.spec.ts b/apps/server/src/modules/room/api/test/room-delete.api.spec.ts index 4afca6d37e2..cd290922e6c 100644 --- a/apps/server/src/modules/room/api/test/room-delete.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-delete.api.spec.ts @@ -2,11 +2,13 @@ import { EntityManager, ObjectId } from '@mikro-orm/mongodb'; import { HttpStatus, INestApplication, NotFoundException } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { Permission, RoleName } from '@shared/domain/interface'; -import { cleanupCollections } from '@shared/testing/cleanup-collections'; -import { groupEntityFactory } from '@shared/testing/factory/group-entity.factory'; -import { roleFactory } from '@shared/testing/factory/role.factory'; -import { UserAndAccountTestFactory } from '@shared/testing/factory/user-and-account.test.factory'; -import { TestApiClient } from '@shared/testing/test-api-client'; +import { + TestApiClient, + UserAndAccountTestFactory, + cleanupCollections, + groupEntityFactory, + roleFactory, +} from '@shared/testing'; import { GroupEntityTypes } from '@src/modules/group/entity/group.entity'; import { roomMemberEntityFactory } from '@src/modules/room-member/testing/room-member-entity.factory'; import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; diff --git a/apps/server/src/modules/room/api/test/room-get-boards.api.spec.ts b/apps/server/src/modules/room/api/test/room-get-boards.api.spec.ts index 0cd9750c467..ff14ce174e9 100644 --- a/apps/server/src/modules/room/api/test/room-get-boards.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-get-boards.api.spec.ts @@ -2,11 +2,13 @@ import { EntityManager, ObjectId } from '@mikro-orm/mongodb'; import { HttpStatus, INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { Permission, RoleName } from '@shared/domain/interface'; -import { cleanupCollections } from '@shared/testing/cleanup-collections'; -import { groupEntityFactory } from '@shared/testing/factory/group-entity.factory'; -import { roleFactory } from '@shared/testing/factory/role.factory'; -import { UserAndAccountTestFactory } from '@shared/testing/factory/user-and-account.test.factory'; -import { TestApiClient } from '@shared/testing/test-api-client'; +import { + cleanupCollections, + groupEntityFactory, + roleFactory, + TestApiClient, + UserAndAccountTestFactory, +} from '@shared/testing'; import { BoardExternalReferenceType } from '@src/modules/board'; import { columnBoardEntityFactory } from '@src/modules/board/testing'; import { GroupEntityTypes } from '@src/modules/group/entity'; diff --git a/apps/server/src/modules/room/api/test/room-get.api.spec.ts b/apps/server/src/modules/room/api/test/room-get.api.spec.ts index 3b7da2cc71f..54961eb25eb 100644 --- a/apps/server/src/modules/room/api/test/room-get.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-get.api.spec.ts @@ -2,13 +2,15 @@ import { EntityManager, ObjectId } from '@mikro-orm/mongodb'; import { HttpStatus, INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { Permission, RoleName } from '@shared/domain/interface'; -import { cleanupCollections } from '@shared/testing/cleanup-collections'; -import { groupEntityFactory } from '@shared/testing/factory/group-entity.factory'; -import { roleFactory } from '@shared/testing/factory/role.factory'; -import { UserAndAccountTestFactory } from '@shared/testing/factory/user-and-account.test.factory'; -import { TestApiClient } from '@shared/testing/test-api-client'; +import { + TestApiClient, + UserAndAccountTestFactory, + cleanupCollections, + groupEntityFactory, + roleFactory, +} from '@shared/testing'; import { GroupEntityTypes } from '@src/modules/group/entity/group.entity'; -import { roomMemberEntityFactory } from '@src/modules/room-member/testing/room-member-entity.factory'; +import { roomMemberEntityFactory } from '@src/modules/room-member/testing'; import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; import { roomEntityFactory } from '../../testing/room-entity.factory'; diff --git a/apps/server/src/modules/room/api/test/room-index.api.spec.ts b/apps/server/src/modules/room/api/test/room-index.api.spec.ts index 06b4a394d6c..26b0cd141ad 100644 --- a/apps/server/src/modules/room/api/test/room-index.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-index.api.spec.ts @@ -3,11 +3,13 @@ import { HttpStatus, INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { Permission } from '@shared/domain/interface/permission.enum'; import { RoleName } from '@shared/domain/interface/rolename.enum'; -import { cleanupCollections } from '@shared/testing/cleanup-collections'; -import { groupEntityFactory } from '@shared/testing/factory/group-entity.factory'; -import { roleFactory } from '@shared/testing/factory/role.factory'; -import { UserAndAccountTestFactory } from '@shared/testing/factory/user-and-account.test.factory'; -import { TestApiClient } from '@shared/testing/test-api-client'; +import { + TestApiClient, + UserAndAccountTestFactory, + cleanupCollections, + groupEntityFactory, + roleFactory, +} from '@shared/testing'; import { GroupEntityTypes } from '@src/modules/group/entity/group.entity'; import { roomMemberEntityFactory } from '@src/modules/room-member/testing/room-member-entity.factory'; import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; diff --git a/apps/server/src/modules/room/api/test/room-members.api.spec.ts b/apps/server/src/modules/room/api/test/room-members.api.spec.ts index 7d2bd40fbfd..80334fbaa08 100644 --- a/apps/server/src/modules/room/api/test/room-members.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-members.api.spec.ts @@ -3,12 +3,14 @@ import { HttpStatus, INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { Permission } from '@shared/domain/interface/permission.enum'; import { RoleName } from '@shared/domain/interface/rolename.enum'; -import { TestApiClient } from '@shared/testing/test-api-client'; -import { cleanupCollections } from '@shared/testing/cleanup-collections'; -import { UserAndAccountTestFactory } from '@shared/testing/factory/user-and-account.test.factory'; -import { groupEntityFactory } from '@shared/testing/factory/group-entity.factory'; -import { roleFactory } from '@shared/testing/factory/role.factory'; -import { userFactory } from '@shared/testing/factory/user.factory'; +import { + TestApiClient, + UserAndAccountTestFactory, + cleanupCollections, + groupEntityFactory, + roleFactory, + userFactory, +} from '@shared/testing'; import { GroupEntityTypes } from '@src/modules/group/entity/group.entity'; import { roomMemberEntityFactory } from '@src/modules/room-member/testing/room-member-entity.factory'; import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; diff --git a/apps/server/src/modules/room/api/test/room-remove-members.api.spec.ts b/apps/server/src/modules/room/api/test/room-remove-members.api.spec.ts index 977ab77638e..6829f3f5cd9 100644 --- a/apps/server/src/modules/room/api/test/room-remove-members.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-remove-members.api.spec.ts @@ -3,11 +3,13 @@ import { HttpStatus, INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { Permission } from '@shared/domain/interface/permission.enum'; import { RoleName } from '@shared/domain/interface/rolename.enum'; -import { cleanupCollections } from '@shared/testing/cleanup-collections'; -import { groupEntityFactory } from '@shared/testing/factory/group-entity.factory'; -import { roleFactory } from '@shared/testing/factory/role.factory'; -import { UserAndAccountTestFactory } from '@shared/testing/factory/user-and-account.test.factory'; -import { TestApiClient } from '@shared/testing/test-api-client'; +import { + TestApiClient, + UserAndAccountTestFactory, + cleanupCollections, + groupEntityFactory, + roleFactory, +} from '@shared/testing'; import { GroupEntityTypes } from '@src/modules/group/entity/group.entity'; import { roomMemberEntityFactory } from '@src/modules/room-member/testing/room-member-entity.factory'; import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; diff --git a/apps/server/src/modules/room/api/test/room-update.api.spec.ts b/apps/server/src/modules/room/api/test/room-update.api.spec.ts index 164765a8b3f..08ed5847d21 100644 --- a/apps/server/src/modules/room/api/test/room-update.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-update.api.spec.ts @@ -2,12 +2,14 @@ import { EntityManager, ObjectId } from '@mikro-orm/mongodb'; import { HttpStatus, INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { Permission, RoleName } from '@shared/domain/interface'; -import { TestApiClient } from '@shared/testing/test-api-client'; -import { cleanupCollections } from '@shared/testing/cleanup-collections'; -import { UserAndAccountTestFactory } from '@shared/testing/factory/user-and-account.test.factory'; -import { groupEntityFactory } from '@shared/testing/factory/group-entity.factory'; -import { roleFactory } from '@shared/testing/factory/role.factory'; -import { roomMemberEntityFactory } from '@src/modules/room-member/testing/room-member-entity.factory'; +import { + TestApiClient, + UserAndAccountTestFactory, + cleanupCollections, + groupEntityFactory, + roleFactory, +} from '@shared/testing'; +import { roomMemberEntityFactory } from '@src/modules/room-member/testing'; import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; import { RoomEntity } from '../../repo'; import { roomEntityFactory } from '../../testing'; diff --git a/apps/server/src/modules/room/domain/do/room.do.spec.ts b/apps/server/src/modules/room/domain/do/room.do.spec.ts index 8ff3d847d42..d19c279405e 100644 --- a/apps/server/src/modules/room/domain/do/room.do.spec.ts +++ b/apps/server/src/modules/room/domain/do/room.do.spec.ts @@ -1,7 +1,7 @@ import { ObjectId } from '@mikro-orm/mongodb'; import { ValidationError } from '@shared/common'; import { EntityId } from '@shared/domain/types'; -import { roomFactory } from '../../testing/room.factory'; +import { roomFactory } from '../../testing'; import { RoomColor } from '../type'; import { Room, RoomProps } from './room.do'; diff --git a/apps/server/src/modules/room/repo/room.repo.spec.ts b/apps/server/src/modules/room/repo/room.repo.spec.ts index 69f461d872e..d89fd630b4e 100644 --- a/apps/server/src/modules/room/repo/room.repo.spec.ts +++ b/apps/server/src/modules/room/repo/room.repo.spec.ts @@ -3,7 +3,7 @@ import { NotFoundError } from '@mikro-orm/core'; import { EntityManager } from '@mikro-orm/mongodb'; import { Test, TestingModule } from '@nestjs/testing'; import { Page } from '@shared/domain/domainobject'; -import { cleanupCollections } from '@shared/testing/cleanup-collections'; +import { cleanupCollections } from '@shared/testing'; import { Room } from '../domain/do/room.do'; import { roomEntityFactory, roomFactory } from '../testing'; import { RoomEntity } from './entity'; diff --git a/apps/server/src/modules/room/testing/room.factory.ts b/apps/server/src/modules/room/testing/room.factory.ts index d1821d62de5..7f1ef879488 100644 --- a/apps/server/src/modules/room/testing/room.factory.ts +++ b/apps/server/src/modules/room/testing/room.factory.ts @@ -1,4 +1,4 @@ -import { BaseFactory } from '@shared/testing/factory/base.factory'; +import { BaseFactory } from '@shared/testing'; import { ObjectId } from '@mikro-orm/mongodb'; import { Room, RoomProps } from '../domain/do/room.do'; import { RoomColor } from '../domain/type'; From 62d7bc2aaaf027d62394ae8e303bf53b1481071d Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Wed, 27 Nov 2024 18:14:49 +0100 Subject: [PATCH 42/60] reset room-member test changes --- .../room-member/authorization/room-member.rule.spec.ts | 3 +-- .../src/modules/room-member/repo/room-member.repo.spec.ts | 2 +- .../modules/room-member/service/room-member.service.spec.ts | 6 +++--- .../src/modules/room-member/testing/room-member.factory.ts | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/server/src/modules/room-member/authorization/room-member.rule.spec.ts b/apps/server/src/modules/room-member/authorization/room-member.rule.spec.ts index 07f39836cfa..1ca26adb941 100644 --- a/apps/server/src/modules/room-member/authorization/room-member.rule.spec.ts +++ b/apps/server/src/modules/room-member/authorization/room-member.rule.spec.ts @@ -1,7 +1,6 @@ import { Test, TestingModule } from '@nestjs/testing'; import { Permission } from '@shared/domain/interface'; -import { setupEntities } from '@shared/testing/setup-entities'; -import { roleDtoFactory, userFactory } from '@shared/testing/factory'; +import { roleDtoFactory, setupEntities, userFactory } from '@shared/testing'; import { Action, AuthorizationHelper, AuthorizationInjectionService } from '@src/modules/authorization'; import { RoomMemberAuthorizable } from '../do/room-member-authorizable.do'; import { RoomMemberRule } from './room-member.rule'; diff --git a/apps/server/src/modules/room-member/repo/room-member.repo.spec.ts b/apps/server/src/modules/room-member/repo/room-member.repo.spec.ts index 8242bbcd101..3cf9364019e 100644 --- a/apps/server/src/modules/room-member/repo/room-member.repo.spec.ts +++ b/apps/server/src/modules/room-member/repo/room-member.repo.spec.ts @@ -2,7 +2,7 @@ import { MongoMemoryDatabaseModule } from '@infra/database'; import { NotFoundError } from '@mikro-orm/core'; import { EntityManager, ObjectId } from '@mikro-orm/mongodb'; import { Test, TestingModule } from '@nestjs/testing'; -import { cleanupCollections } from '@shared/testing/cleanup-collections'; +import { cleanupCollections } from '@shared/testing'; import { RoomMember } from '../do/room-member.do'; import { roomMemberEntityFactory, roomMemberFactory } from '../testing'; import { RoomMemberEntity } from './entity'; diff --git a/apps/server/src/modules/room-member/service/room-member.service.spec.ts b/apps/server/src/modules/room-member/service/room-member.service.spec.ts index f94d67a68b9..c61c9108fee 100644 --- a/apps/server/src/modules/room-member/service/room-member.service.spec.ts +++ b/apps/server/src/modules/room-member/service/room-member.service.spec.ts @@ -2,11 +2,11 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { BadRequestException } from '@nestjs/common/exceptions'; import { Test, TestingModule } from '@nestjs/testing'; import { RoleName } from '@shared/domain/interface'; -import { groupFactory, roleDtoFactory, userFactory } from '@shared/testing/factory'; +import { groupFactory, roleDtoFactory, userFactory } from '@shared/testing'; import { MongoMemoryDatabaseModule } from '@src/infra/database'; -import { GroupService, GroupTypes } from '@modules/group'; +import { GroupService, GroupTypes } from '@src/modules/group'; import { RoleService } from '@modules/role'; -import { roomFactory } from '@modules/room'; +import { roomFactory } from '@modules/room/testing'; import { RoomMemberAuthorizable } from '../do/room-member-authorizable.do'; import { RoomMemberRepo } from '../repo/room-member.repo'; import { roomMemberFactory } from '../testing'; diff --git a/apps/server/src/modules/room-member/testing/room-member.factory.ts b/apps/server/src/modules/room-member/testing/room-member.factory.ts index 4e9c561918a..829f0f1708c 100644 --- a/apps/server/src/modules/room-member/testing/room-member.factory.ts +++ b/apps/server/src/modules/room-member/testing/room-member.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing/factory/base.factory'; +import { BaseFactory } from '@shared/testing'; import { RoomMember, RoomMemberProps } from '../do/room-member.do'; export const roomMemberFactory = BaseFactory.define(RoomMember, () => { From df9704dca08240af63101eb5ab610163c85d40ed Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Wed, 27 Nov 2024 18:39:26 +0100 Subject: [PATCH 43/60] reset board test changes --- .../api-test/board-copy-in-course.api.spec.ts | 10 +++------- .../api-test/content-element-delete.api.spec.ts | 8 ++------ .../api-test/board-collaboration.gateway.spec.ts | 11 +++++------ .../board/metrics/metrics.service.spec.ts | 2 +- .../modules/board/repo/board-node.repo.spec.ts | 2 +- .../service/board-common-tool.service.spec.ts | 2 +- .../board-node-authorizable.service.spec.ts | 2 +- .../board-node-permission.service.spec.ts | 3 +-- .../board/service/board-node.service.spec.ts | 2 +- ...al-tool-deleted-event-handler.service.spec.ts | 3 +-- .../user-deleted-event-handler.service.spec.ts | 7 +++---- .../internal/board-context.service.spec.ts | 11 +++++------ .../board-node-copy-specific.service.spec.ts | 5 ++--- .../board-node-delete-hooks.service.spec.ts | 12 ++++++------ .../internal/column-board-copy.service.spec.ts | 16 ++++++++-------- .../internal/column-board-link.service.spec.ts | 5 ++--- .../internal/column-board-title.service.ts | 2 +- .../testing/board-node-authorizable.factory.ts | 2 +- .../src/modules/board/testing/card.factory.ts | 2 +- .../testing/collaborative-text-editor.factory.ts | 2 +- .../board/testing/column-board.factory.ts | 2 +- .../src/modules/board/testing/column.factory.ts | 2 +- .../board/testing/deleted-element.factory.ts | 2 +- .../board/testing/drawing-element.factory.ts | 2 +- .../testing/external-tool-element.factory.ts | 2 +- .../board/testing/file-element.factory.ts | 2 +- .../board/testing/link-element.factory.ts | 2 +- .../media-available-line-element.factory.ts | 2 +- .../testing/media-available-line.factory.ts | 2 +- .../modules/board/testing/media-board.factory.ts | 2 +- .../media-external-tool-element.factory.ts | 2 +- .../modules/board/testing/media-line.factory.ts | 2 +- .../submission-container-element.factory.ts | 2 +- .../board/testing/submission-item.factory.ts | 2 +- .../server/src/modules/board/uc/board.uc.spec.ts | 8 ++++---- apps/server/src/modules/board/uc/card.uc.spec.ts | 3 +-- .../src/modules/board/uc/column.uc.spec.ts | 3 +-- .../media-board/media-available-line.uc.spec.ts | 11 +++++------ .../board/uc/media-board/media-board.uc.spec.ts | 3 +-- .../board/uc/media-board/media-line.uc.spec.ts | 3 +-- .../modules/board/uc/submission-item.uc.spec.ts | 3 +-- 41 files changed, 75 insertions(+), 96 deletions(-) diff --git a/apps/server/src/modules/board/controller/api-test/board-copy-in-course.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-copy-in-course.api.spec.ts index e7407e7e453..c196444e28a 100644 --- a/apps/server/src/modules/board/controller/api-test/board-copy-in-course.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-copy-in-course.api.spec.ts @@ -1,16 +1,12 @@ import { EntityManager } from '@mikro-orm/mongodb'; -import { CopyApiResponse } from '@modules/copy-helper/dto/copy.response'; -import { CopyElementType, CopyStatusEnum } from '@modules/copy-helper/types/copy.types'; import { ServerTestModule } from '@modules/server/server.module'; import { INestApplication } from '@nestjs/common'; import { Test, TestingModule } from '@nestjs/testing'; -import { cleanupCollections } from '@shared/testing/cleanup-collections'; -import { courseFactory } from '@shared/testing/factory/course.factory'; -import { UserAndAccountTestFactory } from '@shared/testing/factory/user-and-account.test.factory'; -import { TestApiClient } from '@shared/testing/test-api-client'; -import { BoardExternalReferenceType } from '../../domain'; +import { TestApiClient, UserAndAccountTestFactory, cleanupCollections, courseFactory } from '@shared/testing'; +import { CopyApiResponse, CopyElementType, CopyStatusEnum } from '@modules/copy-helper'; import { BoardNodeEntity } from '../../repo'; import { columnBoardEntityFactory } from '../../testing'; +import { BoardExternalReferenceType } from '../../domain'; const baseRouteName = '/boards'; diff --git a/apps/server/src/modules/board/controller/api-test/content-element-delete.api.spec.ts b/apps/server/src/modules/board/controller/api-test/content-element-delete.api.spec.ts index ee223a2fc58..94f52c94eee 100644 --- a/apps/server/src/modules/board/controller/api-test/content-element-delete.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/content-element-delete.api.spec.ts @@ -1,16 +1,13 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { ICurrentUser, JwtAuthGuard } from '@infra/auth-guard'; import { EntityManager } from '@mikro-orm/mongodb'; -import { FilesStorageClientAdapterService } from '@modules/files-storage-client/service/files-storage-client.service'; +import { FilesStorageClientAdapterService } from '@modules/files-storage-client'; import { ServerTestModule } from '@modules/server/server.module'; import { DrawingElementAdapterService } from '@modules/tldraw-client'; import { ExecutionContext, INestApplication } from '@nestjs/common'; import { Test, TestingModule } from '@nestjs/testing'; import { ApiValidationError } from '@shared/common'; -import { cleanupCollections } from '@shared/testing/cleanup-collections'; -import { courseFactory } from '@shared/testing/factory/course.factory'; -import { userFactory } from '@shared/testing/factory/user.factory'; -import { mapUserToCurrentUser } from '@shared/testing/map-user-to-current-user'; +import { cleanupCollections, courseFactory, mapUserToCurrentUser, userFactory } from '@shared/testing'; import { Request } from 'express'; import request from 'supertest'; import { BoardExternalReferenceType } from '../../domain'; @@ -22,7 +19,6 @@ import { drawingElementEntityFactory, richTextElementEntityFactory, } from '../../testing'; - const baseRouteName = '/elements'; class API { diff --git a/apps/server/src/modules/board/gateway/api-test/board-collaboration.gateway.spec.ts b/apps/server/src/modules/board/gateway/api-test/board-collaboration.gateway.spec.ts index ab8f66184b8..1d35a9d10c8 100644 --- a/apps/server/src/modules/board/gateway/api-test/board-collaboration.gateway.spec.ts +++ b/apps/server/src/modules/board/gateway/api-test/board-collaboration.gateway.spec.ts @@ -1,21 +1,20 @@ -import { MongoIoAdapter } from '@infra/socketio'; import { EntityManager } from '@mikro-orm/mongodb'; import { INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; + +import { MongoIoAdapter } from '@infra/socketio'; import { InputFormat } from '@shared/domain/types'; -import { cleanupCollections } from '@shared/testing/cleanup-collections'; -import { courseFactory } from '@shared/testing/factory/course.factory'; -import { userFactory } from '@shared/testing/factory/user.factory'; +import { cleanupCollections, courseFactory, userFactory } from '@shared/testing'; import { getSocketApiClient, waitForEvent } from '@shared/testing/test-socket-api-client'; import { Socket } from 'socket.io-client'; -import { BoardCollaborationTestingModule } from '../../board-collaboration.testing.module'; -import { BoardExternalReferenceType, CardProps, ContentElementType } from '../../domain'; import { cardEntityFactory, columnBoardEntityFactory, columnEntityFactory, richTextElementEntityFactory, } from '../../testing'; +import { BoardExternalReferenceType, CardProps, ContentElementType } from '../../domain'; +import { BoardCollaborationTestingModule } from '../../board-collaboration.testing.module'; import { BoardCollaborationGateway } from '../board-collaboration.gateway'; describe(BoardCollaborationGateway.name, () => { diff --git a/apps/server/src/modules/board/metrics/metrics.service.spec.ts b/apps/server/src/modules/board/metrics/metrics.service.spec.ts index 48e01153526..9da48af0baa 100644 --- a/apps/server/src/modules/board/metrics/metrics.service.spec.ts +++ b/apps/server/src/modules/board/metrics/metrics.service.spec.ts @@ -2,7 +2,7 @@ import { DeepMocked, createMock } from '@golevelup/ts-jest'; import { Test, TestingModule } from '@nestjs/testing'; import { UserService } from '@src/modules/user'; import { RoleName } from '@shared/domain/interface'; -import { roleFactory, userDoFactory } from '@shared/testing/factory'; +import { roleFactory, userDoFactory } from '@shared/testing'; import { MetricsService } from './metrics.service'; describe(MetricsService.name, () => { diff --git a/apps/server/src/modules/board/repo/board-node.repo.spec.ts b/apps/server/src/modules/board/repo/board-node.repo.spec.ts index 2be0cbb5324..3a6cf173d23 100644 --- a/apps/server/src/modules/board/repo/board-node.repo.spec.ts +++ b/apps/server/src/modules/board/repo/board-node.repo.spec.ts @@ -1,7 +1,7 @@ import { EntityManager } from '@mikro-orm/mongodb'; import { Test, TestingModule } from '@nestjs/testing'; import { BaseEntityWithTimestamps } from '@shared/domain/entity'; -import { cleanupCollections } from '@shared/testing/cleanup-collections'; +import { cleanupCollections } from '@shared/testing'; import { MongoMemoryDatabaseModule } from '@src/infra/database'; import { ColumnBoard } from '../domain'; import { cardFactory, columnBoardFactory, columnFactory } from '../testing'; diff --git a/apps/server/src/modules/board/service/board-common-tool.service.spec.ts b/apps/server/src/modules/board/service/board-common-tool.service.spec.ts index 165d1afc2f3..5895d3eb0b9 100644 --- a/apps/server/src/modules/board/service/board-common-tool.service.spec.ts +++ b/apps/server/src/modules/board/service/board-common-tool.service.spec.ts @@ -1,7 +1,7 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Test, TestingModule } from '@nestjs/testing'; import { NotFoundException } from '@nestjs/common'; -import { contextExternalToolFactory } from '@modules/tool/context-external-tool/testing/context-external-tool.factory'; +import { contextExternalToolFactory } from '@modules/tool/context-external-tool/testing'; import { BoardCommonToolService } from './board-common-tool.service'; import { BoardNodeRepo } from '../repo'; import { BoardNodeService } from './board-node.service'; diff --git a/apps/server/src/modules/board/service/board-node-authorizable.service.spec.ts b/apps/server/src/modules/board/service/board-node-authorizable.service.spec.ts index b92520c1d58..10d768d1c73 100644 --- a/apps/server/src/modules/board/service/board-node-authorizable.service.spec.ts +++ b/apps/server/src/modules/board/service/board-node-authorizable.service.spec.ts @@ -1,6 +1,6 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Test, TestingModule } from '@nestjs/testing'; -import { setupEntities } from '@shared/testing/setup-entities'; +import { setupEntities } from '@shared/testing'; import { AuthorizableReferenceType, AuthorizationInjectionService } from '@modules/authorization'; import { columnBoardFactory, columnFactory } from '../testing'; import { BoardNodeAuthorizable, BoardRoles, UserWithBoardRoles } from '../domain'; diff --git a/apps/server/src/modules/board/service/board-node-permission.service.spec.ts b/apps/server/src/modules/board/service/board-node-permission.service.spec.ts index e837bc568e8..3d636d1561c 100644 --- a/apps/server/src/modules/board/service/board-node-permission.service.spec.ts +++ b/apps/server/src/modules/board/service/board-node-permission.service.spec.ts @@ -1,8 +1,7 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Action, AuthorizationContext, AuthorizationService } from '@modules/authorization'; import { Test, TestingModule } from '@nestjs/testing'; -import { setupEntities } from '@shared/testing/setup-entities'; -import { userFactory } from '@shared/testing/factory'; +import { setupEntities, userFactory } from '@shared/testing'; import { BoardNodeAuthorizable, BoardRoles, UserWithBoardRoles } from '../domain'; import { BoardNodeAuthorizableService } from './board-node-authorizable.service'; import { BoardNodePermissionService } from './board-node-permission.service'; diff --git a/apps/server/src/modules/board/service/board-node.service.spec.ts b/apps/server/src/modules/board/service/board-node.service.spec.ts index 9da714b7309..77449a10034 100644 --- a/apps/server/src/modules/board/service/board-node.service.spec.ts +++ b/apps/server/src/modules/board/service/board-node.service.spec.ts @@ -2,7 +2,7 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { ObjectId } from '@mikro-orm/mongodb'; import { NotFoundException } from '@nestjs/common'; import { Test, TestingModule } from '@nestjs/testing'; -import { setupEntities } from '@shared/testing/setup-entities'; +import { setupEntities } from '@shared/testing'; import { Card, ColumnBoard } from '../domain'; import { BoardNodeRepo } from '../repo'; import { diff --git a/apps/server/src/modules/board/service/event/context-external-tool-deleted-event-handler.service.spec.ts b/apps/server/src/modules/board/service/event/context-external-tool-deleted-event-handler.service.spec.ts index 71e1dedc449..9e32bb622cb 100644 --- a/apps/server/src/modules/board/service/event/context-external-tool-deleted-event-handler.service.spec.ts +++ b/apps/server/src/modules/board/service/event/context-external-tool-deleted-event-handler.service.spec.ts @@ -4,9 +4,8 @@ import { Test, TestingModule } from '@nestjs/testing'; import { ContextExternalToolDeletedEvent } from '../../../tool/context-external-tool/domain'; import { ContentElementType, DeletedElement, ROOT_PATH } from '../../domain'; import { externalToolElementFactory } from '../../testing'; -import { ContextExternalToolDeletedEventHandlerService } from './context-external-tool-deleted-event-handler.service'; -// Warning: do not move the BoardNodeService import up. Otherwise the import will lead to dependency cycles. import { BoardNodeService } from '../board-node.service'; +import { ContextExternalToolDeletedEventHandlerService } from './context-external-tool-deleted-event-handler.service'; describe(ContextExternalToolDeletedEventHandlerService.name, () => { let module: TestingModule; diff --git a/apps/server/src/modules/board/service/event/user-deleted-event-handler.service.spec.ts b/apps/server/src/modules/board/service/event/user-deleted-event-handler.service.spec.ts index 6876920dabb..d8482bcad0e 100644 --- a/apps/server/src/modules/board/service/event/user-deleted-event-handler.service.spec.ts +++ b/apps/server/src/modules/board/service/event/user-deleted-event-handler.service.spec.ts @@ -11,13 +11,12 @@ import { } from '@modules/deletion'; import { EventBus } from '@nestjs/cqrs'; import { Test, TestingModule } from '@nestjs/testing'; -import { setupEntities } from '@shared/testing/setup-entities'; +import { setupEntities } from '@shared/testing'; import { Logger } from '@src/core/logger'; import { mediaBoardFactory } from '../../testing'; -import { UserDeletedEventHandlerService } from './user-deleted-event-handler.service'; import { BoardNodeService } from '../board-node.service'; -// Warning: do not move the MediaBoardService import up. Otherwise the import will lead to dependency cycles. -import { MediaBoardService } from '../media-board/media-board.service'; +import { MediaBoardService } from '../media-board'; +import { UserDeletedEventHandlerService } from './user-deleted-event-handler.service'; describe(UserDeletedEventHandlerService.name, () => { let module: TestingModule; diff --git a/apps/server/src/modules/board/service/internal/board-context.service.spec.ts b/apps/server/src/modules/board/service/internal/board-context.service.spec.ts index b2cd5165b1d..b1a3be99840 100644 --- a/apps/server/src/modules/board/service/internal/board-context.service.spec.ts +++ b/apps/server/src/modules/board/service/internal/board-context.service.spec.ts @@ -1,16 +1,15 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { ObjectId } from '@mikro-orm/mongodb'; import { Test, TestingModule } from '@nestjs/testing'; -import { Permission, RoleName } from '@shared/domain/interface'; import { CourseRepo } from '@shared/repo'; -import { courseFactory, groupFactory, roleFactory, userFactory } from '@shared/testing/factory'; -import { setupEntities } from '@shared/testing/setup-entities'; -import { GroupTypes } from '@src/modules/group'; +import { courseFactory, groupFactory, roleFactory, setupEntities, userFactory } from '@shared/testing'; import { RoomMemberService } from '@src/modules/room-member'; -import { roomMemberFactory } from '@src/modules/room-member/testing'; import { roomFactory } from '@src/modules/room/testing'; +import { Permission, RoleName } from '@shared/domain/interface'; +import { GroupTypes } from '@src/modules/group'; +import { roomMemberFactory } from '@src/modules/room-member/testing'; +import { columnFactory, columnBoardFactory } from '../../testing'; import { BoardExternalReferenceType, BoardRoles, UserWithBoardRoles } from '../../domain'; -import { columnBoardFactory, columnFactory } from '../../testing'; import { BoardContextService } from './board-context.service'; describe(`${BoardContextService.name}`, () => { diff --git a/apps/server/src/modules/board/service/internal/board-node-copy-specific.service.spec.ts b/apps/server/src/modules/board/service/internal/board-node-copy-specific.service.spec.ts index 7926eb15cdb..5bfebf5d43c 100644 --- a/apps/server/src/modules/board/service/internal/board-node-copy-specific.service.spec.ts +++ b/apps/server/src/modules/board/service/internal/board-node-copy-specific.service.spec.ts @@ -1,13 +1,12 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { ObjectId } from '@mikro-orm/mongodb'; -import { CopyHelperService } from '@modules/copy-helper/service/copy-helper.service'; -import { CopyElementType, CopyStatus, CopyStatusEnum } from '@modules/copy-helper/types/copy.types'; +import { CopyElementType, CopyHelperService, CopyStatus, CopyStatusEnum } from '@modules/copy-helper'; import { StorageLocation } from '@modules/files-storage/interface'; import { ContextExternalToolService } from '@modules/tool/context-external-tool/service'; import { ToolConfig } from '@modules/tool/tool-config'; import { ConfigService } from '@nestjs/config'; import { Test, TestingModule } from '@nestjs/testing'; -import { setupEntities } from '@shared/testing/setup-entities'; +import { setupEntities } from '@shared/testing'; import { FilesStorageClientAdapterService } from '@src/modules/files-storage-client'; import { CopyFileDto } from '@src/modules/files-storage-client/dto'; import { contextExternalToolFactory } from '@src/modules/tool/context-external-tool/testing'; diff --git a/apps/server/src/modules/board/service/internal/board-node-delete-hooks.service.spec.ts b/apps/server/src/modules/board/service/internal/board-node-delete-hooks.service.spec.ts index 8a20814fae8..7134dad1ad0 100644 --- a/apps/server/src/modules/board/service/internal/board-node-delete-hooks.service.spec.ts +++ b/apps/server/src/modules/board/service/internal/board-node-delete-hooks.service.spec.ts @@ -1,11 +1,11 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Test, TestingModule } from '@nestjs/testing'; -import { setupEntities } from '@shared/testing/setup-entities'; -import { CollaborativeTextEditorService } from '@modules/collaborative-text-editor/service/collaborative-text-editor.service'; -import { FilesStorageClientAdapterService } from '@modules/files-storage-client/service/files-storage-client.service'; -import { DrawingElementAdapterService } from '@modules/tldraw-client/service/drawing-element-adapter.service'; -import { ContextExternalToolService } from '@modules/tool/context-external-tool/service/context-external-tool.service'; -import { contextExternalToolFactory } from '@modules/tool/context-external-tool/testing/context-external-tool.factory'; +import { setupEntities } from '@shared/testing'; +import { CollaborativeTextEditorService } from '@src/modules/collaborative-text-editor'; +import { FilesStorageClientAdapterService } from '@src/modules/files-storage-client'; +import { DrawingElementAdapterService } from '@src/modules/tldraw-client'; +import { ContextExternalToolService } from '@src/modules/tool/context-external-tool'; +import { contextExternalToolFactory } from '@src/modules/tool/context-external-tool/testing'; import { collaborativeTextEditorFactory, drawingElementFactory, diff --git a/apps/server/src/modules/board/service/internal/column-board-copy.service.spec.ts b/apps/server/src/modules/board/service/internal/column-board-copy.service.spec.ts index bcf4d270493..e78022f73ef 100644 --- a/apps/server/src/modules/board/service/internal/column-board-copy.service.spec.ts +++ b/apps/server/src/modules/board/service/internal/column-board-copy.service.spec.ts @@ -1,17 +1,17 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { ObjectId } from '@mikro-orm/mongodb'; +import { CopyElementType, CopyStatus, CopyStatusEnum } from '@modules/copy-helper'; +import { FilesStorageClientAdapterService } from '@modules/files-storage-client/service'; +import { StorageLocation } from '@modules/files-storage/interface'; import { Test, TestingModule } from '@nestjs/testing'; -import { courseFactory } from '@shared/testing/factory'; -import { setupEntities } from '@shared/testing/setup-entities'; -import { CopyElementType, CopyStatus, CopyStatusEnum } from '@src/modules/copy-helper'; -import { FilesStorageClientAdapterService } from '@src/modules/files-storage-client/service/files-storage-client.service'; -import { StorageLocation } from '@src/modules/files-storage/interface'; -import { BoardExternalReferenceType } from '../../domain'; -import { columnBoardFactory } from '../../testing'; +import { courseFactory, setupEntities } from '@shared/testing'; +import { BoardExternalReferenceType } from '../../domain/types'; +import { columnBoardFactory } from '../../testing/column-board.factory'; import { BoardNodeService } from '../board-node.service'; -import { BoardNodeCopyService } from './board-node-copy.service'; import { ColumnBoardCopyService, CopyColumnBoardParams } from './column-board-copy.service'; import { ColumnBoardTitleService } from './column-board-title.service'; +// Warning: do not move the BoardNodeCopyService import up. Otherwise it will lead to dependency cycle. +import { BoardNodeCopyService } from './board-node-copy.service'; describe(ColumnBoardCopyService.name, () => { let module: TestingModule; diff --git a/apps/server/src/modules/board/service/internal/column-board-link.service.spec.ts b/apps/server/src/modules/board/service/internal/column-board-link.service.spec.ts index db75dc884d9..aca7d8ea204 100644 --- a/apps/server/src/modules/board/service/internal/column-board-link.service.spec.ts +++ b/apps/server/src/modules/board/service/internal/column-board-link.service.spec.ts @@ -2,7 +2,7 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { ObjectId } from '@mikro-orm/mongodb'; import { Test, TestingModule } from '@nestjs/testing'; import { EntityId } from '@shared/domain/types'; -import { setupEntities } from '@shared/testing/setup-entities'; +import { setupEntities } from '@shared/testing'; import { ColumnBoard, LinkElement } from '../../domain'; import { BoardNodeRepo } from '../../repo'; import { @@ -12,9 +12,8 @@ import { linkElementFactory, richTextElementFactory, } from '../../testing'; -import { ColumnBoardLinkService } from './column-board-link.service'; -// Warning: do not move the BoardNodeService import up. Otherwise the import will lead to dependency cycles. import { BoardNodeService } from '../board-node.service'; +import { ColumnBoardLinkService } from './column-board-link.service'; describe(ColumnBoardLinkService.name, () => { let module: TestingModule; diff --git a/apps/server/src/modules/board/service/internal/column-board-title.service.ts b/apps/server/src/modules/board/service/internal/column-board-title.service.ts index e43cbda1afe..07f6c1b6faa 100644 --- a/apps/server/src/modules/board/service/internal/column-board-title.service.ts +++ b/apps/server/src/modules/board/service/internal/column-board-title.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@nestjs/common'; -import { CopyHelperService } from '@modules/copy-helper'; +import { CopyHelperService } from '@modules/copy-helper/service/copy-helper.service'; import { BoardExternalReference } from '../../domain'; import { ColumnBoardReferenceService } from './column-board-reference.service'; diff --git a/apps/server/src/modules/board/testing/board-node-authorizable.factory.ts b/apps/server/src/modules/board/testing/board-node-authorizable.factory.ts index c3ea7c19b7c..e34d399b5c7 100644 --- a/apps/server/src/modules/board/testing/board-node-authorizable.factory.ts +++ b/apps/server/src/modules/board/testing/board-node-authorizable.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { DomainObjectFactory } from '@shared/testing/factory/domainobject/domain-object.factory'; +import { DomainObjectFactory } from '@shared/testing'; import { BoardNodeAuthorizable, BoardNodeAuthorizableProps } from '../domain'; import { columnBoardFactory } from './column-board.factory'; import { columnFactory } from './column.factory'; diff --git a/apps/server/src/modules/board/testing/card.factory.ts b/apps/server/src/modules/board/testing/card.factory.ts index 5a7497fb66f..71999aef7e8 100644 --- a/apps/server/src/modules/board/testing/card.factory.ts +++ b/apps/server/src/modules/board/testing/card.factory.ts @@ -1,6 +1,6 @@ /* istanbul ignore file */ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing/factory/base.factory'; +import { BaseFactory } from '@shared/testing'; import { Card, CardProps, ROOT_PATH } from '../domain'; export const cardFactory = BaseFactory.define(Card, ({ sequence }) => { diff --git a/apps/server/src/modules/board/testing/collaborative-text-editor.factory.ts b/apps/server/src/modules/board/testing/collaborative-text-editor.factory.ts index d9a7c473fcf..1bc197060a3 100644 --- a/apps/server/src/modules/board/testing/collaborative-text-editor.factory.ts +++ b/apps/server/src/modules/board/testing/collaborative-text-editor.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing/factory/base.factory'; +import { BaseFactory } from '@shared/testing'; import { CollaborativeTextEditorElement, CollaborativeTextEditorElementProps, ROOT_PATH } from '../domain'; export const collaborativeTextEditorFactory = BaseFactory.define< diff --git a/apps/server/src/modules/board/testing/column-board.factory.ts b/apps/server/src/modules/board/testing/column-board.factory.ts index dff17ffde1c..48c925dcaf6 100644 --- a/apps/server/src/modules/board/testing/column-board.factory.ts +++ b/apps/server/src/modules/board/testing/column-board.factory.ts @@ -1,6 +1,6 @@ /* istanbul ignore file */ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing/factory/base.factory'; +import { BaseFactory } from '@shared/testing'; import { BoardExternalReferenceType, BoardLayout, ColumnBoard, ColumnBoardProps, ROOT_PATH } from '../domain'; class ColumnBoardFactory extends BaseFactory { diff --git a/apps/server/src/modules/board/testing/column.factory.ts b/apps/server/src/modules/board/testing/column.factory.ts index 802a025fe7c..9de33a2765a 100644 --- a/apps/server/src/modules/board/testing/column.factory.ts +++ b/apps/server/src/modules/board/testing/column.factory.ts @@ -1,6 +1,6 @@ /* istanbul ignore file */ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing/factory/base.factory'; +import { BaseFactory } from '@shared/testing'; import { Column, ColumnProps, ROOT_PATH } from '../domain'; export const columnFactory = BaseFactory.define(Column, ({ sequence }) => { diff --git a/apps/server/src/modules/board/testing/deleted-element.factory.ts b/apps/server/src/modules/board/testing/deleted-element.factory.ts index 4e66a375e2b..23a682bd3c8 100644 --- a/apps/server/src/modules/board/testing/deleted-element.factory.ts +++ b/apps/server/src/modules/board/testing/deleted-element.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing/factory/base.factory'; +import { BaseFactory } from '@shared/testing'; import { ContentElementType, DeletedElement, DeletedElementProps, ROOT_PATH } from '../domain'; export const deletedElementFactory = BaseFactory.define( diff --git a/apps/server/src/modules/board/testing/drawing-element.factory.ts b/apps/server/src/modules/board/testing/drawing-element.factory.ts index 21a8b1875c7..678a23384bc 100644 --- a/apps/server/src/modules/board/testing/drawing-element.factory.ts +++ b/apps/server/src/modules/board/testing/drawing-element.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing/factory/base.factory'; +import { BaseFactory } from '@shared/testing'; import { DrawingElement, DrawingElementProps, ROOT_PATH } from '../domain'; export const drawingElementFactory = BaseFactory.define( diff --git a/apps/server/src/modules/board/testing/external-tool-element.factory.ts b/apps/server/src/modules/board/testing/external-tool-element.factory.ts index aabef73fe8e..06e6ec4f5ea 100644 --- a/apps/server/src/modules/board/testing/external-tool-element.factory.ts +++ b/apps/server/src/modules/board/testing/external-tool-element.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing/factory/base.factory'; +import { BaseFactory } from '@shared/testing'; import { ExternalToolElement, ExternalToolElementProps, ROOT_PATH } from '../domain'; export const externalToolElementFactory = BaseFactory.define( diff --git a/apps/server/src/modules/board/testing/file-element.factory.ts b/apps/server/src/modules/board/testing/file-element.factory.ts index 8a20b1583ef..5599de53251 100644 --- a/apps/server/src/modules/board/testing/file-element.factory.ts +++ b/apps/server/src/modules/board/testing/file-element.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing/factory/base.factory'; +import { BaseFactory } from '@shared/testing'; import { FileElement, FileElementProps, ROOT_PATH } from '../domain'; export const fileElementFactory = BaseFactory.define(FileElement, ({ sequence }) => { diff --git a/apps/server/src/modules/board/testing/link-element.factory.ts b/apps/server/src/modules/board/testing/link-element.factory.ts index acb879703d6..257d1f23f72 100644 --- a/apps/server/src/modules/board/testing/link-element.factory.ts +++ b/apps/server/src/modules/board/testing/link-element.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing/factory/base.factory'; +import { BaseFactory } from '@shared/testing'; import { LinkElement, LinkElementProps, ROOT_PATH } from '../domain'; export const linkElementFactory = BaseFactory.define(LinkElement, ({ sequence }) => { diff --git a/apps/server/src/modules/board/testing/media-available-line-element.factory.ts b/apps/server/src/modules/board/testing/media-available-line-element.factory.ts index c6b9fe706fc..d1615fc2239 100644 --- a/apps/server/src/modules/board/testing/media-available-line-element.factory.ts +++ b/apps/server/src/modules/board/testing/media-available-line-element.factory.ts @@ -1,5 +1,5 @@ +import { BaseFactory } from '@shared/testing'; import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing/factory/base.factory'; import { MediaAvailableLineElement, MediaAvailableLineElementProps } from '../domain'; export const mediaAvailableLineElementFactory = BaseFactory.define< diff --git a/apps/server/src/modules/board/testing/media-available-line.factory.ts b/apps/server/src/modules/board/testing/media-available-line.factory.ts index 31d71be64a2..ba9ee9e716b 100644 --- a/apps/server/src/modules/board/testing/media-available-line.factory.ts +++ b/apps/server/src/modules/board/testing/media-available-line.factory.ts @@ -1,5 +1,5 @@ import { DeepPartial } from 'fishery'; -import { BaseFactory } from '@shared/testing/factory/base.factory'; +import { BaseFactory } from '@shared/testing'; import { MediaBoardColors, MediaAvailableLine, MediaAvailableLineElement, MediaAvailableLineProps } from '../domain'; class MediaAvailableLineFactory extends BaseFactory { diff --git a/apps/server/src/modules/board/testing/media-board.factory.ts b/apps/server/src/modules/board/testing/media-board.factory.ts index a62609a899f..3bbd8a705a0 100644 --- a/apps/server/src/modules/board/testing/media-board.factory.ts +++ b/apps/server/src/modules/board/testing/media-board.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing/factory/base.factory'; +import { BaseFactory } from '@shared/testing'; import { BoardExternalReferenceType, BoardLayout, diff --git a/apps/server/src/modules/board/testing/media-external-tool-element.factory.ts b/apps/server/src/modules/board/testing/media-external-tool-element.factory.ts index 26d8bef7fed..cb1dbf4c2fc 100644 --- a/apps/server/src/modules/board/testing/media-external-tool-element.factory.ts +++ b/apps/server/src/modules/board/testing/media-external-tool-element.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing/factory/base.factory'; +import { BaseFactory } from '@shared/testing'; import { MediaExternalToolElement, MediaExternalToolElementProps, ROOT_PATH } from '../domain'; export const mediaExternalToolElementFactory = BaseFactory.define< diff --git a/apps/server/src/modules/board/testing/media-line.factory.ts b/apps/server/src/modules/board/testing/media-line.factory.ts index 2b6f0af5999..2f2c7bf3395 100644 --- a/apps/server/src/modules/board/testing/media-line.factory.ts +++ b/apps/server/src/modules/board/testing/media-line.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing/factory/base.factory'; +import { BaseFactory } from '@shared/testing'; import { MediaLine, MediaLineProps, ROOT_PATH } from '../domain'; import { MediaBoardColors } from '../domain/media-board/types'; diff --git a/apps/server/src/modules/board/testing/submission-container-element.factory.ts b/apps/server/src/modules/board/testing/submission-container-element.factory.ts index f8911326bb6..42d67af9176 100644 --- a/apps/server/src/modules/board/testing/submission-container-element.factory.ts +++ b/apps/server/src/modules/board/testing/submission-container-element.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing/factory/base.factory'; +import { BaseFactory } from '@shared/testing'; import { ROOT_PATH, SubmissionContainerElement, SubmissionContainerElementProps } from '../domain'; export const submissionContainerElementFactory = BaseFactory.define< diff --git a/apps/server/src/modules/board/testing/submission-item.factory.ts b/apps/server/src/modules/board/testing/submission-item.factory.ts index 4f9066ec880..cc01e1cb114 100644 --- a/apps/server/src/modules/board/testing/submission-item.factory.ts +++ b/apps/server/src/modules/board/testing/submission-item.factory.ts @@ -1,5 +1,5 @@ import { ObjectId } from '@mikro-orm/mongodb'; -import { BaseFactory } from '@shared/testing/factory/base.factory'; +import { BaseFactory } from '@shared/testing'; import { ROOT_PATH, SubmissionItem, SubmissionItemProps } from '../domain'; export const submissionItemFactory = BaseFactory.define(SubmissionItem, () => { diff --git a/apps/server/src/modules/board/uc/board.uc.spec.ts b/apps/server/src/modules/board/uc/board.uc.spec.ts index a44fa1aedd5..cd7c0c28827 100644 --- a/apps/server/src/modules/board/uc/board.uc.spec.ts +++ b/apps/server/src/modules/board/uc/board.uc.spec.ts @@ -4,11 +4,11 @@ import { Action, AuthorizationService } from '@modules/authorization'; import { Test, TestingModule } from '@nestjs/testing'; import { Permission } from '@shared/domain/interface'; import { CourseRepo } from '@shared/repo'; -import { courseFactory, userFactory } from '@shared/testing/factory'; -import { setupEntities } from '@shared/testing/setup-entities'; +import { setupEntities, userFactory } from '@shared/testing'; +import { courseFactory } from '@shared/testing/factory'; import { LegacyLogger } from '@src/core/logger'; -import { RoomService } from '@modules/room'; -import { RoomMemberService } from '@modules/room-member'; +import { RoomService } from '@src/modules/room'; +import { RoomMemberService } from '@src/modules/room-member'; import { CopyElementType, CopyStatus, CopyStatusEnum } from '../../copy-helper'; import { BoardExternalReferenceType, BoardLayout, BoardNodeFactory, Column, ColumnBoard } from '../domain'; import { BoardNodePermissionService, BoardNodeService, ColumnBoardService } from '../service'; diff --git a/apps/server/src/modules/board/uc/card.uc.spec.ts b/apps/server/src/modules/board/uc/card.uc.spec.ts index 29eb4bedd4f..be5bba4afa8 100644 --- a/apps/server/src/modules/board/uc/card.uc.spec.ts +++ b/apps/server/src/modules/board/uc/card.uc.spec.ts @@ -1,8 +1,7 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Action, AuthorizationService } from '@modules/authorization'; import { Test, TestingModule } from '@nestjs/testing'; -import { setupEntities } from '@shared/testing/setup-entities'; -import { userFactory } from '@shared/testing/factory'; +import { setupEntities, userFactory } from '@shared/testing'; import { LegacyLogger } from '@src/core/logger'; import { BoardNodeAuthorizable, BoardNodeFactory, Card, ContentElementType } from '../domain'; import { BoardNodeAuthorizableService, BoardNodePermissionService, BoardNodeService } from '../service'; diff --git a/apps/server/src/modules/board/uc/column.uc.spec.ts b/apps/server/src/modules/board/uc/column.uc.spec.ts index 47f6f4b52f0..3c80734550e 100644 --- a/apps/server/src/modules/board/uc/column.uc.spec.ts +++ b/apps/server/src/modules/board/uc/column.uc.spec.ts @@ -1,8 +1,7 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Action } from '@modules/authorization'; import { Test, TestingModule } from '@nestjs/testing'; -import { setupEntities } from '@shared/testing/setup-entities'; -import { userFactory } from '@shared/testing/factory'; +import { setupEntities, userFactory } from '@shared/testing'; import { LegacyLogger } from '@src/core/logger'; import { BoardNodeFactory, Card, Column, ContentElementType } from '../domain'; import { BoardNodeService } from '../service'; diff --git a/apps/server/src/modules/board/uc/media-board/media-available-line.uc.spec.ts b/apps/server/src/modules/board/uc/media-board/media-available-line.uc.spec.ts index 445a25e44db..534e5b133c0 100644 --- a/apps/server/src/modules/board/uc/media-board/media-available-line.uc.spec.ts +++ b/apps/server/src/modules/board/uc/media-board/media-available-line.uc.spec.ts @@ -1,17 +1,16 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { ObjectId } from '@mikro-orm/mongodb'; import { Action, AuthorizationService } from '@modules/authorization'; -import { ExternalTool } from '@modules/tool/external-tool/domain/external-tool.do'; -import { SchoolExternalTool } from '@modules/tool/school-external-tool/domain/school-external-tool.do'; -import { schoolExternalToolFactory } from '@modules/tool/school-external-tool/testing/school-external-tool.factory'; +import { ExternalTool } from '@modules/tool/external-tool/domain'; +import { SchoolExternalTool } from '@modules/tool/school-external-tool/domain'; +import { schoolExternalToolFactory } from '@modules/tool/school-external-tool/testing'; import { MediaUserLicense, mediaUserLicenseFactory, MediaUserLicenseService } from '@modules/user-license'; import { ConfigService } from '@nestjs/config'; import { Test, TestingModule } from '@nestjs/testing'; import { FeatureDisabledLoggableException } from '@shared/common/loggable-exception'; import { User } from '@shared/domain/entity'; -import { setupEntities } from '@shared/testing/setup-entities'; -import { userFactory as userEntityFactory, userFactory } from '@shared/testing/factory'; -import { externalToolFactory } from '@modules/tool/external-tool/testing/external-tool.factory'; +import { setupEntities, userFactory as userEntityFactory, userFactory } from '@shared/testing'; +import { externalToolFactory } from '@modules/tool/external-tool/testing'; import { MediaAvailableLine, MediaAvailableLineElement, diff --git a/apps/server/src/modules/board/uc/media-board/media-board.uc.spec.ts b/apps/server/src/modules/board/uc/media-board/media-board.uc.spec.ts index c083570dfc8..8d1b231cb98 100644 --- a/apps/server/src/modules/board/uc/media-board/media-board.uc.spec.ts +++ b/apps/server/src/modules/board/uc/media-board/media-board.uc.spec.ts @@ -3,8 +3,7 @@ import { Action, AuthorizationContextBuilder, AuthorizationService } from '@modu import { ConfigService } from '@nestjs/config'; import { Test, TestingModule } from '@nestjs/testing'; import { FeatureDisabledLoggableException } from '@shared/common/loggable-exception'; -import { setupEntities } from '@shared/testing/setup-entities'; -import { userFactory as userEntityFactory } from '@shared/testing/factory'; +import { setupEntities, userFactory as userEntityFactory } from '@shared/testing'; import type { MediaBoardConfig } from '../../media-board.config'; import { BoardNodePermissionService, BoardNodeService, MediaBoardService } from '../../service'; import { mediaBoardFactory, mediaLineFactory } from '../../testing'; diff --git a/apps/server/src/modules/board/uc/media-board/media-line.uc.spec.ts b/apps/server/src/modules/board/uc/media-board/media-line.uc.spec.ts index 31e49679c0a..96732a1e4dd 100644 --- a/apps/server/src/modules/board/uc/media-board/media-line.uc.spec.ts +++ b/apps/server/src/modules/board/uc/media-board/media-line.uc.spec.ts @@ -3,8 +3,7 @@ import { Action } from '@modules/authorization'; import { ConfigService } from '@nestjs/config'; import { Test, TestingModule } from '@nestjs/testing'; import { FeatureDisabledLoggableException } from '@shared/common/loggable-exception'; -import { setupEntities } from '@shared/testing/setup-entities'; -import { userFactory as userEntityFactory } from '@shared/testing/factory'; +import { setupEntities, userFactory as userEntityFactory } from '@shared/testing'; import type { MediaBoardConfig } from '../../media-board.config'; import { BoardNodePermissionService, BoardNodeService, MediaBoardService } from '../../service'; import { mediaBoardFactory, mediaLineFactory } from '../../testing'; diff --git a/apps/server/src/modules/board/uc/submission-item.uc.spec.ts b/apps/server/src/modules/board/uc/submission-item.uc.spec.ts index d8cc588fd9c..a516784b6fe 100644 --- a/apps/server/src/modules/board/uc/submission-item.uc.spec.ts +++ b/apps/server/src/modules/board/uc/submission-item.uc.spec.ts @@ -2,8 +2,7 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Action } from '@modules/authorization'; import { BadRequestException, ForbiddenException } from '@nestjs/common'; import { Test, TestingModule } from '@nestjs/testing'; -import { setupEntities } from '@shared/testing/setup-entities'; -import { userFactory } from '@shared/testing/factory'; +import { setupEntities, userFactory } from '@shared/testing'; import { BoardNodeAuthorizable, BoardNodeFactory, From 689656844be6dd108bb45f622519093c3689cf5b Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Wed, 27 Nov 2024 19:54:30 +0100 Subject: [PATCH 44/60] implement draft status on board copy --- .../api-test/board-copy-in-course.api.spec.ts | 21 +++++++++++++++++++ .../internal/column-board-copy.service.ts | 1 + 2 files changed, 22 insertions(+) diff --git a/apps/server/src/modules/board/controller/api-test/board-copy-in-course.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-copy-in-course.api.spec.ts index c196444e28a..5d1b966ee01 100644 --- a/apps/server/src/modules/board/controller/api-test/board-copy-in-course.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-copy-in-course.api.spec.ts @@ -82,6 +82,27 @@ describe(`board copy with course relation (api)`, () => { expect(result).toBeDefined(); }); + it('should set draft status on the board copy', async () => { + const { loggedInClient, columnBoardNode } = await setup(); + + const response = await loggedInClient.post(`${columnBoardNode.id}/copy`); + const body = response.body as CopyApiResponse; + + const expectedBody: CopyApiResponse = { + id: expect.any(String), + type: CopyElementType.COLUMNBOARD, + status: CopyStatusEnum.SUCCESS, + destinationId: columnBoardNode.context?.id, + }; + + expect(body).toEqual(expectedBody); + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const result = await em.findOneOrFail(BoardNodeEntity, body.id!); + + expect(result.isVisible).toBe(false); + }); + describe('with invalid id', () => { it('should return status 400', async () => { const { loggedInClient } = await setup(); diff --git a/apps/server/src/modules/board/service/internal/column-board-copy.service.ts b/apps/server/src/modules/board/service/internal/column-board-copy.service.ts index 785694734f9..531ec8c3510 100644 --- a/apps/server/src/modules/board/service/internal/column-board-copy.service.ts +++ b/apps/server/src/modules/board/service/internal/column-board-copy.service.ts @@ -54,6 +54,7 @@ export class ColumnBoardCopyService { ); } copyStatus.copyEntity.context = params.targetExternalReference; + copyStatus.copyEntity.isVisible = false; await this.boardNodeService.addRoot(copyStatus.copyEntity); copyStatus.originalEntity = originalBoard; From 8b9feea3ee6f3ea966759ece215b4985946ae62f Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Wed, 27 Nov 2024 21:27:26 +0100 Subject: [PATCH 45/60] rename room-member to room-membership --- .../mikro-orm/Migration202411271951208.ts | 15 +++ .../src/modules/board/board-api.module.ts | 4 +- .../src/modules/board/board-ws-api.module.ts | 11 ++- apps/server/src/modules/board/board.module.ts | 4 +- .../board-context-in-rooms.api.spec.ts | 4 +- .../api-test/board-create-in-room.api.spec.ts | 8 +- .../api-test/board-delete-in-room.api.spec.ts | 4 +- .../api-test/board-lookup-in-room.api.spec.ts | 4 +- .../board-update-title-in-room.api.spec.ts | 4 +- .../board-visibility-in-room.api.spec.ts | 4 +- .../internal/board-context.service.spec.ts | 26 ++--- .../service/internal/board-context.service.ts | 9 +- .../src/modules/board/uc/board.uc.spec.ts | 6 +- apps/server/src/modules/board/uc/board.uc.ts | 8 +- apps/server/src/modules/room-member/index.ts | 9 -- .../modules/room-member/repo/entity/index.ts | 1 - .../repo/room-member-domain.mapper.spec.ts | 93 ------------------ .../repo/room-member-domain.mapper.ts | 37 ------- .../room-member/repo/room-member.repo.ts | 64 ------------- .../modules/room-member/room-member.module.ts | 15 --- .../src/modules/room-member/testing/index.ts | 2 - .../room-membership.rule.spec.ts} | 46 ++++----- .../authorization/room-membership.rule.ts} | 10 +- .../do/room-membership-authorizable.do.ts} | 4 +- .../do/room-membership.do.spec.ts} | 20 ++-- .../do/room-membership.do.ts} | 8 +- .../src/modules/room-membership/index.ts | 9 ++ .../room-membership/repo/entity/index.ts | 1 + .../repo/entity/room-membership.entity.ts} | 10 +- .../room-membership-domain.mapper.spec.ts | 93 ++++++++++++++++++ .../repo/room-membership-domain.mapper.ts | 37 +++++++ .../repo/room-membership.repo.spec.ts} | 54 +++++------ .../repo/room-membership.repo.ts | 64 +++++++++++++ .../room-membership/room-membership.module.ts | 15 +++ .../service/room-membership.service.spec.ts} | 96 +++++++++---------- .../service/room-membership.service.ts} | 44 +++++---- .../modules/room-membership/testing/index.ts | 2 + .../room-membership-entity.factory.ts} | 6 +- .../testing/room-membership.factory.ts} | 6 +- .../dto/request/create-room.body.params.ts | 4 +- .../dto/request/update-room.body.params.ts | 4 +- .../dto/response/room-board-item.response.ts | 2 +- .../api/dto/response/room-details.response.ts | 2 +- .../modules/room/api/mapper/room.mapper.ts | 2 +- .../src/modules/room/api/room.uc.spec.ts | 18 ++-- apps/server/src/modules/room/api/room.uc.ts | 42 ++++---- .../api/test/room-add-members.api.spec.ts | 8 +- .../room/api/test/room-create.api.spec.ts | 8 +- .../room/api/test/room-delete.api.spec.ts | 8 +- .../room/api/test/room-get-boards.api.spec.ts | 12 +-- .../room/api/test/room-get.api.spec.ts | 8 +- .../room/api/test/room-index.api.spec.ts | 8 +- .../room/api/test/room-members.api.spec.ts | 8 +- .../api/test/room-remove-members.api.spec.ts | 8 +- .../room/api/test/room-update.api.spec.ts | 6 +- .../src/modules/room/room-api.module.ts | 4 +- .../src/modules/sharing/sharing-api.module.ts | 18 ++-- .../modules/sharing/uc/share-token.uc.spec.ts | 12 +-- .../src/modules/sharing/uc/share-token.uc.ts | 16 ++-- .../src/shared/domain/entity/all-entities.ts | 4 +- backup/setup/migrations.json | 9 ++ 61 files changed, 551 insertions(+), 517 deletions(-) create mode 100644 apps/server/src/migrations/mikro-orm/Migration202411271951208.ts delete mode 100644 apps/server/src/modules/room-member/index.ts delete mode 100644 apps/server/src/modules/room-member/repo/entity/index.ts delete mode 100644 apps/server/src/modules/room-member/repo/room-member-domain.mapper.spec.ts delete mode 100644 apps/server/src/modules/room-member/repo/room-member-domain.mapper.ts delete mode 100644 apps/server/src/modules/room-member/repo/room-member.repo.ts delete mode 100644 apps/server/src/modules/room-member/room-member.module.ts delete mode 100644 apps/server/src/modules/room-member/testing/index.ts rename apps/server/src/modules/{room-member/authorization/room-member.rule.spec.ts => room-membership/authorization/room-membership.rule.spec.ts} (60%) rename apps/server/src/modules/{room-member/authorization/room-member.rule.ts => room-membership/authorization/room-membership.rule.ts} (69%) rename apps/server/src/modules/{room-member/do/room-member-authorizable.do.ts => room-membership/do/room-membership-authorizable.do.ts} (79%) rename apps/server/src/modules/{room-member/do/room-member.do.spec.ts => room-membership/do/room-membership.do.spec.ts} (60%) rename apps/server/src/modules/{room-member/do/room-member.do.ts => room-membership/do/room-membership.do.ts} (75%) create mode 100644 apps/server/src/modules/room-membership/index.ts create mode 100644 apps/server/src/modules/room-membership/repo/entity/index.ts rename apps/server/src/modules/{room-member/repo/entity/room-member.entity.ts => room-membership/repo/entity/room-membership.entity.ts} (67%) create mode 100644 apps/server/src/modules/room-membership/repo/room-membership-domain.mapper.spec.ts create mode 100644 apps/server/src/modules/room-membership/repo/room-membership-domain.mapper.ts rename apps/server/src/modules/{room-member/repo/room-member.repo.spec.ts => room-membership/repo/room-membership.repo.spec.ts} (63%) create mode 100644 apps/server/src/modules/room-membership/repo/room-membership.repo.ts create mode 100644 apps/server/src/modules/room-membership/room-membership.module.ts rename apps/server/src/modules/{room-member/service/room-member.service.spec.ts => room-membership/service/room-membership.service.spec.ts} (68%) rename apps/server/src/modules/{room-member/service/room-member.service.ts => room-membership/service/room-membership.service.ts} (73%) create mode 100644 apps/server/src/modules/room-membership/testing/index.ts rename apps/server/src/modules/{room-member/testing/room-member-entity.factory.ts => room-membership/testing/room-membership-entity.factory.ts} (57%) rename apps/server/src/modules/{room-member/testing/room-member.factory.ts => room-membership/testing/room-membership.factory.ts} (55%) diff --git a/apps/server/src/migrations/mikro-orm/Migration202411271951208.ts b/apps/server/src/migrations/mikro-orm/Migration202411271951208.ts new file mode 100644 index 00000000000..0b74ac61e63 --- /dev/null +++ b/apps/server/src/migrations/mikro-orm/Migration202411271951208.ts @@ -0,0 +1,15 @@ +import { Migration } from '@mikro-orm/migrations-mongodb'; + +export class Migration20241127195120 extends Migration { + async up(): Promise { + const db = this.driver.getConnection().getDb(); + await db.renameCollection('room-members', 'room-memberships'); + console.info('Collection renamed from room-members to room-memberships'); + } + + async down(): Promise { + const db = this.driver.getConnection().getDb(); + await db.renameCollection('room-memberships', 'room-members'); + console.info('Collection renamed from room-memberships to room-members'); + } +} diff --git a/apps/server/src/modules/board/board-api.module.ts b/apps/server/src/modules/board/board-api.module.ts index 83d5c1ebb73..e4fa5ac9cb0 100644 --- a/apps/server/src/modules/board/board-api.module.ts +++ b/apps/server/src/modules/board/board-api.module.ts @@ -2,7 +2,7 @@ import { AuthorizationModule } from '@modules/authorization'; import { forwardRef, Module } from '@nestjs/common'; import { CourseRepo } from '@shared/repo/course'; import { LoggerModule } from '@src/core/logger'; -import { RoomMemberModule } from '@modules/room-member'; +import { RoomMembershipModule } from '@src/modules/room-membership'; import { BoardModule } from './board.module'; import { BoardController, @@ -16,7 +16,7 @@ import { BoardUc, CardUc, ColumnUc, ElementUc, SubmissionItemUc } from './uc'; import { RoomModule } from '../room'; @Module({ - imports: [BoardModule, LoggerModule, RoomMemberModule, RoomModule, forwardRef(() => AuthorizationModule)], + imports: [BoardModule, LoggerModule, RoomMembershipModule, RoomModule, forwardRef(() => AuthorizationModule)], controllers: [BoardController, ColumnController, CardController, ElementController, BoardSubmissionController], providers: [BoardUc, BoardNodePermissionService, ColumnUc, CardUc, ElementUc, SubmissionItemUc, CourseRepo], }) diff --git a/apps/server/src/modules/board/board-ws-api.module.ts b/apps/server/src/modules/board/board-ws-api.module.ts index 8c2e07203f7..663b1417b5d 100644 --- a/apps/server/src/modules/board/board-ws-api.module.ts +++ b/apps/server/src/modules/board/board-ws-api.module.ts @@ -3,7 +3,7 @@ import { UserModule } from '@modules/user'; import { forwardRef, Module } from '@nestjs/common'; import { CourseRepo } from '@shared/repo/course'; import { LoggerModule } from '@src/core/logger'; -import { RoomMemberModule } from '../room-member'; +import { RoomMembershipModule } from '../room-membership'; import { BoardModule } from './board.module'; import { BoardCollaborationGateway } from './gateway/board-collaboration.gateway'; import { MetricsService } from './metrics/metrics.service'; @@ -12,7 +12,14 @@ import { BoardUc, CardUc, ColumnUc, ElementUc } from './uc'; import { RoomModule } from '../room'; @Module({ - imports: [BoardModule, forwardRef(() => AuthorizationModule), LoggerModule, UserModule, RoomMemberModule, RoomModule], + imports: [ + BoardModule, + forwardRef(() => AuthorizationModule), + LoggerModule, + UserModule, + RoomMembershipModule, + RoomModule, + ], providers: [ BoardCollaborationGateway, BoardNodePermissionService, diff --git a/apps/server/src/modules/board/board.module.ts b/apps/server/src/modules/board/board.module.ts index 7a2142e1204..e8d703431bd 100644 --- a/apps/server/src/modules/board/board.module.ts +++ b/apps/server/src/modules/board/board.module.ts @@ -10,7 +10,7 @@ import { CqrsModule } from '@nestjs/cqrs'; import { CourseRepo } from '@shared/repo/course'; import { LoggerModule } from '@src/core/logger'; import { AuthorizationModule } from '../authorization'; -import { RoomMemberModule } from '../room-member'; +import { RoomMembershipModule } from '../room-membership'; import { BoardNodeRule } from './authorisation/board-node.rule'; import { BoardNodeFactory } from './domain'; import { BoardNodeRepo } from './repo'; @@ -46,7 +46,7 @@ import { CqrsModule, CollaborativeTextEditorModule, AuthorizationModule, - RoomMemberModule, + RoomMembershipModule, ], providers: [ // TODO: move BoardDoAuthorizableService, BoardDoRepo, BoardDoService, BoardNodeRepo in separate module and move mediaboard related services in mediaboard module diff --git a/apps/server/src/modules/board/controller/api-test/board-context-in-rooms.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-context-in-rooms.api.spec.ts index 1461f141013..9fe85f82b51 100644 --- a/apps/server/src/modules/board/controller/api-test/board-context-in-rooms.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-context-in-rooms.api.spec.ts @@ -6,7 +6,7 @@ import { TestApiClient, cleanupCollections, groupEntityFactory, roleFactory, use import { Permission, RoleName } from '@shared/domain/interface'; import { accountFactory } from '@src/modules/account/testing'; import { GroupEntityTypes } from '@src/modules/group/entity'; -import { roomMemberEntityFactory } from '@src/modules/room-member/testing'; +import { roomMembershipEntityFactory } from '@src/modules/room-membership/testing'; import { roomEntityFactory } from '@src/modules/room/testing'; import { columnBoardEntityFactory } from '../../testing'; import { BoardExternalReferenceType } from '../../domain'; @@ -66,7 +66,7 @@ describe('board get context in room (api)', () => { const room = roomEntityFactory.buildWithId(); - const roomMember = roomMemberEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + const roomMember = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); await em.persistAndFlush([ accountWithEditRole, diff --git a/apps/server/src/modules/board/controller/api-test/board-create-in-room.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-create-in-room.api.spec.ts index 3da8c8240da..a79c2559c43 100644 --- a/apps/server/src/modules/board/controller/api-test/board-create-in-room.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-create-in-room.api.spec.ts @@ -7,7 +7,7 @@ import { RoleName } from '@shared/domain/interface/rolename.enum'; import { cleanupCollections, groupEntityFactory, roleFactory, TestApiClient, userFactory } from '@shared/testing'; import { accountFactory } from '@src/modules/account/testing'; import { GroupEntityTypes } from '@src/modules/group/entity'; -import { roomMemberEntityFactory } from '@src/modules/room-member/testing'; +import { roomMembershipEntityFactory } from '@src/modules/room-membership/testing'; import { roomEntityFactory } from '@src/modules/room/testing'; import { BoardExternalReferenceType, BoardLayout } from '../../domain'; import { BoardNodeEntity } from '../../repo'; @@ -54,7 +54,7 @@ describe(`create board in room (api)`, () => { const room = roomEntityFactory.buildWithId(); - const roomMember = roomMemberEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + const roomMember = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); await em.persistAndFlush([account, user, role, userGroup, room, roomMember]); em.clear(); @@ -170,7 +170,7 @@ describe(`create board in room (api)`, () => { const room = roomEntityFactory.buildWithId(); - const roomMember = roomMemberEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + const roomMember = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); await em.persistAndFlush([account, user, role, userGroup, room, roomMember]); em.clear(); @@ -238,7 +238,7 @@ describe(`create board in room (api)`, () => { const room = roomEntityFactory.buildWithId(); - const roomMember = roomMemberEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + const roomMember = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); await em.persistAndFlush([account, user, role, userGroup, room, roomMember]); em.clear(); diff --git a/apps/server/src/modules/board/controller/api-test/board-delete-in-room.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-delete-in-room.api.spec.ts index 30f05f7953f..dbb50f06c32 100644 --- a/apps/server/src/modules/board/controller/api-test/board-delete-in-room.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-delete-in-room.api.spec.ts @@ -7,7 +7,7 @@ import { accountFactory } from '@src/modules/account/testing'; import { Permission, RoleName } from '@shared/domain/interface'; import { GroupEntityTypes } from '@src/modules/group/entity'; import { roomEntityFactory } from '@src/modules/room/testing'; -import { roomMemberEntityFactory } from '@src/modules/room-member/testing'; +import { roomMembershipEntityFactory } from '@src/modules/room-membership/testing'; import { columnBoardEntityFactory, columnEntityFactory } from '../../testing'; import { BoardNodeEntity } from '../../repo'; import { BoardExternalReferenceType } from '../../domain'; @@ -61,7 +61,7 @@ describe(`board delete in room (api)`, () => { const room = roomEntityFactory.buildWithId(); - const roomMember = roomMemberEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + const roomMember = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); await em.persistAndFlush([ accountWithEditRole, diff --git a/apps/server/src/modules/board/controller/api-test/board-lookup-in-room.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-lookup-in-room.api.spec.ts index 952140cc19e..76d617c9525 100644 --- a/apps/server/src/modules/board/controller/api-test/board-lookup-in-room.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-lookup-in-room.api.spec.ts @@ -7,7 +7,7 @@ import { cleanupCollections, groupEntityFactory, roleFactory, TestApiClient, use import { Permission, RoleName } from '@shared/domain/interface'; import { accountFactory } from '@src/modules/account/testing'; import { GroupEntityTypes } from '@src/modules/group/entity'; -import { roomMemberEntityFactory } from '@src/modules/room-member/testing'; +import { roomMembershipEntityFactory } from '@src/modules/room-membership/testing'; import { roomEntityFactory } from '@src/modules/room/testing'; import { BoardExternalReferenceType, BoardLayout } from '../../domain'; import { BoardResponse } from '../dto'; @@ -62,7 +62,7 @@ describe(`board lookup in room (api)`, () => { const room = roomEntityFactory.buildWithId(); - const roomMember = roomMemberEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + const roomMember = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); await em.persistAndFlush([ accountWithEditRole, diff --git a/apps/server/src/modules/board/controller/api-test/board-update-title-in-room.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-update-title-in-room.api.spec.ts index 8cf0930de8a..d074df6a0eb 100644 --- a/apps/server/src/modules/board/controller/api-test/board-update-title-in-room.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-update-title-in-room.api.spec.ts @@ -7,7 +7,7 @@ import { TestApiClient, cleanupCollections, groupEntityFactory, roleFactory, use import { Permission, RoleName } from '@shared/domain/interface'; import { accountFactory } from '@src/modules/account/testing'; import { GroupEntityTypes } from '@src/modules/group/entity'; -import { roomMemberEntityFactory } from '@src/modules/room-member/testing'; +import { roomMembershipEntityFactory } from '@src/modules/room-membership/testing'; import { roomEntityFactory } from '@src/modules/room/testing'; import { BoardNodeEntity } from '../../repo'; import { columnBoardEntityFactory } from '../../testing'; @@ -68,7 +68,7 @@ describe(`board update title with room relation (api)`, () => { const room = roomEntityFactory.buildWithId(); - const roomMember = roomMemberEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + const roomMember = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); await em.persistAndFlush([ accountWithEditRole, diff --git a/apps/server/src/modules/board/controller/api-test/board-visibility-in-room.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-visibility-in-room.api.spec.ts index 56a0e52e71e..58a1669774e 100644 --- a/apps/server/src/modules/board/controller/api-test/board-visibility-in-room.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-visibility-in-room.api.spec.ts @@ -6,7 +6,7 @@ import { TestApiClient, cleanupCollections, groupEntityFactory, roleFactory, use import { Permission, RoleName } from '@shared/domain/interface'; import { accountFactory } from '@src/modules/account/testing'; import { GroupEntityTypes } from '@src/modules/group/entity'; -import { roomMemberEntityFactory } from '@src/modules/room-member/testing'; +import { roomMembershipEntityFactory } from '@src/modules/room-membership/testing'; import { roomEntityFactory } from '@src/modules/room/testing'; import { BoardExternalReferenceType } from '../../domain'; import { columnBoardEntityFactory } from '../../testing'; @@ -67,7 +67,7 @@ describe(`board update visibility with room relation (api)`, () => { const room = roomEntityFactory.buildWithId(); - const roomMember = roomMemberEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + const roomMember = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); await em.persistAndFlush([ accountWithEditRole, diff --git a/apps/server/src/modules/board/service/internal/board-context.service.spec.ts b/apps/server/src/modules/board/service/internal/board-context.service.spec.ts index 82859128268..ecf3656b2d3 100644 --- a/apps/server/src/modules/board/service/internal/board-context.service.spec.ts +++ b/apps/server/src/modules/board/service/internal/board-context.service.spec.ts @@ -5,26 +5,26 @@ import { Permission, RoleName } from '@shared/domain/interface'; import { CourseRepo } from '@shared/repo/course'; import { courseFactory, groupFactory, roleFactory, setupEntities, userFactory } from '@shared/testing'; import { GroupTypes } from '@src/modules/group'; -import { RoomMemberService } from '@src/modules/room-member'; -import { roomMemberFactory } from '@src/modules/room-member/testing'; +import { RoomMembershipService } from '@src/modules/room-membership'; +import { roomMembershipFactory } from '@src/modules/room-membership/testing'; import { roomFactory } from '@src/modules/room/testing'; import { BoardExternalReferenceType, BoardRoles, UserWithBoardRoles } from '../../domain'; import { columnBoardFactory, columnFactory } from '../../testing'; import { BoardContextService } from './board-context.service'; -describe(`${BoardContextService.name}`, () => { +describe(BoardContextService.name, () => { let module: TestingModule; let service: BoardContextService; let courseRepo: DeepMocked; - let roomMemberService: DeepMocked; + let roomMembershipService: DeepMocked; beforeAll(async () => { module = await Test.createTestingModule({ providers: [ BoardContextService, { - provide: RoomMemberService, - useValue: createMock(), + provide: RoomMembershipService, + useValue: createMock(), }, { provide: CourseRepo, @@ -34,7 +34,7 @@ describe(`${BoardContextService.name}`, () => { }).compile(); service = module.get(BoardContextService); - roomMemberService = module.get(RoomMemberService); + roomMembershipService = module.get(RoomMembershipService); courseRepo = module.get(CourseRepo); await setupEntities(); @@ -221,7 +221,7 @@ describe(`${BoardContextService.name}`, () => { const role = roleFactory.build({ name: RoleName.ROOMEDITOR, permissions: [Permission.ROOM_EDIT] }); const group = groupFactory.build({ type: GroupTypes.ROOM, users: [{ userId: user.id, roleId: role.id }] }); const room = roomFactory.build(); - roomMemberFactory.build({ roomId: room.id, userGroupId: group.id }); + roomMembershipFactory.build({ roomId: room.id, userGroupId: group.id }); const columnBoard = columnBoardFactory.build({ context: { id: room.id, type: BoardExternalReferenceType.Room }, }); @@ -232,7 +232,7 @@ describe(`${BoardContextService.name}`, () => { it('should return their information + editor role', async () => { const { columnBoard, role, user } = setup(); - roomMemberService.getRoomMemberAuthorizable.mockResolvedValue({ + roomMembershipService.getRoomMembershipAuthorizable.mockResolvedValue({ id: 'foo', roomId: columnBoard.context.id, members: [{ userId: user.id, roles: [role] }], @@ -256,7 +256,7 @@ describe(`${BoardContextService.name}`, () => { const role = roleFactory.build({ name: RoleName.ROOMVIEWER, permissions: [Permission.ROOM_VIEW] }); const group = groupFactory.build({ type: GroupTypes.ROOM, users: [{ userId: user.id, roleId: role.id }] }); const room = roomFactory.build(); - roomMemberFactory.build({ roomId: room.id, userGroupId: group.id }); + roomMembershipFactory.build({ roomId: room.id, userGroupId: group.id }); const columnBoard = columnBoardFactory.build({ context: { id: room.id, type: BoardExternalReferenceType.Room }, }); @@ -267,7 +267,7 @@ describe(`${BoardContextService.name}`, () => { it('should return their information + reader role', async () => { const { columnBoard, role, user } = setup(); - roomMemberService.getRoomMemberAuthorizable.mockResolvedValue({ + roomMembershipService.getRoomMembershipAuthorizable.mockResolvedValue({ id: 'foo', roomId: columnBoard.context.id, members: [{ userId: user.id, roles: [role] }], @@ -291,7 +291,7 @@ describe(`${BoardContextService.name}`, () => { const role = roleFactory.build(); const group = groupFactory.build({ type: GroupTypes.ROOM, users: [{ userId: user.id, roleId: role.id }] }); const room = roomFactory.build(); - roomMemberFactory.build({ roomId: room.id, userGroupId: group.id }); + roomMembershipFactory.build({ roomId: room.id, userGroupId: group.id }); const columnBoard = columnBoardFactory.build({ context: { id: room.id, type: BoardExternalReferenceType.Room }, }); @@ -302,7 +302,7 @@ describe(`${BoardContextService.name}`, () => { it('should return their information + no role', async () => { const { columnBoard, role, user } = setup(); - roomMemberService.getRoomMemberAuthorizable.mockResolvedValue({ + roomMembershipService.getRoomMembershipAuthorizable.mockResolvedValue({ id: 'foo', roomId: columnBoard.context.id, members: [{ userId: user.id, roles: [role] }], diff --git a/apps/server/src/modules/board/service/internal/board-context.service.ts b/apps/server/src/modules/board/service/internal/board-context.service.ts index 66c78a1ac1f..32b6ef1df2d 100644 --- a/apps/server/src/modules/board/service/internal/board-context.service.ts +++ b/apps/server/src/modules/board/service/internal/board-context.service.ts @@ -2,13 +2,12 @@ import { Injectable } from '@nestjs/common'; import { Permission } from '@shared/domain/interface'; import { EntityId } from '@shared/domain/types'; import { CourseRepo } from '@shared/repo/course'; -import { RoomMemberService } from '@src/modules/room-member'; -import { UserWithRoomRoles } from '@src/modules/room-member/do/room-member-authorizable.do'; +import { RoomMembershipService, UserWithRoomRoles } from '@src/modules/room-membership'; import { AnyBoardNode, BoardExternalReferenceType, BoardRoles, UserWithBoardRoles } from '../../domain'; @Injectable() export class BoardContextService { - constructor(private readonly courseRepo: CourseRepo, private readonly roomMemberService: RoomMemberService) {} + constructor(private readonly courseRepo: CourseRepo, private readonly roomMembershipService: RoomMembershipService) {} async getUsersWithBoardRoles(rootNode: AnyBoardNode): Promise { if (!('context' in rootNode)) { @@ -31,8 +30,8 @@ export class BoardContextService { } private async getFromRoom(roomId: EntityId): Promise { - const roomMemberAuthorizable = await this.roomMemberService.getRoomMemberAuthorizable(roomId); - const usersWithRoles: UserWithBoardRoles[] = roomMemberAuthorizable.members.map((member) => { + const roomMembershipAuthorizable = await this.roomMembershipService.getRoomMembershipAuthorizable(roomId); + const usersWithRoles: UserWithBoardRoles[] = roomMembershipAuthorizable.members.map((member) => { const roles = this.getBoardRolesFromRoomMember(member); return { userId: member.userId, diff --git a/apps/server/src/modules/board/uc/board.uc.spec.ts b/apps/server/src/modules/board/uc/board.uc.spec.ts index 2706ff151ba..ff22353895b 100644 --- a/apps/server/src/modules/board/uc/board.uc.spec.ts +++ b/apps/server/src/modules/board/uc/board.uc.spec.ts @@ -8,7 +8,7 @@ import { setupEntities, userFactory } from '@shared/testing'; import { courseFactory } from '@shared/testing/factory'; import { LegacyLogger } from '@src/core/logger'; import { RoomService } from '@src/modules/room'; -import { RoomMemberService } from '@src/modules/room-member'; +import { RoomMembershipService } from '@src/modules/room-membership'; import { CopyElementType, CopyStatus, CopyStatusEnum } from '../../copy-helper'; import { BoardExternalReferenceType, BoardLayout, BoardNodeFactory, Column, ColumnBoard } from '../domain'; import { BoardNodePermissionService, BoardNodeService, ColumnBoardService } from '../service'; @@ -58,8 +58,8 @@ describe(BoardUc.name, () => { useValue: createMock(), }, { - provide: RoomMemberService, - useValue: createMock(), + provide: RoomMembershipService, + useValue: createMock(), }, { provide: LegacyLogger, diff --git a/apps/server/src/modules/board/uc/board.uc.ts b/apps/server/src/modules/board/uc/board.uc.ts index 31abada02d5..c18a722304a 100644 --- a/apps/server/src/modules/board/uc/board.uc.ts +++ b/apps/server/src/modules/board/uc/board.uc.ts @@ -7,7 +7,7 @@ import { CourseRepo } from '@shared/repo/course'; import { LegacyLogger } from '@src/core/logger'; import { StorageLocation } from '@src/modules/files-storage/interface'; import { RoomService } from '@src/modules/room'; -import { RoomMemberService } from '@src/modules/room-member'; +import { RoomMembershipService } from '@src/modules/room-membership'; import { CreateBoardBodyParams } from '../controller/dto'; import { BoardExternalReference, BoardExternalReferenceType, BoardNodeFactory, Column, ColumnBoard } from '../domain'; import { BoardNodePermissionService, BoardNodeService, ColumnBoardService } from '../service'; @@ -19,7 +19,7 @@ export class BoardUc { @Inject(forwardRef(() => AuthorizationService)) // TODO is this needed? private readonly authorizationService: AuthorizationService, private readonly boardPermissionService: BoardNodePermissionService, - private readonly roomMemberService: RoomMemberService, + private readonly roomMembershipService: RoomMembershipService, private readonly boardNodeService: BoardNodeService, private readonly columnBoardService: ColumnBoardService, private readonly logger: LegacyLogger, @@ -158,9 +158,9 @@ export class BoardUc { requiredPermissions: [Permission.COURSE_EDIT], }); } else if (context.type === BoardExternalReferenceType.Room) { - const roomMemberAuthorizable = await this.roomMemberService.getRoomMemberAuthorizable(context.id); + const roomMembershipAuthorizable = await this.roomMembershipService.getRoomMembershipAuthorizable(context.id); - this.authorizationService.checkPermission(user, roomMemberAuthorizable, { + this.authorizationService.checkPermission(user, roomMembershipAuthorizable, { action: Action.write, requiredPermissions: [], }); diff --git a/apps/server/src/modules/room-member/index.ts b/apps/server/src/modules/room-member/index.ts deleted file mode 100644 index 772b42aa05a..00000000000 --- a/apps/server/src/modules/room-member/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { RoomMemberEntity } from './repo/entity'; -import { RoomMemberRepo } from './repo/room-member.repo'; -import { RoomMemberService } from './service/room-member.service'; - -export * from './do/room-member.do'; -export * from './room-member.module'; -export { RoomMemberEntity, RoomMemberRepo, RoomMemberService }; - -export { UserWithRoomRoles, RoomMemberAuthorizable } from './do/room-member-authorizable.do'; diff --git a/apps/server/src/modules/room-member/repo/entity/index.ts b/apps/server/src/modules/room-member/repo/entity/index.ts deleted file mode 100644 index 845b87253da..00000000000 --- a/apps/server/src/modules/room-member/repo/entity/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './room-member.entity'; diff --git a/apps/server/src/modules/room-member/repo/room-member-domain.mapper.spec.ts b/apps/server/src/modules/room-member/repo/room-member-domain.mapper.spec.ts deleted file mode 100644 index d2629ebef65..00000000000 --- a/apps/server/src/modules/room-member/repo/room-member-domain.mapper.spec.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { RoomMember, RoomMemberProps } from '../do/room-member.do'; -import { roomMemberEntityFactory } from '../testing'; -import { RoomMemberEntity } from './entity'; -import { RoomMemberDomainMapper } from './room-member-domain.mapper'; - -describe('RoomMemberDomainMapper', () => { - describe('mapEntityToDo', () => { - it('should correctly map roomMemberEntity to RoomMember domain object', () => { - const roomMemberEntity = { - id: '1', - } as RoomMemberEntity; - - const result = RoomMemberDomainMapper.mapEntityToDo(roomMemberEntity); - - expect(result).toBeInstanceOf(RoomMember); - expect(result.getProps()).toEqual({ - id: '1', - }); - }); - - it('should return existing domainObject if present, regardless of entity properties', () => { - const existingRoomMember = new RoomMember({ - id: '1', - roomId: 'r1', - userGroupId: 'ug1', - createdAt: new Date('2023-01-01'), - updatedAt: new Date('2023-01-01'), - }); - - const roomMemberEntity = { - id: '1', - domainObject: existingRoomMember, - } as RoomMemberEntity; - - const result = RoomMemberDomainMapper.mapEntityToDo(roomMemberEntity); - - expect(result).toBe(existingRoomMember); - expect(result).toBeInstanceOf(RoomMember); - expect(result.getProps()).toEqual({ - id: '1', - roomId: 'r1', - userGroupId: 'ug1', - createdAt: new Date('2023-01-01'), - updatedAt: new Date('2023-01-01'), - }); - expect(result.getProps().id).toBe('1'); - expect(result.getProps().id).toBe(roomMemberEntity.id); - }); - - it('should wrap the actual entity reference in the domain object', () => { - const roomMemberEntity = { - id: '1', - } as RoomMemberEntity; - - const result = RoomMemberDomainMapper.mapEntityToDo(roomMemberEntity); - // @ts-expect-error check necessary - const { props } = result; - - expect(props === roomMemberEntity).toBe(true); - }); - }); - - describe('mapDoToEntity', () => { - describe('when domain object props are instanceof roomMemberEntity', () => { - it('should return the entity', () => { - const roomMemberEntity = roomMemberEntityFactory.build(); - const roomMember = new RoomMember(roomMemberEntity); - - const result = RoomMemberDomainMapper.mapDoToEntity(roomMember); - - expect(result).toBe(roomMemberEntity); - }); - }); - - describe('when domain object props are not instanceof roomMemberEntity', () => { - it('should convert them to an entity and return it', () => { - const roomMemberEntity: RoomMemberProps = { - id: '66d581c3ef74c548a4efea1d', - roomId: '66d581c3ef74c548a4efea1a', - userGroupId: '66d581c3ef74c548a4efea1b', - createdAt: new Date('2024-10-1'), - updatedAt: new Date('2024-10-1'), - }; - const room = new RoomMember(roomMemberEntity); - - const result = RoomMemberDomainMapper.mapDoToEntity(room); - - expect(result).toBeInstanceOf(RoomMemberEntity); - expect(result).toMatchObject(roomMemberEntity); - }); - }); - }); -}); diff --git a/apps/server/src/modules/room-member/repo/room-member-domain.mapper.ts b/apps/server/src/modules/room-member/repo/room-member-domain.mapper.ts deleted file mode 100644 index 73163a07769..00000000000 --- a/apps/server/src/modules/room-member/repo/room-member-domain.mapper.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { RoomMember } from '../do/room-member.do'; -import { RoomMemberEntity } from './entity'; - -export class RoomMemberDomainMapper { - static mapEntityToDo(roomMemberEntity: RoomMemberEntity): RoomMember { - // check identity map reference - if (roomMemberEntity.domainObject) { - return roomMemberEntity.domainObject; - } - - const roomMember = new RoomMember(roomMemberEntity); - - // attach to identity map - roomMemberEntity.domainObject = roomMember; - - return roomMember; - } - - static mapDoToEntity(roomMember: RoomMember): RoomMemberEntity { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const { props } = roomMember; - - if (!(props instanceof RoomMemberEntity)) { - const entity = new RoomMemberEntity(); - Object.assign(entity, props); - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - roomMember.props = entity; - - return entity; - } - - return props; - } -} diff --git a/apps/server/src/modules/room-member/repo/room-member.repo.ts b/apps/server/src/modules/room-member/repo/room-member.repo.ts deleted file mode 100644 index 022383fffaf..00000000000 --- a/apps/server/src/modules/room-member/repo/room-member.repo.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { Utils } from '@mikro-orm/core'; -import { EntityManager } from '@mikro-orm/mongodb'; -import { Injectable } from '@nestjs/common'; -import { EntityId } from '@shared/domain/types'; -import { RoomMember } from '../do/room-member.do'; -import { RoomMemberEntity } from './entity'; -import { RoomMemberDomainMapper } from './room-member-domain.mapper'; - -@Injectable() -export class RoomMemberRepo { - constructor(private readonly em: EntityManager) {} - - async findByRoomId(roomId: EntityId): Promise { - const roomMemberEntities = await this.em.findOne(RoomMemberEntity, { roomId }); - if (!roomMemberEntities) return null; - - const roomMembers = RoomMemberDomainMapper.mapEntityToDo(roomMemberEntities); - - return roomMembers; - } - - async findByRoomIds(roomIds: EntityId[]): Promise { - const entities = await this.em.find(RoomMemberEntity, { roomId: { $in: roomIds } }); - const roomMembers = entities.map((entity) => RoomMemberDomainMapper.mapEntityToDo(entity)); - - return roomMembers; - } - - async findByGroupId(groupId: EntityId): Promise { - const entities = await this.em.find(RoomMemberEntity, { userGroupId: groupId }); - const roomMembers = entities.map((entity) => RoomMemberDomainMapper.mapEntityToDo(entity)); - - return roomMembers; - } - - async findByGroupIds(groupIds: EntityId[]): Promise { - const entities = await this.em.find(RoomMemberEntity, { userGroupId: { $in: groupIds } }); - const roomMembers = entities.map((entity) => RoomMemberDomainMapper.mapEntityToDo(entity)); - - return roomMembers; - } - - async save(roomMember: RoomMember | RoomMember[]): Promise { - const roomMembers = Utils.asArray(roomMember); - - roomMembers.forEach((member) => { - const entity = RoomMemberDomainMapper.mapDoToEntity(member); - this.em.persist(entity); - }); - - await this.em.flush(); - } - - async delete(roomMember: RoomMember | RoomMember[]): Promise { - const roomMembers = Utils.asArray(roomMember); - - roomMembers.forEach((member) => { - const entity = RoomMemberDomainMapper.mapDoToEntity(member); - this.em.remove(entity); - }); - - await this.em.flush(); - } -} diff --git a/apps/server/src/modules/room-member/room-member.module.ts b/apps/server/src/modules/room-member/room-member.module.ts deleted file mode 100644 index b07ace89160..00000000000 --- a/apps/server/src/modules/room-member/room-member.module.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { GroupModule } from '@modules/group'; -import { Module } from '@nestjs/common'; -import { CqrsModule } from '@nestjs/cqrs'; -import { AuthorizationModule } from '../authorization'; -import { RoleModule } from '../role'; -import { RoomMemberRule } from './authorization/room-member.rule'; -import { RoomMemberRepo } from './repo/room-member.repo'; -import { RoomMemberService } from './service/room-member.service'; - -@Module({ - imports: [AuthorizationModule, CqrsModule, GroupModule, RoleModule], - providers: [RoomMemberService, RoomMemberRepo, RoomMemberRule], - exports: [RoomMemberService], -}) -export class RoomMemberModule {} diff --git a/apps/server/src/modules/room-member/testing/index.ts b/apps/server/src/modules/room-member/testing/index.ts deleted file mode 100644 index 7f1a2950ff5..00000000000 --- a/apps/server/src/modules/room-member/testing/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './room-member-entity.factory'; -export * from './room-member.factory'; diff --git a/apps/server/src/modules/room-member/authorization/room-member.rule.spec.ts b/apps/server/src/modules/room-membership/authorization/room-membership.rule.spec.ts similarity index 60% rename from apps/server/src/modules/room-member/authorization/room-member.rule.spec.ts rename to apps/server/src/modules/room-membership/authorization/room-membership.rule.spec.ts index 1ca26adb941..6946c83aa8d 100644 --- a/apps/server/src/modules/room-member/authorization/room-member.rule.spec.ts +++ b/apps/server/src/modules/room-membership/authorization/room-membership.rule.spec.ts @@ -1,22 +1,22 @@ import { Test, TestingModule } from '@nestjs/testing'; import { Permission } from '@shared/domain/interface'; import { roleDtoFactory, setupEntities, userFactory } from '@shared/testing'; -import { Action, AuthorizationHelper, AuthorizationInjectionService } from '@src/modules/authorization'; -import { RoomMemberAuthorizable } from '../do/room-member-authorizable.do'; -import { RoomMemberRule } from './room-member.rule'; +import { Action, AuthorizationHelper, AuthorizationInjectionService } from '@modules/authorization'; +import { RoomMembershipAuthorizable } from '../do/room-membership-authorizable.do'; +import { RoomMembershipRule } from './room-membership.rule'; -describe(RoomMemberRule.name, () => { - let service: RoomMemberRule; +describe(RoomMembershipRule.name, () => { + let service: RoomMembershipRule; let injectionService: AuthorizationInjectionService; beforeAll(async () => { await setupEntities(); const module: TestingModule = await Test.createTestingModule({ - providers: [RoomMemberRule, AuthorizationHelper, AuthorizationInjectionService], + providers: [RoomMembershipRule, AuthorizationHelper, AuthorizationInjectionService], }).compile(); - service = await module.get(RoomMemberRule); + service = await module.get(RoomMembershipRule); injectionService = await module.get(AuthorizationInjectionService); }); @@ -30,14 +30,14 @@ describe(RoomMemberRule.name, () => { describe('when entity is applicable', () => { const setup = () => { const user = userFactory.buildWithId(); - const roomMemberAuthorizable = new RoomMemberAuthorizable('', []); + const roomMembershipAuthorizable = new RoomMembershipAuthorizable('', []); - return { user, roomMemberAuthorizable }; + return { user, roomMembershipAuthorizable }; }; it('should return true', () => { - const { user, roomMemberAuthorizable } = setup(); - const result = service.isApplicable(user, roomMemberAuthorizable); + const { user, roomMembershipAuthorizable } = setup(); + const result = service.isApplicable(user, roomMembershipAuthorizable); expect(result).toStrictEqual(true); }); @@ -64,15 +64,15 @@ describe(RoomMemberRule.name, () => { const setup = () => { const user = userFactory.buildWithId(); const roleDto = roleDtoFactory.build({ permissions: [Permission.ROOM_VIEW] }); - const roomMemberAuthorizable = new RoomMemberAuthorizable('', [{ roles: [roleDto], userId: user.id }]); + const roomMembershipAuthorizable = new RoomMembershipAuthorizable('', [{ roles: [roleDto], userId: user.id }]); - return { user, roomMemberAuthorizable }; + return { user, roomMembershipAuthorizable }; }; it('should return "true" for read action', () => { - const { user, roomMemberAuthorizable } = setup(); + const { user, roomMembershipAuthorizable } = setup(); - const res = service.hasPermission(user, roomMemberAuthorizable, { + const res = service.hasPermission(user, roomMembershipAuthorizable, { action: Action.read, requiredPermissions: [], }); @@ -81,9 +81,9 @@ describe(RoomMemberRule.name, () => { }); it('should return "false" for write action', () => { - const { user, roomMemberAuthorizable } = setup(); + const { user, roomMembershipAuthorizable } = setup(); - const res = service.hasPermission(user, roomMemberAuthorizable, { + const res = service.hasPermission(user, roomMembershipAuthorizable, { action: Action.write, requiredPermissions: [], }); @@ -95,15 +95,15 @@ describe(RoomMemberRule.name, () => { describe('when user is not member of room', () => { const setup = () => { const user = userFactory.buildWithId(); - const roomMemberAuthorizable = new RoomMemberAuthorizable('', []); + const roomMembershipAuthorizable = new RoomMembershipAuthorizable('', []); - return { user, roomMemberAuthorizable }; + return { user, roomMembershipAuthorizable }; }; it('should return "false" for read action', () => { - const { user, roomMemberAuthorizable } = setup(); + const { user, roomMembershipAuthorizable } = setup(); - const res = service.hasPermission(user, roomMemberAuthorizable, { + const res = service.hasPermission(user, roomMembershipAuthorizable, { action: Action.read, requiredPermissions: [], }); @@ -112,9 +112,9 @@ describe(RoomMemberRule.name, () => { }); it('should return "false" for write action', () => { - const { user, roomMemberAuthorizable } = setup(); + const { user, roomMembershipAuthorizable } = setup(); - const res = service.hasPermission(user, roomMemberAuthorizable, { + const res = service.hasPermission(user, roomMembershipAuthorizable, { action: Action.write, requiredPermissions: [], }); diff --git a/apps/server/src/modules/room-member/authorization/room-member.rule.ts b/apps/server/src/modules/room-membership/authorization/room-membership.rule.ts similarity index 69% rename from apps/server/src/modules/room-member/authorization/room-member.rule.ts rename to apps/server/src/modules/room-membership/authorization/room-membership.rule.ts index 7a98c93a215..cfcd11c33af 100644 --- a/apps/server/src/modules/room-member/authorization/room-member.rule.ts +++ b/apps/server/src/modules/room-membership/authorization/room-membership.rule.ts @@ -1,22 +1,22 @@ import { Injectable } from '@nestjs/common'; import { User } from '@shared/domain/entity'; import { Permission } from '@shared/domain/interface'; -import { AuthorizationInjectionService, Action, AuthorizationContext, Rule } from '@src/modules/authorization'; -import { RoomMemberAuthorizable } from '../do/room-member-authorizable.do'; +import { AuthorizationInjectionService, Action, AuthorizationContext, Rule } from '@modules/authorization'; +import { RoomMembershipAuthorizable } from '../do/room-membership-authorizable.do'; @Injectable() -export class RoomMemberRule implements Rule { +export class RoomMembershipRule implements Rule { constructor(private readonly authorisationInjectionService: AuthorizationInjectionService) { this.authorisationInjectionService.injectAuthorizationRule(this); } public isApplicable(user: User, object: unknown): boolean { - const isMatched = object instanceof RoomMemberAuthorizable; + const isMatched = object instanceof RoomMembershipAuthorizable; return isMatched; } - public hasPermission(user: User, object: RoomMemberAuthorizable, context: AuthorizationContext): boolean { + public hasPermission(user: User, object: RoomMembershipAuthorizable, context: AuthorizationContext): boolean { const { action } = context; const permissionsThisUserHas = object.members .filter((member) => member.userId === user.id) diff --git a/apps/server/src/modules/room-member/do/room-member-authorizable.do.ts b/apps/server/src/modules/room-membership/do/room-membership-authorizable.do.ts similarity index 79% rename from apps/server/src/modules/room-member/do/room-member-authorizable.do.ts rename to apps/server/src/modules/room-membership/do/room-membership-authorizable.do.ts index 1728d0045b9..61821fa4b82 100644 --- a/apps/server/src/modules/room-member/do/room-member-authorizable.do.ts +++ b/apps/server/src/modules/room-membership/do/room-membership-authorizable.do.ts @@ -1,13 +1,13 @@ import { AuthorizableObject } from '@shared/domain/domain-object'; import { EntityId } from '@shared/domain/types'; -import { RoleDto } from '@src/modules/role'; +import { RoleDto } from '@modules/role'; export type UserWithRoomRoles = { roles: RoleDto[]; userId: EntityId; }; -export class RoomMemberAuthorizable implements AuthorizableObject { +export class RoomMembershipAuthorizable implements AuthorizableObject { public readonly id: EntityId = ''; public readonly roomId: EntityId; diff --git a/apps/server/src/modules/room-member/do/room-member.do.spec.ts b/apps/server/src/modules/room-membership/do/room-membership.do.spec.ts similarity index 60% rename from apps/server/src/modules/room-member/do/room-member.do.spec.ts rename to apps/server/src/modules/room-membership/do/room-membership.do.spec.ts index d7ed3fb03ac..5dc0735fc0d 100644 --- a/apps/server/src/modules/room-member/do/room-member.do.spec.ts +++ b/apps/server/src/modules/room-membership/do/room-membership.do.spec.ts @@ -1,11 +1,11 @@ import { EntityId } from '@shared/domain/types'; -import { roomMemberFactory } from '../testing'; -import { RoomMember, RoomMemberProps } from './room-member.do'; +import { roomMembershipFactory } from '../testing'; +import { RoomMembership, RoomMembershipProps } from './room-membership.do'; -describe('RoomMember', () => { - let roomMember: RoomMember; +describe('RoomMembership', () => { + let roomMember: RoomMembership; const roomMemberId: EntityId = 'roomMemberId'; - const roomMemberProps: RoomMemberProps = { + const roomMembershipProps: RoomMembershipProps = { id: roomMemberId, roomId: 'roomId', userGroupId: 'userGroupId', @@ -14,11 +14,11 @@ describe('RoomMember', () => { }; beforeEach(() => { - roomMember = new RoomMember(roomMemberProps); + roomMember = new RoomMembership(roomMembershipProps); }); it('should props without domainObject', () => { - const mockDomainObject = roomMemberFactory.build(); + const mockDomainObject = roomMembershipFactory.build(); // this tests the hotfix for the mikro-orm issue // eslint-disable-next-line @typescript-eslint/dot-notation roomMember['domainObject'] = mockDomainObject; @@ -29,14 +29,14 @@ describe('RoomMember', () => { const { domainObject, ...props } = roomMember.getProps(); expect(domainObject).toEqual(undefined); - expect(props).toEqual(roomMemberProps); + expect(props).toEqual(roomMembershipProps); }); it('should get roomId', () => { - expect(roomMember.roomId).toEqual(roomMemberProps.roomId); + expect(roomMember.roomId).toEqual(roomMembershipProps.roomId); }); it('should get userGroupId', () => { - expect(roomMember.userGroupId).toEqual(roomMemberProps.userGroupId); + expect(roomMember.userGroupId).toEqual(roomMembershipProps.userGroupId); }); }); diff --git a/apps/server/src/modules/room-member/do/room-member.do.ts b/apps/server/src/modules/room-membership/do/room-membership.do.ts similarity index 75% rename from apps/server/src/modules/room-member/do/room-member.do.ts rename to apps/server/src/modules/room-membership/do/room-membership.do.ts index 8aeebfffbda..e8654923cb4 100644 --- a/apps/server/src/modules/room-member/do/room-member.do.ts +++ b/apps/server/src/modules/room-membership/do/room-membership.do.ts @@ -1,7 +1,7 @@ import { AuthorizableObject, DomainObject } from '@shared/domain/domain-object'; import { EntityId } from '@shared/domain/types'; -export interface RoomMemberProps extends AuthorizableObject { +export interface RoomMembershipProps extends AuthorizableObject { id: EntityId; roomId: EntityId; userGroupId: EntityId; @@ -9,12 +9,12 @@ export interface RoomMemberProps extends AuthorizableObject { updatedAt: Date; } -export class RoomMember extends DomainObject { - public constructor(props: RoomMemberProps) { +export class RoomMembership extends DomainObject { + public constructor(props: RoomMembershipProps) { super(props); } - public getProps(): RoomMemberProps { + public getProps(): RoomMembershipProps { // Note: Propagated hotfix. Will be resolved with mikro-orm update. Look at the comment in board-node.do.ts. // eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/ban-ts-comment diff --git a/apps/server/src/modules/room-membership/index.ts b/apps/server/src/modules/room-membership/index.ts new file mode 100644 index 00000000000..be6ccd4b3ac --- /dev/null +++ b/apps/server/src/modules/room-membership/index.ts @@ -0,0 +1,9 @@ +import { RoomMembershipEntity } from './repo/entity'; +import { RoomMembershipRepo } from './repo/room-membership.repo'; +import { RoomMembershipService } from './service/room-membership.service'; + +export * from './do/room-membership.do'; +export * from './room-membership.module'; +export { RoomMembershipEntity, RoomMembershipRepo, RoomMembershipService }; + +export { UserWithRoomRoles, RoomMembershipAuthorizable } from './do/room-membership-authorizable.do'; diff --git a/apps/server/src/modules/room-membership/repo/entity/index.ts b/apps/server/src/modules/room-membership/repo/entity/index.ts new file mode 100644 index 00000000000..43e58e0db14 --- /dev/null +++ b/apps/server/src/modules/room-membership/repo/entity/index.ts @@ -0,0 +1 @@ +export * from './room-membership.entity'; diff --git a/apps/server/src/modules/room-member/repo/entity/room-member.entity.ts b/apps/server/src/modules/room-membership/repo/entity/room-membership.entity.ts similarity index 67% rename from apps/server/src/modules/room-member/repo/entity/room-member.entity.ts rename to apps/server/src/modules/room-membership/repo/entity/room-membership.entity.ts index 3aacb3f1069..f9b9c37bebd 100644 --- a/apps/server/src/modules/room-member/repo/entity/room-member.entity.ts +++ b/apps/server/src/modules/room-membership/repo/entity/room-membership.entity.ts @@ -3,9 +3,9 @@ import { AuthorizableObject } from '@shared/domain/domain-object'; import { ObjectIdType } from '@shared/repo/types/object-id.type'; import { BaseEntityWithTimestamps } from '@shared/domain/entity/base.entity'; import { EntityId } from '@shared/domain/types'; -import { RoomMember } from '../../do/room-member.do'; +import { RoomMembership } from '../../do/room-membership.do'; -export interface RoomMemberEntityProps extends AuthorizableObject { +export interface RoomMembershipEntityProps extends AuthorizableObject { id: EntityId; roomId: EntityId; userGroupId: EntityId; @@ -13,9 +13,9 @@ export interface RoomMemberEntityProps extends AuthorizableObject { updatedAt: Date; } -@Entity({ tableName: 'room-members' }) +@Entity({ tableName: 'room-memberships' }) @Unique({ properties: ['roomId', 'userGroupId'] }) -export class RoomMemberEntity extends BaseEntityWithTimestamps implements RoomMemberEntityProps { +export class RoomMembershipEntity extends BaseEntityWithTimestamps implements RoomMembershipEntityProps { @Unique() @Property({ type: ObjectIdType, fieldName: 'room' }) roomId!: EntityId; @@ -24,5 +24,5 @@ export class RoomMemberEntity extends BaseEntityWithTimestamps implements RoomMe userGroupId!: EntityId; @Property({ persist: false }) - domainObject: RoomMember | undefined; + domainObject: RoomMembership | undefined; } diff --git a/apps/server/src/modules/room-membership/repo/room-membership-domain.mapper.spec.ts b/apps/server/src/modules/room-membership/repo/room-membership-domain.mapper.spec.ts new file mode 100644 index 00000000000..74ae9033575 --- /dev/null +++ b/apps/server/src/modules/room-membership/repo/room-membership-domain.mapper.spec.ts @@ -0,0 +1,93 @@ +import { RoomMembership, RoomMembershipProps } from '../do/room-membership.do'; +import { roomMembershipEntityFactory } from '../testing'; +import { RoomMembershipEntity } from './entity'; +import { RoomMembershipDomainMapper } from './room-membership-domain.mapper'; + +describe('RoomMembershipDomainMapper', () => { + describe('mapEntityToDo', () => { + it('should correctly map roomMembershipEntity to RoomMembership domain object', () => { + const roomMembershipEntity = { + id: '1', + } as RoomMembershipEntity; + + const result = RoomMembershipDomainMapper.mapEntityToDo(roomMembershipEntity); + + expect(result).toBeInstanceOf(RoomMembership); + expect(result.getProps()).toEqual({ + id: '1', + }); + }); + + it('should return existing domainObject if present, regardless of entity properties', () => { + const existingRoomMember = new RoomMembership({ + id: '1', + roomId: 'r1', + userGroupId: 'ug1', + createdAt: new Date('2023-01-01'), + updatedAt: new Date('2023-01-01'), + }); + + const roomMembershipEntity = { + id: '1', + domainObject: existingRoomMember, + } as RoomMembershipEntity; + + const result = RoomMembershipDomainMapper.mapEntityToDo(roomMembershipEntity); + + expect(result).toBe(existingRoomMember); + expect(result).toBeInstanceOf(RoomMembership); + expect(result.getProps()).toEqual({ + id: '1', + roomId: 'r1', + userGroupId: 'ug1', + createdAt: new Date('2023-01-01'), + updatedAt: new Date('2023-01-01'), + }); + expect(result.getProps().id).toBe('1'); + expect(result.getProps().id).toBe(roomMembershipEntity.id); + }); + + it('should wrap the actual entity reference in the domain object', () => { + const roomMembershipEntity = { + id: '1', + } as RoomMembershipEntity; + + const result = RoomMembershipDomainMapper.mapEntityToDo(roomMembershipEntity); + // @ts-expect-error check necessary + const { props } = result; + + expect(props === roomMembershipEntity).toBe(true); + }); + }); + + describe('mapDoToEntity', () => { + describe('when domain object props are instanceof roomMembershipEntity', () => { + it('should return the entity', () => { + const roomMembershipEntity = roomMembershipEntityFactory.build(); + const roomMember = new RoomMembership(roomMembershipEntity); + + const result = RoomMembershipDomainMapper.mapDoToEntity(roomMember); + + expect(result).toBe(roomMembershipEntity); + }); + }); + + describe('when domain object props are not instanceof roomMembershipEntity', () => { + it('should convert them to an entity and return it', () => { + const roomMembershipEntity: RoomMembershipProps = { + id: '66d581c3ef74c548a4efea1d', + roomId: '66d581c3ef74c548a4efea1a', + userGroupId: '66d581c3ef74c548a4efea1b', + createdAt: new Date('2024-10-1'), + updatedAt: new Date('2024-10-1'), + }; + const room = new RoomMembership(roomMembershipEntity); + + const result = RoomMembershipDomainMapper.mapDoToEntity(room); + + expect(result).toBeInstanceOf(RoomMembershipEntity); + expect(result).toMatchObject(roomMembershipEntity); + }); + }); + }); +}); diff --git a/apps/server/src/modules/room-membership/repo/room-membership-domain.mapper.ts b/apps/server/src/modules/room-membership/repo/room-membership-domain.mapper.ts new file mode 100644 index 00000000000..355a366e536 --- /dev/null +++ b/apps/server/src/modules/room-membership/repo/room-membership-domain.mapper.ts @@ -0,0 +1,37 @@ +import { RoomMembership } from '../do/room-membership.do'; +import { RoomMembershipEntity } from './entity'; + +export class RoomMembershipDomainMapper { + static mapEntityToDo(roomMembershipEntity: RoomMembershipEntity): RoomMembership { + // check identity map reference + if (roomMembershipEntity.domainObject) { + return roomMembershipEntity.domainObject; + } + + const roomMember = new RoomMembership(roomMembershipEntity); + + // attach to identity map + roomMembershipEntity.domainObject = roomMember; + + return roomMember; + } + + static mapDoToEntity(roomMember: RoomMembership): RoomMembershipEntity { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const { props } = roomMember; + + if (!(props instanceof RoomMembershipEntity)) { + const entity = new RoomMembershipEntity(); + Object.assign(entity, props); + + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + roomMember.props = entity; + + return entity; + } + + return props; + } +} diff --git a/apps/server/src/modules/room-member/repo/room-member.repo.spec.ts b/apps/server/src/modules/room-membership/repo/room-membership.repo.spec.ts similarity index 63% rename from apps/server/src/modules/room-member/repo/room-member.repo.spec.ts rename to apps/server/src/modules/room-membership/repo/room-membership.repo.spec.ts index 3cf9364019e..27afbe63c6a 100644 --- a/apps/server/src/modules/room-member/repo/room-member.repo.spec.ts +++ b/apps/server/src/modules/room-membership/repo/room-membership.repo.spec.ts @@ -3,23 +3,23 @@ import { NotFoundError } from '@mikro-orm/core'; import { EntityManager, ObjectId } from '@mikro-orm/mongodb'; import { Test, TestingModule } from '@nestjs/testing'; import { cleanupCollections } from '@shared/testing'; -import { RoomMember } from '../do/room-member.do'; -import { roomMemberEntityFactory, roomMemberFactory } from '../testing'; -import { RoomMemberEntity } from './entity'; -import { RoomMemberRepo } from './room-member.repo'; +import { RoomMembership } from '../do/room-membership.do'; +import { roomMembershipEntityFactory, roomMembershipFactory } from '../testing'; +import { RoomMembershipEntity } from './entity'; +import { RoomMembershipRepo } from './room-membership.repo'; -describe('RoomMemberRepo', () => { +describe('RoomMembershipRepo', () => { let module: TestingModule; - let repo: RoomMemberRepo; + let repo: RoomMembershipRepo; let em: EntityManager; beforeAll(async () => { module = await Test.createTestingModule({ imports: [MongoMemoryDatabaseModule.forRoot()], - providers: [RoomMemberRepo], + providers: [RoomMembershipRepo], }).compile(); - repo = module.get(RoomMemberRepo); + repo = module.get(RoomMembershipRepo); em = module.get(EntityManager); }); @@ -33,20 +33,20 @@ describe('RoomMemberRepo', () => { describe('findByRoomId', () => { const setup = async () => { - const roomMemberEntity = roomMemberEntityFactory.buildWithId(); - await em.persistAndFlush([roomMemberEntity]); + const roomMembershipEntity = roomMembershipEntityFactory.buildWithId(); + await em.persistAndFlush([roomMembershipEntity]); em.clear(); - return { roomMemberEntity }; + return { roomMembershipEntity }; }; it('should find room member by roomId', async () => { - const { roomMemberEntity } = await setup(); + const { roomMembershipEntity } = await setup(); - const roomMember = await repo.findByRoomId(roomMemberEntity.roomId); + const roomMember = await repo.findByRoomId(roomMembershipEntity.roomId); expect(roomMember).toBeDefined(); - expect(roomMember?.getProps()).toEqual(roomMemberEntity); + expect(roomMember?.getProps()).toEqual(roomMembershipEntity); }); }); @@ -56,9 +56,9 @@ describe('RoomMemberRepo', () => { const roomId2 = new ObjectId().toHexString(); const roomMemberEntities = [ - roomMemberEntityFactory.buildWithId({ roomId: roomId1 }), - roomMemberEntityFactory.buildWithId({ roomId: roomId1 }), - roomMemberEntityFactory.buildWithId({ roomId: roomId2 }), + roomMembershipEntityFactory.buildWithId({ roomId: roomId1 }), + roomMembershipEntityFactory.buildWithId({ roomId: roomId1 }), + roomMembershipEntityFactory.buildWithId({ roomId: roomId2 }), ]; await em.persistAndFlush(roomMemberEntities); @@ -80,9 +80,9 @@ describe('RoomMemberRepo', () => { const setup = async () => { const groupId = new ObjectId().toHexString(); const roomMemberEntities = [ - roomMemberEntityFactory.build({ userGroupId: groupId }), - roomMemberEntityFactory.build({ userGroupId: groupId }), - roomMemberEntityFactory.build({ userGroupId: new ObjectId().toHexString() }), + roomMembershipEntityFactory.build({ userGroupId: groupId }), + roomMembershipEntityFactory.build({ userGroupId: groupId }), + roomMembershipEntityFactory.build({ userGroupId: new ObjectId().toHexString() }), ]; await em.persistAndFlush(roomMemberEntities); @@ -102,7 +102,7 @@ describe('RoomMemberRepo', () => { describe('save', () => { const setup = () => { - const roomMembers = roomMemberFactory.buildList(3); + const roomMembers = roomMembershipFactory.buildList(3); return { roomMembers }; }; @@ -110,7 +110,7 @@ describe('RoomMemberRepo', () => { const { roomMembers } = setup(); await repo.save(roomMembers[0]); - const result = await em.findOneOrFail(RoomMemberEntity, roomMembers[0].id); + const result = await em.findOneOrFail(RoomMembershipEntity, roomMembers[0].id); expect(roomMembers[0].getProps()).toMatchObject(result); }); @@ -119,7 +119,7 @@ describe('RoomMemberRepo', () => { const { roomMembers } = setup(); await repo.save(roomMembers); - const result = await em.find(RoomMemberEntity, { id: { $in: roomMembers.map((r) => r.id) } }); + const result = await em.find(RoomMembershipEntity, { id: { $in: roomMembers.map((r) => r.id) } }); expect(result.length).toBe(roomMembers.length); }); @@ -127,9 +127,9 @@ describe('RoomMemberRepo', () => { describe('delete', () => { const setup = async () => { - const roomMemberEntities = roomMemberEntityFactory.buildListWithId(3); + const roomMemberEntities = roomMembershipEntityFactory.buildListWithId(3); await em.persistAndFlush(roomMemberEntities); - const roomMembers = roomMemberEntities.map((entity) => new RoomMember(entity)); + const roomMembers = roomMemberEntities.map((entity) => new RoomMembership(entity)); em.clear(); return { roomMembers }; @@ -140,7 +140,7 @@ describe('RoomMemberRepo', () => { await repo.delete(roomMembers[0]); - await expect(em.findOneOrFail(RoomMemberEntity, roomMembers[0].id)).rejects.toThrow(NotFoundError); + await expect(em.findOneOrFail(RoomMembershipEntity, roomMembers[0].id)).rejects.toThrow(NotFoundError); }); it('should be able to delete many rooms', async () => { @@ -148,7 +148,7 @@ describe('RoomMemberRepo', () => { await repo.delete(roomMembers); - const remainingCount = await em.count(RoomMemberEntity); + const remainingCount = await em.count(RoomMembershipEntity); expect(remainingCount).toBe(0); }); }); diff --git a/apps/server/src/modules/room-membership/repo/room-membership.repo.ts b/apps/server/src/modules/room-membership/repo/room-membership.repo.ts new file mode 100644 index 00000000000..0512fca7dcc --- /dev/null +++ b/apps/server/src/modules/room-membership/repo/room-membership.repo.ts @@ -0,0 +1,64 @@ +import { Utils } from '@mikro-orm/core'; +import { EntityManager } from '@mikro-orm/mongodb'; +import { Injectable } from '@nestjs/common'; +import { EntityId } from '@shared/domain/types'; +import { RoomMembership } from '../do/room-membership.do'; +import { RoomMembershipEntity } from './entity'; +import { RoomMembershipDomainMapper } from './room-membership-domain.mapper'; + +@Injectable() +export class RoomMembershipRepo { + constructor(private readonly em: EntityManager) {} + + async findByRoomId(roomId: EntityId): Promise { + const roomMemberEntities = await this.em.findOne(RoomMembershipEntity, { roomId }); + if (!roomMemberEntities) return null; + + const roomMembers = RoomMembershipDomainMapper.mapEntityToDo(roomMemberEntities); + + return roomMembers; + } + + async findByRoomIds(roomIds: EntityId[]): Promise { + const entities = await this.em.find(RoomMembershipEntity, { roomId: { $in: roomIds } }); + const roomMembers = entities.map((entity) => RoomMembershipDomainMapper.mapEntityToDo(entity)); + + return roomMembers; + } + + async findByGroupId(groupId: EntityId): Promise { + const entities = await this.em.find(RoomMembershipEntity, { userGroupId: groupId }); + const roomMembers = entities.map((entity) => RoomMembershipDomainMapper.mapEntityToDo(entity)); + + return roomMembers; + } + + async findByGroupIds(groupIds: EntityId[]): Promise { + const entities = await this.em.find(RoomMembershipEntity, { userGroupId: { $in: groupIds } }); + const roomMembers = entities.map((entity) => RoomMembershipDomainMapper.mapEntityToDo(entity)); + + return roomMembers; + } + + async save(roomMember: RoomMembership | RoomMembership[]): Promise { + const roomMembers = Utils.asArray(roomMember); + + roomMembers.forEach((member) => { + const entity = RoomMembershipDomainMapper.mapDoToEntity(member); + this.em.persist(entity); + }); + + await this.em.flush(); + } + + async delete(roomMember: RoomMembership | RoomMembership[]): Promise { + const roomMembers = Utils.asArray(roomMember); + + roomMembers.forEach((member) => { + const entity = RoomMembershipDomainMapper.mapDoToEntity(member); + this.em.remove(entity); + }); + + await this.em.flush(); + } +} diff --git a/apps/server/src/modules/room-membership/room-membership.module.ts b/apps/server/src/modules/room-membership/room-membership.module.ts new file mode 100644 index 00000000000..520d8c66628 --- /dev/null +++ b/apps/server/src/modules/room-membership/room-membership.module.ts @@ -0,0 +1,15 @@ +import { GroupModule } from '@modules/group'; +import { Module } from '@nestjs/common'; +import { CqrsModule } from '@nestjs/cqrs'; +import { AuthorizationModule } from '../authorization'; +import { RoleModule } from '../role'; +import { RoomMembershipRule } from './authorization/room-membership.rule'; +import { RoomMembershipRepo } from './repo/room-membership.repo'; +import { RoomMembershipService } from './service/room-membership.service'; + +@Module({ + imports: [AuthorizationModule, CqrsModule, GroupModule, RoleModule], + providers: [RoomMembershipService, RoomMembershipRepo, RoomMembershipRule], + exports: [RoomMembershipService], +}) +export class RoomMembershipModule {} diff --git a/apps/server/src/modules/room-member/service/room-member.service.spec.ts b/apps/server/src/modules/room-membership/service/room-membership.service.spec.ts similarity index 68% rename from apps/server/src/modules/room-member/service/room-member.service.spec.ts rename to apps/server/src/modules/room-membership/service/room-membership.service.spec.ts index c61c9108fee..d768c4abf68 100644 --- a/apps/server/src/modules/room-member/service/room-member.service.spec.ts +++ b/apps/server/src/modules/room-membership/service/room-membership.service.spec.ts @@ -4,18 +4,18 @@ import { Test, TestingModule } from '@nestjs/testing'; import { RoleName } from '@shared/domain/interface'; import { groupFactory, roleDtoFactory, userFactory } from '@shared/testing'; import { MongoMemoryDatabaseModule } from '@src/infra/database'; -import { GroupService, GroupTypes } from '@src/modules/group'; +import { GroupService, GroupTypes } from '@modules/group'; import { RoleService } from '@modules/role'; import { roomFactory } from '@modules/room/testing'; -import { RoomMemberAuthorizable } from '../do/room-member-authorizable.do'; -import { RoomMemberRepo } from '../repo/room-member.repo'; -import { roomMemberFactory } from '../testing'; -import { RoomMemberService } from './room-member.service'; +import { RoomMembershipAuthorizable } from '../do/room-membership-authorizable.do'; +import { RoomMembershipRepo } from '../repo/room-membership.repo'; +import { roomMembershipFactory } from '../testing'; +import { RoomMembershipService } from './room-membership.service'; -describe('RoomMemberService', () => { +describe('RoomMembershipService', () => { let module: TestingModule; - let service: RoomMemberService; - let roomMemberRepo: DeepMocked; + let service: RoomMembershipService; + let roomMembershipRepo: DeepMocked; let groupService: DeepMocked; let roleService: DeepMocked; @@ -23,14 +23,14 @@ describe('RoomMemberService', () => { module = await Test.createTestingModule({ imports: [MongoMemoryDatabaseModule.forRoot()], providers: [ - RoomMemberService, + RoomMembershipService, { provide: GroupService, useValue: createMock(), }, { - provide: RoomMemberRepo, - useValue: createMock(), + provide: RoomMembershipRepo, + useValue: createMock(), }, { provide: RoleService, @@ -39,8 +39,8 @@ describe('RoomMemberService', () => { ], }).compile(); - service = module.get(RoomMemberService); - roomMemberRepo = module.get(RoomMemberRepo); + service = module.get(RoomMembershipService); + roomMembershipRepo = module.get(RoomMembershipRepo); groupService = module.get(GroupService); roleService = module.get(RoleService); }); @@ -60,10 +60,10 @@ describe('RoomMemberService', () => { const room = roomFactory.build(); const group = groupFactory.build({ type: GroupTypes.ROOM }); - roomMemberRepo.findByRoomId.mockResolvedValue(null); + roomMembershipRepo.findByRoomId.mockResolvedValue(null); groupService.createGroup.mockResolvedValue(group); groupService.addUserToGroup.mockResolvedValue(); - roomMemberRepo.save.mockResolvedValue(); + roomMembershipRepo.save.mockResolvedValue(); return { user, @@ -76,14 +76,14 @@ describe('RoomMemberService', () => { await service.addMembersToRoom(room.id, [{ userId: user.id, roleName: RoleName.ROOMEDITOR }]); - expect(roomMemberRepo.save).toHaveBeenCalled(); + expect(roomMembershipRepo.save).toHaveBeenCalled(); }); describe('when no user is provided', () => { it('should throw an exception', async () => { const { room } = setup(); - roomMemberRepo.findByRoomId.mockResolvedValue(null); + roomMembershipRepo.findByRoomId.mockResolvedValue(null); await expect(service.addMembersToRoom(room.id, [])).rejects.toThrow(); }); @@ -95,9 +95,9 @@ describe('RoomMemberService', () => { const user = userFactory.buildWithId(); const group = groupFactory.build({ type: GroupTypes.ROOM }); const room = roomFactory.build(); - const roomMember = roomMemberFactory.build({ roomId: room.id, userGroupId: group.id }); + const roomMember = roomMembershipFactory.build({ roomId: room.id, userGroupId: group.id }); - roomMemberRepo.findByRoomId.mockResolvedValue(roomMember); + roomMembershipRepo.findByRoomId.mockResolvedValue(roomMember); return { user, @@ -126,10 +126,10 @@ describe('RoomMemberService', () => { const room = roomFactory.build(); const group = groupFactory.build({ type: GroupTypes.ROOM }); - roomMemberRepo.findByRoomId.mockResolvedValue(null); + roomMembershipRepo.findByRoomId.mockResolvedValue(null); groupService.createGroup.mockResolvedValue(group); groupService.addUserToGroup.mockResolvedValue(); - roomMemberRepo.save.mockResolvedValue(); + roomMembershipRepo.save.mockResolvedValue(); return { user, @@ -140,7 +140,7 @@ describe('RoomMemberService', () => { describe('when roomMember does not exist', () => { it('should throw an exception', async () => { const { room } = setup(); - roomMemberRepo.findByRoomId.mockResolvedValue(null); + roomMembershipRepo.findByRoomId.mockResolvedValue(null); await expect(service.removeMembersFromRoom(room.id, [])).rejects.toThrowError(BadRequestException); }); @@ -152,9 +152,9 @@ describe('RoomMemberService', () => { const user = userFactory.buildWithId(); const group = groupFactory.build({ type: GroupTypes.ROOM }); const room = roomFactory.build(); - const roomMember = roomMemberFactory.build({ roomId: room.id, userGroupId: group.id }); + const roomMember = roomMembershipFactory.build({ roomId: room.id, userGroupId: group.id }); - roomMemberRepo.findByRoomId.mockResolvedValue(roomMember); + roomMembershipRepo.findByRoomId.mockResolvedValue(roomMember); groupService.findById.mockResolvedValue(group); return { @@ -178,22 +178,22 @@ describe('RoomMemberService', () => { describe('deleteRoomMember', () => { describe('when room member does not exist', () => { const setup = () => { - roomMemberRepo.findByRoomId.mockResolvedValue(null); + roomMembershipRepo.findByRoomId.mockResolvedValue(null); }; it('no nothing', async () => { setup(); await service.deleteRoomMember('roomId'); expect(groupService.delete).not.toHaveBeenCalled(); - expect(roomMemberRepo.delete).not.toHaveBeenCalled(); + expect(roomMembershipRepo.delete).not.toHaveBeenCalled(); }); }); describe('when room member exists', () => { const setup = () => { const group = groupFactory.build(); - const roomMember = roomMemberFactory.build({ userGroupId: group.id }); - roomMemberRepo.findByRoomId.mockResolvedValue(roomMember); + const roomMember = roomMembershipFactory.build({ userGroupId: group.id }); + roomMembershipRepo.findByRoomId.mockResolvedValue(roomMember); groupService.findById.mockResolvedValue(group); return { roomMember, group }; @@ -203,54 +203,54 @@ describe('RoomMemberService', () => { const { roomMember, group } = setup(); await service.deleteRoomMember(roomMember.roomId); expect(groupService.delete).toHaveBeenCalledWith(group); - expect(roomMemberRepo.delete).toHaveBeenCalledWith(roomMember); + expect(roomMembershipRepo.delete).toHaveBeenCalledWith(roomMember); }); }); }); - describe('getRoomMemberAuthorizable', () => { + describe('getRoomMembershipAuthorizable', () => { const setup = () => { const roomId = 'room123'; const userId = 'user456'; const groupId = 'group789'; const roleId = 'role101'; - const roomMember = roomMemberFactory.build({ roomId, userGroupId: groupId }); + const roomMember = roomMembershipFactory.build({ roomId, userGroupId: groupId }); const group = groupFactory.build({ id: groupId, users: [{ userId, roleId }] }); const role = roleDtoFactory.build({ id: roleId }); - roomMemberRepo.findByRoomId.mockResolvedValue(roomMember); + roomMembershipRepo.findByRoomId.mockResolvedValue(roomMember); groupService.findById.mockResolvedValue(group); roleService.findByIds.mockResolvedValue([role]); return { roomId, userId, groupId, roleId, roomMember, group, role }; }; - it('should return RoomMemberAuthorizable when room member exists', async () => { + it('should return RoomMembershipAuthorizable when room member exists', async () => { const { roomId, userId, roleId } = setup(); - const result = await service.getRoomMemberAuthorizable(roomId); + const result = await service.getRoomMembershipAuthorizable(roomId); - expect(result).toBeInstanceOf(RoomMemberAuthorizable); + expect(result).toBeInstanceOf(RoomMembershipAuthorizable); expect(result.roomId).toBe(roomId); expect(result.members).toHaveLength(1); expect(result.members[0].userId).toBe(userId); expect(result.members[0].roles[0].id).toBe(roleId); }); - it('should return empty RoomMemberAuthorizable when room member not exists', async () => { + it('should return empty RoomMembershipAuthorizable when room member not exists', async () => { const roomId = 'nonexistent'; - roomMemberRepo.findByRoomId.mockResolvedValue(null); + roomMembershipRepo.findByRoomId.mockResolvedValue(null); - const result = await service.getRoomMemberAuthorizable(roomId); + const result = await service.getRoomMembershipAuthorizable(roomId); - expect(result).toBeInstanceOf(RoomMemberAuthorizable); + expect(result).toBeInstanceOf(RoomMembershipAuthorizable); expect(result.roomId).toBe(roomId); expect(result.members).toHaveLength(0); }); }); - describe('getRoomMemberAuthorizablesByUserId', () => { + describe('getRoomMembershipAuthorizablesByUserId', () => { const setup = () => { const userId = 'user123'; const groupId1 = 'group456'; @@ -265,29 +265,29 @@ describe('RoomMemberService', () => { groupFactory.build({ id: groupId2, users: [{ userId, roleId: roleId2 }] }), ]; const roomMembers = [ - roomMemberFactory.build({ roomId: roomId1, userGroupId: groupId1 }), - roomMemberFactory.build({ roomId: roomId2, userGroupId: groupId2 }), + roomMembershipFactory.build({ roomId: roomId1, userGroupId: groupId1 }), + roomMembershipFactory.build({ roomId: roomId2, userGroupId: groupId2 }), ]; const roles = [roleDtoFactory.build({ id: roleId1 }), roleDtoFactory.build({ id: roleId2 })]; groupService.findGroups.mockResolvedValue({ data: groups, total: groups.length }); - roomMemberRepo.findByGroupIds.mockResolvedValue(roomMembers); + roomMembershipRepo.findByGroupIds.mockResolvedValue(roomMembers); roleService.findByIds.mockResolvedValue(roles); return { userId, roomMembers, roles }; }; - it('should return RoomMemberAuthorizables for user', async () => { + it('should return RoomMembershipAuthorizables for user', async () => { const { userId, roomMembers, roles } = setup(); - const result = await service.getRoomMemberAuthorizablesByUserId(userId); + const result = await service.getRoomMembershipAuthorizablesByUserId(userId); expect(result).toHaveLength(2); - expect(result[0]).toBeInstanceOf(RoomMemberAuthorizable); + expect(result[0]).toBeInstanceOf(RoomMembershipAuthorizable); expect(result[0].roomId).toBe(roomMembers[0].roomId); expect(result[0].members[0].userId).toBe(userId); expect(result[0].members[0].roles[0].id).toBe(roles[0].id); - expect(result[1]).toBeInstanceOf(RoomMemberAuthorizable); + expect(result[1]).toBeInstanceOf(RoomMembershipAuthorizable); expect(result[1].roomId).toBe(roomMembers[1].roomId); expect(result[1].members[0].userId).toBe(userId); expect(result[1].members[0].roles[0].id).toBe(roles[1].id); @@ -297,7 +297,7 @@ describe('RoomMemberService', () => { const { userId } = setup(); groupService.findGroups.mockResolvedValue({ data: [], total: 0 }); - const result = await service.getRoomMemberAuthorizablesByUserId(userId); + const result = await service.getRoomMembershipAuthorizablesByUserId(userId); expect(result).toHaveLength(0); }); diff --git a/apps/server/src/modules/room-member/service/room-member.service.ts b/apps/server/src/modules/room-membership/service/room-membership.service.ts similarity index 73% rename from apps/server/src/modules/room-member/service/room-member.service.ts rename to apps/server/src/modules/room-membership/service/room-membership.service.ts index 8ac26bdbe15..efd32e5f61f 100644 --- a/apps/server/src/modules/room-member/service/room-member.service.ts +++ b/apps/server/src/modules/room-membership/service/room-membership.service.ts @@ -1,18 +1,18 @@ import { BadRequestException, Injectable } from '@nestjs/common'; import { RoleName } from '@shared/domain/interface'; import { EntityId } from '@shared/domain/types'; -import { Group, GroupService, GroupTypes } from '@src/modules/group'; +import { Group, GroupService, GroupTypes } from '@modules/group'; import { ObjectId } from '@mikro-orm/mongodb'; -import { RoleDto, RoleService } from '@src/modules/role'; -import { RoomMember } from '../do/room-member.do'; -import { RoomMemberRepo } from '../repo/room-member.repo'; -import { RoomMemberAuthorizable, UserWithRoomRoles } from '../do/room-member-authorizable.do'; +import { RoleDto, RoleService } from '@modules/role'; +import { RoomMembership } from '../do/room-membership.do'; +import { RoomMembershipRepo } from '../repo/room-membership.repo'; +import { RoomMembershipAuthorizable, UserWithRoomRoles } from '../do/room-membership-authorizable.do'; @Injectable() -export class RoomMemberService { +export class RoomMembershipService { constructor( private readonly groupService: GroupService, - private readonly roomMembersRepo: RoomMemberRepo, + private readonly roomMembersRepo: RoomMembershipRepo, private readonly roleService: RoleService ) {} @@ -25,7 +25,7 @@ export class RoomMemberService { const group = await this.groupService.createGroup(`Room Members for Room ${roomId}`, GroupTypes.ROOM, schoolId); await this.groupService.addUsersToGroup(group.id, [{ userId, roleName }]); - const roomMember = new RoomMember({ + const roomMember = new RoomMembership({ id: new ObjectId().toHexString(), roomId, userGroupId: group.id, @@ -38,7 +38,11 @@ export class RoomMemberService { return roomMember; } - private buildRoomMemberAuthorizable(roomId: EntityId, group: Group, roleSet: RoleDto[]): RoomMemberAuthorizable { + private buildRoomMembershipAuthorizable( + roomId: EntityId, + group: Group, + roleSet: RoleDto[] + ): RoomMembershipAuthorizable { const members = group.users.map((groupUser): UserWithRoomRoles => { const roleDto = roleSet.find((role) => role.id === groupUser.roleId); if (roleDto === undefined) throw new BadRequestException('Role not found'); @@ -48,9 +52,9 @@ export class RoomMemberService { }; }); - const roomMemberAuthorizable = new RoomMemberAuthorizable(roomId, members); + const roomMembershipAuthorizable = new RoomMembershipAuthorizable(roomId, members); - return roomMemberAuthorizable; + return roomMembershipAuthorizable; } public async deleteRoomMember(roomId: EntityId) { @@ -92,27 +96,27 @@ export class RoomMemberService { await this.groupService.removeUsersFromGroup(group.id, userIds); } - public async getRoomMemberAuthorizablesByUserId(userId: EntityId): Promise { + public async getRoomMembershipAuthorizablesByUserId(userId: EntityId): Promise { const groupPage = await this.groupService.findGroups({ userId, groupTypes: [GroupTypes.ROOM] }); const groupIds = groupPage.data.map((group) => group.id); const roomMembers = await this.roomMembersRepo.findByGroupIds(groupIds); const roleIds = groupPage.data.flatMap((group) => group.users.map((groupUser) => groupUser.roleId)); const roleSet = await this.roleService.findByIds(roleIds); - const roomMemberAuthorizables = roomMembers + const roomMembershipAuthorizables = roomMembers .map((item) => { const group = groupPage.data.find((g) => g.id === item.userGroupId); if (!group) return null; - return this.buildRoomMemberAuthorizable(item.roomId, group, roleSet); + return this.buildRoomMembershipAuthorizable(item.roomId, group, roleSet); }) - .filter((item): item is RoomMemberAuthorizable => item !== null); + .filter((item): item is RoomMembershipAuthorizable => item !== null); - return roomMemberAuthorizables; + return roomMembershipAuthorizables; } - public async getRoomMemberAuthorizable(roomId: EntityId): Promise { + public async getRoomMembershipAuthorizable(roomId: EntityId): Promise { const roomMember = await this.roomMembersRepo.findByRoomId(roomId); if (roomMember === null) { - return new RoomMemberAuthorizable(roomId, []); + return new RoomMembershipAuthorizable(roomId, []); } const group = await this.groupService.findById(roomMember.userGroupId); const roleSet = await this.roleService.findByIds(group.users.map((groupUser) => groupUser.roleId)); @@ -126,8 +130,8 @@ export class RoomMemberService { }; }); - const roomMemberAuthorizable = new RoomMemberAuthorizable(roomId, members); + const roomMembershipAuthorizable = new RoomMembershipAuthorizable(roomId, members); - return roomMemberAuthorizable; + return roomMembershipAuthorizable; } } diff --git a/apps/server/src/modules/room-membership/testing/index.ts b/apps/server/src/modules/room-membership/testing/index.ts new file mode 100644 index 00000000000..a29c3fae4a1 --- /dev/null +++ b/apps/server/src/modules/room-membership/testing/index.ts @@ -0,0 +1,2 @@ +export { roomMembershipEntityFactory } from './room-membership-entity.factory'; +export { roomMembershipFactory } from './room-membership.factory'; diff --git a/apps/server/src/modules/room-member/testing/room-member-entity.factory.ts b/apps/server/src/modules/room-membership/testing/room-membership-entity.factory.ts similarity index 57% rename from apps/server/src/modules/room-member/testing/room-member-entity.factory.ts rename to apps/server/src/modules/room-membership/testing/room-membership-entity.factory.ts index b63f70ecffd..c58746adf96 100644 --- a/apps/server/src/modules/room-member/testing/room-member-entity.factory.ts +++ b/apps/server/src/modules/room-membership/testing/room-membership-entity.factory.ts @@ -1,9 +1,9 @@ import { ObjectId } from '@mikro-orm/mongodb'; import { EntityFactory } from '@shared/testing/factory/entity.factory'; -import { RoomMemberEntity, RoomMemberEntityProps } from '../repo/entity/room-member.entity'; +import { RoomMembershipEntity, RoomMembershipEntityProps } from '../repo/entity/room-membership.entity'; -export const roomMemberEntityFactory = EntityFactory.define( - RoomMemberEntity, +export const roomMembershipEntityFactory = EntityFactory.define( + RoomMembershipEntity, () => { return { id: new ObjectId().toHexString(), diff --git a/apps/server/src/modules/room-member/testing/room-member.factory.ts b/apps/server/src/modules/room-membership/testing/room-membership.factory.ts similarity index 55% rename from apps/server/src/modules/room-member/testing/room-member.factory.ts rename to apps/server/src/modules/room-membership/testing/room-membership.factory.ts index 829f0f1708c..70c80b05a93 100644 --- a/apps/server/src/modules/room-member/testing/room-member.factory.ts +++ b/apps/server/src/modules/room-membership/testing/room-membership.factory.ts @@ -1,9 +1,9 @@ import { ObjectId } from '@mikro-orm/mongodb'; import { BaseFactory } from '@shared/testing'; -import { RoomMember, RoomMemberProps } from '../do/room-member.do'; +import { RoomMembership, RoomMembershipProps } from '../do/room-membership.do'; -export const roomMemberFactory = BaseFactory.define(RoomMember, () => { - const props: RoomMemberProps = { +export const roomMembershipFactory = BaseFactory.define(RoomMembership, () => { + const props: RoomMembershipProps = { id: new ObjectId().toHexString(), roomId: new ObjectId().toHexString(), userGroupId: new ObjectId().toHexString(), diff --git a/apps/server/src/modules/room/api/dto/request/create-room.body.params.ts b/apps/server/src/modules/room/api/dto/request/create-room.body.params.ts index d21d64fd10a..8cb204691a3 100644 --- a/apps/server/src/modules/room/api/dto/request/create-room.body.params.ts +++ b/apps/server/src/modules/room/api/dto/request/create-room.body.params.ts @@ -1,7 +1,7 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { SanitizeHtml } from '@shared/controller'; -import { RoomCreateProps } from '@src/modules/room/domain'; -import { RoomColor } from '@src/modules/room/domain/type'; +import { RoomCreateProps } from '@modules/room/domain'; +import { RoomColor } from '@modules/room/domain/type'; import { IsDate, IsEnum, IsOptional, IsString, MaxLength, MinLength } from 'class-validator'; export class CreateRoomBodyParams implements Omit { diff --git a/apps/server/src/modules/room/api/dto/request/update-room.body.params.ts b/apps/server/src/modules/room/api/dto/request/update-room.body.params.ts index 8afebced7d3..550357b7aca 100644 --- a/apps/server/src/modules/room/api/dto/request/update-room.body.params.ts +++ b/apps/server/src/modules/room/api/dto/request/update-room.body.params.ts @@ -1,7 +1,7 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { SanitizeHtml } from '@shared/controller'; -import { RoomUpdateProps } from '@src/modules/room/domain'; -import { RoomColor } from '@src/modules/room/domain/type'; +import { RoomUpdateProps } from '@modules/room/domain'; +import { RoomColor } from '@modules/room/domain/type'; import { IsDate, IsEnum, IsOptional, IsString, MaxLength, MinLength } from 'class-validator'; export class UpdateRoomBodyParams implements RoomUpdateProps { diff --git a/apps/server/src/modules/room/api/dto/response/room-board-item.response.ts b/apps/server/src/modules/room/api/dto/response/room-board-item.response.ts index 0840c1c1d87..f96d927741b 100644 --- a/apps/server/src/modules/room/api/dto/response/room-board-item.response.ts +++ b/apps/server/src/modules/room/api/dto/response/room-board-item.response.ts @@ -1,5 +1,5 @@ import { ApiProperty } from '@nestjs/swagger'; -import { BoardLayout } from '@src/modules/board'; +import { BoardLayout } from '@modules/board'; export class RoomBoardItemResponse { @ApiProperty() diff --git a/apps/server/src/modules/room/api/dto/response/room-details.response.ts b/apps/server/src/modules/room/api/dto/response/room-details.response.ts index 00b37e38236..bb3a385941e 100644 --- a/apps/server/src/modules/room/api/dto/response/room-details.response.ts +++ b/apps/server/src/modules/room/api/dto/response/room-details.response.ts @@ -1,6 +1,6 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Permission } from '@shared/domain/interface'; -import { RoomColor } from '@src/modules/room/domain/type'; +import { RoomColor } from '@modules/room/domain/type'; import { IsEnum } from 'class-validator'; export class RoomDetailsResponse { diff --git a/apps/server/src/modules/room/api/mapper/room.mapper.ts b/apps/server/src/modules/room/api/mapper/room.mapper.ts index cd5772fbd49..4edc7fc5a63 100644 --- a/apps/server/src/modules/room/api/mapper/room.mapper.ts +++ b/apps/server/src/modules/room/api/mapper/room.mapper.ts @@ -1,5 +1,5 @@ import { Page } from '@shared/domain/domainobject'; -import { ColumnBoard } from '@src/modules/board'; +import { ColumnBoard } from '@modules/board'; import { Room } from '../../domain/do/room.do'; import { RoomPaginationParams } from '../dto/request/room-pagination.params'; import { RoomBoardItemResponse } from '../dto/response/room-board-item.response'; diff --git a/apps/server/src/modules/room/api/room.uc.spec.ts b/apps/server/src/modules/room/api/room.uc.spec.ts index ab0e958ae6c..8910130093e 100644 --- a/apps/server/src/modules/room/api/room.uc.spec.ts +++ b/apps/server/src/modules/room/api/room.uc.spec.ts @@ -1,6 +1,6 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { AuthorizationService } from '@modules/authorization'; -import { RoomMemberRepo, RoomMemberService } from '@modules/room-member'; +import { RoomMembershipRepo, RoomMembershipService } from '@src/modules/room-membership'; import { UserService } from '@modules/user'; import { ConfigService } from '@nestjs/config'; import { Test, TestingModule } from '@nestjs/testing'; @@ -8,7 +8,7 @@ import { FeatureDisabledLoggableException } from '@shared/common/loggable-except import { Page } from '@shared/domain/domainobject'; import { IFindOptions } from '@shared/domain/interface'; import { setupEntities, userFactory } from '@shared/testing'; -import { ColumnBoardService } from '@src/modules/board'; +import { ColumnBoardService } from '@modules/board'; import { Room, RoomService } from '../domain'; import { RoomColor } from '../domain/type'; import { roomFactory } from '../testing'; @@ -20,7 +20,7 @@ describe('RoomUc', () => { let configService: DeepMocked; let roomService: DeepMocked; let authorizationService: DeepMocked; - let roomMemberService: DeepMocked; + let roomMembershipService: DeepMocked; beforeAll(async () => { module = await Test.createTestingModule({ providers: [ @@ -34,8 +34,8 @@ describe('RoomUc', () => { useValue: createMock(), }, { - provide: RoomMemberService, - useValue: createMock(), + provide: RoomMembershipService, + useValue: createMock(), }, { provide: ColumnBoardService, @@ -46,8 +46,8 @@ describe('RoomUc', () => { useValue: createMock(), }, { - provide: RoomMemberRepo, - useValue: createMock(), + provide: RoomMembershipRepo, + useValue: createMock(), }, { provide: UserService, @@ -60,7 +60,7 @@ describe('RoomUc', () => { configService = module.get(ConfigService); roomService = module.get(RoomService); authorizationService = module.get(AuthorizationService); - roomMemberService = module.get(RoomMemberService); + roomMembershipService = module.get(RoomMembershipService); await setupEntities(); }); @@ -117,7 +117,7 @@ describe('RoomUc', () => { authorizationService.checkOneOfPermissions.mockReturnValue(undefined); const room = roomFactory.build(); roomService.createRoom.mockResolvedValue(room); - roomMemberService.addMembersToRoom.mockRejectedValue(new Error('test')); + roomMembershipService.addMembersToRoom.mockRejectedValue(new Error('test')); return { user, room }; }; diff --git a/apps/server/src/modules/room/api/room.uc.ts b/apps/server/src/modules/room/api/room.uc.ts index 0fe0cea00cf..2f7cb691c96 100644 --- a/apps/server/src/modules/room/api/room.uc.ts +++ b/apps/server/src/modules/room/api/room.uc.ts @@ -1,5 +1,5 @@ import { Action, AuthorizationService } from '@modules/authorization'; -import { RoomMemberAuthorizable, RoomMemberService, UserWithRoomRoles } from '@modules/room-member'; +import { RoomMembershipAuthorizable, RoomMembershipService, UserWithRoomRoles } from '@src/modules/room-membership'; import { UserService } from '@modules/user'; import { Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; @@ -7,7 +7,7 @@ import { FeatureDisabledLoggableException } from '@shared/common/loggable-except import { Page, UserDO } from '@shared/domain/domainobject'; import { IFindOptions, Permission, RoleName, RoomRole } from '@shared/domain/interface'; import { EntityId } from '@shared/domain/types'; -import { BoardExternalReferenceType, ColumnBoard, ColumnBoardService } from '@src/modules/board'; +import { BoardExternalReferenceType, ColumnBoard, ColumnBoardService } from '@modules/board'; import { Room, RoomService } from '../domain'; import { RoomConfig } from '../room.config'; import { CreateRoomBodyParams } from './dto/request/create-room.body.params'; @@ -19,7 +19,7 @@ export class RoomUc { constructor( private readonly configService: ConfigService, private readonly roomService: RoomService, - private readonly roomMemberService: RoomMemberService, + private readonly roomMembershipService: RoomMembershipService, private readonly columnBoardService: ColumnBoardService, private readonly userService: UserService, private readonly authorizationService: AuthorizationService @@ -40,7 +40,7 @@ export class RoomUc { this.authorizationService.checkOneOfPermissions(user, [Permission.ROOM_CREATE]); - await this.roomMemberService + await this.roomMembershipService .addMembersToRoom(room.id, [{ userId: user.id, roleName: RoleName.ROOMEDITOR }], user.school.id) .catch(async (err) => { await this.roomService.deleteRoom(room); @@ -54,8 +54,8 @@ export class RoomUc { this.checkFeatureEnabled(); const room = await this.roomService.getSingleRoom(roomId); - const roomMemberAuthorizable = await this.checkRoomAuthorization(userId, roomId, Action.read); - const permissions = this.getPermissions(userId, roomMemberAuthorizable); + const roomMembershipAuthorizable = await this.checkRoomAuthorization(userId, roomId, Action.read); + const permissions = this.getPermissions(userId, roomMembershipAuthorizable); return { room, permissions }; } @@ -85,8 +85,8 @@ export class RoomUc { this.checkFeatureEnabled(); const room = await this.roomService.getSingleRoom(roomId); - const roomMemberAuthorizable = await this.checkRoomAuthorization(userId, roomId, Action.write); - const permissions = this.getPermissions(userId, roomMemberAuthorizable); + const roomMembershipAuthorizable = await this.checkRoomAuthorization(userId, roomId, Action.write); + const permissions = this.getPermissions(userId, roomMembershipAuthorizable); await this.roomService.updateRoom(room, props); @@ -103,18 +103,18 @@ export class RoomUc { public async getRoomMembers(userId: EntityId, roomId: EntityId): Promise { this.checkFeatureEnabled(); - const roomMemberAuthorizable = await this.roomMemberService.getRoomMemberAuthorizable(roomId); + const roomMembershipAuthorizable = await this.roomMembershipService.getRoomMembershipAuthorizable(roomId); const currentUser = await this.authorizationService.getUserWithPermissions(userId); - this.authorizationService.checkPermission(currentUser, roomMemberAuthorizable, { + this.authorizationService.checkPermission(currentUser, roomMembershipAuthorizable, { action: Action.read, requiredPermissions: [], }); - const userIds = roomMemberAuthorizable.members.map((member) => member.userId); + const userIds = roomMembershipAuthorizable.members.map((member) => member.userId); const users = await this.userService.findByIds(userIds); const memberResponses = users.map((user) => { - const member = roomMemberAuthorizable.members.find((item) => item.userId === user.id); + const member = roomMembershipAuthorizable.members.find((item) => item.userId === user.id); if (!member) { /* istanbul ignore next */ throw new Error('User not found in room members'); @@ -132,7 +132,7 @@ export class RoomUc { ): Promise { this.checkFeatureEnabled(); await this.checkRoomAuthorization(currentUserId, roomId, Action.write); - await this.roomMemberService.addMembersToRoom(roomId, userIdsAndRoles); + await this.roomMembershipService.addMembersToRoom(roomId, userIdsAndRoles); } private mapToMember(member: UserWithRoomRoles, user: UserDO) { @@ -148,12 +148,12 @@ export class RoomUc { public async removeMembersFromRoom(currentUserId: EntityId, roomId: EntityId, userIds: EntityId[]): Promise { this.checkFeatureEnabled(); await this.checkRoomAuthorization(currentUserId, roomId, Action.write); - await this.roomMemberService.removeMembersFromRoom(roomId, userIds); + await this.roomMembershipService.removeMembersFromRoom(roomId, userIds); } private async getAuthorizedRoomIds(userId: EntityId, action: Action): Promise { const user = await this.authorizationService.getUserWithPermissions(userId); - const roomAuthorizables = await this.roomMemberService.getRoomMemberAuthorizablesByUserId(userId); + const roomAuthorizables = await this.roomMembershipService.getRoomMembershipAuthorizablesByUserId(userId); const authorizedRoomIds = roomAuthorizables.filter((item) => this.authorizationService.hasPermission(user, item, { action, requiredPermissions: [] }) @@ -167,16 +167,16 @@ export class RoomUc { roomId: EntityId, action: Action, requiredPermissions: Permission[] = [] - ): Promise { - const roomMemberAuthorizable = await this.roomMemberService.getRoomMemberAuthorizable(roomId); + ): Promise { + const roomMembershipAuthorizable = await this.roomMembershipService.getRoomMembershipAuthorizable(roomId); const user = await this.authorizationService.getUserWithPermissions(userId); - this.authorizationService.checkPermission(user, roomMemberAuthorizable, { action, requiredPermissions }); + this.authorizationService.checkPermission(user, roomMembershipAuthorizable, { action, requiredPermissions }); - return roomMemberAuthorizable; + return roomMembershipAuthorizable; } - private getPermissions(userId: EntityId, roomMemberAuthorizable: RoomMemberAuthorizable): Permission[] { - const permissions = roomMemberAuthorizable.members + private getPermissions(userId: EntityId, roomMembershipAuthorizable: RoomMembershipAuthorizable): Permission[] { + const permissions = roomMembershipAuthorizable.members .filter((member) => member.userId === userId) .flatMap((member) => member.roles) .flatMap((role) => role.permissions ?? []); diff --git a/apps/server/src/modules/room/api/test/room-add-members.api.spec.ts b/apps/server/src/modules/room/api/test/room-add-members.api.spec.ts index 7ba93b377e0..b5647dc3f47 100644 --- a/apps/server/src/modules/room/api/test/room-add-members.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-add-members.api.spec.ts @@ -10,9 +10,9 @@ import { groupEntityFactory, roleFactory, } from '@shared/testing'; -import { GroupEntityTypes } from '@src/modules/group/entity/group.entity'; -import { roomMemberEntityFactory } from '@src/modules/room-member/testing/room-member-entity.factory'; -import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; +import { GroupEntityTypes } from '@modules/group/entity/group.entity'; +import { roomMembershipEntityFactory } from '@src/modules/room-membership/testing/room-membership-entity.factory'; +import { ServerTestModule, serverConfig, type ServerConfig } from '@modules/server'; import { roomEntityFactory } from '../../testing/room-entity.factory'; describe('Room Controller (API)', () => { @@ -61,7 +61,7 @@ describe('Room Controller (API)', () => { externalSource: undefined, }); - const roomMembers = roomMemberEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }); + const roomMembers = roomMembershipEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }); await em.persistAndFlush([ room, roomMembers, diff --git a/apps/server/src/modules/room/api/test/room-create.api.spec.ts b/apps/server/src/modules/room/api/test/room-create.api.spec.ts index 48c93c5b4c6..0c965bdb0b9 100644 --- a/apps/server/src/modules/room/api/test/room-create.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-create.api.spec.ts @@ -2,9 +2,9 @@ import { EntityManager } from '@mikro-orm/mongodb'; import { HttpStatus, INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { TestApiClient, UserAndAccountTestFactory, cleanupCollections, roleFactory } from '@shared/testing'; -import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; -import { RoomMemberEntity } from '@src/modules/room-member'; -import { GroupEntity } from '@src/modules/group/entity'; +import { ServerTestModule, serverConfig, type ServerConfig } from '@modules/server'; +import { RoomMembershipEntity } from '@src/modules/room-membership'; +import { GroupEntity } from '@modules/group/entity'; import { Permission, RoleName } from '@shared/domain/interface'; import { RoomEntity } from '../../repo'; @@ -98,7 +98,7 @@ describe('Room Controller (API)', () => { const response = await loggedInClient.post(undefined, params); const roomId = (response.body as { id: string }).id; - const roomMember = await em.findOneOrFail(RoomMemberEntity, { roomId }); + const roomMember = await em.findOneOrFail(RoomMembershipEntity, { roomId }); const userGroup = await em.findOneOrFail(GroupEntity, { id: roomMember.userGroupId, diff --git a/apps/server/src/modules/room/api/test/room-delete.api.spec.ts b/apps/server/src/modules/room/api/test/room-delete.api.spec.ts index cd290922e6c..e5fb5c5bd0d 100644 --- a/apps/server/src/modules/room/api/test/room-delete.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-delete.api.spec.ts @@ -9,9 +9,9 @@ import { groupEntityFactory, roleFactory, } from '@shared/testing'; -import { GroupEntityTypes } from '@src/modules/group/entity/group.entity'; -import { roomMemberEntityFactory } from '@src/modules/room-member/testing/room-member-entity.factory'; -import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; +import { GroupEntityTypes } from '@modules/group/entity/group.entity'; +import { roomMembershipEntityFactory } from '@src/modules/room-membership/testing/room-membership-entity.factory'; +import { ServerTestModule, serverConfig, type ServerConfig } from '@modules/server'; import { RoomEntity } from '../../repo'; import { roomEntityFactory } from '../../testing/room-entity.factory'; @@ -103,7 +103,7 @@ describe('Room Controller (API)', () => { type: GroupEntityTypes.ROOM, users: [{ role, user: teacherUser }], }); - const roomMember = roomMemberEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + const roomMember = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); await em.persistAndFlush([room, roomMember, teacherAccount, teacherUser, userGroup, role]); em.clear(); diff --git a/apps/server/src/modules/room/api/test/room-get-boards.api.spec.ts b/apps/server/src/modules/room/api/test/room-get-boards.api.spec.ts index ff14ce174e9..89c70bba5b0 100644 --- a/apps/server/src/modules/room/api/test/room-get-boards.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-get-boards.api.spec.ts @@ -9,11 +9,11 @@ import { TestApiClient, UserAndAccountTestFactory, } from '@shared/testing'; -import { BoardExternalReferenceType } from '@src/modules/board'; -import { columnBoardEntityFactory } from '@src/modules/board/testing'; -import { GroupEntityTypes } from '@src/modules/group/entity'; -import { roomMemberEntityFactory } from '@src/modules/room-member/testing'; -import { serverConfig, ServerConfig, ServerTestModule } from '@src/modules/server'; +import { BoardExternalReferenceType } from '@modules/board'; +import { columnBoardEntityFactory } from '@modules/board/testing'; +import { GroupEntityTypes } from '@modules/group/entity'; +import { roomMembershipEntityFactory } from '@src/modules/room-membership/testing'; +import { serverConfig, ServerConfig, ServerTestModule } from '@modules/server'; import { roomEntityFactory } from '../../testing'; describe('Room Controller (API)', () => { @@ -109,7 +109,7 @@ describe('Room Controller (API)', () => { organization: studentUser.school, externalSource: undefined, }); - const roomMember = roomMemberEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }); + const roomMember = roomMembershipEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }); await em.persistAndFlush([room, board, studentAccount, studentUser, role, userGroupEntity, roomMember]); em.clear(); diff --git a/apps/server/src/modules/room/api/test/room-get.api.spec.ts b/apps/server/src/modules/room/api/test/room-get.api.spec.ts index 54961eb25eb..b246d22221e 100644 --- a/apps/server/src/modules/room/api/test/room-get.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-get.api.spec.ts @@ -9,9 +9,9 @@ import { groupEntityFactory, roleFactory, } from '@shared/testing'; -import { GroupEntityTypes } from '@src/modules/group/entity/group.entity'; -import { roomMemberEntityFactory } from '@src/modules/room-member/testing'; -import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; +import { GroupEntityTypes } from '@modules/group/entity/group.entity'; +import { roomMembershipEntityFactory } from '@src/modules/room-membership/testing'; +import { ServerTestModule, serverConfig, type ServerConfig } from '@modules/server'; import { roomEntityFactory } from '../../testing/room-entity.factory'; describe('Room Controller (API)', () => { @@ -104,7 +104,7 @@ describe('Room Controller (API)', () => { organization: studentUser.school, externalSource: undefined, }); - const roomMember = roomMemberEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }); + const roomMember = roomMembershipEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }); await em.persistAndFlush([room, studentAccount, studentUser, role, userGroupEntity, roomMember]); em.clear(); diff --git a/apps/server/src/modules/room/api/test/room-index.api.spec.ts b/apps/server/src/modules/room/api/test/room-index.api.spec.ts index 26b0cd141ad..212ca2db7af 100644 --- a/apps/server/src/modules/room/api/test/room-index.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-index.api.spec.ts @@ -10,9 +10,9 @@ import { groupEntityFactory, roleFactory, } from '@shared/testing'; -import { GroupEntityTypes } from '@src/modules/group/entity/group.entity'; -import { roomMemberEntityFactory } from '@src/modules/room-member/testing/room-member-entity.factory'; -import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; +import { GroupEntityTypes } from '@modules/group/entity/group.entity'; +import { roomMembershipEntityFactory } from '@src/modules/room-membership/testing/room-membership-entity.factory'; +import { ServerTestModule, serverConfig, type ServerConfig } from '@modules/server'; import { roomEntityFactory } from '../../testing/room-entity.factory'; import { RoomListResponse } from '../dto/response/room-list.response'; @@ -141,7 +141,7 @@ describe('Room Controller (API)', () => { externalSource: undefined, }); const roomMembers = rooms.map((room) => - roomMemberEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }) + roomMembershipEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }) ); await em.persistAndFlush([...rooms, ...roomMembers, studentAccount, studentUser, userGroupEntity]); em.clear(); diff --git a/apps/server/src/modules/room/api/test/room-members.api.spec.ts b/apps/server/src/modules/room/api/test/room-members.api.spec.ts index 80334fbaa08..98464e46772 100644 --- a/apps/server/src/modules/room/api/test/room-members.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-members.api.spec.ts @@ -11,9 +11,9 @@ import { roleFactory, userFactory, } from '@shared/testing'; -import { GroupEntityTypes } from '@src/modules/group/entity/group.entity'; -import { roomMemberEntityFactory } from '@src/modules/room-member/testing/room-member-entity.factory'; -import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; +import { GroupEntityTypes } from '@modules/group/entity/group.entity'; +import { roomMembershipEntityFactory } from '@src/modules/room-membership/testing/room-membership-entity.factory'; +import { ServerTestModule, serverConfig, type ServerConfig } from '@modules/server'; import { roomEntityFactory } from '../../testing/room-entity.factory'; import { RoomMemberListResponse } from '../dto/response/room-member.response'; @@ -71,7 +71,7 @@ describe('Room Controller (API)', () => { organization: teacherUser.school, externalSource: undefined, }); - const roomMembers = roomMemberEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }); + const roomMembers = roomMembershipEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }); await em.persistAndFlush([ room, roomMembers, diff --git a/apps/server/src/modules/room/api/test/room-remove-members.api.spec.ts b/apps/server/src/modules/room/api/test/room-remove-members.api.spec.ts index 6829f3f5cd9..c35d7bce1aa 100644 --- a/apps/server/src/modules/room/api/test/room-remove-members.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-remove-members.api.spec.ts @@ -10,9 +10,9 @@ import { groupEntityFactory, roleFactory, } from '@shared/testing'; -import { GroupEntityTypes } from '@src/modules/group/entity/group.entity'; -import { roomMemberEntityFactory } from '@src/modules/room-member/testing/room-member-entity.factory'; -import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; +import { GroupEntityTypes } from '@modules/group/entity/group.entity'; +import { roomMembershipEntityFactory } from '@src/modules/room-membership/testing/room-membership-entity.factory'; +import { ServerTestModule, serverConfig, type ServerConfig } from '@modules/server'; import { roomEntityFactory } from '../../testing/room-entity.factory'; describe('Room Controller (API)', () => { @@ -81,7 +81,7 @@ describe('Room Controller (API)', () => { externalSource: undefined, }); - const roomMembers = roomMemberEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }); + const roomMembers = roomMembershipEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }); await em.persistAndFlush([...Object.values(users), room, roomMembers, teacherAccount, userGroupEntity]); em.clear(); diff --git a/apps/server/src/modules/room/api/test/room-update.api.spec.ts b/apps/server/src/modules/room/api/test/room-update.api.spec.ts index 08ed5847d21..c77888b09af 100644 --- a/apps/server/src/modules/room/api/test/room-update.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-update.api.spec.ts @@ -9,8 +9,8 @@ import { groupEntityFactory, roleFactory, } from '@shared/testing'; -import { roomMemberEntityFactory } from '@src/modules/room-member/testing'; -import { ServerTestModule, serverConfig, type ServerConfig } from '@src/modules/server'; +import { roomMembershipEntityFactory } from '@src/modules/room-membership/testing'; +import { ServerTestModule, serverConfig, type ServerConfig } from '@modules/server'; import { RoomEntity } from '../../repo'; import { roomEntityFactory } from '../../testing'; @@ -106,7 +106,7 @@ describe('Room Controller (API)', () => { const userGroup = groupEntityFactory.buildWithId({ users: [{ role, user: teacherUser }], }); - const roomMember = roomMemberEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + const roomMember = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); await em.persistAndFlush([room, roomMember, teacherAccount, teacherUser, userGroup, role]); em.clear(); diff --git a/apps/server/src/modules/room/room-api.module.ts b/apps/server/src/modules/room/room-api.module.ts index 7405a83afe8..7711d7cd842 100644 --- a/apps/server/src/modules/room/room-api.module.ts +++ b/apps/server/src/modules/room/room-api.module.ts @@ -2,13 +2,13 @@ import { AuthorizationModule } from '@modules/authorization'; import { Module } from '@nestjs/common'; import { LoggerModule } from '@src/core/logger'; import { BoardModule } from '../board'; -import { RoomMemberModule } from '../room-member/room-member.module'; +import { RoomMembershipModule } from '../room-membership/room-membership.module'; import { UserModule } from '../user'; import { RoomController, RoomUc } from './api'; import { RoomModule } from './room.module'; @Module({ - imports: [RoomModule, AuthorizationModule, LoggerModule, RoomMemberModule, BoardModule, UserModule], + imports: [RoomModule, AuthorizationModule, LoggerModule, RoomMembershipModule, BoardModule, UserModule], controllers: [RoomController], providers: [RoomUc], }) diff --git a/apps/server/src/modules/sharing/sharing-api.module.ts b/apps/server/src/modules/sharing/sharing-api.module.ts index e81e4a8b48e..3c30c03a883 100644 --- a/apps/server/src/modules/sharing/sharing-api.module.ts +++ b/apps/server/src/modules/sharing/sharing-api.module.ts @@ -1,13 +1,13 @@ +import { AuthorizationModule } from '@modules/authorization'; +import { BoardModule } from '@modules/board'; +import { LearnroomModule } from '@modules/learnroom'; +import { LessonModule } from '@modules/lesson'; +import { RoomModule } from '@modules/room'; +import { RoomMembershipModule } from '@src/modules/room-membership'; +import { SchoolModule } from '@modules/school'; +import { TaskModule } from '@modules/task'; import { Module } from '@nestjs/common'; import { LoggerModule } from '@src/core/logger'; -import { AuthorizationModule } from '../authorization'; -import { BoardModule } from '../board'; -import { LearnroomModule } from '../learnroom'; -import { LessonModule } from '../lesson'; -import { RoomModule } from '../room'; -import { RoomMemberModule } from '../room-member'; -import { SchoolModule } from '../school'; -import { TaskModule } from '../task'; import { ShareTokenController } from './controller/share-token.controller'; import { SharingModule } from './sharing.module'; import { ShareTokenUC } from './uc'; @@ -20,7 +20,7 @@ import { ShareTokenUC } from './uc'; LessonModule, TaskModule, BoardModule, - RoomMemberModule, + RoomMembershipModule, RoomModule, SchoolModule, LoggerModule, diff --git a/apps/server/src/modules/sharing/uc/share-token.uc.spec.ts b/apps/server/src/modules/sharing/uc/share-token.uc.spec.ts index 52fe2e0c9b9..3ef5be161e7 100644 --- a/apps/server/src/modules/sharing/uc/share-token.uc.spec.ts +++ b/apps/server/src/modules/sharing/uc/share-token.uc.spec.ts @@ -23,10 +23,10 @@ import { userFactory, } from '@shared/testing'; import { LegacyLogger } from '@src/core/logger'; -import { CopyColumnBoardParams } from '@src/modules/board/service/internal'; -import { StorageLocation } from '@src/modules/files-storage/interface'; -import { RoomService } from '@src/modules/room'; -import { RoomMemberService } from '@src/modules/room-member'; +import { CopyColumnBoardParams } from '@modules/board/service/internal'; +import { StorageLocation } from '@modules/files-storage/interface'; +import { RoomService } from '@modules/room'; +import { RoomMembershipService } from '@src/modules/room-membership'; import { ShareTokenContextType, ShareTokenParentType, ShareTokenPayload } from '../domainobject/share-token.do'; import { ShareTokenService } from '../service'; import { ShareTokenUC } from './share-token.uc'; @@ -91,8 +91,8 @@ describe('ShareTokenUC', () => { useValue: createMock(), }, { - provide: RoomMemberService, - useValue: createMock(), + provide: RoomMembershipService, + useValue: createMock(), }, { provide: ColumnBoardService, diff --git a/apps/server/src/modules/sharing/uc/share-token.uc.ts b/apps/server/src/modules/sharing/uc/share-token.uc.ts index fbc655190e8..b009c81cc7f 100644 --- a/apps/server/src/modules/sharing/uc/share-token.uc.ts +++ b/apps/server/src/modules/sharing/uc/share-token.uc.ts @@ -15,11 +15,11 @@ import { Course, User } from '@shared/domain/entity'; import { Permission } from '@shared/domain/interface'; import { EntityId } from '@shared/domain/types'; import { LegacyLogger } from '@src/core/logger'; -import { StorageLocationReference } from '@src/modules/board/service/internal'; -import { StorageLocation } from '@src/modules/files-storage/interface'; -import { RoomService } from '@src/modules/room'; -import { RoomMemberService } from '@src/modules/room-member'; -import { SchoolService } from '@src/modules/school'; +import { StorageLocationReference } from '@modules/board/service/internal'; +import { StorageLocation } from '@modules/files-storage/interface'; +import { RoomService } from '@modules/room'; +import { RoomMembershipService } from '@src/modules/room-membership'; +import { SchoolService } from '@modules/school'; import { ShareTokenContext, ShareTokenContextType, @@ -42,7 +42,7 @@ export class ShareTokenUC { private readonly lessonService: LessonService, private readonly taskService: TaskService, private readonly roomService: RoomService, - private readonly roomMemberService: RoomMemberService, + private readonly roomMembershipService: RoomMembershipService, private readonly columnBoardService: ColumnBoardService, private readonly schoolService: SchoolService, private readonly boardNodeAuthorizableService: BoardNodeAuthorizableService, @@ -249,11 +249,11 @@ export class ShareTokenUC { } private async checkRoomWritePermission(user: User, roomId: EntityId, permissions: Permission[] = []) { - const roomMemberAuthorizable = await this.roomMemberService.getRoomMemberAuthorizable(roomId); + const roomMembershipAuthorizable = await this.roomMembershipService.getRoomMembershipAuthorizable(roomId); this.authorizationService.checkPermission( user, - roomMemberAuthorizable, + roomMembershipAuthorizable, AuthorizationContextBuilder.write(permissions) ); } diff --git a/apps/server/src/shared/domain/entity/all-entities.ts b/apps/server/src/shared/domain/entity/all-entities.ts index 537d17b30d5..23c52671aeb 100644 --- a/apps/server/src/shared/domain/entity/all-entities.ts +++ b/apps/server/src/shared/domain/entity/all-entities.ts @@ -11,7 +11,7 @@ import { ExternalToolPseudonymEntity, PseudonymEntity } from '@modules/pseudonym import { RegistrationPinEntity } from '@modules/registration-pin/entity'; import { RocketChatUserEntity } from '@modules/rocketchat-user/entity'; import { RoomEntity } from '@modules/room/repo/entity'; -import { RoomMemberEntity } from '@src/modules/room-member/repo/entity/room-member.entity'; +import { RoomMembershipEntity } from '@modules/room-membership/repo/entity/room-membership.entity'; import { ShareToken } from '@modules/sharing/entity/share-token.entity'; import { SystemEntity } from '@modules/system/entity/system.entity'; import { TldrawDrawing } from '@modules/tldraw/entities'; @@ -77,7 +77,7 @@ export const ALL_ENTITIES = [ RocketChatUserEntity, Role, RoomEntity, - RoomMemberEntity, + RoomMembershipEntity, SchoolEntity, SchoolExternalToolEntity, SchoolNews, diff --git a/backup/setup/migrations.json b/backup/setup/migrations.json index 211631c68b9..9d02afcf4b9 100644 --- a/backup/setup/migrations.json +++ b/backup/setup/migrations.json @@ -340,5 +340,14 @@ "created_at": { "$date": "2024-11-14T15:43:35.024Z" } + }, + { + "_id": { + "$oid": "67477a7455d881b78f7a79fa" + }, + "name": "Migration202411271951208", + "created_at": { + "$date": "2024-11-27T20:00:52.582Z" + } } ] From 9fb359da92abfe13d815abe68ffabf325e95b941 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Thu, 28 Nov 2024 10:06:16 +0100 Subject: [PATCH 46/60] fix linter errors --- .../controller/api-test/content-element-delete.api.spec.ts | 1 + apps/server/src/modules/room/api/mapper/room.mapper.ts | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/server/src/modules/board/controller/api-test/content-element-delete.api.spec.ts b/apps/server/src/modules/board/controller/api-test/content-element-delete.api.spec.ts index 94f52c94eee..8f4619fa0b0 100644 --- a/apps/server/src/modules/board/controller/api-test/content-element-delete.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/content-element-delete.api.spec.ts @@ -19,6 +19,7 @@ import { drawingElementEntityFactory, richTextElementEntityFactory, } from '../../testing'; + const baseRouteName = '/elements'; class API { diff --git a/apps/server/src/modules/room/api/mapper/room.mapper.ts b/apps/server/src/modules/room/api/mapper/room.mapper.ts index 4edc7fc5a63..1f7d18ebc65 100644 --- a/apps/server/src/modules/room/api/mapper/room.mapper.ts +++ b/apps/server/src/modules/room/api/mapper/room.mapper.ts @@ -1,5 +1,6 @@ -import { Page } from '@shared/domain/domainobject'; import { ColumnBoard } from '@modules/board'; +import { Page } from '@shared/domain/domainobject'; +import { Permission } from '@shared/domain/interface'; import { Room } from '../../domain/do/room.do'; import { RoomPaginationParams } from '../dto/request/room-pagination.params'; import { RoomBoardItemResponse } from '../dto/response/room-board-item.response'; @@ -7,7 +8,6 @@ import { RoomBoardListResponse } from '../dto/response/room-board-list.response' import { RoomDetailsResponse } from '../dto/response/room-details.response'; import { RoomItemResponse } from '../dto/response/room-item.response'; import { RoomListResponse } from '../dto/response/room-list.response'; -import { Permission } from '@shared/domain/interface'; export class RoomMapper { static mapToRoomItemResponse(room: Room): RoomItemResponse { From 84a015802c4b8c0f4ae8a657c3051051f543af9b Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Thu, 28 Nov 2024 14:46:33 +0100 Subject: [PATCH 47/60] rename variables regarding roomMembership --- .../board-context-in-rooms.api.spec.ts | 4 +- .../api-test/board-create-in-room.api.spec.ts | 12 ++--- .../api-test/board-delete-in-room.api.spec.ts | 4 +- .../api-test/board-lookup-in-room.api.spec.ts | 4 +- .../board-update-title-in-room.api.spec.ts | 4 +- .../board-visibility-in-room.api.spec.ts | 4 +- .../service/internal/board-context.service.ts | 4 +- .../do/room-membership.do.spec.ts | 12 ++--- .../room-membership-domain.mapper.spec.ts | 10 ++-- .../repo/room-membership-domain.mapper.ts | 12 ++--- .../repo/room-membership.repo.spec.ts | 48 +++++++++---------- .../repo/room-membership.repo.ts | 32 ++++++------- .../service/room-membership.service.spec.ts | 48 +++++++++---------- .../api/test/room-add-members.api.spec.ts | 4 +- .../room/api/test/room-create.api.spec.ts | 6 +-- .../room/api/test/room-delete.api.spec.ts | 4 +- .../room/api/test/room-get-boards.api.spec.ts | 4 +- .../room/api/test/room-get.api.spec.ts | 4 +- .../room/api/test/room-index.api.spec.ts | 4 +- .../room/api/test/room-members.api.spec.ts | 4 +- .../api/test/room-remove-members.api.spec.ts | 4 +- .../room/api/test/room-update.api.spec.ts | 4 +- 22 files changed, 118 insertions(+), 118 deletions(-) diff --git a/apps/server/src/modules/board/controller/api-test/board-context-in-rooms.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-context-in-rooms.api.spec.ts index 9fe85f82b51..15b42ea15a8 100644 --- a/apps/server/src/modules/board/controller/api-test/board-context-in-rooms.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-context-in-rooms.api.spec.ts @@ -66,7 +66,7 @@ describe('board get context in room (api)', () => { const room = roomEntityFactory.buildWithId(); - const roomMember = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + const roomMembership = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); await em.persistAndFlush([ accountWithEditRole, @@ -79,7 +79,7 @@ describe('board get context in room (api)', () => { roleRoomView, userGroup, room, - roomMember, + roomMembership, ]); const columnBoardNode = columnBoardEntityFactory.build({ diff --git a/apps/server/src/modules/board/controller/api-test/board-create-in-room.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-create-in-room.api.spec.ts index a79c2559c43..bb10e3fb33c 100644 --- a/apps/server/src/modules/board/controller/api-test/board-create-in-room.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-create-in-room.api.spec.ts @@ -54,9 +54,9 @@ describe(`create board in room (api)`, () => { const room = roomEntityFactory.buildWithId(); - const roomMember = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + const roomMembership = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); - await em.persistAndFlush([account, user, role, userGroup, room, roomMember]); + await em.persistAndFlush([account, user, role, userGroup, room, roomMembership]); em.clear(); const loggedInClient = await testApiClient.login(account); @@ -170,9 +170,9 @@ describe(`create board in room (api)`, () => { const room = roomEntityFactory.buildWithId(); - const roomMember = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + const roomMembership = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); - await em.persistAndFlush([account, user, role, userGroup, room, roomMember]); + await em.persistAndFlush([account, user, role, userGroup, room, roomMembership]); em.clear(); const loggedInClient = await testApiClient.login(account); @@ -238,9 +238,9 @@ describe(`create board in room (api)`, () => { const room = roomEntityFactory.buildWithId(); - const roomMember = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + const roomMembership = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); - await em.persistAndFlush([account, user, role, userGroup, room, roomMember]); + await em.persistAndFlush([account, user, role, userGroup, room, roomMembership]); em.clear(); const loggedInClient = await testApiClient.login(account); diff --git a/apps/server/src/modules/board/controller/api-test/board-delete-in-room.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-delete-in-room.api.spec.ts index dbb50f06c32..c46ae270dfd 100644 --- a/apps/server/src/modules/board/controller/api-test/board-delete-in-room.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-delete-in-room.api.spec.ts @@ -61,7 +61,7 @@ describe(`board delete in room (api)`, () => { const room = roomEntityFactory.buildWithId(); - const roomMember = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + const roomMembership = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); await em.persistAndFlush([ accountWithEditRole, @@ -74,7 +74,7 @@ describe(`board delete in room (api)`, () => { roleRoomView, userGroup, room, - roomMember, + roomMembership, ]); const columnBoardNode = columnBoardEntityFactory.build({ diff --git a/apps/server/src/modules/board/controller/api-test/board-lookup-in-room.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-lookup-in-room.api.spec.ts index 76d617c9525..0f1dea74740 100644 --- a/apps/server/src/modules/board/controller/api-test/board-lookup-in-room.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-lookup-in-room.api.spec.ts @@ -62,7 +62,7 @@ describe(`board lookup in room (api)`, () => { const room = roomEntityFactory.buildWithId(); - const roomMember = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + const roomMembership = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); await em.persistAndFlush([ accountWithEditRole, @@ -75,7 +75,7 @@ describe(`board lookup in room (api)`, () => { roleRoomView, userGroup, room, - roomMember, + roomMembership, ]); const columnBoardNode = columnBoardEntityFactory.build({ diff --git a/apps/server/src/modules/board/controller/api-test/board-update-title-in-room.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-update-title-in-room.api.spec.ts index d074df6a0eb..168f2ac77f6 100644 --- a/apps/server/src/modules/board/controller/api-test/board-update-title-in-room.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-update-title-in-room.api.spec.ts @@ -68,7 +68,7 @@ describe(`board update title with room relation (api)`, () => { const room = roomEntityFactory.buildWithId(); - const roomMember = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + const roomMembership = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); await em.persistAndFlush([ accountWithEditRole, @@ -81,7 +81,7 @@ describe(`board update title with room relation (api)`, () => { roleRoomView, userGroup, room, - roomMember, + roomMembership, ]); const originalTitle = 'old title'; diff --git a/apps/server/src/modules/board/controller/api-test/board-visibility-in-room.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-visibility-in-room.api.spec.ts index 58a1669774e..8bd6a4b9eab 100644 --- a/apps/server/src/modules/board/controller/api-test/board-visibility-in-room.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-visibility-in-room.api.spec.ts @@ -67,7 +67,7 @@ describe(`board update visibility with room relation (api)`, () => { const room = roomEntityFactory.buildWithId(); - const roomMember = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + const roomMembership = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); await em.persistAndFlush([ accountWithEditRole, @@ -80,7 +80,7 @@ describe(`board update visibility with room relation (api)`, () => { roleRoomView, userGroup, room, - roomMember, + roomMembership, ]); const columnBoardNode = columnBoardEntityFactory.build({ diff --git a/apps/server/src/modules/board/service/internal/board-context.service.ts b/apps/server/src/modules/board/service/internal/board-context.service.ts index 32b6ef1df2d..efb1e51ddf2 100644 --- a/apps/server/src/modules/board/service/internal/board-context.service.ts +++ b/apps/server/src/modules/board/service/internal/board-context.service.ts @@ -32,7 +32,7 @@ export class BoardContextService { private async getFromRoom(roomId: EntityId): Promise { const roomMembershipAuthorizable = await this.roomMembershipService.getRoomMembershipAuthorizable(roomId); const usersWithRoles: UserWithBoardRoles[] = roomMembershipAuthorizable.members.map((member) => { - const roles = this.getBoardRolesFromRoomMember(member); + const roles = this.getBoardRolesFromRoomMembership(member); return { userId: member.userId, roles, @@ -84,7 +84,7 @@ export class BoardContextService { return usersWithRoles; } - private getBoardRolesFromRoomMember(member: UserWithRoomRoles): BoardRoles[] { + private getBoardRolesFromRoomMembership(member: UserWithRoomRoles): BoardRoles[] { const isReader = member.roles.flatMap((role) => role.permissions ?? []).includes(Permission.ROOM_VIEW); const isEditor = member.roles.flatMap((role) => role.permissions ?? []).includes(Permission.ROOM_EDIT); diff --git a/apps/server/src/modules/room-membership/do/room-membership.do.spec.ts b/apps/server/src/modules/room-membership/do/room-membership.do.spec.ts index 5dc0735fc0d..ee3d4746360 100644 --- a/apps/server/src/modules/room-membership/do/room-membership.do.spec.ts +++ b/apps/server/src/modules/room-membership/do/room-membership.do.spec.ts @@ -3,7 +3,7 @@ import { roomMembershipFactory } from '../testing'; import { RoomMembership, RoomMembershipProps } from './room-membership.do'; describe('RoomMembership', () => { - let roomMember: RoomMembership; + let roomMembership: RoomMembership; const roomMemberId: EntityId = 'roomMemberId'; const roomMembershipProps: RoomMembershipProps = { id: roomMemberId, @@ -14,29 +14,29 @@ describe('RoomMembership', () => { }; beforeEach(() => { - roomMember = new RoomMembership(roomMembershipProps); + roomMembership = new RoomMembership(roomMembershipProps); }); it('should props without domainObject', () => { const mockDomainObject = roomMembershipFactory.build(); // this tests the hotfix for the mikro-orm issue // eslint-disable-next-line @typescript-eslint/dot-notation - roomMember['domainObject'] = mockDomainObject; + roomMembership['domainObject'] = mockDomainObject; // eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - const { domainObject, ...props } = roomMember.getProps(); + const { domainObject, ...props } = roomMembership.getProps(); expect(domainObject).toEqual(undefined); expect(props).toEqual(roomMembershipProps); }); it('should get roomId', () => { - expect(roomMember.roomId).toEqual(roomMembershipProps.roomId); + expect(roomMembership.roomId).toEqual(roomMembershipProps.roomId); }); it('should get userGroupId', () => { - expect(roomMember.userGroupId).toEqual(roomMembershipProps.userGroupId); + expect(roomMembership.userGroupId).toEqual(roomMembershipProps.userGroupId); }); }); diff --git a/apps/server/src/modules/room-membership/repo/room-membership-domain.mapper.spec.ts b/apps/server/src/modules/room-membership/repo/room-membership-domain.mapper.spec.ts index 74ae9033575..e4d024be0c2 100644 --- a/apps/server/src/modules/room-membership/repo/room-membership-domain.mapper.spec.ts +++ b/apps/server/src/modules/room-membership/repo/room-membership-domain.mapper.spec.ts @@ -19,7 +19,7 @@ describe('RoomMembershipDomainMapper', () => { }); it('should return existing domainObject if present, regardless of entity properties', () => { - const existingRoomMember = new RoomMembership({ + const existingRoomMembership = new RoomMembership({ id: '1', roomId: 'r1', userGroupId: 'ug1', @@ -29,12 +29,12 @@ describe('RoomMembershipDomainMapper', () => { const roomMembershipEntity = { id: '1', - domainObject: existingRoomMember, + domainObject: existingRoomMembership, } as RoomMembershipEntity; const result = RoomMembershipDomainMapper.mapEntityToDo(roomMembershipEntity); - expect(result).toBe(existingRoomMember); + expect(result).toBe(existingRoomMembership); expect(result).toBeInstanceOf(RoomMembership); expect(result.getProps()).toEqual({ id: '1', @@ -64,9 +64,9 @@ describe('RoomMembershipDomainMapper', () => { describe('when domain object props are instanceof roomMembershipEntity', () => { it('should return the entity', () => { const roomMembershipEntity = roomMembershipEntityFactory.build(); - const roomMember = new RoomMembership(roomMembershipEntity); + const roomMembership = new RoomMembership(roomMembershipEntity); - const result = RoomMembershipDomainMapper.mapDoToEntity(roomMember); + const result = RoomMembershipDomainMapper.mapDoToEntity(roomMembership); expect(result).toBe(roomMembershipEntity); }); diff --git a/apps/server/src/modules/room-membership/repo/room-membership-domain.mapper.ts b/apps/server/src/modules/room-membership/repo/room-membership-domain.mapper.ts index 355a366e536..3538822a17a 100644 --- a/apps/server/src/modules/room-membership/repo/room-membership-domain.mapper.ts +++ b/apps/server/src/modules/room-membership/repo/room-membership-domain.mapper.ts @@ -8,18 +8,18 @@ export class RoomMembershipDomainMapper { return roomMembershipEntity.domainObject; } - const roomMember = new RoomMembership(roomMembershipEntity); + const roomMembership = new RoomMembership(roomMembershipEntity); // attach to identity map - roomMembershipEntity.domainObject = roomMember; + roomMembershipEntity.domainObject = roomMembership; - return roomMember; + return roomMembership; } - static mapDoToEntity(roomMember: RoomMembership): RoomMembershipEntity { + static mapDoToEntity(roomMembership: RoomMembership): RoomMembershipEntity { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - const { props } = roomMember; + const { props } = roomMembership; if (!(props instanceof RoomMembershipEntity)) { const entity = new RoomMembershipEntity(); @@ -27,7 +27,7 @@ export class RoomMembershipDomainMapper { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - roomMember.props = entity; + roomMembership.props = entity; return entity; } diff --git a/apps/server/src/modules/room-membership/repo/room-membership.repo.spec.ts b/apps/server/src/modules/room-membership/repo/room-membership.repo.spec.ts index 27afbe63c6a..5fb6b3a0932 100644 --- a/apps/server/src/modules/room-membership/repo/room-membership.repo.spec.ts +++ b/apps/server/src/modules/room-membership/repo/room-membership.repo.spec.ts @@ -43,10 +43,10 @@ describe('RoomMembershipRepo', () => { it('should find room member by roomId', async () => { const { roomMembershipEntity } = await setup(); - const roomMember = await repo.findByRoomId(roomMembershipEntity.roomId); + const roomMembership = await repo.findByRoomId(roomMembershipEntity.roomId); - expect(roomMember).toBeDefined(); - expect(roomMember?.getProps()).toEqual(roomMembershipEntity); + expect(roomMembership).toBeDefined(); + expect(roomMembership?.getProps()).toEqual(roomMembershipEntity); }); }); @@ -70,9 +70,9 @@ describe('RoomMembershipRepo', () => { it('should find room member by roomIds', async () => { const { roomId1, roomId2 } = await setup(); - const roomMembers = await repo.findByRoomIds([roomId1, roomId2]); + const roomMemberships = await repo.findByRoomIds([roomId1, roomId2]); - expect(roomMembers).toHaveLength(3); + expect(roomMemberships).toHaveLength(3); }); }); @@ -94,34 +94,34 @@ describe('RoomMembershipRepo', () => { it('should find room members by groupId', async () => { const { groupId } = await setup(); - const roomMembers = await repo.findByGroupId(groupId); + const roomMemberships = await repo.findByGroupId(groupId); - expect(roomMembers).toHaveLength(2); + expect(roomMemberships).toHaveLength(2); }); }); describe('save', () => { const setup = () => { - const roomMembers = roomMembershipFactory.buildList(3); - return { roomMembers }; + const roomMemberships = roomMembershipFactory.buildList(3); + return { roomMemberships }; }; it('should be able to persist a single room member', async () => { - const { roomMembers } = setup(); + const { roomMemberships } = setup(); - await repo.save(roomMembers[0]); - const result = await em.findOneOrFail(RoomMembershipEntity, roomMembers[0].id); + await repo.save(roomMemberships[0]); + const result = await em.findOneOrFail(RoomMembershipEntity, roomMemberships[0].id); - expect(roomMembers[0].getProps()).toMatchObject(result); + expect(roomMemberships[0].getProps()).toMatchObject(result); }); it('should be able to persist many room members', async () => { - const { roomMembers } = setup(); + const { roomMemberships } = setup(); - await repo.save(roomMembers); - const result = await em.find(RoomMembershipEntity, { id: { $in: roomMembers.map((r) => r.id) } }); + await repo.save(roomMemberships); + const result = await em.find(RoomMembershipEntity, { id: { $in: roomMemberships.map((r) => r.id) } }); - expect(result.length).toBe(roomMembers.length); + expect(result.length).toBe(roomMemberships.length); }); }); @@ -129,24 +129,24 @@ describe('RoomMembershipRepo', () => { const setup = async () => { const roomMemberEntities = roomMembershipEntityFactory.buildListWithId(3); await em.persistAndFlush(roomMemberEntities); - const roomMembers = roomMemberEntities.map((entity) => new RoomMembership(entity)); + const roomMemberships = roomMemberEntities.map((entity) => new RoomMembership(entity)); em.clear(); - return { roomMembers }; + return { roomMemberships }; }; it('should be able to delete a single room member', async () => { - const { roomMembers } = await setup(); + const { roomMemberships } = await setup(); - await repo.delete(roomMembers[0]); + await repo.delete(roomMemberships[0]); - await expect(em.findOneOrFail(RoomMembershipEntity, roomMembers[0].id)).rejects.toThrow(NotFoundError); + await expect(em.findOneOrFail(RoomMembershipEntity, roomMemberships[0].id)).rejects.toThrow(NotFoundError); }); it('should be able to delete many rooms', async () => { - const { roomMembers } = await setup(); + const { roomMemberships } = await setup(); - await repo.delete(roomMembers); + await repo.delete(roomMemberships); const remainingCount = await em.count(RoomMembershipEntity); expect(remainingCount).toBe(0); diff --git a/apps/server/src/modules/room-membership/repo/room-membership.repo.ts b/apps/server/src/modules/room-membership/repo/room-membership.repo.ts index 0512fca7dcc..5db8b3750ce 100644 --- a/apps/server/src/modules/room-membership/repo/room-membership.repo.ts +++ b/apps/server/src/modules/room-membership/repo/room-membership.repo.ts @@ -11,39 +11,39 @@ export class RoomMembershipRepo { constructor(private readonly em: EntityManager) {} async findByRoomId(roomId: EntityId): Promise { - const roomMemberEntities = await this.em.findOne(RoomMembershipEntity, { roomId }); - if (!roomMemberEntities) return null; + const roomMembershipEntities = await this.em.findOne(RoomMembershipEntity, { roomId }); + if (!roomMembershipEntities) return null; - const roomMembers = RoomMembershipDomainMapper.mapEntityToDo(roomMemberEntities); + const roomMemberships = RoomMembershipDomainMapper.mapEntityToDo(roomMembershipEntities); - return roomMembers; + return roomMemberships; } async findByRoomIds(roomIds: EntityId[]): Promise { const entities = await this.em.find(RoomMembershipEntity, { roomId: { $in: roomIds } }); - const roomMembers = entities.map((entity) => RoomMembershipDomainMapper.mapEntityToDo(entity)); + const roomMemberships = entities.map((entity) => RoomMembershipDomainMapper.mapEntityToDo(entity)); - return roomMembers; + return roomMemberships; } async findByGroupId(groupId: EntityId): Promise { const entities = await this.em.find(RoomMembershipEntity, { userGroupId: groupId }); - const roomMembers = entities.map((entity) => RoomMembershipDomainMapper.mapEntityToDo(entity)); + const roomMemberships = entities.map((entity) => RoomMembershipDomainMapper.mapEntityToDo(entity)); - return roomMembers; + return roomMemberships; } async findByGroupIds(groupIds: EntityId[]): Promise { const entities = await this.em.find(RoomMembershipEntity, { userGroupId: { $in: groupIds } }); - const roomMembers = entities.map((entity) => RoomMembershipDomainMapper.mapEntityToDo(entity)); + const roomMemberships = entities.map((entity) => RoomMembershipDomainMapper.mapEntityToDo(entity)); - return roomMembers; + return roomMemberships; } - async save(roomMember: RoomMembership | RoomMembership[]): Promise { - const roomMembers = Utils.asArray(roomMember); + async save(roomMembership: RoomMembership | RoomMembership[]): Promise { + const roomMemberships = Utils.asArray(roomMembership); - roomMembers.forEach((member) => { + roomMemberships.forEach((member) => { const entity = RoomMembershipDomainMapper.mapDoToEntity(member); this.em.persist(entity); }); @@ -51,10 +51,10 @@ export class RoomMembershipRepo { await this.em.flush(); } - async delete(roomMember: RoomMembership | RoomMembership[]): Promise { - const roomMembers = Utils.asArray(roomMember); + async delete(roomMembership: RoomMembership | RoomMembership[]): Promise { + const roomMemberships = Utils.asArray(roomMembership); - roomMembers.forEach((member) => { + roomMemberships.forEach((member) => { const entity = RoomMembershipDomainMapper.mapDoToEntity(member); this.em.remove(entity); }); diff --git a/apps/server/src/modules/room-membership/service/room-membership.service.spec.ts b/apps/server/src/modules/room-membership/service/room-membership.service.spec.ts index d768c4abf68..abc5f5f9fb2 100644 --- a/apps/server/src/modules/room-membership/service/room-membership.service.spec.ts +++ b/apps/server/src/modules/room-membership/service/room-membership.service.spec.ts @@ -95,14 +95,14 @@ describe('RoomMembershipService', () => { const user = userFactory.buildWithId(); const group = groupFactory.build({ type: GroupTypes.ROOM }); const room = roomFactory.build(); - const roomMember = roomMembershipFactory.build({ roomId: room.id, userGroupId: group.id }); + const roomMembership = roomMembershipFactory.build({ roomId: room.id, userGroupId: group.id }); - roomMembershipRepo.findByRoomId.mockResolvedValue(roomMember); + roomMembershipRepo.findByRoomId.mockResolvedValue(roomMembership); return { user, room, - roomMember, + roomMembership, group, }; }; @@ -137,7 +137,7 @@ describe('RoomMembershipService', () => { }; }; - describe('when roomMember does not exist', () => { + describe('when roomMembership does not exist', () => { it('should throw an exception', async () => { const { room } = setup(); roomMembershipRepo.findByRoomId.mockResolvedValue(null); @@ -152,15 +152,15 @@ describe('RoomMembershipService', () => { const user = userFactory.buildWithId(); const group = groupFactory.build({ type: GroupTypes.ROOM }); const room = roomFactory.build(); - const roomMember = roomMembershipFactory.build({ roomId: room.id, userGroupId: group.id }); + const roomMembership = roomMembershipFactory.build({ roomId: room.id, userGroupId: group.id }); - roomMembershipRepo.findByRoomId.mockResolvedValue(roomMember); + roomMembershipRepo.findByRoomId.mockResolvedValue(roomMembership); groupService.findById.mockResolvedValue(group); return { user, room, - roomMember, + roomMembership, group, }; }; @@ -175,7 +175,7 @@ describe('RoomMembershipService', () => { }); }); - describe('deleteRoomMember', () => { + describe('deleteRoomMembership', () => { describe('when room member does not exist', () => { const setup = () => { roomMembershipRepo.findByRoomId.mockResolvedValue(null); @@ -183,7 +183,7 @@ describe('RoomMembershipService', () => { it('no nothing', async () => { setup(); - await service.deleteRoomMember('roomId'); + await service.deleteRoomMembership('roomId'); expect(groupService.delete).not.toHaveBeenCalled(); expect(roomMembershipRepo.delete).not.toHaveBeenCalled(); }); @@ -192,18 +192,18 @@ describe('RoomMembershipService', () => { describe('when room member exists', () => { const setup = () => { const group = groupFactory.build(); - const roomMember = roomMembershipFactory.build({ userGroupId: group.id }); - roomMembershipRepo.findByRoomId.mockResolvedValue(roomMember); + const roomMembership = roomMembershipFactory.build({ userGroupId: group.id }); + roomMembershipRepo.findByRoomId.mockResolvedValue(roomMembership); groupService.findById.mockResolvedValue(group); - return { roomMember, group }; + return { roomMembership, group }; }; it('should call delete group and room member', async () => { - const { roomMember, group } = setup(); - await service.deleteRoomMember(roomMember.roomId); + const { roomMembership, group } = setup(); + await service.deleteRoomMembership(roomMembership.roomId); expect(groupService.delete).toHaveBeenCalledWith(group); - expect(roomMembershipRepo.delete).toHaveBeenCalledWith(roomMember); + expect(roomMembershipRepo.delete).toHaveBeenCalledWith(roomMembership); }); }); }); @@ -215,15 +215,15 @@ describe('RoomMembershipService', () => { const groupId = 'group789'; const roleId = 'role101'; - const roomMember = roomMembershipFactory.build({ roomId, userGroupId: groupId }); + const roomMembership = roomMembershipFactory.build({ roomId, userGroupId: groupId }); const group = groupFactory.build({ id: groupId, users: [{ userId, roleId }] }); const role = roleDtoFactory.build({ id: roleId }); - roomMembershipRepo.findByRoomId.mockResolvedValue(roomMember); + roomMembershipRepo.findByRoomId.mockResolvedValue(roomMembership); groupService.findById.mockResolvedValue(group); roleService.findByIds.mockResolvedValue([role]); - return { roomId, userId, groupId, roleId, roomMember, group, role }; + return { roomId, userId, groupId, roleId, roomMembership, group, role }; }; it('should return RoomMembershipAuthorizable when room member exists', async () => { @@ -264,31 +264,31 @@ describe('RoomMembershipService', () => { groupFactory.build({ id: groupId1, users: [{ userId, roleId: roleId1 }] }), groupFactory.build({ id: groupId2, users: [{ userId, roleId: roleId2 }] }), ]; - const roomMembers = [ + const roomMemberships = [ roomMembershipFactory.build({ roomId: roomId1, userGroupId: groupId1 }), roomMembershipFactory.build({ roomId: roomId2, userGroupId: groupId2 }), ]; const roles = [roleDtoFactory.build({ id: roleId1 }), roleDtoFactory.build({ id: roleId2 })]; groupService.findGroups.mockResolvedValue({ data: groups, total: groups.length }); - roomMembershipRepo.findByGroupIds.mockResolvedValue(roomMembers); + roomMembershipRepo.findByGroupIds.mockResolvedValue(roomMemberships); roleService.findByIds.mockResolvedValue(roles); - return { userId, roomMembers, roles }; + return { userId, roomMemberships, roles }; }; it('should return RoomMembershipAuthorizables for user', async () => { - const { userId, roomMembers, roles } = setup(); + const { userId, roomMemberships, roles } = setup(); const result = await service.getRoomMembershipAuthorizablesByUserId(userId); expect(result).toHaveLength(2); expect(result[0]).toBeInstanceOf(RoomMembershipAuthorizable); - expect(result[0].roomId).toBe(roomMembers[0].roomId); + expect(result[0].roomId).toBe(roomMemberships[0].roomId); expect(result[0].members[0].userId).toBe(userId); expect(result[0].members[0].roles[0].id).toBe(roles[0].id); expect(result[1]).toBeInstanceOf(RoomMembershipAuthorizable); - expect(result[1].roomId).toBe(roomMembers[1].roomId); + expect(result[1].roomId).toBe(roomMemberships[1].roomId); expect(result[1].members[0].userId).toBe(userId); expect(result[1].members[0].roles[0].id).toBe(roles[1].id); }); diff --git a/apps/server/src/modules/room/api/test/room-add-members.api.spec.ts b/apps/server/src/modules/room/api/test/room-add-members.api.spec.ts index b5647dc3f47..5fab1cced7e 100644 --- a/apps/server/src/modules/room/api/test/room-add-members.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-add-members.api.spec.ts @@ -61,10 +61,10 @@ describe('Room Controller (API)', () => { externalSource: undefined, }); - const roomMembers = roomMembershipEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }); + const roomMemberships = roomMembershipEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }); await em.persistAndFlush([ room, - roomMembers, + roomMemberships, teacherAccount, teacherUser, otherTeacherUser, diff --git a/apps/server/src/modules/room/api/test/room-create.api.spec.ts b/apps/server/src/modules/room/api/test/room-create.api.spec.ts index 0c965bdb0b9..eeca260725b 100644 --- a/apps/server/src/modules/room/api/test/room-create.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-create.api.spec.ts @@ -98,13 +98,13 @@ describe('Room Controller (API)', () => { const response = await loggedInClient.post(undefined, params); const roomId = (response.body as { id: string }).id; - const roomMember = await em.findOneOrFail(RoomMembershipEntity, { roomId }); + const roomMembership = await em.findOneOrFail(RoomMembershipEntity, { roomId }); const userGroup = await em.findOneOrFail(GroupEntity, { - id: roomMember.userGroupId, + id: roomMembership.userGroupId, }); - expect(roomMember).toBeDefined(); + expect(roomMembership).toBeDefined(); expect(userGroup).toBeDefined(); expect(userGroup.users).toHaveLength(1); expect(userGroup.users[0].user.id).toBe(teacherUser.id); diff --git a/apps/server/src/modules/room/api/test/room-delete.api.spec.ts b/apps/server/src/modules/room/api/test/room-delete.api.spec.ts index e5fb5c5bd0d..23d752e0abf 100644 --- a/apps/server/src/modules/room/api/test/room-delete.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-delete.api.spec.ts @@ -103,8 +103,8 @@ describe('Room Controller (API)', () => { type: GroupEntityTypes.ROOM, users: [{ role, user: teacherUser }], }); - const roomMember = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); - await em.persistAndFlush([room, roomMember, teacherAccount, teacherUser, userGroup, role]); + const roomMembership = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + await em.persistAndFlush([room, roomMembership, teacherAccount, teacherUser, userGroup, role]); em.clear(); const loggedInClient = await testApiClient.login(teacherAccount); diff --git a/apps/server/src/modules/room/api/test/room-get-boards.api.spec.ts b/apps/server/src/modules/room/api/test/room-get-boards.api.spec.ts index 89c70bba5b0..4f1646ec708 100644 --- a/apps/server/src/modules/room/api/test/room-get-boards.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-get-boards.api.spec.ts @@ -109,8 +109,8 @@ describe('Room Controller (API)', () => { organization: studentUser.school, externalSource: undefined, }); - const roomMember = roomMembershipEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }); - await em.persistAndFlush([room, board, studentAccount, studentUser, role, userGroupEntity, roomMember]); + const roomMembership = roomMembershipEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }); + await em.persistAndFlush([room, board, studentAccount, studentUser, role, userGroupEntity, roomMembership]); em.clear(); const loggedInClient = await testApiClient.login(studentAccount); diff --git a/apps/server/src/modules/room/api/test/room-get.api.spec.ts b/apps/server/src/modules/room/api/test/room-get.api.spec.ts index b246d22221e..719889d82ec 100644 --- a/apps/server/src/modules/room/api/test/room-get.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-get.api.spec.ts @@ -104,8 +104,8 @@ describe('Room Controller (API)', () => { organization: studentUser.school, externalSource: undefined, }); - const roomMember = roomMembershipEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }); - await em.persistAndFlush([room, studentAccount, studentUser, role, userGroupEntity, roomMember]); + const roomMembership = roomMembershipEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }); + await em.persistAndFlush([room, studentAccount, studentUser, role, userGroupEntity, roomMembership]); em.clear(); const loggedInClient = await testApiClient.login(studentAccount); diff --git a/apps/server/src/modules/room/api/test/room-index.api.spec.ts b/apps/server/src/modules/room/api/test/room-index.api.spec.ts index 212ca2db7af..cbb68d0f38c 100644 --- a/apps/server/src/modules/room/api/test/room-index.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-index.api.spec.ts @@ -140,10 +140,10 @@ describe('Room Controller (API)', () => { organization: studentUser.school, externalSource: undefined, }); - const roomMembers = rooms.map((room) => + const roomMemberships = rooms.map((room) => roomMembershipEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }) ); - await em.persistAndFlush([...rooms, ...roomMembers, studentAccount, studentUser, userGroupEntity]); + await em.persistAndFlush([...rooms, ...roomMemberships, studentAccount, studentUser, userGroupEntity]); em.clear(); const loggedInClient = await testApiClient.login(studentAccount); diff --git a/apps/server/src/modules/room/api/test/room-members.api.spec.ts b/apps/server/src/modules/room/api/test/room-members.api.spec.ts index 98464e46772..c509e59c41b 100644 --- a/apps/server/src/modules/room/api/test/room-members.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-members.api.spec.ts @@ -71,10 +71,10 @@ describe('Room Controller (API)', () => { organization: teacherUser.school, externalSource: undefined, }); - const roomMembers = roomMembershipEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }); + const roomMemberships = roomMembershipEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }); await em.persistAndFlush([ room, - roomMembers, + roomMemberships, teacherAccount, teacherUser, userGroupEntity, diff --git a/apps/server/src/modules/room/api/test/room-remove-members.api.spec.ts b/apps/server/src/modules/room/api/test/room-remove-members.api.spec.ts index c35d7bce1aa..d87d0e68314 100644 --- a/apps/server/src/modules/room/api/test/room-remove-members.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-remove-members.api.spec.ts @@ -81,9 +81,9 @@ describe('Room Controller (API)', () => { externalSource: undefined, }); - const roomMembers = roomMembershipEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }); + const roomMemberships = roomMembershipEntityFactory.build({ userGroupId: userGroupEntity.id, roomId: room.id }); - await em.persistAndFlush([...Object.values(users), room, roomMembers, teacherAccount, userGroupEntity]); + await em.persistAndFlush([...Object.values(users), room, roomMemberships, teacherAccount, userGroupEntity]); em.clear(); const loggedInClient = await testApiClient.login(teacherAccount); diff --git a/apps/server/src/modules/room/api/test/room-update.api.spec.ts b/apps/server/src/modules/room/api/test/room-update.api.spec.ts index c77888b09af..35b1c196f2d 100644 --- a/apps/server/src/modules/room/api/test/room-update.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-update.api.spec.ts @@ -106,8 +106,8 @@ describe('Room Controller (API)', () => { const userGroup = groupEntityFactory.buildWithId({ users: [{ role, user: teacherUser }], }); - const roomMember = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); - await em.persistAndFlush([room, roomMember, teacherAccount, teacherUser, userGroup, role]); + const roomMembership = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + await em.persistAndFlush([room, roomMembership, teacherAccount, teacherUser, userGroup, role]); em.clear(); const loggedInClient = await testApiClient.login(teacherAccount); From c887a775307f0355b11d4970e5b691aecfb84e03 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Thu, 28 Nov 2024 19:34:12 +0100 Subject: [PATCH 48/60] add schoolId to roomMembership --- ...41210124.ts => Migration20241004121012.ts} | 2 +- .../mikro-orm/Migration20241030126666.ts | 2 +- ...11604124.ts => Migration20241111160412.ts} | 0 ...21635382.ts => Migration20241112163538.ts} | 0 ...31005352.ts => Migration20241113100535.ts} | 0 ...31520015.ts => Migration20241113152001.ts} | 0 ...71951208.ts => Migration20241127195120.ts} | 0 .../mikro-orm/Migration20241128155801.ts | 61 +++++++++++++++ .../do/room-membership.do.spec.ts | 5 ++ .../room-membership/do/room-membership.do.ts | 5 ++ .../repo/entity/room-membership.entity.ts | 16 ++-- .../room-membership-domain.mapper.spec.ts | 3 + .../room-membership/room-membership.module.ts | 3 +- .../service/room-membership.service.spec.ts | 50 ++++++++---- .../service/room-membership.service.ts | 77 ++++++++++--------- .../testing/room-membership-entity.factory.ts | 6 +- .../testing/room-membership.factory.ts | 1 + apps/server/src/modules/room/api/room.uc.ts | 3 +- .../room/api/test/room-delete.api.spec.ts | 15 +++- backup/setup/migrations.json | 40 +++------- 20 files changed, 191 insertions(+), 98 deletions(-) rename apps/server/src/migrations/mikro-orm/{Migration202410041210124.ts => Migration20241004121012.ts} (93%) rename apps/server/src/migrations/mikro-orm/{Migration202411111604124.ts => Migration20241111160412.ts} (100%) rename apps/server/src/migrations/mikro-orm/{Migration202411121635382.ts => Migration20241112163538.ts} (100%) rename apps/server/src/migrations/mikro-orm/{Migration202411131005352.ts => Migration20241113100535.ts} (100%) rename apps/server/src/migrations/mikro-orm/{Migration202411131520015.ts => Migration20241113152001.ts} (100%) rename apps/server/src/migrations/mikro-orm/{Migration202411271951208.ts => Migration20241127195120.ts} (100%) create mode 100644 apps/server/src/migrations/mikro-orm/Migration20241128155801.ts diff --git a/apps/server/src/migrations/mikro-orm/Migration202410041210124.ts b/apps/server/src/migrations/mikro-orm/Migration20241004121012.ts similarity index 93% rename from apps/server/src/migrations/mikro-orm/Migration202410041210124.ts rename to apps/server/src/migrations/mikro-orm/Migration20241004121012.ts index ff244c257c2..3a04e168632 100644 --- a/apps/server/src/migrations/mikro-orm/Migration202410041210124.ts +++ b/apps/server/src/migrations/mikro-orm/Migration20241004121012.ts @@ -1,6 +1,6 @@ import { Migration } from '@mikro-orm/migrations-mongodb'; -export class Migration202410041210124 extends Migration { +export class Migration20241004121012 extends Migration { async up(): Promise { // Add ROOMVIEWER role await this.getCollection('roles').insertOne({ diff --git a/apps/server/src/migrations/mikro-orm/Migration20241030126666.ts b/apps/server/src/migrations/mikro-orm/Migration20241030126666.ts index ed24789a790..523e340f269 100644 --- a/apps/server/src/migrations/mikro-orm/Migration20241030126666.ts +++ b/apps/server/src/migrations/mikro-orm/Migration20241030126666.ts @@ -1,6 +1,6 @@ import { Migration } from '@mikro-orm/migrations-mongodb'; -export class Migration202410041210124 extends Migration { +export class Migration20241030126666 extends Migration { async up(): Promise { await this.getCollection('files').createIndex({ createdAt: 1 }); } diff --git a/apps/server/src/migrations/mikro-orm/Migration202411111604124.ts b/apps/server/src/migrations/mikro-orm/Migration20241111160412.ts similarity index 100% rename from apps/server/src/migrations/mikro-orm/Migration202411111604124.ts rename to apps/server/src/migrations/mikro-orm/Migration20241111160412.ts diff --git a/apps/server/src/migrations/mikro-orm/Migration202411121635382.ts b/apps/server/src/migrations/mikro-orm/Migration20241112163538.ts similarity index 100% rename from apps/server/src/migrations/mikro-orm/Migration202411121635382.ts rename to apps/server/src/migrations/mikro-orm/Migration20241112163538.ts diff --git a/apps/server/src/migrations/mikro-orm/Migration202411131005352.ts b/apps/server/src/migrations/mikro-orm/Migration20241113100535.ts similarity index 100% rename from apps/server/src/migrations/mikro-orm/Migration202411131005352.ts rename to apps/server/src/migrations/mikro-orm/Migration20241113100535.ts diff --git a/apps/server/src/migrations/mikro-orm/Migration202411131520015.ts b/apps/server/src/migrations/mikro-orm/Migration20241113152001.ts similarity index 100% rename from apps/server/src/migrations/mikro-orm/Migration202411131520015.ts rename to apps/server/src/migrations/mikro-orm/Migration20241113152001.ts diff --git a/apps/server/src/migrations/mikro-orm/Migration202411271951208.ts b/apps/server/src/migrations/mikro-orm/Migration20241127195120.ts similarity index 100% rename from apps/server/src/migrations/mikro-orm/Migration202411271951208.ts rename to apps/server/src/migrations/mikro-orm/Migration20241127195120.ts diff --git a/apps/server/src/migrations/mikro-orm/Migration20241128155801.ts b/apps/server/src/migrations/mikro-orm/Migration20241128155801.ts new file mode 100644 index 00000000000..725ef54ecd3 --- /dev/null +++ b/apps/server/src/migrations/mikro-orm/Migration20241128155801.ts @@ -0,0 +1,61 @@ +import { Migration } from '@mikro-orm/migrations-mongodb'; + +export class Migration20241128155801 extends Migration { + async up(): Promise { + const roomMembershipToSchoolView = [ + { + $match: { + school: { $exists: false, $eq: null }, + }, + }, + { + $lookup: { + from: 'rooms', + localField: 'room', + foreignField: '_id', + as: 'roomDetails', + }, + }, + { + $unwind: '$roomDetails', + }, + { + $group: { + _id: '$roomDetails.school', + roomMemberships: { $push: '$_id' }, + }, + }, + { + $project: { + _id: 0, + school: '$_id', + roomMemberships: 1, + }, + }, + ]; + + const mappings = await this.driver.aggregate('room-memberships', roomMembershipToSchoolView); + + for await (const mapping of mappings) { + const schoolUpdate = await this.driver.nativeUpdate( + 'room-memberships', + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-member-access + { _id: { $in: mapping.roomMemberships } }, + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-member-access + { $set: { school: mapping.school } } + ); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access, @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-unsafe-call + console.info(`Updated ${schoolUpdate.affectedRows} rooms with school ${mapping.school.toHexString()}`); + } + + if (mappings.length === 0) { + console.info(`No roomMemberships without school to update`); + } + } + + async down(): Promise { + await Promise.resolve(); + console.error(`Migration down not implemented. You might need to restore database from backup!`); + } +} diff --git a/apps/server/src/modules/room-membership/do/room-membership.do.spec.ts b/apps/server/src/modules/room-membership/do/room-membership.do.spec.ts index ee3d4746360..5033cdc33b4 100644 --- a/apps/server/src/modules/room-membership/do/room-membership.do.spec.ts +++ b/apps/server/src/modules/room-membership/do/room-membership.do.spec.ts @@ -9,6 +9,7 @@ describe('RoomMembership', () => { id: roomMemberId, roomId: 'roomId', userGroupId: 'userGroupId', + schoolId: 'schoolId', createdAt: new Date('2024-01-01'), updatedAt: new Date('2024-01-01'), }; @@ -39,4 +40,8 @@ describe('RoomMembership', () => { it('should get userGroupId', () => { expect(roomMembership.userGroupId).toEqual(roomMembershipProps.userGroupId); }); + + it('should get schoolId', () => { + expect(roomMembership.schoolId).toEqual(roomMembershipProps.schoolId); + }); }); diff --git a/apps/server/src/modules/room-membership/do/room-membership.do.ts b/apps/server/src/modules/room-membership/do/room-membership.do.ts index e8654923cb4..99062d69545 100644 --- a/apps/server/src/modules/room-membership/do/room-membership.do.ts +++ b/apps/server/src/modules/room-membership/do/room-membership.do.ts @@ -5,6 +5,7 @@ export interface RoomMembershipProps extends AuthorizableObject { id: EntityId; roomId: EntityId; userGroupId: EntityId; + schoolId: EntityId; createdAt: Date; updatedAt: Date; } @@ -31,4 +32,8 @@ export class RoomMembership extends DomainObject { public get userGroupId(): EntityId { return this.props.userGroupId; } + + public get schoolId(): EntityId { + return this.props.schoolId; + } } diff --git a/apps/server/src/modules/room-membership/repo/entity/room-membership.entity.ts b/apps/server/src/modules/room-membership/repo/entity/room-membership.entity.ts index f9b9c37bebd..eafbfd3aeab 100644 --- a/apps/server/src/modules/room-membership/repo/entity/room-membership.entity.ts +++ b/apps/server/src/modules/room-membership/repo/entity/room-membership.entity.ts @@ -1,21 +1,12 @@ import { Entity, Property, Unique } from '@mikro-orm/core'; -import { AuthorizableObject } from '@shared/domain/domain-object'; import { ObjectIdType } from '@shared/repo/types/object-id.type'; import { BaseEntityWithTimestamps } from '@shared/domain/entity/base.entity'; import { EntityId } from '@shared/domain/types'; -import { RoomMembership } from '../../do/room-membership.do'; - -export interface RoomMembershipEntityProps extends AuthorizableObject { - id: EntityId; - roomId: EntityId; - userGroupId: EntityId; - createdAt: Date; - updatedAt: Date; -} +import { RoomMembership, RoomMembershipProps } from '../../do/room-membership.do'; @Entity({ tableName: 'room-memberships' }) @Unique({ properties: ['roomId', 'userGroupId'] }) -export class RoomMembershipEntity extends BaseEntityWithTimestamps implements RoomMembershipEntityProps { +export class RoomMembershipEntity extends BaseEntityWithTimestamps implements RoomMembershipProps { @Unique() @Property({ type: ObjectIdType, fieldName: 'room' }) roomId!: EntityId; @@ -23,6 +14,9 @@ export class RoomMembershipEntity extends BaseEntityWithTimestamps implements Ro @Property({ type: ObjectIdType, fieldName: 'userGroup' }) userGroupId!: EntityId; + @Property({ type: ObjectIdType, fieldName: 'school' }) + schoolId!: EntityId; + @Property({ persist: false }) domainObject: RoomMembership | undefined; } diff --git a/apps/server/src/modules/room-membership/repo/room-membership-domain.mapper.spec.ts b/apps/server/src/modules/room-membership/repo/room-membership-domain.mapper.spec.ts index e4d024be0c2..a95d86fdb73 100644 --- a/apps/server/src/modules/room-membership/repo/room-membership-domain.mapper.spec.ts +++ b/apps/server/src/modules/room-membership/repo/room-membership-domain.mapper.spec.ts @@ -23,6 +23,7 @@ describe('RoomMembershipDomainMapper', () => { id: '1', roomId: 'r1', userGroupId: 'ug1', + schoolId: 's1', createdAt: new Date('2023-01-01'), updatedAt: new Date('2023-01-01'), }); @@ -40,6 +41,7 @@ describe('RoomMembershipDomainMapper', () => { id: '1', roomId: 'r1', userGroupId: 'ug1', + schoolId: 's1', createdAt: new Date('2023-01-01'), updatedAt: new Date('2023-01-01'), }); @@ -78,6 +80,7 @@ describe('RoomMembershipDomainMapper', () => { id: '66d581c3ef74c548a4efea1d', roomId: '66d581c3ef74c548a4efea1a', userGroupId: '66d581c3ef74c548a4efea1b', + schoolId: '66d581c3ef74c548a4efea1c', createdAt: new Date('2024-10-1'), updatedAt: new Date('2024-10-1'), }; diff --git a/apps/server/src/modules/room-membership/room-membership.module.ts b/apps/server/src/modules/room-membership/room-membership.module.ts index 520d8c66628..a261d8ea475 100644 --- a/apps/server/src/modules/room-membership/room-membership.module.ts +++ b/apps/server/src/modules/room-membership/room-membership.module.ts @@ -3,12 +3,13 @@ import { Module } from '@nestjs/common'; import { CqrsModule } from '@nestjs/cqrs'; import { AuthorizationModule } from '../authorization'; import { RoleModule } from '../role'; +import { RoomModule } from '../room/room.module'; import { RoomMembershipRule } from './authorization/room-membership.rule'; import { RoomMembershipRepo } from './repo/room-membership.repo'; import { RoomMembershipService } from './service/room-membership.service'; @Module({ - imports: [AuthorizationModule, CqrsModule, GroupModule, RoleModule], + imports: [AuthorizationModule, CqrsModule, GroupModule, RoleModule, RoomModule], providers: [RoomMembershipService, RoomMembershipRepo, RoomMembershipRule], exports: [RoomMembershipService], }) diff --git a/apps/server/src/modules/room-membership/service/room-membership.service.spec.ts b/apps/server/src/modules/room-membership/service/room-membership.service.spec.ts index abc5f5f9fb2..d9134cb2867 100644 --- a/apps/server/src/modules/room-membership/service/room-membership.service.spec.ts +++ b/apps/server/src/modules/room-membership/service/room-membership.service.spec.ts @@ -1,12 +1,13 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; +import { GroupService, GroupTypes } from '@modules/group'; +import { RoleService } from '@modules/role'; +import { roomFactory } from '@modules/room/testing'; import { BadRequestException } from '@nestjs/common/exceptions'; import { Test, TestingModule } from '@nestjs/testing'; import { RoleName } from '@shared/domain/interface'; import { groupFactory, roleDtoFactory, userFactory } from '@shared/testing'; import { MongoMemoryDatabaseModule } from '@src/infra/database'; -import { GroupService, GroupTypes } from '@modules/group'; -import { RoleService } from '@modules/role'; -import { roomFactory } from '@modules/room/testing'; +import { RoomService } from '@src/modules/room/domain'; import { RoomMembershipAuthorizable } from '../do/room-membership-authorizable.do'; import { RoomMembershipRepo } from '../repo/room-membership.repo'; import { roomMembershipFactory } from '../testing'; @@ -18,6 +19,7 @@ describe('RoomMembershipService', () => { let roomMembershipRepo: DeepMocked; let groupService: DeepMocked; let roleService: DeepMocked; + let roomService: DeepMocked; beforeAll(async () => { module = await Test.createTestingModule({ @@ -36,6 +38,10 @@ describe('RoomMembershipService', () => { provide: RoleService, useValue: createMock(), }, + { + provide: RoomService, + useValue: createMock(), + }, ], }).compile(); @@ -43,6 +49,7 @@ describe('RoomMembershipService', () => { roomMembershipRepo = module.get(RoomMembershipRepo); groupService = module.get(GroupService); roleService = module.get(RoleService); + roomService = module.get(RoomService); }); afterAll(async () => { @@ -54,7 +61,7 @@ describe('RoomMembershipService', () => { }); describe('addMembersToRoom', () => { - describe('when room member does not exist', () => { + describe('when roomMembership does not exist', () => { const setup = () => { const user = userFactory.buildWithId(); const room = roomFactory.build(); @@ -64,6 +71,7 @@ describe('RoomMembershipService', () => { groupService.createGroup.mockResolvedValue(group); groupService.addUserToGroup.mockResolvedValue(); roomMembershipRepo.save.mockResolvedValue(); + roomService.getSingleRoom.mockResolvedValue(room); return { user, @@ -71,7 +79,7 @@ describe('RoomMembershipService', () => { }; }; - it('should create new room member when not exists', async () => { + it('should create new roomMembership when not exists', async () => { const { user, room } = setup(); await service.addMembersToRoom(room.id, [{ userId: user.id, roleName: RoleName.ROOMEDITOR }]); @@ -79,6 +87,18 @@ describe('RoomMembershipService', () => { expect(roomMembershipRepo.save).toHaveBeenCalled(); }); + it('should save the schoolId of the room in the roomMembership', async () => { + const { user, room } = setup(); + + await service.addMembersToRoom(room.id, [{ userId: user.id, roleName: RoleName.ROOMEDITOR }]); + + expect(roomMembershipRepo.save).toHaveBeenCalledWith( + expect.objectContaining({ + schoolId: room.schoolId, + }) + ); + }); + describe('when no user is provided', () => { it('should throw an exception', async () => { const { room } = setup(); @@ -90,7 +110,7 @@ describe('RoomMembershipService', () => { }); }); - describe('when room member exists', () => { + describe('when roomMembership exists', () => { const setup = () => { const user = userFactory.buildWithId(); const group = groupFactory.build({ type: GroupTypes.ROOM }); @@ -107,7 +127,7 @@ describe('RoomMembershipService', () => { }; }; - it('should add user to existing room member', async () => { + it('should add user to existing roomMembership', async () => { const { user, room, group } = setup(); await service.addMembersToRoom(room.id, [{ userId: user.id, roleName: RoleName.ROOMEDITOR }]); @@ -120,7 +140,7 @@ describe('RoomMembershipService', () => { }); describe('removeMembersFromRoom', () => { - describe('when room member does not exist', () => { + describe('when roomMembership does not exist', () => { const setup = () => { const user = userFactory.buildWithId(); const room = roomFactory.build(); @@ -147,7 +167,7 @@ describe('RoomMembershipService', () => { }); }); - describe('when room member exists', () => { + describe('when roomMembership exists', () => { const setup = () => { const user = userFactory.buildWithId(); const group = groupFactory.build({ type: GroupTypes.ROOM }); @@ -165,7 +185,7 @@ describe('RoomMembershipService', () => { }; }; - it('should remove room member', async () => { + it('should remove roomMembership', async () => { const { user, room, group } = setup(); await service.removeMembersFromRoom(room.id, [user.id]); @@ -176,7 +196,7 @@ describe('RoomMembershipService', () => { }); describe('deleteRoomMembership', () => { - describe('when room member does not exist', () => { + describe('when roomMembership does not exist', () => { const setup = () => { roomMembershipRepo.findByRoomId.mockResolvedValue(null); }; @@ -189,7 +209,7 @@ describe('RoomMembershipService', () => { }); }); - describe('when room member exists', () => { + describe('when roomMembership exists', () => { const setup = () => { const group = groupFactory.build(); const roomMembership = roomMembershipFactory.build({ userGroupId: group.id }); @@ -199,7 +219,7 @@ describe('RoomMembershipService', () => { return { roomMembership, group }; }; - it('should call delete group and room member', async () => { + it('should call delete group and roomMembership', async () => { const { roomMembership, group } = setup(); await service.deleteRoomMembership(roomMembership.roomId); expect(groupService.delete).toHaveBeenCalledWith(group); @@ -226,7 +246,7 @@ describe('RoomMembershipService', () => { return { roomId, userId, groupId, roleId, roomMembership, group, role }; }; - it('should return RoomMembershipAuthorizable when room member exists', async () => { + it('should return RoomMembershipAuthorizable when roomMembership exists', async () => { const { roomId, userId, roleId } = setup(); const result = await service.getRoomMembershipAuthorizable(roomId); @@ -238,7 +258,7 @@ describe('RoomMembershipService', () => { expect(result.members[0].roles[0].id).toBe(roleId); }); - it('should return empty RoomMembershipAuthorizable when room member not exists', async () => { + it('should return empty RoomMembershipAuthorizable when roomMembership not exists', async () => { const roomId = 'nonexistent'; roomMembershipRepo.findByRoomId.mockResolvedValue(null); diff --git a/apps/server/src/modules/room-membership/service/room-membership.service.ts b/apps/server/src/modules/room-membership/service/room-membership.service.ts index efd32e5f61f..75e6e6922eb 100644 --- a/apps/server/src/modules/room-membership/service/room-membership.service.ts +++ b/apps/server/src/modules/room-membership/service/room-membership.service.ts @@ -1,41 +1,49 @@ +import { ObjectId } from '@mikro-orm/mongodb'; +import { Group, GroupService, GroupTypes } from '@modules/group'; +import { RoleDto, RoleService } from '@modules/role'; import { BadRequestException, Injectable } from '@nestjs/common'; import { RoleName } from '@shared/domain/interface'; import { EntityId } from '@shared/domain/types'; -import { Group, GroupService, GroupTypes } from '@modules/group'; -import { ObjectId } from '@mikro-orm/mongodb'; -import { RoleDto, RoleService } from '@modules/role'; +import { RoomService } from '@src/modules/room/domain'; +import { RoomMembershipAuthorizable, UserWithRoomRoles } from '../do/room-membership-authorizable.do'; import { RoomMembership } from '../do/room-membership.do'; import { RoomMembershipRepo } from '../repo/room-membership.repo'; -import { RoomMembershipAuthorizable, UserWithRoomRoles } from '../do/room-membership-authorizable.do'; @Injectable() export class RoomMembershipService { constructor( private readonly groupService: GroupService, - private readonly roomMembersRepo: RoomMembershipRepo, - private readonly roleService: RoleService + private readonly roomMembershipRepo: RoomMembershipRepo, + private readonly roleService: RoleService, + private readonly roomService: RoomService ) {} - private async createNewRoomMember( + private async createNewRoomMembership( roomId: EntityId, userId: EntityId, - roleName: RoleName.ROOMEDITOR | RoleName.ROOMVIEWER, - schoolId?: EntityId + roleName: RoleName.ROOMEDITOR | RoleName.ROOMVIEWER ) { - const group = await this.groupService.createGroup(`Room Members for Room ${roomId}`, GroupTypes.ROOM, schoolId); + const room = await this.roomService.getSingleRoom(roomId); + + const group = await this.groupService.createGroup( + `Room Members for Room ${roomId}`, + GroupTypes.ROOM, + room.schoolId + ); await this.groupService.addUsersToGroup(group.id, [{ userId, roleName }]); - const roomMember = new RoomMembership({ + const roomMembership = new RoomMembership({ id: new ObjectId().toHexString(), roomId, userGroupId: group.id, + schoolId: room.schoolId, createdAt: new Date(), updatedAt: new Date(), }); - await this.roomMembersRepo.save(roomMember); + await this.roomMembershipRepo.save(roomMembership); - return roomMember; + return roomMembership; } private buildRoomMembershipAuthorizable( @@ -57,52 +65,51 @@ export class RoomMembershipService { return roomMembershipAuthorizable; } - public async deleteRoomMember(roomId: EntityId) { - const roomMember = await this.roomMembersRepo.findByRoomId(roomId); - if (roomMember === null) return; + public async deleteRoomMembership(roomId: EntityId) { + const roomMembership = await this.roomMembershipRepo.findByRoomId(roomId); + if (roomMembership === null) return; - const group = await this.groupService.findById(roomMember.userGroupId); + const group = await this.groupService.findById(roomMembership.userGroupId); await this.groupService.delete(group); - await this.roomMembersRepo.delete(roomMember); + await this.roomMembershipRepo.delete(roomMembership); } public async addMembersToRoom( roomId: EntityId, - userIdsAndRoles: Array<{ userId: EntityId; roleName: RoleName.ROOMEDITOR | RoleName.ROOMVIEWER }>, - schoolId?: EntityId + userIdsAndRoles: Array<{ userId: EntityId; roleName: RoleName.ROOMEDITOR | RoleName.ROOMVIEWER }> ): Promise { - const roomMember = await this.roomMembersRepo.findByRoomId(roomId); - if (roomMember === null) { - const firstUser = userIdsAndRoles.pop(); + const roomMembership = await this.roomMembershipRepo.findByRoomId(roomId); + if (roomMembership === null) { + const firstUser = userIdsAndRoles.shift(); if (firstUser === undefined) { throw new BadRequestException('No user provided'); } - const newRoomMember = await this.createNewRoomMember(roomId, firstUser.userId, firstUser.roleName, schoolId); - return newRoomMember.id; + const newRoomMembership = await this.createNewRoomMembership(roomId, firstUser.userId, firstUser.roleName); + return newRoomMembership.id; } - await this.groupService.addUsersToGroup(roomMember.userGroupId, userIdsAndRoles); + await this.groupService.addUsersToGroup(roomMembership.userGroupId, userIdsAndRoles); - return roomMember.id; + return roomMembership.id; } public async removeMembersFromRoom(roomId: EntityId, userIds: EntityId[]): Promise { - const roomMember = await this.roomMembersRepo.findByRoomId(roomId); - if (roomMember === null) { + const roomMembership = await this.roomMembershipRepo.findByRoomId(roomId); + if (roomMembership === null) { throw new BadRequestException('Room member not found'); } - const group = await this.groupService.findById(roomMember.userGroupId); + const group = await this.groupService.findById(roomMembership.userGroupId); await this.groupService.removeUsersFromGroup(group.id, userIds); } public async getRoomMembershipAuthorizablesByUserId(userId: EntityId): Promise { const groupPage = await this.groupService.findGroups({ userId, groupTypes: [GroupTypes.ROOM] }); const groupIds = groupPage.data.map((group) => group.id); - const roomMembers = await this.roomMembersRepo.findByGroupIds(groupIds); + const roomMemberships = await this.roomMembershipRepo.findByGroupIds(groupIds); const roleIds = groupPage.data.flatMap((group) => group.users.map((groupUser) => groupUser.roleId)); const roleSet = await this.roleService.findByIds(roleIds); - const roomMembershipAuthorizables = roomMembers + const roomMembershipAuthorizables = roomMemberships .map((item) => { const group = groupPage.data.find((g) => g.id === item.userGroupId); if (!group) return null; @@ -114,11 +121,11 @@ export class RoomMembershipService { } public async getRoomMembershipAuthorizable(roomId: EntityId): Promise { - const roomMember = await this.roomMembersRepo.findByRoomId(roomId); - if (roomMember === null) { + const roomMembership = await this.roomMembershipRepo.findByRoomId(roomId); + if (roomMembership === null) { return new RoomMembershipAuthorizable(roomId, []); } - const group = await this.groupService.findById(roomMember.userGroupId); + const group = await this.groupService.findById(roomMembership.userGroupId); const roleSet = await this.roleService.findByIds(group.users.map((groupUser) => groupUser.roleId)); const members = group.users.map((groupUser): UserWithRoomRoles => { diff --git a/apps/server/src/modules/room-membership/testing/room-membership-entity.factory.ts b/apps/server/src/modules/room-membership/testing/room-membership-entity.factory.ts index c58746adf96..8ea19809b55 100644 --- a/apps/server/src/modules/room-membership/testing/room-membership-entity.factory.ts +++ b/apps/server/src/modules/room-membership/testing/room-membership-entity.factory.ts @@ -1,14 +1,16 @@ import { ObjectId } from '@mikro-orm/mongodb'; import { EntityFactory } from '@shared/testing/factory/entity.factory'; -import { RoomMembershipEntity, RoomMembershipEntityProps } from '../repo/entity/room-membership.entity'; +import { RoomMembershipEntity } from '../repo/entity/room-membership.entity'; +import { RoomMembershipProps } from '../do/room-membership.do'; -export const roomMembershipEntityFactory = EntityFactory.define( +export const roomMembershipEntityFactory = EntityFactory.define( RoomMembershipEntity, () => { return { id: new ObjectId().toHexString(), roomId: new ObjectId().toHexString(), userGroupId: new ObjectId().toHexString(), + schoolId: new ObjectId().toHexString(), createdAt: new Date(), updatedAt: new Date(), }; diff --git a/apps/server/src/modules/room-membership/testing/room-membership.factory.ts b/apps/server/src/modules/room-membership/testing/room-membership.factory.ts index 70c80b05a93..64c294187cb 100644 --- a/apps/server/src/modules/room-membership/testing/room-membership.factory.ts +++ b/apps/server/src/modules/room-membership/testing/room-membership.factory.ts @@ -7,6 +7,7 @@ export const roomMembershipFactory = BaseFactory.define { await this.roomService.deleteRoom(room); throw err; @@ -99,6 +99,7 @@ export class RoomUc { await this.checkRoomAuthorization(userId, roomId, Action.write, [Permission.ROOM_DELETE]); await this.roomService.deleteRoom(room); + await this.roomMembershipService.deleteRoomMembership(roomId); } public async getRoomMembers(userId: EntityId, roomId: EntityId): Promise { diff --git a/apps/server/src/modules/room/api/test/room-delete.api.spec.ts b/apps/server/src/modules/room/api/test/room-delete.api.spec.ts index 23d752e0abf..22f74c7edc8 100644 --- a/apps/server/src/modules/room/api/test/room-delete.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-delete.api.spec.ts @@ -1,4 +1,6 @@ import { EntityManager, ObjectId } from '@mikro-orm/mongodb'; +import { GroupEntityTypes } from '@modules/group/entity/group.entity'; +import { ServerTestModule, serverConfig, type ServerConfig } from '@modules/server'; import { HttpStatus, INestApplication, NotFoundException } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import { Permission, RoleName } from '@shared/domain/interface'; @@ -9,9 +11,8 @@ import { groupEntityFactory, roleFactory, } from '@shared/testing'; -import { GroupEntityTypes } from '@modules/group/entity/group.entity'; +import { RoomMembershipEntity } from '@src/modules/room-membership'; import { roomMembershipEntityFactory } from '@src/modules/room-membership/testing/room-membership-entity.factory'; -import { ServerTestModule, serverConfig, type ServerConfig } from '@modules/server'; import { RoomEntity } from '../../repo'; import { roomEntityFactory } from '../../testing/room-entity.factory'; @@ -120,6 +121,16 @@ describe('Room Controller (API)', () => { expect(response.status).toBe(HttpStatus.NO_CONTENT); await expect(em.findOneOrFail(RoomEntity, room.id)).rejects.toThrow(NotFoundException); }); + + it('should delete the roomMembership', async () => { + const { loggedInClient, room } = await setup(); + + await expect(em.findOneOrFail(RoomMembershipEntity, { roomId: room.id })).resolves.not.toThrow(); + + const response = await loggedInClient.delete(room.id); + expect(response.status).toBe(HttpStatus.NO_CONTENT); + await expect(em.findOneOrFail(RoomMembershipEntity, { roomId: room.id })).rejects.toThrow(NotFoundException); + }); }); describe('when the room does not exist', () => { diff --git a/backup/setup/migrations.json b/backup/setup/migrations.json index 9d02afcf4b9..a697b568320 100644 --- a/backup/setup/migrations.json +++ b/backup/setup/migrations.json @@ -246,7 +246,7 @@ "_id": { "$oid": "6718c7e97459fd3674d36a29" }, - "name": "Migration202410041210124", + "name": "Migration20241004121012", "created_at": { "$date": "2024-10-23T09:54:49.077Z" } @@ -282,7 +282,7 @@ "_id": { "$oid": "673387c13aba1e283484119d" }, - "name": "Migration202411121635382", + "name": "Migration20241112163538", "created_at": { "$date": "2024-11-12T16:52:17.292Z" } @@ -296,15 +296,6 @@ "$date": "2024-11-13T10:13:12.402Z" } }, - { - "_id": { - "$oid": "67347bb8b1bcb78aecbab90e" - }, - "name": "Migration20241112163538", - "created_at": { - "$date": "2024-11-13T10:13:12.409Z" - } - }, { "_id": { "$oid": "67347bb8b1bcb78aecbab90f" @@ -316,38 +307,29 @@ }, { "_id": { - "$oid": "6734805b32785b5d369ed96a" - }, - "name": "Migration202411131005352", - "created_at": { - "$date": "2024-11-13T10:32:59.991Z" - } - }, - { - "_id": { - "$oid": "6734cb1d7b04e799e79c1ec1" + "$oid": "67361aa7776f2f3e5a519735" }, - "name": "Migration202411131520015", + "name": "Migration20241113152001", "created_at": { - "$date": "2024-11-13T15:51:57.334Z" + "$date": "2024-11-14T15:43:35.024Z" } }, { "_id": { - "$oid": "67361aa7776f2f3e5a519735" + "$oid": "67477a7455d881b78f7a79fa" }, - "name": "Migration20241113152001", + "name": "Migration20241127195120", "created_at": { - "$date": "2024-11-14T15:43:35.024Z" + "$date": "2024-11-27T20:00:52.582Z" } }, { "_id": { - "$oid": "67477a7455d881b78f7a79fa" + "$oid": "6748b0f451c62e9dc6899983" }, - "name": "Migration202411271951208", + "name": "Migration20241128155801", "created_at": { - "$date": "2024-11-27T20:00:52.582Z" + "$date": "2024-11-28T18:05:40.839Z" } } ] From c23014b37dfc2ff137a3a9830c42ca247e67876b Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Thu, 28 Nov 2024 19:34:38 +0100 Subject: [PATCH 49/60] add api test --- .../controller/api-test/board-copy-in-course.api.spec.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/server/src/modules/board/controller/api-test/board-copy-in-course.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-copy-in-course.api.spec.ts index 5d1b966ee01..854cf4e36e9 100644 --- a/apps/server/src/modules/board/controller/api-test/board-copy-in-course.api.spec.ts +++ b/apps/server/src/modules/board/controller/api-test/board-copy-in-course.api.spec.ts @@ -6,7 +6,7 @@ import { TestApiClient, UserAndAccountTestFactory, cleanupCollections, courseFac import { CopyApiResponse, CopyElementType, CopyStatusEnum } from '@modules/copy-helper'; import { BoardNodeEntity } from '../../repo'; import { columnBoardEntityFactory } from '../../testing'; -import { BoardExternalReferenceType } from '../../domain'; +import { BoardExternalReferenceType, ColumnBoardProps } from '../../domain'; const baseRouteName = '/boards'; @@ -35,13 +35,14 @@ describe(`board copy with course relation (api)`, () => { }); describe('with valid user', () => { - const setup = async () => { + const setup = async (columnBoardProps: Partial = {}) => { const { teacherAccount, teacherUser } = UserAndAccountTestFactory.buildTeacher(); const course = courseFactory.build({ teachers: [teacherUser] }); await em.persistAndFlush([teacherAccount, teacherUser, course]); const columnBoardNode = columnBoardEntityFactory.build({ + ...columnBoardProps, context: { id: course.id, type: BoardExternalReferenceType.Course }, }); @@ -83,7 +84,7 @@ describe(`board copy with course relation (api)`, () => { }); it('should set draft status on the board copy', async () => { - const { loggedInClient, columnBoardNode } = await setup(); + const { loggedInClient, columnBoardNode } = await setup({ isVisible: true }); const response = await loggedInClient.post(`${columnBoardNode.id}/copy`); const body = response.body as CopyApiResponse; From 82f29246a3ee088bf91e9ab0b6ced4d689f1ea43 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Thu, 28 Nov 2024 20:50:13 +0100 Subject: [PATCH 50/60] fix migration seeds --- backup/setup/migrations.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backup/setup/migrations.json b/backup/setup/migrations.json index a8c1398133e..4a5b506a66d 100644 --- a/backup/setup/migrations.json +++ b/backup/setup/migrations.json @@ -321,6 +321,6 @@ "name": "Migration20241128155801", "created_at": { "$date": "2024-11-28T18:05:40.839Z" - }, + } } ] From 7d4f69a8dbf335b8ac7932079323b8816035a64a Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Mon, 2 Dec 2024 09:59:01 +0100 Subject: [PATCH 51/60] undo rename migration --- apps/server/src/migrations/mikro-orm/Migration20241030126666.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/server/src/migrations/mikro-orm/Migration20241030126666.ts b/apps/server/src/migrations/mikro-orm/Migration20241030126666.ts index 523e340f269..ed24789a790 100644 --- a/apps/server/src/migrations/mikro-orm/Migration20241030126666.ts +++ b/apps/server/src/migrations/mikro-orm/Migration20241030126666.ts @@ -1,6 +1,6 @@ import { Migration } from '@mikro-orm/migrations-mongodb'; -export class Migration20241030126666 extends Migration { +export class Migration202410041210124 extends Migration { async up(): Promise { await this.getCollection('files').createIndex({ createdAt: 1 }); } From 939ae36dadad07e68fb3a7451f261f834506756a Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Mon, 2 Dec 2024 10:05:25 +0100 Subject: [PATCH 52/60] undo rename migration --- .../{Migration20241004121012.ts => Migration202410041210124.ts} | 2 +- backup/setup/migrations.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename apps/server/src/migrations/mikro-orm/{Migration20241004121012.ts => Migration202410041210124.ts} (93%) diff --git a/apps/server/src/migrations/mikro-orm/Migration20241004121012.ts b/apps/server/src/migrations/mikro-orm/Migration202410041210124.ts similarity index 93% rename from apps/server/src/migrations/mikro-orm/Migration20241004121012.ts rename to apps/server/src/migrations/mikro-orm/Migration202410041210124.ts index 3a04e168632..ff244c257c2 100644 --- a/apps/server/src/migrations/mikro-orm/Migration20241004121012.ts +++ b/apps/server/src/migrations/mikro-orm/Migration202410041210124.ts @@ -1,6 +1,6 @@ import { Migration } from '@mikro-orm/migrations-mongodb'; -export class Migration20241004121012 extends Migration { +export class Migration202410041210124 extends Migration { async up(): Promise { // Add ROOMVIEWER role await this.getCollection('roles').insertOne({ diff --git a/backup/setup/migrations.json b/backup/setup/migrations.json index 4a5b506a66d..dc3e4d04196 100644 --- a/backup/setup/migrations.json +++ b/backup/setup/migrations.json @@ -246,7 +246,7 @@ "_id": { "$oid": "6718c7e97459fd3674d36a29" }, - "name": "Migration20241004121012", + "name": "Migration202410041210124", "created_at": { "$date": "2024-10-23T09:54:49.077Z" } From 2437608408919b849af0a1a8fc725c0b3ba5d2bc Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Mon, 2 Dec 2024 10:12:11 +0100 Subject: [PATCH 53/60] rename comments --- .../mikro-orm/Migration202410041210124.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/server/src/migrations/mikro-orm/Migration202410041210124.ts b/apps/server/src/migrations/mikro-orm/Migration202410041210124.ts index ff244c257c2..cf10456dcdb 100644 --- a/apps/server/src/migrations/mikro-orm/Migration202410041210124.ts +++ b/apps/server/src/migrations/mikro-orm/Migration202410041210124.ts @@ -2,28 +2,28 @@ import { Migration } from '@mikro-orm/migrations-mongodb'; export class Migration202410041210124 extends Migration { async up(): Promise { - // Add ROOMVIEWER role + // Add ROOM_VIEWER role await this.getCollection('roles').insertOne({ name: 'room_viewer', permissions: ['ROOM_VIEW'], }); - console.info('Added ROOMVIEWER role with ROOM_VIEW permission'); + console.info('Added ROOM_VIEWER role with ROOM_VIEW permission'); - // Add ROOMEDITOR role + // Add ROOM_EDITOR role await this.getCollection('roles').insertOne({ name: 'room_editor', permissions: ['ROOM_VIEW', 'ROOM_EDIT'], }); - console.info('Added ROOMEDITOR role with ROOM_VIEW and ROOM_EDIT permissions'); + console.info('Added ROOM_EDITOR role with ROOM_VIEW and ROOM_EDIT permissions'); } async down(): Promise { - // Remove ROOMVIEWER role + // Remove ROOM_VIEWER role await this.getCollection('roles').deleteOne({ name: 'room_viewer' }); - console.info('Rollback: Removed ROOMVIEWER role'); + console.info('Rollback: Removed ROOM_VIEWER role'); - // Remove ROOMEDITOR role + // Remove ROOM_EDITOR role await this.getCollection('roles').deleteOne({ name: 'room_editor' }); - console.info('Rollback: Removed ROOMEDITOR role'); + console.info('Rollback: Removed ROOM_EDITOR role'); } } From cd2a1975f3682b190c1bab44d6e2319812418d65 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Mon, 2 Dec 2024 10:16:46 +0100 Subject: [PATCH 54/60] rename comments and console outputs --- .../mikro-orm/Migration20241111160412.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/server/src/migrations/mikro-orm/Migration20241111160412.ts b/apps/server/src/migrations/mikro-orm/Migration20241111160412.ts index e74aaa59473..e642e195e69 100644 --- a/apps/server/src/migrations/mikro-orm/Migration20241111160412.ts +++ b/apps/server/src/migrations/mikro-orm/Migration20241111160412.ts @@ -2,26 +2,26 @@ import { Migration } from '@mikro-orm/migrations-mongodb'; export class Migration20241111160412 extends Migration { async up(): Promise { - // Rename ROOMVIEWER role from room_viewer to roomviewer + // Rename ROOM_VIEWER role from room_viewer to roomviewer await this.getCollection('roles').updateMany({ name: 'room_viewer' }, { $set: { name: 'roomviewer' } }); - console.info('Renamed ROOMVIEWER role from room_viewer to roomviewer'); + console.info('Renamed ROOM_VIEWER role from room_viewer to roomviewer'); - // Rename ROOMEDITOR role from room_editor to roomeditor + // Rename ROOM_EDITOR role from room_editor to roomeditor await this.getCollection('roles').updateMany({ name: 'room_editor' }, { $set: { name: 'roomeditor' } }); - console.info('Renamed ROOMEDITOR role from room_editor to roomeditor'); + console.info('Renamed ROOM_EDITOR role from room_editor to roomeditor'); } async down(): Promise { - // Rename ROOMVIEWER role from roomviewer to room_viewer + // Rename ROOM_VIEWER role from roomviewer to room_viewer await this.getCollection('roles').updateMany({ name: 'roomviewer' }, { $set: { name: 'room_viewer' } }); - console.info('Rollback: Renamed ROOMVIEWER role from roomviewer to room_viewer'); + console.info('Rollback: Renamed ROOM_VIEWER role from roomviewer to room_viewer'); - // Rename ROOMEDITOR role from roomeditor to room_editor + // Rename ROOM_EDITOR role from roomeditor to room_editor await this.getCollection('roles').updateMany({ name: 'roomeditor' }, { $set: { name: 'room_editor' } }); - console.info('Rollback: Renamed ROOMEDITOR role from roomeditor to room_editor'); + console.info('Rollback: Renamed ROOM_EDITOR role from roomeditor to room_editor'); } } From 097b117e06fbcb056c16659c2afdf1ceb7e7309d Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Mon, 2 Dec 2024 10:23:14 +0100 Subject: [PATCH 55/60] fix module imports --- .../board/service/internal/board-context.service.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/server/src/modules/board/service/internal/board-context.service.spec.ts b/apps/server/src/modules/board/service/internal/board-context.service.spec.ts index ecf3656b2d3..489c09f8a8f 100644 --- a/apps/server/src/modules/board/service/internal/board-context.service.spec.ts +++ b/apps/server/src/modules/board/service/internal/board-context.service.spec.ts @@ -1,13 +1,13 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { ObjectId } from '@mikro-orm/mongodb'; +import { GroupTypes } from '@modules/group'; +import { RoomMembershipService } from '@modules/room-membership'; +import { roomMembershipFactory } from '@modules/room-membership/testing'; +import { roomFactory } from '@modules/room/testing'; import { Test, TestingModule } from '@nestjs/testing'; import { Permission, RoleName } from '@shared/domain/interface'; import { CourseRepo } from '@shared/repo/course'; import { courseFactory, groupFactory, roleFactory, setupEntities, userFactory } from '@shared/testing'; -import { GroupTypes } from '@src/modules/group'; -import { RoomMembershipService } from '@src/modules/room-membership'; -import { roomMembershipFactory } from '@src/modules/room-membership/testing'; -import { roomFactory } from '@src/modules/room/testing'; import { BoardExternalReferenceType, BoardRoles, UserWithBoardRoles } from '../../domain'; import { columnBoardFactory, columnFactory } from '../../testing'; import { BoardContextService } from './board-context.service'; From 8f5e6cdc7dbc645e2255ded961e5d994c2a83a84 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 3 Dec 2024 16:04:23 +0100 Subject: [PATCH 56/60] implement handling optional date values --- .../dto/request/create-room.body.params.ts | 8 +- .../dto/request/update-room.body.params.ts | 6 +- .../src/modules/room/api/room.controller.ts | 5 +- .../room/api/test/room-update.api.spec.ts | 81 ++++++++++++------- .../src/modules/room/domain/do/room.do.ts | 4 +- .../room/domain/service/room.service.ts | 14 +++- .../shared/controller/transformer/index.ts | 1 + .../null-to-undefined.transformer.spec.ts | 35 ++++++++ .../null-to-undefined.transformer.ts | 12 +++ 9 files changed, 127 insertions(+), 39 deletions(-) create mode 100644 apps/server/src/shared/controller/transformer/null-to-undefined.transformer.spec.ts create mode 100644 apps/server/src/shared/controller/transformer/null-to-undefined.transformer.ts diff --git a/apps/server/src/modules/room/api/dto/request/create-room.body.params.ts b/apps/server/src/modules/room/api/dto/request/create-room.body.params.ts index 8cb204691a3..42e4e5b586e 100644 --- a/apps/server/src/modules/room/api/dto/request/create-room.body.params.ts +++ b/apps/server/src/modules/room/api/dto/request/create-room.body.params.ts @@ -1,5 +1,5 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; -import { SanitizeHtml } from '@shared/controller'; +import { NullToUndefined, SanitizeHtml } from '@shared/controller'; import { RoomCreateProps } from '@modules/room/domain'; import { RoomColor } from '@modules/room/domain/type'; import { IsDate, IsEnum, IsOptional, IsString, MaxLength, MinLength } from 'class-validator'; @@ -23,8 +23,9 @@ export class CreateRoomBodyParams implements Omit { @IsEnum(RoomColor) color!: RoomColor; - @IsDate() @IsOptional() + @NullToUndefined() + @IsDate() @ApiPropertyOptional({ description: 'Start date of the room', required: false, @@ -32,8 +33,9 @@ export class CreateRoomBodyParams implements Omit { }) startDate?: Date; - @IsDate() @IsOptional() + @NullToUndefined() + @IsDate() @ApiPropertyOptional({ description: 'End date of the room', required: false, diff --git a/apps/server/src/modules/room/api/dto/request/update-room.body.params.ts b/apps/server/src/modules/room/api/dto/request/update-room.body.params.ts index 550357b7aca..71bf7ac10a1 100644 --- a/apps/server/src/modules/room/api/dto/request/update-room.body.params.ts +++ b/apps/server/src/modules/room/api/dto/request/update-room.body.params.ts @@ -1,7 +1,7 @@ -import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; -import { SanitizeHtml } from '@shared/controller'; import { RoomUpdateProps } from '@modules/room/domain'; import { RoomColor } from '@modules/room/domain/type'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +import { NullToUndefined, SanitizeHtml } from '@shared/controller'; import { IsDate, IsEnum, IsOptional, IsString, MaxLength, MinLength } from 'class-validator'; export class UpdateRoomBodyParams implements RoomUpdateProps { @@ -25,6 +25,7 @@ export class UpdateRoomBodyParams implements RoomUpdateProps { @IsDate() @IsOptional() + @NullToUndefined() @ApiPropertyOptional({ description: 'Start date of the room', required: false, @@ -34,6 +35,7 @@ export class UpdateRoomBodyParams implements RoomUpdateProps { @IsDate() @IsOptional() + @NullToUndefined() @ApiPropertyOptional({ description: 'Start date of the room', required: false, diff --git a/apps/server/src/modules/room/api/room.controller.ts b/apps/server/src/modules/room/api/room.controller.ts index 8a57be144df..b9a125787cc 100644 --- a/apps/server/src/modules/room/api/room.controller.ts +++ b/apps/server/src/modules/room/api/room.controller.ts @@ -11,6 +11,7 @@ import { Param, Patch, Post, + Put, Query, UnauthorizedException, } from '@nestjs/common'; @@ -115,8 +116,8 @@ export class RoomController { return response; } - @Patch(':roomId') - @ApiOperation({ summary: 'Create a new room' }) + @Put(':roomId') + @ApiOperation({ summary: 'Update an existing room' }) @ApiResponse({ status: HttpStatus.OK, description: 'Returns the details of a room', type: RoomDetailsResponse }) @ApiResponse({ status: HttpStatus.BAD_REQUEST, type: ApiValidationError }) @ApiResponse({ status: HttpStatus.UNAUTHORIZED, type: UnauthorizedException }) diff --git a/apps/server/src/modules/room/api/test/room-update.api.spec.ts b/apps/server/src/modules/room/api/test/room-update.api.spec.ts index 35b1c196f2d..782c23961d4 100644 --- a/apps/server/src/modules/room/api/test/room-update.api.spec.ts +++ b/apps/server/src/modules/room/api/test/room-update.api.spec.ts @@ -42,11 +42,11 @@ describe('Room Controller (API)', () => { await app.close(); }); - describe('PATCH /rooms/:id', () => { + describe('PUT /rooms/:id', () => { describe('when the user is not authenticated', () => { it('should return a 401 error', async () => { const someId = new ObjectId().toHexString(); - const response = await testApiClient.patch(someId); + const response = await testApiClient.put(someId); expect(response.status).toBe(HttpStatus.UNAUTHORIZED); }); }); @@ -68,7 +68,7 @@ describe('Room Controller (API)', () => { const { loggedInClient } = await setup(); const someId = new ObjectId().toHexString(); const params = { name: 'Room #101', color: 'green' }; - const response = await loggedInClient.patch(someId, params); + const response = await loggedInClient.put(someId, params); expect(response.status).toBe(HttpStatus.FORBIDDEN); }); }); @@ -87,7 +87,7 @@ describe('Room Controller (API)', () => { it('should return a 400 error', async () => { const { loggedInClient } = await setup(); const params = { name: 'Room #101', color: 'green' }; - const response = await loggedInClient.patch('42', params); + const response = await loggedInClient.put('42', params); expect(response.status).toBe(HttpStatus.BAD_REQUEST); }); }); @@ -121,7 +121,7 @@ describe('Room Controller (API)', () => { const someId = new ObjectId().toHexString(); const params = { name: 'Room #101', color: 'green' }; - const response = await loggedInClient.patch(someId, params); + const response = await loggedInClient.put(someId, params); expect(response.status).toBe(HttpStatus.NOT_FOUND); }); @@ -132,7 +132,7 @@ describe('Room Controller (API)', () => { const { loggedInClient, room } = await setup(); const params = { name: 'Room #101', color: 'green' }; - const response = await loggedInClient.patch(room.id, params); + const response = await loggedInClient.put(room.id, params); expect(response.status).toBe(HttpStatus.OK); await expect(em.findOneOrFail(RoomEntity, room.id)).resolves.toMatchObject({ @@ -147,7 +147,7 @@ describe('Room Controller (API)', () => { const { loggedInClient, room } = await setup(); const params = { name: '', color: 'red' }; - const response = await loggedInClient.patch(room.id, params); + const response = await loggedInClient.put(room.id, params); expect(response.status).toBe(HttpStatus.BAD_REQUEST); }); @@ -158,7 +158,7 @@ describe('Room Controller (API)', () => { const { loggedInClient, room } = await setup(); const params = { name: 'Room #101', color: '' }; - const response = await loggedInClient.patch(room.id, params); + const response = await loggedInClient.put(room.id, params); expect(response.status).toBe(HttpStatus.BAD_REQUEST); }); @@ -169,7 +169,7 @@ describe('Room Controller (API)', () => { const { loggedInClient, room } = await setup(); const params = { name: 'Room #101', color: 'fancy-color' }; - const response = await loggedInClient.patch(room.id, params); + const response = await loggedInClient.put(room.id, params); expect(response.status).toBe(HttpStatus.BAD_REQUEST); }); @@ -181,7 +181,7 @@ describe('Room Controller (API)', () => { const { loggedInClient, room } = await setup(); const params = { name: 'Room #101', color: 'green', startDate: '2024-10-02' }; - const response = await loggedInClient.patch(room.id, params); + const response = await loggedInClient.put(room.id, params); expect(response.status).toBe(HttpStatus.OK); await expect(em.findOneOrFail(RoomEntity, room.id)).resolves.toMatchObject({ @@ -194,7 +194,7 @@ describe('Room Controller (API)', () => { it('should return a 400 error', async () => { const { loggedInClient, room } = await setup(); const params = { name: 'Room #101', color: 'green', startDate: 'invalid date' }; - const response = await loggedInClient.patch(room.id, params); + const response = await loggedInClient.put(room.id, params); expect(response.status).toBe(HttpStatus.BAD_REQUEST); }); }); @@ -204,23 +204,35 @@ describe('Room Controller (API)', () => { const { loggedInClient, room } = await setup(); const params = { name: 'Room #101', color: 'green', startDate: null }; - const response = await loggedInClient.patch(room.id, params); + const response = await loggedInClient.put(room.id, params); expect(response.status).toBe(HttpStatus.OK); - await expect(em.findOneOrFail(RoomEntity, room.id)).resolves.toMatchObject({ - id: room.id, - startDate: null, - }); + const resultRoom = await em.findOneOrFail(RoomEntity, room.id); + expect(resultRoom.startDate).toBe(undefined); }); }); }); + describe('when the startDate is omitted', () => { + it('should unset the property', async () => { + const { loggedInClient, room } = await setup(); + const params = { name: 'Room #101', color: 'green' }; + + const response = await loggedInClient.put(room.id, params); + + expect(response.status).toBe(HttpStatus.OK); + + const resultRoom = await em.findOneOrFail(RoomEntity, room.id); + expect(resultRoom.endDate).toBe(undefined); + }); + }); + describe('when an end date is given', () => { it('should update the room', async () => { const { loggedInClient, room } = await setup(); const params = { name: 'Room #101', color: 'green', endDate: '2024-10-18' }; - const response = await loggedInClient.patch(room.id, params); + const response = await loggedInClient.put(room.id, params); expect(response.status).toBe(HttpStatus.OK); await expect(em.findOneOrFail(RoomEntity, room.id)).resolves.toMatchObject({ @@ -233,7 +245,7 @@ describe('Room Controller (API)', () => { it('should return a 400 error', async () => { const { loggedInClient, room } = await setup(); const params = { name: 'Room #101', color: 'green', endDate: 'invalid date' }; - const response = await loggedInClient.patch(room.id, params); + const response = await loggedInClient.put(room.id, params); expect(response.status).toBe(HttpStatus.BAD_REQUEST); }); }); @@ -241,19 +253,32 @@ describe('Room Controller (API)', () => { describe('when the date is null', () => { it('should unset the property', async () => { const { loggedInClient, room } = await setup(); - const params = { name: 'Room #101', color: 'green', endDate: null }; + const params = { name: 'Room #101', color: 'green', startDate: '2024-10-02', endDate: null }; - const response = await loggedInClient.patch(room.id, params); + const response = await loggedInClient.put(room.id, params); expect(response.status).toBe(HttpStatus.OK); - await expect(em.findOneOrFail(RoomEntity, room.id)).resolves.toMatchObject({ - id: room.id, - endDate: null, - }); + + const resultRoom = await em.findOneOrFail(RoomEntity, room.id); + expect(resultRoom.endDate).toBe(undefined); }); }); }); + describe('when the endDate is omitted', () => { + it('should unset the property', async () => { + const { loggedInClient, room } = await setup(); + const params = { name: 'Room #101', color: 'green', startDate: '2024-10-02' }; + + const response = await loggedInClient.put(room.id, params); + + expect(response.status).toBe(HttpStatus.OK); + + const resultRoom = await em.findOneOrFail(RoomEntity, room.id); + expect(resultRoom.endDate).toBe(undefined); + }); + }); + describe('when the start date is before the end date', () => { it('should update the room', async () => { const { loggedInClient, room } = await setup(); @@ -264,7 +289,7 @@ describe('Room Controller (API)', () => { endDate: '2024-10-18', }; - const response = await loggedInClient.patch(room.id, params); + const response = await loggedInClient.put(room.id, params); expect(response.status).toBe(HttpStatus.OK); await expect(em.findOneOrFail(RoomEntity, room.id)).resolves.toMatchObject({ @@ -285,7 +310,7 @@ describe('Room Controller (API)', () => { endDate: '2024-10-05', }; - const response = await loggedInClient.patch(room.id, params); + const response = await loggedInClient.put(room.id, params); expect(response.status).toBe(HttpStatus.BAD_REQUEST); }); @@ -313,7 +338,7 @@ describe('Room Controller (API)', () => { const someId = new ObjectId().toHexString(); const params = { name: 'Room #101', color: 'green' }; - const response = await loggedInClient.patch(someId, params); + const response = await loggedInClient.put(someId, params); expect(response.status).toBe(HttpStatus.NOT_FOUND); }); @@ -324,7 +349,7 @@ describe('Room Controller (API)', () => { const { loggedInClient, room } = await setup(); const params = { name: 'Room #101', color: 'green' }; - const response = await loggedInClient.patch(room.id, params); + const response = await loggedInClient.put(room.id, params); expect(response.status).toBe(HttpStatus.FORBIDDEN); }); diff --git a/apps/server/src/modules/room/domain/do/room.do.ts b/apps/server/src/modules/room/domain/do/room.do.ts index 309be132243..af6ccf005d4 100644 --- a/apps/server/src/modules/room/domain/do/room.do.ts +++ b/apps/server/src/modules/room/domain/do/room.do.ts @@ -55,7 +55,7 @@ export class Room extends DomainObject { return this.props.startDate; } - public set startDate(value: Date) { + public set startDate(value: Date | undefined) { this.props.startDate = value; } @@ -63,7 +63,7 @@ export class Room extends DomainObject { return this.props.endDate; } - public set endDate(value: Date) { + public set endDate(value: Date | undefined) { this.props.endDate = value; } diff --git a/apps/server/src/modules/room/domain/service/room.service.ts b/apps/server/src/modules/room/domain/service/room.service.ts index 4ec2c62c779..241b26a191a 100644 --- a/apps/server/src/modules/room/domain/service/room.service.ts +++ b/apps/server/src/modules/room/domain/service/room.service.ts @@ -26,7 +26,12 @@ export class RoomService { public async createRoom(props: RoomCreateProps): Promise { const roomProps: RoomProps = { id: new ObjectId().toHexString(), - ...props, + name: props.name, + color: props.color, + schoolId: props.schoolId, + // make sure that the dates are not null at runtime + startDate: props.startDate ?? undefined, + endDate: props.endDate ?? undefined, createdAt: new Date(), updatedAt: new Date(), }; @@ -46,7 +51,12 @@ export class RoomService { public async updateRoom(room: Room, props: RoomUpdateProps): Promise { this.validateTimeSpan(props, room.id); - Object.assign(room, props); + + room.name = props.name; + room.color = props.color; + // make sure that the dates are not null at runtime + room.startDate = props.startDate ?? undefined; + room.endDate = props.endDate ?? undefined; await this.roomRepo.save(room); } diff --git a/apps/server/src/shared/controller/transformer/index.ts b/apps/server/src/shared/controller/transformer/index.ts index 889f33130c7..1a037feef76 100644 --- a/apps/server/src/shared/controller/transformer/index.ts +++ b/apps/server/src/shared/controller/transformer/index.ts @@ -4,3 +4,4 @@ export * from './single-value-to-array.transformer'; export * from './sanitize-html.transformer'; export { PolymorphicArrayTransform } from './polymorphic-array.transformer'; export { StringToObject } from './string-to-object.transformer'; +export { NullToUndefined } from './null-to-undefined.transformer'; diff --git a/apps/server/src/shared/controller/transformer/null-to-undefined.transformer.spec.ts b/apps/server/src/shared/controller/transformer/null-to-undefined.transformer.spec.ts new file mode 100644 index 00000000000..490e8745be6 --- /dev/null +++ b/apps/server/src/shared/controller/transformer/null-to-undefined.transformer.spec.ts @@ -0,0 +1,35 @@ +import { plainToClass } from 'class-transformer'; +import { NullToUndefined } from './null-to-undefined.transformer'; + +describe('NullToUndefined Decorator', () => { + describe('when transforming an optionl value', () => { + class WithOptionalDto { + @NullToUndefined() + optionalDate?: Date; + } + + it('should transform from `null` to `undefined`', () => { + const props = { optionalDate: null }; + const instance = plainToClass(WithOptionalDto, props); + expect(instance.optionalDate).toEqual(undefined); + }); + + it('should transform from `undefined` to `undefined`', () => { + const props = { optionalDate: undefined }; + const instance = plainToClass(WithOptionalDto, props); + expect(instance.optionalDate).toEqual(undefined); + }); + + it('should transform from omitted property to `undefined`', () => { + const props = {}; + const instance = plainToClass(WithOptionalDto, props); + expect(instance.optionalDate).toEqual(undefined); + }); + + it('should transform from value to value', () => { + const props = { optionalDate: new Date() }; + const instance = plainToClass(WithOptionalDto, props); + expect(instance.optionalDate).toEqual(props.optionalDate); + }); + }); +}); diff --git a/apps/server/src/shared/controller/transformer/null-to-undefined.transformer.ts b/apps/server/src/shared/controller/transformer/null-to-undefined.transformer.ts new file mode 100644 index 00000000000..1be36c10825 --- /dev/null +++ b/apps/server/src/shared/controller/transformer/null-to-undefined.transformer.ts @@ -0,0 +1,12 @@ +import { Transform } from 'class-transformer'; + +/** + * Decorator to replace a null value by undefined. + * Can be used to make optinal values consistent. + * Place after IsOptional decorator. + * It will return undefined if the value is null. + * @returns + */ +export function NullToUndefined(): PropertyDecorator { + return Transform(({ value }): unknown => (value === null ? undefined : value)); +} From 0b47cd32765aed1889352baee21e1cf5c3ccc173 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 3 Dec 2024 18:52:54 +0100 Subject: [PATCH 57/60] add api tests --- ...haring-import-room-board-token.api.spec.ts | 108 +++++++ .../api-test/sharing-import-token.api.spec.ts | 283 ++++++++---------- .../src/modules/sharing/uc/share-token.uc.ts | 9 +- 3 files changed, 235 insertions(+), 165 deletions(-) create mode 100644 apps/server/src/modules/sharing/controller/api-test/sharing-import-room-board-token.api.spec.ts diff --git a/apps/server/src/modules/sharing/controller/api-test/sharing-import-room-board-token.api.spec.ts b/apps/server/src/modules/sharing/controller/api-test/sharing-import-room-board-token.api.spec.ts new file mode 100644 index 00000000000..5e4a85209ba --- /dev/null +++ b/apps/server/src/modules/sharing/controller/api-test/sharing-import-room-board-token.api.spec.ts @@ -0,0 +1,108 @@ +import { EntityManager } from '@mikro-orm/mongodb'; +import { HttpStatus, INestApplication } from '@nestjs/common'; +import { + cleanupCollections, + groupEntityFactory, + roleFactory, + TestApiClient, + UserAndAccountTestFactory, +} from '@shared/testing'; +import { ShareTokenService } from '../../service'; +import { Test } from '@nestjs/testing'; +import { ServerTestModule } from '@src/modules/server'; +import { Configuration } from '@hpi-schul-cloud/commons/lib'; +import { Permission, RoleName } from '@shared/domain/interface'; +import { roomEntityFactory } from '@src/modules/room/testing'; +import { GroupEntityTypes } from '@src/modules/group/entity'; +import { roomMembershipEntityFactory } from '@src/modules/room-membership/testing'; +import { ShareTokenParentType } from '../../domainobject/share-token.do'; +import { columnBoardEntityFactory } from '@src/modules/board/testing'; +import { BoardExternalReferenceType } from '@src/modules/board'; + +describe('Sharing Controller (API)', () => { + let app: INestApplication; + let em: EntityManager; + let testApiClient: TestApiClient; + let shareTokenService: ShareTokenService; + + beforeAll(async () => { + const module = await Test.createTestingModule({ + imports: [ServerTestModule], + }).compile(); + + app = module.createNestApplication(); + await app.init(); + em = module.get(EntityManager); + testApiClient = new TestApiClient(app, 'sharetoken'); + shareTokenService = module.get(ShareTokenService); + }); + + beforeEach(async () => { + await cleanupCollections(em); + Configuration.set('FEATURE_COLUMN_BOARD_SHARE', true); + }); + + afterAll(async () => { + await app.close(); + }); + + describe('POST /sharetoken/:token/import', () => { + const setup = async () => { + const room = roomEntityFactory.buildWithId(); + const role = roleFactory.buildWithId({ + name: RoleName.ROOMEDITOR, + permissions: [Permission.ROOM_EDIT], + }); + const { teacherAccount, teacherUser } = UserAndAccountTestFactory.buildTeacher(); + const userGroup = groupEntityFactory.buildWithId({ + type: GroupEntityTypes.ROOM, + users: [{ role, user: teacherUser }], + }); + const roomMembership = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + const board = columnBoardEntityFactory.build({ + context: { id: room.id, type: BoardExternalReferenceType.Room }, + }); + await em.persistAndFlush([room, roomMembership, teacherAccount, teacherUser, userGroup, role, board]); + em.clear(); + + const shareToken = await shareTokenService.createToken({ + parentId: board.id, + parentType: ShareTokenParentType.ColumnBoard, + }); + + const loggedInClient = await testApiClient.login(teacherAccount); + + return { loggedInClient, token: shareToken.token, room }; + }; + + describe('when the feature is disabled', () => { + beforeEach(() => { + Configuration.set('FEATURE_COLUMN_BOARD_SHARE', false); + }); + + it('should return a 403 error', async () => { + const { loggedInClient, token } = await setup(); + const response = await loggedInClient.post(`${token}/import`, { newName: 'NewName' }); + expect(response.status).toBe(HttpStatus.FORBIDDEN); + }); + }); + + describe('when the user has the required permissions', () => { + describe('when the destination is omitted', () => { + it('should return a 401 status', async () => { + const { loggedInClient, token } = await setup(); + const response = await loggedInClient.post(`${token}/import`, { newName: 'NewName' }); + expect(response.status).toBe(HttpStatus.BAD_REQUEST); + }); + }); + + describe('when the destination is valid', () => { + it('should return a 201 status', async () => { + const { loggedInClient, token, room } = await setup(); + const response = await loggedInClient.post(`${token}/import`, { newName: 'NewName', destinationId: room.id }); + expect(response.status).toBe(HttpStatus.CREATED); + }); + }); + }); + }); +}); diff --git a/apps/server/src/modules/sharing/controller/api-test/sharing-import-token.api.spec.ts b/apps/server/src/modules/sharing/controller/api-test/sharing-import-token.api.spec.ts index 9386b965857..ff24d2ed78b 100644 --- a/apps/server/src/modules/sharing/controller/api-test/sharing-import-token.api.spec.ts +++ b/apps/server/src/modules/sharing/controller/api-test/sharing-import-token.api.spec.ts @@ -1,211 +1,172 @@ import { Configuration } from '@hpi-schul-cloud/commons/lib'; -import { ICurrentUser, JwtAuthGuard } from '@infra/auth-guard'; import { EntityManager } from '@mikro-orm/mongodb'; import { CopyApiResponse, CopyElementType, CopyStatusEnum } from '@modules/copy-helper'; import { ServerTestModule } from '@modules/server'; -import { ExecutionContext, HttpStatus, INestApplication } from '@nestjs/common'; -import { Test, TestingModule } from '@nestjs/testing'; -import { ApiValidationError } from '@shared/common'; +import { HttpStatus, INestApplication } from '@nestjs/common'; +import { Test } from '@nestjs/testing'; import { Permission } from '@shared/domain/interface'; import { cleanupCollections, courseFactory, - mapUserToCurrentUser, roleFactory, schoolEntityFactory, + TestApiClient, + UserAndAccountTestFactory, userFactory, } from '@shared/testing'; -import { Request } from 'express'; -import request from 'supertest'; import { ShareTokenContext, ShareTokenContextType, ShareTokenParentType } from '../../domainobject/share-token.do'; import { ShareTokenService } from '../../service'; -import { ShareTokenImportBodyParams, ShareTokenResponse, ShareTokenUrlParams } from '../dto'; -const baseRouteName = '/sharetoken'; - -class API { - app: INestApplication; - - constructor(app: INestApplication) { - this.app = app; - } - - async post(urlParams: ShareTokenUrlParams, body: ShareTokenImportBodyParams) { - const response = await request(this.app.getHttpServer()) - .post(`${baseRouteName}/${urlParams.token}/import`) - .set('Accept', 'application/json') - .set('Authorization', 'jwt') - .send(body); - - return { - result: response.body as ShareTokenResponse, - error: response.body as ApiValidationError, - status: response.status, - }; - } -} - -describe(`share token import (api)`, () => { +describe(`Share Token Import (API)`, () => { let app: INestApplication; let em: EntityManager; - let currentUser: ICurrentUser; + let testApiClient: TestApiClient; let shareTokenService: ShareTokenService; - let api: API; beforeAll(async () => { - const module: TestingModule = await Test.createTestingModule({ + const module = await Test.createTestingModule({ imports: [ServerTestModule], - }) - .overrideGuard(JwtAuthGuard) - .useValue({ - canActivate(context: ExecutionContext) { - const req: Request = context.switchToHttp().getRequest(); - req.user = currentUser; - return true; - }, - }) - .compile(); + }).compile(); app = module.createNestApplication(); await app.init(); em = module.get(EntityManager); + testApiClient = new TestApiClient(app, 'sharetoken'); shareTokenService = module.get(ShareTokenService); - - api = new API(app); }); - afterAll(async () => { - await app.close(); - }); - - beforeEach(() => { + beforeEach(async () => { + await cleanupCollections(em); Configuration.set('FEATURE_COURSE_SHARE', true); }); - const setup = async (context?: ShareTokenContext) => { - await cleanupCollections(em); - const school = schoolEntityFactory.build(); - const roles = roleFactory.buildList(1, { - permissions: [Permission.COURSE_CREATE], - }); - const user = userFactory.build({ school, roles }); - const course = courseFactory.build({ teachers: [user] }); - await em.persistAndFlush([user, course]); - - const shareToken = await shareTokenService.createToken( - { - parentType: ShareTokenParentType.Course, - parentId: course.id, - }, - { context } - ); - - em.clear(); - - currentUser = mapUserToCurrentUser(user); - - return { - token: shareToken.token, - elementType: CopyElementType.COURSE, - }; - }; - - describe('with the feature disabled', () => { - it('should return status 500', async () => { - Configuration.set('FEATURE_COURSE_SHARE', false); - const { token } = await setup(); - - const response = await api.post({ token }, { newName: 'NewName' }); - - expect(response.status).toEqual(HttpStatus.INTERNAL_SERVER_ERROR); - }); + afterAll(async () => { + await app.close(); }); - describe('with a valid token', () => { - it('should return status 201', async () => { - const { token } = await setup(); - - const response = await api.post({ token }, { newName: 'NewName' }); - - expect(response.status).toEqual(HttpStatus.CREATED); + describe('POST /sharetoken/:token/import', () => { + describe('when the user is not authenticated', () => { + it('should return a 401 error', async () => { + const token = 'aaLnAEZ0xqIW'; + const response = await testApiClient.post(`${token}/import`, { + newName: 'NewName', + }); + expect(response.status).toBe(HttpStatus.UNAUTHORIZED); + }); }); - it('should return a valid result', async () => { - const { token, elementType } = await setup(); - const newName = 'NewName'; - const response = await api.post({ token }, { newName }); - - const expectedResult: CopyApiResponse = { - id: expect.any(String), - type: elementType, - title: newName, - status: CopyStatusEnum.SUCCESS, + describe('when the user is valid', () => { + const setup = async (context?: ShareTokenContext) => { + const school = schoolEntityFactory.build(); + const roles = roleFactory.buildList(1, { + permissions: [Permission.COURSE_CREATE], + }); + const user = userFactory.build({ school, roles }); + const course = courseFactory.build({ teachers: [user] }); + await em.persistAndFlush([user, course]); + + const shareToken = await shareTokenService.createToken( + { + parentType: ShareTokenParentType.Course, + parentId: course.id, + }, + { context } + ); + + const { teacherAccount, teacherUser } = UserAndAccountTestFactory.buildTeacher(); + await em.persistAndFlush([teacherAccount, teacherUser]); + em.clear(); + + const loggedInClient = await testApiClient.login(teacherAccount); + + return { + loggedInClient, + token: shareToken.token, + elementType: CopyElementType.COURSE, + }; }; - expect(response.result).toEqual(expect.objectContaining(expectedResult)); - }); - }); - - describe('with invalid token', () => { - it('should return status 404', async () => { - await setup(); - - const response = await api.post({ token: 'invalid_token' }, { newName: 'NewName' }); - - expect(response.status).toEqual(HttpStatus.NOT_FOUND); - }); - }); - - describe('with invalid context', () => { - const setup2 = async () => { - const school = schoolEntityFactory.build(); - const otherSchool = schoolEntityFactory.build(); - const roles = roleFactory.buildList(1, { - permissions: [Permission.COURSE_CREATE], + describe('with the feature disabled', () => { + beforeEach(() => { + Configuration.set('FEATURE_COURSE_SHARE', false); + }); + + it('should return a 403 error', async () => { + const { loggedInClient, token } = await setup(); + const response = await loggedInClient.post(`${token}/import`, { + newName: 'NewName', + }); + expect(response.status).toBe(HttpStatus.FORBIDDEN); + }); }); - const user = userFactory.build({ school, roles }); - const course = courseFactory.build({ teachers: [user] }); - await em.persistAndFlush([user, course, otherSchool]); - - const context = { - contextType: ShareTokenContextType.School, - contextId: otherSchool.id, - }; - - const shareToken = await shareTokenService.createToken( - { - parentType: ShareTokenParentType.Course, - parentId: course.id, - }, - { context } - ); + describe('with a valid token', () => { + it('should return status 201', async () => { + const { loggedInClient, token } = await setup(); + + const response = await loggedInClient.post(`${token}/import`, { + newName: 'NewName', + }); + + expect(response.status).toEqual(HttpStatus.CREATED); + }); + + it('should return a valid result', async () => { + const { loggedInClient, token, elementType } = await setup(); + const newName = 'NewName'; + const response = await loggedInClient.post(`${token}/import`, { + newName, + }); + const expectedResult: CopyApiResponse = { + id: expect.any(String), + type: elementType, + title: newName, + status: CopyStatusEnum.SUCCESS, + }; + + expect(response.body as CopyApiResponse).toEqual(expect.objectContaining(expectedResult)); + }); + }); - em.clear(); + describe('with invalid token', () => { + it('should return status 404', async () => { + const { loggedInClient } = await setup(); - currentUser = mapUserToCurrentUser(user); + const response = await loggedInClient.post(`invalid_token/import`, { + newName: 'NewName', + }); - return { - shareTokenFromDifferentCourse: shareToken.token, - }; - }; + expect(response.status).toEqual(HttpStatus.NOT_FOUND); + }); + }); - it('should return status 403', async () => { - const { shareTokenFromDifferentCourse } = await setup2(); + describe('with invalid context', () => { + it('should return status 403', async () => { + const otherSchool = schoolEntityFactory.build(); + await em.persistAndFlush(otherSchool); - const response = await api.post({ token: shareTokenFromDifferentCourse }, { newName: 'NewName' }); + const { loggedInClient, token: tokenFromOtherSchool } = await setup({ + contextId: otherSchool.id, + contextType: ShareTokenContextType.School, + }); - expect(response.status).toEqual(HttpStatus.FORBIDDEN); - }); - }); + const response = await loggedInClient.post(`${tokenFromOtherSchool}/import`, { + newName: 'NewName', + }); - describe('with invalid new name', () => { - it('should return status 501', async () => { - const { token } = await setup(); - // @ts-expect-error invalid new name - const response = await api.post({ token }, { newName: 42 }); + expect(response.status).toEqual(HttpStatus.FORBIDDEN); + }); + }); - expect(response.status).toEqual(HttpStatus.NOT_IMPLEMENTED); + describe('with invalid new name', () => { + it('should return status 501', async () => { + const { loggedInClient, token } = await setup(); + const response = await loggedInClient.post(`${token}/import`, { + newName: 42, + }); + expect(response.status).toEqual(HttpStatus.NOT_IMPLEMENTED); + }); + }); }); }); }); diff --git a/apps/server/src/modules/sharing/uc/share-token.uc.ts b/apps/server/src/modules/sharing/uc/share-token.uc.ts index b009c81cc7f..7f8a5391668 100644 --- a/apps/server/src/modules/sharing/uc/share-token.uc.ts +++ b/apps/server/src/modules/sharing/uc/share-token.uc.ts @@ -29,6 +29,7 @@ import { } from '../domainobject/share-token.do'; import { ShareTokenService } from '../service'; import { ShareTokenInfoDto } from './dto'; +import { FeatureDisabledLoggableException } from '@shared/common/loggable-exception'; @Injectable() export class ShareTokenUC { @@ -332,25 +333,25 @@ export class ShareTokenUC { case ShareTokenParentType.Course: // Configuration.get is the deprecated way to read envirment variables if (!(Configuration.get('FEATURE_COURSE_SHARE') as boolean)) { - throw new InternalServerErrorException('Import Course Feature not enabled'); + throw new FeatureDisabledLoggableException('FEATURE_COURSE_SHARE'); } break; case ShareTokenParentType.Lesson: // Configuration.get is the deprecated way to read envirment variables if (!(Configuration.get('FEATURE_LESSON_SHARE') as boolean)) { - throw new InternalServerErrorException('Import Lesson Feature not enabled'); + throw new FeatureDisabledLoggableException('FEATURE_LESSON_SHARE'); } break; case ShareTokenParentType.Task: // Configuration.get is the deprecated way to read envirment variables if (!(Configuration.get('FEATURE_TASK_SHARE') as boolean)) { - throw new InternalServerErrorException('Import Task Feature not enabled'); + throw new FeatureDisabledLoggableException('FEATURE_TASK_SHARE'); } break; case ShareTokenParentType.ColumnBoard: // Configuration.get is the deprecated way to read envirment variables if (!(Configuration.get('FEATURE_COLUMN_BOARD_SHARE') as boolean)) { - throw new InternalServerErrorException('Import Task Feature not enabled'); + throw new FeatureDisabledLoggableException('FEATURE_COLUMN_BOARD_SHARE'); } break; default: From 09eee1bb98ff2a7dc4efca60f4c40ce0847233cb Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 3 Dec 2024 19:28:15 +0100 Subject: [PATCH 58/60] fix tests and linting --- .../api-test/sharing-create-token.api.spec.ts | 4 ++-- .../sharing-import-room-board-token.api.spec.ts | 16 ++++++++-------- .../api-test/sharing-lookup-token.api.spec.ts | 10 ++-------- .../modules/sharing/uc/share-token.uc.spec.ts | 17 +++++++++-------- .../src/modules/sharing/uc/share-token.uc.ts | 12 ++++++------ 5 files changed, 27 insertions(+), 32 deletions(-) diff --git a/apps/server/src/modules/sharing/controller/api-test/sharing-create-token.api.spec.ts b/apps/server/src/modules/sharing/controller/api-test/sharing-create-token.api.spec.ts index 68423d68574..d7aa58a65e4 100644 --- a/apps/server/src/modules/sharing/controller/api-test/sharing-create-token.api.spec.ts +++ b/apps/server/src/modules/sharing/controller/api-test/sharing-create-token.api.spec.ts @@ -94,13 +94,13 @@ describe(`share token creation (api)`, () => { }; describe('with the feature disabled', () => { - it('should return status 500', async () => { + it('should return status 403', async () => { Configuration.set('FEATURE_COURSE_SHARE', false); const { course } = await setup(); const response = await api.post({ parentId: course.id, parentType: ShareTokenParentType.Course }); - expect(response.status).toEqual(HttpStatus.INTERNAL_SERVER_ERROR); + expect(response.status).toEqual(HttpStatus.FORBIDDEN); }); }); diff --git a/apps/server/src/modules/sharing/controller/api-test/sharing-import-room-board-token.api.spec.ts b/apps/server/src/modules/sharing/controller/api-test/sharing-import-room-board-token.api.spec.ts index 5e4a85209ba..799a1bcca32 100644 --- a/apps/server/src/modules/sharing/controller/api-test/sharing-import-room-board-token.api.spec.ts +++ b/apps/server/src/modules/sharing/controller/api-test/sharing-import-room-board-token.api.spec.ts @@ -1,5 +1,8 @@ +import { Configuration } from '@hpi-schul-cloud/commons/lib'; import { EntityManager } from '@mikro-orm/mongodb'; import { HttpStatus, INestApplication } from '@nestjs/common'; +import { Test } from '@nestjs/testing'; +import { Permission, RoleName } from '@shared/domain/interface'; import { cleanupCollections, groupEntityFactory, @@ -7,17 +10,14 @@ import { TestApiClient, UserAndAccountTestFactory, } from '@shared/testing'; -import { ShareTokenService } from '../../service'; -import { Test } from '@nestjs/testing'; -import { ServerTestModule } from '@src/modules/server'; -import { Configuration } from '@hpi-schul-cloud/commons/lib'; -import { Permission, RoleName } from '@shared/domain/interface'; -import { roomEntityFactory } from '@src/modules/room/testing'; +import { BoardExternalReferenceType } from '@src/modules/board'; +import { columnBoardEntityFactory } from '@src/modules/board/testing'; import { GroupEntityTypes } from '@src/modules/group/entity'; import { roomMembershipEntityFactory } from '@src/modules/room-membership/testing'; +import { roomEntityFactory } from '@src/modules/room/testing'; +import { ServerTestModule } from '@src/modules/server'; import { ShareTokenParentType } from '../../domainobject/share-token.do'; -import { columnBoardEntityFactory } from '@src/modules/board/testing'; -import { BoardExternalReferenceType } from '@src/modules/board'; +import { ShareTokenService } from '../../service'; describe('Sharing Controller (API)', () => { let app: INestApplication; diff --git a/apps/server/src/modules/sharing/controller/api-test/sharing-lookup-token.api.spec.ts b/apps/server/src/modules/sharing/controller/api-test/sharing-lookup-token.api.spec.ts index 57498162304..adf854d9b3d 100644 --- a/apps/server/src/modules/sharing/controller/api-test/sharing-lookup-token.api.spec.ts +++ b/apps/server/src/modules/sharing/controller/api-test/sharing-lookup-token.api.spec.ts @@ -59,18 +59,12 @@ describe(`share token lookup (api)`, () => { }; }; - it('should return status 500', async () => { + it('should return status 403', async () => { const { token, loggedInClient } = await setup(); const response = await loggedInClient.get(token); - expect(response.status).toEqual(HttpStatus.INTERNAL_SERVER_ERROR); - expect(response.body).toEqual({ - code: 500, - message: 'Import Course Feature not enabled', - title: 'Internal Server Error', - type: 'INTERNAL_SERVER_ERROR', - }); + expect(response.status).toEqual(HttpStatus.FORBIDDEN); }); }); diff --git a/apps/server/src/modules/sharing/uc/share-token.uc.spec.ts b/apps/server/src/modules/sharing/uc/share-token.uc.spec.ts index 3ef5be161e7..193f4606285 100644 --- a/apps/server/src/modules/sharing/uc/share-token.uc.spec.ts +++ b/apps/server/src/modules/sharing/uc/share-token.uc.spec.ts @@ -3,15 +3,19 @@ import { Configuration } from '@hpi-schul-cloud/commons/lib'; import { AuthorizationContextBuilder, AuthorizationService } from '@modules/authorization'; import { BoardExternalReferenceType, BoardNodeAuthorizableService, ColumnBoardService } from '@modules/board'; +import { CopyColumnBoardParams } from '@modules/board/service/internal'; import { boardNodeAuthorizableFactory, columnBoardFactory } from '@modules/board/testing'; import { CopyElementType, CopyStatus, CopyStatusEnum } from '@modules/copy-helper'; +import { StorageLocation } from '@modules/files-storage/interface'; import { CourseCopyService, CourseService } from '@modules/learnroom'; import { LessonCopyService, LessonService } from '@modules/lesson'; +import { RoomService } from '@modules/room'; import { SchoolService } from '@modules/school'; import { schoolFactory } from '@modules/school/testing'; import { TaskCopyService, TaskService } from '@modules/task'; -import { BadRequestException, InternalServerErrorException, NotImplementedException } from '@nestjs/common'; +import { BadRequestException, NotImplementedException } from '@nestjs/common'; import { Test, TestingModule } from '@nestjs/testing'; +import { FeatureDisabledLoggableException } from '@shared/common/loggable-exception'; import { Permission } from '@shared/domain/interface'; import { courseFactory, @@ -23,9 +27,6 @@ import { userFactory, } from '@shared/testing'; import { LegacyLogger } from '@src/core/logger'; -import { CopyColumnBoardParams } from '@modules/board/service/internal'; -import { StorageLocation } from '@modules/files-storage/interface'; -import { RoomService } from '@modules/room'; import { RoomMembershipService } from '@src/modules/room-membership'; import { ShareTokenContextType, ShareTokenParentType, ShareTokenPayload } from '../domainobject/share-token.do'; import { ShareTokenService } from '../service'; @@ -863,7 +864,7 @@ describe('ShareTokenUC', () => { Configuration.set('FEATURE_COURSE_SHARE', false); await expect(uc.importShareToken(user.id, shareToken.token, 'NewName')).rejects.toThrowError( - InternalServerErrorException + FeatureDisabledLoggableException ); }); @@ -936,7 +937,7 @@ describe('ShareTokenUC', () => { Configuration.set('FEATURE_LESSON_SHARE', false); await expect(uc.importShareToken(user.id, shareToken.token, 'NewName')).rejects.toThrowError( - InternalServerErrorException + FeatureDisabledLoggableException ); }); @@ -1022,7 +1023,7 @@ describe('ShareTokenUC', () => { Configuration.set('FEATURE_TASK_SHARE', false); await expect(uc.importShareToken(user.id, shareToken.token, 'NewName')).rejects.toThrowError( - InternalServerErrorException + FeatureDisabledLoggableException ); }); @@ -1105,7 +1106,7 @@ describe('ShareTokenUC', () => { const { user, shareToken } = setup(); Configuration.set('FEATURE_COLUMN_BOARD_SHARE', false); await expect(uc.importShareToken(user.id, shareToken.token, 'NewName')).rejects.toThrowError( - InternalServerErrorException + FeatureDisabledLoggableException ); }); it('should check the permission to create the columnboard', async () => { diff --git a/apps/server/src/modules/sharing/uc/share-token.uc.ts b/apps/server/src/modules/sharing/uc/share-token.uc.ts index 7f8a5391668..0e24d10565e 100644 --- a/apps/server/src/modules/sharing/uc/share-token.uc.ts +++ b/apps/server/src/modules/sharing/uc/share-token.uc.ts @@ -6,20 +6,21 @@ import { BoardNodeAuthorizableService, ColumnBoardService, } from '@modules/board'; +import { StorageLocationReference } from '@modules/board/service/internal'; import { CopyStatus } from '@modules/copy-helper'; +import { StorageLocation } from '@modules/files-storage/interface'; import { CourseCopyService, CourseService } from '@modules/learnroom'; import { LessonCopyService, LessonService } from '@modules/lesson'; +import { RoomService } from '@modules/room'; +import { SchoolService } from '@modules/school'; import { TaskCopyService, TaskService } from '@modules/task'; -import { BadRequestException, Injectable, InternalServerErrorException, NotImplementedException } from '@nestjs/common'; +import { BadRequestException, Injectable, NotImplementedException } from '@nestjs/common'; +import { FeatureDisabledLoggableException } from '@shared/common/loggable-exception'; import { Course, User } from '@shared/domain/entity'; import { Permission } from '@shared/domain/interface'; import { EntityId } from '@shared/domain/types'; import { LegacyLogger } from '@src/core/logger'; -import { StorageLocationReference } from '@modules/board/service/internal'; -import { StorageLocation } from '@modules/files-storage/interface'; -import { RoomService } from '@modules/room'; import { RoomMembershipService } from '@src/modules/room-membership'; -import { SchoolService } from '@modules/school'; import { ShareTokenContext, ShareTokenContextType, @@ -29,7 +30,6 @@ import { } from '../domainobject/share-token.do'; import { ShareTokenService } from '../service'; import { ShareTokenInfoDto } from './dto'; -import { FeatureDisabledLoggableException } from '@shared/common/loggable-exception'; @Injectable() export class ShareTokenUC { From ec854b1f00416f54e0985c27a389bbe2b7f68fa5 Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 3 Dec 2024 20:17:25 +0100 Subject: [PATCH 59/60] fix test coverage --- .../src/modules/sharing/uc/share-token.uc.ts | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/apps/server/src/modules/sharing/uc/share-token.uc.ts b/apps/server/src/modules/sharing/uc/share-token.uc.ts index 0e24d10565e..af4a079f10e 100644 --- a/apps/server/src/modules/sharing/uc/share-token.uc.ts +++ b/apps/server/src/modules/sharing/uc/share-token.uc.ts @@ -202,7 +202,7 @@ export class ShareTokenUC { type: originalBoard.context.type, }; - await this.checkBoardReferenceWritePermission(user, targetExternalReference); + await this.checkBoardContextWritePermission(user, targetExternalReference); const sourceStorageLocationReference = await this.getStorageLocationReference(originalBoard.context); const targetStorageLocationReference = await this.getStorageLocationReference(targetExternalReference); @@ -361,29 +361,30 @@ export class ShareTokenUC { // ---- Move to shared service? (see apps/server/src/modules/board/uc/board.uc.ts) - private async checkBoardReferenceWritePermission(user: User, boardExternalReference: BoardExternalReference) { - if (boardExternalReference.type === BoardExternalReferenceType.Course) { - await this.checkCourseWritePermission(user, boardExternalReference.id, Permission.COURSE_EDIT); - } else if (boardExternalReference.type === BoardExternalReferenceType.Room) { - await this.checkRoomWritePermission(user, boardExternalReference.id); + private async checkBoardContextWritePermission(user: User, boardContext: BoardExternalReference) { + if (boardContext.type === BoardExternalReferenceType.Course) { + await this.checkCourseWritePermission(user, boardContext.id, Permission.COURSE_EDIT); + } else if (boardContext.type === BoardExternalReferenceType.Room) { + await this.checkRoomWritePermission(user, boardContext.id); } else { - throw new Error(`Unsupported target reference type ${boardExternalReference.type as string}`); + /* istanbul ignore next */ + throw new Error(`Unsupported board reference type ${boardContext.type as string}`); } } - private async getStorageLocationReference(context: BoardExternalReference): Promise { - if (context.type === BoardExternalReferenceType.Course) { - const course = await this.courseService.findById(context.id); + private async getStorageLocationReference(boardContext: BoardExternalReference): Promise { + if (boardContext.type === BoardExternalReferenceType.Course) { + const course = await this.courseService.findById(boardContext.id); return { id: course.school.id, type: StorageLocation.SCHOOL }; } - if (context.type === BoardExternalReferenceType.Room) { - const room = await this.roomService.getSingleRoom(context.id); + if (boardContext.type === BoardExternalReferenceType.Room) { + const room = await this.roomService.getSingleRoom(boardContext.id); return { id: room.schoolId, type: StorageLocation.SCHOOL }; } - - throw new Error(`Cannot get storage location reference for context type ${context.type as string}`); + /* istanbul ignore next */ + throw new Error(`Unsupported board reference type ${boardContext.type as string}`); } } From 1d6d7fa846ae8e7a81d44a2b8afbbf2fde4caccb Mon Sep 17 00:00:00 2001 From: Uwe Ilgenstein Date: Tue, 3 Dec 2024 20:34:30 +0100 Subject: [PATCH 60/60] add api tests --- .../api-test/board-copy-in-room.api.spec.ts | 78 +++++++++++++++++++ apps/server/src/modules/board/uc/board.uc.ts | 4 +- 2 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 apps/server/src/modules/board/controller/api-test/board-copy-in-room.api.spec.ts diff --git a/apps/server/src/modules/board/controller/api-test/board-copy-in-room.api.spec.ts b/apps/server/src/modules/board/controller/api-test/board-copy-in-room.api.spec.ts new file mode 100644 index 00000000000..d833eb510b2 --- /dev/null +++ b/apps/server/src/modules/board/controller/api-test/board-copy-in-room.api.spec.ts @@ -0,0 +1,78 @@ +import { EntityManager } from '@mikro-orm/mongodb'; +import { INestApplication } from '@nestjs/common'; +import { Test, TestingModule } from '@nestjs/testing'; +import { Permission, RoleName } from '@shared/domain/interface'; +import { + cleanupCollections, + groupEntityFactory, + roleFactory, + TestApiClient, + UserAndAccountTestFactory, +} from '@shared/testing'; +import { GroupEntityTypes } from '@src/modules/group/entity'; +import { roomMembershipEntityFactory } from '@src/modules/room-membership/testing'; +import { roomEntityFactory } from '@src/modules/room/testing'; +import { ServerTestModule } from '@src/modules/server'; +import { BoardExternalReferenceType, ColumnBoardProps } from '../../domain'; +import { columnBoardEntityFactory } from '../../testing'; + +const baseRouteName = '/boards'; + +describe(`board copy with room relation (api)`, () => { + let app: INestApplication; + let em: EntityManager; + let testApiClient: TestApiClient; + + beforeAll(async () => { + const module: TestingModule = await Test.createTestingModule({ + imports: [ServerTestModule], + }).compile(); + + app = module.createNestApplication(); + await app.init(); + em = module.get(EntityManager); + testApiClient = new TestApiClient(app, baseRouteName); + }); + + afterAll(async () => { + await app.close(); + }); + + beforeEach(async () => { + await cleanupCollections(em); + }); + + describe('with valid user', () => { + const setup = async (columnBoardProps: Partial = {}) => { + const room = roomEntityFactory.buildWithId(); + const role = roleFactory.buildWithId({ + name: RoleName.ROOMEDITOR, + permissions: [Permission.ROOM_EDIT], + }); + const { teacherAccount, teacherUser } = UserAndAccountTestFactory.buildTeacher(); + const userGroup = groupEntityFactory.buildWithId({ + type: GroupEntityTypes.ROOM, + users: [{ role, user: teacherUser }], + }); + const roomMembership = roomMembershipEntityFactory.build({ roomId: room.id, userGroupId: userGroup.id }); + const columnBoardNode = columnBoardEntityFactory.build({ + ...columnBoardProps, + context: { id: room.id, type: BoardExternalReferenceType.Room }, + }); + await em.persistAndFlush([room, roomMembership, teacherAccount, teacherUser, userGroup, role, columnBoardNode]); + em.clear(); + + const loggedInClient = await testApiClient.login(teacherAccount); + + return { loggedInClient, columnBoardNode }; + }; + + it('should return status 201', async () => { + const { loggedInClient, columnBoardNode } = await setup(); + + const response = await loggedInClient.post(`${columnBoardNode.id}/copy`); + + expect(response.status).toEqual(201); + }); + }); +}); diff --git a/apps/server/src/modules/board/uc/board.uc.ts b/apps/server/src/modules/board/uc/board.uc.ts index c18a722304a..3dae0f22bb2 100644 --- a/apps/server/src/modules/board/uc/board.uc.ts +++ b/apps/server/src/modules/board/uc/board.uc.ts @@ -181,7 +181,7 @@ export class BoardUc { return { id: room.schoolId, type: StorageLocation.SCHOOL }; } - - throw new Error(`Cannot get storage location reference for context type ${context.type as string}`); + /* istanbul ignore next */ + throw new Error(`Unsupported board reference type ${context.type as string}`); } }