diff --git a/.gitignore b/.gitignore index 18f45fe..05ed670 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ out/ .vscode/ /src/main/resources/global-bundle.pem +/src/main/resources/devlink-key.pem diff --git a/src/main/java/com/mtvs/devlinkbackend/character/controller/UserCharacterQueryController.java b/src/main/java/com/mtvs/devlinkbackend/character/controller/UserCharacterQueryController.java index 7cfd935..298c51b 100644 --- a/src/main/java/com/mtvs/devlinkbackend/character/controller/UserCharacterQueryController.java +++ b/src/main/java/com/mtvs/devlinkbackend/character/controller/UserCharacterQueryController.java @@ -1,6 +1,5 @@ package com.mtvs.devlinkbackend.character.controller; -import com.mtvs.devlinkbackend.character.dto.response.UserCharacterListResponseDTO; import com.mtvs.devlinkbackend.character.dto.response.UserCharacterSingleResponseDTO; import com.mtvs.devlinkbackend.character.service.UserCharacterViewService; import com.mtvs.devlinkbackend.util.JwtUtil; @@ -24,11 +23,12 @@ public UserCharacterQueryController(JwtUtil jwtUtil, UserCharacterViewService us @Operation(summary = "캐릭터 조회", description = "캐릭터 ID로 캐릭터를 조회합니다.") @ApiResponse(responseCode = "200", description = "캐릭터가 성공적으로 조회되었습니다.") @ApiResponse(responseCode = "404", description = "해당 계정 ID로 캐릭터를 찾을 수 없습니다.") - @GetMapping("/{characterId}") + @GetMapping public ResponseEntity getCharacterByCharacterId( - @PathVariable(name = "characterId") Long characterId) throws Exception { + @RequestHeader(name = "Authorization") String authorizationHeader) throws Exception { - UserCharacterSingleResponseDTO userCharacter = userCharacterViewService.findCharacterByCharacterId(characterId); + String accountId = jwtUtil.getSubjectFromAuthHeaderWithoutAuth(authorizationHeader); + UserCharacterSingleResponseDTO userCharacter = userCharacterViewService.findCharacterByAccountId(accountId); if (userCharacter == null) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } diff --git a/src/main/java/com/mtvs/devlinkbackend/member/entity/AcceptStatus.java b/src/main/java/com/mtvs/devlinkbackend/member/entity/AcceptStatus.java new file mode 100644 index 0000000..b31b84a --- /dev/null +++ b/src/main/java/com/mtvs/devlinkbackend/member/entity/AcceptStatus.java @@ -0,0 +1,28 @@ +package com.mtvs.devlinkbackend.member.entity; + +public enum AcceptStatus { + DELETED(0), + PENDING(1), // 대기중 + ACCEPTED(2), // 수락 + REJECTED(3); // 거절 + + private final int value; + + AcceptStatus(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + // Integer 값에서 Enum으로 변환하는 메소드 + public static AcceptStatus fromValue(int value) { + for (AcceptStatus status : AcceptStatus.values()) { + if (status.getValue() == value) { + return status; + } + } + throw new IllegalArgumentException("Invalid value: " + value); + } +} diff --git a/src/main/java/com/mtvs/devlinkbackend/member/entity/Member.java b/src/main/java/com/mtvs/devlinkbackend/member/entity/Member.java new file mode 100644 index 0000000..d8ffc75 --- /dev/null +++ b/src/main/java/com/mtvs/devlinkbackend/member/entity/Member.java @@ -0,0 +1,55 @@ +package com.mtvs.devlinkbackend.member.entity; + +import com.mtvs.devlinkbackend.util.converter.AcceptStatusConverter; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import java.time.LocalDateTime; + +@Table(name = "MEMBER") +@Entity(name = "Member") +@Getter +@NoArgsConstructor +@ToString +public class Member { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "MEMBER_ID") + private Long memberId; + + @Column(name = "TYPE") + private String type; + + @Column(name = "ASSIGNEES_ID") + private Long assigneesId; + + @Column(name = "USER_ID") + private Long userId; + + @Column(name = "MOTIVE") + private String motive; + + @Column(name = "IS_ACCEPTED") + @Convert(converter = AcceptStatusConverter.class) + private AcceptStatus isAccepted; + + @CreationTimestamp + @Column(name = "CREATED_AT", updatable = false) + private LocalDateTime createdAt; + + @UpdateTimestamp + @Column(name = "MODIFIED_AT") + private LocalDateTime modifiedAt; + + public Member(String type, Long assigneesId, Long userId, String motive, AcceptStatus isAccepted) { + this.type = type; + this.assigneesId = assigneesId; + this.userId = userId; + this.motive = motive; + this.isAccepted = isAccepted; + } +} diff --git a/src/main/java/com/mtvs/devlinkbackend/member/repository/MemberRepository.java b/src/main/java/com/mtvs/devlinkbackend/member/repository/MemberRepository.java new file mode 100644 index 0000000..2a22bff --- /dev/null +++ b/src/main/java/com/mtvs/devlinkbackend/member/repository/MemberRepository.java @@ -0,0 +1,10 @@ +package com.mtvs.devlinkbackend.member.repository; + +import com.mtvs.devlinkbackend.member.entity.Member; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface MemberRepository extends JpaRepository { + void deleteMembersByMemberIdIn(List memberIdList); +} diff --git a/src/main/java/com/mtvs/devlinkbackend/member/repository/MemberViewRepository.java b/src/main/java/com/mtvs/devlinkbackend/member/repository/MemberViewRepository.java new file mode 100644 index 0000000..43be417 --- /dev/null +++ b/src/main/java/com/mtvs/devlinkbackend/member/repository/MemberViewRepository.java @@ -0,0 +1,9 @@ +package com.mtvs.devlinkbackend.member.repository; + +import com.mtvs.devlinkbackend.member.entity.Member; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface MemberViewRepository extends JpaRepository { +} diff --git a/src/main/java/com/mtvs/devlinkbackend/member/service/MemberService.java b/src/main/java/com/mtvs/devlinkbackend/member/service/MemberService.java new file mode 100644 index 0000000..4db86fe --- /dev/null +++ b/src/main/java/com/mtvs/devlinkbackend/member/service/MemberService.java @@ -0,0 +1,27 @@ +package com.mtvs.devlinkbackend.member.service; + +import com.mtvs.devlinkbackend.member.entity.Member; +import com.mtvs.devlinkbackend.member.repository.MemberRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +public class MemberService { + private final MemberRepository memberRepository; + + public MemberService(MemberRepository memberRepository) { + this.memberRepository = memberRepository; + } + + @Transactional + public void registAll(List memberList) { + memberRepository.saveAll(memberList); + } + + @Transactional + public void deleteAll(List memberIdList) { + memberRepository.deleteMembersByMemberIdIn(memberIdList); + } +} diff --git a/src/main/java/com/mtvs/devlinkbackend/member/service/MemberViewService.java b/src/main/java/com/mtvs/devlinkbackend/member/service/MemberViewService.java new file mode 100644 index 0000000..188eae5 --- /dev/null +++ b/src/main/java/com/mtvs/devlinkbackend/member/service/MemberViewService.java @@ -0,0 +1,7 @@ +package com.mtvs.devlinkbackend.member.service; + +import org.springframework.stereotype.Service; + +@Service +public class MemberViewService { +} diff --git a/src/main/java/com/mtvs/devlinkbackend/team/controller/TeamCommandController.java b/src/main/java/com/mtvs/devlinkbackend/team/controller/TeamCommandController.java new file mode 100644 index 0000000..557461f --- /dev/null +++ b/src/main/java/com/mtvs/devlinkbackend/team/controller/TeamCommandController.java @@ -0,0 +1,94 @@ +package com.mtvs.devlinkbackend.team.controller; + +import com.mtvs.devlinkbackend.team.dto.request.TeamMemberModifyRequestDTO; +import com.mtvs.devlinkbackend.team.dto.request.TeamRegistRequestDTO; +import com.mtvs.devlinkbackend.team.dto.request.TeamUpdateRequestDTO; +import com.mtvs.devlinkbackend.team.dto.response.TeamSingleReponseDTO; +import com.mtvs.devlinkbackend.team.service.TeamService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/team") +public class TeamCommandController { + + private final TeamService teamService; + + public TeamCommandController(TeamService teamService) { + this.teamService = teamService; + } + + @Operation(summary = "팀 등록", description = "새로운 팀을 등록하고 등록된 팀 정보를 반환합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "팀이 성공적으로 등록되었습니다."), + @ApiResponse(responseCode = "400", description = "잘못된 입력 데이터입니다.") + }) + @PostMapping + public ResponseEntity registTeam( + @RequestBody TeamRegistRequestDTO teamRegistRequestDTO) { + + TeamSingleReponseDTO team = teamService.registTeam(teamRegistRequestDTO); + return new ResponseEntity<>(team, HttpStatus.CREATED); + } + + @Operation(summary = "팀 업데이트", description = "기존 팀을 업데이트하고 업데이트된 팀 정보를 반환합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "팀이 성공적으로 업데이트되었습니다."), + @ApiResponse(responseCode = "400", description = "잘못된 입력 데이터 또는 권한이 없는 접근입니다."), + @ApiResponse(responseCode = "404", description = "팀을 찾을 수 없습니다.") + }) + @PatchMapping + public ResponseEntity updateTeam( + @RequestBody TeamUpdateRequestDTO teamUpdateRequestDTO) { + + try { + TeamSingleReponseDTO updatedTeam = teamService.updateTeam(teamUpdateRequestDTO); + return ResponseEntity.ok(updatedTeam); + } catch (IllegalArgumentException e) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); + } + } + + @Operation(summary = "팀 멤버 지원", description = "팀에 멤버로 지원합니다.") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "성공적으로 추가되었습니다."), + @ApiResponse(responseCode = "403", description = "추가 권한이 없습니다."), + @ApiResponse(responseCode = "404", description = "팀을 찾을 수 없습니다.") + }) + @PatchMapping("/apply") + public ResponseEntity addMemberToTeam( + @RequestBody TeamMemberModifyRequestDTO teamMemberModifyRequestDTO) { + + TeamSingleReponseDTO updatedTeam = teamService.applyMemberToTeam(teamMemberModifyRequestDTO); + return updatedTeam != null ? ResponseEntity.ok(updatedTeam) : ResponseEntity.notFound().build(); + } + + @Operation(summary = "팀에서 멤버 제거 ", description = "길드에서 멤버를 제거합니다.") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "멤버가 성공적으로 제거되었습니다."), + @ApiResponse(responseCode = "403", description = "제거 권한이 없습니다."), + @ApiResponse(responseCode = "404", description = "팀을 찾을 수 없습니다.") + }) + @PatchMapping("/remove") + public ResponseEntity removeMemberFromTeam( + @RequestBody TeamMemberModifyRequestDTO teamMemberModifyRequestDTO) throws Exception { + + TeamSingleReponseDTO updatedTeam = teamService.removeMemberToTeam(teamMemberModifyRequestDTO); + return updatedTeam != null ? ResponseEntity.ok(updatedTeam) : ResponseEntity.notFound().build(); + } + + @Operation(summary = "팀 삭제", description = "ID를 통해 팀을 삭제합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "204", description = "팀이 성공적으로 삭제되었습니다."), + @ApiResponse(responseCode = "404", description = "팀을 찾을 수 없습니다.") + }) + @DeleteMapping("/{teamId}") + public ResponseEntity deleteTeam(@PathVariable Long teamId) { + teamService.deleteTeam(teamId); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/com/mtvs/devlinkbackend/team/controller/TeamController.java b/src/main/java/com/mtvs/devlinkbackend/team/controller/TeamController.java deleted file mode 100644 index 91c1bc5..0000000 --- a/src/main/java/com/mtvs/devlinkbackend/team/controller/TeamController.java +++ /dev/null @@ -1,161 +0,0 @@ -package com.mtvs.devlinkbackend.team.controller; - -import com.mtvs.devlinkbackend.team.dto.request.TeamMemberModifyRequestDTO; -import com.mtvs.devlinkbackend.team.dto.request.TeamRegistRequestDTO; -import com.mtvs.devlinkbackend.team.dto.request.TeamUpdateRequestDTO; -import com.mtvs.devlinkbackend.team.dto.response.TeamListResponseDTO; -import com.mtvs.devlinkbackend.team.dto.response.TeamSingleReponseDTO; -import com.mtvs.devlinkbackend.util.JwtUtil; -import com.mtvs.devlinkbackend.team.service.TeamService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -@RestController -@RequestMapping("/api/team") -public class TeamController { - - private final TeamService teamService; - private final JwtUtil jwtUtil; - - public TeamController(TeamService teamService, JwtUtil jwtUtil) { - this.teamService = teamService; - this.jwtUtil = jwtUtil; - } - - @Operation(summary = "팀 등록", description = "새로운 팀을 등록하고 등록된 팀 정보를 반환합니다.") - @ApiResponses(value = { - @ApiResponse(responseCode = "201", description = "팀이 성공적으로 등록되었습니다."), - @ApiResponse(responseCode = "400", description = "잘못된 입력 데이터입니다.") - }) - @PostMapping - public ResponseEntity registTeam( - @RequestBody TeamRegistRequestDTO teamRegistRequestDTO, @RequestHeader(name = "Authorization") String authorizationHeader) throws Exception { - - String accountId = jwtUtil.getSubjectFromAuthHeaderWithoutAuth(authorizationHeader); - TeamSingleReponseDTO team = teamService.registTeam(teamRegistRequestDTO, accountId); - return new ResponseEntity<>(team, HttpStatus.CREATED); - } - - @Operation(summary = "ID로 팀 조회", description = "ID를 기반으로 팀 정보를 반환합니다.") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "팀이 성공적으로 조회되었습니다."), - @ApiResponse(responseCode = "404", description = "팀을 찾을 수 없습니다.") - }) - @GetMapping("/{teamId}") - public ResponseEntity getTeamById( - @PathVariable Long teamId) { - - TeamSingleReponseDTO team = teamService.findTeamByTeamId(teamId); - if (team != null) { - return ResponseEntity.ok(team); - } else { - return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); - } - } - - @Operation(summary = "사용자가 프로젝트 매니저인 팀 조회", description = "사용자가 프로젝트 매니저인 팀 목록을 반환합니다.") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "팀이 성공적으로 조회되었습니다."), - @ApiResponse(responseCode = "404", description = "주어진 프로젝트 매니저 ID에 대한 팀이 없습니다.") - }) - @GetMapping("/manager") - public ResponseEntity getTeamsByPmId( - @RequestHeader(name = "Authorization") String authorizationHeader) throws Exception { - - String pmId = jwtUtil.getSubjectFromAuthHeaderWithoutAuth(authorizationHeader); - TeamListResponseDTO teams = teamService.findTeamsByPmId(pmId); - return ResponseEntity.ok(teams); - } - - @Operation(summary = "팀 이름으로 팀 조회", description = "지정된 문자열이 포함된 팀 이름을 가진 팀 목록을 반환합니다.") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "팀이 성공적으로 조회되었습니다.") - }) - @GetMapping("/search") - public ResponseEntity getTeamsByTeamNameContaining( - @RequestParam String teamName) { - - TeamListResponseDTO teams = teamService.findTeamsByTeamNameContaining(teamName); - return ResponseEntity.ok(teams); - } - - @Operation(summary = "사용자가 멤버인 팀 조회", description = "사용자가 멤버인 팀 목록을 반환합니다.") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "팀이 성공적으로 조회되었습니다.") - }) - @GetMapping("/members/search") - public ResponseEntity getTeamsByMemberIdContaining( - @RequestHeader(name = "Authorization") String authorizationHeader) throws Exception { - - String memberId = jwtUtil.getSubjectFromAuthHeaderWithoutAuth(authorizationHeader); - TeamListResponseDTO teams = teamService.findTeamsByMemberIdContaining(memberId); - return ResponseEntity.ok(teams); - } - - @Operation(summary = "팀 업데이트", description = "기존 팀을 업데이트하고 업데이트된 팀 정보를 반환합니다.") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "팀이 성공적으로 업데이트되었습니다."), - @ApiResponse(responseCode = "400", description = "잘못된 입력 데이터 또는 권한이 없는 접근입니다."), - @ApiResponse(responseCode = "404", description = "팀을 찾을 수 없습니다.") - }) - @PatchMapping - public ResponseEntity updateTeam( - @RequestBody TeamUpdateRequestDTO teamUpdateRequestDTO, - @RequestHeader(name = "Authorization") String authorizationHeader) throws Exception { - - String accountId = jwtUtil.getSubjectFromAuthHeaderWithoutAuth(authorizationHeader); - - try { - TeamSingleReponseDTO updatedTeam = teamService.updateTeam(teamUpdateRequestDTO, accountId); - return ResponseEntity.ok(updatedTeam); - } catch (IllegalArgumentException e) { - return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); - } - } - - @Operation(summary = "팀 멤버 추가", description = "길드에 멤버를 추가합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "멤버가 성공적으로 추가되었습니다."), - @ApiResponse(responseCode = "403", description = "추가 권한이 없습니다."), - @ApiResponse(responseCode = "404", description = "길드를 찾을 수 없습니다.") - }) - @PostMapping("/member") - public TeamSingleReponseDTO addMemberToTeam( - @RequestBody TeamMemberModifyRequestDTO teamMemberModifyRequestDTO, - @RequestHeader(name = "Authorization") String authorizationHeader) throws Exception { - - String accountId = jwtUtil.getSubjectFromAuthHeaderWithoutAuth(authorizationHeader); - System.out.println(teamMemberModifyRequestDTO); - return teamService.addMemberToTeam(teamMemberModifyRequestDTO, accountId); - } - - @Operation(summary = "팀 멤버 제거", description = "길드에서 멤버를 제거합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "멤버가 성공적으로 제거되었습니다."), - @ApiResponse(responseCode = "403", description = "제거 권한이 없습니다."), - @ApiResponse(responseCode = "404", description = "길드를 찾을 수 없습니다.") - }) - @DeleteMapping("/member") - public TeamSingleReponseDTO removeMemberFromTeam( - @RequestBody TeamMemberModifyRequestDTO teamMemberModifyRequestDTO, - @RequestHeader(name = "Authorization") String authorizationHeader) throws Exception { - - String accountId = jwtUtil.getSubjectFromAuthHeaderWithoutAuth(authorizationHeader); - return teamService.removeMemberToTeam(teamMemberModifyRequestDTO, accountId); - } - - @Operation(summary = "팀 삭제", description = "ID를 통해 팀을 삭제합니다.") - @ApiResponses(value = { - @ApiResponse(responseCode = "204", description = "팀이 성공적으로 삭제되었습니다."), - @ApiResponse(responseCode = "404", description = "팀을 찾을 수 없습니다.") - }) - @DeleteMapping("/{teamId}") - public ResponseEntity deleteTeam(@PathVariable Long teamId) { - teamService.deleteTeam(teamId); - return ResponseEntity.noContent().build(); - } -} diff --git a/src/main/java/com/mtvs/devlinkbackend/team/controller/TeamQueryController.java b/src/main/java/com/mtvs/devlinkbackend/team/controller/TeamQueryController.java new file mode 100644 index 0000000..859a882 --- /dev/null +++ b/src/main/java/com/mtvs/devlinkbackend/team/controller/TeamQueryController.java @@ -0,0 +1,54 @@ +package com.mtvs.devlinkbackend.team.controller; + +import com.mtvs.devlinkbackend.team.dto.response.TeamListResponseDTO; +import com.mtvs.devlinkbackend.team.dto.response.TeamSingleReponseDTO; +import com.mtvs.devlinkbackend.team.service.TeamViewService; +import com.mtvs.devlinkbackend.util.JwtUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/team") +public class TeamQueryController { + private final JwtUtil jwtUtil; + private final TeamViewService teamViewService; + + public TeamQueryController(JwtUtil jwtUtil, TeamViewService teamViewService) { + this.jwtUtil = jwtUtil; + this.teamViewService = teamViewService; + } + + @Operation(summary = "ID로 팀 조회", description = "ID를 기반으로 팀 정보를 반환합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "팀이 성공적으로 조회되었습니다."), + @ApiResponse(responseCode = "404", description = "팀을 찾을 수 없습니다.") + }) + @GetMapping("/{teamId}") + public ResponseEntity getTeamById( + @PathVariable Long teamId) { + + TeamSingleReponseDTO team = teamViewService.findTeamByTeamId(teamId); + if (team != null) { + return ResponseEntity.ok(team); + } else { + return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + } + } + + @Operation(summary = "사용자가 멤버인 팀 조회", description = "사용자가 멤버인 팀 목록을 반환합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "팀이 성공적으로 조회되었습니다.") + }) + @GetMapping("/teamlist") + public ResponseEntity getTeamsByMemberIdContaining( + @RequestHeader(name = "Authorization") String authorizationHeader) throws Exception { + + String accountId = jwtUtil.getSubjectFromAuthHeaderWithoutAuth(authorizationHeader); + TeamListResponseDTO teams = teamViewService.findByAccountIdInTeam(accountId); + return ResponseEntity.ok(teams); + } +} diff --git a/src/main/java/com/mtvs/devlinkbackend/team/dto/request/TeamMemberModifyRequestDTO.java b/src/main/java/com/mtvs/devlinkbackend/team/dto/request/TeamMemberModifyRequestDTO.java index e795ba9..794101b 100644 --- a/src/main/java/com/mtvs/devlinkbackend/team/dto/request/TeamMemberModifyRequestDTO.java +++ b/src/main/java/com/mtvs/devlinkbackend/team/dto/request/TeamMemberModifyRequestDTO.java @@ -1,5 +1,6 @@ package com.mtvs.devlinkbackend.team.dto.request; +import com.mtvs.devlinkbackend.member.entity.Member; import lombok.*; import java.util.List; @@ -11,5 +12,6 @@ @ToString public class TeamMemberModifyRequestDTO { private Long teamId; - private List newMemberList; + private Long leaderUserId; + private List teamMemberList; } diff --git a/src/main/java/com/mtvs/devlinkbackend/team/dto/request/TeamRegistRequestDTO.java b/src/main/java/com/mtvs/devlinkbackend/team/dto/request/TeamRegistRequestDTO.java index 2642334..6b44f85 100644 --- a/src/main/java/com/mtvs/devlinkbackend/team/dto/request/TeamRegistRequestDTO.java +++ b/src/main/java/com/mtvs/devlinkbackend/team/dto/request/TeamRegistRequestDTO.java @@ -10,7 +10,6 @@ @NoArgsConstructor @ToString public class TeamRegistRequestDTO { - private String teamName; - private String introduction; - private List memberList; + private String teamIntroduction; + private Long leaderUserId; } diff --git a/src/main/java/com/mtvs/devlinkbackend/team/dto/request/TeamUpdateRequestDTO.java b/src/main/java/com/mtvs/devlinkbackend/team/dto/request/TeamUpdateRequestDTO.java index f3edfb0..c563aba 100644 --- a/src/main/java/com/mtvs/devlinkbackend/team/dto/request/TeamUpdateRequestDTO.java +++ b/src/main/java/com/mtvs/devlinkbackend/team/dto/request/TeamUpdateRequestDTO.java @@ -1,5 +1,6 @@ package com.mtvs.devlinkbackend.team.dto.request; +import com.mtvs.devlinkbackend.member.entity.Member; import lombok.*; import java.util.List; @@ -11,7 +12,7 @@ @ToString public class TeamUpdateRequestDTO { private Long teamId; - private String teamName; - private String introduction; - private List memberList; + private String teamIntroduction; + private Long leaderUserId; + private List teamMemberList; } diff --git a/src/main/java/com/mtvs/devlinkbackend/team/entity/Team.java b/src/main/java/com/mtvs/devlinkbackend/team/entity/Team.java index 07758f8..40bc21d 100644 --- a/src/main/java/com/mtvs/devlinkbackend/team/entity/Team.java +++ b/src/main/java/com/mtvs/devlinkbackend/team/entity/Team.java @@ -1,11 +1,13 @@ package com.mtvs.devlinkbackend.team.entity; +import com.mtvs.devlinkbackend.util.converter.LongListConverter; import jakarta.persistence.*; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.ToString; import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.UpdateTimestamp; +import org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters; import java.time.LocalDateTime; import java.util.ArrayList; @@ -22,19 +24,15 @@ public class Team { @Column(name = "TEAM_ID") private Long teamId; - @Column(name = "PM_ID") - private String pmId; + @Column(name = "LEADER_USER_ID") + private Long leaderUserId; - @Column(name = "TEAM_NAME", unique = true) - private String teamName; + @Column(name = "TEAM_INTRODUCTION") + private String teamIntroduction; - @Column(name = "INTRODUCTION") - private String introduction; - - @ElementCollection - @CollectionTable(name = "TEAM_MEMBER", joinColumns = @JoinColumn(name = "TEAM_ID")) - @Column(name = "MEMBER_LIST") - private List memberList = new ArrayList<>(); + @Convert(converter = LongListConverter.class) + @Column(name = "TEAM_MEMBER_LIST", columnDefinition = "TEXT") + private List teamMemberList = new ArrayList<>(); @CreationTimestamp @Column(name = "CREATED_AT", updatable = false) @@ -44,26 +42,21 @@ public class Team { @Column(name = "MODIFIED_AT") private LocalDateTime modifiedAt; - public Team(String pmId, String teamName, String introduction, List memberList) { - this.pmId = pmId; - this.teamName = teamName; - this.introduction = introduction; - this.memberList = memberList; - } - - public void setPmId(String pmId) { - this.pmId = pmId; + public Team(Long leaderUserId, String teamIntroduction, List teamMemberList) { + this.leaderUserId = leaderUserId; + this.teamIntroduction = teamIntroduction; + this.teamMemberList = teamMemberList; } - public void setTeamName(String teamName) { - this.teamName = teamName; + public void setLeaderUserId(Long leaderUserId) { + this.leaderUserId = leaderUserId; } - public void setIntroduction(String introduction) { - this.introduction = introduction; + public void setTeamIntroduction(String teamIntroduction) { + this.teamIntroduction = teamIntroduction; } - public void setMemberList(List memberList) { - this.memberList = memberList; + public void setTeamMemberList(List teamMemberList) { + this.teamMemberList = teamMemberList; } } diff --git a/src/main/java/com/mtvs/devlinkbackend/team/repository/TeamRepository.java b/src/main/java/com/mtvs/devlinkbackend/team/repository/TeamRepository.java index c11bb4a..64e8902 100644 --- a/src/main/java/com/mtvs/devlinkbackend/team/repository/TeamRepository.java +++ b/src/main/java/com/mtvs/devlinkbackend/team/repository/TeamRepository.java @@ -10,10 +10,4 @@ @Repository public interface TeamRepository extends JpaRepository { - List findTeamsByTeamNameContaining(String teamName); - - List findTeamByPmId(String pmId); - - @Query("SELECT t FROM Team t JOIN t.memberList m WHERE m LIKE :memberId") - List findTeamsByMemberIdContaining(@Param("memberId") String accountId); } diff --git a/src/main/java/com/mtvs/devlinkbackend/team/repository/TeamViewRepository.java b/src/main/java/com/mtvs/devlinkbackend/team/repository/TeamViewRepository.java new file mode 100644 index 0000000..5c40fe9 --- /dev/null +++ b/src/main/java/com/mtvs/devlinkbackend/team/repository/TeamViewRepository.java @@ -0,0 +1,18 @@ +package com.mtvs.devlinkbackend.team.repository; + +import com.mtvs.devlinkbackend.team.entity.Team; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface TeamViewRepository extends JpaRepository { + Team findTeamByLeaderUserId(Long leaderUserId); + + // teamMemberList에 memberId를 포함하는 팀 조회 + @Query("SELECT t FROM Team t WHERE :memberId IN (t.teamMemberList)") + List findByMemberIdInTeam(@Param("memberId") Long memberId); +} diff --git a/src/main/java/com/mtvs/devlinkbackend/team/service/TeamService.java b/src/main/java/com/mtvs/devlinkbackend/team/service/TeamService.java index 57eb133..4e807d4 100644 --- a/src/main/java/com/mtvs/devlinkbackend/team/service/TeamService.java +++ b/src/main/java/com/mtvs/devlinkbackend/team/service/TeamService.java @@ -1,86 +1,90 @@ package com.mtvs.devlinkbackend.team.service; +import com.mtvs.devlinkbackend.member.entity.AcceptStatus; +import com.mtvs.devlinkbackend.member.entity.Member; +import com.mtvs.devlinkbackend.member.service.MemberService; import com.mtvs.devlinkbackend.team.dto.request.TeamMemberModifyRequestDTO; import com.mtvs.devlinkbackend.team.dto.request.TeamRegistRequestDTO; import com.mtvs.devlinkbackend.team.dto.request.TeamUpdateRequestDTO; -import com.mtvs.devlinkbackend.team.dto.response.TeamListResponseDTO; import com.mtvs.devlinkbackend.team.dto.response.TeamSingleReponseDTO; import com.mtvs.devlinkbackend.team.entity.Team; import com.mtvs.devlinkbackend.team.repository.TeamRepository; import jakarta.transaction.Transactional; import org.springframework.stereotype.Service; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; @Service public class TeamService { private final TeamRepository teamRepository; + private final MemberService memberService; - public TeamService(TeamRepository teamRepository) { + public TeamService(TeamRepository teamRepository, MemberService memberService) { this.teamRepository = teamRepository; + this.memberService = memberService; } @Transactional - public TeamSingleReponseDTO registTeam(TeamRegistRequestDTO teamRegistRequestDTO, String accountId) { + public TeamSingleReponseDTO registTeam(TeamRegistRequestDTO teamRegistRequestDTO) { + + List initialTeamMemberList = new ArrayList<>(); return new TeamSingleReponseDTO(teamRepository.save(new Team( - accountId, - teamRegistRequestDTO.getTeamName(), - teamRegistRequestDTO.getIntroduction(), - teamRegistRequestDTO.getMemberList() + teamRegistRequestDTO.getLeaderUserId(), + teamRegistRequestDTO.getTeamIntroduction(), + initialTeamMemberList ))); } - public TeamSingleReponseDTO findTeamByTeamId(Long teamId) { - return new TeamSingleReponseDTO(teamRepository.findById(teamId).orElse(null)); - } - - public TeamListResponseDTO findTeamsByPmId(String pmId) { - return new TeamListResponseDTO(teamRepository.findTeamByPmId(pmId)); - } - - public TeamListResponseDTO findTeamsByTeamNameContaining(String teamName) { - return new TeamListResponseDTO(teamRepository.findTeamsByTeamNameContaining(teamName)); - } - - public TeamListResponseDTO findTeamsByMemberIdContaining(String memberId) { - return new TeamListResponseDTO(teamRepository.findTeamsByMemberIdContaining(memberId)); - } - @Transactional - public TeamSingleReponseDTO updateTeam(TeamUpdateRequestDTO teamUpdateRequestDTO, String accountId) { + public TeamSingleReponseDTO updateTeam(TeamUpdateRequestDTO teamUpdateRequestDTO) { Optional team = teamRepository.findById(teamUpdateRequestDTO.getTeamId()); if (team.isPresent()) { Team foundTeam = team.get(); - if(foundTeam.getPmId().equals(accountId)) { - foundTeam.setTeamName(teamUpdateRequestDTO.getTeamName()); - foundTeam.setIntroduction(teamUpdateRequestDTO.getIntroduction()); - foundTeam.setMemberList(teamUpdateRequestDTO.getMemberList()); - return new TeamSingleReponseDTO(foundTeam); - } else throw new IllegalArgumentException("pm이 아닌 계정으로 team 수정 시도"); + foundTeam.setTeamIntroduction(teamUpdateRequestDTO.getTeamIntroduction()); + foundTeam.setTeamMemberList( + teamUpdateRequestDTO.getTeamMemberList().stream() + .map(Member::getMemberId).toList()); + + return new TeamSingleReponseDTO(foundTeam); } else throw new IllegalArgumentException("해당 Team은 존재하지 않음"); } @Transactional - public TeamSingleReponseDTO addMemberToTeam(TeamMemberModifyRequestDTO teamMemberModifyRequestDTO, String accountId) { + public TeamSingleReponseDTO applyMemberToTeam(TeamMemberModifyRequestDTO teamMemberModifyRequestDTO) { Optional team = teamRepository.findById(teamMemberModifyRequestDTO.getTeamId()); if (team.isPresent()) { Team foundTeam = team.get(); - if(foundTeam.getPmId().equals(accountId)) { - foundTeam.getMemberList().addAll(teamMemberModifyRequestDTO.getNewMemberList()); - return new TeamSingleReponseDTO(foundTeam); - } else throw new IllegalArgumentException("owner가 아닌 계정으로 Guild 수정 시도"); + List memberList = teamMemberModifyRequestDTO.getTeamMemberList().stream() + .map(teamMember -> + new Member( + teamMember.getType(), + teamMember.getUserId(), + teamMember.getAssigneesId(), + teamMember.getMotive(), + AcceptStatus.PENDING)).toList(); + + memberService.registAll(memberList); + + foundTeam.getTeamMemberList().addAll(memberList.stream().map(Member::getMemberId).toList()); + + return new TeamSingleReponseDTO(foundTeam); } else return null; } @Transactional - public TeamSingleReponseDTO removeMemberToTeam(TeamMemberModifyRequestDTO teamMemberModifyRequestDTO, String accountId) { + public TeamSingleReponseDTO removeMemberToTeam(TeamMemberModifyRequestDTO teamMemberModifyRequestDTO) { Optional team = teamRepository.findById(teamMemberModifyRequestDTO.getTeamId()); if (team.isPresent()) { Team foundTeam = team.get(); - if(foundTeam.getPmId().equals(accountId)) { - foundTeam.getMemberList().removeAll(teamMemberModifyRequestDTO.getNewMemberList()); - return new TeamSingleReponseDTO(foundTeam); - } else throw new IllegalArgumentException("owner가 아닌 계정으로 Guild 수정 시도"); + List memberIdListToRemove = teamMemberModifyRequestDTO.getTeamMemberList().stream() + .map(Member::getMemberId).toList(); + foundTeam.getTeamMemberList().removeAll(memberIdListToRemove); + + memberService.deleteAll(memberIdListToRemove); + + return new TeamSingleReponseDTO(foundTeam); } else return null; } diff --git a/src/main/java/com/mtvs/devlinkbackend/team/service/TeamViewService.java b/src/main/java/com/mtvs/devlinkbackend/team/service/TeamViewService.java new file mode 100644 index 0000000..7e93d32 --- /dev/null +++ b/src/main/java/com/mtvs/devlinkbackend/team/service/TeamViewService.java @@ -0,0 +1,36 @@ +package com.mtvs.devlinkbackend.team.service; + +import com.mtvs.devlinkbackend.team.dto.response.TeamListResponseDTO; +import com.mtvs.devlinkbackend.team.dto.response.TeamSingleReponseDTO; +import com.mtvs.devlinkbackend.team.repository.TeamViewRepository; +import com.mtvs.devlinkbackend.user.command.model.entity.User; +import com.mtvs.devlinkbackend.user.query.repository.UserViewRepository; +import org.springframework.stereotype.Service; + +@Service +public class TeamViewService { + private final TeamViewRepository teamViewRepository; + private final UserViewRepository userViewRepository; + + public TeamViewService(TeamViewRepository teamViewRepository, UserViewRepository userViewRepository) { + this.teamViewRepository = teamViewRepository; + this.userViewRepository = userViewRepository; + } + + public TeamSingleReponseDTO findTeamByTeamId(Long teamId) { + return new TeamSingleReponseDTO(teamViewRepository.findById(teamId).orElse(null)); + } + + public TeamSingleReponseDTO findTeamsByLeaderUserId(Long leaderUserId) { + return new TeamSingleReponseDTO(teamViewRepository.findTeamByLeaderUserId(leaderUserId)); + } + + public TeamListResponseDTO findByMemberIdInTeam(Long memberUserId) { + return new TeamListResponseDTO(teamViewRepository.findByMemberIdInTeam(memberUserId)); + } + + public TeamListResponseDTO findByAccountIdInTeam(String accountId) { + User foundUser = userViewRepository.findUserByEpicAccountId(accountId); + return new TeamListResponseDTO(teamViewRepository.findByMemberIdInTeam(foundUser.getUserId())); + } +} diff --git a/src/main/java/com/mtvs/devlinkbackend/user/query/service/EpicGamesTokenService.java b/src/main/java/com/mtvs/devlinkbackend/user/query/service/EpicGamesTokenService.java index 87e55e3..958ba8f 100644 --- a/src/main/java/com/mtvs/devlinkbackend/user/query/service/EpicGamesTokenService.java +++ b/src/main/java/com/mtvs/devlinkbackend/user/query/service/EpicGamesTokenService.java @@ -26,16 +26,14 @@ public class EpicGamesTokenService { @Value("${epicgames.registration.deployment-id}") private String deploymentId; - private final String getAuthorizationCodeURL = "https://www.epicgames.com/id/authorize"; - private final String getAccessTokenURL = "https://api.epicgames.dev/epic/oauth/v2/token"; + @Value("${epicgames.provider.epicgames.token-uri}") + private String getAccessTokenURL; + private final String getAccountURL = "https://api.epicgames.dev/epic/id/v2/accounts?accountId="; - private final EpicGamesJWKCache jwkCache; private final JwtUtil jwtUtil; - // EpicGamesJWKCache를 주입받아 사용합니다. - public EpicGamesTokenService(EpicGamesJWKCache jwkCache, JwtUtil jwtUtil) { - this.jwkCache = jwkCache; + public EpicGamesTokenService(JwtUtil jwtUtil) { this.jwtUtil = jwtUtil; } diff --git a/src/main/java/com/mtvs/devlinkbackend/util/converter/AcceptStatusConverter.java b/src/main/java/com/mtvs/devlinkbackend/util/converter/AcceptStatusConverter.java new file mode 100644 index 0000000..de88c55 --- /dev/null +++ b/src/main/java/com/mtvs/devlinkbackend/util/converter/AcceptStatusConverter.java @@ -0,0 +1,26 @@ +package com.mtvs.devlinkbackend.util.converter; + +import com.mtvs.devlinkbackend.member.entity.AcceptStatus; +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; + +@Converter(autoApply = true) +public class AcceptStatusConverter implements AttributeConverter { + + @Override + public Integer convertToDatabaseColumn(AcceptStatus status) { + if (status == null) { + return null; + } + return status.getValue(); + } + + @Override + public AcceptStatus convertToEntityAttribute(Integer value) { + if (value == null) { + return null; + } + return AcceptStatus.fromValue(value); + } +} + diff --git a/src/test/java/com/mtvs/devlinkbackend/crud/TeamCRUDTest.java b/src/test/java/com/mtvs/devlinkbackend/crud/TeamCRUDTest.java index c7306fe..ddd7350 100644 --- a/src/test/java/com/mtvs/devlinkbackend/crud/TeamCRUDTest.java +++ b/src/test/java/com/mtvs/devlinkbackend/crud/TeamCRUDTest.java @@ -1,9 +1,12 @@ package com.mtvs.devlinkbackend.crud; +import com.mtvs.devlinkbackend.member.entity.AcceptStatus; +import com.mtvs.devlinkbackend.member.entity.Member; import com.mtvs.devlinkbackend.team.dto.request.TeamMemberModifyRequestDTO; import com.mtvs.devlinkbackend.team.dto.request.TeamRegistRequestDTO; import com.mtvs.devlinkbackend.team.dto.request.TeamUpdateRequestDTO; import com.mtvs.devlinkbackend.team.service.TeamService; +import com.mtvs.devlinkbackend.team.service.TeamViewService; import jakarta.transaction.Transactional; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; @@ -24,25 +27,72 @@ public class TeamCRUDTest { @Autowired private TeamService teamService; + @Autowired + private TeamViewService teamViewService; private static Stream newTeam() { return Stream.of( - Arguments.of(new TeamRegistRequestDTO("팀 이름00", "소개00", List.of("계정1","계정3")), "계정2"), - Arguments.of(new TeamRegistRequestDTO("팀 이름00", "소개00", List.of("계정1","계정3")), "계정2") + Arguments.of(new TeamRegistRequestDTO( + "소개00", + 1L), "계정2"), + Arguments.of(new TeamRegistRequestDTO("소개00", + 1L), "계정2") ); } private static Stream updatedTeam() { return Stream.of( - Arguments.of(new TeamUpdateRequestDTO(1L,"팀 이름0", "소개0", List.of("계정2","계정3")), "계정1"), - Arguments.of(new TeamUpdateRequestDTO(2L,"팀 이름00", "소개00", List.of("계정1","계정3")), "계정2") + Arguments.of(new TeamUpdateRequestDTO( + 1L, + "소개0", + 1L, + List.of(new Member(), new Member())), "계정1"), + Arguments.of(new TeamUpdateRequestDTO( + 1L, + "소개0", + 1L, + List.of(new Member(), new Member())), "계정2") ); } private static Stream modifiedTeam() { return Stream.of( - Arguments.of(new TeamMemberModifyRequestDTO(1L, List.of("계정2","계정3")), "계정1"), - Arguments.of(new TeamMemberModifyRequestDTO(2L, List.of("계정3","계정4")), "계정2") + Arguments.of(new TeamMemberModifyRequestDTO( + 1L, + 1L, + List.of( + new Member( + "Team", + 1L, + 1L, + "지원 동기1", + AcceptStatus.ACCEPTED + ), + new Member( + "Team", + 1L, + 1L, + "지원 동기1", + AcceptStatus.REJECTED + ))), "계정1"), + Arguments.of(new TeamMemberModifyRequestDTO( + 2L, + 1L, + List.of( + new Member( + "Team", + 1L, + 1L, + "지원 동기1", + AcceptStatus.ACCEPTED + ), + new Member( + "Team", + 1L, + 1L, + "지원 동기1", + AcceptStatus.REJECTED + ))), "계정2") ); } @@ -51,7 +101,7 @@ private static Stream modifiedTeam() { @MethodSource("newTeam") @Order(0) public void testCreateTeam(TeamRegistRequestDTO questionRegistRequestDTO, String accountId) { - Assertions.assertDoesNotThrow(() -> teamService.registTeam(questionRegistRequestDTO, accountId)); + Assertions.assertDoesNotThrow(() -> teamService.registTeam(questionRegistRequestDTO)); } @DisplayName("PK로 팀 조회 테스트") @@ -60,16 +110,7 @@ public void testCreateTeam(TeamRegistRequestDTO questionRegistRequestDTO, String @Order(1) public void testFindTeamByTeamId(long teamId) { Assertions.assertDoesNotThrow(() -> - System.out.println("Team = " + teamService.findTeamByTeamId(teamId))); - } - - @DisplayName("계정 ID가 PM인 팀 조회 테스트") - @ValueSource(strings = {"계정1","계정2"}) - @ParameterizedTest - @Order(2) - public void testFindTeamByPmId(String pmId) { - Assertions.assertDoesNotThrow(() -> - System.out.println("Team = " + teamService.findTeamsByPmId(pmId))); + System.out.println("Team = " + teamViewService.findTeamByTeamId(teamId))); } @DisplayName("계정 ID가 멤버인 팀 조회 테스트") @@ -78,16 +119,7 @@ public void testFindTeamByPmId(String pmId) { @Order(3) public void testFindTeamsByMemberId(String memberId) { Assertions.assertDoesNotThrow(() -> - System.out.println("Team = " + teamService.findTeamsByMemberIdContaining(memberId))); - } - - @DisplayName("팀 이름으로 팀 조회 테스트") - @ValueSource(strings = {"팀 이름0", "팀 이름1"}) - @ParameterizedTest - @Order(4) - public void testFindTeamsByTeamNameContaining(String teamName) { - Assertions.assertDoesNotThrow(() -> - System.out.println("Team = " + teamService.findTeamsByTeamNameContaining(teamName))); + System.out.println("Team = " + teamViewService.findByAccountIdInTeam(memberId))); } @DisplayName("팀 수정 테스트") @@ -96,7 +128,7 @@ public void testFindTeamsByTeamNameContaining(String teamName) { @Order(5) public void testUpdateTeam(TeamUpdateRequestDTO questionUpdateRequestDTO, String accountId) { Assertions.assertDoesNotThrow(() -> - System.out.println(teamService.updateTeam(questionUpdateRequestDTO, accountId))); + System.out.println(teamService.updateTeam(questionUpdateRequestDTO))); } @DisplayName("팀 멤버 추가 테스트") @@ -105,7 +137,7 @@ public void testUpdateTeam(TeamUpdateRequestDTO questionUpdateRequestDTO, String @Order(5) public void testAddMemberToTeam(TeamMemberModifyRequestDTO teamMemberModifyRequestDTO, String accountId) { Assertions.assertDoesNotThrow(() -> - System.out.println(teamService.addMemberToTeam(teamMemberModifyRequestDTO, accountId))); + System.out.println(teamService.applyMemberToTeam(teamMemberModifyRequestDTO))); } @DisplayName("팀 멤버 삭제 테스트") @@ -114,7 +146,7 @@ public void testAddMemberToTeam(TeamMemberModifyRequestDTO teamMemberModifyReque @Order(5) public void testRemoveMemberToTeam(TeamMemberModifyRequestDTO teamMemberModifyRequestDTO, String accountId) { Assertions.assertDoesNotThrow(() -> - System.out.println(teamService.removeMemberToTeam(teamMemberModifyRequestDTO, accountId))); + System.out.println(teamService.removeMemberToTeam(teamMemberModifyRequestDTO))); } @DisplayName("팀 삭제 테스트")