Skip to content

Commit d4966ab

Browse files
committed
feat: 설정 페이지 입장 API 구현
- joinSetting 이벤트 추가 - 설정 페이지 입장시 프로젝트의 이름, 주제, 회원 데이터 응답 구현 - 설정페이지 응답 DTO 추가 - E2E테스트 추가
1 parent 4fdad7b commit d4966ab

File tree

4 files changed

+157
-0
lines changed

4 files changed

+157
-0
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { Member } from 'src/member/entity/member.entity';
2+
import { Project } from 'src/project/entity/project.entity';
3+
import { MemberRole } from 'src/project/enum/MemberRole.enum';
4+
5+
class ProjectMemberDto {
6+
id: number;
7+
username: string;
8+
imageUrl: string;
9+
role: MemberRole;
10+
11+
static of(member: Member): ProjectMemberDto {
12+
const dto = new ProjectMemberDto();
13+
dto.id = member.id;
14+
dto.username = member.username;
15+
dto.imageUrl = member.github_image_url;
16+
dto.role = member.projectToMember[0].role;
17+
return dto;
18+
}
19+
}
20+
21+
class ProjectDto {
22+
title: string;
23+
subject: string;
24+
25+
static of(project: Project): ProjectDto {
26+
const dto = new ProjectDto();
27+
dto.title = project.title;
28+
dto.subject = project.subject;
29+
return dto;
30+
}
31+
}
32+
33+
class ProjectInfoDto {
34+
project: ProjectDto;
35+
member: ProjectMemberDto[];
36+
37+
static of(project: Project, memberList: Member[]): ProjectInfoDto {
38+
const dto = new ProjectInfoDto();
39+
dto.project = ProjectDto.of(project);
40+
dto.member = memberList.map((member) => ProjectMemberDto.of(member));
41+
return dto;
42+
}
43+
}
44+
45+
export class InitSettingResponseDto {
46+
domain: string;
47+
action: string;
48+
content: ProjectInfoDto;
49+
50+
static of(project: Project, memberList: Member[]): InitSettingResponseDto {
51+
const dto = new InitSettingResponseDto();
52+
dto.domain = 'setting';
53+
dto.action = 'init';
54+
dto.content = ProjectInfoDto.of(project, memberList);
55+
return dto;
56+
}
57+
}

backend/src/project/websocket.gateway.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,10 @@ export class ProjectWebsocketGateway
176176
this.wsProjectTaskController.updateTask(client, data);
177177
}
178178
}
179+
@SubscribeMessage('joinSetting')
180+
async handleJoinSettingEvent(@ConnectedSocket() client: ClientSocket) {
181+
this.wsProjectController.joinSettingPage(client);
182+
}
179183

180184
notifyJoinToConnectedMembers(projectId: number, member: Member) {
181185
const projectNamespace = this.namespaceMap.get(projectId);

backend/src/project/ws-controller/ws-project.controller.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { MemberUpdateNotifyDto } from '../dto/member/MemberUpdateNotify.dto';
55
import { MemberStatus } from '../enum/MemberStatus.enum';
66
import { ProjectService } from '../service/project.service';
77
import { ClientSocket } from '../type/ClientSocket.type';
8+
import { InitSettingResponseDto } from '../dto/setting-page/InitSettingResponse.dto';
89

910
@Injectable()
1011
export class WsProjectController {
@@ -39,6 +40,9 @@ export class WsProjectController {
3940
linkList,
4041
);
4142
client.emit('landing', response);
43+
44+
client.leave('landing');
45+
client.leave('setting');
4246
client.join('landing');
4347

4448
if (sameMemberSocket) return;
@@ -53,9 +57,26 @@ export class WsProjectController {
5357

5458
async joinBacklogPage(client: ClientSocket) {
5559
client.leave('landing');
60+
client.leave('setting');
5661
client.join('backlog');
5762
const backlog = await this.projectService.getProjectBacklog(client.project);
5863

5964
client.emit('backlog', InitBacklogResponseDto.of(backlog));
6065
}
66+
67+
async joinSettingPage(client: ClientSocket) {
68+
client.leave('landing');
69+
client.leave('backlog');
70+
client.join('setting');
71+
72+
const [project, projectMemberList] = await Promise.all([
73+
this.projectService.getProject(client.projectId),
74+
this.projectService.getProjectMemberList(client.project),
75+
]);
76+
77+
client.emit(
78+
'setting',
79+
InitSettingResponseDto.of(project, projectMemberList),
80+
);
81+
}
6182
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { Socket } from 'socket.io-client';
2+
import {
3+
app,
4+
appInit,
5+
connectServer,
6+
createMember,
7+
createProject,
8+
getMemberByAccessToken,
9+
getProjectLinkId,
10+
joinProject,
11+
listenAppAndSetPortEnv,
12+
memberFixture,
13+
memberFixture2,
14+
projectPayload,
15+
} from 'test/setup';
16+
import { emitJoinLanding, handleConnectErrorWithReject } from '../ws-common';
17+
import { MemberRole } from 'src/project/enum/MemberRole.enum';
18+
19+
describe('WS Setting', () => {
20+
beforeEach(async () => {
21+
await app.close();
22+
await appInit();
23+
await listenAppAndSetPortEnv(app);
24+
});
25+
26+
it('Should return project setting data when leader enters setting page', async () => {
27+
let socket1: Socket;
28+
29+
return new Promise<void>(async (resolve, reject) => {
30+
const accessToken1 = (await createMember(memberFixture, app)).accessToken;
31+
const member1 = await getMemberByAccessToken(accessToken1);
32+
const project = await createProject(accessToken1, projectPayload, app);
33+
const projectLinkId = await getProjectLinkId(accessToken1, project.id);
34+
35+
const accessToken2 = (await createMember(memberFixture2, app))
36+
.accessToken;
37+
const member2 = await getMemberByAccessToken(accessToken2);
38+
await joinProject(accessToken2, projectLinkId);
39+
40+
socket1 = connectServer(project.id, accessToken1);
41+
handleConnectErrorWithReject(socket1, reject);
42+
await emitJoinLanding(socket1);
43+
44+
socket1.emit('joinSetting');
45+
socket1.on('error', (e) => reject(e));
46+
47+
socket1.on('setting', (data) => {
48+
const { action, domain, content } = data;
49+
expect(domain).toBe('setting');
50+
expect(action).toBe('init');
51+
52+
expect(content.project.title).toBe(projectPayload.title);
53+
expect(content.project.subject).toBe(projectPayload.subject);
54+
expect(content.member.length).toBe(2);
55+
56+
const responseMember1 = content.member.find(
57+
(member) => member.id === member1.id,
58+
);
59+
expect(responseMember1.username).toBe(member1.username);
60+
expect(responseMember1.imageUrl).toBe(member1.github_image_url);
61+
expect(responseMember1.role).toBe(MemberRole.LEADER);
62+
63+
const responseMember2 = content.member.find(
64+
(member) => member.id === member2.id,
65+
);
66+
expect(responseMember2.username).toBe(member2.username);
67+
expect(responseMember2.imageUrl).toBe(member2.github_image_url);
68+
expect(responseMember2.role).toBe(MemberRole.MEMBER);
69+
resolve();
70+
});
71+
}).finally(() => {
72+
socket1.close();
73+
});
74+
});
75+
});

0 commit comments

Comments
 (0)