Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BC-8570 - add roommembers as viewers #5473

Merged
merged 19 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
1c209bd
add user as viewer to room
Metauriel Jan 29, 2025
cd73024
Merge branch 'main' into BC-8570-add-roommembers-as-viewer
hoeppner-dataport Jan 30, 2025
a729a37
Merge branch 'main' into BC-8570-add-roommembers-as-viewer
Metauriel Jan 30, 2025
36f2b62
Merge branch 'main' of https://github.com/hpi-schul-cloud/schulcloud-…
hoeppner-dataport Jan 31, 2025
a457f9e
return role of added room members
hoeppner-dataport Jan 31, 2025
7b96572
Merge branch 'main' into BC-8570-add-roommembers-as-viewer
hoeppner-dataport Feb 4, 2025
3e93d9d
Merge branch 'main' of https://github.com/hpi-schul-cloud/schulcloud-…
hoeppner-dataport Feb 5, 2025
7a43e88
add ROOM_LEAVE permission for room-admin, -editor and -viewer
hoeppner-dataport Feb 5, 2025
f994313
chore: fix method accessors
hoeppner-dataport Feb 6, 2025
877766e
Merge branch 'main' into BC-8570-add-roommembers-as-viewer
hoeppner-dataport Feb 6, 2025
3e72720
make leaving room depend on ROOM_LEAVE permission
hoeppner-dataport Feb 6, 2025
e18662e
Merge branch 'main' of https://github.com/hpi-schul-cloud/schulcloud-…
hoeppner-dataport Feb 6, 2025
46963f7
Merge branch 'BC-8570-add-roommembers-as-viewer' of https://github.co…
hoeppner-dataport Feb 6, 2025
b6f8c9e
remove ROOM_LEAVE permission from role RoomViewer
hoeppner-dataport Feb 6, 2025
37f0c1c
Merge branch 'main' of https://github.com/hpi-schul-cloud/schulcloud-…
hoeppner-dataport Feb 6, 2025
50c84db
add leaveRoom endpoint
hoeppner-dataport Feb 6, 2025
46b421f
update seed data
hoeppner-dataport Feb 6, 2025
22ac126
update migrations
hoeppner-dataport Feb 7, 2025
4e35c02
Merge branch 'main' into BC-8570-add-roommembers-as-viewer
hoeppner-dataport Feb 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions apps/server/src/migrations/mikro-orm/Migration20250205101112.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Migration } from '@mikro-orm/migrations-mongodb';

export class Migration20250205101112 extends Migration {
public async up(): Promise<void> {
const adminRoleUpdate = await this.getCollection('roles').updateOne(
{ name: 'roomadmin' },
{
$addToSet: {
permissions: {
$each: ['ROOM_LEAVE'],
},
},
}
);

if (adminRoleUpdate.modifiedCount > 0) {
console.info('Permission ROOM_LEAVE added to role roomadmin.');
}

const editorRoleUpdate = await this.getCollection('roles').updateOne(
{ name: 'roomeditor' },
{
$addToSet: {
permissions: {
$each: ['ROOM_LEAVE'],
},
},
}
);

if (editorRoleUpdate.modifiedCount > 0) {
console.info('Permission ROOM_LEAVE added to role roomeditor.');
}
}

public async down(): Promise<void> {
const adminRoleUpdate = await this.getCollection('roles').updateOne(
{ name: 'roomadmin' },
{
$pull: {
permissions: {
$in: ['ROOM_LEAVE'],
},
},
}
);

if (adminRoleUpdate.modifiedCount > 0) {
console.info('Rollback: Permission ROOM_LEAVE added to role roomadmin.');
}

const editorRoleUpdate = await this.getCollection('roles').updateOne(
{ name: 'roomeditor' },
{
$pull: {
permissions: {
$in: ['ROOM_LEAVE'],
},
},
}
);

if (editorRoleUpdate.modifiedCount > 0) {
console.info('Rollback: Permission ROOM_LEAVE added to role roomeditor.');
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export class BoardCollaborationGateway implements OnGatewayDisconnect {
private readonly metricsService: MetricsService
) {}

trackExecutionTime(methodName: string, executionTimeMs: number) {
public trackExecutionTime(methodName: string, executionTimeMs: number): void {
if (this.metricsService) {
this.metricsService.setExecutionTime(methodName, executionTimeMs);
this.metricsService.incrementActionCount(methodName);
Expand All @@ -77,7 +77,7 @@ export class BoardCollaborationGateway implements OnGatewayDisconnect {
return user;
}

private async updateRoomsAndUsersMetrics(socket: Socket) {
private async updateRoomsAndUsersMetrics(socket: Socket): Promise<void> {
const roomCount = Array.from(this.server.of('/').adapter.rooms.keys()).filter((key) =>
key.startsWith('board_')
).length;
Expand All @@ -92,7 +92,7 @@ export class BoardCollaborationGateway implements OnGatewayDisconnect {

@SubscribeMessage('delete-board-request')
@UseRequestContext()
async deleteBoard(socket: Socket, data: DeleteBoardMessageParams) {
public async deleteBoard(socket: Socket, data: DeleteBoardMessageParams): Promise<void> {
const emitter = this.buildBoardSocketEmitter({ socket, action: 'delete-board' });
const { userId } = this.getCurrentUser(socket);
try {
Expand All @@ -107,7 +107,7 @@ export class BoardCollaborationGateway implements OnGatewayDisconnect {
@SubscribeMessage('update-board-title-request')
@TrackExecutionTime()
@UseRequestContext()
async updateBoardTitle(socket: Socket, data: UpdateBoardTitleMessageParams) {
public async updateBoardTitle(socket: Socket, data: UpdateBoardTitleMessageParams): Promise<void> {
const emitter = this.buildBoardSocketEmitter({ socket, action: 'update-board-title' });
const { userId } = this.getCurrentUser(socket);
try {
Expand All @@ -122,7 +122,7 @@ export class BoardCollaborationGateway implements OnGatewayDisconnect {
@SubscribeMessage('update-card-title-request')
@TrackExecutionTime()
@UseRequestContext()
async updateCardTitle(socket: Socket, data: UpdateCardTitleMessageParams) {
public async updateCardTitle(socket: Socket, data: UpdateCardTitleMessageParams): Promise<void> {
const emitter = this.buildBoardSocketEmitter({ socket, action: 'update-card-title' });
const { userId } = this.getCurrentUser(socket);
try {
Expand All @@ -137,7 +137,7 @@ export class BoardCollaborationGateway implements OnGatewayDisconnect {
@SubscribeMessage('update-card-height-request')
@TrackExecutionTime()
@UseRequestContext()
async updateCardHeight(socket: Socket, data: UpdateCardHeightMessageParams) {
public async updateCardHeight(socket: Socket, data: UpdateCardHeightMessageParams): Promise<void> {
const emitter = this.buildBoardSocketEmitter({ socket, action: 'update-card-height' });
const { userId } = this.getCurrentUser(socket);
try {
Expand All @@ -152,7 +152,7 @@ export class BoardCollaborationGateway implements OnGatewayDisconnect {
@SubscribeMessage('delete-card-request')
@TrackExecutionTime()
@UseRequestContext()
async deleteCard(socket: Socket, data: DeleteCardMessageParams) {
public async deleteCard(socket: Socket, data: DeleteCardMessageParams): Promise<void> {
const emitter = this.buildBoardSocketEmitter({ socket, action: 'delete-card' });
const { userId } = this.getCurrentUser(socket);
try {
Expand All @@ -167,7 +167,7 @@ export class BoardCollaborationGateway implements OnGatewayDisconnect {
@SubscribeMessage('create-card-request')
@TrackExecutionTime()
@UseRequestContext()
async createCard(socket: Socket, data: CreateCardMessageParams) {
public async createCard(socket: Socket, data: CreateCardMessageParams): Promise<void> {
const emitter = this.buildBoardSocketEmitter({ socket, action: 'create-card' });
const { userId } = this.getCurrentUser(socket);
try {
Expand All @@ -189,7 +189,7 @@ export class BoardCollaborationGateway implements OnGatewayDisconnect {
@SubscribeMessage('create-column-request')
@TrackExecutionTime()
@UseRequestContext()
async createColumn(socket: Socket, data: CreateColumnMessageParams) {
public async createColumn(socket: Socket, data: CreateColumnMessageParams) {
const emitter = this.buildBoardSocketEmitter({ socket, action: 'create-column' });
const { userId } = this.getCurrentUser(socket);
try {
Expand All @@ -215,7 +215,7 @@ export class BoardCollaborationGateway implements OnGatewayDisconnect {
@SubscribeMessage('fetch-board-request')
@TrackExecutionTime()
@UseRequestContext()
async fetchBoard(socket: Socket, data: FetchBoardMessageParams) {
public async fetchBoard(socket: Socket, data: FetchBoardMessageParams): Promise<void> {
const emitter = this.buildBoardSocketEmitter({ socket, action: 'fetch-board' });
const { userId } = this.getCurrentUser(socket);
try {
Expand All @@ -232,7 +232,7 @@ export class BoardCollaborationGateway implements OnGatewayDisconnect {
@SubscribeMessage('move-card-request')
@TrackExecutionTime()
@UseRequestContext()
async moveCard(socket: Socket, data: MoveCardMessageParams) {
public async moveCard(socket: Socket, data: MoveCardMessageParams): Promise<void> {
const emitter = this.buildBoardSocketEmitter({ socket, action: 'move-card' });
const { userId } = this.getCurrentUser(socket);
try {
Expand All @@ -247,7 +247,7 @@ export class BoardCollaborationGateway implements OnGatewayDisconnect {
@SubscribeMessage('move-column-request')
@TrackExecutionTime()
@UseRequestContext()
async moveColumn(socket: Socket, data: MoveColumnMessageParams) {
public async moveColumn(socket: Socket, data: MoveColumnMessageParams): Promise<void> {
const emitter = this.buildBoardSocketEmitter({ socket, action: 'move-column' });
const { userId } = this.getCurrentUser(socket);
try {
Expand All @@ -267,7 +267,7 @@ export class BoardCollaborationGateway implements OnGatewayDisconnect {
@SubscribeMessage('update-column-title-request')
@TrackExecutionTime()
@UseRequestContext()
async updateColumnTitle(socket: Socket, data: UpdateColumnTitleMessageParams) {
public async updateColumnTitle(socket: Socket, data: UpdateColumnTitleMessageParams): Promise<void> {
const emitter = this.buildBoardSocketEmitter({ socket, action: 'update-column-title' });
const { userId } = this.getCurrentUser(socket);
try {
Expand All @@ -282,7 +282,7 @@ export class BoardCollaborationGateway implements OnGatewayDisconnect {
@SubscribeMessage('update-board-visibility-request')
@TrackExecutionTime()
@UseRequestContext()
async updateBoardVisibility(socket: Socket, data: UpdateBoardVisibilityMessageParams) {
public async updateBoardVisibility(socket: Socket, data: UpdateBoardVisibilityMessageParams): Promise<void> {
const emitter = this.buildBoardSocketEmitter({ socket, action: 'update-board-visibility' });
const { userId } = this.getCurrentUser(socket);
try {
Expand Down Expand Up @@ -312,7 +312,7 @@ export class BoardCollaborationGateway implements OnGatewayDisconnect {
@SubscribeMessage('delete-column-request')
@TrackExecutionTime()
@UseRequestContext()
async deleteColumn(socket: Socket, data: DeleteColumnMessageParams) {
public async deleteColumn(socket: Socket, data: DeleteColumnMessageParams): Promise<void> {
const emitter = this.buildBoardSocketEmitter({ socket, action: 'delete-column' });
const { userId } = this.getCurrentUser(socket);
try {
Expand All @@ -327,7 +327,7 @@ export class BoardCollaborationGateway implements OnGatewayDisconnect {
@SubscribeMessage('fetch-card-request')
@TrackExecutionTime()
@UseRequestContext()
async fetchCards(socket: Socket, data: FetchCardsMessageParams) {
public async fetchCards(socket: Socket, data: FetchCardsMessageParams): Promise<void> {
const emitter = this.buildBoardSocketEmitter({ socket, action: 'fetch-card' });
const { userId } = this.getCurrentUser(socket);
try {
Expand All @@ -344,7 +344,7 @@ export class BoardCollaborationGateway implements OnGatewayDisconnect {
@SubscribeMessage('create-element-request')
@TrackExecutionTime()
@UseRequestContext()
async createElement(socket: Socket, data: CreateContentElementMessageParams) {
public async createElement(socket: Socket, data: CreateContentElementMessageParams): Promise<void> {
const emitter = this.buildBoardSocketEmitter({ socket, action: 'create-element' });
const { userId } = this.getCurrentUser(socket);
try {
Expand All @@ -364,7 +364,7 @@ export class BoardCollaborationGateway implements OnGatewayDisconnect {
@SubscribeMessage('update-element-request')
@TrackExecutionTime()
@UseRequestContext()
async updateElement(socket: Socket, data: UpdateContentElementMessageParams) {
public async updateElement(socket: Socket, data: UpdateContentElementMessageParams): Promise<void> {
const emitter = this.buildBoardSocketEmitter({ socket, action: 'update-element' });
const { userId } = this.getCurrentUser(socket);
try {
Expand All @@ -379,7 +379,7 @@ export class BoardCollaborationGateway implements OnGatewayDisconnect {
@SubscribeMessage('delete-element-request')
@TrackExecutionTime()
@UseRequestContext()
async deleteElement(socket: Socket, data: DeleteContentElementMessageParams) {
public async deleteElement(socket: Socket, data: DeleteContentElementMessageParams): Promise<void> {
const emitter = this.buildBoardSocketEmitter({ socket, action: 'delete-element' });
const { userId } = this.getCurrentUser(socket);

Expand All @@ -395,7 +395,7 @@ export class BoardCollaborationGateway implements OnGatewayDisconnect {
@SubscribeMessage('move-element-request')
@TrackExecutionTime()
@UseRequestContext()
async moveElement(socket: Socket, data: MoveContentElementMessageParams) {
public async moveElement(socket: Socket, data: MoveContentElementMessageParams): Promise<void> {
const emitter = this.buildBoardSocketEmitter({ socket, action: 'move-element' });
const { userId } = this.getCurrentUser(socket);

Expand Down
2 changes: 2 additions & 0 deletions apps/server/src/modules/room-membership/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ export * from './do/room-membership.do';
export * from './room-membership.module';
export { RoomMembershipEntity, RoomMembershipRepo, RoomMembershipService };

export { RoomMembershipConfig } from './room-membership-config';

export { UserWithRoomRoles, RoomMembershipAuthorizable } from './do/room-membership-authorizable.do';
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface RoomMembershipConfig {
FEATURE_ROOMS_CHANGE_PERMISSIONS_ENABLED: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { roomFactory } from '@modules/room/testing';
import { schoolFactory } from '@modules/school/testing';
import { UserService } from '@modules/user';
import { BadRequestException } from '@nestjs/common/exceptions';
import { ConfigService } from '@nestjs/config';
import { Test, TestingModule } from '@nestjs/testing';
import { RoleName } from '@shared/domain/interface';
import { MongoMemoryDatabaseModule } from '@testing/database';
Expand All @@ -28,6 +29,7 @@ describe('RoomMembershipService', () => {
let roleService: DeepMocked<RoleService>;
let roomService: DeepMocked<RoomService>;
let userService: DeepMocked<UserService>;
let configService: DeepMocked<ConfigService>;

beforeAll(async () => {
module = await Test.createTestingModule({
Expand All @@ -54,6 +56,10 @@ describe('RoomMembershipService', () => {
provide: UserService,
useValue: createMock<UserService>(),
},
{
provide: ConfigService,
useValue: createMock<ConfigService>(),
},
],
}).compile();

Expand All @@ -63,6 +69,7 @@ describe('RoomMembershipService', () => {
roleService = module.get(RoleService);
roomService = module.get(RoomService);
userService = module.get(UserService);
configService = module.get(ConfigService);
});

afterAll(async () => {
Expand Down Expand Up @@ -113,6 +120,11 @@ describe('RoomMembershipService', () => {
schoolId: school.id,
});

configService.get.mockImplementation((key) => {
if (key === 'FEATURE_ROOMS_CHANGE_PERMISSIONS_ENABLED') return true;
return undefined;
});

roomMembershipRepo.findByRoomId.mockResolvedValue(roomMembership);

return {
Expand All @@ -123,14 +135,13 @@ describe('RoomMembershipService', () => {
};
};

it('should add user as admin to existing roomMembership', async () => {
// TODO: in the future, once room roles can be changed, this should become ROOMVIEWER
it('should add user to room as viewer', async () => {
const { user, room, group } = setup();

await service.addMembersToRoom(room.id, [user.id]);

expect(groupService.addUsersToGroup).toHaveBeenCalledWith(group.id, [
{ userId: user.id, roleName: RoleName.ROOMADMIN },
{ userId: user.id, roleName: RoleName.ROOMVIEWER },
]);
});

Expand All @@ -141,6 +152,29 @@ describe('RoomMembershipService', () => {

expect(userService.addSecondarySchoolToUsers).toHaveBeenCalledWith([user.id], room.schoolId);
});

describe('when role change is disabled', () => {
const setupWithRoleChangeDisabled = () => {
const { user, room, group } = setup();

configService.get.mockImplementation((key) => {
if (key === 'FEATURE_ROOMS_CHANGE_PERMISSIONS_ENABLED') return false;
return undefined;
});

return { user, room, group };
};

it('should add user to room as admin', async () => {
const { user, room, group } = setupWithRoleChangeDisabled();

await service.addMembersToRoom(room.id, [user.id]);

expect(groupService.addUsersToGroup).toHaveBeenCalledWith(group.id, [
{ userId: user.id, roleName: RoleName.ROOMADMIN },
]);
});
});
});
});

Expand Down
Loading
Loading