Skip to content

Commit

Permalink
add skeleton for controller and uc
Browse files Browse the repository at this point in the history
  • Loading branch information
Metauriel committed Jan 17, 2025
1 parent bc7f9bf commit 9da8ddb
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 6 deletions.
14 changes: 14 additions & 0 deletions apps/server/src/modules/room/api/room.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,20 @@ export class RoomController {
await this.roomUc.addMembersToRoom(currentUser.userId, urlParams.roomId, bodyParams.userIds);
}

@Patch(':roomId/members/roles')
@ApiOperation({ summary: 'Change the roles that members have within the room' })
@ApiResponse({ status: HttpStatus.OK, description: 'Adding successful', type: String })
@ApiResponse({ status: HttpStatus.BAD_REQUEST, type: ApiValidationError })
@ApiResponse({ status: HttpStatus.UNAUTHORIZED, type: UnauthorizedException })
@ApiResponse({ status: HttpStatus.FORBIDDEN, type: ForbiddenException })
@ApiResponse({ status: '5XX', type: ErrorResponse })
public async changeRolesOfMembers(
@CurrentUser() currentUser: ICurrentUser,
@Param() urlParams: RoomUrlParams
): Promise<void> {
await this.roomUc.changeRolesOfMembers(currentUser.userId, urlParams.roomId);
}

@Patch(':roomId/members/remove')
@ApiOperation({ summary: 'Remove members from a room' })
@ApiResponse({ status: HttpStatus.OK, description: 'Removing successful', type: String })
Expand Down
22 changes: 16 additions & 6 deletions apps/server/src/modules/room/api/room.uc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,6 @@ export class RoomUc {
return memberResponses;
}

public async addMembersToRoom(currentUserId: EntityId, roomId: EntityId, userIds: Array<EntityId>): Promise<void> {
this.checkFeatureEnabled();
await this.checkRoomAuthorization(currentUserId, roomId, Action.write, [Permission.ROOM_MEMBERS_ADD]);
await this.roomMembershipService.addMembersToRoom(roomId, userIds);
}

private mapToMember(member: UserWithRoomRoles, user: UserDO): RoomMemberResponse {
return new RoomMemberResponse({
userId: member.userId,
Expand All @@ -141,6 +135,22 @@ export class RoomUc {
});
}

public async addMembersToRoom(currentUserId: EntityId, roomId: EntityId, userIds: Array<EntityId>): Promise<void> {
this.checkFeatureEnabled();
await this.checkRoomAuthorization(currentUserId, roomId, Action.write, [Permission.ROOM_MEMBERS_ADD]);
await this.roomMembershipService.addMembersToRoom(roomId, userIds);
}

public async changeRolesOfMembers(
currentUserId: EntityId,
roomId: EntityId
// userIds: Array<EntityId>
): Promise<void> {
this.checkFeatureEnabled();
await this.checkRoomAuthorization(currentUserId, roomId, Action.write, [Permission.ROOM_MEMBERS_CHANGE_ROLE]);
return Promise.resolve();
}

public async removeMembersFromRoom(currentUserId: EntityId, roomId: EntityId, userIds: EntityId[]): Promise<void> {
this.checkFeatureEnabled();
await this.checkRoomAuthorization(currentUserId, roomId, Action.write, [Permission.ROOM_MEMBERS_REMOVE]);
Expand Down
159 changes: 159 additions & 0 deletions apps/server/src/modules/room/api/test/room-change-role.api.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import { EntityManager } from '@mikro-orm/mongodb';
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,
schoolEntityFactory,
} from '@shared/testing';
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)', () => {
let app: INestApplication;
let em: EntityManager;
let testApiClient: TestApiClient;
let config: ServerConfig;

beforeAll(async () => {
const moduleFixture = await Test.createTestingModule({
imports: [ServerTestModule],
}).compile();

app = moduleFixture.createNestApplication();
await app.init();
em = app.get(EntityManager);
testApiClient = new TestApiClient(app, 'rooms');

config = serverConfig();
});

beforeEach(async () => {
await cleanupCollections(em);
config.FEATURE_ROOMS_ENABLED = true;
});

afterAll(async () => {
await app.close();
});

describe('PATCH /rooms/:roomId/members/roles', () => {
const setupRoomWithMembers = async () => {
const school = schoolEntityFactory.buildWithId();
const { teacherAccount, teacherUser } = UserAndAccountTestFactory.buildTeacher({ school });
const { teacherAccount: otherTeacherAccount, teacherUser: otherTeacherUser } =
UserAndAccountTestFactory.buildTeacher({ school: teacherUser.school });
const room = roomEntityFactory.buildWithId({ schoolId: teacherUser.school.id });
const teacherGuestRole = roleFactory.buildWithId({ name: RoleName.GUESTTEACHER });
const studentGuestRole = roleFactory.buildWithId({ name: RoleName.GUESTSTUDENT });
const role = roleFactory.buildWithId({
name: RoleName.ROOMADMIN,
permissions: [
Permission.ROOM_VIEW,
Permission.ROOM_EDIT,
Permission.ROOM_MEMBERS_ADD,
Permission.ROOM_MEMBERS_REMOVE,
Permission.ROOM_MEMBERS_CHANGE_ROLE,
],
});
const roomEditorRole = roleFactory.buildWithId({
name: RoleName.ROOMEDITOR,
permissions: [Permission.ROOM_VIEW, Permission.ROOM_EDIT],
});
// TODO: add more than one user
const userGroupEntity = groupEntityFactory.buildWithId({
users: [{ role, user: teacherUser }],
type: GroupEntityTypes.ROOM,
organization: teacherUser.school,
externalSource: undefined,
});

const roomMemberships = roomMembershipEntityFactory.build({
userGroupId: userGroupEntity.id,
roomId: room.id,
schoolId: school.id,
});
await em.persistAndFlush([
room,
roomMemberships,
teacherAccount,
teacherUser,
teacherGuestRole,
studentGuestRole,
roomEditorRole,
otherTeacherUser,
otherTeacherAccount,
userGroupEntity,
]);
em.clear();

const loggedInClient = await testApiClient.login(teacherAccount);

return { loggedInClient, room, otherTeacherUser };
};

describe('when the user is not authenticated', () => {
it('should return a 401 error', async () => {
const { room } = await setupRoomWithMembers();

const response = await testApiClient.patch(`/${room.id}/members/roles`);

expect(response.status).toBe(HttpStatus.UNAUTHORIZED);
});
});

describe('when the user has not the required permissions', () => {
const setupLoggedInUser = async () => {
const { teacherAccount, teacherUser } = UserAndAccountTestFactory.buildTeacher();
await em.persistAndFlush([teacherAccount, teacherUser]);

const loggedInClient = await testApiClient.login(teacherAccount);

return { loggedInClient };
};

it('should return forbidden error', async () => {
const { room, otherTeacherUser } = await setupRoomWithMembers();
const { loggedInClient } = await setupLoggedInUser();

const response = await loggedInClient.patch(`/${room.id}/members/roles`, {
userIds: [otherTeacherUser.id],
});

expect(response.status).toBe(HttpStatus.FORBIDDEN);
});
});

describe('when the feature is disabled', () => {
it('should return a 403 error', async () => {
const { loggedInClient, room, otherTeacherUser } = await setupRoomWithMembers();
config.FEATURE_ROOMS_ENABLED = false;

const response = await loggedInClient.patch(`/${room.id}/members/roles`, {
userIds: [otherTeacherUser.id],
});

expect(response.status).toBe(HttpStatus.FORBIDDEN);
});
});

describe('when the user has the required permissions', () => {
it('should return OK', async () => {
const { loggedInClient, room, otherTeacherUser } = await setupRoomWithMembers();

const response = await loggedInClient.patch(`/${room.id}/members/roles`, {
userIds: [otherTeacherUser.id],
});

expect(response.status).toBe(HttpStatus.OK);
});
});
});
});
1 change: 1 addition & 0 deletions apps/server/src/shared/domain/interface/permission.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export enum Permission {
ROOM_DELETE = 'ROOM_DELETE',
ROOM_MEMBERS_ADD = 'ROOM_MEMBERS_ADD',
ROOM_MEMBERS_REMOVE = 'ROOM_MEMBERS_REMOVE',
ROOM_MEMBERS_CHANGE_ROLE = 'ROOM_MEMBERS_CHANGE_ROLE',
ROOM_CHANGE_OWNER = 'ROOM_CHANGE_OWNER',
SCHOOL_CHAT_MANAGE = 'SCHOOL_CHAT_MANAGE',
SCHOOL_CREATE = 'SCHOOL_CREATE',
Expand Down

0 comments on commit 9da8ddb

Please sign in to comment.