diff --git a/src/main/java/com/codiary/backend/global/apiPayload/code/status/ErrorStatus.java b/src/main/java/com/codiary/backend/global/apiPayload/code/status/ErrorStatus.java index e4112f32..ca2d8854 100644 --- a/src/main/java/com/codiary/backend/global/apiPayload/code/status/ErrorStatus.java +++ b/src/main/java/com/codiary/backend/global/apiPayload/code/status/ErrorStatus.java @@ -25,6 +25,8 @@ public enum ErrorStatus implements BaseErrorCode { MEMBER_LOGIN_FAIL(HttpStatus.BAD_REQUEST, "MEMBER_1006", "아이디나 비밀번호가 올바르지 않습니다."), MEMBER_WRONG_EMAIL(HttpStatus.BAD_REQUEST, "MEMBER_1007", "이메일 형식이 올바르지 않습니다."), MEMBER_WRONG_PASSWORD(HttpStatus.BAD_REQUEST, "MEMBER_1008", "비밀번호 형식이 올바르지 않습니다."), + MEMBER_EMAIL_ALREADY_EXISTS(HttpStatus.CONFLICT, "MEMBER_1009", "이미 가입된 이메일입니다."), + MEMBER_NICKNAME_ALREADY_EXISTS(HttpStatus.CONFLICT, "MEMBER_1010", "이미 존재하는 닉네임입니다."), MEMBER_SELF_FOLLOW(HttpStatus.BAD_REQUEST, "MEMBER_1100", "셀프 팔로우 기능은 제공하지 않습니다"), diff --git a/src/main/java/com/codiary/backend/global/config/SecurityConfig.java b/src/main/java/com/codiary/backend/global/config/SecurityConfig.java index d646f028..28f07068 100644 --- a/src/main/java/com/codiary/backend/global/config/SecurityConfig.java +++ b/src/main/java/com/codiary/backend/global/config/SecurityConfig.java @@ -53,7 +53,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti .authorizeHttpRequests( authorize -> authorize // Member 관련 접근 - .requestMatchers("/members/sign-up").permitAll() + .requestMatchers("/members/sign-up", "/members/sign-up/check-email", "/members/sign-up/check-nickname").permitAll() .requestMatchers("/members/login", "members/posts").permitAll() // Post 관련 접근 .requestMatchers("/posts","/posts/{postId}", "/posts/visibility/{postId}", "/posts/coauthors/{postId}", "/posts/categories/{postId}").permitAll() //.hasRole("USER") diff --git a/src/main/java/com/codiary/backend/global/converter/MemberConverter.java b/src/main/java/com/codiary/backend/global/converter/MemberConverter.java index dbffe026..944c2cac 100644 --- a/src/main/java/com/codiary/backend/global/converter/MemberConverter.java +++ b/src/main/java/com/codiary/backend/global/converter/MemberConverter.java @@ -94,9 +94,9 @@ public static MemberResponseDTO.BookmarkDTO toBookmarkDTO(Bookmark bookmark) { .memberId(bookmark.getMember().getMemberId()) .bookmarkId(bookmark.getId()) .postId(bookmark.getPost().getPostId()) - // Post의 첫 번째 사진을 가져온다 - // 나중에 postFile이 존재하지 않을 경우 나오는 기본 사진 처리를 해줘야 한다 - .photoUrl(bookmark.getPost().getPostFileList().get(0).getFileUrl()) + .thumbnailImageUrl((bookmark.getPost().getThumbnailImage() != null) + ? bookmark.getPost().getThumbnailImage().getFileUrl() + : "") .postTitle(bookmark.getPost().getPostTitle()) .nickname(bookmark.getPost().getMember().getNickname()) .postBody(bookmark.getPost().getPostBody()) diff --git a/src/main/java/com/codiary/backend/global/converter/PostConverter.java b/src/main/java/com/codiary/backend/global/converter/PostConverter.java index dafce945..dcae8c65 100644 --- a/src/main/java/com/codiary/backend/global/converter/PostConverter.java +++ b/src/main/java/com/codiary/backend/global/converter/PostConverter.java @@ -15,36 +15,28 @@ public class PostConverter { -// public static Post toPost(PostRequestDTO.CreatePostRequestDTO request) { -// return Post.builder() -// .postTitle(request.getPostTitle()) -// .postBody(request.getPostBody()) -// .postStatus(request.getPostStatus()) -// .postAccess(request.getPostAccess()) -// .build(); -// } -public static Post toPost(PostRequestDTO.CreatePostRequestDTO request, TeamRepository teamRepository, ProjectRepository projectRepository) { - Team team = null; - Project project = null; - // teamId가 제공된 경우에만 Team 객체를 조회 - if (request.getTeamId() != null) { - team = teamRepository.findById(request.getTeamId()) - .orElseThrow(() -> new IllegalArgumentException("Team not found with id: " + request.getTeamId())); - } - // projectId가 제공된 경우에만 Project 객체를 조회 - if (request.getProjectId() != null) { - project = projectRepository.findById(request.getProjectId()) - .orElseThrow(() -> new IllegalArgumentException("Project not found with id: " + request.getProjectId())); + public static Post toPost(PostRequestDTO.CreatePostRequestDTO request, TeamRepository teamRepository, ProjectRepository projectRepository) { + Team team = null; + Project project = null; + // teamId가 제공된 경우에만 Team 객체를 조회 + if (request.getTeamId() != null) { + team = teamRepository.findById(request.getTeamId()) + .orElseThrow(() -> new IllegalArgumentException("Team not found with id: " + request.getTeamId())); + } + // projectId가 제공된 경우에만 Project 객체를 조회 + if (request.getProjectId() != null) { + project = projectRepository.findById(request.getProjectId()) + .orElseThrow(() -> new IllegalArgumentException("Project not found with id: " + request.getProjectId())); + } + return Post.builder() + .postTitle(request.getPostTitle()) + .postBody(request.getPostBody()) + .team(team) + .project(project) + .postStatus(request.getPostStatus()) + .postAccess(request.getPostAccess()) + .build(); } - return Post.builder() - .postTitle(request.getPostTitle()) - .postBody(request.getPostBody()) - .team(team) - .project(project) - .postStatus(request.getPostStatus()) - .postAccess(request.getPostAccess()) - .build(); -} public static PostResponseDTO.CreatePostResultDTO toCreateResultDTO(Post post) { @@ -64,6 +56,9 @@ public static PostResponseDTO.CreatePostResultDTO toCreateResultDTO(Post post) { .map(author -> author.getMember().getMemberId()) .collect(Collectors.toSet())) .postAccess(post.getPostAccess()) + .thumbnailImageUrl((post.getThumbnailImage() != null) + ? post.getThumbnailImage().getFileUrl() + : "") .postFileList(PostFileConverter.toPostFileListDTO(post.getPostFileList())) .build(); } @@ -86,6 +81,9 @@ public static PostResponseDTO.UpdatePostResultDTO toUpdatePostResultDTO(Post pos .map(author -> author.getMember().getMemberId()) .collect(Collectors.toSet())) .postAccess(post.getPostAccess()) + .thumbnailImageUrl((post.getThumbnailImage() != null) + ? post.getThumbnailImage().getFileUrl() + : "") .postFileList(PostFileConverter.toPostFileListDTO(post.getPostFileList())) .build(); } @@ -109,6 +107,9 @@ public static PostResponseDTO.PostPreviewDTO toPostPreviewDTO(Post post) { .map(author -> author.getMember().getMemberId()) .collect(Collectors.toSet())) .postAccess(post.getPostAccess()) + .thumbnailImageUrl((post.getThumbnailImage() != null) + ? post.getThumbnailImage().getFileUrl() + : "") .postFileList(PostFileConverter.toPostFileListDTO(post.getPostFileList())) .createdAt(post.getCreatedAt()) .updatedAt(post.getUpdatedAt()) @@ -150,6 +151,9 @@ public static PostResponseDTO.MemberPostPreviewDTO toMemberPostPreviewDTO(Post p .map(author -> author.getMember().getMemberId()) .collect(Collectors.toSet())) .postAccess(post.getPostAccess()) + .thumbnailImageUrl((post.getThumbnailImage() != null) + ? post.getThumbnailImage().getFileUrl() + : "") .postFileList(PostFileConverter.toPostFileListDTO(post.getPostFileList())) .createdAt(post.getCreatedAt()) .updatedAt(post.getUpdatedAt()) @@ -191,6 +195,9 @@ public static PostResponseDTO.TeamPostPreviewDTO toTeamPostPreviewDTO(Post post) .map(author -> author.getMember().getMemberId()) .collect(Collectors.toSet())) .postAccess(post.getPostAccess()) + .thumbnailImageUrl((post.getThumbnailImage() != null) + ? post.getThumbnailImage().getFileUrl() + : "") .postFileList(PostFileConverter.toPostFileListDTO(post.getPostFileList())) .createdAt(post.getCreatedAt()) .updatedAt(post.getUpdatedAt()) @@ -233,6 +240,9 @@ public static PostResponseDTO.MemberPostInProjectPreviewDTO toMemberPostInProjec .map(author -> author.getMember().getMemberId()) .collect(Collectors.toSet())) .postAccess(post.getPostAccess()) + .thumbnailImageUrl((post.getThumbnailImage() != null) + ? post.getThumbnailImage().getFileUrl() + : "") .postFileList(PostFileConverter.toPostFileListDTO(post.getPostFileList())) .createdAt(post.getCreatedAt()) .updatedAt(post.getUpdatedAt()) @@ -274,6 +284,9 @@ public static PostResponseDTO.TeamPostInProjectPreviewDTO toTeamPostInProjectPre .map(author -> author.getMember().getMemberId()) .collect(Collectors.toSet())) .postAccess(post.getPostAccess()) + .thumbnailImageUrl((post.getThumbnailImage() != null) + ? post.getThumbnailImage().getFileUrl() + : "") .postFileList(PostFileConverter.toPostFileListDTO(post.getPostFileList())) .createdAt(post.getCreatedAt()) .updatedAt(post.getUpdatedAt()) @@ -315,6 +328,9 @@ public static PostResponseDTO.MemberPostInTeamPreviewDTO toMemberPostInTeamPrevi .map(author -> author.getMember().getMemberId()) .collect(Collectors.toSet())) .postAccess(post.getPostAccess()) + .thumbnailImageUrl((post.getThumbnailImage() != null) + ? post.getThumbnailImage().getFileUrl() + : "") .postFileList(PostFileConverter.toPostFileListDTO(post.getPostFileList())) .createdAt(post.getCreatedAt()) .updatedAt(post.getUpdatedAt()) @@ -358,6 +374,9 @@ public static PostResponseDTO.PostAdjacentDTO.PostAdjacentPreviewDTO toPostAdjac .map(author -> author.getMember().getMemberId()) .collect(Collectors.toSet())) .postAccess(post.getPostAccess()) + .thumbnailImageUrl((post.getThumbnailImage() != null) + ? post.getThumbnailImage().getFileUrl() + : "") .postFileList(PostFileConverter.toPostFileListDTO(post.getPostFileList())) .createdAt(post.getCreatedAt()) .updatedAt(post.getUpdatedAt()) @@ -392,6 +411,9 @@ public static PostResponseDTO.UpdatePostResultDTO toSetPostCategoriesResultDTO(P .map(author -> author.getMember().getMemberId()) .collect(Collectors.toSet())) .postAccess(post.getPostAccess()) + .thumbnailImageUrl((post.getThumbnailImage() != null) + ? post.getThumbnailImage().getFileUrl() + : "") .postFileList(PostFileConverter.toPostFileListDTO(post.getPostFileList())) .build(); } diff --git a/src/main/java/com/codiary/backend/global/domain/entity/Post.java b/src/main/java/com/codiary/backend/global/domain/entity/Post.java index 1980f79b..62e01100 100644 --- a/src/main/java/com/codiary/backend/global/domain/entity/Post.java +++ b/src/main/java/com/codiary/backend/global/domain/entity/Post.java @@ -41,6 +41,10 @@ public class Post extends BaseEntity { @Column(name = "post_body", nullable = false, columnDefinition = "varchar(500)") private String postBody; + @OneToOne + @JoinColumn(name = "thumbnail_image_id") + private PostFile thumbnailImage; + @Builder.Default @Enumerated(EnumType.STRING) @Column(name = "post_access", nullable = false, columnDefinition = "varchar(500)") diff --git a/src/main/java/com/codiary/backend/global/repository/MemberRepository.java b/src/main/java/com/codiary/backend/global/repository/MemberRepository.java index 11a02848..c7b0ffac 100644 --- a/src/main/java/com/codiary/backend/global/repository/MemberRepository.java +++ b/src/main/java/com/codiary/backend/global/repository/MemberRepository.java @@ -12,6 +12,8 @@ public interface MemberRepository extends JpaRepository { // 이미 가입된 메일인지 확인 Boolean existsByEmail(String email); + Boolean existsByNickname(String nickname); + Optional findByEmail(String email); diff --git a/src/main/java/com/codiary/backend/global/service/MemberService/MemberCommandService.java b/src/main/java/com/codiary/backend/global/service/MemberService/MemberCommandService.java index 8d35dac4..a3cdb745 100644 --- a/src/main/java/com/codiary/backend/global/service/MemberService/MemberCommandService.java +++ b/src/main/java/com/codiary/backend/global/service/MemberService/MemberCommandService.java @@ -13,6 +13,10 @@ public interface MemberCommandService { public ApiResponse signUp(MemberRequestDTO.MemberSignUpRequestDTO signUpRequest); + ApiResponse checkEmailDuplication(String email); + + ApiResponse checkNicknameDuplication(String nickname); + public ApiResponse login(MemberRequestDTO.MemberLoginRequestDTO loginRequest); // 회원별 관심 카테고리탭 리스트 조회 diff --git a/src/main/java/com/codiary/backend/global/service/MemberService/MemberCommandServiceImpl.java b/src/main/java/com/codiary/backend/global/service/MemberService/MemberCommandServiceImpl.java index aba841ef..6f1a2c85 100644 --- a/src/main/java/com/codiary/backend/global/service/MemberService/MemberCommandServiceImpl.java +++ b/src/main/java/com/codiary/backend/global/service/MemberService/MemberCommandServiceImpl.java @@ -53,7 +53,8 @@ public class MemberCommandServiceImpl implements MemberCommandService { public ApiResponse signUp(MemberRequestDTO.MemberSignUpRequestDTO signUpRequest) { signUpRequest.isCorrect(); - if (memberRepository.existsByEmail(signUpRequest.getEmail())) { + if (memberRepository.existsByEmail(signUpRequest.getEmail()) + || memberRepository.existsByNickname(signUpRequest.getNickname())) { throw new MemberHandler(ErrorStatus.MEMBER_ALREADY_EXISTS); } @@ -65,6 +66,7 @@ public ApiResponse signUp(MemberRequestDTO.MemberSignUpRequestDTO signUp .gender(Member.Gender.Female) .github(signUpRequest.getGithub()) .linkedin(signUpRequest.getLinkedin()) + .discord(signUpRequest.getDiscord()) .image(null) .build(); memberRepository.save(member); @@ -72,6 +74,28 @@ public ApiResponse signUp(MemberRequestDTO.MemberSignUpRequestDTO signUp return ApiResponse.of(SuccessStatus.MEMBER_OK, "정상적으로 가입되었습니다."); } + @Override + public ApiResponse checkEmailDuplication(String email) { + if (memberRepository.existsByEmail(email)) { + throw new MemberHandler(ErrorStatus.MEMBER_EMAIL_ALREADY_EXISTS); + } + + if (!email.matches("^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$")) { + throw new MemberHandler(ErrorStatus.MEMBER_WRONG_EMAIL); + } + + return ApiResponse.onSuccess(SuccessStatus.MEMBER_OK, "사용가능한 이메일입니다!"); + } + + @Override + public ApiResponse checkNicknameDuplication(String nickname) { + if (memberRepository.existsByNickname(nickname)) { + throw new MemberHandler(ErrorStatus.MEMBER_NICKNAME_ALREADY_EXISTS); + } + return ApiResponse.onSuccess(SuccessStatus.MEMBER_OK, "사용가능한 닉네임입니다!"); + } + + @Override public ApiResponse login(MemberRequestDTO.MemberLoginRequestDTO loginRequest) { diff --git a/src/main/java/com/codiary/backend/global/service/PostService/PostCommandServiceImpl.java b/src/main/java/com/codiary/backend/global/service/PostService/PostCommandServiceImpl.java index 57997435..acbffdbf 100644 --- a/src/main/java/com/codiary/backend/global/service/PostService/PostCommandServiceImpl.java +++ b/src/main/java/com/codiary/backend/global/service/PostService/PostCommandServiceImpl.java @@ -74,6 +74,17 @@ public Post createPost(PostRequestDTO.CreatePostRequestDTO request) { } } + // 대표 사진 설정 + String thumbnailImageName = request.getThumbnailImageName(); + for (PostFile postFile : tempPost.getPostFileList()) { + if (postFile.getFileName().equals(thumbnailImageName)) { + tempPost.setThumbnailImage(postFile); + } + } + if (tempPost.getPostFileList().size() != 0 && tempPost.getThumbnailImage() == null) { + tempPost.setThumbnailImage(tempPost.getPostFileList().get(0)); + } + Post savedPost = postRepository.save(tempPost); return savedPost; } @@ -101,6 +112,17 @@ public Post updatePost(Long postId, PostRequestDTO.UpdatePostDTO request) { } } + // 대표 사진 설정 + String thumbnailImageName = request.getThumbnailImageName(); + for (PostFile postFile : updatePost.getPostFileList()) { + if (postFile.getFileName() == thumbnailImageName) { + updatePost.setThumbnailImage(postFile); + } + } + if (updatePost.getPostFileList().size() != 0 && updatePost.getThumbnailImage() == null) { + updatePost.setThumbnailImage(updatePost.getPostFileList().get(0)); + } + return postRepository.save(updatePost); } diff --git a/src/main/java/com/codiary/backend/global/web/controller/MemberController.java b/src/main/java/com/codiary/backend/global/web/controller/MemberController.java index 792520b9..5b8d856d 100644 --- a/src/main/java/com/codiary/backend/global/web/controller/MemberController.java +++ b/src/main/java/com/codiary/backend/global/web/controller/MemberController.java @@ -50,6 +50,18 @@ public ApiResponse signUp(@Valid @RequestBody MemberRequestDTO.MemberSig return memberCommandService.signUp(request); } + @GetMapping("/sign-up/check-email") + @Operation(summary = "이메일 중복 확인") + public ApiResponse checkEmailDuplication(@RequestParam String email) { + return memberCommandService.checkEmailDuplication(email); + } + + @GetMapping("/sign-up/check-nickname") + @Operation(summary = "닉네임 중복 확인") + public ApiResponse checkNicknameDuplication(@RequestParam String nickname) { + return memberCommandService.checkNicknameDuplication(nickname); + } + @PostMapping("/login") @Operation( summary = "로그인" diff --git a/src/main/java/com/codiary/backend/global/web/dto/Member/MemberRequestDTO.java b/src/main/java/com/codiary/backend/global/web/dto/Member/MemberRequestDTO.java index f3cc6a5c..50f801a4 100644 --- a/src/main/java/com/codiary/backend/global/web/dto/Member/MemberRequestDTO.java +++ b/src/main/java/com/codiary/backend/global/web/dto/Member/MemberRequestDTO.java @@ -28,6 +28,7 @@ public static class MemberSignUpRequestDTO { private Member.Gender gender; private String github; private String linkedin; + private String discord; @JsonIgnore public Boolean isCorrect() { diff --git a/src/main/java/com/codiary/backend/global/web/dto/Member/MemberResponseDTO.java b/src/main/java/com/codiary/backend/global/web/dto/Member/MemberResponseDTO.java index e473042d..84c348d6 100644 --- a/src/main/java/com/codiary/backend/global/web/dto/Member/MemberResponseDTO.java +++ b/src/main/java/com/codiary/backend/global/web/dto/Member/MemberResponseDTO.java @@ -43,7 +43,7 @@ public static class BookmarkDTO { Long memberId; Long bookmarkId; Long postId; - String photoUrl; + String thumbnailImageUrl; String postTitle; String nickname; String postBody; diff --git a/src/main/java/com/codiary/backend/global/web/dto/Post/PostRequestDTO.java b/src/main/java/com/codiary/backend/global/web/dto/Post/PostRequestDTO.java index 68d4af24..9b59e749 100644 --- a/src/main/java/com/codiary/backend/global/web/dto/Post/PostRequestDTO.java +++ b/src/main/java/com/codiary/backend/global/web/dto/Post/PostRequestDTO.java @@ -22,6 +22,7 @@ public static class CreatePostRequestDTO { private Boolean postStatus; //private Set postCategory; private PostAccess postAccess; + private String thumbnailImageName; private List postFiles; } @@ -36,6 +37,7 @@ public static class UpdatePostDTO { private Boolean postStatus; //private Set postCategory; private PostAccess postAccess; + private String thumbnailImageName; private List addedPostFiles; } diff --git a/src/main/java/com/codiary/backend/global/web/dto/Post/PostResponseDTO.java b/src/main/java/com/codiary/backend/global/web/dto/Post/PostResponseDTO.java index 10e52d9f..57469187 100644 --- a/src/main/java/com/codiary/backend/global/web/dto/Post/PostResponseDTO.java +++ b/src/main/java/com/codiary/backend/global/web/dto/Post/PostResponseDTO.java @@ -25,6 +25,7 @@ public static class CreatePostResultDTO { Long projectId; String postTitle; String postBody; + String thumbnailImageUrl; Boolean postStatus; String postCategory; Set coauthorIds; @@ -43,6 +44,7 @@ public static class UpdatePostResultDTO { Long projectId; String postTitle; String postBody; + String thumbnailImageUrl; Boolean postStatus; String postCategory; Set coauthorIds; @@ -61,6 +63,7 @@ public static class PostPreviewDTO { // Post 조회 Long projectId; String postTitle; String postBody; + String thumbnailImageUrl; Boolean postStatus; String postCategory; Set coauthorIds; @@ -94,6 +97,7 @@ public static class MemberPostPreviewDTO { // 저자별 Post 조회 Long projectId; String postTitle; String postBody; + String thumbnailImageUrl; Boolean postStatus; String postCategory; Set coauthorIds; @@ -128,6 +132,7 @@ public static class TeamPostPreviewDTO { // 팀별 Post 조회 Long projectId; String postTitle; String postBody; + String thumbnailImageUrl; Boolean postStatus; String postCategory; Set coauthorIds; @@ -161,6 +166,7 @@ public static class MemberPostInProjectPreviewDTO { // 프로젝트별 저자의 Long teamId; String postTitle; String postBody; + String thumbnailImageUrl; Boolean postStatus; String postCategory; Set coauthorIds; @@ -194,6 +200,7 @@ public static class TeamPostInProjectPreviewDTO { // 프로젝트별 팀의 Post Long memberId; String postTitle; String postBody; + String thumbnailImageUrl; Boolean postStatus; String postCategory; Set coauthorIds; @@ -227,6 +234,7 @@ public static class MemberPostInTeamPreviewDTO { // 팀별 멤버의 Post 조회 Long projectId; String postTitle; String postBody; + String thumbnailImageUrl; Boolean postStatus; String postCategory; Set coauthorIds; @@ -271,6 +279,7 @@ public static class PostAdjacentPreviewDTO { Long projectId; String postTitle; String postBody; + String thumbnailImageUrl; Boolean postStatus; String postCategory; Set coauthorIds;