From 6057846df2b95001f9850d2ef1e0a47e424757ea Mon Sep 17 00:00:00 2001 From: yumzen Date: Thu, 21 Nov 2024 10:15:35 +0900 Subject: [PATCH] =?UTF-8?q?#274=20Feat:=20=ED=8C=80=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=EC=A0=9D=ED=8A=B8=20=EC=83=9D=EC=84=B1=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/converter/MemberConverter.java | 2 +- .../backend/domain/member/entity/Member.java | 11 +--- .../member/entity/MemberProjectMap.java | 29 ---------- .../repository/MemberRepositoryImpl.java | 14 ++--- .../project/controller/ProjectController.java | 9 +++ .../project/converter/ProjectConverter.java | 12 +++- .../dto/response/ProjectResponseDTO.java | 3 +- .../domain/project/entity/Project.java | 18 ++++-- .../repository/ProjectRepositoryImpl.java | 15 ++++- .../project/service/ProjectService.java | 55 ++++++++++++++----- .../domain/team/converter/TeamConverter.java | 2 +- .../backend/domain/team/entity/Team.java | 6 +- .../domain/team/entity/TeamProjectMap.java | 23 -------- 13 files changed, 99 insertions(+), 100 deletions(-) delete mode 100644 src/main/java/com/codiary/backend/domain/member/entity/MemberProjectMap.java delete mode 100644 src/main/java/com/codiary/backend/domain/team/entity/TeamProjectMap.java diff --git a/src/main/java/com/codiary/backend/domain/member/converter/MemberConverter.java b/src/main/java/com/codiary/backend/domain/member/converter/MemberConverter.java index 90897dd0..a3f89b06 100644 --- a/src/main/java/com/codiary/backend/domain/member/converter/MemberConverter.java +++ b/src/main/java/com/codiary/backend/domain/member/converter/MemberConverter.java @@ -79,7 +79,7 @@ public static List toSimpleFollowResponseDto( .collect(Collectors.toList()); } - public static MemberResponseDTO.SimpleMemberProfileDTO tosimpleMemberProfileResponseDto(Member member) { + public static MemberResponseDTO.SimpleMemberProfileDTO toSimpleMemberProfileResponseDto(Member member) { return MemberResponseDTO.SimpleMemberProfileDTO.builder() .userId(member.getMemberId()) .userName(member.getNickname()) diff --git a/src/main/java/com/codiary/backend/domain/member/entity/Member.java b/src/main/java/com/codiary/backend/domain/member/entity/Member.java index d2b2200c..f976245d 100644 --- a/src/main/java/com/codiary/backend/domain/member/entity/Member.java +++ b/src/main/java/com/codiary/backend/domain/member/entity/Member.java @@ -2,6 +2,7 @@ import com.codiary.backend.domain.coauthor.entity.Authors; import com.codiary.backend.domain.comment.entity.Comment; +import com.codiary.backend.domain.project.entity.Project; import com.codiary.backend.domain.member.dto.request.MemberRequestDTO; import com.codiary.backend.domain.member.enumerate.MemberState; import com.codiary.backend.domain.post.entity.Bookmark; @@ -78,7 +79,7 @@ public enum Gender {Male, Female} private List authorsList = new ArrayList<>(); @OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true) - private List memberProjectMapList = new ArrayList<>(); + private List projectList = new ArrayList<>(); @OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true) private List commentList = new ArrayList<>(); @@ -127,15 +128,7 @@ public void setImage(MemberImage image) { this.image = image; } - public void setMemberProjectMapList(List projects) { - this.memberProjectMapList = projects; - } - public void setTeamMemberList(List teamMembers) { this.teamMemberList = teamMembers; } - - public void addProject(MemberProjectMap memberProjectMap) { - memberProjectMapList.add(memberProjectMap); - } } diff --git a/src/main/java/com/codiary/backend/domain/member/entity/MemberProjectMap.java b/src/main/java/com/codiary/backend/domain/member/entity/MemberProjectMap.java deleted file mode 100644 index 496a7341..00000000 --- a/src/main/java/com/codiary/backend/domain/member/entity/MemberProjectMap.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.codiary.backend.domain.member.entity; - -import com.codiary.backend.domain.project.entity.Project; -import jakarta.persistence.*; -import lombok.*; - -@Entity -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public class MemberProjectMap { - - @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "member_project_id", nullable = false, columnDefinition = "bigint") - private Long memberProjectId; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id") - private Member member; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "project_id") - private Project project; - - @Builder - public MemberProjectMap(Member member, Project project) { - this.member = member; - this.project = project; - } -} diff --git a/src/main/java/com/codiary/backend/domain/member/repository/MemberRepositoryImpl.java b/src/main/java/com/codiary/backend/domain/member/repository/MemberRepositoryImpl.java index df26c539..e2743c08 100644 --- a/src/main/java/com/codiary/backend/domain/member/repository/MemberRepositoryImpl.java +++ b/src/main/java/com/codiary/backend/domain/member/repository/MemberRepositoryImpl.java @@ -1,8 +1,8 @@ package com.codiary.backend.domain.member.repository; import com.codiary.backend.domain.member.entity.Member; -import com.codiary.backend.domain.member.entity.MemberProjectMap; import com.codiary.backend.domain.team.entity.TeamMember; +import com.codiary.backend.domain.project.entity.Project; import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; @@ -13,7 +13,6 @@ import static com.codiary.backend.domain.member.entity.QMember.member; import static com.codiary.backend.domain.member.entity.QMemberCategory.memberCategory; import static com.codiary.backend.domain.techstack.entity.QTechStacks.techStacks; -import static com.codiary.backend.domain.member.entity.QMemberProjectMap.memberProjectMap; import static com.codiary.backend.domain.project.entity.QProject.project; import static com.codiary.backend.domain.team.entity.QTeamMember.teamMember; import static com.codiary.backend.domain.team.entity.QTeam.team; @@ -88,13 +87,12 @@ public Optional findByIdWithFollowers(Long id) { } private void fetchMemberProjects(Long userId, Member fetchedMember) { - List projects = queryFactory - .selectFrom(memberProjectMap) - .leftJoin(memberProjectMap.project, project) - .where(memberProjectMap.member.memberId.eq(userId)) + List projects = queryFactory + .selectFrom(project) + .leftJoin(member.projectList, project) + .where(member.memberId.eq(userId) + .and(project.deletedAt.isNull())) .fetch(); - - fetchedMember.setMemberProjectMapList(projects); } private void fetchTeamMembers(Long userId, Member fetchedMember) { diff --git a/src/main/java/com/codiary/backend/domain/project/controller/ProjectController.java b/src/main/java/com/codiary/backend/domain/project/controller/ProjectController.java index 6027ebc0..52896540 100644 --- a/src/main/java/com/codiary/backend/domain/project/controller/ProjectController.java +++ b/src/main/java/com/codiary/backend/domain/project/controller/ProjectController.java @@ -38,4 +38,13 @@ public ApiResponse> getMyProje return ApiResponse.onSuccess(SuccessStatus.PROJECT_OK, ProjectConverter.toSimpleProjectListResponseDTO(projects)); } + @Operation(summary = "팀 프로젝트 생성", description = "팀 프로젝트를 생성합니다.") + @PostMapping("/create/team/{team_id}/{project_name}") + public ApiResponse createTeamProject(@AuthenticationPrincipal CustomMemberDetails memberDetails, + @PathVariable("team_id") Long teamId, + @PathVariable("project_name") String projectName) { + Project project = projectService.createTeamProject(memberDetails.getId(), teamId, projectName); + return ApiResponse.onSuccess(SuccessStatus.PROJECT_OK, ProjectConverter.toSimpleProjectResponseDTO(project)); + } + } diff --git a/src/main/java/com/codiary/backend/domain/project/converter/ProjectConverter.java b/src/main/java/com/codiary/backend/domain/project/converter/ProjectConverter.java index b07033d5..9c5ff7d1 100644 --- a/src/main/java/com/codiary/backend/domain/project/converter/ProjectConverter.java +++ b/src/main/java/com/codiary/backend/domain/project/converter/ProjectConverter.java @@ -9,12 +9,18 @@ public class ProjectConverter { public static ProjectResponseDTO.ProjectDetailResponseDTO toProjectDetailResponseDTO(Project project) { + Boolean isTeam = project.getTeam() != null; return ProjectResponseDTO.ProjectDetailResponseDTO.builder() .projectId(project.getProjectId()) .name(project.getProjectName()) - .members(project.getMemberProjectMaps().stream() - .map(memberProjectMap -> MemberConverter.tosimpleMemberProfileResponseDto(memberProjectMap.getMember())) - .collect(Collectors.toList())) + .isTeam(isTeam) + .projectMembers( + isTeam + ? project.getTeam().getTeamMemberList().stream() + .map(teamMember -> MemberConverter.toSimpleMemberProfileResponseDto(teamMember.getMember())) + .collect(Collectors.toList()) + : List.of(MemberConverter.toSimpleMemberProfileResponseDto(project.getMember())) + ) .build(); } diff --git a/src/main/java/com/codiary/backend/domain/project/dto/response/ProjectResponseDTO.java b/src/main/java/com/codiary/backend/domain/project/dto/response/ProjectResponseDTO.java index 6cafc5ec..e0610cd9 100644 --- a/src/main/java/com/codiary/backend/domain/project/dto/response/ProjectResponseDTO.java +++ b/src/main/java/com/codiary/backend/domain/project/dto/response/ProjectResponseDTO.java @@ -25,7 +25,8 @@ public record SimpleProjectResponseDTO( public record ProjectDetailResponseDTO( Long projectId, String name, - List members + Boolean isTeam, + List projectMembers ) { } } diff --git a/src/main/java/com/codiary/backend/domain/project/entity/Project.java b/src/main/java/com/codiary/backend/domain/project/entity/Project.java index 3530a18c..8acd5fc9 100644 --- a/src/main/java/com/codiary/backend/domain/project/entity/Project.java +++ b/src/main/java/com/codiary/backend/domain/project/entity/Project.java @@ -1,7 +1,8 @@ package com.codiary.backend.domain.project.entity; -import com.codiary.backend.domain.member.entity.MemberProjectMap; +import com.codiary.backend.domain.member.entity.Member; import com.codiary.backend.domain.post.entity.Post; +import com.codiary.backend.domain.team.entity.Team; import com.codiary.backend.global.common.BaseEntity; import jakarta.persistence.*; import lombok.*; @@ -25,13 +26,20 @@ public class Project extends BaseEntity { private String projectName; @OneToMany(mappedBy = "project") - private List memberProjectMaps = new ArrayList<>(); + private List posts = new ArrayList<>(); - @OneToMany(mappedBy = "project") - private List posts = new ArrayList<>(); + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "team_id") + private Team team; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + private Member member; @Builder - public Project(String projectName) { + public Project(Team team, Member member, String projectName) { + this.team = team; + this.member = member; this.projectName = projectName; } } diff --git a/src/main/java/com/codiary/backend/domain/project/repository/ProjectRepositoryImpl.java b/src/main/java/com/codiary/backend/domain/project/repository/ProjectRepositoryImpl.java index 9cd16946..b0e1b9e1 100644 --- a/src/main/java/com/codiary/backend/domain/project/repository/ProjectRepositoryImpl.java +++ b/src/main/java/com/codiary/backend/domain/project/repository/ProjectRepositoryImpl.java @@ -14,6 +14,8 @@ import static com.codiary.backend.domain.post.entity.QPost.post; import static com.codiary.backend.domain.project.entity.QProject.project; +import static com.codiary.backend.domain.team.entity.QTeam.team; +import static com.codiary.backend.domain.team.entity.QTeamMember.teamMember; @RequiredArgsConstructor public class ProjectRepositoryImpl implements ProjectRepositoryCustom { @@ -40,8 +42,17 @@ public Map> findProjectsForCalendar(Long memberId, Loca public List findByMemberProjectMapsMember(Member member) { return queryFactory .selectFrom(project) - .leftJoin(project.memberProjectMaps).fetchJoin() - .where(project.memberProjectMaps.any().member.eq(member)) + .leftJoin(project.member) + .leftJoin(project.team, team) + .leftJoin(team.teamMemberList, teamMember) + .where( + project.member.eq(member) + .and(project.deletedAt.isNull()) + .or( + team.teamMemberList.any().member.eq(member) + .and(team.deletedAt.isNull()) + ) + ) .fetch(); } } diff --git a/src/main/java/com/codiary/backend/domain/project/service/ProjectService.java b/src/main/java/com/codiary/backend/domain/project/service/ProjectService.java index 1bcbc6cc..6332ba99 100644 --- a/src/main/java/com/codiary/backend/domain/project/service/ProjectService.java +++ b/src/main/java/com/codiary/backend/domain/project/service/ProjectService.java @@ -1,10 +1,11 @@ package com.codiary.backend.domain.project.service; import com.codiary.backend.domain.member.entity.Member; -import com.codiary.backend.domain.member.entity.MemberProjectMap; import com.codiary.backend.domain.project.entity.Project; import com.codiary.backend.domain.member.repository.MemberRepository; import com.codiary.backend.domain.project.repository.ProjectRepository; +import com.codiary.backend.domain.team.entity.Team; +import com.codiary.backend.domain.team.repository.TeamRepository; import com.codiary.backend.global.apiPayload.code.status.ErrorStatus; import com.codiary.backend.global.apiPayload.exception.GeneralException; import lombok.RequiredArgsConstructor; @@ -19,34 +20,28 @@ public class ProjectService { private final ProjectRepository projectRepository; private final MemberRepository memberRepository; + private final TeamRepository teamRepository; @Transactional public Project createPersonalProject(Long memberId, String projectName) { //validation Member member = memberRepository.findById(memberId) .orElseThrow(() -> new GeneralException(ErrorStatus.MEMBER_NOT_FOUND)); - Project project = projectRepository.findByProjectNameAndDeletedAtIsNull(projectName) + Project existingProject = projectRepository.findByProjectNameAndDeletedAtIsNull(projectName) .orElse(null); - //business - if (project != null) { // 프로젝트 이름 중복 확인 + // business + if (existingProject != null) { // 프로젝트 이름 중복 확인 throw new GeneralException(ErrorStatus.PROJECT_ALREADY_EXISTS); } else { - project = Project.builder() + Project project = Project.builder() .projectName(projectName) - .build(); - projectRepository.save(project); - - MemberProjectMap memberProjectMap = MemberProjectMap.builder() + .team(null) .member(member) - .project(project) .build(); - - member.addProject(memberProjectMap); + projectRepository.save(project); + return project; } - - //return - return project; } public List getMyProject(Long id) { @@ -57,4 +52,34 @@ public List getMyProject(Long id) { //return return projectRepository.findByMemberProjectMapsMember(member); } + + @Transactional + public Project createTeamProject(Long id, Long teamId, String projectName) { + // validation + Member member = memberRepository.findById(id) + .orElseThrow(() -> new GeneralException(ErrorStatus.MEMBER_NOT_FOUND)); + + Team team = teamRepository.findByTeamIdAndDeletedAtIsNull(teamId) + .orElseThrow(() -> new GeneralException(ErrorStatus.TEAM_NOT_FOUND)); + + if (teamRepository.isTeamMember(team, member)) { + throw new GeneralException(ErrorStatus.TEAM_MEMBER_ONLY_ACCESS); + } + + Project existingProject = projectRepository.findByProjectNameAndDeletedAtIsNull(projectName) + .orElse(null); + + // business + if (existingProject != null) { // 프로젝트 이름 중복 확인 + throw new GeneralException(ErrorStatus.PROJECT_ALREADY_EXISTS); + } else { + Project project = Project.builder() + .projectName(projectName) + .team(team) + .member(member) + .build(); + projectRepository.save(project); + return project; + } + } } diff --git a/src/main/java/com/codiary/backend/domain/team/converter/TeamConverter.java b/src/main/java/com/codiary/backend/domain/team/converter/TeamConverter.java index 9e051fe0..42697161 100644 --- a/src/main/java/com/codiary/backend/domain/team/converter/TeamConverter.java +++ b/src/main/java/com/codiary/backend/domain/team/converter/TeamConverter.java @@ -72,7 +72,7 @@ public static TeamResponseDTO.TeamFollowersDTO toTeamFollowersResponseDTO(Long t public static TeamResponseDTO.TeamMemberDTO toTeamMemberResponseDTO(TeamMember teamMember){ return TeamResponseDTO.TeamMemberDTO.builder() .teamMemberId(teamMember.getTeamMemberId()) - .member(MemberConverter.tosimpleMemberProfileResponseDto(teamMember.getMember())) + .member(MemberConverter.toSimpleMemberProfileResponseDto(teamMember.getMember())) .teamMemberRole(teamMember.getTeamMemberRole().name()) .teamMemberPosition(teamMember.getMemberPosition()) .build(); diff --git a/src/main/java/com/codiary/backend/domain/team/entity/Team.java b/src/main/java/com/codiary/backend/domain/team/entity/Team.java index cb922d83..b1731f3c 100644 --- a/src/main/java/com/codiary/backend/domain/team/entity/Team.java +++ b/src/main/java/com/codiary/backend/domain/team/entity/Team.java @@ -1,6 +1,7 @@ package com.codiary.backend.domain.team.entity; import com.codiary.backend.domain.post.entity.Post; +import com.codiary.backend.domain.project.entity.Project; import com.codiary.backend.domain.team.dto.request.TeamRequestDTO; import com.codiary.backend.global.common.BaseEntity; import jakarta.persistence.CascadeType; @@ -51,7 +52,7 @@ public class Team extends BaseEntity { private String instagram; @OneToMany(mappedBy = "team", cascade = CascadeType.ALL, orphanRemoval = true) - private List teamProjectMapList = new ArrayList<>(); + private List projectList = new ArrayList<>(); @OneToMany(mappedBy = "team", cascade = CascadeType.ALL, orphanRemoval = true) private List postList = new ArrayList<>(); @@ -69,7 +70,7 @@ public class Team extends BaseEntity { private TeamProfileImage profileImage; @Builder - public Team(Long teamId, String name, String intro, String github, String email, String linkedin, String discord, String instagram, List teamProjectMapList, List postList, List teamMemberList, List followers, TeamBannerImage bannerImage, TeamProfileImage profileImage) { + public Team(Long teamId, String name, String intro, String github, String email, String linkedin, String discord, String instagram, List postList, List teamMemberList, List followers, TeamBannerImage bannerImage, TeamProfileImage profileImage) { this.teamId = teamId; this.name = name; this.intro = intro; @@ -78,7 +79,6 @@ public Team(Long teamId, String name, String intro, String github, String email, this.linkedin = linkedin; this.discord = discord; this.instagram = instagram; - this.teamProjectMapList = teamProjectMapList; this.postList = postList; this.teamMemberList = teamMemberList; this.followers = followers; diff --git a/src/main/java/com/codiary/backend/domain/team/entity/TeamProjectMap.java b/src/main/java/com/codiary/backend/domain/team/entity/TeamProjectMap.java deleted file mode 100644 index a56ce755..00000000 --- a/src/main/java/com/codiary/backend/domain/team/entity/TeamProjectMap.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.codiary.backend.domain.team.entity; - -import com.codiary.backend.domain.project.entity.Project; -import jakarta.persistence.*; -import lombok.*; - -@Entity -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public class TeamProjectMap { - - @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "team_project__id", nullable = false, columnDefinition = "bigint") - private Long teamProjectId; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "team_id") - private Team team; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "project_id") - private Project project; -}