Skip to content

Commit

Permalink
feat: 랜딩페이지 입장시 프로젝트의 리더에게만 초대링크를 제공하도록 구현
Browse files Browse the repository at this point in the history
- getProject 서비스 메서드에서 리더에게만 초대링크를 제공하도록 변경
- getProject의 파라미터가 회원정보를 추가로 요구하기 영향을 받는 메서드 수정
- 클라이언트 API의 DTO인 initLandingDto에서 초대링크 정보가 있을때만 첨부하도록 변경
- 리더에게는 초대링크가 제공되고, 일반 멤버에게는 초대링크가 제공되지 않는것을 확인하는 E2E테스트 추가
  • Loading branch information
choyoungwoo9 committed Sep 18, 2024
1 parent 1b62505 commit 3ac9658
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 12 deletions.
4 changes: 2 additions & 2 deletions backend/src/project/dto/InitLandingResponse.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class ProjectLandingPageContentDto {
sprint: null;
memoList: MemoDto[];
linkList: LinkDto[];
inviteLinkId: string;
inviteLinkId?: string;

static of(
project: Project,
Expand Down Expand Up @@ -112,7 +112,7 @@ class ProjectLandingPageContentDto {
const linkDtoList = linkList.map((link) => LinkDto.of(link));
dto.linkList = linkDtoList;

dto.inviteLinkId = project.inviteLinkId;
if (project.inviteLinkId) dto.inviteLinkId = project.inviteLinkId;
return dto;
}
}
Expand Down
26 changes: 24 additions & 2 deletions backend/src/project/service/project.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,25 @@ export class ProjectService {
return await this.projectRepository.getProjectList(member);
}

async getProject(projectId: number): Promise<Project | null> {
return await this.projectRepository.getProject(projectId);
private getProjectWithInviteLink(projectId: number) {
return this.projectRepository.getProject(projectId);
}
private async getProjectWithOutInviteLink(projectId: number) {
const project = await this.projectRepository.getProject(projectId);
delete project.inviteLinkId;
return project;
}

async getProject(projectId: number, member: Member): Promise<Project | null> {
if (!(await this.isExistProject(projectId)))
throw new Error('Project not found');
if (!(await this.isProjectMember(projectId, member))) {
throw new Error('Not project member');
}
if (await this.isProjectLeader(projectId, member)) {
return this.getProjectWithInviteLink(projectId);
}
return this.getProjectWithOutInviteLink(projectId);
}

async addMember(project: Project, member: Member): Promise<void> {
Expand All @@ -64,6 +81,11 @@ export class ProjectService {
return this.projectRepository.getProjectMemberList(project);
}

async isExistProject(projectId: number): Promise<boolean> {
const project = await this.projectRepository.getProject(projectId);
return !!project;
}

async isProjectMember(projectId: number, member: Member): Promise<boolean> {
const projectToMember: ProjectToMember | null =
await this.projectRepository.getProjectToMember(projectId, member);
Expand Down
7 changes: 2 additions & 5 deletions backend/src/project/websocket.gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,13 +226,10 @@ export class ProjectWebsocketGateway
client.projectId = parseInt(projectId[1], 10);
if (isNaN(client.projectId)) throw new Error('Project is not number');
}
const project = await this.projectService.getProject(client.projectId);
if (!project) throw new Error('Project not found');
const isProjectMember = await this.projectService.isProjectMember(
project.id,
const project = await this.projectService.getProject(
client.projectId,
client.member,
);
if (!isProjectMember) throw new Error('Not project member');
client.project = project;
}
}
4 changes: 2 additions & 2 deletions backend/src/project/ws-controller/ws-project.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export class WsProjectController {
async joinLandingPage(client: ClientSocket) {
const [project, projectMemberList, memoListWithMember, linkList] =
await Promise.all([
this.projectService.getProject(client.projectId),
this.projectService.getProject(client.projectId, client.member),
this.projectService.getProjectMemberList(client.project),
this.projectService.getProjectMemoListWithMember(client.project.id),
this.projectService.getProjectLinkList(client.project),
Expand Down Expand Up @@ -80,7 +80,7 @@ export class WsProjectController {
client.join('setting');

const [project, projectMemberList] = await Promise.all([
this.projectService.getProject(client.projectId),
this.projectService.getProject(client.projectId, client.member),
this.projectService.getProjectMemberList(client.project),
]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ describe('WS landing', () => {
expect(content.sprint).toBeDefined();
expect(content.memoList).toBeDefined();
expect(content.linkList).toBeDefined();
expect(content.inviteLinkId).toBeDefined();

resolve();
});
Expand Down
49 changes: 49 additions & 0 deletions backend/test/project/ws-landing-page/ws-role.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,54 @@ describe('WS role', () => {
});
});
};

it('should return invite link when member is project leader', async () => {
let socket1;
let socket2;
return new Promise<void>(async (resolve, reject) => {
// 회원1 회원가입 + 프로젝트 생성
const accessToken = (await createMember(memberFixture, app))
.accessToken;
const project = await createProject(accessToken, projectPayload, app);
const projectLinkId = await getProjectLinkId(accessToken, project.id);

// 회원2 회원가입 + 프로젝트 참여
const accessToken2 = (await createMember(memberFixture2, app))
.accessToken;
await joinProject(accessToken2, projectLinkId);

socket1 = connectServer(project.id, accessToken);
handleConnectErrorWithReject(socket1, reject);
handleErrorWithReject(socket1, reject);
await emitJoinLanding(socket1);
await expectInviteLink(socket1, MemberRole.LEADER);

socket2 = connectServer(project.id, accessToken2);
handleConnectErrorWithReject(socket2, reject);
handleErrorWithReject(socket2, reject);
await emitJoinLanding(socket2);
await expectInviteLink(socket2, MemberRole.MEMBER);

resolve();
}).finally(() => {
socket1.close();
socket2.close();
});
});

const expectInviteLink = async (socket: Socket, role: string) => {
await new Promise<void>((resolve, reject) => {
socket.once('landing', async (data) => {
const { action, domain, content } = data;
if (action === 'init' && domain === 'landing') {
if (role === MemberRole.LEADER)
expect(content.inviteLinkId).toBeDefined();
else if (role === MemberRole.MEMBER)
expect(content.inviteLinkId).toBeUndefined();
resolve();
} else reject();
});
});
};
});
});

0 comments on commit 3ac9658

Please sign in to comment.