From a5091615357c18ad35fc2c86c6e7988c12c962c7 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Wed, 13 Mar 2024 19:15:14 +0900 Subject: [PATCH 001/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20API=20?= =?UTF-8?q?=EB=AC=B8=EC=84=9C=ED=99=94=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/api/FriendApi.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java index e4021f851..e99440247 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java @@ -17,8 +17,10 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import site.timecapsulearchive.core.domain.friend.data.reqeust.SearchFriendsRequest; +import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsPageResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; +import site.timecapsulearchive.core.global.common.response.ApiSpec; public interface FriendApi { @@ -34,7 +36,7 @@ public interface FriendApi { description = "처리 완료" ) }) - @PostMapping(value = "/friends/accept-request") + @PostMapping(value = "/accept-request") ResponseEntity acceptFriendRequest( @Parameter(in = ParameterIn.QUERY, required = true, schema = @Schema()) @NotNull @Valid @RequestParam(value = "friend_id") Long friendId @@ -53,7 +55,7 @@ ResponseEntity acceptFriendRequest( description = "처리 완료" ) }) - @DeleteMapping(value = "/friends/{friend_id}") + @DeleteMapping(value = "/{friend_id}") ResponseEntity deleteFriend( @Parameter(in = ParameterIn.PATH, required = true, schema = @Schema()) @PathVariable("friend_id") Long friendId @@ -72,7 +74,7 @@ ResponseEntity deleteFriend( description = "처리 완료" ) }) - @PostMapping(value = "/friends/deny-request") + @PostMapping(value = "/deny-request") ResponseEntity denyFriendRequest( @Parameter(in = ParameterIn.QUERY, required = true, schema = @Schema()) @NotNull @Valid @RequestParam(value = "friend_id") Long friendId @@ -92,7 +94,6 @@ ResponseEntity denyFriendRequest( ) }) @GetMapping( - value = "/friends", produces = {"application/json"} ) ResponseEntity findFriends( @@ -116,10 +117,11 @@ ResponseEntity findFriends( description = "처리 시작" ) }) - @PostMapping(value = "/friends/request") - ResponseEntity requestFriend( - @Parameter(in = ParameterIn.QUERY, required = true, schema = @Schema()) - @NotNull @Valid @RequestParam(value = "friend_id") Long friendId + ResponseEntity> requestFriend( + Long memberId, + + @Parameter(in = ParameterIn.PATH, description = "친구 아이디", required = true, schema = @Schema()) + @PathVariable("friend_id") Long friendId ); From db002165e556be453234bfe37f84aec33d3cb486 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Wed, 13 Mar 2024 19:15:36 +0900 Subject: [PATCH 002/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20Controller=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../friend/api/FriendApiController.java | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java new file mode 100644 index 000000000..b8e1796e9 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java @@ -0,0 +1,65 @@ +package site.timecapsulearchive.core.domain.friend.api; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import site.timecapsulearchive.core.domain.friend.data.reqeust.SearchFriendsRequest; +import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; +import site.timecapsulearchive.core.domain.friend.data.response.FriendsPageResponse; +import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; +import site.timecapsulearchive.core.domain.friend.service.FriendService; +import site.timecapsulearchive.core.global.common.response.ApiSpec; +import site.timecapsulearchive.core.global.common.response.SuccessCode; + +@RestController +@RequestMapping("/friend") +@RequiredArgsConstructor +public class FriendApiController implements FriendApi { + + private final FriendService friendService; + + @Override + public ResponseEntity acceptFriendRequest(Long friendId) { + return null; + } + + @Override + public ResponseEntity deleteFriend(Long friendId) { + return null; + } + + @Override + public ResponseEntity denyFriendRequest(Long friendId) { + return null; + } + + @Override + public ResponseEntity findFriends(Long friendId, Long size) { + return null; + } + + @PostMapping(value = "/{friend_id}/request") + @Override + public ResponseEntity> requestFriend( + @AuthenticationPrincipal Long memberId, + @PathVariable("friend_id") final Long friendId) { + + return ResponseEntity.accepted() + .body( + ApiSpec.success( + SuccessCode.SUCCESS, + friendService.requestFriend(memberId, friendId) + ) + ); + } + + @Override + public ResponseEntity searchMembersByPhones( + SearchFriendsRequest request) { + return null; + } +} From 872d6daba747bb9ee5201242ee8c60fadc3a6d4e Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Wed, 13 Mar 2024 19:15:56 +0900 Subject: [PATCH 003/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EC=9D=91=EB=8B=B5=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/response/FriendReqStatusResponse.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendReqStatusResponse.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendReqStatusResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendReqStatusResponse.java new file mode 100644 index 000000000..ccd3452de --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendReqStatusResponse.java @@ -0,0 +1,12 @@ +package site.timecapsulearchive.core.domain.friend.data.response; + +import org.springframework.http.HttpStatus; + +public record FriendReqStatusResponse( + HttpStatus httpStatus, + String result +) { + public static FriendReqStatusResponse success() { + return new FriendReqStatusResponse(HttpStatus.ACCEPTED, "친구 요청 메시지 전송 성공!"); + } +} From 0ed02fe82d8fcc0256459225c943bdd63b4aef9f Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Wed, 13 Mar 2024 19:17:13 +0900 Subject: [PATCH 004/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EC=A0=80=EC=9E=A5=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/friend/repository/FriendInviteRepository.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java index d573d12a0..c3b84b87e 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java @@ -1,9 +1,9 @@ package site.timecapsulearchive.core.domain.friend.repository; -import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.repository.Repository; import site.timecapsulearchive.core.domain.friend.entity.FriendInvite; -public interface FriendInviteRepository extends JpaRepository { - +public interface FriendInviteRepository extends Repository { + void save(FriendInvite friendInvite); } From d9b2a48ed3de01b48f84aa5b74cacd763e611e5d Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Wed, 13 Mar 2024 19:18:13 +0900 Subject: [PATCH 005/314] =?UTF-8?q?feat:=20frinedStatus=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - pending = 진행중 - accepted = 수락 - rejected = 거절 --- .../core/domain/friend/entity/FriendStatus.java | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendStatus.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendStatus.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendStatus.java new file mode 100644 index 000000000..7525e95cb --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendStatus.java @@ -0,0 +1,5 @@ +package site.timecapsulearchive.core.domain.friend.entity; + +public enum FriendStatus { + PENDING, ACCEPTED, REJECTED +} From 4d94075bd031eb3481dd7d43465029bf28c60440 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Wed, 13 Mar 2024 19:18:53 +0900 Subject: [PATCH 006/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=EC=97=90=EC=84=9C=20=EB=8F=84=EB=A9=94=EC=9D=B8?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../friend/data/mapper/FriendMapper.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/FriendMapper.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/FriendMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/FriendMapper.java new file mode 100644 index 000000000..abb9b4e03 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/FriendMapper.java @@ -0,0 +1,18 @@ +package site.timecapsulearchive.core.domain.friend.data.mapper; + +import org.springframework.stereotype.Component; +import site.timecapsulearchive.core.domain.friend.entity.FriendInvite; +import site.timecapsulearchive.core.domain.friend.entity.FriendStatus; +import site.timecapsulearchive.core.domain.member.entity.Member; + +@Component +public class FriendMapper { + + public FriendInvite friendReqToEntity(Member owner, Member friend) { + return FriendInvite.builder() + .friendStatus(FriendStatus.PENDING) + .owner(owner) + .friend(friend) + .build(); + } +} From 85be8318715b78b66767f2f99cd7c14692d7be78 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Wed, 13 Mar 2024 20:49:28 +0900 Subject: [PATCH 007/314] =?UTF-8?q?feat:=20FriendInvite=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=20friend=5Fstatus=20=EC=86=8D=EC=84=B1=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/entity/FriendInvite.java | 14 ++++++++++++-- .../db/migration/V16__friend_invite_update.sql | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 backend/core/src/main/resources/db/migration/V16__friend_invite_update.sql diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendInvite.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendInvite.java index e3ceb44b2..cbfd067ff 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendInvite.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendInvite.java @@ -10,6 +10,7 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import site.timecapsulearchive.core.domain.member.entity.Member; @@ -26,12 +27,21 @@ public class FriendInvite extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Column(name = "friend_status") + private FriendStatus friendStatus; + @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id", nullable = false, insertable = false, updatable = false) + @JoinColumn(name = "member_id", nullable = false) private Member owner; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id", nullable = false, insertable = false, updatable = false) + @JoinColumn(name = "member_id", nullable = false) private Member friend; + @Builder + private FriendInvite(FriendStatus friendStatus, Member owner, Member friend) { + this.friendStatus = friendStatus; + this.owner = owner; + this.friend = friend; + } } diff --git a/backend/core/src/main/resources/db/migration/V16__friend_invite_update.sql b/backend/core/src/main/resources/db/migration/V16__friend_invite_update.sql new file mode 100644 index 000000000..01ab3107c --- /dev/null +++ b/backend/core/src/main/resources/db/migration/V16__friend_invite_update.sql @@ -0,0 +1 @@ +ALTER TABLE friend_invite ADD COLUMN friend_status VARCHAR(20); From 8f543cdbfb7764a741bbae086d0c833b269d83d1 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Wed, 13 Mar 2024 20:51:45 +0900 Subject: [PATCH 008/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EC=95=8C=EB=A6=BC=20Request=20dto=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/request/FriendReqNotificationRequest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/dto/request/FriendReqNotificationRequest.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/dto/request/FriendReqNotificationRequest.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/dto/request/FriendReqNotificationRequest.java new file mode 100644 index 000000000..760f61b14 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/dto/request/FriendReqNotificationRequest.java @@ -0,0 +1,13 @@ +package site.timecapsulearchive.core.infra.notification.data.dto.request; + +import lombok.Builder; + +@Builder +public record FriendReqNotificationRequest( + Long friendId, + String status, + String title, + String text +) { + +} From 629a13ed78e5d38f26aae8c5a8a695cea756122f Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Wed, 13 Mar 2024 20:52:27 +0900 Subject: [PATCH 009/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20dto=20mapper=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/mapper/NotificationMapper.java | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java index a808a68ee..7500d8965 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java @@ -4,6 +4,7 @@ import org.springframework.stereotype.Component; import site.timecapsulearchive.core.domain.capsuleskin.data.dto.CapsuleSkinCreateDto; import site.timecapsulearchive.core.infra.notification.data.dto.request.CreatedCapsuleSkinNotificationRequest; +import site.timecapsulearchive.core.infra.notification.data.dto.request.FriendReqNotificationRequest; import site.timecapsulearchive.core.infra.s3.manager.S3PreSignedUrlManager; import site.timecapsulearchive.core.infra.s3.manager.S3UrlGenerator; @@ -14,17 +15,26 @@ public class NotificationMapper { private final S3PreSignedUrlManager s3PreSignedUrlManager; private final S3UrlGenerator s3UrlGenerator; - public CreatedCapsuleSkinNotificationRequest toRequest(Long memberId, + public CreatedCapsuleSkinNotificationRequest capsuleSkinDtoToMessage(Long memberId, CapsuleSkinCreateDto dto) { - return new CreatedCapsuleSkinNotificationRequest( - memberId, - "SUCCESS_MAKE_CAPSULE_SKIN", - dto.skinName(), - "캡슐 스킨 생성이 완료되었습니다", - dto.skinName() + "이 생성되었습니다. ARchive에서 확인해보세요!", - s3PreSignedUrlManager.getS3PreSignedUrlForGet( + return CreatedCapsuleSkinNotificationRequest.builder() + .memberId(memberId) + .status("SUCCESS_MAKE_CAPSULE_SKIN") + .skinName(dto.skinName()) + .title("캡슐 스킨 생성 알림") + .text(dto.skinName() + "이 생성되었습니다. ARchive에서 확인해보세요!") + .skinUrl(s3PreSignedUrlManager.getS3PreSignedUrlForGet( s3UrlGenerator.generateFileName(memberId, dto.directory(), dto.skinName()) - ) - ); + )) + .build(); + } + + public FriendReqNotificationRequest friendReqToMessage(Long friendId, String ownerNickname) { + return FriendReqNotificationRequest.builder() + .friendId(friendId) + .status("SEND_FRIEND_REQ_MESSAGE") + .title("친구 요청 알림") + .text(ownerNickname + "로부터 친구 요청이 왔습니다. ARchive에서 확인해보세요!") + .build(); } } From 10f6fdfef9596848d28711c06552fdfaf0d250c2 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Wed, 13 Mar 2024 20:52:54 +0900 Subject: [PATCH 010/314] =?UTF-8?q?feat:=20url=20enum=20=ED=83=80=EC=9E=85?= =?UTF-8?q?=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notification/manager/NotificationUrl.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationUrl.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationUrl.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationUrl.java new file mode 100644 index 000000000..9d2222991 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationUrl.java @@ -0,0 +1,16 @@ +package site.timecapsulearchive.core.infra.notification.manager; + +public enum NotificationUrl { + CAPSULE_SKIN_ALARM_URL("https://notification.archive-timecapsule.kro.kr/api/notification/capsule_skin/send"), + FRIEND_REQ_ALARM_URL("https://notification.archive-timecapsule.kro.kr/api/notification/friend_req/send"); + + private String url; + + NotificationUrl(String url) { + this.url = url; + } + + public String getUrl() { + return this.url; + } +} From b1f7184efcfe6a6eb8039490aba2403f23ba2335 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Wed, 13 Mar 2024 20:53:52 +0900 Subject: [PATCH 011/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EC=95=8C=EB=A6=BC=20=EC=A0=84=EC=86=A1=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../manager/NotificationManager.java | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java index eb7b0d312..650c4d724 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java @@ -1,6 +1,5 @@ package site.timecapsulearchive.core.infra.notification.manager; -import java.net.URI; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; @@ -11,6 +10,7 @@ import site.timecapsulearchive.core.domain.capsuleskin.data.dto.CapsuleSkinCreateDto; import site.timecapsulearchive.core.global.error.ErrorCode; import site.timecapsulearchive.core.infra.notification.data.dto.request.CreatedCapsuleSkinNotificationRequest; +import site.timecapsulearchive.core.infra.notification.data.dto.request.FriendReqNotificationRequest; import site.timecapsulearchive.core.infra.notification.data.mapper.NotificationMapper; import site.timecapsulearchive.core.infra.sms.exception.ExternalApiException; @@ -19,22 +19,35 @@ @RequiredArgsConstructor public class NotificationManager { - private static final String NOTIFICATION_SERVER_URL = "https://notification.archive-timecapsule.kro.kr/api/notification/capsule_skin/send"; private final RestTemplate restTemplate; private final NotificationMapper notificationMapper; - public void sendCreatedSkinMessage( - final Long memberId, - final CapsuleSkinCreateDto dto - ) { - final CreatedCapsuleSkinNotificationRequest request = notificationMapper.toRequest(memberId, dto); + public void sendCreatedSkinMessage(final Long memberId, final CapsuleSkinCreateDto dto) { + final CreatedCapsuleSkinNotificationRequest request = notificationMapper.capsuleSkinDtoToMessage(memberId, dto); try { final HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); restTemplate.postForEntity( - NOTIFICATION_SERVER_URL, + NotificationUrl.CAPSULE_SKIN_ALARM_URL.getUrl(), + new HttpEntity<>(request, headers), + Void.class + ); + } catch (HttpClientErrorException e) { + throw new ExternalApiException(ErrorCode.EXTERNAL_API_ERROR); + } + } + + public void sendFriendReqMessage(final Long friendId, final String ownerNickname) { + final FriendReqNotificationRequest request = notificationMapper.friendReqToMessage(friendId, ownerNickname); + + try { + final HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + + restTemplate.postForEntity( + NotificationUrl.FRIEND_REQ_ALARM_URL.getUrl(), new HttpEntity<>(request, headers), Void.class ); From 6dcd8b3ec949ecf33c77071f95c05d0389836f54 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Wed, 13 Mar 2024 20:54:30 +0900 Subject: [PATCH 012/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/friend/service/FriendService.java | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java new file mode 100644 index 000000000..2c1f53f7e --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -0,0 +1,63 @@ +package site.timecapsulearchive.core.domain.friend.service; + + +import org.springframework.stereotype.Service; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; +import site.timecapsulearchive.core.domain.friend.data.mapper.FriendMapper; +import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; +import site.timecapsulearchive.core.domain.friend.entity.FriendInvite; +import site.timecapsulearchive.core.domain.friend.repository.FriendInviteRepository; +import site.timecapsulearchive.core.domain.member.entity.Member; +import site.timecapsulearchive.core.domain.member.exception.MemberNotFoundException; +import site.timecapsulearchive.core.domain.member.repository.MemberRepository; +import site.timecapsulearchive.core.infra.notification.manager.NotificationManager; + +@Service + +public class FriendService { + + private final MemberRepository memberRepository; + private final FriendInviteRepository friendInviteRepository; + private final FriendMapper friendMapper; + private final NotificationManager notificationManager; + private final TransactionTemplate transactionTemplate; + + public FriendService( + MemberRepository memberRepository, + FriendInviteRepository friendInviteRepository, + FriendMapper friendMapper, + NotificationManager notificationManager, + PlatformTransactionManager transactionManager + ) { + this.memberRepository = memberRepository; + this.friendInviteRepository = friendInviteRepository; + this.friendMapper = friendMapper; + this.notificationManager = notificationManager; + this.transactionTemplate = new TransactionTemplate(transactionManager); + this.transactionTemplate.setTimeout(7); + } + + public FriendReqStatusResponse requestFriend(final Long memberId, final Long friendId) { + final Member owner = memberRepository.findMemberById(memberId).orElseThrow( + MemberNotFoundException::new); + + final Member friend = memberRepository.findMemberById(friendId).orElseThrow( + MemberNotFoundException::new); + + final FriendInvite friendInvite = friendMapper.friendReqToEntity(owner, friend); + + transactionTemplate.execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(TransactionStatus status) { + friendInviteRepository.save(friendInvite); + } + }); + + notificationManager.sendFriendReqMessage(friendId, owner.getNickname()); + + return FriendReqStatusResponse.success(); + } +} From 4351b4c916ab571884881bd214fb6f614fa18295 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Wed, 13 Mar 2024 20:56:11 +0900 Subject: [PATCH 013/314] =?UTF-8?q?chore:=20=EC=9E=90=EB=B0=94=20=EA=B5=AC?= =?UTF-8?q?=EA=B8=80=20=ED=98=95=EC=8B=9D=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/response/CapsuleSkinStatusResponse.java | 2 +- .../core/domain/friend/data/mapper/FriendMapper.java | 2 +- .../friend/data/response/FriendReqStatusResponse.java | 1 + .../domain/friend/repository/FriendInviteRepository.java | 1 + .../domain/friend/repository/MemberFriendRepository.java | 4 ++-- .../core/domain/member/api/MemberApiController.java | 2 +- .../request/CreatedCapsuleSkinNotificationRequest.java | 9 +++------ .../infra/notification/manager/NotificationManager.java | 6 ++++-- .../core/infra/notification/manager/NotificationUrl.java | 8 +++++--- backend/notification/src/main/resources/config | 2 +- 10 files changed, 20 insertions(+), 17 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsuleskin/data/response/CapsuleSkinStatusResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsuleskin/data/response/CapsuleSkinStatusResponse.java index 4697d2ff5..115da1a1a 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsuleskin/data/response/CapsuleSkinStatusResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsuleskin/data/response/CapsuleSkinStatusResponse.java @@ -8,7 +8,7 @@ public record CapsuleSkinStatusResponse( ) { public static CapsuleSkinStatusResponse success() { - return new CapsuleSkinStatusResponse(HttpStatus.OK ,"캡슐 스킨 생성 성공!"); + return new CapsuleSkinStatusResponse(HttpStatus.OK, "캡슐 스킨 생성 성공!"); } public static CapsuleSkinStatusResponse sendMessage() { diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/FriendMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/FriendMapper.java index abb9b4e03..5519badd4 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/FriendMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/FriendMapper.java @@ -8,7 +8,7 @@ @Component public class FriendMapper { - public FriendInvite friendReqToEntity(Member owner, Member friend) { + public FriendInvite friendReqToEntity(final Member owner, final Member friend) { return FriendInvite.builder() .friendStatus(FriendStatus.PENDING) .owner(owner) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendReqStatusResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendReqStatusResponse.java index ccd3452de..307da6a73 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendReqStatusResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendReqStatusResponse.java @@ -6,6 +6,7 @@ public record FriendReqStatusResponse( HttpStatus httpStatus, String result ) { + public static FriendReqStatusResponse success() { return new FriendReqStatusResponse(HttpStatus.ACCEPTED, "친구 요청 메시지 전송 성공!"); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java index c3b84b87e..00508bdc8 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java @@ -4,6 +4,7 @@ import site.timecapsulearchive.core.domain.friend.entity.FriendInvite; public interface FriendInviteRepository extends Repository { + void save(FriendInvite friendInvite); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepository.java index 7aa3b31d0..0720acaa1 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepository.java @@ -1,8 +1,8 @@ package site.timecapsulearchive.core.domain.friend.repository; -import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.repository.Repository; import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; -public interface MemberFriendRepository extends JpaRepository { +public interface MemberFriendRepository extends Repository { } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java index f31f0d111..2f76697f6 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java @@ -98,6 +98,6 @@ public ResponseEntity> getMemberNotific SuccessCode.SUCCESS, memberService.findNotificationSliceByMemberId(memberId, size, createdAt) ) - ); + ); } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/dto/request/CreatedCapsuleSkinNotificationRequest.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/dto/request/CreatedCapsuleSkinNotificationRequest.java index 9e0974b8d..c05a8b3c1 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/dto/request/CreatedCapsuleSkinNotificationRequest.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/dto/request/CreatedCapsuleSkinNotificationRequest.java @@ -1,17 +1,14 @@ package site.timecapsulearchive.core.infra.notification.data.dto.request; -public record CreatedCapsuleSkinNotificationRequest( +import lombok.Builder; +@Builder +public record CreatedCapsuleSkinNotificationRequest( Long memberId, - String status, - String skinName, - String title, - String text, - String skinUrl ) { diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java index 650c4d724..25dca0d2d 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java @@ -23,7 +23,8 @@ public class NotificationManager { private final NotificationMapper notificationMapper; public void sendCreatedSkinMessage(final Long memberId, final CapsuleSkinCreateDto dto) { - final CreatedCapsuleSkinNotificationRequest request = notificationMapper.capsuleSkinDtoToMessage(memberId, dto); + final CreatedCapsuleSkinNotificationRequest request = + notificationMapper.capsuleSkinDtoToMessage(memberId, dto); try { final HttpHeaders headers = new HttpHeaders(); @@ -40,7 +41,8 @@ public void sendCreatedSkinMessage(final Long memberId, final CapsuleSkinCreateD } public void sendFriendReqMessage(final Long friendId, final String ownerNickname) { - final FriendReqNotificationRequest request = notificationMapper.friendReqToMessage(friendId, ownerNickname); + final FriendReqNotificationRequest request = notificationMapper.friendReqToMessage(friendId, + ownerNickname); try { final HttpHeaders headers = new HttpHeaders(); diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationUrl.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationUrl.java index 9d2222991..c8d566d3b 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationUrl.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationUrl.java @@ -1,10 +1,12 @@ package site.timecapsulearchive.core.infra.notification.manager; public enum NotificationUrl { - CAPSULE_SKIN_ALARM_URL("https://notification.archive-timecapsule.kro.kr/api/notification/capsule_skin/send"), - FRIEND_REQ_ALARM_URL("https://notification.archive-timecapsule.kro.kr/api/notification/friend_req/send"); + CAPSULE_SKIN_ALARM_URL( + "https://notification.archive-timecapsule.kro.kr/api/notification/capsule_skin/send"), + FRIEND_REQ_ALARM_URL( + "https://notification.archive-timecapsule.kro.kr/api/notification/friend_req/send"); - private String url; + private final String url; NotificationUrl(String url) { this.url = url; diff --git a/backend/notification/src/main/resources/config b/backend/notification/src/main/resources/config index 375799a03..9c932cc6c 160000 --- a/backend/notification/src/main/resources/config +++ b/backend/notification/src/main/resources/config @@ -1 +1 @@ -Subproject commit 375799a03e4436f87d1cd69547dd3a69871f2688 +Subproject commit 9c932cc6c99dd13768e8af801d4fbde4d1f6b9bd From 9d0900c19af4817b85a110039a46cdb5c591a44d Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Wed, 13 Mar 2024 23:05:23 +0900 Subject: [PATCH 014/314] =?UTF-8?q?refact:=20FriendInvite=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=20=EC=99=B8=EB=9E=98=ED=82=A4=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/entity/FriendInvite.java | 4 ++-- .../db/migration/V16__friend_invite_update.sql | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendInvite.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendInvite.java index cbfd067ff..528574dbc 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendInvite.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendInvite.java @@ -31,11 +31,11 @@ public class FriendInvite extends BaseEntity { private FriendStatus friendStatus; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id", nullable = false) + @JoinColumn(name = "owner_id", nullable = false) private Member owner; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id", nullable = false) + @JoinColumn(name = "friend_id", nullable = false) private Member friend; @Builder diff --git a/backend/core/src/main/resources/db/migration/V16__friend_invite_update.sql b/backend/core/src/main/resources/db/migration/V16__friend_invite_update.sql index 01ab3107c..01cb9f73e 100644 --- a/backend/core/src/main/resources/db/migration/V16__friend_invite_update.sql +++ b/backend/core/src/main/resources/db/migration/V16__friend_invite_update.sql @@ -1 +1,11 @@ ALTER TABLE friend_invite ADD COLUMN friend_status VARCHAR(20); +ALTER TABLE friend_invite DROP CONSTRAINT fk_friend_invite_member_id; +ALTER TABLE friend_invite DROP COLUMN member_id; + +ALTER TABLE friend_invite ADD COLUMN owner_id BIGINT; +ALTER TABLE friend_invite ADD COLUMN friend_id BIGINT; +ALTER TABLE friend_invite + ADD CONSTRAINT fk_friend_invite_owner_id FOREIGN KEY (owner_id) REFERENCES member (member_id); + +ALTER TABLE friend_invite + ADD CONSTRAINT fk_friend_invite_friend_id FOREIGN KEY (friend_id) REFERENCES member (member_id); From 35b5389a38bb51cd56e19ee0813c41ec47f8c52d Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Fri, 15 Mar 2024 01:28:51 +0900 Subject: [PATCH 015/314] =?UTF-8?q?fix:=20@PathVariable=20=EC=96=B4?= =?UTF-8?q?=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timecapsulearchive/core/domain/friend/api/FriendApi.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java index e99440247..fdd899241 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java @@ -121,7 +121,7 @@ ResponseEntity> requestFriend( Long memberId, @Parameter(in = ParameterIn.PATH, description = "친구 아이디", required = true, schema = @Schema()) - @PathVariable("friend_id") Long friendId + Long friendId ); From e40ed94412e24e948f48bcce97b71998833db709 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Fri, 15 Mar 2024 01:47:59 +0900 Subject: [PATCH 016/314] =?UTF-8?q?refact:=20NotificationUrl=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../manager/NotificationManager.java | 5 +++-- .../notification/manager/NotificationUrl.java | 19 ++++++------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java index 25dca0d2d..d7e6fb8b8 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java @@ -21,6 +21,7 @@ public class NotificationManager { private final RestTemplate restTemplate; private final NotificationMapper notificationMapper; + private final NotificationUrl notificationUrl; public void sendCreatedSkinMessage(final Long memberId, final CapsuleSkinCreateDto dto) { final CreatedCapsuleSkinNotificationRequest request = @@ -31,7 +32,7 @@ public void sendCreatedSkinMessage(final Long memberId, final CapsuleSkinCreateD headers.setContentType(MediaType.APPLICATION_JSON); restTemplate.postForEntity( - NotificationUrl.CAPSULE_SKIN_ALARM_URL.getUrl(), + notificationUrl.capsuleSkinAlarmUrl(), new HttpEntity<>(request, headers), Void.class ); @@ -49,7 +50,7 @@ public void sendFriendReqMessage(final Long friendId, final String ownerNickname headers.setContentType(MediaType.APPLICATION_JSON); restTemplate.postForEntity( - NotificationUrl.FRIEND_REQ_ALARM_URL.getUrl(), + notificationUrl.friendReqAlarmUrl(), new HttpEntity<>(request, headers), Void.class ); diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationUrl.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationUrl.java index c8d566d3b..6403dde73 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationUrl.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationUrl.java @@ -1,18 +1,11 @@ package site.timecapsulearchive.core.infra.notification.manager; -public enum NotificationUrl { - CAPSULE_SKIN_ALARM_URL( - "https://notification.archive-timecapsule.kro.kr/api/notification/capsule_skin/send"), - FRIEND_REQ_ALARM_URL( - "https://notification.archive-timecapsule.kro.kr/api/notification/friend_req/send"); +import org.springframework.boot.context.properties.ConfigurationProperties; - private final String url; +@ConfigurationProperties(prefix = "notification-url") +public record NotificationUrl( + String capsuleSkinAlarmUrl, + String friendReqAlarmUrl +) { - NotificationUrl(String url) { - this.url = url; - } - - public String getUrl() { - return this.url; - } } From df1362c8cb581521441593969b4c83fd6e1a8e68 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Fri, 15 Mar 2024 01:48:55 +0900 Subject: [PATCH 017/314] =?UTF-8?q?chore:=20=EC=84=9C=EB=B8=8C=EB=AA=A8?= =?UTF-8?q?=EB=93=88=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/core/src/main/resources/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/core/src/main/resources/config b/backend/core/src/main/resources/config index cb726d029..aefe5b1fc 160000 --- a/backend/core/src/main/resources/config +++ b/backend/core/src/main/resources/config @@ -1 +1 @@ -Subproject commit cb726d029aaa6d6bfa2aade429efe4c9c96e3662 +Subproject commit aefe5b1fc708ace034b9310779afba28df20d2e0 From 2b5b624b4ccb452760842b67b28d051b3bb2c23c Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 9 Mar 2024 10:57:10 +0900 Subject: [PATCH 018/314] =?UTF-8?q?fix=20:=20MemberFriend=20=ED=85=8C?= =?UTF-8?q?=EC=9D=B4=EB=B8=94=20&=20=EC=97=94=ED=8B=B0=ED=8B=B0=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/entity/MemberFriend.java | 4 ++-- .../resources/db/migration/V16__member_friend_update.sql | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 backend/core/src/main/resources/db/migration/V16__member_friend_update.sql diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java index 02582383c..38c951f55 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java @@ -27,11 +27,11 @@ public class MemberFriend extends BaseEntity { private Long id; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id", nullable = false, insertable = false, updatable = false) + @JoinColumn(name = "owner_id", nullable = false, insertable = false, updatable = false) private Member owner; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id", nullable = false, insertable = false, updatable = false) + @JoinColumn(name = "friend_id", nullable = false, insertable = false, updatable = false) private Member friend; } diff --git a/backend/core/src/main/resources/db/migration/V16__member_friend_update.sql b/backend/core/src/main/resources/db/migration/V16__member_friend_update.sql new file mode 100644 index 000000000..2e445a0c0 --- /dev/null +++ b/backend/core/src/main/resources/db/migration/V16__member_friend_update.sql @@ -0,0 +1,7 @@ +# 친구 대상 아이디 추가 +ALTER TABLE member_friend + ADD COLUMN friend_id bigint, + ADD FOREIGN KEY fk_member_friend_member(member_id) REFERENCES member(member_id); + +ALTER TABLE member_friend + CHANGE member_id owner_id BIGINT \ No newline at end of file From 20f13b0e6c0f66340a241554bc15af5238684be2 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 9 Mar 2024 10:58:06 +0900 Subject: [PATCH 019/314] =?UTF-8?q?feat=20:=20=EC=B9=9C=EA=B5=AC=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/api/FriendApi.java | 16 ++--- .../friend/api/FriendApiController.java | 68 +++++++++++++++++++ .../exception/FriendNotFoundException.java | 11 +++ .../repository/FriendInviteRepository.java | 4 +- .../repository/MemberFriendRepository.java | 7 +- .../domain/friend/service/FriendService.java | 25 +++++++ .../core/global/error/ErrorCode.java | 5 +- 7 files changed, 123 insertions(+), 13 deletions(-) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/exception/FriendNotFoundException.java create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java index e4021f851..2c988fdfe 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java @@ -10,15 +10,14 @@ import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import site.timecapsulearchive.core.domain.friend.data.reqeust.SearchFriendsRequest; import site.timecapsulearchive.core.domain.friend.data.response.FriendsPageResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; +import site.timecapsulearchive.core.global.common.response.ApiSpec; public interface FriendApi { @@ -36,8 +35,8 @@ public interface FriendApi { }) @PostMapping(value = "/friends/accept-request") ResponseEntity acceptFriendRequest( - @Parameter(in = ParameterIn.QUERY, required = true, schema = @Schema()) - @NotNull @Valid @RequestParam(value = "friend_id") Long friendId + @Parameter(in = ParameterIn.QUERY, required = true) + @RequestParam(value = "friend_id") Long friendId ); @@ -49,14 +48,15 @@ ResponseEntity acceptFriendRequest( ) @ApiResponses(value = { @ApiResponse( - responseCode = "204", + responseCode = "200", description = "처리 완료" ) }) - @DeleteMapping(value = "/friends/{friend_id}") - ResponseEntity deleteFriend( + ResponseEntity> deleteFriend( + Long memberId, + @Parameter(in = ParameterIn.PATH, required = true, schema = @Schema()) - @PathVariable("friend_id") Long friendId + Long friendId ); diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java new file mode 100644 index 000000000..24a636712 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java @@ -0,0 +1,68 @@ +package site.timecapsulearchive.core.domain.friend.api; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import site.timecapsulearchive.core.domain.friend.data.reqeust.SearchFriendsRequest; +import site.timecapsulearchive.core.domain.friend.data.response.FriendsPageResponse; +import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; +import site.timecapsulearchive.core.domain.friend.service.FriendService; +import site.timecapsulearchive.core.global.common.response.ApiSpec; +import site.timecapsulearchive.core.global.common.response.SuccessCode; + +@RestController +@RequestMapping("/friends") +@RequiredArgsConstructor +public class FriendApiController implements FriendApi { + + private final FriendService friendService; + + @Override + public ResponseEntity acceptFriendRequest(Long friendId) { + return null; + } + + /** + * 회원 아이디와 친구 아이디를 받아서 삭제 + * @param memberId + * @param friendId + * @return + */ + @DeleteMapping(value = "/{friend_id}") + @Override + public ResponseEntity> deleteFriend( + @AuthenticationPrincipal final Long memberId, + @PathVariable("friend_id") final Long friendId + ) { + friendService.deleteFriend(memberId, friendId); + + return ResponseEntity.ok( + ApiSpec.empty(SuccessCode.SUCCESS) + ); + } + + @Override + public ResponseEntity denyFriendRequest(Long friendId) { + return null; + } + + @Override + public ResponseEntity findFriends(Long friendId, Long size) { + return null; + } + + @Override + public ResponseEntity requestFriend(Long friendId) { + return null; + } + + @Override + public ResponseEntity searchMembersByPhones( + SearchFriendsRequest request) { + return null; + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/exception/FriendNotFoundException.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/exception/FriendNotFoundException.java new file mode 100644 index 000000000..0eb24d8d3 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/exception/FriendNotFoundException.java @@ -0,0 +1,11 @@ +package site.timecapsulearchive.core.domain.friend.exception; + +import site.timecapsulearchive.core.global.error.ErrorCode; +import site.timecapsulearchive.core.global.error.exception.BusinessException; + +public class FriendNotFoundException extends BusinessException { + + public FriendNotFoundException() { + super(ErrorCode.FRIEND_NOT_FOUND_ERROR); + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java index d573d12a0..ec96e20db 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java @@ -1,9 +1,9 @@ package site.timecapsulearchive.core.domain.friend.repository; -import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.repository.Repository; import site.timecapsulearchive.core.domain.friend.entity.FriendInvite; -public interface FriendInviteRepository extends JpaRepository { +public interface FriendInviteRepository extends Repository { } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepository.java index 7aa3b31d0..c1b56feb9 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepository.java @@ -1,8 +1,11 @@ package site.timecapsulearchive.core.domain.friend.repository; -import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; +import org.springframework.data.repository.Repository; import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; -public interface MemberFriendRepository extends JpaRepository { +public interface MemberFriendRepository extends Repository { + Optional findMemberFriendByOwnerIdAndFriendId(Long ownerId, Long friendId); + void delete(MemberFriend memberFriend); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java new file mode 100644 index 000000000..c44674063 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -0,0 +1,25 @@ +package site.timecapsulearchive.core.domain.friend.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; +import site.timecapsulearchive.core.domain.friend.exception.FriendNotFoundException; +import site.timecapsulearchive.core.domain.friend.repository.MemberFriendRepository; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class FriendService { + + private final MemberFriendRepository memberFriendRepository; + + @Transactional + public void deleteFriend(final Long memberId, final Long friendId) { + MemberFriend memberFriend = memberFriendRepository.findMemberFriendByOwnerIdAndFriendId( + memberId, friendId) + .orElseThrow(FriendNotFoundException::new); + + memberFriendRepository.delete(memberFriend); + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java index 8283d789a..2d2934842 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java @@ -48,7 +48,10 @@ public enum ErrorCode { CAPSULE_SKIN_NOT_FOUND_ERROR(404, "SKIN-001", "캡슐 스킨을 찾지 못하였습니다."), //capsule - CAPSULE_NOT_FOUND_ERROR(404, "CAPSULE-001", "캡슐을 찾지 못하였습니다."); + CAPSULE_NOT_FOUND_ERROR(404, "CAPSULE-001", "캡슐을 찾지 못하였습니다."), + + //friend + FRIEND_NOT_FOUND_ERROR(404, "FRIEND-001", "친구를 찾지 못하였습니다"); private final int status; private final String code; From 65347b7439959c57f94081c8814a0121bcc270fc Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 9 Mar 2024 11:07:02 +0900 Subject: [PATCH 020/314] =?UTF-8?q?feat=20:=20=EC=9E=85=EB=A0=A5=20?= =?UTF-8?q?=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20=ED=83=80=EC=9E=85=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/global/error/ErrorCode.java | 1 + .../core/global/error/ErrorResponse.java | 14 ++++++++++++++ .../global/error/GlobalExceptionHandler.java | 17 +++++++++++++++++ backend/core/src/main/resources/config | 2 +- 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java index 2d2934842..0ffdce8fd 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java @@ -12,6 +12,7 @@ public enum ErrorCode { INPUT_INVALID_VALUE_ERROR(400, "GLOBAL-002", "잘못된 입력 값입니다."), INPUT_INVALID_TYPE_ERROR(400, "GLOBAL-003", "잘못된 입력 타입입니다."), REQUEST_PARAMETER_NOT_FOUND_ERROR(400, "GLOBAL-004", "입력 파라미터가 존재하지 않습니다."), + REQUEST_PARAMETER_TYPE_NOT_MATCH_ERROR(400, "GLOBAL-005", "입력 파라미터의 타입이 올바르지 않습니다."), //jwt INVALID_TOKEN_ERROR(400, "AUTH-001", "jwt 토큰이 유효하지 않습니다."), diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorResponse.java index 72f201e56..562d3fd8a 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorResponse.java @@ -45,12 +45,26 @@ public static ErrorResponse parameter( List.of(Error.parameter(parameterName)) ); } + + public static ErrorResponse type( + final ErrorCode errorCode, + final String parameterName + ) { + return new ErrorResponse( + errorCode.getCode(), + errorCode.getMessage(), + List.of(Error.type(parameterName)) + ); + } public record Error( String field, String value, String reason ) { + public static Error type(final String parameterName) { + return new Error(parameterName, null, "입력 파라미터의 타입이 올바르지 않습니다."); + } public static Error parameter(final String parameterName) { return new Error(parameterName, null, "필수 입력 파라미터를 포함하지 않았습니다."); diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/GlobalExceptionHandler.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/GlobalExceptionHandler.java index 28b944d12..92959b6d6 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/GlobalExceptionHandler.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/GlobalExceptionHandler.java @@ -4,6 +4,7 @@ import static site.timecapsulearchive.core.global.error.ErrorCode.INPUT_INVALID_VALUE_ERROR; import static site.timecapsulearchive.core.global.error.ErrorCode.INTERNAL_SERVER_ERROR; import static site.timecapsulearchive.core.global.error.ErrorCode.REQUEST_PARAMETER_NOT_FOUND_ERROR; +import static site.timecapsulearchive.core.global.error.ErrorCode.REQUEST_PARAMETER_TYPE_NOT_MATCH_ERROR; import jakarta.transaction.TransactionalException; import lombok.extern.slf4j.Slf4j; @@ -14,6 +15,7 @@ import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; import site.timecapsulearchive.core.global.error.exception.BusinessException; import site.timecapsulearchive.core.infra.sms.exception.ExternalApiException; @@ -89,6 +91,21 @@ protected ResponseEntity handleMissingServletRequestParameterExce .body(errorResponse); } + @ExceptionHandler(MethodArgumentTypeMismatchException.class) + protected ResponseEntity handleMethodArgumentTypeMismatchException( + MethodArgumentTypeMismatchException e + ) { + log.warn(e.getMessage(), e); + + final ErrorResponse errorResponse = ErrorResponse.type( + REQUEST_PARAMETER_TYPE_NOT_MATCH_ERROR, + e.getParameter().getParameterName() + ); + + return ResponseEntity.status(REQUEST_PARAMETER_NOT_FOUND_ERROR.getStatus()) + .body(errorResponse); + } + @ExceptionHandler(DataIntegrityViolationException.class) protected ResponseEntity handleDataIntegrityViolationException( DataIntegrityViolationException e diff --git a/backend/core/src/main/resources/config b/backend/core/src/main/resources/config index cb726d029..ed5290f31 160000 --- a/backend/core/src/main/resources/config +++ b/backend/core/src/main/resources/config @@ -1 +1 @@ -Subproject commit cb726d029aaa6d6bfa2aade429efe4c9c96e3662 +Subproject commit ed5290f3197ac922d2423bd874d4884121c4e63f From 353e5696a721e5cdc8e25677b36e52fd399f0940 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 9 Mar 2024 11:10:48 +0900 Subject: [PATCH 021/314] =?UTF-8?q?refact=20:=20ErrorResponse=20&=20Error?= =?UTF-8?q?=20=EC=A0=95=EC=A0=81=20=ED=8C=A9=ED=86=A0=EB=A6=AC=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EC=9D=B4=EB=A6=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 명확하게 수정 --- .../core/global/error/ErrorResponse.java | 29 ++++++++++--------- .../global/error/GlobalExceptionHandler.java | 23 ++++++++------- .../handler/CustomAccessDeniedHandler.java | 2 +- .../security/jwt/JwtAuthenticationFilter.java | 2 +- .../handler/OAuth2LoginFailureHandler.java | 2 +- .../handler/OAuth2LoginSuccessHandler.java | 2 +- 6 files changed, 31 insertions(+), 29 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorResponse.java index 562d3fd8a..08ef89382 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorResponse.java @@ -18,7 +18,7 @@ public record ErrorResponse( List result ) { - public static ErrorResponse create(final ErrorCode errorCode) { + public static ErrorResponse fromErrorCode(final ErrorCode errorCode) { return new ErrorResponse( errorCode.getCode(), errorCode.getMessage(), @@ -26,34 +26,35 @@ public static ErrorResponse create(final ErrorCode errorCode) { ); } - public static ErrorResponse create(final ErrorCode errorCode, + public static ErrorResponse ofBindingResult(final ErrorCode errorCode, final BindingResult bindingResult) { return new ErrorResponse( errorCode.getCode(), errorCode.getMessage(), - Error.from(bindingResult) + Error.fromBindingResult(bindingResult) ); } - public static ErrorResponse parameter( + public static ErrorResponse fromParameter( final ErrorCode errorCode, final String parameterName ) { return new ErrorResponse( errorCode.getCode(), errorCode.getMessage(), - List.of(Error.parameter(parameterName)) + List.of(Error.fromParameter(parameterName)) ); } - public static ErrorResponse type( + public static ErrorResponse fromType( final ErrorCode errorCode, - final String parameterName + final String parameterName, + final String value ) { return new ErrorResponse( errorCode.getCode(), errorCode.getMessage(), - List.of(Error.type(parameterName)) + List.of(Error.fromType(parameterName, value)) ); } @@ -62,21 +63,21 @@ public record Error( String value, String reason ) { - public static Error type(final String parameterName) { - return new Error(parameterName, null, "입력 파라미터의 타입이 올바르지 않습니다."); + public static Error fromType(final String parameterName, final String value) { + return new Error(parameterName, value, "입력 파라미터의 타입이 올바르지 않습니다."); } - public static Error parameter(final String parameterName) { + public static Error fromParameter(final String parameterName) { return new Error(parameterName, null, "필수 입력 파라미터를 포함하지 않았습니다."); } - public static List from(final BindingResult bindingResult) { + public static List fromBindingResult(final BindingResult bindingResult) { return bindingResult.getFieldErrors().stream() - .map(Error::from) + .map(Error::fromFieldError) .toList(); } - private static Error from(final FieldError fieldError) { + private static Error fromFieldError(final FieldError fieldError) { return new Error( fieldError.getField(), String.valueOf(fieldError.getRejectedValue()), diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/GlobalExceptionHandler.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/GlobalExceptionHandler.java index 92959b6d6..ae5c51c83 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/GlobalExceptionHandler.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/GlobalExceptionHandler.java @@ -27,7 +27,7 @@ public class GlobalExceptionHandler { protected ResponseEntity handleGlobalException(final Exception e) { log.error(e.getMessage(), e); - final ErrorResponse errorResponse = ErrorResponse.create(ErrorCode.INTERNAL_SERVER_ERROR); + final ErrorResponse errorResponse = ErrorResponse.fromErrorCode(ErrorCode.INTERNAL_SERVER_ERROR); return ResponseEntity.status(INTERNAL_SERVER_ERROR.getStatus()) .body(errorResponse); } @@ -37,7 +37,7 @@ protected ResponseEntity handleBusinessException(final BusinessEx log.error(e.getMessage(), e); final ErrorCode errorCode = e.getErrorCode(); - final ErrorResponse errorResponse = ErrorResponse.create(errorCode); + final ErrorResponse errorResponse = ErrorResponse.fromErrorCode(errorCode); return ResponseEntity.status(errorCode.getStatus()) .body(errorResponse); @@ -49,7 +49,7 @@ protected ResponseEntity handleRequestArgumentNotValidException( ) { log.warn(e.getMessage(), e); - final ErrorResponse response = ErrorResponse.create(INPUT_INVALID_VALUE_ERROR, + final ErrorResponse response = ErrorResponse.ofBindingResult(INPUT_INVALID_VALUE_ERROR, e.getBindingResult()); return ResponseEntity.status(INPUT_INVALID_VALUE_ERROR.getStatus()) .body(response); @@ -61,7 +61,7 @@ protected ResponseEntity handleRequestTypeNotValidException( ) { log.warn(e.getMessage(), e); - final ErrorResponse response = ErrorResponse.create(INPUT_INVALID_TYPE_ERROR); + final ErrorResponse response = ErrorResponse.fromErrorCode(INPUT_INVALID_TYPE_ERROR); return ResponseEntity.status(INPUT_INVALID_VALUE_ERROR.getStatus()) .body(response); } @@ -71,7 +71,7 @@ protected ResponseEntity handleExternalApiException(ExternalApiEx log.warn(e.getMessage(), e); final ErrorCode errorCode = e.getErrorCode(); - final ErrorResponse response = ErrorResponse.create(errorCode); + final ErrorResponse response = ErrorResponse.fromErrorCode(errorCode); return ResponseEntity.status(errorCode.getStatus()) .body(response); @@ -83,7 +83,7 @@ protected ResponseEntity handleMissingServletRequestParameterExce ) { log.warn(e.getMessage(), e); - final ErrorResponse errorResponse = ErrorResponse.parameter( + final ErrorResponse errorResponse = ErrorResponse.fromParameter( REQUEST_PARAMETER_NOT_FOUND_ERROR, e.getParameterName()); @@ -96,10 +96,11 @@ protected ResponseEntity handleMethodArgumentTypeMismatchExceptio MethodArgumentTypeMismatchException e ) { log.warn(e.getMessage(), e); - - final ErrorResponse errorResponse = ErrorResponse.type( + + final ErrorResponse errorResponse = ErrorResponse.fromType( REQUEST_PARAMETER_TYPE_NOT_MATCH_ERROR, - e.getParameter().getParameterName() + e.getParameter().getParameterName(), + String.valueOf(e.getValue()) ); return ResponseEntity.status(REQUEST_PARAMETER_NOT_FOUND_ERROR.getStatus()) @@ -113,7 +114,7 @@ protected ResponseEntity handleDataIntegrityViolationException( log.warn(e.getMessage(), e); ErrorCode errorCode = INPUT_INVALID_VALUE_ERROR; - final ErrorResponse errorResponse = ErrorResponse.create(errorCode); + final ErrorResponse errorResponse = ErrorResponse.fromErrorCode(errorCode); return ResponseEntity.status(errorCode.getStatus()) .body(errorResponse); @@ -124,7 +125,7 @@ protected ResponseEntity handleTransactionException(Transactional log.warn(e.getMessage(), e); ErrorCode errorCode = INTERNAL_SERVER_ERROR; - final ErrorResponse errorResponse = ErrorResponse.create(errorCode); + final ErrorResponse errorResponse = ErrorResponse.fromErrorCode(errorCode); return ResponseEntity.status(errorCode.getStatus()) .body(errorResponse); diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/security/handler/CustomAccessDeniedHandler.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/security/handler/CustomAccessDeniedHandler.java index 223ac768a..ad38fe46d 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/security/handler/CustomAccessDeniedHandler.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/security/handler/CustomAccessDeniedHandler.java @@ -25,7 +25,7 @@ public void handle( final AccessDeniedException accessDeniedException ) throws IOException { - final ErrorResponse errorResponse = ErrorResponse.create( + final ErrorResponse errorResponse = ErrorResponse.fromErrorCode( ErrorCode.AUTHORIZATION_ERROR ); diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/security/jwt/JwtAuthenticationFilter.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/security/jwt/JwtAuthenticationFilter.java index e9a5b068b..3f6b0387f 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/security/jwt/JwtAuthenticationFilter.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/security/jwt/JwtAuthenticationFilter.java @@ -98,7 +98,7 @@ private void unsuccessfulAuthentication( log.info("액세스 토큰 인증 실패", exception); SecurityContextHolder.clearContext(); - final ErrorResponse errorResponse = ErrorResponse.create( + final ErrorResponse errorResponse = ErrorResponse.fromErrorCode( ErrorCode.AUTHENTICATION_ERROR ); diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/security/oauth/handler/OAuth2LoginFailureHandler.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/security/oauth/handler/OAuth2LoginFailureHandler.java index 84d8ec1d3..2b88c9f7f 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/security/oauth/handler/OAuth2LoginFailureHandler.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/security/oauth/handler/OAuth2LoginFailureHandler.java @@ -28,7 +28,7 @@ public void onAuthenticationFailure( ) throws IOException { log.info("oauth2 인증 실패", exception); - final ErrorResponse errorResponse = ErrorResponse.create( + final ErrorResponse errorResponse = ErrorResponse.fromErrorCode( ErrorCode.OAUTH2_NOT_AUTHENTICATED_ERROR ); diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/security/oauth/handler/OAuth2LoginSuccessHandler.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/security/oauth/handler/OAuth2LoginSuccessHandler.java index 50de77748..8518816f5 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/security/oauth/handler/OAuth2LoginSuccessHandler.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/security/oauth/handler/OAuth2LoginSuccessHandler.java @@ -53,7 +53,7 @@ public void onAuthenticationSuccess( } catch (final Exception exception) { log.info("oauth2 인증 실패", exception); - final ErrorResponse errorResponse = ErrorResponse.create( + final ErrorResponse errorResponse = ErrorResponse.fromErrorCode( ErrorCode.INTERNAL_SERVER_ERROR ); From 1248a12828c72f4b3ae6c0e02966fbe697527d03 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sat, 16 Mar 2024 22:14:07 +0900 Subject: [PATCH 022/314] =?UTF-8?q?fix=20:=20ci/cd=20=EB=B8=8C=EB=9E=9C?= =?UTF-8?q?=EC=B9=98=20=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/core-application-ci-cd-flow.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/core-application-ci-cd-flow.yml b/.github/workflows/core-application-ci-cd-flow.yml index 322411b49..8cc5156ef 100644 --- a/.github/workflows/core-application-ci-cd-flow.yml +++ b/.github/workflows/core-application-ci-cd-flow.yml @@ -3,11 +3,11 @@ name: ci/cd on: push: branches: - - develop_back - - 'hotfix/[0-9a-zA-z]+-B-#[0-9a-zA-z]+' + - develop_back_core + - 'hotfix/[0-9a-zA-z]+-B-core-#[0-9a-zA-z]+' pull_request: branches: - - develop_back + - develop_back_core jobs: formatting: From 6bcb404aa41c663f4918bc295ddbd9927f76ffbf Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Thu, 14 Mar 2024 00:26:39 +0900 Subject: [PATCH 023/314] =?UTF-8?q?chore:=20aop=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20build.gradle=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/core/build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/core/build.gradle b/backend/core/build.gradle index 0b16df4a1..3d7540abf 100644 --- a/backend/core/build.gradle +++ b/backend/core/build.gradle @@ -71,6 +71,9 @@ dependencies { //swagger implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0' + //aop + implementation 'org.springframework.boot:spring-boot-starter-aop' + compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok' From ac76c2ad443e92ca6edd1f2b9bb371d7324f9c45 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Thu, 14 Mar 2024 00:26:56 +0900 Subject: [PATCH 024/314] =?UTF-8?q?feat:=20=EC=95=8C=EB=A6=BC=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/aop/anotation/NotificationRequest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/global/aop/anotation/NotificationRequest.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/aop/anotation/NotificationRequest.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/aop/anotation/NotificationRequest.java new file mode 100644 index 000000000..c2e7fc796 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/aop/anotation/NotificationRequest.java @@ -0,0 +1,11 @@ +package site.timecapsulearchive.core.global.aop.anotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface NotificationRequest { +} From 2a5b9370b5cb9434172fa6d51c240e73bfeaadf0 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Thu, 14 Mar 2024 00:27:52 +0900 Subject: [PATCH 025/314] =?UTF-8?q?feat:=20=EC=95=8C=EB=A6=BC=EC=84=9C?= =?UTF-8?q?=EB=B2=84=20=EC=9A=94=EC=B2=AD=20=EC=98=88=EC=99=B8=20Aspect=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NotificationRequestExceptionAspect.java | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/global/aop/aspect/NotificationRequestExceptionAspect.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/aop/aspect/NotificationRequestExceptionAspect.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/aop/aspect/NotificationRequestExceptionAspect.java new file mode 100644 index 000000000..8eba031e7 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/aop/aspect/NotificationRequestExceptionAspect.java @@ -0,0 +1,49 @@ +package site.timecapsulearchive.core.global.aop.aspect; + +import lombok.RequiredArgsConstructor; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; +import site.timecapsulearchive.core.global.error.ErrorCode; +import site.timecapsulearchive.core.infra.sms.exception.ExternalApiException; + +@Aspect +@Component +@RequiredArgsConstructor +public class NotificationRequestExceptionAspect { + + private final RestTemplate restTemplate; + private final HttpHeaders headers = new HttpHeaders(); + + + @Pointcut("@annotation(site.timecapsulearchive.core.global.aop.anotation.NotificationRequest)") + public void notificationRequest() { + } + + @Before("notificationRequest()") + public void setHttpHeaders() { + headers.setContentType(MediaType.APPLICATION_JSON); + } + + @AfterThrowing(pointcut = "notificationRequest()", throwing = "ex") + public void handleExternalApiException(Exception ex) { + throw new ExternalApiException(ErrorCode.EXTERNAL_API_ERROR); + } + + public void sendNotification(T request, String url) { + try { + restTemplate.postForEntity(url, new HttpEntity<>(request, headers), Void.class); + } catch (HttpClientErrorException e) { + throw new ExternalApiException(ErrorCode.EXTERNAL_API_ERROR); + } + } + + +} From f048cde2b9633639a724812a18f22df290637441 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Thu, 14 Mar 2024 00:28:10 +0900 Subject: [PATCH 026/314] =?UTF-8?q?feat:=20NotificationManager=20aop=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../manager/NotificationManager.java | 39 ++++--------------- 1 file changed, 7 insertions(+), 32 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java index d7e6fb8b8..aee888362 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java @@ -1,61 +1,36 @@ package site.timecapsulearchive.core.infra.notification.manager; import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; import org.springframework.stereotype.Component; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.RestTemplate; import site.timecapsulearchive.core.domain.capsuleskin.data.dto.CapsuleSkinCreateDto; -import site.timecapsulearchive.core.global.error.ErrorCode; +import site.timecapsulearchive.core.global.aop.anotation.NotificationRequest; +import site.timecapsulearchive.core.global.aop.aspect.NotificationRequestExceptionAspect; import site.timecapsulearchive.core.infra.notification.data.dto.request.CreatedCapsuleSkinNotificationRequest; import site.timecapsulearchive.core.infra.notification.data.dto.request.FriendReqNotificationRequest; import site.timecapsulearchive.core.infra.notification.data.mapper.NotificationMapper; -import site.timecapsulearchive.core.infra.sms.exception.ExternalApiException; @Component @RequiredArgsConstructor public class NotificationManager { - private final RestTemplate restTemplate; private final NotificationMapper notificationMapper; + private final NotificationRequestExceptionAspect aspect; private final NotificationUrl notificationUrl; + @NotificationRequest public void sendCreatedSkinMessage(final Long memberId, final CapsuleSkinCreateDto dto) { final CreatedCapsuleSkinNotificationRequest request = notificationMapper.capsuleSkinDtoToMessage(memberId, dto); - try { - final HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - - restTemplate.postForEntity( - notificationUrl.capsuleSkinAlarmUrl(), - new HttpEntity<>(request, headers), - Void.class - ); - } catch (HttpClientErrorException e) { - throw new ExternalApiException(ErrorCode.EXTERNAL_API_ERROR); - } + aspect.sendNotification(request, notificationUrl.capsuleSkinAlarmUrl()); } + @NotificationRequest public void sendFriendReqMessage(final Long friendId, final String ownerNickname) { final FriendReqNotificationRequest request = notificationMapper.friendReqToMessage(friendId, ownerNickname); - try { - final HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - - restTemplate.postForEntity( - notificationUrl.friendReqAlarmUrl(), - new HttpEntity<>(request, headers), - Void.class - ); - } catch (HttpClientErrorException e) { - throw new ExternalApiException(ErrorCode.EXTERNAL_API_ERROR); - } + aspect.sendNotification(request, notificationUrl.friendReqAlarmUrl()); } } From ea976589b585413029b6c80c1d9a7dd8f7346bad Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Fri, 15 Mar 2024 01:52:30 +0900 Subject: [PATCH 027/314] =?UTF-8?q?chore:=20FriendApi=20=EB=AC=B8=EC=84=9C?= =?UTF-8?q?=ED=99=94=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timecapsulearchive/core/domain/friend/api/FriendApi.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java index fdd899241..fdacae0c9 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java @@ -115,6 +115,10 @@ ResponseEntity findFriends( @ApiResponse( responseCode = "202", description = "처리 시작" + ), + @ApiResponse( + responseCode = "500", + description = "외부 API 요청 실패" ) }) ResponseEntity> requestFriend( From 6e740c5b7ed6f50939301b3f7a59649f743b568c Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Fri, 15 Mar 2024 17:08:56 +0900 Subject: [PATCH 028/314] =?UTF-8?q?fix:=20=EC=BA=A1=EC=8A=90=20=EC=8A=A4?= =?UTF-8?q?=ED=82=A8=20=EC=83=9D=EC=84=B1=20API=20=EB=AC=B8=EC=84=9C?= =?UTF-8?q?=ED=99=94=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/capsuleskin/api/CapsuleSkinApi.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsuleskin/api/CapsuleSkinApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsuleskin/api/CapsuleSkinApi.java index ff24dfafc..93076b2a9 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsuleskin/api/CapsuleSkinApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsuleskin/api/CapsuleSkinApi.java @@ -71,6 +71,10 @@ ResponseEntity> getCapsuleSkins( @ApiResponse( responseCode = "202", description = "처리 시작" + ), + @ApiResponse( + responseCode = "500", + description = "외부 API 요청 실패" ) }) ResponseEntity> createCapsuleSkin( From 6c843a47d810d067300ae7c90901b98755f02f1a Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Fri, 15 Mar 2024 17:09:35 +0900 Subject: [PATCH 029/314] =?UTF-8?q?chore:=20=EA=B5=AC=EA=B8=80=20=EC=9E=90?= =?UTF-8?q?=EB=B0=94=20=EC=BD=94=EB=93=9C=20=ED=98=95=EC=8B=9D=20=EB=A7=9E?= =?UTF-8?q?=EC=B6=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/global/aop/anotation/NotificationRequest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/aop/anotation/NotificationRequest.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/aop/anotation/NotificationRequest.java index c2e7fc796..d3eedac40 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/aop/anotation/NotificationRequest.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/aop/anotation/NotificationRequest.java @@ -8,4 +8,5 @@ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface NotificationRequest { + } From 8b56e62ce858b49f885789e4083fc5b1dce24417 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 17 Mar 2024 00:14:32 +0900 Subject: [PATCH 030/314] =?UTF-8?q?chore:=20=EC=84=9C=EB=B8=8C=20=EB=AA=A8?= =?UTF-8?q?=EB=93=88=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/notification/src/main/resources/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/notification/src/main/resources/config b/backend/notification/src/main/resources/config index 9c932cc6c..3ff231abc 160000 --- a/backend/notification/src/main/resources/config +++ b/backend/notification/src/main/resources/config @@ -1 +1 @@ -Subproject commit 9c932cc6c99dd13768e8af801d4fbde4d1f6b9bd +Subproject commit 3ff231abc750e1a81621c998054892d7294e210d From eba1b850345b8883917d4a9cdfcd3ef8238cb495 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 17 Mar 2024 00:22:01 +0900 Subject: [PATCH 031/314] =?UTF-8?q?chore:=20=EC=84=9C=EB=B8=8C=EB=AA=A8?= =?UTF-8?q?=EB=93=88=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/notification/src/main/resources/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/notification/src/main/resources/config b/backend/notification/src/main/resources/config index 3ff231abc..72b28b3c9 160000 --- a/backend/notification/src/main/resources/config +++ b/backend/notification/src/main/resources/config @@ -1 +1 @@ -Subproject commit 3ff231abc750e1a81621c998054892d7294e210d +Subproject commit 72b28b3c98e05dda4b62247a55bdf64ca2d0a726 From e58d2da00a715d7251ea7dcc4d57eab38d708f6e Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 17 Mar 2024 00:57:12 +0900 Subject: [PATCH 032/314] =?UTF-8?q?fix:=20=EC=95=8C=EB=A6=BC=20=EC=A0=84?= =?UTF-8?q?=EC=86=A1=20=EC=83=81=ED=83=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infra/notification/data/mapper/NotificationMapper.java | 7 +++++-- backend/core/src/main/resources/config | 2 +- backend/notification/src/main/resources/config | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java index 78b75cda3..4ceb54292 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java @@ -11,13 +11,16 @@ @RequiredArgsConstructor public class NotificationMapper { + private static final String NOTIFICATION_SEND_SUCCESS = "SUCCESS"; + private static final String NOTIFICATION_SEND_FAILED = "FAILED"; + private final S3UrlGenerator s3UrlGenerator; public CreatedCapsuleSkinNotificationRequest capsuleSkinDtoToMessage(Long memberId, CapsuleSkinCreateDto dto) { return CreatedCapsuleSkinNotificationRequest.builder() .memberId(memberId) - .status("SUCCESS_MAKE_CAPSULE_SKIN") + .status(NOTIFICATION_SEND_SUCCESS) .skinName(dto.skinName()) .title("캡슐 스킨 생성 알림") .text(dto.skinName() + "이 생성되었습니다. ARchive에서 확인해보세요!") @@ -28,7 +31,7 @@ public CreatedCapsuleSkinNotificationRequest capsuleSkinDtoToMessage(Long member public FriendReqNotificationRequest friendReqToMessage(Long friendId, String ownerNickname) { return FriendReqNotificationRequest.builder() .friendId(friendId) - .status("SEND_FRIEND_REQ_MESSAGE") + .status(NOTIFICATION_SEND_FAILED) .title("친구 요청 알림") .text(ownerNickname + "로부터 친구 요청이 왔습니다. ARchive에서 확인해보세요!") .build(); diff --git a/backend/core/src/main/resources/config b/backend/core/src/main/resources/config index aefe5b1fc..e744bce0a 160000 --- a/backend/core/src/main/resources/config +++ b/backend/core/src/main/resources/config @@ -1 +1 @@ -Subproject commit aefe5b1fc708ace034b9310779afba28df20d2e0 +Subproject commit e744bce0aa8a426e1656116d0f56dc4595bc9b59 diff --git a/backend/notification/src/main/resources/config b/backend/notification/src/main/resources/config index 9c932cc6c..72b28b3c9 160000 --- a/backend/notification/src/main/resources/config +++ b/backend/notification/src/main/resources/config @@ -1 +1 @@ -Subproject commit 9c932cc6c99dd13768e8af801d4fbde4d1f6b9bd +Subproject commit 72b28b3c98e05dda4b62247a55bdf64ca2d0a726 From 4a661e3cde08ec68ecd8541b11024e9a26075600 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 17 Mar 2024 01:03:12 +0900 Subject: [PATCH 033/314] =?UTF-8?q?chore:=20=EC=84=9C=EB=B8=8C=EB=AA=A8?= =?UTF-8?q?=EB=93=88=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/core/src/main/resources/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/core/src/main/resources/config b/backend/core/src/main/resources/config index e744bce0a..236c790f5 160000 --- a/backend/core/src/main/resources/config +++ b/backend/core/src/main/resources/config @@ -1 +1 @@ -Subproject commit e744bce0aa8a426e1656116d0f56dc4595bc9b59 +Subproject commit 236c790f5ace1e57ec8f2aa4d35e4a517e4e45b1 From a5932930d927229539158decc66a4992d8ecac9c Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 17 Mar 2024 10:58:22 +0900 Subject: [PATCH 034/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EA=B1=B0=EC=A0=88=20API=20=EB=AC=B8=EC=84=9C?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/api/FriendApi.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java index fdacae0c9..553a6a9c3 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java @@ -74,10 +74,11 @@ ResponseEntity deleteFriend( description = "처리 완료" ) }) - @PostMapping(value = "/deny-request") - ResponseEntity denyFriendRequest( + ResponseEntity> denyFriendRequest( + Long memberId, + @Parameter(in = ParameterIn.QUERY, required = true, schema = @Schema()) - @NotNull @Valid @RequestParam(value = "friend_id") Long friendId + Long friendId ); From cbdb3313da3cc99909f8a59bc2e3ba4f1777fb15 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 17 Mar 2024 10:58:50 +0900 Subject: [PATCH 035/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EA=B1=B0=EC=A0=88=20Controller=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/api/FriendApiController.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java index b8e1796e9..3a3d11761 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java @@ -3,6 +3,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -32,9 +33,16 @@ public ResponseEntity deleteFriend(Long friendId) { return null; } + @DeleteMapping("{friend_id}/deny-request") @Override - public ResponseEntity denyFriendRequest(Long friendId) { - return null; + public ResponseEntity> denyFriendRequest( + @AuthenticationPrincipal Long memberId, + @PathVariable("friend_id") final Long friendId) { + + friendService.denyRequestFriend(memberId, friendId); + + return ResponseEntity.ok(ApiSpec.empty(SuccessCode.SUCCESS)); + } @Override From 89716139b3e5cfce28fc245d8245b62441d30245 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 17 Mar 2024 10:59:35 +0900 Subject: [PATCH 036/314] =?UTF-8?q?refact:=20FriendStatus=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/entity/FriendInvite.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendInvite.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendInvite.java index 528574dbc..83bbb8dc5 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendInvite.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendInvite.java @@ -2,6 +2,8 @@ import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; @@ -28,6 +30,7 @@ public class FriendInvite extends BaseEntity { private Long id; @Column(name = "friend_status") + @Enumerated(EnumType.STRING) private FriendStatus friendStatus; @ManyToOne(fetch = FetchType.LAZY) From 3a392fae96eaef639126dd71d37244d7dce9d0cd Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 17 Mar 2024 11:00:35 +0900 Subject: [PATCH 037/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EC=82=AD=EC=A0=9C=20Service=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/service/FriendService.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java index 2c1f53f7e..b9bca9a3f 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -4,6 +4,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; import site.timecapsulearchive.core.domain.friend.data.mapper.FriendMapper; @@ -16,7 +17,6 @@ import site.timecapsulearchive.core.infra.notification.manager.NotificationManager; @Service - public class FriendService { private final MemberRepository memberRepository; @@ -60,4 +60,9 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { return FriendReqStatusResponse.success(); } + + @Transactional + public void denyRequestFriend(Long memberId, Long friendId) { + friendInviteRepository.deleteFriendInviteByOwnerIdAndFriendId(memberId, friendId); + } } From 8932e59af3e9b80e0c225764523b381baf2f9751 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 17 Mar 2024 11:08:34 +0900 Subject: [PATCH 038/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EB=AA=BE?= =?UTF-8?q?=EC=B0=B8=EC=9D=8C=20=EC=98=88=EC=99=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../friend/exception/FriendNotFoundException.java | 11 +++++++++++ .../core/global/error/ErrorCode.java | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/exception/FriendNotFoundException.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/exception/FriendNotFoundException.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/exception/FriendNotFoundException.java new file mode 100644 index 000000000..0eb24d8d3 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/exception/FriendNotFoundException.java @@ -0,0 +1,11 @@ +package site.timecapsulearchive.core.domain.friend.exception; + +import site.timecapsulearchive.core.global.error.ErrorCode; +import site.timecapsulearchive.core.global.error.exception.BusinessException; + +public class FriendNotFoundException extends BusinessException { + + public FriendNotFoundException() { + super(ErrorCode.FRIEND_NOT_FOUND_ERROR); + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java index 8283d789a..a74bc52d8 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java @@ -48,7 +48,8 @@ public enum ErrorCode { CAPSULE_SKIN_NOT_FOUND_ERROR(404, "SKIN-001", "캡슐 스킨을 찾지 못하였습니다."), //capsule - CAPSULE_NOT_FOUND_ERROR(404, "CAPSULE-001", "캡슐을 찾지 못하였습니다."); + CAPSULE_NOT_FOUND_ERROR(404, "CAPSULE-001", "캡슐을 찾지 못하였습니다."), + FRIEND_NOT_FOUND_ERROR(404, "FRIEND-001", "친구를 찾지 못하였습니다"); private final int status; private final String code; From ce79f17a332e7344a5b9c3808b113169e17f5b3e Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 17 Mar 2024 11:09:18 +0900 Subject: [PATCH 039/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EA=B1=B0=EC=A0=88=20JPA=20=EC=BF=BC=EB=A6=AC=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/friend/repository/FriendInviteRepository.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java index 00508bdc8..c2cd3a9a3 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java @@ -1,10 +1,15 @@ package site.timecapsulearchive.core.domain.friend.repository; +import java.util.Optional; import org.springframework.data.repository.Repository; import site.timecapsulearchive.core.domain.friend.entity.FriendInvite; public interface FriendInviteRepository extends Repository { void save(FriendInvite friendInvite); + + Optional findFriendInviteByOwnerIdAndFriendId(Long memberId, Long friendId); + + void deleteFriendInviteById(Long id); } From c1d477df740d77f4c5dee273dd62b74107b3c639 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 17 Mar 2024 11:10:06 +0900 Subject: [PATCH 040/314] =?UTF-8?q?refact:=20=EC=B9=9C=EA=B5=AC=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20=EA=B1=B0=EC=A0=88=20Service=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 거절 : FriendInvite를 찾고 삭제하는 방식 --- .../core/domain/friend/service/FriendService.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java index b9bca9a3f..efae10bf1 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -10,6 +10,7 @@ import site.timecapsulearchive.core.domain.friend.data.mapper.FriendMapper; import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; import site.timecapsulearchive.core.domain.friend.entity.FriendInvite; +import site.timecapsulearchive.core.domain.friend.exception.FriendNotFoundException; import site.timecapsulearchive.core.domain.friend.repository.FriendInviteRepository; import site.timecapsulearchive.core.domain.member.entity.Member; import site.timecapsulearchive.core.domain.member.exception.MemberNotFoundException; @@ -63,6 +64,10 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { @Transactional public void denyRequestFriend(Long memberId, Long friendId) { - friendInviteRepository.deleteFriendInviteByOwnerIdAndFriendId(memberId, friendId); + final FriendInvite friendInvite = friendInviteRepository + .findFriendInviteByOwnerIdAndFriendId(memberId, friendId).orElseThrow( + FriendNotFoundException::new); + + friendInviteRepository.deleteFriendInviteById(friendInvite.getId()); } } From 1cba78756308b40d2626950388a472cc913d7a06 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 17 Mar 2024 11:28:46 +0900 Subject: [PATCH 041/314] =?UTF-8?q?feat:=20friend=5Finvite=20=EC=A0=9C?= =?UTF-8?q?=EC=95=BD=20=EC=A1=B0=EA=B1=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - owner_id, friend_id가 중복되면 또 친구 요청을 보내지 못하게한다. --- .../resources/db/migration/V17__friend_invite_add_constraint.sql | 1 + 1 file changed, 1 insertion(+) create mode 100644 backend/core/src/main/resources/db/migration/V17__friend_invite_add_constraint.sql diff --git a/backend/core/src/main/resources/db/migration/V17__friend_invite_add_constraint.sql b/backend/core/src/main/resources/db/migration/V17__friend_invite_add_constraint.sql new file mode 100644 index 000000000..2ba909ef6 --- /dev/null +++ b/backend/core/src/main/resources/db/migration/V17__friend_invite_add_constraint.sql @@ -0,0 +1 @@ +ALTER TABLE friend_invite ADD CONSTRAINT unique_owner_friend_pair UNIQUE (owner_id, friend_id); From ede641b2c681e3696935d153f248c406cb963fbc Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sun, 17 Mar 2024 12:29:29 +0900 Subject: [PATCH 042/314] =?UTF-8?q?fix=20:=20insertable,=20updatable=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/entity/FriendInvite.java | 4 ++-- .../core/domain/friend/entity/MemberFriend.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendInvite.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendInvite.java index e3ceb44b2..21c0bf003 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendInvite.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendInvite.java @@ -27,11 +27,11 @@ public class FriendInvite extends BaseEntity { private Long id; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id", nullable = false, insertable = false, updatable = false) + @JoinColumn(name = "member_id", nullable = false) private Member owner; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id", nullable = false, insertable = false, updatable = false) + @JoinColumn(name = "member_id", nullable = false) private Member friend; } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java index 38c951f55..d5f4b417b 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java @@ -27,11 +27,11 @@ public class MemberFriend extends BaseEntity { private Long id; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "owner_id", nullable = false, insertable = false, updatable = false) + @JoinColumn(name = "owner_id", nullable = false) private Member owner; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "friend_id", nullable = false, insertable = false, updatable = false) + @JoinColumn(name = "friend_id", nullable = false) private Member friend; } From 0b52084c70619bdb2df2da10ee4f7c3890df5ead Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sun, 17 Mar 2024 12:39:57 +0900 Subject: [PATCH 043/314] =?UTF-8?q?fix=20:=20=EC=B6=A9=EB=8F=8C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/api/FriendApi.java | 1 + .../domain/friend/api/FriendApiController.java | 14 ++------------ .../friend/repository/MemberFriendRepository.java | 1 + .../core/domain/friend/service/FriendService.java | 8 ++++++-- backend/notification/src/main/resources/config | 2 +- 5 files changed, 11 insertions(+), 15 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java index 75d6f0ba4..4ddcfc704 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java @@ -18,6 +18,7 @@ import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsPageResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; +import site.timecapsulearchive.core.global.common.response.ApiSpec; public interface FriendApi { diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java index 40786ceca..9e4fa7c53 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java @@ -3,17 +3,13 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import site.timecapsulearchive.core.domain.friend.data.reqeust.SearchFriendsRequest; import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import site.timecapsulearchive.core.domain.friend.data.reqeust.SearchFriendsRequest; import site.timecapsulearchive.core.domain.friend.data.response.FriendsPageResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; import site.timecapsulearchive.core.domain.friend.service.FriendService; @@ -32,12 +28,6 @@ public ResponseEntity acceptFriendRequest(Long friendId) { return null; } - /** - * 회원 아이디와 친구 아이디를 받아서 삭제 - * @param memberId - * @param friendId - * @return - */ @DeleteMapping(value = "/{friend_id}") @Override public ResponseEntity> deleteFriend( @@ -64,7 +54,7 @@ public ResponseEntity findFriends(Long friendId, Long size) @PostMapping(value = "/{friend_id}/request") @Override public ResponseEntity> requestFriend( - @AuthenticationPrincipal Long memberId, + @AuthenticationPrincipal final Long memberId, @PathVariable("friend_id") final Long friendId) { return ResponseEntity.accepted() diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepository.java index c1b56feb9..82bb105b6 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepository.java @@ -5,6 +5,7 @@ import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; public interface MemberFriendRepository extends Repository { + Optional findMemberFriendByOwnerIdAndFriendId(Long ownerId, Long friendId); void delete(MemberFriend memberFriend); diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java index 3f579bc0f..7f40c5f15 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -3,11 +3,14 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; import site.timecapsulearchive.core.domain.friend.data.mapper.FriendMapper; import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; import site.timecapsulearchive.core.domain.friend.entity.FriendInvite; +import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; +import site.timecapsulearchive.core.domain.friend.exception.FriendNotFoundException; import site.timecapsulearchive.core.domain.friend.repository.FriendInviteRepository; import site.timecapsulearchive.core.domain.friend.repository.MemberFriendRepository; import site.timecapsulearchive.core.domain.member.entity.Member; @@ -27,12 +30,13 @@ public class FriendService { private final TransactionTemplate transactionTemplate; public FriendService( - MemberRepository memberRepository, + MemberFriendRepository memberFriendRepository, MemberRepository memberRepository, FriendInviteRepository friendInviteRepository, FriendMapper friendMapper, NotificationManager notificationManager, PlatformTransactionManager transactionManager ) { + this.memberFriendRepository = memberFriendRepository; this.memberRepository = memberRepository; this.friendInviteRepository = friendInviteRepository; this.friendMapper = friendMapper; @@ -64,7 +68,7 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { @Transactional public void deleteFriend(final Long memberId, final Long friendId) { - MemberFriend memberFriend = memberFriendRepository.findMemberFriendByOwnerIdAndFriendId( + final MemberFriend memberFriend = memberFriendRepository.findMemberFriendByOwnerIdAndFriendId( memberId, friendId) .orElseThrow(FriendNotFoundException::new); diff --git a/backend/notification/src/main/resources/config b/backend/notification/src/main/resources/config index 72b28b3c9..9c932cc6c 160000 --- a/backend/notification/src/main/resources/config +++ b/backend/notification/src/main/resources/config @@ -1 +1 @@ -Subproject commit 72b28b3c98e05dda4b62247a55bdf64ca2d0a726 +Subproject commit 9c932cc6c99dd13768e8af801d4fbde4d1f6b9bd From 44be7569af908c29c712134ae027763c09a2c983 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Thu, 14 Mar 2024 20:25:35 +0900 Subject: [PATCH 044/314] =?UTF-8?q?feat=20:=20=EC=B9=9C=EA=B5=AC=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20API=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Open #233 --- .../core/domain/friend/api/FriendApi.java | 53 +++++++++++++++--- .../friend/api/FriendApiController.java | 23 +++++++- .../friend/data/dto/FriendSummaryDto.java | 9 +++ .../data/mapper/MemberFriendMapper.java | 25 +++++++++ .../data/response/FriendSummaryResponse.java | 17 ++++++ .../data/response/FriendsPageResponse.java | 20 ------- .../data/response/FriendsSliceResponse.java | 15 +++++ .../MemberFriendQueryRepository.java | 55 +++++++++++++++++++ .../domain/friend/service/FriendService.java | 25 ++++++++- 9 files changed, 209 insertions(+), 33 deletions(-) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/dto/FriendSummaryDto.java create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSummaryResponse.java delete mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendsPageResponse.java create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendsSliceResponse.java create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java index 4ddcfc704..44fb61525 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java @@ -3,22 +3,25 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; +import java.time.ZonedDateTime; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import site.timecapsulearchive.core.domain.friend.data.reqeust.SearchFriendsRequest; +import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; -import site.timecapsulearchive.core.domain.friend.data.response.FriendsPageResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; import site.timecapsulearchive.core.global.common.response.ApiSpec; +import site.timecapsulearchive.core.global.error.ErrorResponse; public interface FriendApi { @@ -36,8 +39,8 @@ public interface FriendApi { }) @PostMapping(value = "/accept-request") ResponseEntity acceptFriendRequest( - @Parameter(in = ParameterIn.QUERY, required = true, schema = @Schema()) - @NotNull @Valid @RequestParam(value = "friend_id") Long friendId + @Parameter(in = ParameterIn.QUERY, required = true) + @RequestParam(value = "friend_id") Long friendId ); @@ -51,6 +54,13 @@ ResponseEntity acceptFriendRequest( @ApiResponse( responseCode = "200", description = "처리 완료" + ), + @ApiResponse( + responseCode = "400", + description = """ + 잘못된 요청 파라미터 또는 존재하지 않는 사용자로 요청하거나 존재하지 않는 친구에게 친구 요청을 보낼 경우 발생 + """, + content = @Content(schema = @Schema(implementation = ErrorResponse.class)) ) }) ResponseEntity> deleteFriend( @@ -79,7 +89,6 @@ ResponseEntity denyFriendRequest( @NotNull @Valid @RequestParam(value = "friend_id") Long friendId ); - @Operation( summary = "소셜 친구 목록 조회", description = "사용자의 소셜 친구 목록을 보여준다.", @@ -95,12 +104,38 @@ ResponseEntity denyFriendRequest( @GetMapping( produces = {"application/json"} ) - ResponseEntity findFriends( - @Parameter(in = ParameterIn.QUERY, description = "마지막 친구 아이디", required = true, schema = @Schema()) - @NotNull @Valid @RequestParam(value = "friend_id") Long friendId, + ResponseEntity> findFriends( + Long memberId, + + @Parameter(in = ParameterIn.QUERY, description = "페이지 크기", required = true) + int size, + + @Parameter(in = ParameterIn.QUERY, description = "마지막 데이터의 시간", required = true) + ZonedDateTime createdAt + ); + + @Operation( + summary = "소셜 친구 요청 목록 조회", + description = "사용자의 소셜 친구 요청 목록을 보여준다.", + security = {@SecurityRequirement(name = "user_token")}, + tags = {"friend"} + ) + @ApiResponses(value = { + @ApiResponse( + responseCode = "200", + description = "ok" + ) + }) + @GetMapping( + value = "/requests", + produces = {"application/json"} + ) + ResponseEntity> findFriendRequests( + @Parameter(in = ParameterIn.QUERY, description = "페이지 크기", required = true) + int size, - @Parameter(in = ParameterIn.QUERY, description = "페이지 크기", schema = @Schema()) - @NotNull @Valid @RequestParam(value = "size", required = false) Long size + @Parameter(in = ParameterIn.QUERY, description = "마지막 데이터의 시간", required = true) + ZonedDateTime createdAt ); diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java index 9e4fa7c53..991d61e1f 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java @@ -1,5 +1,6 @@ package site.timecapsulearchive.core.domain.friend.api; +import java.time.ZonedDateTime; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; @@ -7,10 +8,11 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import site.timecapsulearchive.core.domain.friend.data.reqeust.SearchFriendsRequest; import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; -import site.timecapsulearchive.core.domain.friend.data.response.FriendsPageResponse; +import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; import site.timecapsulearchive.core.domain.friend.service.FriendService; import site.timecapsulearchive.core.global.common.response.ApiSpec; @@ -42,12 +44,27 @@ public ResponseEntity> deleteFriend( } @Override - public ResponseEntity denyFriendRequest(Long friendId) { + public ResponseEntity> findFriends( + @AuthenticationPrincipal final Long memberId, + @RequestParam(defaultValue = "20", value = "size") final int size, + @RequestParam(value = "createdAt") final ZonedDateTime createdAt + ) { + return ResponseEntity.ok( + ApiSpec.success( + SuccessCode.SUCCESS, + friendService.findFriendsSlice(memberId, size, createdAt) + ) + ); + } + + @Override + public ResponseEntity> findFriendRequests(int size, + ZonedDateTime createdAt) { return null; } @Override - public ResponseEntity findFriends(Long friendId, Long size) { + public ResponseEntity denyFriendRequest(Long friendId) { return null; } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/dto/FriendSummaryDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/dto/FriendSummaryDto.java new file mode 100644 index 000000000..4a535e335 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/dto/FriendSummaryDto.java @@ -0,0 +1,9 @@ +package site.timecapsulearchive.core.domain.friend.data.dto; + +public record FriendSummaryDto( + Long id, + String profileUrl, + String nickname +) { + +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java new file mode 100644 index 000000000..eddf438e0 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java @@ -0,0 +1,25 @@ +package site.timecapsulearchive.core.domain.friend.data.mapper; + +import java.util.List; +import org.springframework.data.domain.Slice; +import org.springframework.stereotype.Component; +import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; +import site.timecapsulearchive.core.domain.friend.data.response.FriendSummaryResponse; +import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; + +@Component +public class MemberFriendMapper { + + public FriendsSliceResponse friendsSliceToResponse(Slice slice) { + List friends = slice.getContent() + .stream() + .map(this::friendsSummaryDtoToResponse) + .toList(); + + return new FriendsSliceResponse(friends, slice.hasNext()); + } + + private FriendSummaryResponse friendsSummaryDtoToResponse(FriendSummaryDto dto) { + return new FriendSummaryResponse(dto.id(), dto.profileUrl(), dto.nickname()); + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSummaryResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSummaryResponse.java new file mode 100644 index 000000000..b7e59b445 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSummaryResponse.java @@ -0,0 +1,17 @@ +package site.timecapsulearchive.core.domain.friend.data.response; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "친구 요약 정보") +public record FriendSummaryResponse( + @Schema(description = "친구 아이디") + Long id, + + @Schema(description = "친구 프로필") + String profileUrl, + + @Schema(description = "친구 닉네임") + String nickname +) { + +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendsPageResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendsPageResponse.java deleted file mode 100644 index ac88fbbd3..000000000 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendsPageResponse.java +++ /dev/null @@ -1,20 +0,0 @@ -package site.timecapsulearchive.core.domain.friend.data.response; - -import io.swagger.v3.oas.annotations.media.Schema; -import java.util.List; -import site.timecapsulearchive.core.domain.member.data.response.MemberSummaryResponse; - -@Schema(description = "친구 리스트 페이징") -public record FriendsPageResponse( - - @Schema(description = "회원 요약 정보 리스트") - List friends, - - @Schema(description = "다음 페이지 유무") - Boolean hasNext, - - @Schema(description = "이전 페이지유무") - Boolean hasPrevious -) { - -} \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendsSliceResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendsSliceResponse.java new file mode 100644 index 000000000..4de96c945 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendsSliceResponse.java @@ -0,0 +1,15 @@ +package site.timecapsulearchive.core.domain.friend.data.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; + +@Schema(description = "친구 리스트") +public record FriendsSliceResponse( + @Schema(description = "친구 요약 정보 리스트") + List friends, + + @Schema(description = "다음 페이지 유무") + Boolean hasNext +) { + +} \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java new file mode 100644 index 000000000..16cf8ae2f --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java @@ -0,0 +1,55 @@ +package site.timecapsulearchive.core.domain.friend.repository; + +import static site.timecapsulearchive.core.domain.friend.entity.QMemberFriend.memberFriend; +import static site.timecapsulearchive.core.domain.member.entity.QMember.member; + +import com.querydsl.core.types.Projections; +import com.querydsl.jpa.impl.JPAQueryFactory; +import java.time.ZonedDateTime; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.data.domain.SliceImpl; +import org.springframework.stereotype.Repository; +import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; + +@Repository +@RequiredArgsConstructor +public class MemberFriendQueryRepository { + + private final JPAQueryFactory jpaQueryFactory; + + public Slice findFriendsSlice( + final Long memberId, + final int size, + final ZonedDateTime createdAt + ) { + List friends = jpaQueryFactory + .select( + Projections.constructor( + FriendSummaryDto.class, + memberFriend.friend.id, + memberFriend.friend.profileUrl, + memberFriend.friend.nickname + ) + ) + .from(memberFriend) + .leftJoin(member).on(memberFriend.friend.id.eq(member.id)) + .leftJoin(member).on(memberFriend.owner.id.eq(member.id)) + .where(memberFriend.owner.id.eq(memberId).and(memberFriend.createdAt.lt(createdAt))) + .limit(size + 1) + .fetch(); + + final boolean hasNext = canMoreRead(size, friends.size()); + if (hasNext) { + friends.remove(size); + } + + return new SliceImpl<>(friends, Pageable.ofSize(size), hasNext); + } + + private boolean canMoreRead(final int size, final int capsuleSize) { + return capsuleSize > size; + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java index 7f40c5f15..a64b5f90c 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -1,17 +1,23 @@ package site.timecapsulearchive.core.domain.friend.service; +import java.time.ZonedDateTime; +import org.springframework.data.domain.Slice; import org.springframework.stereotype.Service; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; +import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; import site.timecapsulearchive.core.domain.friend.data.mapper.FriendMapper; +import site.timecapsulearchive.core.domain.friend.data.mapper.MemberFriendMapper; import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; +import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; import site.timecapsulearchive.core.domain.friend.entity.FriendInvite; import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; import site.timecapsulearchive.core.domain.friend.exception.FriendNotFoundException; import site.timecapsulearchive.core.domain.friend.repository.FriendInviteRepository; +import site.timecapsulearchive.core.domain.friend.repository.MemberFriendQueryRepository; import site.timecapsulearchive.core.domain.friend.repository.MemberFriendRepository; import site.timecapsulearchive.core.domain.member.entity.Member; import site.timecapsulearchive.core.domain.member.exception.MemberNotFoundException; @@ -23,6 +29,8 @@ public class FriendService { private final MemberFriendRepository memberFriendRepository; + private final MemberFriendQueryRepository memberFriendQueryRepository; + private final MemberFriendMapper memberFriendMapper; private final MemberRepository memberRepository; private final FriendInviteRepository friendInviteRepository; private final FriendMapper friendMapper; @@ -30,13 +38,17 @@ public class FriendService { private final TransactionTemplate transactionTemplate; public FriendService( - MemberFriendRepository memberFriendRepository, MemberRepository memberRepository, + MemberFriendRepository memberFriendRepository, + MemberFriendQueryRepository memberFriendQueryRepository, + MemberFriendMapper memberFriendMapper, MemberRepository memberRepository, FriendInviteRepository friendInviteRepository, FriendMapper friendMapper, NotificationManager notificationManager, PlatformTransactionManager transactionManager ) { this.memberFriendRepository = memberFriendRepository; + this.memberFriendQueryRepository = memberFriendQueryRepository; + this.memberFriendMapper = memberFriendMapper; this.memberRepository = memberRepository; this.friendInviteRepository = friendInviteRepository; this.friendMapper = friendMapper; @@ -74,4 +86,15 @@ public void deleteFriend(final Long memberId, final Long friendId) { memberFriendRepository.delete(memberFriend); } + + public FriendsSliceResponse findFriendsSlice( + final Long memberId, + final int size, + final ZonedDateTime createdAt + ) { + Slice friends = memberFriendQueryRepository.findFriendsSlice(memberId, + size, createdAt); + + return memberFriendMapper.friendsSliceToResponse(friends); + } } From 0ae3419067d4f6e2a8116c0f4459fb854a49efff Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 16 Mar 2024 10:41:39 +0900 Subject: [PATCH 045/314] =?UTF-8?q?fix=20:=20GetMapping=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/api/FriendApiController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java index 991d61e1f..c5896b9bc 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java @@ -5,6 +5,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -43,6 +44,7 @@ public ResponseEntity> deleteFriend( ); } + @GetMapping @Override public ResponseEntity> findFriends( @AuthenticationPrincipal final Long memberId, From 56c7b1d01a671227e9ac4f26563d7db8889d56e6 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 16 Mar 2024 10:41:54 +0900 Subject: [PATCH 046/314] =?UTF-8?q?fix=20:=20=EC=BF=BC=EB=A6=AC=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=8F=20=ED=95=A8=EC=88=98=20=ED=8C=8C?= =?UTF-8?q?=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EC=9D=B4=EB=A6=84=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../friend/repository/MemberFriendQueryRepository.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java index 16cf8ae2f..70cfbc5c6 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java @@ -35,8 +35,8 @@ public Slice findFriendsSlice( ) ) .from(memberFriend) - .leftJoin(member).on(memberFriend.friend.id.eq(member.id)) - .leftJoin(member).on(memberFriend.owner.id.eq(member.id)) + .innerJoin(member).on(memberFriend.owner.id.eq(member.id)) + .innerJoin(member).on(memberFriend.friend.id.eq(member.id)) .where(memberFriend.owner.id.eq(memberId).and(memberFriend.createdAt.lt(createdAt))) .limit(size + 1) .fetch(); @@ -49,7 +49,7 @@ public Slice findFriendsSlice( return new SliceImpl<>(friends, Pageable.ofSize(size), hasNext); } - private boolean canMoreRead(final int size, final int capsuleSize) { - return capsuleSize > size; + private boolean canMoreRead(final int size, final int data) { + return data > size; } } From 4cb6c92a75414edf50350b23359dfee21142844a Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 16 Mar 2024 10:42:49 +0900 Subject: [PATCH 047/314] =?UTF-8?q?test=20:=20Repository=20Test=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/core/build.gradle | 8 +- .../src/main/resources/test/data/insert.sql | 45 ++++++++ .../src/main/resources/test/data/truncate.sql | 8 ++ .../core/common/DatabaseContainer.java | 39 +++++++ .../core/common/RepositoryTest.java | 56 ++++++++++ .../MemberFriendQueryRepositoryTest.java | 104 ++++++++++++++++++ 6 files changed, 258 insertions(+), 2 deletions(-) create mode 100644 backend/core/src/main/resources/test/data/insert.sql create mode 100644 backend/core/src/main/resources/test/data/truncate.sql create mode 100644 backend/core/src/test/java/site/timecapsulearchive/core/common/DatabaseContainer.java create mode 100644 backend/core/src/test/java/site/timecapsulearchive/core/common/RepositoryTest.java create mode 100644 backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java diff --git a/backend/core/build.gradle b/backend/core/build.gradle index 3d7540abf..7520ee105 100644 --- a/backend/core/build.gradle +++ b/backend/core/build.gradle @@ -41,8 +41,8 @@ dependencies { implementation 'org.apache.httpcomponents.client5:httpclient5:5.3' //flyway - implementation 'org.flywaydb:flyway-core:9.5.1' - implementation 'org.flywaydb:flyway-mysql:9.5.1' + implementation 'org.flywaydb:flyway-core:9.5.0' + implementation 'org.flywaydb:flyway-mysql:9.5.0' //s3 implementation 'software.amazon.awssdk:s3:2.21.46' @@ -81,6 +81,10 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' testImplementation 'org.springframework.amqp:spring-rabbit-test' + testImplementation 'org.flywaydb.flyway-test-extensions:flyway-spring-test:9.5.0' + testImplementation 'org.testcontainers:testcontainers:1.19.1' + testImplementation 'org.testcontainers:junit-jupiter:1.19.1' + testImplementation 'org.testcontainers:mysql:1.19.1' } tasks.named('test') { diff --git a/backend/core/src/main/resources/test/data/insert.sql b/backend/core/src/main/resources/test/data/insert.sql new file mode 100644 index 000000000..7057e9898 --- /dev/null +++ b/backend/core/src/main/resources/test/data/insert.sql @@ -0,0 +1,45 @@ +--friend & owner +insert into member(nickname, is_verified, notification_enabled, social_type, email, profile_url, auth_id, created_at, updated_at) +values (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '12341', now(), now()), + (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '12342', now(), now()), + (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '12343', now(), now()), + (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '12344', now(), now()), + (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '12345', now(), now()), + (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '12346', now(), now()), + (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '12347', now(), now()), + (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '12348', now(), now()), + (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '12349', now(), now()), + (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123410', now(), now()), + (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123411', now(), now()), + (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123412', now(), now()), + (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123413', now(), now()), + (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123414', now(), now()), + (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123415', now(), now()), + (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123416', now(), now()), + (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123417', now(), now()), + (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123418', now(), now()), + (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123419', now(), now()), + (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123420', now(), now()), + (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '1234121', now(), now()); + +insert into member_friend(owner_id, friend_id, created_at, updated_at) +values (21, 1, now(), now()), + (21, 2, now(), now()), + (21, 3, now(), now()), + (21, 4, now(), now()), + (21, 5, now(), now()), + (21, 6, now(), now()), + (21, 7, now(), now()), + (21, 8, now(), now()), + (21, 9, now(), now()), + (21, 10, now(), now()), + (21, 11, now(), now()), + (21, 12, now(), now()), + (21, 13, now(), now()), + (21, 14, now(), now()), + (21, 15, now(), now()), + (21, 16, now(), now()), + (21, 17, now(), now()), + (21, 18, now(), now()), + (21, 19, now(), now()), + (21, 20, now(), now()); \ No newline at end of file diff --git a/backend/core/src/main/resources/test/data/truncate.sql b/backend/core/src/main/resources/test/data/truncate.sql new file mode 100644 index 000000000..f9ba3770d --- /dev/null +++ b/backend/core/src/main/resources/test/data/truncate.sql @@ -0,0 +1,8 @@ +-- 외래 키 제약 조건 해제 +SET FOREIGN_KEY_CHECKS = 0; + +TRUNCATE TABLE member_friend; +TRUNCATE TABLE member; + +-- 외래 키 제약 조건 활성화 +SET FOREIGN_KEY_CHECKS = 1; \ No newline at end of file diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/common/DatabaseContainer.java b/backend/core/src/test/java/site/timecapsulearchive/core/common/DatabaseContainer.java new file mode 100644 index 000000000..d6af4fd4a --- /dev/null +++ b/backend/core/src/test/java/site/timecapsulearchive/core/common/DatabaseContainer.java @@ -0,0 +1,39 @@ +package site.timecapsulearchive.core.common; + +import com.github.dockerjava.api.command.CreateContainerCmd; +import com.github.dockerjava.api.model.ExposedPort; +import com.github.dockerjava.api.model.HostConfig; +import com.github.dockerjava.api.model.PortBinding; +import com.github.dockerjava.api.model.Ports; +import java.util.function.Consumer; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.MySQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +@Testcontainers +public abstract class DatabaseContainer { + + @Container + protected static final MySQLContainer mysqlContainer = + new MySQLContainer<>(DockerImageName.parse("mysql:8.0.35")) + .withCreateContainerCmdModifier(bingPort()) + .withDatabaseName("test-database") + .withUsername("test-user") + .withPassword("test-password"); + + private static Consumer bingPort() { + return cmd -> cmd.withHostConfig(new HostConfig().withPortBindings( + new PortBinding(Ports.Binding.bindPort(36915), new ExposedPort(3306)) + )); + } + + @DynamicPropertySource + static void registerPgProperties(DynamicPropertyRegistry registry) { + registry.add("spring.datasource.url", mysqlContainer::getJdbcUrl); + registry.add("spring.datasource.username", mysqlContainer::getUsername); + registry.add("spring.datasource.password", mysqlContainer::getPassword); + } +} diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/common/RepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/common/RepositoryTest.java new file mode 100644 index 000000000..f15b30142 --- /dev/null +++ b/backend/core/src/test/java/site/timecapsulearchive/core/common/RepositoryTest.java @@ -0,0 +1,56 @@ +package site.timecapsulearchive.core.common; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import org.flywaydb.test.annotation.FlywayTest; +import org.flywaydb.test.junit5.annotation.FlywayTestExtension; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; +import org.springframework.core.io.ClassPathResource; +import org.springframework.jdbc.datasource.init.ScriptUtils; +import org.springframework.test.context.ActiveProfiles; +import site.timecapsulearchive.core.global.config.JpaAuditingConfig; + +@Import(JpaAuditingConfig.class) +@DataJpaTest +@FlywayTestExtension +@ActiveProfiles("test") +@AutoConfigureTestDatabase(replace = Replace.NONE) +public abstract class RepositoryTest extends DatabaseContainer { + + private static final Logger logger = LoggerFactory.getLogger("RepositoryTest"); + + @FlywayTest + @BeforeAll + static void setupAll() { + runScript("test/data/insert.sql"); + } + + private static void runScript(String path) { + String url = mysqlContainer.getJdbcUrl(); + String username = mysqlContainer.getUsername(); + String password = mysqlContainer.getPassword(); + + try (Connection conn = DriverManager.getConnection(url, username, password)) { + ScriptUtils.executeSqlScript(conn, new ClassPathResource(path)); + } catch (SQLException e) { + logger.error("sql init error"); + throw new RuntimeException(e); + } + + logger.info("[SQL INIT] successfully init"); + } + + @AfterAll + static void cleanupAll() { + runScript("test/data/truncate.sql"); + logger.info("[SQL TRUNCATE] successfully truncate"); + } +} diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java new file mode 100644 index 000000000..9081323f2 --- /dev/null +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java @@ -0,0 +1,104 @@ +package site.timecapsulearchive.core.domain.friend.repository; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import jakarta.persistence.EntityManager; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.data.domain.Slice; +import org.springframework.test.context.TestConstructor; +import org.springframework.test.context.TestConstructor.AutowireMode; +import site.timecapsulearchive.core.common.RepositoryTest; +import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; + +@TestConstructor(autowireMode = AutowireMode.ALL) +class MemberFriendQueryRepositoryTest extends RepositoryTest { + + private final MemberFriendQueryRepository memberFriendQueryRepository; + + MemberFriendQueryRepositoryTest(EntityManager entityManager) { + this.memberFriendQueryRepository = new MemberFriendQueryRepository( + new JPAQueryFactory(entityManager)); + } + + @DisplayName("사용자의_친구_목록_조회_테스트") + @Test + void findFriendsSlice() { + //given + Long memberId = 21L; + int size = 20; + ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(5); + + //when + Slice slice = memberFriendQueryRepository.findFriendsSlice( + memberId, + size, + now + ); + + //then + assertThat(slice.getContent().size()).isEqualTo(size); + } + + @DisplayName("사용자의_친구_목록_조회_테스트") + @ParameterizedTest + @ValueSource(ints = {20, 15, 10, 5}) + void findFriendsSliceWithDifferentSize(int size) { + //given + Long memberId = 21L; + ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(5); + + //when + Slice slice = memberFriendQueryRepository.findFriendsSlice( + memberId, + size, + now + ); + + //then + assertThat(slice.getContent().size()).isEqualTo(size); + } + + @DisplayName("유효하지_않은_시간으로_사용자의_친구_목록_조회_테스트") + @Test + void findFriendsSliceWithNotValidDate() { + //given + Long memberId = 21L; + int size = 20; + ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(5); + + //when + Slice slice = memberFriendQueryRepository.findFriendsSlice( + memberId, + size, + now + ); + + //then + assertThat(slice.getContent().size()).isEqualTo(0); + } + + @DisplayName("친구가_없는_사용자의_친구_목록_조회_테스트") + @Test + void findFriendsSliceWithNotMemberId() { + //given + Long memberId = 20L; + int size = 20; + ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(5); + + //when + Slice slice = memberFriendQueryRepository.findFriendsSlice( + memberId, + size, + now + ); + + //then + assertThat(slice.getContent().size()).isEqualTo(0); + } +} \ No newline at end of file From 22418aa1150de6c51c449d168c996b5b62f35475 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 16 Mar 2024 12:02:04 +0900 Subject: [PATCH 048/314] =?UTF-8?q?fix=20:=20response=EC=97=90=20=EC=88=98?= =?UTF-8?q?=EB=9D=BD=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/data/dto/FriendSummaryDto.java | 5 ++++- .../core/domain/friend/data/mapper/MemberFriendMapper.java | 2 +- .../domain/friend/data/response/FriendSummaryResponse.java | 6 +++++- .../friend/repository/MemberFriendQueryRepository.java | 3 ++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/dto/FriendSummaryDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/dto/FriendSummaryDto.java index 4a535e335..dadab1917 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/dto/FriendSummaryDto.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/dto/FriendSummaryDto.java @@ -1,9 +1,12 @@ package site.timecapsulearchive.core.domain.friend.data.dto; +import java.time.ZonedDateTime; + public record FriendSummaryDto( Long id, String profileUrl, - String nickname + String nickname, + ZonedDateTime createdAt ) { } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java index eddf438e0..1f4dccd8e 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java @@ -20,6 +20,6 @@ public FriendsSliceResponse friendsSliceToResponse(Slice slice } private FriendSummaryResponse friendsSummaryDtoToResponse(FriendSummaryDto dto) { - return new FriendSummaryResponse(dto.id(), dto.profileUrl(), dto.nickname()); + return new FriendSummaryResponse(dto.id(), dto.profileUrl(), dto.nickname(), dto.createdAt()); } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSummaryResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSummaryResponse.java index b7e59b445..c6fe7d9bf 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSummaryResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSummaryResponse.java @@ -1,6 +1,7 @@ package site.timecapsulearchive.core.domain.friend.data.response; import io.swagger.v3.oas.annotations.media.Schema; +import java.time.ZonedDateTime; @Schema(description = "친구 요약 정보") public record FriendSummaryResponse( @@ -11,7 +12,10 @@ public record FriendSummaryResponse( String profileUrl, @Schema(description = "친구 닉네임") - String nickname + String nickname, + + @Schema(description = "친구 수락일") + ZonedDateTime createdAt ) { } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java index 70cfbc5c6..017689c82 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java @@ -31,7 +31,8 @@ public Slice findFriendsSlice( FriendSummaryDto.class, memberFriend.friend.id, memberFriend.friend.profileUrl, - memberFriend.friend.nickname + memberFriend.friend.nickname, + memberFriend.createdAt ) ) .from(memberFriend) From b77b8c9b44931135bc50373c44df747765e87d15 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 16 Mar 2024 12:30:03 +0900 Subject: [PATCH 049/314] =?UTF-8?q?feat=20:=20=EC=B9=9C=EA=B5=AC=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/api/FriendApi.java | 13 +--- .../friend/api/FriendApiController.java | 19 ++++- .../data/mapper/MemberFriendMapper.java | 12 +++ .../response/FriendRequestsSliceResponse.java | 15 ++++ .../MemberFriendQueryRepository.java | 31 ++++++++ .../domain/friend/service/FriendService.java | 12 +++ .../migration/V17__friend_invite_update.sql | 7 ++ .../src/main/resources/test/data/insert.sql | 22 ++++++ .../MemberFriendQueryRepositoryTest.java | 76 +++++++++++++++++++ 9 files changed, 195 insertions(+), 12 deletions(-) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendRequestsSliceResponse.java create mode 100644 backend/core/src/main/resources/db/migration/V17__friend_invite_update.sql diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java index 44fb61525..0b3ccee1e 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java @@ -12,11 +12,11 @@ import jakarta.validation.constraints.NotNull; import java.time.ZonedDateTime; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import site.timecapsulearchive.core.domain.friend.data.reqeust.SearchFriendsRequest; +import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; @@ -101,9 +101,6 @@ ResponseEntity denyFriendRequest( description = "ok" ) }) - @GetMapping( - produces = {"application/json"} - ) ResponseEntity> findFriends( Long memberId, @@ -126,11 +123,9 @@ ResponseEntity> findFriends( description = "ok" ) }) - @GetMapping( - value = "/requests", - produces = {"application/json"} - ) - ResponseEntity> findFriendRequests( + ResponseEntity> findFriendRequests( + Long memberId, + @Parameter(in = ParameterIn.QUERY, description = "페이지 크기", required = true) int size, diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java index c5896b9bc..5ea6bbdd4 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java @@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.RestController; import site.timecapsulearchive.core.domain.friend.data.reqeust.SearchFriendsRequest; import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; +import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; import site.timecapsulearchive.core.domain.friend.service.FriendService; @@ -59,10 +60,22 @@ public ResponseEntity> findFriends( ); } + @GetMapping( + value = "/requests", + produces = {"application/json"} + ) @Override - public ResponseEntity> findFriendRequests(int size, - ZonedDateTime createdAt) { - return null; + public ResponseEntity> findFriendRequests( + @AuthenticationPrincipal final Long memberId, + @RequestParam(defaultValue = "20", value = "size") final int size, + @RequestParam(value = "createdAt") final ZonedDateTime createdAt + ) { + return ResponseEntity.ok( + ApiSpec.success( + SuccessCode.SUCCESS, + friendService.findFriendRequestsSlice(memberId, size, createdAt) + ) + ); } @Override diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java index 1f4dccd8e..1fffb43d1 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java @@ -4,6 +4,7 @@ import org.springframework.data.domain.Slice; import org.springframework.stereotype.Component; import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; +import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendSummaryResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; @@ -22,4 +23,15 @@ public FriendsSliceResponse friendsSliceToResponse(Slice slice private FriendSummaryResponse friendsSummaryDtoToResponse(FriendSummaryDto dto) { return new FriendSummaryResponse(dto.id(), dto.profileUrl(), dto.nickname(), dto.createdAt()); } + + public FriendRequestsSliceResponse friendRequestsSliceToResponse( + List content, + boolean hasNext + ) { + List friendRequests = content.stream() + .map(this::friendsSummaryDtoToResponse) + .toList(); + + return new FriendRequestsSliceResponse(friendRequests, hasNext); + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendRequestsSliceResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendRequestsSliceResponse.java new file mode 100644 index 000000000..77368c782 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendRequestsSliceResponse.java @@ -0,0 +1,15 @@ +package site.timecapsulearchive.core.domain.friend.data.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; + +@Schema(description = "친구 요청 리스트") +public record FriendRequestsSliceResponse( + @Schema(description = "친구 요약 정보 리스트") + List friends, + + @Schema(description = "다음 페이지 유무") + Boolean hasNext +) { + +} \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java index 017689c82..d076ea081 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java @@ -1,5 +1,6 @@ package site.timecapsulearchive.core.domain.friend.repository; +import static site.timecapsulearchive.core.domain.friend.entity.QFriendInvite.friendInvite; import static site.timecapsulearchive.core.domain.friend.entity.QMemberFriend.memberFriend; import static site.timecapsulearchive.core.domain.member.entity.QMember.member; @@ -53,4 +54,34 @@ public Slice findFriendsSlice( private boolean canMoreRead(final int size, final int data) { return data > size; } + + public Slice findFriendRequestsSlice( + final Long memberId, + final int size, + final ZonedDateTime createdAt + ) { + List friends = jpaQueryFactory + .select( + Projections.constructor( + FriendSummaryDto.class, + friendInvite.friend.id, + friendInvite.friend.profileUrl, + friendInvite.friend.nickname, + friendInvite.createdAt + ) + ) + .from(friendInvite) + .innerJoin(member).on(friendInvite.owner.id.eq(member.id)) + .innerJoin(member).on(friendInvite.friend.id.eq(member.id)) + .where(friendInvite.owner.id.eq(memberId).and(friendInvite.createdAt.lt(createdAt))) + .limit(size + 1) + .fetch(); + + final boolean hasNext = canMoreRead(size, friends.size()); + if (hasNext) { + friends.remove(size); + } + + return new SliceImpl<>(friends, Pageable.ofSize(size), hasNext); + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java index a64b5f90c..109afa894 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -11,6 +11,7 @@ import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; import site.timecapsulearchive.core.domain.friend.data.mapper.FriendMapper; import site.timecapsulearchive.core.domain.friend.data.mapper.MemberFriendMapper; +import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; import site.timecapsulearchive.core.domain.friend.entity.FriendInvite; @@ -97,4 +98,15 @@ public FriendsSliceResponse findFriendsSlice( return memberFriendMapper.friendsSliceToResponse(friends); } + + public FriendRequestsSliceResponse findFriendRequestsSlice( + final Long memberId, + final int size, + final ZonedDateTime createdAt + ) { + Slice friendRequests = memberFriendQueryRepository.findFriendRequestsSlice( + memberId, size, createdAt); + + return memberFriendMapper.friendRequestsSliceToResponse(friendRequests.getContent(), friendRequests.hasNext()); + } } diff --git a/backend/core/src/main/resources/db/migration/V17__friend_invite_update.sql b/backend/core/src/main/resources/db/migration/V17__friend_invite_update.sql new file mode 100644 index 000000000..66db8bce7 --- /dev/null +++ b/backend/core/src/main/resources/db/migration/V17__friend_invite_update.sql @@ -0,0 +1,7 @@ +# 친구 대상 아이디 추가 +ALTER TABLE friend_invite + ADD COLUMN friend_id bigint, + ADD FOREIGN KEY fk_member_friend_member(member_id) REFERENCES member(member_id); + +ALTER TABLE friend_invite + CHANGE member_id owner_id BIGINT \ No newline at end of file diff --git a/backend/core/src/main/resources/test/data/insert.sql b/backend/core/src/main/resources/test/data/insert.sql index 7057e9898..b065395a4 100644 --- a/backend/core/src/main/resources/test/data/insert.sql +++ b/backend/core/src/main/resources/test/data/insert.sql @@ -23,6 +23,28 @@ values (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '12341', now(), (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '1234121', now(), now()); insert into member_friend(owner_id, friend_id, created_at, updated_at) +values (21, 1, now(), now()), + (21, 2, now(), now()), + (21, 3, now(), now()), + (21, 4, now(), now()), + (21, 5, now(), now()), + (21, 6, now(), now()), + (21, 7, now(), now()), + (21, 8, now(), now()), + (21, 9, now(), now()), + (21, 10, now(), now()), + (21, 11, now(), now()), + (21, 12, now(), now()), + (21, 13, now(), now()), + (21, 14, now(), now()), + (21, 15, now(), now()), + (21, 16, now(), now()), + (21, 17, now(), now()), + (21, 18, now(), now()), + (21, 19, now(), now()), + (21, 20, now(), now()); + +insert into friend_invite(owner_id, friend_id, created_at, updated_at) values (21, 1, now(), now()), (21, 2, now(), now()), (21, 3, now(), now()), diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java index 9081323f2..4206a2c12 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java @@ -101,4 +101,80 @@ void findFriendsSliceWithNotMemberId() { //then assertThat(slice.getContent().size()).isEqualTo(0); } + + @DisplayName("사용자의_친구_요청_목록_조회_테스트") + @Test + void findFriendRequestsSlice() { + //given + Long memberId = 21L; + int size = 20; + ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(5); + + //when + Slice slice = memberFriendQueryRepository.findFriendRequestsSlice( + memberId, + size, + now + ); + + //then + assertThat(slice.getContent().size()).isEqualTo(size); + } + + @DisplayName("사용자의_친구_요청_목록_조회_테스트") + @ParameterizedTest + @ValueSource(ints = {20, 15, 10, 5}) + void findFriendRequestsSliceWithDifferentSize(int size) { + //given + Long memberId = 21L; + ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(5); + + //when + Slice slice = memberFriendQueryRepository.findFriendRequestsSlice( + memberId, + size, + now + ); + + //then + assertThat(slice.getContent().size()).isEqualTo(size); + } + + @DisplayName("유효하지_않은_시간으로_사용자의_친구_요청_목록_조회_테스트") + @Test + void findFriendRequestsSliceWithNotValidDate() { + //given + Long memberId = 21L; + int size = 20; + ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(5); + + //when + Slice slice = memberFriendQueryRepository.findFriendRequestsSlice( + memberId, + size, + now + ); + + //then + assertThat(slice.getContent().size()).isEqualTo(0); + } + + @DisplayName("친구가_없는_사용자의_친구_요청_목록_조회_테스트") + @Test + void findFriendRequestsSliceWithNotMemberId() { + //given + Long memberId = 20L; + int size = 20; + ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(5); + + //when + Slice slice = memberFriendQueryRepository.findFriendRequestsSlice( + memberId, + size, + now + ); + + //then + assertThat(slice.getContent().size()).isEqualTo(0); + } } \ No newline at end of file From c2a204f49de86c87f1df7be2dd10a5f4dd6c1c55 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sun, 17 Mar 2024 14:23:10 +0900 Subject: [PATCH 050/314] =?UTF-8?q?fix=20:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - sql 파일로 초기화하는 대신 EntityManager 이용 --- .../domain/friend/entity/MemberFriend.java | 6 ++ .../migration/V16__member_friend_update.sql | 7 -- .../migration/V17__friend_invite_update.sql | 7 -- .../migration/V17__member_friend_update.sql | 11 +++ .../src/main/resources/test/data/insert.sql | 67 --------------- .../src/main/resources/test/data/truncate.sql | 8 -- .../core/common/RepositoryTest.java | 38 +-------- .../MemberFriendQueryRepositoryTest.java | 82 +++++++++---------- 8 files changed, 59 insertions(+), 167 deletions(-) delete mode 100644 backend/core/src/main/resources/db/migration/V16__member_friend_update.sql delete mode 100644 backend/core/src/main/resources/db/migration/V17__friend_invite_update.sql create mode 100644 backend/core/src/main/resources/db/migration/V17__member_friend_update.sql delete mode 100644 backend/core/src/main/resources/test/data/insert.sql delete mode 100644 backend/core/src/main/resources/test/data/truncate.sql diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java index d5f4b417b..e089effda 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java @@ -10,6 +10,7 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import site.timecapsulearchive.core.domain.member.entity.Member; @@ -34,4 +35,9 @@ public class MemberFriend extends BaseEntity { @JoinColumn(name = "friend_id", nullable = false) private Member friend; + @Builder + private MemberFriend(Member owner, Member friend) { + this.owner = owner; + this.friend = friend; + } } diff --git a/backend/core/src/main/resources/db/migration/V16__member_friend_update.sql b/backend/core/src/main/resources/db/migration/V16__member_friend_update.sql deleted file mode 100644 index 2e445a0c0..000000000 --- a/backend/core/src/main/resources/db/migration/V16__member_friend_update.sql +++ /dev/null @@ -1,7 +0,0 @@ -# 친구 대상 아이디 추가 -ALTER TABLE member_friend - ADD COLUMN friend_id bigint, - ADD FOREIGN KEY fk_member_friend_member(member_id) REFERENCES member(member_id); - -ALTER TABLE member_friend - CHANGE member_id owner_id BIGINT \ No newline at end of file diff --git a/backend/core/src/main/resources/db/migration/V17__friend_invite_update.sql b/backend/core/src/main/resources/db/migration/V17__friend_invite_update.sql deleted file mode 100644 index 66db8bce7..000000000 --- a/backend/core/src/main/resources/db/migration/V17__friend_invite_update.sql +++ /dev/null @@ -1,7 +0,0 @@ -# 친구 대상 아이디 추가 -ALTER TABLE friend_invite - ADD COLUMN friend_id bigint, - ADD FOREIGN KEY fk_member_friend_member(member_id) REFERENCES member(member_id); - -ALTER TABLE friend_invite - CHANGE member_id owner_id BIGINT \ No newline at end of file diff --git a/backend/core/src/main/resources/db/migration/V17__member_friend_update.sql b/backend/core/src/main/resources/db/migration/V17__member_friend_update.sql new file mode 100644 index 000000000..8f3f226f8 --- /dev/null +++ b/backend/core/src/main/resources/db/migration/V17__member_friend_update.sql @@ -0,0 +1,11 @@ +ALTER TABLE member_friend DROP CONSTRAINT fk_member_friend_member_id; +ALTER TABLE member_friend DROP COLUMN member_id; + +ALTER TABLE member_friend ADD COLUMN owner_id BIGINT; +ALTER TABLE member_friend ADD COLUMN friend_id BIGINT; + +ALTER TABLE member_friend + ADD CONSTRAINT fk_member_friend_owner_id FOREIGN KEY (owner_id) REFERENCES member (member_id); + +ALTER TABLE member_friend + ADD CONSTRAINT fk_member_friend_friend_id FOREIGN KEY (friend_id) REFERENCES member (member_id); diff --git a/backend/core/src/main/resources/test/data/insert.sql b/backend/core/src/main/resources/test/data/insert.sql deleted file mode 100644 index b065395a4..000000000 --- a/backend/core/src/main/resources/test/data/insert.sql +++ /dev/null @@ -1,67 +0,0 @@ ---friend & owner -insert into member(nickname, is_verified, notification_enabled, social_type, email, profile_url, auth_id, created_at, updated_at) -values (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '12341', now(), now()), - (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '12342', now(), now()), - (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '12343', now(), now()), - (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '12344', now(), now()), - (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '12345', now(), now()), - (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '12346', now(), now()), - (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '12347', now(), now()), - (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '12348', now(), now()), - (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '12349', now(), now()), - (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123410', now(), now()), - (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123411', now(), now()), - (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123412', now(), now()), - (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123413', now(), now()), - (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123414', now(), now()), - (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123415', now(), now()), - (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123416', now(), now()), - (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123417', now(), now()), - (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123418', now(), now()), - (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123419', now(), now()), - (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '123420', now(), now()), - (1, false, false, 'GOOGLE', 'test@gmail.com', 'test.com', '1234121', now(), now()); - -insert into member_friend(owner_id, friend_id, created_at, updated_at) -values (21, 1, now(), now()), - (21, 2, now(), now()), - (21, 3, now(), now()), - (21, 4, now(), now()), - (21, 5, now(), now()), - (21, 6, now(), now()), - (21, 7, now(), now()), - (21, 8, now(), now()), - (21, 9, now(), now()), - (21, 10, now(), now()), - (21, 11, now(), now()), - (21, 12, now(), now()), - (21, 13, now(), now()), - (21, 14, now(), now()), - (21, 15, now(), now()), - (21, 16, now(), now()), - (21, 17, now(), now()), - (21, 18, now(), now()), - (21, 19, now(), now()), - (21, 20, now(), now()); - -insert into friend_invite(owner_id, friend_id, created_at, updated_at) -values (21, 1, now(), now()), - (21, 2, now(), now()), - (21, 3, now(), now()), - (21, 4, now(), now()), - (21, 5, now(), now()), - (21, 6, now(), now()), - (21, 7, now(), now()), - (21, 8, now(), now()), - (21, 9, now(), now()), - (21, 10, now(), now()), - (21, 11, now(), now()), - (21, 12, now(), now()), - (21, 13, now(), now()), - (21, 14, now(), now()), - (21, 15, now(), now()), - (21, 16, now(), now()), - (21, 17, now(), now()), - (21, 18, now(), now()), - (21, 19, now(), now()), - (21, 20, now(), now()); \ No newline at end of file diff --git a/backend/core/src/main/resources/test/data/truncate.sql b/backend/core/src/main/resources/test/data/truncate.sql deleted file mode 100644 index f9ba3770d..000000000 --- a/backend/core/src/main/resources/test/data/truncate.sql +++ /dev/null @@ -1,8 +0,0 @@ --- 외래 키 제약 조건 해제 -SET FOREIGN_KEY_CHECKS = 0; - -TRUNCATE TABLE member_friend; -TRUNCATE TABLE member; - --- 외래 키 제약 조건 활성화 -SET FOREIGN_KEY_CHECKS = 1; \ No newline at end of file diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/common/RepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/common/RepositoryTest.java index f15b30142..8da3a3bc7 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/common/RepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/common/RepositoryTest.java @@ -1,56 +1,20 @@ package site.timecapsulearchive.core.common; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; import org.flywaydb.test.annotation.FlywayTest; import org.flywaydb.test.junit5.annotation.FlywayTestExtension; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.context.annotation.Import; -import org.springframework.core.io.ClassPathResource; -import org.springframework.jdbc.datasource.init.ScriptUtils; import org.springframework.test.context.ActiveProfiles; import site.timecapsulearchive.core.global.config.JpaAuditingConfig; @Import(JpaAuditingConfig.class) @DataJpaTest +@FlywayTest @FlywayTestExtension @ActiveProfiles("test") @AutoConfigureTestDatabase(replace = Replace.NONE) public abstract class RepositoryTest extends DatabaseContainer { - private static final Logger logger = LoggerFactory.getLogger("RepositoryTest"); - - @FlywayTest - @BeforeAll - static void setupAll() { - runScript("test/data/insert.sql"); - } - - private static void runScript(String path) { - String url = mysqlContainer.getJdbcUrl(); - String username = mysqlContainer.getUsername(); - String password = mysqlContainer.getPassword(); - - try (Connection conn = DriverManager.getConnection(url, username, password)) { - ScriptUtils.executeSqlScript(conn, new ClassPathResource(path)); - } catch (SQLException e) { - logger.error("sql init error"); - throw new RuntimeException(e); - } - - logger.info("[SQL INIT] successfully init"); - } - - @AfterAll - static void cleanupAll() { - runScript("test/data/truncate.sql"); - logger.info("[SQL TRUNCATE] successfully truncate"); - } } diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java index 4206a2c12..be934b498 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java @@ -6,43 +6,68 @@ import jakarta.persistence.EntityManager; import java.time.ZoneId; import java.time.ZonedDateTime; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Slice; import org.springframework.test.context.TestConstructor; import org.springframework.test.context.TestConstructor.AutowireMode; +import org.springframework.transaction.annotation.Transactional; import site.timecapsulearchive.core.common.RepositoryTest; import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; +import site.timecapsulearchive.core.domain.friend.entity.FriendInvite; +import site.timecapsulearchive.core.domain.friend.entity.FriendStatus; +import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; +import site.timecapsulearchive.core.domain.member.entity.Member; +import site.timecapsulearchive.core.domain.member.entity.SocialType; @TestConstructor(autowireMode = AutowireMode.ALL) class MemberFriendQueryRepositoryTest extends RepositoryTest { private final MemberFriendQueryRepository memberFriendQueryRepository; + private Long memberId; MemberFriendQueryRepositoryTest(EntityManager entityManager) { this.memberFriendQueryRepository = new MemberFriendQueryRepository( new JPAQueryFactory(entityManager)); } - @DisplayName("사용자의_친구_목록_조회_테스트") - @Test - void findFriendsSlice() { - //given - Long memberId = 21L; - int size = 20; - ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(5); - - //when - Slice slice = memberFriendQueryRepository.findFriendsSlice( - memberId, - size, - now - ); + @Transactional + @BeforeEach + void setup(@Autowired EntityManager entityManager) { + Member owner = getMember(0); + entityManager.persist(owner); + memberId = owner.getId(); + + for (int i = 1; i < 21; i++) { + Member friend = getMember(i); + entityManager.persist(friend); + + MemberFriend memberFriend = MemberFriend.builder() + .friend(friend) + .owner(owner) + .build(); + entityManager.persist(memberFriend); + + FriendInvite friendInvite = FriendInvite.builder() + .friend(friend) + .owner(owner) + .friendStatus(FriendStatus.PENDING) + .build(); + entityManager.persist(friendInvite); + } + } - //then - assertThat(slice.getContent().size()).isEqualTo(size); + private Member getMember(int count) { + return Member.builder() + .socialType(SocialType.GOOGLE) + .email(count + "test@google.com") + .authId(count + "test") + .profileUrl(count + "test.com") + .build(); } @DisplayName("사용자의_친구_목록_조회_테스트") @@ -50,7 +75,6 @@ void findFriendsSlice() { @ValueSource(ints = {20, 15, 10, 5}) void findFriendsSliceWithDifferentSize(int size) { //given - Long memberId = 21L; ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(5); //when @@ -68,7 +92,6 @@ void findFriendsSliceWithDifferentSize(int size) { @Test void findFriendsSliceWithNotValidDate() { //given - Long memberId = 21L; int size = 20; ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(5); @@ -87,7 +110,6 @@ void findFriendsSliceWithNotValidDate() { @Test void findFriendsSliceWithNotMemberId() { //given - Long memberId = 20L; int size = 20; ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(5); @@ -102,31 +124,11 @@ void findFriendsSliceWithNotMemberId() { assertThat(slice.getContent().size()).isEqualTo(0); } - @DisplayName("사용자의_친구_요청_목록_조회_테스트") - @Test - void findFriendRequestsSlice() { - //given - Long memberId = 21L; - int size = 20; - ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(5); - - //when - Slice slice = memberFriendQueryRepository.findFriendRequestsSlice( - memberId, - size, - now - ); - - //then - assertThat(slice.getContent().size()).isEqualTo(size); - } - @DisplayName("사용자의_친구_요청_목록_조회_테스트") @ParameterizedTest @ValueSource(ints = {20, 15, 10, 5}) void findFriendRequestsSliceWithDifferentSize(int size) { //given - Long memberId = 21L; ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(5); //when @@ -144,7 +146,6 @@ void findFriendRequestsSliceWithDifferentSize(int size) { @Test void findFriendRequestsSliceWithNotValidDate() { //given - Long memberId = 21L; int size = 20; ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(5); @@ -163,7 +164,6 @@ void findFriendRequestsSliceWithNotValidDate() { @Test void findFriendRequestsSliceWithNotMemberId() { //given - Long memberId = 20L; int size = 20; ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(5); From 5bd82ce1e9ce10a01a452cc6163d2272d9365685 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sun, 17 Mar 2024 14:23:22 +0900 Subject: [PATCH 051/314] =?UTF-8?q?feat=20:=20flyway=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EC=9A=A9=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/core/src/main/resources/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/core/src/main/resources/config b/backend/core/src/main/resources/config index ed5290f31..5014e57d2 160000 --- a/backend/core/src/main/resources/config +++ b/backend/core/src/main/resources/config @@ -1 +1 @@ -Subproject commit ed5290f3197ac922d2423bd874d4884121c4e63f +Subproject commit 5014e57d219c7c09dc69cf905324ff5848d67c07 From 4b78a0267cd33a6f04ff1067b6c2814867ed8311 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sun, 17 Mar 2024 14:36:59 +0900 Subject: [PATCH 052/314] =?UTF-8?q?feat=20:=20status=EB=A5=BC=20=EA=B3=A0?= =?UTF-8?q?=EB=A0=A4=ED=95=9C=20=EC=BF=BC=EB=A6=AC=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EB=B0=8F=20=EC=9D=BD=EA=B8=B0=20=ED=8A=B8=EB=9E=9C=EC=9E=AD?= =?UTF-8?q?=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timecapsulearchive/core/domain/friend/api/FriendApi.java | 2 +- .../friend/repository/MemberFriendQueryRepository.java | 5 ++++- .../core/domain/friend/service/FriendService.java | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java index 0b3ccee1e..46c4e5880 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java @@ -113,7 +113,7 @@ ResponseEntity> findFriends( @Operation( summary = "소셜 친구 요청 목록 조회", - description = "사용자의 소셜 친구 요청 목록을 보여준다.", + description = "사용자의 소셜 친구 요청 목록을 보여준다. 수락 대기 중인 요청만 해당한다.", security = {@SecurityRequirement(name = "user_token")}, tags = {"friend"} ) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java index d076ea081..d56f61cf7 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java @@ -14,6 +14,7 @@ import org.springframework.data.domain.SliceImpl; import org.springframework.stereotype.Repository; import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; +import site.timecapsulearchive.core.domain.friend.entity.FriendStatus; @Repository @RequiredArgsConstructor @@ -73,7 +74,9 @@ public Slice findFriendRequestsSlice( .from(friendInvite) .innerJoin(member).on(friendInvite.owner.id.eq(member.id)) .innerJoin(member).on(friendInvite.friend.id.eq(member.id)) - .where(friendInvite.owner.id.eq(memberId).and(friendInvite.createdAt.lt(createdAt))) + .where(friendInvite.owner.id.eq(memberId) + .and(friendInvite.createdAt.lt(createdAt)) + .and(friendInvite.friendStatus.eq(FriendStatus.PENDING))) .limit(size + 1) .fetch(); diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java index 109afa894..d54cb7f90 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -26,7 +26,6 @@ import site.timecapsulearchive.core.infra.notification.manager.NotificationManager; @Service - public class FriendService { private final MemberFriendRepository memberFriendRepository; @@ -88,6 +87,7 @@ public void deleteFriend(final Long memberId, final Long friendId) { memberFriendRepository.delete(memberFriend); } + @Transactional(readOnly = true) public FriendsSliceResponse findFriendsSlice( final Long memberId, final int size, @@ -99,6 +99,7 @@ public FriendsSliceResponse findFriendsSlice( return memberFriendMapper.friendsSliceToResponse(friends); } + @Transactional(readOnly = true) public FriendRequestsSliceResponse findFriendRequestsSlice( final Long memberId, final int size, From 4f01911d1a0aa20deea74c4c72e33058c5434656 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sun, 17 Mar 2024 21:30:56 +0900 Subject: [PATCH 053/314] =?UTF-8?q?feat=20:=20notification=20status=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/db/migration/V18__notification_update.sql} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename backend/{notification/src/main/resources/db/migration/V1__notification_fix.sql => core/src/main/resources/db/migration/V18__notification_update.sql} (100%) diff --git a/backend/notification/src/main/resources/db/migration/V1__notification_fix.sql b/backend/core/src/main/resources/db/migration/V18__notification_update.sql similarity index 100% rename from backend/notification/src/main/resources/db/migration/V1__notification_fix.sql rename to backend/core/src/main/resources/db/migration/V18__notification_update.sql From 82e46b7ca78b262b0d28d7796a83869c7628d561 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sun, 17 Mar 2024 23:02:04 +0900 Subject: [PATCH 054/314] =?UTF-8?q?fix=20:=20s3=20=EB=A7=81=ED=81=AC=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/infra/notification/data/mapper/NotificationMapper.java | 2 +- backend/core/src/main/resources/config | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java index 4ceb54292..12da7ec6d 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java @@ -24,7 +24,7 @@ public CreatedCapsuleSkinNotificationRequest capsuleSkinDtoToMessage(Long member .skinName(dto.skinName()) .title("캡슐 스킨 생성 알림") .text(dto.skinName() + "이 생성되었습니다. ARchive에서 확인해보세요!") - .skinUrl(s3UrlGenerator.generateFileName(memberId, dto.directory(), dto.skinName())) + .skinUrl(s3UrlGenerator.generateFileName(memberId, dto.directory(), dto.imageUrl())) .build(); } diff --git a/backend/core/src/main/resources/config b/backend/core/src/main/resources/config index ed5290f31..236c790f5 160000 --- a/backend/core/src/main/resources/config +++ b/backend/core/src/main/resources/config @@ -1 +1 @@ -Subproject commit ed5290f3197ac922d2423bd874d4884121c4e63f +Subproject commit 236c790f5ace1e57ec8f2aa4d35e4a517e4e45b1 From 6de2dac5051ea27a6871c277c40848deeab8677c Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sun, 17 Mar 2024 23:18:31 +0900 Subject: [PATCH 055/314] =?UTF-8?q?fix=20:=20=EC=A4=91=EB=B3=B5=20?= =?UTF-8?q?=EB=A7=88=EC=9D=B4=EA=B7=B8=EB=A0=88=EC=9D=B4=EC=85=98=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/db/migration/V16__member_friend_update.sql | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 backend/core/src/main/resources/db/migration/V16__member_friend_update.sql diff --git a/backend/core/src/main/resources/db/migration/V16__member_friend_update.sql b/backend/core/src/main/resources/db/migration/V16__member_friend_update.sql deleted file mode 100644 index 2e445a0c0..000000000 --- a/backend/core/src/main/resources/db/migration/V16__member_friend_update.sql +++ /dev/null @@ -1,7 +0,0 @@ -# 친구 대상 아이디 추가 -ALTER TABLE member_friend - ADD COLUMN friend_id bigint, - ADD FOREIGN KEY fk_member_friend_member(member_id) REFERENCES member(member_id); - -ALTER TABLE member_friend - CHANGE member_id owner_id BIGINT \ No newline at end of file From eb108ad2cfe4ce565859bf3dbc1fef6af4ef012b Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sun, 17 Mar 2024 23:45:07 +0900 Subject: [PATCH 056/314] =?UTF-8?q?test=20:=20=EB=82=B4=EC=9A=A9=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/core/src/main/resources/config | 2 +- .../MemberFriendQueryRepositoryTest.java | 39 ++++++++++++------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/backend/core/src/main/resources/config b/backend/core/src/main/resources/config index 5014e57d2..22f616d77 160000 --- a/backend/core/src/main/resources/config +++ b/backend/core/src/main/resources/config @@ -1 +1 @@ -Subproject commit 5014e57d219c7c09dc69cf905324ff5848d67c07 +Subproject commit 22f616d7743c5c149bcaa92c640d9727c22f6e17 diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java index be934b498..136ce25b4 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java @@ -1,13 +1,14 @@ package site.timecapsulearchive.core.domain.friend.repository; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.SoftAssertions.assertSoftly; import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import java.time.ZoneId; import java.time.ZonedDateTime; +import java.util.Objects; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -70,10 +71,9 @@ private Member getMember(int count) { .build(); } - @DisplayName("사용자의_친구_목록_조회_테스트") @ParameterizedTest @ValueSource(ints = {20, 15, 10, 5}) - void findFriendsSliceWithDifferentSize(int size) { + void 사용자의_친구_목록_조회_테스트(int size) { //given ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(5); @@ -85,12 +85,18 @@ void findFriendsSliceWithDifferentSize(int size) { ); //then - assertThat(slice.getContent().size()).isEqualTo(size); + assertSoftly(softly -> { + softly.assertThat(slice.getContent().size()).isEqualTo(size); + softly.assertThat(slice.getContent()).allMatch(dto -> dto.createdAt().isBefore(now)); + softly.assertThat(slice.getContent()).allMatch(dto -> Objects.nonNull(dto.id())); + softly.assertThat(slice.getContent()).allMatch(dto -> !dto.profileUrl().isBlank()); + softly.assertThat(slice.getContent()).allMatch(dto -> !dto.nickname().isBlank()); + } + ); } - @DisplayName("유효하지_않은_시간으로_사용자의_친구_목록_조회_테스트") @Test - void findFriendsSliceWithNotValidDate() { + void 유효하지_않은_시간으로_사용자의_친구_목록_조회_테스트() { //given int size = 20; ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(5); @@ -106,9 +112,8 @@ void findFriendsSliceWithNotValidDate() { assertThat(slice.getContent().size()).isEqualTo(0); } - @DisplayName("친구가_없는_사용자의_친구_목록_조회_테스트") @Test - void findFriendsSliceWithNotMemberId() { + void 친구가_없는_사용자의_친구_목록_조회_테스트() { //given int size = 20; ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(5); @@ -124,10 +129,9 @@ void findFriendsSliceWithNotMemberId() { assertThat(slice.getContent().size()).isEqualTo(0); } - @DisplayName("사용자의_친구_요청_목록_조회_테스트") @ParameterizedTest @ValueSource(ints = {20, 15, 10, 5}) - void findFriendRequestsSliceWithDifferentSize(int size) { + void 사용자의_친구_요청_목록_조회_테스트(int size) { //given ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(5); @@ -139,12 +143,18 @@ void findFriendRequestsSliceWithDifferentSize(int size) { ); //then - assertThat(slice.getContent().size()).isEqualTo(size); + assertSoftly(softly -> { + softly.assertThat(slice.getContent().size()).isEqualTo(size); + softly.assertThat(slice.getContent()).allMatch(dto -> dto.createdAt().isBefore(now)); + softly.assertThat(slice.getContent()).allMatch(dto -> Objects.nonNull(dto.id())); + softly.assertThat(slice.getContent()).allMatch(dto -> !dto.profileUrl().isBlank()); + softly.assertThat(slice.getContent()).allMatch(dto -> !dto.nickname().isBlank()); + } + ); } - @DisplayName("유효하지_않은_시간으로_사용자의_친구_요청_목록_조회_테스트") @Test - void findFriendRequestsSliceWithNotValidDate() { + void 유효하지_않은_시간으로_사용자의_친구_요청_목록_조회_테스트() { //given int size = 20; ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(5); @@ -160,9 +170,8 @@ void findFriendRequestsSliceWithNotValidDate() { assertThat(slice.getContent().size()).isEqualTo(0); } - @DisplayName("친구가_없는_사용자의_친구_요청_목록_조회_테스트") @Test - void findFriendRequestsSliceWithNotMemberId() { + void 친구가_없는_사용자의_친구_요청_목록_조회_테스트() { //given int size = 20; ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(5); From 5e0e9fe54c0b22a8a7fba8925eb67a15e08df486 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Mon, 18 Mar 2024 15:34:37 +0900 Subject: [PATCH 057/314] =?UTF-8?q?fix:=20flyway=20=EB=B2=84=EC=A0=84?= =?UTF-8?q?=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/core/src/main/resources/config | 2 +- ...__member_friend_update.sql => V18__member_friend_update.sql} | 0 ...18__notification_update.sql => V19__notification_update.sql} | 0 backend/notification/src/main/resources/config | 2 +- 4 files changed, 2 insertions(+), 2 deletions(-) rename backend/core/src/main/resources/db/migration/{V17__member_friend_update.sql => V18__member_friend_update.sql} (100%) rename backend/core/src/main/resources/db/migration/{V18__notification_update.sql => V19__notification_update.sql} (100%) diff --git a/backend/core/src/main/resources/config b/backend/core/src/main/resources/config index 22f616d77..236c790f5 160000 --- a/backend/core/src/main/resources/config +++ b/backend/core/src/main/resources/config @@ -1 +1 @@ -Subproject commit 22f616d7743c5c149bcaa92c640d9727c22f6e17 +Subproject commit 236c790f5ace1e57ec8f2aa4d35e4a517e4e45b1 diff --git a/backend/core/src/main/resources/db/migration/V17__member_friend_update.sql b/backend/core/src/main/resources/db/migration/V18__member_friend_update.sql similarity index 100% rename from backend/core/src/main/resources/db/migration/V17__member_friend_update.sql rename to backend/core/src/main/resources/db/migration/V18__member_friend_update.sql diff --git a/backend/core/src/main/resources/db/migration/V18__notification_update.sql b/backend/core/src/main/resources/db/migration/V19__notification_update.sql similarity index 100% rename from backend/core/src/main/resources/db/migration/V18__notification_update.sql rename to backend/core/src/main/resources/db/migration/V19__notification_update.sql diff --git a/backend/notification/src/main/resources/config b/backend/notification/src/main/resources/config index 9c932cc6c..72b28b3c9 160000 --- a/backend/notification/src/main/resources/config +++ b/backend/notification/src/main/resources/config @@ -1 +1 @@ -Subproject commit 9c932cc6c99dd13768e8af801d4fbde4d1f6b9bd +Subproject commit 72b28b3c98e05dda4b62247a55bdf64ca2d0a726 From 08b3eb2910e0a912f0ad82b8a6b6026e2738601b Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Mon, 18 Mar 2024 17:04:22 +0900 Subject: [PATCH 058/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=88=98?= =?UTF-8?q?=EB=9D=BD=20API=20=EB=AC=B8=EC=84=9C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/api/FriendApi.java | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java index 4ceeadc91..8306529ff 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java @@ -8,17 +8,15 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.security.SecurityRequirement; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; import java.time.ZonedDateTime; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import site.timecapsulearchive.core.domain.friend.data.reqeust.SearchFriendsRequest; +import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; -import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; import site.timecapsulearchive.core.global.common.response.ApiSpec; import site.timecapsulearchive.core.global.error.ErrorResponse; @@ -26,7 +24,7 @@ public interface FriendApi { @Operation( - summary = "친구 요청 수락", + summary = "소셜 친구 요청 수락", description = "상대방으로부터 온 친구 요청을 수락한다.", security = {@SecurityRequirement(name = "user_token")}, tags = {"friend"} @@ -35,17 +33,22 @@ public interface FriendApi { @ApiResponse( responseCode = "200", description = "처리 완료" + ), + @ApiResponse( + responseCode = "500", + description = "외부 API 요청 실패" ) }) - @PostMapping(value = "/accept-request") - ResponseEntity acceptFriendRequest( - @Parameter(in = ParameterIn.QUERY, required = true) + ResponseEntity> acceptFriendRequest( + Long memberId, + + @Parameter(in = ParameterIn.QUERY, required = true, schema = @Schema()) @RequestParam(value = "friend_id") Long friendId ); @Operation( - summary = "친구 삭제", + summary = "소셜 친구 삭제", description = "사용자의 소셜 친구를 삭제한다.", security = {@SecurityRequirement(name = "user_token")}, tags = {"friend"} @@ -72,7 +75,7 @@ ResponseEntity> deleteFriend( @Operation( - summary = "친구 요청 거부", + summary = "소셜 친구 요청 거부", description = "상대방으로부터 온 친구 요청을 거부한다.", security = {@SecurityRequirement(name = "user_token")}, tags = {"friend"} @@ -136,7 +139,7 @@ ResponseEntity> findFriendRequests( @Operation( - summary = "친구 요청", + summary = "소셜 친구 요청", description = "사용자에게 친구 요청을 보낸다. 해당 사용자에게 알림이 발송된다.", security = {@SecurityRequirement(name = "user_token")}, tags = {"friend"} From 97d08d2f89cd853d777fa21e090f97a72fcc0ecd Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Mon, 18 Mar 2024 17:04:42 +0900 Subject: [PATCH 059/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EC=88=98=EB=9D=BD=20Controller=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/api/FriendApiController.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java index 0f4334fe2..0779773e7 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java @@ -27,9 +27,15 @@ public class FriendApiController implements FriendApi { private final FriendService friendService; + @PostMapping(value = "/{friend_id}/accept-request") @Override - public ResponseEntity acceptFriendRequest(Long friendId) { - return null; + public ResponseEntity> acceptFriendRequest( + @AuthenticationPrincipal final Long memberId, + @PathVariable("friend_id") final Long friendId + ) { + friendService.acceptFriend(memberId, friendId); + + return ResponseEntity.ok(ApiSpec.empty(SuccessCode.SUCCESS)); } @GetMapping @@ -81,7 +87,7 @@ public ResponseEntity> deleteFriend( @DeleteMapping("{friend_id}/deny-request") @Override public ResponseEntity> denyFriendRequest( - @AuthenticationPrincipal Long memberId, + @AuthenticationPrincipal final Long memberId, @PathVariable("friend_id") final Long friendId) { friendService.denyRequestFriend(memberId, friendId); From 54f35160b754638904c8f16d4466e52f7e22e296 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Mon, 18 Mar 2024 17:05:50 +0900 Subject: [PATCH 060/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EC=88=98=EB=9D=BD=20JPA=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/repository/FriendInviteRepository.java | 2 ++ .../core/domain/friend/repository/MemberFriendRepository.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java index c2cd3a9a3..fbb85172b 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java @@ -11,5 +11,7 @@ public interface FriendInviteRepository extends Repository { Optional findFriendInviteByOwnerIdAndFriendId(Long memberId, Long friendId); void deleteFriendInviteById(Long id); + + void delete(FriendInvite friendInvite); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepository.java index 82bb105b6..a487ea212 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepository.java @@ -9,4 +9,6 @@ public interface MemberFriendRepository extends Repository { Optional findMemberFriendByOwnerIdAndFriendId(Long ownerId, Long friendId); void delete(MemberFriend memberFriend); + + void save(MemberFriend memberFriend); } From 3a6e4f23543dd0cc8ebb0704b360f3860f7b17b1 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Mon, 18 Mar 2024 17:07:15 +0900 Subject: [PATCH 061/314] =?UTF-8?q?feat:=20MemberFriend=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=20=EC=83=9D=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../friend/data/mapper/MemberFriendMapper.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java index 1fffb43d1..f20bcd5d8 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java @@ -7,6 +7,8 @@ import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendSummaryResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; +import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; +import site.timecapsulearchive.core.domain.member.entity.Member; @Component public class MemberFriendMapper { @@ -21,7 +23,8 @@ public FriendsSliceResponse friendsSliceToResponse(Slice slice } private FriendSummaryResponse friendsSummaryDtoToResponse(FriendSummaryDto dto) { - return new FriendSummaryResponse(dto.id(), dto.profileUrl(), dto.nickname(), dto.createdAt()); + return new FriendSummaryResponse(dto.id(), dto.profileUrl(), dto.nickname(), + dto.createdAt()); } public FriendRequestsSliceResponse friendRequestsSliceToResponse( @@ -34,4 +37,11 @@ public FriendRequestsSliceResponse friendRequestsSliceToResponse( return new FriendRequestsSliceResponse(friendRequests, hasNext); } + + public MemberFriend memberToEntity(Member owner, Member friend) { + return MemberFriend.builder() + .owner(owner) + .friend(friend) + .build(); + } } From b7e677ad9ef9ac0c4c76ae6e74960c5cc2039f51 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Mon, 18 Mar 2024 17:08:20 +0900 Subject: [PATCH 062/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EC=88=98=EB=9D=BD=20Request=20mapper=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/mapper/NotificationMapper.java | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java index 12da7ec6d..31e7e35bc 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java @@ -4,6 +4,7 @@ import org.springframework.stereotype.Component; import site.timecapsulearchive.core.domain.capsuleskin.data.dto.CapsuleSkinCreateDto; import site.timecapsulearchive.core.infra.notification.data.dto.request.CreatedCapsuleSkinNotificationRequest; +import site.timecapsulearchive.core.infra.notification.data.dto.request.FriendAcceptNotificationRequest; import site.timecapsulearchive.core.infra.notification.data.dto.request.FriendReqNotificationRequest; import site.timecapsulearchive.core.infra.s3.manager.S3UrlGenerator; @@ -12,12 +13,12 @@ public class NotificationMapper { private static final String NOTIFICATION_SEND_SUCCESS = "SUCCESS"; - private static final String NOTIFICATION_SEND_FAILED = "FAILED"; - private final S3UrlGenerator s3UrlGenerator; - public CreatedCapsuleSkinNotificationRequest capsuleSkinDtoToMessage(Long memberId, - CapsuleSkinCreateDto dto) { + public CreatedCapsuleSkinNotificationRequest capsuleSkinDtoToMessage( + final Long memberId, + final CapsuleSkinCreateDto dto + ) { return CreatedCapsuleSkinNotificationRequest.builder() .memberId(memberId) .status(NOTIFICATION_SEND_SUCCESS) @@ -28,12 +29,27 @@ public CreatedCapsuleSkinNotificationRequest capsuleSkinDtoToMessage(Long member .build(); } - public FriendReqNotificationRequest friendReqToMessage(Long friendId, String ownerNickname) { + public FriendReqNotificationRequest friendReqToMessage( + final Long friendId, + final String ownerNickname + ) { return FriendReqNotificationRequest.builder() .friendId(friendId) - .status(NOTIFICATION_SEND_FAILED) + .status(NOTIFICATION_SEND_SUCCESS) .title("친구 요청 알림") .text(ownerNickname + "로부터 친구 요청이 왔습니다. ARchive에서 확인해보세요!") .build(); } + + public FriendAcceptNotificationRequest friendAcceptToMessage( + final Long memberId, + final String friendNickname + ) { + return FriendAcceptNotificationRequest.builder() + .memberId(memberId) + .status(NOTIFICATION_SEND_SUCCESS) + .title("친구 수락 알림") + .text(friendNickname + "가 친구 요청을 수락하였습니다. ARchive에서 확인해보세요!") + .build(); + } } From ec78d97ca8a2efebbee16ecb7c68f61b833ebb89 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Mon, 18 Mar 2024 17:08:51 +0900 Subject: [PATCH 063/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=88=98?= =?UTF-8?q?=EB=9D=BD=20=EC=9A=94=EC=B2=AD=20dto=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/FriendAcceptNotificationRequest.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/dto/request/FriendAcceptNotificationRequest.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/dto/request/FriendAcceptNotificationRequest.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/dto/request/FriendAcceptNotificationRequest.java new file mode 100644 index 000000000..0b2dd1782 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/dto/request/FriendAcceptNotificationRequest.java @@ -0,0 +1,14 @@ +package site.timecapsulearchive.core.infra.notification.data.dto.request; + +import lombok.Builder; + +@Builder +public record FriendAcceptNotificationRequest( + Long memberId, + String status, + String title, + String text + +) { + +} From f29a4ccd1c6845f9a90b77cc987ae3a74eab9728 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Mon, 18 Mar 2024 17:09:14 +0900 Subject: [PATCH 064/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EC=88=98=EB=9D=BD=20=EC=95=8C=EB=A6=BC=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infra/notification/manager/NotificationManager.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java index aee888362..e5f50c77a 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java @@ -6,6 +6,7 @@ import site.timecapsulearchive.core.global.aop.anotation.NotificationRequest; import site.timecapsulearchive.core.global.aop.aspect.NotificationRequestExceptionAspect; import site.timecapsulearchive.core.infra.notification.data.dto.request.CreatedCapsuleSkinNotificationRequest; +import site.timecapsulearchive.core.infra.notification.data.dto.request.FriendAcceptNotificationRequest; import site.timecapsulearchive.core.infra.notification.data.dto.request.FriendReqNotificationRequest; import site.timecapsulearchive.core.infra.notification.data.mapper.NotificationMapper; @@ -33,4 +34,12 @@ public void sendFriendReqMessage(final Long friendId, final String ownerNickname aspect.sendNotification(request, notificationUrl.friendReqAlarmUrl()); } + + @NotificationRequest + public void sendFriendAcceptMessage(final Long memberId, final String friendNickname) { + final FriendAcceptNotificationRequest request = notificationMapper.friendAcceptToMessage(memberId, + friendNickname); + + aspect.sendNotification(request, notificationUrl.friendAcceptAlarmUrl()); + } } From 8a4890c3f1e39d3a3ebc7c4fafc5815c7366345f Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Mon, 18 Mar 2024 17:10:11 +0900 Subject: [PATCH 065/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EC=88=98=EB=9D=BD=20service=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/friend/service/FriendService.java | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java index 5567b6fa1..16053c8e3 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -11,8 +11,8 @@ import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; import site.timecapsulearchive.core.domain.friend.data.mapper.FriendMapper; import site.timecapsulearchive.core.domain.friend.data.mapper.MemberFriendMapper; -import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; +import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; import site.timecapsulearchive.core.domain.friend.entity.FriendInvite; import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; @@ -78,6 +78,30 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { return FriendReqStatusResponse.success(); } + public void acceptFriend(final Long memberId, final Long friendId) { + final FriendInvite friendInvite = friendInviteRepository + .findFriendInviteByOwnerIdAndFriendId(memberId, friendId) + .orElseThrow(FriendNotFoundException::new); + + final Member owner = memberRepository + .findMemberById(memberId) + .orElseThrow(MemberNotFoundException::new); + final Member friend = memberRepository + .findMemberById(friendId) + .orElseThrow(MemberNotFoundException::new); + final MemberFriend memberFriend = memberFriendMapper.memberToEntity(owner, friend); + + transactionTemplate.execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(TransactionStatus status) { + friendInviteRepository.delete(friendInvite); + memberFriendRepository.save(memberFriend); + } + }); + + notificationManager.sendFriendAcceptMessage(memberId, friend.getNickname()); + } + @Transactional public void denyRequestFriend(Long memberId, Long friendId) { final FriendInvite friendInvite = friendInviteRepository @@ -86,7 +110,7 @@ public void denyRequestFriend(Long memberId, Long friendId) { friendInviteRepository.deleteFriendInviteById(friendInvite.getId()); } - + @Transactional public void deleteFriend(final Long memberId, final Long friendId) { final MemberFriend memberFriend = memberFriendRepository.findMemberFriendByOwnerIdAndFriendId( @@ -117,6 +141,7 @@ public FriendRequestsSliceResponse findFriendRequestsSlice( Slice friendRequests = memberFriendQueryRepository.findFriendRequestsSlice( memberId, size, createdAt); - return memberFriendMapper.friendRequestsSliceToResponse(friendRequests.getContent(), friendRequests.hasNext()); + return memberFriendMapper.friendRequestsSliceToResponse(friendRequests.getContent(), + friendRequests.hasNext()); } } From 03dc5e19c1849e55d431336c2b9614cbdb161546 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Mon, 18 Mar 2024 17:10:24 +0900 Subject: [PATCH 066/314] =?UTF-8?q?feat:=20NotificationUrl=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/infra/notification/manager/NotificationUrl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationUrl.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationUrl.java index 6403dde73..26bf35475 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationUrl.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationUrl.java @@ -5,7 +5,8 @@ @ConfigurationProperties(prefix = "notification-url") public record NotificationUrl( String capsuleSkinAlarmUrl, - String friendReqAlarmUrl + String friendReqAlarmUrl, + String friendAcceptAlarmUrl ) { } From f649f5627293b506051274caed275080331833aa Mon Sep 17 00:00:00 2001 From: hong seokho Date: Mon, 18 Mar 2024 19:21:31 +0900 Subject: [PATCH 067/314] =?UTF-8?q?fix=20:=20flyway=20schema=20=EB=B2=84?= =?UTF-8?q?=EC=A0=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...17__member_friend_update.sql => V18__member_friend_update.sql} | 0 ...{V18__notification_update.sql => V19__notification_update.sql} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename backend/core/src/main/resources/db/migration/{V17__member_friend_update.sql => V18__member_friend_update.sql} (100%) rename backend/core/src/main/resources/db/migration/{V18__notification_update.sql => V19__notification_update.sql} (100%) diff --git a/backend/core/src/main/resources/db/migration/V17__member_friend_update.sql b/backend/core/src/main/resources/db/migration/V18__member_friend_update.sql similarity index 100% rename from backend/core/src/main/resources/db/migration/V17__member_friend_update.sql rename to backend/core/src/main/resources/db/migration/V18__member_friend_update.sql diff --git a/backend/core/src/main/resources/db/migration/V18__notification_update.sql b/backend/core/src/main/resources/db/migration/V19__notification_update.sql similarity index 100% rename from backend/core/src/main/resources/db/migration/V18__notification_update.sql rename to backend/core/src/main/resources/db/migration/V19__notification_update.sql From fb9a98981152372f45b3b4d01cb763aeaa5b8f1f Mon Sep 17 00:00:00 2001 From: hong seokho Date: Mon, 18 Mar 2024 21:32:18 +0900 Subject: [PATCH 068/314] =?UTF-8?q?feat=20:=20=EC=A3=BC=EC=86=8C=EB=A1=9D?= =?UTF-8?q?=20=EA=B8=B0=EB=B0=98=20=ED=9A=8C=EC=9B=90=20=EC=B0=BE=EA=B8=B0?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/api/FriendApi.java | 16 ++++------- .../friend/api/FriendApiController.java | 20 +++++++++++--- .../data/mapper/MemberFriendMapper.java | 11 +++++++- .../data/reqeust/SearchFriendsRequest.java | 3 ++- .../data/response/SearchFriendsResponse.java | 3 +-- .../MemberFriendQueryRepository.java | 20 +++++++++++++- .../domain/friend/service/FriendService.java | 27 ++++++++++++++++--- .../data/response/MemberSummaryResponse.java | 18 ------------- .../global/common/valid/annotation/Phone.java | 4 +-- ...date.sql => V18__member_friend_update.sql} | 0 ...pdate.sql => V19__notification_update.sql} | 0 11 files changed, 79 insertions(+), 43 deletions(-) delete mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/response/MemberSummaryResponse.java rename backend/core/src/main/resources/db/migration/{V17__member_friend_update.sql => V18__member_friend_update.sql} (100%) rename backend/core/src/main/resources/db/migration/{V18__notification_update.sql => V19__notification_update.sql} (100%) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java index 4ceeadc91..079d2138f 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java @@ -8,17 +8,14 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.security.SecurityRequirement; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; import java.time.ZonedDateTime; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import site.timecapsulearchive.core.domain.friend.data.reqeust.SearchFriendsRequest; +import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; -import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; import site.timecapsulearchive.core.global.common.response.ApiSpec; import site.timecapsulearchive.core.global.error.ErrorResponse; @@ -171,11 +168,8 @@ ResponseEntity> requestFriend( description = "ok" ) }) - @PostMapping( - value = "/friends/search", - produces = {"application/json"}, - consumes = {"application/json"} - ) - ResponseEntity searchMembersByPhones( - @RequestBody SearchFriendsRequest request); + ResponseEntity> searchMembersByPhones( + Long memberId, + SearchFriendsRequest request + ); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java index 0f4334fe2..bce66d18a 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java @@ -1,5 +1,6 @@ package site.timecapsulearchive.core.domain.friend.api; +import jakarta.validation.Valid; import java.time.ZonedDateTime; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -8,6 +9,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -105,9 +107,21 @@ public ResponseEntity> requestFriend( ); } + @PostMapping( + value = "/search/phone", + produces = {"application/json"}, + consumes = {"application/json"} + ) @Override - public ResponseEntity searchMembersByPhones( - SearchFriendsRequest request) { - return null; + public ResponseEntity> searchMembersByPhones( + @AuthenticationPrincipal Long memberId, + @Valid @RequestBody SearchFriendsRequest request + ) { + return ResponseEntity.ok( + ApiSpec.success( + SuccessCode.SUCCESS, + friendService.findFriendsByPhone(memberId, request.phones()) + ) + ); } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java index 1fffb43d1..c788b7a91 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java @@ -7,6 +7,7 @@ import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendSummaryResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; +import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; @Component public class MemberFriendMapper { @@ -21,7 +22,8 @@ public FriendsSliceResponse friendsSliceToResponse(Slice slice } private FriendSummaryResponse friendsSummaryDtoToResponse(FriendSummaryDto dto) { - return new FriendSummaryResponse(dto.id(), dto.profileUrl(), dto.nickname(), dto.createdAt()); + return new FriendSummaryResponse(dto.id(), dto.profileUrl(), dto.nickname(), + dto.createdAt()); } public FriendRequestsSliceResponse friendRequestsSliceToResponse( @@ -34,4 +36,11 @@ public FriendRequestsSliceResponse friendRequestsSliceToResponse( return new FriendRequestsSliceResponse(friendRequests, hasNext); } + + public SearchFriendsResponse friendSummaryDtosToResponse(List dtos) { + return new SearchFriendsResponse(dtos.stream() + .map(this::friendsSummaryDtoToResponse) + .toList() + ); + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/reqeust/SearchFriendsRequest.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/reqeust/SearchFriendsRequest.java index 9a7bcff24..4dccf326e 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/reqeust/SearchFriendsRequest.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/reqeust/SearchFriendsRequest.java @@ -2,12 +2,13 @@ import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; +import site.timecapsulearchive.core.global.common.valid.annotation.Phone; @Schema(description = "전화번호 리스트로 친구 찾기 요청") public record SearchFriendsRequest( @Schema(description = "전화번호 리스트") - List phones + List<@Phone String> phones ) { } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/SearchFriendsResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/SearchFriendsResponse.java index b04bdd105..def572912 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/SearchFriendsResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/SearchFriendsResponse.java @@ -2,13 +2,12 @@ import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; -import site.timecapsulearchive.core.domain.member.data.response.MemberSummaryResponse; @Schema(description = "전화번호 리스트로 찾은 친구") public record SearchFriendsResponse( @Schema(description = "회원 요약 정보") - List friends + List friends ) { } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java index d56f61cf7..53395aacb 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java @@ -61,7 +61,7 @@ public Slice findFriendRequestsSlice( final int size, final ZonedDateTime createdAt ) { - List friends = jpaQueryFactory + List friends = jpaQueryFactory .select( Projections.constructor( FriendSummaryDto.class, @@ -87,4 +87,22 @@ public Slice findFriendRequestsSlice( return new SliceImpl<>(friends, Pageable.ofSize(size), hasNext); } + + public List findFriendsByPhone(Long memberId, List hashes) { + return jpaQueryFactory + .select( + Projections.constructor( + FriendSummaryDto.class, + member.id, + member.profileUrl, + member.nickname, + member.createdAt + ) + ) + .from(memberFriend) + .innerJoin(member).on(memberFriend.friend.id.eq(member.id)) + .where(memberFriend.owner.id.eq(memberId) + .and(memberFriend.friend.phone_hash.in(hashes))) + .fetch(); + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java index 5567b6fa1..34b0b209f 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -1,6 +1,8 @@ package site.timecapsulearchive.core.domain.friend.service; +import java.nio.charset.StandardCharsets; import java.time.ZonedDateTime; +import java.util.List; import org.springframework.data.domain.Slice; import org.springframework.stereotype.Service; import org.springframework.transaction.PlatformTransactionManager; @@ -11,9 +13,10 @@ import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; import site.timecapsulearchive.core.domain.friend.data.mapper.FriendMapper; import site.timecapsulearchive.core.domain.friend.data.mapper.MemberFriendMapper; -import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; +import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; +import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; import site.timecapsulearchive.core.domain.friend.entity.FriendInvite; import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; import site.timecapsulearchive.core.domain.friend.exception.FriendNotFoundException; @@ -23,6 +26,7 @@ import site.timecapsulearchive.core.domain.member.entity.Member; import site.timecapsulearchive.core.domain.member.exception.MemberNotFoundException; import site.timecapsulearchive.core.domain.member.repository.MemberRepository; +import site.timecapsulearchive.core.global.security.encryption.HashEncryptionManager; import site.timecapsulearchive.core.infra.notification.manager.NotificationManager; @Service @@ -36,6 +40,7 @@ public class FriendService { private final FriendMapper friendMapper; private final NotificationManager notificationManager; private final TransactionTemplate transactionTemplate; + private final HashEncryptionManager hashEncryptionManager; public FriendService( MemberFriendRepository memberFriendRepository, @@ -44,7 +49,7 @@ public FriendService( FriendInviteRepository friendInviteRepository, FriendMapper friendMapper, NotificationManager notificationManager, - PlatformTransactionManager transactionManager + PlatformTransactionManager transactionManager, HashEncryptionManager hashEncryptionManager ) { this.memberFriendRepository = memberFriendRepository; this.memberFriendQueryRepository = memberFriendQueryRepository; @@ -54,6 +59,7 @@ public FriendService( this.friendMapper = friendMapper; this.notificationManager = notificationManager; this.transactionTemplate = new TransactionTemplate(transactionManager); + this.hashEncryptionManager = hashEncryptionManager; this.transactionTemplate.setTimeout(7); } @@ -86,7 +92,7 @@ public void denyRequestFriend(Long memberId, Long friendId) { friendInviteRepository.deleteFriendInviteById(friendInvite.getId()); } - + @Transactional public void deleteFriend(final Long memberId, final Long friendId) { final MemberFriend memberFriend = memberFriendRepository.findMemberFriendByOwnerIdAndFriendId( @@ -117,6 +123,19 @@ public FriendRequestsSliceResponse findFriendRequestsSlice( Slice friendRequests = memberFriendQueryRepository.findFriendRequestsSlice( memberId, size, createdAt); - return memberFriendMapper.friendRequestsSliceToResponse(friendRequests.getContent(), friendRequests.hasNext()); + return memberFriendMapper.friendRequestsSliceToResponse(friendRequests.getContent(), + friendRequests.hasNext()); + } + + @Transactional(readOnly = true) + public SearchFriendsResponse findFriendsByPhone(Long memberId, List phones) { + List hashes = phones.stream() + .map(phone -> hashEncryptionManager.encrypt(phone.getBytes(StandardCharsets.UTF_8))) + .toList(); + + List friends = memberFriendQueryRepository.findFriendsByPhone( + memberId, hashes); + + return memberFriendMapper.friendSummaryDtosToResponse(friends); } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/response/MemberSummaryResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/response/MemberSummaryResponse.java deleted file mode 100644 index a252c316a..000000000 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/response/MemberSummaryResponse.java +++ /dev/null @@ -1,18 +0,0 @@ -package site.timecapsulearchive.core.domain.member.data.response; - -import io.swagger.v3.oas.annotations.media.Schema; - -@Schema(description = "회원 요약 정보") -public record MemberSummaryResponse( - - @Schema(description = "회원 아이디") - Long id, - - @Schema(description = "회원 닉네임") - String nickname, - - @Schema(description = "회원 프로필 url") - String profileUrl -) { - -} \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/common/valid/annotation/Phone.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/common/valid/annotation/Phone.java index 44abaf4c3..f7be765ac 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/common/valid/annotation/Phone.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/common/valid/annotation/Phone.java @@ -9,13 +9,13 @@ import java.lang.annotation.Target; import site.timecapsulearchive.core.global.common.valid.PhoneValidator; -@Target({ElementType.FIELD}) +@Target({ElementType.FIELD, ElementType.TYPE_USE}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = PhoneValidator.class) @Documented public @interface Phone { - String message() default "Invalid Phone"; + String message() default "유효하지 않은 전화번호 형식입니다."; Class[] groups() default {}; diff --git a/backend/core/src/main/resources/db/migration/V17__member_friend_update.sql b/backend/core/src/main/resources/db/migration/V18__member_friend_update.sql similarity index 100% rename from backend/core/src/main/resources/db/migration/V17__member_friend_update.sql rename to backend/core/src/main/resources/db/migration/V18__member_friend_update.sql diff --git a/backend/core/src/main/resources/db/migration/V18__notification_update.sql b/backend/core/src/main/resources/db/migration/V19__notification_update.sql similarity index 100% rename from backend/core/src/main/resources/db/migration/V18__notification_update.sql rename to backend/core/src/main/resources/db/migration/V19__notification_update.sql From e48225443f160013fc008c517ed5a78cfb7f999d Mon Sep 17 00:00:00 2001 From: hong seokho Date: Mon, 18 Mar 2024 23:19:04 +0900 Subject: [PATCH 069/314] =?UTF-8?q?fix=20:=20=EC=BF=BC=EB=A6=AC=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 조인이 한 번만 발생하도록 수정 --- .../friend/repository/MemberFriendQueryRepository.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java index 53395aacb..683a8778d 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java @@ -100,9 +100,8 @@ public List findFriendsByPhone(Long memberId, List has ) ) .from(memberFriend) - .innerJoin(member).on(memberFriend.friend.id.eq(member.id)) - .where(memberFriend.owner.id.eq(memberId) - .and(memberFriend.friend.phone_hash.in(hashes))) + .innerJoin(memberFriend.friend, member) + .where(memberFriend.owner.id.eq(memberId).and(member.phone_hash.in(hashes))) .fetch(); } } From 5a9bca16014161780ceb0c88ff0ce47307d61b9d Mon Sep 17 00:00:00 2001 From: hong seokho Date: Mon, 18 Mar 2024 23:22:05 +0900 Subject: [PATCH 070/314] =?UTF-8?q?test=20:=20=EC=BF=BC=EB=A6=AC=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MemberFriendQueryRepositoryTest.java | 96 +++++++++++++++++-- 1 file changed, 86 insertions(+), 10 deletions(-) diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java index 136ce25b4..ef6e6c12f 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java @@ -5,9 +5,13 @@ import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; +import java.nio.charset.StandardCharsets; import java.time.ZoneId; import java.time.ZonedDateTime; +import java.util.Collections; +import java.util.List; import java.util.Objects; +import java.util.stream.IntStream; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -24,12 +28,17 @@ import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; import site.timecapsulearchive.core.domain.member.entity.Member; import site.timecapsulearchive.core.domain.member.entity.SocialType; +import site.timecapsulearchive.core.global.security.encryption.HashEncryptionManager; +import site.timecapsulearchive.core.global.security.encryption.HashProperties; @TestConstructor(autowireMode = AutowireMode.ALL) class MemberFriendQueryRepositoryTest extends RepositoryTest { private final MemberFriendQueryRepository memberFriendQueryRepository; - private Long memberId; + private final HashEncryptionManager hash = new HashEncryptionManager(new HashProperties("test")); + private final int MAX_FRIEND_ID = 21; + + private Long ownerId; MemberFriendQueryRepositoryTest(EntityManager entityManager) { this.memberFriendQueryRepository = new MemberFriendQueryRepository( @@ -41,9 +50,9 @@ class MemberFriendQueryRepositoryTest extends RepositoryTest { void setup(@Autowired EntityManager entityManager) { Member owner = getMember(0); entityManager.persist(owner); - memberId = owner.getId(); + ownerId = owner.getId(); - for (int i = 1; i < 21; i++) { + for (int i = 1; i < MAX_FRIEND_ID; i++) { Member friend = getMember(i); entityManager.persist(friend); @@ -63,12 +72,21 @@ void setup(@Autowired EntityManager entityManager) { } private Member getMember(int count) { - return Member.builder() + Member member = Member.builder() .socialType(SocialType.GOOGLE) .email(count + "test@google.com") .authId(count + "test") .profileUrl(count + "test.com") .build(); + + byte[] number = getPhoneBytes(count); + member.updatePhoneHash(hash.encrypt(number)); + + return member; + } + + private byte[] getPhoneBytes(int count) { + return ("0" + (1000000000 + count)).getBytes(StandardCharsets.UTF_8); } @ParameterizedTest @@ -79,7 +97,7 @@ private Member getMember(int count) { //when Slice slice = memberFriendQueryRepository.findFriendsSlice( - memberId, + ownerId, size, now ); @@ -103,7 +121,7 @@ private Member getMember(int count) { //when Slice slice = memberFriendQueryRepository.findFriendsSlice( - memberId, + ownerId, size, now ); @@ -120,7 +138,7 @@ private Member getMember(int count) { //when Slice slice = memberFriendQueryRepository.findFriendsSlice( - memberId, + ownerId, size, now ); @@ -137,7 +155,7 @@ private Member getMember(int count) { //when Slice slice = memberFriendQueryRepository.findFriendRequestsSlice( - memberId, + ownerId, size, now ); @@ -161,7 +179,7 @@ private Member getMember(int count) { //when Slice slice = memberFriendQueryRepository.findFriendRequestsSlice( - memberId, + ownerId, size, now ); @@ -178,7 +196,7 @@ private Member getMember(int count) { //when Slice slice = memberFriendQueryRepository.findFriendRequestsSlice( - memberId, + ownerId, size, now ); @@ -186,4 +204,62 @@ private Member getMember(int count) { //then assertThat(slice.getContent().size()).isEqualTo(0); } + + @Test + void 앱_사용자의_전화번호로만_사용자_리스트_조회_테스트() { + //given + List phoneHashes = IntStream.range(1, MAX_FRIEND_ID) + .mapToObj(i -> hash.encrypt(getPhoneBytes(i))) + .toList(); + + //when + List friends = memberFriendQueryRepository.findFriendsByPhone(ownerId, + phoneHashes); + + //then + assertThat(friends.size()).isGreaterThan(0); + } + + @Test + void 앱_사용자의_전화번호가_아닌_경우_사용자_리스트_조회_테스트() { + //given + List phoneHashes = IntStream.range(1, MAX_FRIEND_ID) + .mapToObj(count -> hash.encrypt(getPhoneBytes(count + MAX_FRIEND_ID))) + .toList(); + + //when + List friends = memberFriendQueryRepository.findFriendsByPhone(ownerId, + phoneHashes); + + //then + assertThat(friends.size()).isSameAs(0); + } + + @Test + void 친구가_없는_경우_사용자_리스트_조회_테스트() { + //given + List phoneHashes = IntStream.range(1, MAX_FRIEND_ID) + .mapToObj(count -> hash.encrypt(getPhoneBytes(count))) + .toList(); + + //when + List friends = memberFriendQueryRepository.findFriendsByPhone(ownerId + MAX_FRIEND_ID, + phoneHashes); + + //then + assertThat(friends.size()).isSameAs(0); + } + + @Test + void 빈_전화번호_목록인_경우_사용자_리스트_조회_테스트() { + //given + List phoneHashes = Collections.emptyList(); + + //when + List friends = memberFriendQueryRepository.findFriendsByPhone(ownerId, + phoneHashes); + + //then + assertThat(friends.size()).isSameAs(0); + } } \ No newline at end of file From e386bc743fb4a308c535b13961bacf0a0c9a3df2 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Mon, 18 Mar 2024 23:38:14 +0900 Subject: [PATCH 071/314] =?UTF-8?q?test=20:=20service=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../friend/service/FriendServiceTest.java | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/service/FriendServiceTest.java diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/service/FriendServiceTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/service/FriendServiceTest.java new file mode 100644 index 000000000..c424c8e92 --- /dev/null +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/service/FriendServiceTest.java @@ -0,0 +1,100 @@ +package site.timecapsulearchive.core.domain.friend.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.transaction.PlatformTransactionManager; +import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; +import site.timecapsulearchive.core.domain.friend.data.mapper.FriendMapper; +import site.timecapsulearchive.core.domain.friend.data.mapper.MemberFriendMapper; +import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; +import site.timecapsulearchive.core.domain.friend.repository.FriendInviteRepository; +import site.timecapsulearchive.core.domain.friend.repository.MemberFriendQueryRepository; +import site.timecapsulearchive.core.domain.friend.repository.MemberFriendRepository; +import site.timecapsulearchive.core.domain.member.repository.MemberRepository; +import site.timecapsulearchive.core.global.security.encryption.HashEncryptionManager; +import site.timecapsulearchive.core.global.security.encryption.HashProperties; +import site.timecapsulearchive.core.infra.notification.manager.NotificationManager; + +class FriendServiceTest { + + private final MemberFriendMapper memberFriendMapper = new MemberFriendMapper(); + private final MemberFriendQueryRepository memberFriendQueryRepository = mock( + MemberFriendQueryRepository.class); + private final MemberFriendRepository memberFriendRepository = mock( + MemberFriendRepository.class); + private final MemberRepository memberRepository = mock(MemberRepository.class); + private final FriendInviteRepository friendInviteRepository = mock( + FriendInviteRepository.class); + private final FriendMapper friendMapper = mock(FriendMapper.class); + private final NotificationManager notificationManager = mock(NotificationManager.class); + private final PlatformTransactionManager transactionTemplate = mock( + PlatformTransactionManager.class); + private final HashEncryptionManager hashEncryptionManager = new HashEncryptionManager( + new HashProperties("test_salt")); + + private final FriendService friendService = new FriendService(memberFriendRepository, + memberFriendQueryRepository, memberFriendMapper, memberRepository, friendInviteRepository, + friendMapper, notificationManager, transactionTemplate, hashEncryptionManager); + + @Test + void 사용자_핸드폰_번호로_친구_조회_테스트() { + //given + Long memberId = 1L; + List phones = getPhones(); + given(memberFriendQueryRepository.findFriendsByPhone(anyLong(), anyList())) + .willReturn(getFriendSummaryDtos()); + + //when + SearchFriendsResponse response = friendService.findFriendsByPhone(memberId, phones); + + //then + assertThat(response.friends().size()).isEqualTo(phones.size()); + } + + private List getPhones() { + return List.of( + "01012341234", + "01012341235", + "01012341236", + "01012341237", + "01012341238", + "01012341239", + "01012341240", + "01012341241" + ); + } + + private List getFriendSummaryDtos() { + List result = new ArrayList<>(); + for (long i = 0; i < 8; i++) { + result.add(new FriendSummaryDto(i, i + "testProfile.com", i + "testNickname", + ZonedDateTime.now())); + } + + return result; + } + + @Test + void 번호_없이_친구_조회_테스트() { + //given + Long memberId = 1L; + List phones = Collections.emptyList(); + given(memberFriendQueryRepository.findFriendsByPhone(anyLong(), anyList())) + .willReturn(Collections.emptyList()); + + //when + SearchFriendsResponse response = friendService.findFriendsByPhone(memberId, phones); + + //then + assertThat(response.friends().size()).isEqualTo(0); + } +} \ No newline at end of file From e13fa1f284a914ba727130ef241989c056733dc6 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Tue, 19 Mar 2024 12:41:14 +0900 Subject: [PATCH 072/314] =?UTF-8?q?chore:=20JNanoId=20=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EB=B8=8C=EB=9F=AC=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/core/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/core/build.gradle b/backend/core/build.gradle index 7520ee105..e62f7ac25 100644 --- a/backend/core/build.gradle +++ b/backend/core/build.gradle @@ -74,6 +74,7 @@ dependencies { //aop implementation 'org.springframework.boot:spring-boot-starter-aop' + compileOnly 'com.aventrix.jnanoid:jnanoid:2.0.0' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok' From 9935bd803eca999a5eb702b303ebea78931eb403 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Tue, 19 Mar 2024 12:42:04 +0900 Subject: [PATCH 073/314] =?UTF-8?q?refact:=20member=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=20builder=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/member/entity/Member.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java index 3e17a98d1..97737fad8 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java @@ -1,5 +1,6 @@ package site.timecapsulearchive.core.domain.member.entity; +import com.aventrix.jnanoid.jnanoid.NanoIdUtils; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -12,7 +13,6 @@ import jakarta.persistence.Table; import jakarta.validation.constraints.Email; import java.util.List; -import java.util.UUID; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -69,6 +69,9 @@ public class Member extends BaseEntity { @Column(name = "auth_id", nullable = false, unique = true) private String authId; + @Column(name = "tag", nullable = false, unique = true) + private String tag; + @OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true) private List capsules; @@ -93,12 +96,13 @@ public class Member extends BaseEntity { @Builder private Member(String profileUrl, SocialType socialType, String email, String authId) { this.profileUrl = profileUrl; - this.nickname = String.valueOf(UUID.randomUUID()); + this.nickname = randomNickName(); this.socialType = socialType; this.email = email; this.isVerified = false; this.notificationEnabled = false; this.authId = authId; + this.tag = uniqueTag(); } public void updateVerification() { @@ -113,7 +117,11 @@ public void updatePhoneHash(byte[] phone_hash) { this.phone_hash = phone_hash; } - public void updateNickName() { - this.nickname = MakeRandomNickNameUtil.makeRandomNickName(); + private String randomNickName() { + return MakeRandomNickNameUtil.makeRandomNickName(); + } + + private String uniqueTag() { + return NanoIdUtils.randomNanoId(); } } From 00f3d63c83133c2de6cf88060125ab7fbdd872e0 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Tue, 19 Mar 2024 12:42:48 +0900 Subject: [PATCH 074/314] =?UTF-8?q?feat:=20flyway=20member=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...__member_friend_update.sql => V18__member_friend_update.sql} | 0 ...18__notification_update.sql => V19__notification_update.sql} | 0 .../src/main/resources/db/migration/V20__member_add_tag.sql | 2 ++ 3 files changed, 2 insertions(+) rename backend/core/src/main/resources/db/migration/{V17__member_friend_update.sql => V18__member_friend_update.sql} (100%) rename backend/core/src/main/resources/db/migration/{V18__notification_update.sql => V19__notification_update.sql} (100%) create mode 100644 backend/core/src/main/resources/db/migration/V20__member_add_tag.sql diff --git a/backend/core/src/main/resources/db/migration/V17__member_friend_update.sql b/backend/core/src/main/resources/db/migration/V18__member_friend_update.sql similarity index 100% rename from backend/core/src/main/resources/db/migration/V17__member_friend_update.sql rename to backend/core/src/main/resources/db/migration/V18__member_friend_update.sql diff --git a/backend/core/src/main/resources/db/migration/V18__notification_update.sql b/backend/core/src/main/resources/db/migration/V19__notification_update.sql similarity index 100% rename from backend/core/src/main/resources/db/migration/V18__notification_update.sql rename to backend/core/src/main/resources/db/migration/V19__notification_update.sql diff --git a/backend/core/src/main/resources/db/migration/V20__member_add_tag.sql b/backend/core/src/main/resources/db/migration/V20__member_add_tag.sql new file mode 100644 index 000000000..6f681a0c1 --- /dev/null +++ b/backend/core/src/main/resources/db/migration/V20__member_add_tag.sql @@ -0,0 +1,2 @@ +ALTER TABLE member + ADD COLUMN tag VARCHAR(255); \ No newline at end of file From 938fe386af072ec1e2ce3ac0dbd43fa4d53e72d2 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Tue, 19 Mar 2024 12:43:15 +0900 Subject: [PATCH 075/314] =?UTF-8?q?fix:=20member=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/auth/service/MessageVerificationService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/service/MessageVerificationService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/service/MessageVerificationService.java index 27eabe543..90ae404a2 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/service/MessageVerificationService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/service/MessageVerificationService.java @@ -102,7 +102,6 @@ private void updateMemberData(final Long memberId, final String receiver) { findMember.updatePhoneHash(hashEncryptionManager.encrypt(plain)); findMember.updatePhoneNumber(aesEncryptionManager.encryptWithPrefixIV(plain)); - findMember.updateNickName(); findMember.updateVerification(); } } From 6b54750f37b22f5d13e62ca4b470796119a9b9ab Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Tue, 19 Mar 2024 13:57:30 +0900 Subject: [PATCH 076/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=ED=83=9C?= =?UTF-8?q?=EA=B7=B8=20=EA=B2=80=EC=83=89=20API=20=EB=AC=B8=EC=84=9C?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/api/FriendApi.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java index 4ceeadc91..05e1f69db 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java @@ -8,8 +8,6 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.security.SecurityRequirement; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; import java.time.ZonedDateTime; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; @@ -17,6 +15,7 @@ import org.springframework.web.bind.annotation.RequestParam; import site.timecapsulearchive.core.domain.friend.data.reqeust.SearchFriendsRequest; import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; +import site.timecapsulearchive.core.domain.friend.data.response.FriendSearchResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; @@ -178,4 +177,23 @@ ResponseEntity> requestFriend( ) ResponseEntity searchMembersByPhones( @RequestBody SearchFriendsRequest request); + + @Operation( + summary = "찬구 검색", + description = "친구의 tag로 친구 검색을 한다.", + security = {@SecurityRequirement(name = "user_token")}, + tags = {"friend"} + ) + @ApiResponses(value = { + @ApiResponse( + responseCode = "200", + description = "ok" + ) + }) + ResponseEntity> searchFriendByTag( + Long memberId, + + @Parameter(in = ParameterIn.QUERY, description = "페이지 크기", required = true) + String tag + ); } From 47a4bcd1e1718a4961572dc77c471a671e27d89e Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Tue, 19 Mar 2024 13:57:48 +0900 Subject: [PATCH 077/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=ED=83=9C?= =?UTF-8?q?=EA=B7=B8=20=EA=B2=80=EC=83=89=20Controller=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/friend/api/FriendApiController.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java index 0f4334fe2..1398647cc 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java @@ -14,6 +14,7 @@ import site.timecapsulearchive.core.domain.friend.data.reqeust.SearchFriendsRequest; import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; +import site.timecapsulearchive.core.domain.friend.data.response.FriendSearchResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; import site.timecapsulearchive.core.domain.friend.service.FriendService; @@ -110,4 +111,19 @@ public ResponseEntity searchMembersByPhones( SearchFriendsRequest request) { return null; } + + @PostMapping(value = "/search") + @Override + public ResponseEntity> searchFriendByTag( + @AuthenticationPrincipal Long memberId, + @RequestParam(value = "friend-tag") final String tag + ) { + return ResponseEntity.ok() + .body( + ApiSpec.success( + SuccessCode.SUCCESS, + friendService.searchFriend(memberId, tag) + ) + ); + } } From 088087e49dea23ca76c501b50fbcbd842f0df78f Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Tue, 19 Mar 2024 13:58:12 +0900 Subject: [PATCH 078/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=ED=83=9C?= =?UTF-8?q?=EA=B7=B8=20=EA=B2=80=EC=83=89=20=EC=9D=91=EB=8B=B5=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/response/FriendSearchResponse.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSearchResponse.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSearchResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSearchResponse.java new file mode 100644 index 000000000..ffe7f2448 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSearchResponse.java @@ -0,0 +1,21 @@ +package site.timecapsulearchive.core.domain.friend.data.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; + +@Builder +public record FriendSearchResponse( + @Schema(description = "친구 아이디") + Long id, + + @Schema(description = "친구 프로필") + String profileUrl, + + @Schema(description = "친구 닉네임") + String nickname, + + @Schema(description = "친구 관계") + Boolean isFriend +) { + +} From 4176cf2675de32d64bb1e0e1451fda5389a045c0 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Tue, 19 Mar 2024 13:59:01 +0900 Subject: [PATCH 079/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=ED=83=9C?= =?UTF-8?q?=EA=B7=B8=20=EA=B2=80=EC=83=89=20JPA=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/member/repository/MemberRepository.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberRepository.java index 9e8f9b31d..62042ca10 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberRepository.java @@ -26,4 +26,6 @@ int updateMemberNotificationEnabled( @Param("memberId") Long memberId, @Param("notificationEnabled") Boolean notificationEnabled ); + + Optional findMemberByTag(String tag); } From a93bca19a3adf96ea0ae19ef95bce8b4d58ae4b1 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Tue, 19 Mar 2024 14:00:20 +0900 Subject: [PATCH 080/314] =?UTF-8?q?feat:=20MemberFriend=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=20FriendStatus=20=EC=B6=95=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/entity/MemberFriend.java | 10 ++++++++++ .../migration/V21__member_friend_add_friendstatus.sql | 2 ++ 2 files changed, 12 insertions(+) create mode 100644 backend/core/src/main/resources/db/migration/V21__member_friend_add_friendstatus.sql diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java index e089effda..7e58fcc0b 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java @@ -2,6 +2,8 @@ import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; @@ -27,6 +29,10 @@ public class MemberFriend extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Column(name = "friend_status") + @Enumerated(EnumType.STRING) + private FriendStatus friendStatus; + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "owner_id", nullable = false) private Member owner; @@ -40,4 +46,8 @@ private MemberFriend(Member owner, Member friend) { this.owner = owner; this.friend = friend; } + + public boolean isFriend() { + return this.friendStatus.equals(FriendStatus.ACCEPTED); + } } diff --git a/backend/core/src/main/resources/db/migration/V21__member_friend_add_friendstatus.sql b/backend/core/src/main/resources/db/migration/V21__member_friend_add_friendstatus.sql new file mode 100644 index 000000000..c3008c72e --- /dev/null +++ b/backend/core/src/main/resources/db/migration/V21__member_friend_add_friendstatus.sql @@ -0,0 +1,2 @@ +ALTER TABLE member_friend + ADD COLUMN friend_status VARCHAR(255); \ No newline at end of file From cd0de4ca11609a1f1c18813f3b7901a0b16a26a9 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Tue, 19 Mar 2024 14:00:41 +0900 Subject: [PATCH 081/314] =?UTF-8?q?feat:=20SearchDto=20mapper=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/friend/data/mapper/MemberFriendMapper.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java index 1fffb43d1..7430a65cd 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java @@ -5,8 +5,10 @@ import org.springframework.stereotype.Component; import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; +import site.timecapsulearchive.core.domain.friend.data.response.FriendSearchResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendSummaryResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; +import site.timecapsulearchive.core.domain.member.entity.Member; @Component public class MemberFriendMapper { @@ -34,4 +36,13 @@ public FriendRequestsSliceResponse friendRequestsSliceToResponse( return new FriendRequestsSliceResponse(friendRequests, hasNext); } + + public FriendSearchResponse friendSearchDtoToResponse(final Member friend, boolean isFriend) { + return FriendSearchResponse.builder() + .id(friend.getId()) + .profileUrl(friend.getProfileUrl()) + .nickname(friend.getNickname()) + .isFriend(isFriend) + .build(); + } } From c14ab5f5537d8aa5800c89823ddb517355d318c7 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Tue, 19 Mar 2024 14:01:06 +0900 Subject: [PATCH 082/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=ED=83=9C?= =?UTF-8?q?=EA=B7=B8=20=EA=B2=80=EC=83=89=20Service=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/friend/service/FriendService.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java index 5567b6fa1..dfd6da9a7 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -11,8 +11,9 @@ import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; import site.timecapsulearchive.core.domain.friend.data.mapper.FriendMapper; import site.timecapsulearchive.core.domain.friend.data.mapper.MemberFriendMapper; -import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; +import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; +import site.timecapsulearchive.core.domain.friend.data.response.FriendSearchResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; import site.timecapsulearchive.core.domain.friend.entity.FriendInvite; import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; @@ -86,7 +87,7 @@ public void denyRequestFriend(Long memberId, Long friendId) { friendInviteRepository.deleteFriendInviteById(friendInvite.getId()); } - + @Transactional public void deleteFriend(final Long memberId, final Long friendId) { final MemberFriend memberFriend = memberFriendRepository.findMemberFriendByOwnerIdAndFriendId( @@ -117,6 +118,18 @@ public FriendRequestsSliceResponse findFriendRequestsSlice( Slice friendRequests = memberFriendQueryRepository.findFriendRequestsSlice( memberId, size, createdAt); - return memberFriendMapper.friendRequestsSliceToResponse(friendRequests.getContent(), friendRequests.hasNext()); + return memberFriendMapper.friendRequestsSliceToResponse(friendRequests.getContent(), + friendRequests.hasNext()); + } + + public FriendSearchResponse searchFriend(final Long memberId, final String tag) { + final Member friend = memberRepository.findMemberByTag(tag) + .orElseThrow(MemberNotFoundException::new); + + final MemberFriend memberFriend = memberFriendRepository + .findMemberFriendByOwnerIdAndFriendId(memberId, friend.getId()) + .orElseThrow(FriendNotFoundException::new); + + return memberFriendMapper.friendSearchDtoToResponse(friend, memberFriend.isFriend()); } } From 1436777f2adf9c62896d34bf222435a1e99293e4 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Tue, 19 Mar 2024 14:03:07 +0900 Subject: [PATCH 083/314] =?UTF-8?q?refact:=20builder=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/data/mapper/MemberFriendMapper.java | 7 ++++++- .../domain/friend/data/response/FriendSummaryResponse.java | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java index 7430a65cd..19150660c 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java @@ -23,7 +23,12 @@ public FriendsSliceResponse friendsSliceToResponse(Slice slice } private FriendSummaryResponse friendsSummaryDtoToResponse(FriendSummaryDto dto) { - return new FriendSummaryResponse(dto.id(), dto.profileUrl(), dto.nickname(), dto.createdAt()); + return FriendSummaryResponse.builder() + .id(dto.id()) + .profileUrl(dto.profileUrl()) + .nickname(dto.nickname()) + .createdAt(dto.createdAt()) + .build(); } public FriendRequestsSliceResponse friendRequestsSliceToResponse( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSummaryResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSummaryResponse.java index c6fe7d9bf..04030ac7c 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSummaryResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSummaryResponse.java @@ -2,7 +2,9 @@ import io.swagger.v3.oas.annotations.media.Schema; import java.time.ZonedDateTime; +import lombok.Builder; +@Builder @Schema(description = "친구 요약 정보") public record FriendSummaryResponse( @Schema(description = "친구 아이디") From 3b50a6a51b6fe506a06c727539929417aa233c5f Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Tue, 19 Mar 2024 14:04:43 +0900 Subject: [PATCH 084/314] =?UTF-8?q?chore:=20=EC=9E=90=EB=B0=94=20=EA=B5=AC?= =?UTF-8?q?=EA=B8=80=20=ED=98=95=EC=8B=9D=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/api/FriendApi.java | 2 +- .../MemberFriendQueryRepository.java | 2 +- .../core/global/error/ErrorResponse.java | 3 +- .../global/error/GlobalExceptionHandler.java | 5 +- .../db/migration/V11__image_video_update.sql | 16 +++---- .../db/migration/V12__capsule_skin_update.sql | 6 ++- .../db/migration/V13__failed_task.sql | 25 +++++----- .../db/migration/V15__create_notification.sql | 34 +++++++------- .../migration/V16__friend_invite_update.sql | 15 ++++-- .../V17__friend_invite_add_constraint.sql | 3 +- .../migration/V18__member_friend_update.sql | 14 ++++-- .../main/resources/db/migration/V1__init.sql | 46 +++++++++---------- .../db/migration/V2__member_update.sql | 2 +- .../db/migration/V5__member_update.sql | 3 +- .../db/migration/V6__capsule_update.sql | 6 +-- .../db/migration/V7__address_update.sql | 19 +++++--- .../migration/V8__capsule_member_update.sql | 3 +- 17 files changed, 114 insertions(+), 90 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java index 05e1f69db..2268d428c 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java @@ -14,10 +14,10 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import site.timecapsulearchive.core.domain.friend.data.reqeust.SearchFriendsRequest; +import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendSearchResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; -import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; import site.timecapsulearchive.core.global.common.response.ApiSpec; import site.timecapsulearchive.core.global.error.ErrorResponse; diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java index d56f61cf7..71919fbd8 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java @@ -61,7 +61,7 @@ public Slice findFriendRequestsSlice( final int size, final ZonedDateTime createdAt ) { - List friends = jpaQueryFactory + List friends = jpaQueryFactory .select( Projections.constructor( FriendSummaryDto.class, diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorResponse.java index 08ef89382..1356e94cf 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorResponse.java @@ -45,7 +45,7 @@ public static ErrorResponse fromParameter( List.of(Error.fromParameter(parameterName)) ); } - + public static ErrorResponse fromType( final ErrorCode errorCode, final String parameterName, @@ -63,6 +63,7 @@ public record Error( String value, String reason ) { + public static Error fromType(final String parameterName, final String value) { return new Error(parameterName, value, "입력 파라미터의 타입이 올바르지 않습니다."); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/GlobalExceptionHandler.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/GlobalExceptionHandler.java index ae5c51c83..d7435216d 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/GlobalExceptionHandler.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/GlobalExceptionHandler.java @@ -27,7 +27,8 @@ public class GlobalExceptionHandler { protected ResponseEntity handleGlobalException(final Exception e) { log.error(e.getMessage(), e); - final ErrorResponse errorResponse = ErrorResponse.fromErrorCode(ErrorCode.INTERNAL_SERVER_ERROR); + final ErrorResponse errorResponse = ErrorResponse.fromErrorCode( + ErrorCode.INTERNAL_SERVER_ERROR); return ResponseEntity.status(INTERNAL_SERVER_ERROR.getStatus()) .body(errorResponse); } @@ -96,7 +97,7 @@ protected ResponseEntity handleMethodArgumentTypeMismatchExceptio MethodArgumentTypeMismatchException e ) { log.warn(e.getMessage(), e); - + final ErrorResponse errorResponse = ErrorResponse.fromType( REQUEST_PARAMETER_TYPE_NOT_MATCH_ERROR, e.getParameter().getParameterName(), diff --git a/backend/core/src/main/resources/db/migration/V11__image_video_update.sql b/backend/core/src/main/resources/db/migration/V11__image_video_update.sql index 820f44395..6c6a4cceb 100644 --- a/backend/core/src/main/resources/db/migration/V11__image_video_update.sql +++ b/backend/core/src/main/resources/db/migration/V11__image_video_update.sql @@ -1,19 +1,19 @@ -- image 테이블에 member_id 컬럼 추가 ALTER TABLE image -ADD COLUMN member_id BIGINT; + ADD COLUMN member_id BIGINT; -- video 테이블에 member_id 컬럼 추가 ALTER TABLE video -ADD COLUMN member_id BIGINT; + ADD COLUMN member_id BIGINT; -- image 테이블의 member_id를 member 테이블의 기본 키와 외래키로 설정 ALTER TABLE image -ADD CONSTRAINT fk_image_member -FOREIGN KEY (member_id) -REFERENCES member(member_id); + ADD CONSTRAINT fk_image_member + FOREIGN KEY (member_id) + REFERENCES member (member_id); -- video 테이블의 member_id를 member 테이블의 기본 키와 외래키로 설정 ALTER TABLE video -ADD CONSTRAINT fk_video_member -FOREIGN KEY (member_id) -REFERENCES member(member_id); \ No newline at end of file + ADD CONSTRAINT fk_video_member + FOREIGN KEY (member_id) + REFERENCES member (member_id); \ No newline at end of file diff --git a/backend/core/src/main/resources/db/migration/V12__capsule_skin_update.sql b/backend/core/src/main/resources/db/migration/V12__capsule_skin_update.sql index 622addd51..53b06ecfe 100644 --- a/backend/core/src/main/resources/db/migration/V12__capsule_skin_update.sql +++ b/backend/core/src/main/resources/db/migration/V12__capsule_skin_update.sql @@ -1,8 +1,10 @@ -- drop size column in capsule_skin Table -ALTER TABLE capsule_skin DROP COLUMN size; +ALTER TABLE capsule_skin + DROP COLUMN size; -- add retarget -alter table capsule_skin add column retarget varchar(255); +alter table capsule_skin + add column retarget varchar(255); ALTER TABLE capsule_skin MODIFY motion_name VARCHAR(255) null; \ No newline at end of file diff --git a/backend/core/src/main/resources/db/migration/V13__failed_task.sql b/backend/core/src/main/resources/db/migration/V13__failed_task.sql index 13e7375ab..e9b6f32dc 100644 --- a/backend/core/src/main/resources/db/migration/V13__failed_task.sql +++ b/backend/core/src/main/resources/db/migration/V13__failed_task.sql @@ -1,15 +1,16 @@ -CREATE TABLE failed_task ( - id INT AUTO_INCREMENT PRIMARY KEY, - name VARCHAR(255), - full_name VARCHAR(255), - args TEXT, - kwargs TEXT, +CREATE TABLE failed_task +( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255), + full_name VARCHAR(255), + args TEXT, + kwargs TEXT, exception_class TEXT, - exception_msg TEXT, - traceback TEXT, - celery_task_id VARCHAR(255), - failures INT, + exception_msg TEXT, + traceback TEXT, + celery_task_id VARCHAR(255), + failures INT, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); \ No newline at end of file diff --git a/backend/core/src/main/resources/db/migration/V15__create_notification.sql b/backend/core/src/main/resources/db/migration/V15__create_notification.sql index efbd51df1..d6668452b 100644 --- a/backend/core/src/main/resources/db/migration/V15__create_notification.sql +++ b/backend/core/src/main/resources/db/migration/V15__create_notification.sql @@ -1,22 +1,24 @@ -CREATE TABLE notification_category ( +CREATE TABLE notification_category +( notification_category_id BIGINT AUTO_INCREMENT PRIMARY KEY, - category_name VARCHAR(255) NOT NULL, - category_description VARCHAR(255) NOT NULL, + category_name VARCHAR(255) NOT NULL, + category_description VARCHAR(255) NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); -CREATE TABLE notification ( - notification_id BIGINT AUTO_INCREMENT PRIMARY KEY, - title VARCHAR(255) NOT NULL, - text TEXT NOT NULL, - member_id BIGINT NOT NULL, - notification_category_id BIGINT NOT NULL, - image_url VARCHAR(255) null, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, +CREATE TABLE notification +( + notification_id BIGINT AUTO_INCREMENT PRIMARY KEY, + title VARCHAR(255) NOT NULL, + text TEXT NOT NULL, + member_id BIGINT NOT NULL, + notification_category_id BIGINT NOT NULL, + image_url VARCHAR(255) null, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - FOREIGN KEY (member_id) REFERENCES member(member_id), - FOREIGN KEY (notification_category_id) REFERENCES notification_category(notification_category_id) + FOREIGN KEY (member_id) REFERENCES member (member_id), + FOREIGN KEY (notification_category_id) REFERENCES notification_category (notification_category_id) ); diff --git a/backend/core/src/main/resources/db/migration/V16__friend_invite_update.sql b/backend/core/src/main/resources/db/migration/V16__friend_invite_update.sql index 01cb9f73e..8321d2147 100644 --- a/backend/core/src/main/resources/db/migration/V16__friend_invite_update.sql +++ b/backend/core/src/main/resources/db/migration/V16__friend_invite_update.sql @@ -1,9 +1,14 @@ -ALTER TABLE friend_invite ADD COLUMN friend_status VARCHAR(20); -ALTER TABLE friend_invite DROP CONSTRAINT fk_friend_invite_member_id; -ALTER TABLE friend_invite DROP COLUMN member_id; +ALTER TABLE friend_invite + ADD COLUMN friend_status VARCHAR(20); +ALTER TABLE friend_invite + DROP CONSTRAINT fk_friend_invite_member_id; +ALTER TABLE friend_invite + DROP COLUMN member_id; -ALTER TABLE friend_invite ADD COLUMN owner_id BIGINT; -ALTER TABLE friend_invite ADD COLUMN friend_id BIGINT; +ALTER TABLE friend_invite + ADD COLUMN owner_id BIGINT; +ALTER TABLE friend_invite + ADD COLUMN friend_id BIGINT; ALTER TABLE friend_invite ADD CONSTRAINT fk_friend_invite_owner_id FOREIGN KEY (owner_id) REFERENCES member (member_id); diff --git a/backend/core/src/main/resources/db/migration/V17__friend_invite_add_constraint.sql b/backend/core/src/main/resources/db/migration/V17__friend_invite_add_constraint.sql index 2ba909ef6..9c8a5122c 100644 --- a/backend/core/src/main/resources/db/migration/V17__friend_invite_add_constraint.sql +++ b/backend/core/src/main/resources/db/migration/V17__friend_invite_add_constraint.sql @@ -1 +1,2 @@ -ALTER TABLE friend_invite ADD CONSTRAINT unique_owner_friend_pair UNIQUE (owner_id, friend_id); +ALTER TABLE friend_invite + ADD CONSTRAINT unique_owner_friend_pair UNIQUE (owner_id, friend_id); diff --git a/backend/core/src/main/resources/db/migration/V18__member_friend_update.sql b/backend/core/src/main/resources/db/migration/V18__member_friend_update.sql index 8f3f226f8..eea55dfe6 100644 --- a/backend/core/src/main/resources/db/migration/V18__member_friend_update.sql +++ b/backend/core/src/main/resources/db/migration/V18__member_friend_update.sql @@ -1,11 +1,15 @@ -ALTER TABLE member_friend DROP CONSTRAINT fk_member_friend_member_id; -ALTER TABLE member_friend DROP COLUMN member_id; +ALTER TABLE member_friend + DROP CONSTRAINT fk_member_friend_member_id; +ALTER TABLE member_friend + DROP COLUMN member_id; -ALTER TABLE member_friend ADD COLUMN owner_id BIGINT; -ALTER TABLE member_friend ADD COLUMN friend_id BIGINT; +ALTER TABLE member_friend + ADD COLUMN owner_id BIGINT; +ALTER TABLE member_friend + ADD COLUMN friend_id BIGINT; ALTER TABLE member_friend ADD CONSTRAINT fk_member_friend_owner_id FOREIGN KEY (owner_id) REFERENCES member (member_id); -ALTER TABLE member_friend +ALTER TABLE member_friend ADD CONSTRAINT fk_member_friend_friend_id FOREIGN KEY (friend_id) REFERENCES member (member_id); diff --git a/backend/core/src/main/resources/db/migration/V1__init.sql b/backend/core/src/main/resources/db/migration/V1__init.sql index cd7cc8e62..db802e9b6 100644 --- a/backend/core/src/main/resources/db/migration/V1__init.sql +++ b/backend/core/src/main/resources/db/migration/V1__init.sql @@ -1,8 +1,8 @@ CREATE TABLE `group` ( - created_at timestamp NULL, + created_at timestamp NULL, group_id BIGINT AUTO_INCREMENT PRIMARY KEY, - updated_at timestamp NULL, + updated_at timestamp NULL, group_name VARCHAR(255) NOT NULL, group_description VARCHAR(255) NOT NULL, group_profile_url VARCHAR(255) NOT NULL @@ -12,9 +12,9 @@ CREATE TABLE member ( is_verified BIT NOT NULL, notification_enabled BIT NOT NULL, - created_at timestamp NULL, + created_at timestamp NULL, member_id BIGINT AUTO_INCREMENT PRIMARY KEY, - updated_at timestamp NULL, + updated_at timestamp NULL, phone VARCHAR(255) NULL, nickname VARCHAR(255) NOT NULL, oauth2_provider VARCHAR(255) NOT NULL, @@ -26,10 +26,10 @@ CREATE TABLE member CREATE TABLE capsule_skin ( capsule_skin_id BIGINT AUTO_INCREMENT PRIMARY KEY, - created_at timestamp NULL, + created_at timestamp NULL, member_id BIGINT NOT NULL, size BIGINT NOT NULL, - updated_at timestamp NULL, + updated_at timestamp NULL, skin_name VARCHAR(255) NOT NULL, image_url VARCHAR(255) NOT NULL, motion_name VARCHAR(255) NOT NULL, @@ -44,11 +44,11 @@ CREATE TABLE capsule longitude FLOAT NOT NULL, capsule_id BIGINT AUTO_INCREMENT PRIMARY KEY, capsule_skin_id BIGINT NOT NULL, - created_at timestamp NULL, - due_date timestamp NULL, + created_at timestamp NULL, + due_date timestamp NULL, group_id BIGINT NOT NULL, member_id BIGINT NOT NULL, - updated_at timestamp NULL, + updated_at timestamp NULL, village VARCHAR(255) NOT NULL, city VARCHAR(255) NOT NULL, province VARCHAR(255) NOT NULL, @@ -69,7 +69,7 @@ CREATE TABLE friend_invite ( created_at timestamp NULL, friend_invite_id BIGINT AUTO_INCREMENT PRIMARY KEY, - member_id BIGINT NOT NULL, + member_id BIGINT NOT NULL, updated_at timestamp NULL, CONSTRAINT fk_friend_invite_member_id FOREIGN KEY (member_id) REFERENCES member (member_id) @@ -77,10 +77,10 @@ CREATE TABLE friend_invite CREATE TABLE group_capsule_open ( - capsule_id BIGINT NOT NULL, + capsule_id BIGINT NOT NULL, created_at timestamp NULL, group_capsule_open_id BIGINT AUTO_INCREMENT PRIMARY KEY, - member_id BIGINT NOT NULL, + member_id BIGINT NOT NULL, updated_at timestamp NULL, CONSTRAINT fk_group_capsule_open_member_id FOREIGN KEY (member_id) REFERENCES member (member_id), @@ -92,7 +92,7 @@ CREATE TABLE group_invite ( created_at timestamp NULL, group_invite_id BIGINT AUTO_INCREMENT PRIMARY KEY, - member_id BIGINT NOT NULL, + member_id BIGINT NOT NULL, updated_at timestamp NULL, CONSTRAINT fk_group_invite_member_id FOREIGN KEY (member_id) REFERENCES member (member_id) @@ -100,10 +100,10 @@ CREATE TABLE group_invite CREATE TABLE history ( - created_at timestamp NULL, + created_at timestamp NULL, history_id BIGINT AUTO_INCREMENT PRIMARY KEY, member_id BIGINT NOT NULL, - updated_at timestamp NULL, + updated_at timestamp NULL, title VARCHAR(255) NOT NULL, CONSTRAINT fk_history_member_id FOREIGN KEY (member_id) REFERENCES member (member_id) @@ -112,10 +112,10 @@ CREATE TABLE history CREATE TABLE image ( capsule_id BIGINT NOT NULL, - created_at timestamp NULL, + created_at timestamp NULL, image_id BIGINT AUTO_INCREMENT PRIMARY KEY, size BIGINT NOT NULL, - updated_at timestamp NULL, + updated_at timestamp NULL, image_name VARCHAR(255) NOT NULL, image_url VARCHAR(255) NOT NULL, CONSTRAINT fk_image_capsule_id @@ -125,9 +125,9 @@ CREATE TABLE image CREATE TABLE history_image ( created_at timestamp NULL, - history_id BIGINT NOT NULL, + history_id BIGINT NOT NULL, history_image_id BIGINT AUTO_INCREMENT PRIMARY KEY, - image_id BIGINT NOT NULL, + image_id BIGINT NOT NULL, updated_at timestamp NULL, CONSTRAINT fk_history_image_image_id FOREIGN KEY (image_id) REFERENCES image (image_id), @@ -139,7 +139,7 @@ CREATE TABLE member_friend ( created_at timestamp NULL, member_friend_id BIGINT AUTO_INCREMENT PRIMARY KEY, - member_id BIGINT NOT NULL, + member_id BIGINT NOT NULL, updated_at timestamp NULL, CONSTRAINT fk_member_friend_member_id FOREIGN KEY (member_id) REFERENCES member (member_id) @@ -147,11 +147,11 @@ CREATE TABLE member_friend CREATE TABLE member_group ( - is_owner BIT NOT NULL, + is_owner BIT NOT NULL, created_at timestamp NULL, - group_id BIGINT NOT NULL, + group_id BIGINT NOT NULL, member_group_id BIGINT AUTO_INCREMENT PRIMARY KEY, - member_id BIGINT NOT NULL, + member_id BIGINT NOT NULL, updated_at timestamp NULL, CONSTRAINT fk_member_group_group_id FOREIGN KEY (group_id) REFERENCES `group` (group_id), diff --git a/backend/core/src/main/resources/db/migration/V2__member_update.sql b/backend/core/src/main/resources/db/migration/V2__member_update.sql index b8b77d290..e4c2d1cbb 100644 --- a/backend/core/src/main/resources/db/migration/V2__member_update.sql +++ b/backend/core/src/main/resources/db/migration/V2__member_update.sql @@ -1,3 +1,3 @@ -- Add new columns ALTER TABLE member - CHANGE COLUMN oauth2_provider social_type VARCHAR (255) NOT NULL; + CHANGE COLUMN oauth2_provider social_type VARCHAR(255) NOT NULL; diff --git a/backend/core/src/main/resources/db/migration/V5__member_update.sql b/backend/core/src/main/resources/db/migration/V5__member_update.sql index 0d88edb97..79c2731e2 100644 --- a/backend/core/src/main/resources/db/migration/V5__member_update.sql +++ b/backend/core/src/main/resources/db/migration/V5__member_update.sql @@ -1,2 +1,3 @@ -- change phone columns type -ALTER TABLE member MODIFY COLUMN phone VARBINARY(255); \ No newline at end of file +ALTER TABLE member + MODIFY COLUMN phone VARBINARY(255); \ No newline at end of file diff --git a/backend/core/src/main/resources/db/migration/V6__capsule_update.sql b/backend/core/src/main/resources/db/migration/V6__capsule_update.sql index fc9223d05..d0bb9d0dd 100644 --- a/backend/core/src/main/resources/db/migration/V6__capsule_update.sql +++ b/backend/core/src/main/resources/db/migration/V6__capsule_update.sql @@ -1,9 +1,9 @@ -- -- change capsule Geography data type ALTER TABLE capsule -DROP -COLUMN longitude, DROP -COLUMN latitude; + COLUMN longitude, + DROP + COLUMN latitude; ALTER TABLE capsule diff --git a/backend/core/src/main/resources/db/migration/V7__address_update.sql b/backend/core/src/main/resources/db/migration/V7__address_update.sql index 007cc74c7..47c587464 100644 --- a/backend/core/src/main/resources/db/migration/V7__address_update.sql +++ b/backend/core/src/main/resources/db/migration/V7__address_update.sql @@ -1,12 +1,18 @@ -- Add new columns -ALTER TABLE capsule ADD COLUMN full_road_address_name VARCHAR(255); -ALTER TABLE capsule ADD COLUMN road_name VARCHAR(255); -ALTER TABLE capsule ADD COLUMN main_building_number VARCHAR(255); -ALTER TABLE capsule ADD COLUMN sub_building_number VARCHAR(255); -ALTER TABLE capsule ADD COLUMN building_name VARCHAR(255); +ALTER TABLE capsule + ADD COLUMN full_road_address_name VARCHAR(255); +ALTER TABLE capsule + ADD COLUMN road_name VARCHAR(255); +ALTER TABLE capsule + ADD COLUMN main_building_number VARCHAR(255); +ALTER TABLE capsule + ADD COLUMN sub_building_number VARCHAR(255); +ALTER TABLE capsule + ADD COLUMN building_name VARCHAR(255); -- Drop old columns -ALTER TABLE capsule DROP COLUMN village; +ALTER TABLE capsule + DROP COLUMN village; alter table capsule modify city varchar(255) null; @@ -18,7 +24,6 @@ alter table capsule modify sub_district varchar(255) null; - -- drop video, image columns ALTER TABLE video DROP diff --git a/backend/core/src/main/resources/db/migration/V8__capsule_member_update.sql b/backend/core/src/main/resources/db/migration/V8__capsule_member_update.sql index b6a974fa1..6a6bc86dd 100644 --- a/backend/core/src/main/resources/db/migration/V8__capsule_member_update.sql +++ b/backend/core/src/main/resources/db/migration/V8__capsule_member_update.sql @@ -1,5 +1,6 @@ -- 외래 키 제약 조건 삭제 -ALTER TABLE capsule DROP FOREIGN KEY fk_capsule_group_id; +ALTER TABLE capsule + DROP FOREIGN KEY fk_capsule_group_id; -- group_id를 NULL로 변경 alter table capsule From 1918d004bd7cfa611824c552ba28245c7cd42624 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sat, 23 Mar 2024 18:20:06 +0900 Subject: [PATCH 085/314] =?UTF-8?q?refact:=20findFriendInvite=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 멤버들도 가져오도록 --- .../friend/repository/FriendInviteRepository.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java index fbb85172b..73693f2aa 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/FriendInviteRepository.java @@ -1,13 +1,25 @@ package site.timecapsulearchive.core.domain.friend.repository; import java.util.Optional; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.Repository; +import org.springframework.data.repository.query.Param; import site.timecapsulearchive.core.domain.friend.entity.FriendInvite; public interface FriendInviteRepository extends Repository { void save(FriendInvite friendInvite); + @Query(value = "select fi " + + "from FriendInvite fi " + + "join fetch fi.owner " + + "join fetch fi.friend " + + "where fi.owner.id =:friendId and fi.friend.id =:memberId") + Optional findFriendInviteWithMembersByOwnerIdAndFriendId( + @Param(value = "memberId") Long memberId, + @Param(value = "friendId") Long friendId + ); + Optional findFriendInviteByOwnerIdAndFriendId(Long memberId, Long friendId); void deleteFriendInviteById(Long id); From 6e99a93db6a0139a6dc42a0211d42e93ad866936 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sat, 23 Mar 2024 18:20:47 +0900 Subject: [PATCH 086/314] =?UTF-8?q?refact:=20=EC=B9=9C=EA=B5=AC=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20=EC=88=98=EB=9D=BD=20Service=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/service/FriendService.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java index 16053c8e3..1fc09ac26 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -80,15 +80,12 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { public void acceptFriend(final Long memberId, final Long friendId) { final FriendInvite friendInvite = friendInviteRepository - .findFriendInviteByOwnerIdAndFriendId(memberId, friendId) + .findFriendInviteWithMembersByOwnerIdAndFriendId(memberId, friendId) .orElseThrow(FriendNotFoundException::new); - final Member owner = memberRepository - .findMemberById(memberId) - .orElseThrow(MemberNotFoundException::new); - final Member friend = memberRepository - .findMemberById(friendId) - .orElseThrow(MemberNotFoundException::new); + Member friend = friendInvite.getOwner(); + Member owner = friendInvite.getFriend(); + final MemberFriend memberFriend = memberFriendMapper.memberToEntity(owner, friend); transactionTemplate.execute(new TransactionCallbackWithoutResult() { @@ -99,7 +96,7 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { } }); - notificationManager.sendFriendAcceptMessage(memberId, friend.getNickname()); + notificationManager.sendFriendAcceptMessage(friendId, owner.getNickname()); } @Transactional From ba56549ba6960144ad0f328856a0bd3e31ff6ffd Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sat, 23 Mar 2024 18:21:04 +0900 Subject: [PATCH 087/314] =?UTF-8?q?refact:=20=EB=A9=94=EC=8B=9C=EC=A7=80?= =?UTF-8?q?=20=EC=A0=84=EC=86=A1=20=EC=A3=BC=EC=B2=B4=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notification/data/mapper/NotificationMapper.java | 8 ++++---- .../infra/notification/manager/NotificationManager.java | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java index 31e7e35bc..72f1be91f 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java @@ -42,14 +42,14 @@ public FriendReqNotificationRequest friendReqToMessage( } public FriendAcceptNotificationRequest friendAcceptToMessage( - final Long memberId, - final String friendNickname + final Long friendId, + final String ownerNickname ) { return FriendAcceptNotificationRequest.builder() - .memberId(memberId) + .memberId(friendId) .status(NOTIFICATION_SEND_SUCCESS) .title("친구 수락 알림") - .text(friendNickname + "가 친구 요청을 수락하였습니다. ARchive에서 확인해보세요!") + .text(ownerNickname + "가 친구 요청을 수락하였습니다. ARchive에서 확인해보세요!") .build(); } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java index e5f50c77a..791b7467f 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java @@ -36,9 +36,9 @@ public void sendFriendReqMessage(final Long friendId, final String ownerNickname } @NotificationRequest - public void sendFriendAcceptMessage(final Long memberId, final String friendNickname) { - final FriendAcceptNotificationRequest request = notificationMapper.friendAcceptToMessage(memberId, - friendNickname); + public void sendFriendAcceptMessage(final Long friendId, final String ownerNickname) { + final FriendAcceptNotificationRequest request = notificationMapper.friendAcceptToMessage(friendId, + ownerNickname); aspect.sendNotification(request, notificationUrl.friendAcceptAlarmUrl()); } From de2c7da9d3bbc79e0ceab95345cf5fe579cbf18e Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sat, 23 Mar 2024 19:03:10 +0900 Subject: [PATCH 088/314] =?UTF-8?q?refact:=20FriendInvite=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=EB=A5=BC=20MemberFriend=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../friend/data/mapper/MemberFriendMapper.java | 9 --------- .../core/domain/friend/entity/FriendInvite.java | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java index f20bcd5d8..bb5fd1d40 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java @@ -7,8 +7,6 @@ import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendSummaryResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; -import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; -import site.timecapsulearchive.core.domain.member.entity.Member; @Component public class MemberFriendMapper { @@ -37,11 +35,4 @@ public FriendRequestsSliceResponse friendRequestsSliceToResponse( return new FriendRequestsSliceResponse(friendRequests, hasNext); } - - public MemberFriend memberToEntity(Member owner, Member friend) { - return MemberFriend.builder() - .owner(owner) - .friend(friend) - .build(); - } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendInvite.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendInvite.java index 83bbb8dc5..613dd432f 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendInvite.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/FriendInvite.java @@ -47,4 +47,19 @@ private FriendInvite(FriendStatus friendStatus, Member owner, Member friend) { this.owner = owner; this.friend = friend; } + + public MemberFriend friendRelation() { + return MemberFriend.builder() + .owner(owner) + .friend(friend) + .build(); + } + + public MemberFriend ownerRelation() { + return MemberFriend.builder() + .owner(friend) + .friend(owner) + .build(); + } + } From d07a8c3ae5ad071a14e5d31e362adf880f37004f Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sat, 23 Mar 2024 19:03:50 +0900 Subject: [PATCH 089/314] =?UTF-8?q?refact:=20=EC=B9=9C=EA=B5=AC=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20=EC=88=98=EB=9D=BD=20Service=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/entity/MemberFriend.java | 5 +++++ .../core/domain/friend/service/FriendService.java | 10 +++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java index e089effda..a905b810a 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java @@ -40,4 +40,9 @@ private MemberFriend(Member owner, Member friend) { this.owner = owner; this.friend = friend; } + + public String getOwnerNickname() { + return owner.getNickname(); + } + } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java index 1fc09ac26..749009f94 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -83,20 +83,20 @@ public void acceptFriend(final Long memberId, final Long friendId) { .findFriendInviteWithMembersByOwnerIdAndFriendId(memberId, friendId) .orElseThrow(FriendNotFoundException::new); - Member friend = friendInvite.getOwner(); - Member owner = friendInvite.getFriend(); + final MemberFriend ownerRelation = friendInvite.ownerRelation(); + final MemberFriend friendRelation = friendInvite.friendRelation(); - final MemberFriend memberFriend = memberFriendMapper.memberToEntity(owner, friend); transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { friendInviteRepository.delete(friendInvite); - memberFriendRepository.save(memberFriend); + memberFriendRepository.save(ownerRelation); + memberFriendRepository.save(friendRelation); } }); - notificationManager.sendFriendAcceptMessage(friendId, owner.getNickname()); + notificationManager.sendFriendAcceptMessage(friendId, ownerRelation.getOwnerNickname()); } @Transactional From 7ae8c2ba94b68796e9be78448a2d23e0c1e412d5 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sat, 23 Mar 2024 19:04:03 +0900 Subject: [PATCH 090/314] =?UTF-8?q?fix:=20=EC=A0=84=EB=8B=AC=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/infra/notification/data/mapper/NotificationMapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java index 72f1be91f..21d6bc799 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java @@ -49,7 +49,7 @@ public FriendAcceptNotificationRequest friendAcceptToMessage( .memberId(friendId) .status(NOTIFICATION_SEND_SUCCESS) .title("친구 수락 알림") - .text(ownerNickname + "가 친구 요청을 수락하였습니다. ARchive에서 확인해보세요!") + .text(ownerNickname + "님이 친구 요청을 수락하였습니다. ARchive에서 확인해보세요!") .build(); } } From 5de30079a7578a9d98c942acedf57bbf8d9f7f2a Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 23 Mar 2024 15:57:06 +0900 Subject: [PATCH 091/314] =?UTF-8?q?feat=20:=20=EB=A9=A4=EB=B2=84=20?= =?UTF-8?q?=EC=97=94=ED=8B=B0=ED=8B=B0=EC=97=90=20=EB=B9=84=EB=B0=80?= =?UTF-8?q?=EB=B2=88=ED=98=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/member/entity/Member.java | 13 ++++++------- .../resources/db/migration/V20__member_update.sql | 2 ++ 2 files changed, 8 insertions(+), 7 deletions(-) create mode 100644 backend/core/src/main/resources/db/migration/V20__member_update.sql diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java index 3e17a98d1..d3c8e6cde 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java @@ -12,7 +12,6 @@ import jakarta.persistence.Table; import jakarta.validation.constraints.Email; import java.util.List; -import java.util.UUID; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -69,6 +68,9 @@ public class Member extends BaseEntity { @Column(name = "auth_id", nullable = false, unique = true) private String authId; + @Column(name = "password") + private String password; + @OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true) private List capsules; @@ -91,14 +93,15 @@ public class Member extends BaseEntity { private List histories; @Builder - private Member(String profileUrl, SocialType socialType, String email, String authId) { + private Member(String profileUrl, SocialType socialType, String email, String authId, String password) { this.profileUrl = profileUrl; - this.nickname = String.valueOf(UUID.randomUUID()); + this.nickname = MakeRandomNickNameUtil.makeRandomNickName(); this.socialType = socialType; this.email = email; this.isVerified = false; this.notificationEnabled = false; this.authId = authId; + this.password = password; } public void updateVerification() { @@ -112,8 +115,4 @@ public void updatePhoneNumber(byte[] phone) { public void updatePhoneHash(byte[] phone_hash) { this.phone_hash = phone_hash; } - - public void updateNickName() { - this.nickname = MakeRandomNickNameUtil.makeRandomNickName(); - } } diff --git a/backend/core/src/main/resources/db/migration/V20__member_update.sql b/backend/core/src/main/resources/db/migration/V20__member_update.sql new file mode 100644 index 000000000..e260e9731 --- /dev/null +++ b/backend/core/src/main/resources/db/migration/V20__member_update.sql @@ -0,0 +1,2 @@ +ALTER TABLE member ADD COLUMN password VARCHAR(255); +ALTER TABLE member MODIFY email VARCHAR(255) NOT NULL, ADD CONSTRAINT unique_email UNIQUE (email); \ No newline at end of file From b206b13ac943fd753c0bb8672ad9183010543462 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 23 Mar 2024 15:57:44 +0900 Subject: [PATCH 092/314] =?UTF-8?q?feat=20:=20=EC=9D=B4=EB=A9=94=EC=9D=BC?= =?UTF-8?q?=20=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85,=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/auth/api/AuthApi.java | 59 +++++++++++++++++++ .../auth/data/request/EmailSignInRequest.java | 17 ++++++ .../auth/data/request/EmailSignUpRequest.java | 17 ++++++ 3 files changed, 93 insertions(+) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignInRequest.java create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignUpRequest.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApi.java index f730a565a..2f568d08b 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApi.java @@ -8,12 +8,14 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement; import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.ResponseEntity; +import site.timecapsulearchive.core.domain.auth.data.request.EmailSignInRequest; import site.timecapsulearchive.core.domain.auth.data.request.SignInRequest; import site.timecapsulearchive.core.domain.auth.data.request.SignUpRequest; import site.timecapsulearchive.core.domain.auth.data.request.TemporaryTokenReIssueRequest; import site.timecapsulearchive.core.domain.auth.data.request.TokenReIssueRequest; import site.timecapsulearchive.core.domain.auth.data.request.VerificationMessageSendRequest; import site.timecapsulearchive.core.domain.auth.data.request.VerificationNumberValidRequest; +import site.timecapsulearchive.core.domain.auth.data.request.EmailSignUpRequest; import site.timecapsulearchive.core.domain.auth.data.response.OAuth2UriResponse; import site.timecapsulearchive.core.domain.auth.data.response.TemporaryTokenResponse; import site.timecapsulearchive.core.domain.auth.data.response.TokenResponse; @@ -253,5 +255,62 @@ ResponseEntity> validVerificationMessage( Long memberId, VerificationNumberValidRequest request ); + + @Operation( + summary = "이메일로 회원가입", + description = """ + 이메일로 회원가입 한다. + + 인증되지 않은 상태이므로 전화 번호 인증을 해야한다. + """, + tags = {"auth"} + ) + @ApiResponses(value = { + @ApiResponse( + responseCode = "200", + description = "ok" + ) + }) + ResponseEntity> signUpWithEmail(EmailSignUpRequest request); + + @Operation( + summary = "이메일로 로그인", + description = """ + 이메일로 로그인 한다. + + 완전히 인증된 상태의 유저만 가능하다. + """, + tags = {"auth"} + ) + @ApiResponses(value = { + @ApiResponse( + responseCode = "200", + description = "ok" + ), + @ApiResponse( + responseCode = "400", + description = """ + 요청이 잘못되어 발생하는 오류이다. +
    +
  • 올바르지 않은 요청인 경우 예외가 발생한다.
  • +
  • 인증되지 않은 사용자인 경우 예외가 발생한다.
  • +
+ """, + content = @Content(schema = @Schema(implementation = ErrorResponse.class)) + ), + @ApiResponse( + responseCode = "401", + description = """ + 이메일 또는 비밀번호가 올바르지 않은 경우 발생하는 오류이다. (일치하지 않는 경우도 포함) + """, + content = @Content(schema = @Schema(implementation = ErrorResponse.class)) + ), + @ApiResponse( + responseCode = "404", + description = "로그인을 요청한 멤버를 찾을 수 없는 경우 예외가 발생한다.", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)) + ) + }) + ResponseEntity> signInWithEmail(EmailSignInRequest request); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignInRequest.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignInRequest.java new file mode 100644 index 000000000..557277e3e --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignInRequest.java @@ -0,0 +1,17 @@ +package site.timecapsulearchive.core.domain.auth.data.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Email; + +@Schema(description = "이메일 로그인 요청") +public record EmailSignInRequest( + + @Schema(description = "이메일") + @Email + String email, + + @Schema(description = "비밀번호") + String password +) { + +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignUpRequest.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignUpRequest.java new file mode 100644 index 000000000..e8b0e7cae --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignUpRequest.java @@ -0,0 +1,17 @@ +package site.timecapsulearchive.core.domain.auth.data.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Email; + +@Schema(description = "이메일 회원가입 요청") +public record EmailSignUpRequest( + + @Schema(description = "사용할 이메일") + @Email + String email, + + @Schema(description = "사용할 비밀번호") + String password +) { + +} From 8fcc65e375c37dd48d2163a16b418ab7184bf3d8 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 23 Mar 2024 15:59:25 +0900 Subject: [PATCH 093/314] =?UTF-8?q?fix=20:=20=EB=8B=89=EB=84=A4=EC=9E=84?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/auth/service/MessageVerificationService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/service/MessageVerificationService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/service/MessageVerificationService.java index 27eabe543..90ae404a2 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/service/MessageVerificationService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/service/MessageVerificationService.java @@ -102,7 +102,6 @@ private void updateMemberData(final Long memberId, final String receiver) { findMember.updatePhoneHash(hashEncryptionManager.encrypt(plain)); findMember.updatePhoneNumber(aesEncryptionManager.encryptWithPrefixIV(plain)); - findMember.updateNickName(); findMember.updateVerification(); } } From 67146e836376238cc3a8fbb4f3231ae476b5b905 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 23 Mar 2024 16:00:35 +0900 Subject: [PATCH 094/314] =?UTF-8?q?feat=20:=20=EB=A9=A4=EB=B2=84=20?= =?UTF-8?q?=EC=9D=B4=EB=A9=94=EC=9D=BC=20=EC=83=81=ED=83=9C=20=EC=B2=B4?= =?UTF-8?q?=ED=81=AC,=20=EC=A4=91=EB=B3=B5=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/member/api/MemberApi.java | 28 +++++++++++++++++++ .../CheckEmailDuplicationResponse.java | 12 ++++++++ 2 files changed, 40 insertions(+) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/response/CheckEmailDuplicationResponse.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApi.java index 71948d3fb..beb04e87b 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApi.java @@ -11,6 +11,7 @@ import site.timecapsulearchive.core.domain.member.data.reqeust.CheckStatusRequest; import site.timecapsulearchive.core.domain.member.data.reqeust.UpdateFCMTokenRequest; import site.timecapsulearchive.core.domain.member.data.reqeust.UpdateNotificationEnabledRequest; +import site.timecapsulearchive.core.domain.member.data.response.CheckEmailDuplicationResponse; import site.timecapsulearchive.core.domain.member.data.response.MemberDetailResponse; import site.timecapsulearchive.core.domain.member.data.response.MemberNotificationSliceResponse; import site.timecapsulearchive.core.domain.member.data.response.MemberStatusResponse; @@ -51,6 +52,19 @@ public interface MemberApi { }) ResponseEntity> checkMemberStatus(CheckStatusRequest request); + @Operation( + summary = "이메일로 유저의 인증 상태를 반환", + description = "이메일로 유저의 인증 상태를 반환한다.", + tags = {"member"} + ) + @ApiResponses(value = { + @ApiResponse( + responseCode = "200", + description = "ok" + ) + }) + ResponseEntity> checkMemberStatusWithEmail(String email); + @Operation( summary = "회원 FCM 토큰 수정", description = "회원의 FCM 토큰을 수정한다.", @@ -117,4 +131,18 @@ ResponseEntity> getMemberNotifications( int size, ZonedDateTime createdAt ); + + @Operation( + summary = "이메일 중복 조회", + description = "이메일의 중복을 조회한다.", + security = {@SecurityRequirement(name = "user_token")}, + tags = {"member"} + ) + @ApiResponses(value = { + @ApiResponse( + responseCode = "200", + description = "처리 완료" + ) + }) + ResponseEntity> checkEmailDuplication(String email); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/response/CheckEmailDuplicationResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/response/CheckEmailDuplicationResponse.java new file mode 100644 index 000000000..80f548e11 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/response/CheckEmailDuplicationResponse.java @@ -0,0 +1,12 @@ +package site.timecapsulearchive.core.domain.member.data.response; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "이메일 중복 여부 응답") +public record CheckEmailDuplicationResponse( + + @Schema(description = "이메일 중복 여부") + Boolean isDuplicated +) { + +} From 4628d40552eff407898a286d59f72a4202a7576c Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 23 Mar 2024 16:01:12 +0900 Subject: [PATCH 095/314] =?UTF-8?q?feat=20:=20EMAIL=20=EC=86=8C=EC=85=9C?= =?UTF-8?q?=20=ED=83=80=EC=9E=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/member/entity/SocialType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/SocialType.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/SocialType.java index 59685e361..ad1591e91 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/SocialType.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/SocialType.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; public enum SocialType { - KAKAO, GOOGLE; + KAKAO, GOOGLE, EMAIL; @JsonCreator public static SocialType from(String s) { From 529666198927a4042911f5bf711087a26af93e5a Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 23 Mar 2024 16:01:32 +0900 Subject: [PATCH 096/314] =?UTF-8?q?feat=20:=20=EC=9D=B4=EB=A9=94=EC=9D=BC,?= =?UTF-8?q?=20=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/CredentialsNotMatchedException.java | 11 +++++++++++ .../core/global/error/ErrorCode.java | 1 + 2 files changed, 12 insertions(+) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/member/exception/CredentialsNotMatchedException.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/exception/CredentialsNotMatchedException.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/exception/CredentialsNotMatchedException.java new file mode 100644 index 000000000..f15c84188 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/exception/CredentialsNotMatchedException.java @@ -0,0 +1,11 @@ +package site.timecapsulearchive.core.domain.member.exception; + +import site.timecapsulearchive.core.global.error.ErrorCode; +import site.timecapsulearchive.core.global.error.exception.BusinessException; + +public class CredentialsNotMatchedException extends BusinessException { + + public CredentialsNotMatchedException() { + super(ErrorCode.CREDENTIALS_NOT_MATCHED_ERROR); + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java index 0ffdce8fd..2a2807559 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java @@ -21,6 +21,7 @@ public enum ErrorCode { //auth AUTHENTICATION_ERROR(401, "AUTH-003", "인증에 실패했습니다. 인증 수단이 유효한지 확인하세요."), AUTHORIZATION_ERROR(403, "AUTH-004", "권한이 존재하지 않습니다."), + CREDENTIALS_NOT_MATCHED_ERROR(401, "AUTH-005", "이메일과 비밀번호 인증에 실패했습니다."), //message TOO_MANY_REQUEST_ERROR(429, "MESSAGE-001", "너무 많은 인증 메시지를 요청했습니다. 24시간 후 요청해주세요."), From 318129e3632c3677e112dbd6dc966b8ae9e18702 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 23 Mar 2024 16:03:03 +0900 Subject: [PATCH 097/314] =?UTF-8?q?feat=20:=20=EC=9D=B4=EB=A9=94=EC=9D=BC?= =?UTF-8?q?=20=EC=A4=91=EB=B3=B5=EA=B2=80=EC=82=AC,=20=EC=83=81=ED=83=9C?= =?UTF-8?q?=EC=B2=B4=ED=81=AC,=20=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85,=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/auth/api/AuthApiController.java | 30 ++++++++++++ .../member/api/MemberApiController.java | 26 ++++++++++ .../data/dto/EmailVerifiedCheckDto.java | 10 ++++ .../member/data/mapper/MemberMapper.java | 8 ++++ .../repository/MemberQueryRepository.java | 37 +++++++++++++++ .../domain/member/service/MemberService.java | 47 +++++++++++++++++++ 6 files changed, 158 insertions(+) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/dto/EmailVerifiedCheckDto.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApiController.java index 594ebdd4c..d33222737 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApiController.java @@ -10,6 +10,8 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import site.timecapsulearchive.core.domain.auth.data.request.EmailSignInRequest; +import site.timecapsulearchive.core.domain.auth.data.request.EmailSignUpRequest; import site.timecapsulearchive.core.domain.auth.data.request.SignInRequest; import site.timecapsulearchive.core.domain.auth.data.request.SignUpRequest; import site.timecapsulearchive.core.domain.auth.data.request.TemporaryTokenReIssueRequest; @@ -201,4 +203,32 @@ public ResponseEntity> validVerificationMessage( ) ); } + + @Override + public ResponseEntity> signUpWithEmail( + @Valid @RequestBody final EmailSignUpRequest request + ) { + final Long id = memberService.createMemberWithEmail(request.email(), request.password()); + + return ResponseEntity.ok( + ApiSpec.success( + SuccessCode.SUCCESS, + tokenService.createTemporaryToken(id) + ) + ); + } + + @Override + public ResponseEntity> signInWithEmail( + @Valid @RequestBody final EmailSignInRequest request + ) { + final Long id = memberService.findVerifiedMemberIdByEmailAndPassword(request.email(), request.password()); + + return ResponseEntity.ok( + ApiSpec.success( + SuccessCode.SUCCESS, + tokenService.createNewToken(id) + ) + ); + } } \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java index 2f76697f6..92deccb3f 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java @@ -1,6 +1,7 @@ package site.timecapsulearchive.core.domain.member.api; import jakarta.validation.Valid; +import jakarta.validation.constraints.Email; import java.time.ZonedDateTime; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -15,6 +16,7 @@ import site.timecapsulearchive.core.domain.member.data.reqeust.CheckStatusRequest; import site.timecapsulearchive.core.domain.member.data.reqeust.UpdateFCMTokenRequest; import site.timecapsulearchive.core.domain.member.data.reqeust.UpdateNotificationEnabledRequest; +import site.timecapsulearchive.core.domain.member.data.response.CheckEmailDuplicationResponse; import site.timecapsulearchive.core.domain.member.data.response.MemberDetailResponse; import site.timecapsulearchive.core.domain.member.data.response.MemberNotificationSliceResponse; import site.timecapsulearchive.core.domain.member.data.response.MemberStatusResponse; @@ -62,6 +64,17 @@ public ResponseEntity> checkMemberStatus( ); } + @Override + public ResponseEntity> checkMemberStatusWithEmail( + @RequestParam(value = "email") @Email String email) { + return ResponseEntity.ok( + ApiSpec.success( + SuccessCode.SUCCESS, + memberService.checkStatusWithEmail(email) + ) + ); + } + @Override @PatchMapping(value = "/fcm_token") public ResponseEntity> updateMemberFCMToken( @@ -100,4 +113,17 @@ public ResponseEntity> getMemberNotific ) ); } + + @GetMapping("/check-duplication/email") + @Override + public ResponseEntity> checkEmailDuplication( + @RequestParam(value = "email") @Email final String email + ) { + return ResponseEntity.ok( + ApiSpec.success( + SuccessCode.SUCCESS, + memberService.checkEmailDuplication(email) + ) + ); + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/dto/EmailVerifiedCheckDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/dto/EmailVerifiedCheckDto.java new file mode 100644 index 000000000..33be7f8df --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/dto/EmailVerifiedCheckDto.java @@ -0,0 +1,10 @@ +package site.timecapsulearchive.core.domain.member.data.dto; + +public record EmailVerifiedCheckDto( + Long memberId, + Boolean isVerified, + String email, + String password +) { + +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java index 432ba0653..2c37a38fe 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java @@ -77,4 +77,12 @@ public MemberNotificationSliceResponse notificationSliceToResponse( return new MemberNotificationSliceResponse(responses, hasNext); } + + public Member createMemberWithEmail(String email, String password) { + return Member.builder() + .email(email) + .password(password) + .socialType(SocialType.EMAIL) + .build(); + } } \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java index fac045b8d..11253ff7f 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java @@ -13,6 +13,7 @@ import org.springframework.data.domain.Slice; import org.springframework.data.domain.SliceImpl; import org.springframework.stereotype.Repository; +import site.timecapsulearchive.core.domain.member.data.dto.EmailVerifiedCheckDto; import site.timecapsulearchive.core.domain.member.data.dto.MemberDetailResponseDto; import site.timecapsulearchive.core.domain.member.data.dto.MemberNotificationDto; import site.timecapsulearchive.core.domain.member.data.dto.VerifiedCheckDto; @@ -111,4 +112,40 @@ private List findMemberNotificationDtos( private boolean canMoreRead(final int size, final int notificationSize) { return notificationSize > size; } + + public Optional findEmailVerifiedCheckDtoByEmailAndPassword( + String email + ) { + return Optional.ofNullable( + query + .select( + Projections.constructor( + EmailVerifiedCheckDto.class, + member.id, + member.isVerified, + member.email, + member.password + ) + ) + .from(member) + .where(member.email.eq(email)) + .fetchOne() + ); + } + + public Boolean checkEmailDuplication(String email) { + Integer count = query.selectOne() + .from(member) + .where(member.email.eq(email)) + .fetchFirst(); + + return count != null; + } + + public Boolean findIsVerifiedByEmail(String email) { + return query.select(member.isVerified) + .from(member) + .where(member.authId.eq(email)) + .fetchOne(); + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java index a1327fad9..d00d9b719 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java @@ -4,19 +4,23 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Slice; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import site.timecapsulearchive.core.domain.member.data.dto.EmailVerifiedCheckDto; import site.timecapsulearchive.core.domain.member.data.dto.MemberDetailResponseDto; import site.timecapsulearchive.core.domain.member.data.dto.MemberNotificationDto; import site.timecapsulearchive.core.domain.member.data.dto.SignUpRequestDto; import site.timecapsulearchive.core.domain.member.data.dto.VerifiedCheckDto; import site.timecapsulearchive.core.domain.member.data.mapper.MemberMapper; +import site.timecapsulearchive.core.domain.member.data.response.CheckEmailDuplicationResponse; import site.timecapsulearchive.core.domain.member.data.response.MemberDetailResponse; import site.timecapsulearchive.core.domain.member.data.response.MemberNotificationSliceResponse; import site.timecapsulearchive.core.domain.member.data.response.MemberStatusResponse; import site.timecapsulearchive.core.domain.member.entity.Member; import site.timecapsulearchive.core.domain.member.entity.SocialType; import site.timecapsulearchive.core.domain.member.exception.AlreadyVerifiedException; +import site.timecapsulearchive.core.domain.member.exception.CredentialsNotMatchedException; import site.timecapsulearchive.core.domain.member.exception.MemberNotFoundException; import site.timecapsulearchive.core.domain.member.exception.NotVerifiedMemberException; import site.timecapsulearchive.core.domain.member.repository.MemberQueryRepository; @@ -32,6 +36,7 @@ public class MemberService { private final MemberRepository memberRepository; private final MemberQueryRepository memberQueryRepository; private final AESEncryptionManager aesEncryptionManager; + private final PasswordEncoder passwordEncoder; private final MemberMapper memberMapper; @@ -172,4 +177,46 @@ public MemberNotificationSliceResponse findNotificationSliceByMemberId( notifications.hasNext() ); } + + @Transactional + public Long createMemberWithEmail(String email, String password) { + final Member member = memberMapper.createMemberWithEmail(email, + passwordEncoder.encode(password)); + + final Member savedMember = memberRepository.save(member); + + return savedMember.getId(); + } + + public Long findVerifiedMemberIdByEmailAndPassword(String email, String password) { + final EmailVerifiedCheckDto dto = memberQueryRepository.findEmailVerifiedCheckDtoByEmailAndPassword( + email) + .orElseThrow(MemberNotFoundException::new); + + if (!dto.isVerified()) { + throw new NotVerifiedMemberException(); + } + + if (!dto.email().equals(email) || !passwordEncoder.matches(password, dto.password())) { + throw new CredentialsNotMatchedException(); + } + + return dto.memberId(); + } + + public CheckEmailDuplicationResponse checkEmailDuplication(String email) { + Boolean isDuplicated = memberQueryRepository.checkEmailDuplication(email); + + return new CheckEmailDuplicationResponse(isDuplicated); + } + + public MemberStatusResponse checkStatusWithEmail(String email) { + final Boolean isVerified = memberQueryRepository.findIsVerifiedByEmail(email); + + if (isVerified == null) { + return MemberStatusResponse.empty(); + } + + return MemberStatusResponse.from(isVerified); + } } From 6b03859e94afe662f870c3c9e87062a6ba6e2682 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 23 Mar 2024 16:05:58 +0900 Subject: [PATCH 098/314] =?UTF-8?q?feat=20:=20request=20mapping=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/auth/api/AuthApiController.java | 10 ++++++++++ .../core/domain/member/api/MemberApiController.java | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApiController.java index d33222737..ad9c8c071 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApiController.java @@ -204,6 +204,11 @@ public ResponseEntity> validVerificationMessage( ); } + @PostMapping( + value = "/sign-up/email", + produces = {"application/json"}, + consumes = {"application/json"} + ) @Override public ResponseEntity> signUpWithEmail( @Valid @RequestBody final EmailSignUpRequest request @@ -218,6 +223,11 @@ public ResponseEntity> signUpWithEmail( ); } + @PostMapping( + value = "/sign-in/email", + produces = {"application/json"}, + consumes = {"application/json"} + ) @Override public ResponseEntity> signInWithEmail( @Valid @RequestBody final EmailSignInRequest request diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java index 92deccb3f..78ebd495e 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java @@ -64,6 +64,11 @@ public ResponseEntity> checkMemberStatus( ); } + @PostMapping( + value = "/status/email", + consumes = {"application/json"}, + produces = {"application/json"} + ) @Override public ResponseEntity> checkMemberStatusWithEmail( @RequestParam(value = "email") @Email String email) { From 736f73b183151e9de3988b50707380fa92d616be Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 23 Mar 2024 16:06:28 +0900 Subject: [PATCH 099/314] =?UTF-8?q?fea=20:=20security=20config=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/global/config/security/SecurityConfig.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/config/security/SecurityConfig.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/config/security/SecurityConfig.java index 117599f84..247ec6d19 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/config/security/SecurityConfig.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/config/security/SecurityConfig.java @@ -86,7 +86,11 @@ private RequestMatcher notRequireAuthenticationMatcher() { antMatcher(HttpMethod.POST, "/auth/sign-in"), antMatcher(HttpMethod.GET, "/auth/login/**"), antMatcher(HttpMethod.GET, "/health"), - antMatcher(HttpMethod.POST, "/auth/temporary-token/re-issue") + antMatcher(HttpMethod.POST, "/auth/temporary-token/re-issue"), + antMatcher(HttpMethod.POST, "/auth/sign-up/email"), + antMatcher(HttpMethod.POST, "/auth/sign-in/email"), + antMatcher(HttpMethod.GET, "/me/status/email"), + antMatcher(HttpMethod.GET, "/me/check-duplication/email") ); } From 264527be6282552d535289fc700c9440f88645c1 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 23 Mar 2024 20:32:20 +0900 Subject: [PATCH 100/314] =?UTF-8?q?feat=20:=20final=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/repository/MemberQueryRepository.java | 6 +++--- .../core/domain/member/service/MemberService.java | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java index 11253ff7f..018bf8e1f 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java @@ -114,7 +114,7 @@ private boolean canMoreRead(final int size, final int notificationSize) { } public Optional findEmailVerifiedCheckDtoByEmailAndPassword( - String email + final String email ) { return Optional.ofNullable( query @@ -133,7 +133,7 @@ public Optional findEmailVerifiedCheckDtoByEmailAndPasswo ); } - public Boolean checkEmailDuplication(String email) { + public Boolean checkEmailDuplication(final String email) { Integer count = query.selectOne() .from(member) .where(member.email.eq(email)) @@ -142,7 +142,7 @@ public Boolean checkEmailDuplication(String email) { return count != null; } - public Boolean findIsVerifiedByEmail(String email) { + public Boolean findIsVerifiedByEmail(final String email) { return query.select(member.isVerified) .from(member) .where(member.authId.eq(email)) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java index d00d9b719..d960127ca 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java @@ -179,16 +179,16 @@ public MemberNotificationSliceResponse findNotificationSliceByMemberId( } @Transactional - public Long createMemberWithEmail(String email, String password) { - final Member member = memberMapper.createMemberWithEmail(email, - passwordEncoder.encode(password)); + public Long createMemberWithEmail(final String email, final String password) { + final String encodedPassword = passwordEncoder.encode(password); + final Member member = memberMapper.createMemberWithEmail(email, encodedPassword); final Member savedMember = memberRepository.save(member); return savedMember.getId(); } - public Long findVerifiedMemberIdByEmailAndPassword(String email, String password) { + public Long findVerifiedMemberIdByEmailAndPassword(final String email, final String password) { final EmailVerifiedCheckDto dto = memberQueryRepository.findEmailVerifiedCheckDtoByEmailAndPassword( email) .orElseThrow(MemberNotFoundException::new); From 33d27e71839aaab4450261a26619118ae427636f Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 23 Mar 2024 20:32:28 +0900 Subject: [PATCH 101/314] =?UTF-8?q?feat=20:=20validation=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/auth/data/request/EmailSignInRequest.java | 2 ++ .../core/domain/auth/data/request/EmailSignUpRequest.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignInRequest.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignInRequest.java index 557277e3e..5d6f8f8bb 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignInRequest.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignInRequest.java @@ -2,6 +2,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotNull; @Schema(description = "이메일 로그인 요청") public record EmailSignInRequest( @@ -11,6 +12,7 @@ public record EmailSignInRequest( String email, @Schema(description = "비밀번호") + @NotNull String password ) { diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignUpRequest.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignUpRequest.java index e8b0e7cae..28538a819 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignUpRequest.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignUpRequest.java @@ -2,6 +2,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotNull; @Schema(description = "이메일 회원가입 요청") public record EmailSignUpRequest( @@ -11,6 +12,7 @@ public record EmailSignUpRequest( String email, @Schema(description = "사용할 비밀번호") + @NotNull String password ) { From 14959dac59f681187cf0d4e0aebf3c12cb0186aa Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 23 Mar 2024 20:33:55 +0900 Subject: [PATCH 102/314] =?UTF-8?q?fix=20:=20=EC=9D=B4=EB=A9=94=EC=9D=BC?= =?UTF-8?q?=20=EA=B2=80=EC=A6=9D=20API=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/member/api/MemberApi.java | 13 ------------- .../domain/member/api/MemberApiController.java | 16 ---------------- .../member/repository/MemberQueryRepository.java | 7 ------- .../domain/member/service/MemberService.java | 10 ---------- 4 files changed, 46 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApi.java index beb04e87b..f89c49e88 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApi.java @@ -52,19 +52,6 @@ public interface MemberApi { }) ResponseEntity> checkMemberStatus(CheckStatusRequest request); - @Operation( - summary = "이메일로 유저의 인증 상태를 반환", - description = "이메일로 유저의 인증 상태를 반환한다.", - tags = {"member"} - ) - @ApiResponses(value = { - @ApiResponse( - responseCode = "200", - description = "ok" - ) - }) - ResponseEntity> checkMemberStatusWithEmail(String email); - @Operation( summary = "회원 FCM 토큰 수정", description = "회원의 FCM 토큰을 수정한다.", diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java index 78ebd495e..1c5a525e3 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java @@ -64,22 +64,6 @@ public ResponseEntity> checkMemberStatus( ); } - @PostMapping( - value = "/status/email", - consumes = {"application/json"}, - produces = {"application/json"} - ) - @Override - public ResponseEntity> checkMemberStatusWithEmail( - @RequestParam(value = "email") @Email String email) { - return ResponseEntity.ok( - ApiSpec.success( - SuccessCode.SUCCESS, - memberService.checkStatusWithEmail(email) - ) - ); - } - @Override @PatchMapping(value = "/fcm_token") public ResponseEntity> updateMemberFCMToken( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java index 018bf8e1f..ef55a4ca7 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java @@ -141,11 +141,4 @@ public Boolean checkEmailDuplication(final String email) { return count != null; } - - public Boolean findIsVerifiedByEmail(final String email) { - return query.select(member.isVerified) - .from(member) - .where(member.authId.eq(email)) - .fetchOne(); - } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java index d960127ca..9fdc5b8d6 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java @@ -209,14 +209,4 @@ public CheckEmailDuplicationResponse checkEmailDuplication(String email) { return new CheckEmailDuplicationResponse(isDuplicated); } - - public MemberStatusResponse checkStatusWithEmail(String email) { - final Boolean isVerified = memberQueryRepository.findIsVerifiedByEmail(email); - - if (isVerified == null) { - return MemberStatusResponse.empty(); - } - - return MemberStatusResponse.from(isVerified); - } } From 5f6750225e6be696f64d1ec05e0928ceaf2727e2 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 23 Mar 2024 20:37:54 +0900 Subject: [PATCH 103/314] =?UTF-8?q?feat=20:=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EB=AC=B8=EC=84=9C=ED=99=94=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timecapsulearchive/core/domain/member/api/MemberApi.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApi.java index f89c49e88..0db90967f 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApi.java @@ -129,6 +129,10 @@ ResponseEntity> getMemberNotifications( @ApiResponse( responseCode = "200", description = "처리 완료" + ), + @ApiResponse( + responseCode = "400", + description = "입력 이메일이 없거나 형식이 안맞는 경우 발생하는 예외" ) }) ResponseEntity> checkEmailDuplication(String email); From 1733fc562153ba2851cc46656a85df4cf29b0970 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 23 Mar 2024 21:25:56 +0900 Subject: [PATCH 104/314] =?UTF-8?q?feat=20:=20authId,=20profileUrl=20?= =?UTF-8?q?=EA=B8=B0=EB=B3=B8=20=EA=B0=92=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 이메일 회원가입 시 default 값들 추가 --- .../core/domain/member/data/mapper/MemberMapper.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java index 2c37a38fe..666b4e96a 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java @@ -2,6 +2,7 @@ import java.time.ZoneId; import java.util.List; +import java.util.UUID; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import site.timecapsulearchive.core.domain.auth.data.request.SignUpRequest; @@ -82,6 +83,8 @@ public Member createMemberWithEmail(String email, String password) { return Member.builder() .email(email) .password(password) + .authId(String.valueOf(UUID.randomUUID())) + .profileUrl("") .socialType(SocialType.EMAIL) .build(); } From 19ae27899807881c64266b47466d345690b35973 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 23 Mar 2024 21:26:34 +0900 Subject: [PATCH 105/314] =?UTF-8?q?feat=20:=20=EC=A4=91=EB=B3=B5=20?= =?UTF-8?q?=EC=B2=B4=ED=81=AC=20=EC=BF=BC=EB=A6=AC=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/MemberQueryRepositoryTest.java | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 backend/core/src/test/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryTest.java diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryTest.java new file mode 100644 index 000000000..bb729a946 --- /dev/null +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryTest.java @@ -0,0 +1,66 @@ +package site.timecapsulearchive.core.domain.member.repository; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import jakarta.persistence.EntityManager; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.TestConstructor; +import org.springframework.test.context.TestConstructor.AutowireMode; +import org.springframework.transaction.annotation.Transactional; +import site.timecapsulearchive.core.common.RepositoryTest; +import site.timecapsulearchive.core.domain.member.entity.Member; +import site.timecapsulearchive.core.domain.member.entity.SocialType; + +@TestConstructor(autowireMode = AutowireMode.ALL) +class MemberQueryRepositoryTest extends RepositoryTest { + + private final MemberQueryRepository memberQueryRepository; + + MemberQueryRepositoryTest(EntityManager entityManager) { + this.memberQueryRepository = new MemberQueryRepository( + new JPAQueryFactory(entityManager)); + } + + @Transactional + @BeforeEach + void setup(@Autowired EntityManager entityManager) { + Member owner = getMember(); + entityManager.persist(owner); + } + + private Member getMember() { + return Member.builder() + .socialType(SocialType.GOOGLE) + .email(0 + "test@google.com") + .authId(0 + "test") + .profileUrl(0 + "test.com") + .build(); + } + + @Test + void 중복_이메일로_중복_체크_테스트() { + //given + String duplicatedEmail = "0test@google.com"; + + //when + Boolean isDuplicated = memberQueryRepository.checkEmailDuplication(duplicatedEmail); + + //then + assertThat(isDuplicated).isTrue(); + } + + @Test + void 고유한_이메일로_중복_체크_테스트() { + //given + String uniqueEmail = "unique@google.com"; + + //when + Boolean isDuplicated = memberQueryRepository.checkEmailDuplication(uniqueEmail); + + //then + assertThat(isDuplicated).isFalse(); + } +} \ No newline at end of file From 3a669695773310ba74a394bfbd25b9166a4aedc9 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 23 Mar 2024 21:26:53 +0900 Subject: [PATCH 106/314] =?UTF-8?q?feat=20:=20=EC=9D=B4=EB=A9=94=EC=9D=BC?= =?UTF-8?q?=20=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=20=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/service/MemberServiceTest.java | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 backend/core/src/test/java/site/timecapsulearchive/core/domain/member/service/MemberServiceTest.java diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/service/MemberServiceTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/service/MemberServiceTest.java new file mode 100644 index 000000000..cf788a96d --- /dev/null +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/service/MemberServiceTest.java @@ -0,0 +1,136 @@ +package site.timecapsulearchive.core.domain.member.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +import java.util.Optional; +import org.junit.jupiter.api.Test; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import site.timecapsulearchive.core.domain.member.data.dto.EmailVerifiedCheckDto; +import site.timecapsulearchive.core.domain.member.data.mapper.MemberMapper; +import site.timecapsulearchive.core.domain.member.exception.CredentialsNotMatchedException; +import site.timecapsulearchive.core.domain.member.exception.MemberNotFoundException; +import site.timecapsulearchive.core.domain.member.exception.NotVerifiedMemberException; +import site.timecapsulearchive.core.domain.member.repository.MemberQueryRepository; +import site.timecapsulearchive.core.domain.member.repository.MemberRepository; +import site.timecapsulearchive.core.global.security.encryption.AESEncryptionManager; + +class MemberServiceTest { + + private final MemberRepository memberRepository = mock(MemberRepository.class); + private final MemberQueryRepository memberQueryRepository = mock(MemberQueryRepository.class); + private final AESEncryptionManager aesEncryptionManager = mock(AESEncryptionManager.class); + private final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + private final MemberMapper memberMapper = mock(MemberMapper.class); + + private final MemberService memberService = new MemberService( + memberRepository, + memberQueryRepository, + aesEncryptionManager, + passwordEncoder, + memberMapper + ); + + @Test + void 이메일과_패스워드로_존재하지_않는_회원_아이디_검색_테스트() { + //given + String email = "test@google.com"; + String password = "test-password"; + given(memberQueryRepository.findEmailVerifiedCheckDtoByEmailAndPassword(anyString())) + .willReturn(Optional.empty()); + + //when, then + assertThatThrownBy( + () -> memberService.findVerifiedMemberIdByEmailAndPassword(email, password)) + .isExactlyInstanceOf(MemberNotFoundException.class); + } + + @Test + void 이메일과_패스워드로_검증된_회원_아이디_검색_테스트() { + //given + String email = "test@google.com"; + String password = "test-password"; + given(memberQueryRepository.findEmailVerifiedCheckDtoByEmailAndPassword(anyString())) + .willReturn(getVerifiedCheckDto(Boolean.TRUE, email, password)); + + //when + Long id = memberService.findVerifiedMemberIdByEmailAndPassword( + email, password); + + //then + assertThat(id).isNotNull(); + } + + private Optional getVerifiedCheckDto(Boolean isVerified, String email, + String password) { + return Optional.of( + new EmailVerifiedCheckDto( + 1L, + isVerified, + email, + passwordEncoder.encode(password) + ) + ); + } + + @Test + void 이메일과_패스워드로_검증되지_않은_회원_아이디_검색_테스트() { + //given + String email = "test@google.com"; + String password = "test-password"; + given(memberQueryRepository.findEmailVerifiedCheckDtoByEmailAndPassword(anyString())) + .willReturn(getVerifiedCheckDto(Boolean.FALSE, email, password)); + + //when, then + assertThatThrownBy( + () -> memberService.findVerifiedMemberIdByEmailAndPassword(email, password)) + .isExactlyInstanceOf(NotVerifiedMemberException.class); + } + + @Test + void 올바르지_않은_이메일로_검증된_회원_아이디_검색_테스트() { + //given + String email = "test@google.com"; + String password = "test-password"; + given(memberQueryRepository.findEmailVerifiedCheckDtoByEmailAndPassword(anyString())) + .willReturn(getVerifiedCheckDto(Boolean.TRUE, email, password)); + + //when, then + assertThatThrownBy( + () -> memberService.findVerifiedMemberIdByEmailAndPassword(email + "trash", password)) + .isExactlyInstanceOf(CredentialsNotMatchedException.class); + } + + @Test + void 올바르지_않은_비밀번호로_검증된_회원_아이디_검색_테스트() { + //given + String email = "test@google.com"; + String password = "test-password"; + given(memberQueryRepository.findEmailVerifiedCheckDtoByEmailAndPassword(anyString())) + .willReturn(getVerifiedCheckDto(Boolean.TRUE, email, password)); + + //when, then + assertThatThrownBy( + () -> memberService.findVerifiedMemberIdByEmailAndPassword(email, password + "trash")) + .isExactlyInstanceOf(CredentialsNotMatchedException.class); + } + + @Test + void 올바르지_않은_이메일과_비밀번호로_검증된_회원_아이디_검색_테스트() { + //given + String email = "test@google.com"; + String password = "test-password"; + given(memberQueryRepository.findEmailVerifiedCheckDtoByEmailAndPassword(anyString())) + .willReturn(getVerifiedCheckDto(Boolean.TRUE, email, password)); + + //when, then + assertThatThrownBy( + () -> memberService.findVerifiedMemberIdByEmailAndPassword(email + "password", + password + "trash")) + .isExactlyInstanceOf(CredentialsNotMatchedException.class); + } +} From d30109eef141076925c1b47d55647ffb8e213ce8 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 23 Mar 2024 21:45:29 +0900 Subject: [PATCH 107/314] =?UTF-8?q?style=20:=20=EA=B5=AC=EA=B8=80=20?= =?UTF-8?q?=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timecapsulearchive/core/domain/auth/api/AuthApi.java | 2 +- .../core/domain/auth/api/AuthApiController.java | 3 ++- .../friend/repository/MemberFriendQueryRepository.java | 2 +- .../core/domain/friend/service/FriendService.java | 1 - .../timecapsulearchive/core/domain/member/entity/Member.java | 3 ++- .../timecapsulearchive/core/global/error/ErrorResponse.java | 3 ++- .../core/global/error/GlobalExceptionHandler.java | 5 +++-- .../core/infra/notification/manager/NotificationManager.java | 3 ++- 8 files changed, 13 insertions(+), 9 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApi.java index 2f568d08b..b059bb8d8 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApi.java @@ -9,13 +9,13 @@ import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.ResponseEntity; import site.timecapsulearchive.core.domain.auth.data.request.EmailSignInRequest; +import site.timecapsulearchive.core.domain.auth.data.request.EmailSignUpRequest; import site.timecapsulearchive.core.domain.auth.data.request.SignInRequest; import site.timecapsulearchive.core.domain.auth.data.request.SignUpRequest; import site.timecapsulearchive.core.domain.auth.data.request.TemporaryTokenReIssueRequest; import site.timecapsulearchive.core.domain.auth.data.request.TokenReIssueRequest; import site.timecapsulearchive.core.domain.auth.data.request.VerificationMessageSendRequest; import site.timecapsulearchive.core.domain.auth.data.request.VerificationNumberValidRequest; -import site.timecapsulearchive.core.domain.auth.data.request.EmailSignUpRequest; import site.timecapsulearchive.core.domain.auth.data.response.OAuth2UriResponse; import site.timecapsulearchive.core.domain.auth.data.response.TemporaryTokenResponse; import site.timecapsulearchive.core.domain.auth.data.response.TokenResponse; diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApiController.java index ad9c8c071..d8b7f7766 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApiController.java @@ -232,7 +232,8 @@ public ResponseEntity> signUpWithEmail( public ResponseEntity> signInWithEmail( @Valid @RequestBody final EmailSignInRequest request ) { - final Long id = memberService.findVerifiedMemberIdByEmailAndPassword(request.email(), request.password()); + final Long id = memberService.findVerifiedMemberIdByEmailAndPassword(request.email(), + request.password()); return ResponseEntity.ok( ApiSpec.success( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java index d56f61cf7..71919fbd8 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java @@ -61,7 +61,7 @@ public Slice findFriendRequestsSlice( final int size, final ZonedDateTime createdAt ) { - List friends = jpaQueryFactory + List friends = jpaQueryFactory .select( Projections.constructor( FriendSummaryDto.class, diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java index 749009f94..e172586aa 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -86,7 +86,6 @@ public void acceptFriend(final Long memberId, final Long friendId) { final MemberFriend ownerRelation = friendInvite.ownerRelation(); final MemberFriend friendRelation = friendInvite.friendRelation(); - transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java index d3c8e6cde..850a86a78 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java @@ -93,7 +93,8 @@ public class Member extends BaseEntity { private List histories; @Builder - private Member(String profileUrl, SocialType socialType, String email, String authId, String password) { + private Member(String profileUrl, SocialType socialType, String email, String authId, + String password) { this.profileUrl = profileUrl; this.nickname = MakeRandomNickNameUtil.makeRandomNickName(); this.socialType = socialType; diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorResponse.java index 08ef89382..1356e94cf 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorResponse.java @@ -45,7 +45,7 @@ public static ErrorResponse fromParameter( List.of(Error.fromParameter(parameterName)) ); } - + public static ErrorResponse fromType( final ErrorCode errorCode, final String parameterName, @@ -63,6 +63,7 @@ public record Error( String value, String reason ) { + public static Error fromType(final String parameterName, final String value) { return new Error(parameterName, value, "입력 파라미터의 타입이 올바르지 않습니다."); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/GlobalExceptionHandler.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/GlobalExceptionHandler.java index ae5c51c83..d7435216d 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/GlobalExceptionHandler.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/GlobalExceptionHandler.java @@ -27,7 +27,8 @@ public class GlobalExceptionHandler { protected ResponseEntity handleGlobalException(final Exception e) { log.error(e.getMessage(), e); - final ErrorResponse errorResponse = ErrorResponse.fromErrorCode(ErrorCode.INTERNAL_SERVER_ERROR); + final ErrorResponse errorResponse = ErrorResponse.fromErrorCode( + ErrorCode.INTERNAL_SERVER_ERROR); return ResponseEntity.status(INTERNAL_SERVER_ERROR.getStatus()) .body(errorResponse); } @@ -96,7 +97,7 @@ protected ResponseEntity handleMethodArgumentTypeMismatchExceptio MethodArgumentTypeMismatchException e ) { log.warn(e.getMessage(), e); - + final ErrorResponse errorResponse = ErrorResponse.fromType( REQUEST_PARAMETER_TYPE_NOT_MATCH_ERROR, e.getParameter().getParameterName(), diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java index 791b7467f..a43b017f0 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java @@ -37,7 +37,8 @@ public void sendFriendReqMessage(final Long friendId, final String ownerNickname @NotificationRequest public void sendFriendAcceptMessage(final Long friendId, final String ownerNickname) { - final FriendAcceptNotificationRequest request = notificationMapper.friendAcceptToMessage(friendId, + final FriendAcceptNotificationRequest request = notificationMapper.friendAcceptToMessage( + friendId, ownerNickname); aspect.sendNotification(request, notificationUrl.friendAcceptAlarmUrl()); From 08829015f4298ba76a6d59af37659cb8840f1c85 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 23 Mar 2024 23:26:38 +0900 Subject: [PATCH 108/314] =?UTF-8?q?fix=20:=20=EA=B8=B0=EC=A1=B4=20?= =?UTF-8?q?=EC=A1=B0=EA=B1=B4=20=ED=95=A8=EC=88=98=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EB=B0=8F=20=EC=83=88=EB=A1=9C=EC=9A=B4=20=EC=A1=B0=EA=B1=B4=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/service/MemberService.java | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java index 9fdc5b8d6..a22b168d2 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java @@ -94,17 +94,13 @@ public Long findVerifiedMemberIdByAuthIdAndSocialType( authId, socialType) .orElseThrow(MemberNotFoundException::new); - if (isNotVerified(dto)) { + if (!dto.isVerified()) { throw new NotVerifiedMemberException(); } return dto.memberId(); } - private boolean isNotVerified(final VerifiedCheckDto dto) { - return !dto.isVerified(); - } - /** * 인증 아이디와 소셜 프로바이더 타입을 받아 인증되지 않은 회원을 조회한다. * @@ -121,17 +117,13 @@ public Long findNotVerifiedMemberIdByAuthIdAndSocialType( authId, socialType) .orElseThrow(MemberNotFoundException::new); - if (isVerified(dto)) { + if (dto.isVerified()) { throw new AlreadyVerifiedException(); } return dto.memberId(); } - private boolean isVerified(final VerifiedCheckDto dto) { - return dto.isVerified(); - } - public MemberDetailResponse findMemberDetailById(final Long memberId) { final MemberDetailResponseDto dto = memberQueryRepository.findMemberDetailResponseDtoById( memberId) @@ -197,13 +189,24 @@ public Long findVerifiedMemberIdByEmailAndPassword(final String email, final Str throw new NotVerifiedMemberException(); } - if (!dto.email().equals(email) || !passwordEncoder.matches(password, dto.password())) { + if (isNotMatched(email, password, dto.email(), dto.password())) { throw new CredentialsNotMatchedException(); } return dto.memberId(); } + private boolean isNotMatched( + String inputEmail, + String inputPassword, + String email, + String password + ) { + return !inputEmail.equals(email) || + password == null || + !passwordEncoder.matches(inputPassword, password); + } + public CheckEmailDuplicationResponse checkEmailDuplication(String email) { Boolean isDuplicated = memberQueryRepository.checkEmailDuplication(email); From 121e9b55535dda18f1d8e427797f809b0fc14309 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 23 Mar 2024 23:26:55 +0900 Subject: [PATCH 109/314] =?UTF-8?q?feat=20:=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20null=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BC=80?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/service/MemberServiceTest.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/service/MemberServiceTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/service/MemberServiceTest.java index cf788a96d..ff49208a8 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/service/MemberServiceTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/service/MemberServiceTest.java @@ -72,7 +72,7 @@ private Optional getVerifiedCheckDto(Boolean isVerified, 1L, isVerified, email, - passwordEncoder.encode(password) + (password == null) ? null : passwordEncoder.encode(password) ) ); } @@ -119,6 +119,20 @@ private Optional getVerifiedCheckDto(Boolean isVerified, .isExactlyInstanceOf(CredentialsNotMatchedException.class); } + @Test + void 비밀번호가_없는_검증된_회원_아이디_검색_테스트() { + //given + String email = "test@google.com"; + String password = "test-password"; + given(memberQueryRepository.findEmailVerifiedCheckDtoByEmailAndPassword(anyString())) + .willReturn(getVerifiedCheckDto(Boolean.TRUE, email, null)); + + //when, then + assertThatThrownBy( + () -> memberService.findVerifiedMemberIdByEmailAndPassword(email, password)) + .isExactlyInstanceOf(CredentialsNotMatchedException.class); + } + @Test void 올바르지_않은_이메일과_비밀번호로_검증된_회원_아이디_검색_테스트() { //given From 9eb1edda5905126564e13ca25f91469d471b817a Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 23 Mar 2024 23:56:00 +0900 Subject: [PATCH 110/314] =?UTF-8?q?fix=20:=20NotBlank=20validation=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/auth/data/request/EmailSignInRequest.java | 5 +++-- .../core/domain/auth/data/request/EmailSignUpRequest.java | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignInRequest.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignInRequest.java index 5d6f8f8bb..2566946f7 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignInRequest.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignInRequest.java @@ -2,17 +2,18 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.NotBlank; @Schema(description = "이메일 로그인 요청") public record EmailSignInRequest( @Schema(description = "이메일") + @NotBlank @Email String email, @Schema(description = "비밀번호") - @NotNull + @NotBlank String password ) { diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignUpRequest.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignUpRequest.java index 28538a819..9d220b3ba 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignUpRequest.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/data/request/EmailSignUpRequest.java @@ -2,17 +2,18 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.NotBlank; @Schema(description = "이메일 회원가입 요청") public record EmailSignUpRequest( @Schema(description = "사용할 이메일") + @NotBlank @Email String email, @Schema(description = "사용할 비밀번호") - @NotNull + @NotBlank String password ) { From f36a055d6fd3c40bfbdfaafabf56cdfb1a72cb06 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sun, 24 Mar 2024 00:00:05 +0900 Subject: [PATCH 111/314] =?UTF-8?q?fix=20:=20=EC=9D=B4=EB=A9=94=EC=9D=BC?= =?UTF-8?q?=20=EC=A4=91=EB=B3=B5=20=EA=B2=80=EC=A6=9D=20api=20get=20->=20p?= =?UTF-8?q?ost=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/member/api/MemberApi.java | 4 +++- .../domain/member/api/MemberApiController.java | 7 ++++--- .../reqeust/CheckEmailDuplicationRequest.java | 16 ++++++++++++++++ .../global/config/security/SecurityConfig.java | 3 +-- 4 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/reqeust/CheckEmailDuplicationRequest.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApi.java index 0db90967f..dfc4c058d 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApi.java @@ -8,6 +8,7 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement; import java.time.ZonedDateTime; import org.springframework.http.ResponseEntity; +import site.timecapsulearchive.core.domain.member.data.reqeust.CheckEmailDuplicationRequest; import site.timecapsulearchive.core.domain.member.data.reqeust.CheckStatusRequest; import site.timecapsulearchive.core.domain.member.data.reqeust.UpdateFCMTokenRequest; import site.timecapsulearchive.core.domain.member.data.reqeust.UpdateNotificationEnabledRequest; @@ -135,5 +136,6 @@ ResponseEntity> getMemberNotifications( description = "입력 이메일이 없거나 형식이 안맞는 경우 발생하는 예외" ) }) - ResponseEntity> checkEmailDuplication(String email); + ResponseEntity> checkEmailDuplication( + CheckEmailDuplicationRequest request); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java index 1c5a525e3..3dec2cd5e 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java @@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import site.timecapsulearchive.core.domain.member.data.reqeust.CheckEmailDuplicationRequest; import site.timecapsulearchive.core.domain.member.data.reqeust.CheckStatusRequest; import site.timecapsulearchive.core.domain.member.data.reqeust.UpdateFCMTokenRequest; import site.timecapsulearchive.core.domain.member.data.reqeust.UpdateNotificationEnabledRequest; @@ -103,15 +104,15 @@ public ResponseEntity> getMemberNotific ); } - @GetMapping("/check-duplication/email") + @PostMapping("/check-duplication/email") @Override public ResponseEntity> checkEmailDuplication( - @RequestParam(value = "email") @Email final String email + @Valid @RequestBody CheckEmailDuplicationRequest request ) { return ResponseEntity.ok( ApiSpec.success( SuccessCode.SUCCESS, - memberService.checkEmailDuplication(email) + memberService.checkEmailDuplication(request.email()) ) ); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/reqeust/CheckEmailDuplicationRequest.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/reqeust/CheckEmailDuplicationRequest.java new file mode 100644 index 000000000..72bf19213 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/reqeust/CheckEmailDuplicationRequest.java @@ -0,0 +1,16 @@ +package site.timecapsulearchive.core.domain.member.data.reqeust; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; + +@Schema(description = "이메일 중복 검증 요청") +public record CheckEmailDuplicationRequest( + + @Schema(description = "중복 검증할 이메일") + @NotBlank + @Email + String email +) { + +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/config/security/SecurityConfig.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/config/security/SecurityConfig.java index 247ec6d19..1d817aa16 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/config/security/SecurityConfig.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/config/security/SecurityConfig.java @@ -89,8 +89,7 @@ private RequestMatcher notRequireAuthenticationMatcher() { antMatcher(HttpMethod.POST, "/auth/temporary-token/re-issue"), antMatcher(HttpMethod.POST, "/auth/sign-up/email"), antMatcher(HttpMethod.POST, "/auth/sign-in/email"), - antMatcher(HttpMethod.GET, "/me/status/email"), - antMatcher(HttpMethod.GET, "/me/check-duplication/email") + antMatcher(HttpMethod.POST, "/me/check-duplication/email") ); } From 83afe6a1131bdf946e34c1184ecdee010c7e8ef9 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 24 Mar 2024 11:55:11 +0900 Subject: [PATCH 112/314] =?UTF-8?q?refact:=20MemberFriend=20status=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/entity/MemberFriend.java | 8 -------- .../core/domain/friend/service/FriendService.java | 8 ++++---- .../db/migration/V21__member_friend_add_friendstatus.sql | 2 -- 3 files changed, 4 insertions(+), 14 deletions(-) delete mode 100644 backend/core/src/main/resources/db/migration/V21__member_friend_add_friendstatus.sql diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java index 7e58fcc0b..03e6250b7 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java @@ -29,10 +29,6 @@ public class MemberFriend extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(name = "friend_status") - @Enumerated(EnumType.STRING) - private FriendStatus friendStatus; - @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "owner_id", nullable = false) private Member owner; @@ -46,8 +42,4 @@ private MemberFriend(Member owner, Member friend) { this.owner = owner; this.friend = friend; } - - public boolean isFriend() { - return this.friendStatus.equals(FriendStatus.ACCEPTED); - } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java index dfd6da9a7..109635b12 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -1,6 +1,7 @@ package site.timecapsulearchive.core.domain.friend.service; import java.time.ZonedDateTime; +import java.util.Optional; import org.springframework.data.domain.Slice; import org.springframework.stereotype.Service; import org.springframework.transaction.PlatformTransactionManager; @@ -126,10 +127,9 @@ public FriendSearchResponse searchFriend(final Long memberId, final String tag) final Member friend = memberRepository.findMemberByTag(tag) .orElseThrow(MemberNotFoundException::new); - final MemberFriend memberFriend = memberFriendRepository - .findMemberFriendByOwnerIdAndFriendId(memberId, friend.getId()) - .orElseThrow(FriendNotFoundException::new); + final Optional memberFriend = memberFriendRepository + .findMemberFriendByOwnerIdAndFriendId(memberId, friend.getId()); - return memberFriendMapper.friendSearchDtoToResponse(friend, memberFriend.isFriend()); + return memberFriendMapper.friendSearchDtoToResponse(friend, memberFriend.isPresent()); } } diff --git a/backend/core/src/main/resources/db/migration/V21__member_friend_add_friendstatus.sql b/backend/core/src/main/resources/db/migration/V21__member_friend_add_friendstatus.sql deleted file mode 100644 index c3008c72e..000000000 --- a/backend/core/src/main/resources/db/migration/V21__member_friend_add_friendstatus.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE member_friend - ADD COLUMN friend_status VARCHAR(255); \ No newline at end of file From a029383fe1168ba6eb082204252e1878d66f8060 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 24 Mar 2024 11:55:29 +0900 Subject: [PATCH 113/314] =?UTF-8?q?refact:=20Member=20=EA=B0=9D=EC=B2=B4?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/data/mapper/MemberMapper.java | 8 +++++++- .../core/domain/member/entity/Member.java | 15 ++++----------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java index 432ba0653..9a5c965a6 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java @@ -1,5 +1,6 @@ package site.timecapsulearchive.core.domain.member.data.mapper; +import com.aventrix.jnanoid.jnanoid.NanoIdUtils; import java.time.ZoneId; import java.util.List; import lombok.RequiredArgsConstructor; @@ -14,6 +15,7 @@ import site.timecapsulearchive.core.domain.member.entity.Member; import site.timecapsulearchive.core.domain.member.entity.SocialType; import site.timecapsulearchive.core.global.security.oauth.dto.OAuth2UserInfo; +import site.timecapsulearchive.core.global.util.nickname.MakeRandomNickNameUtil; import site.timecapsulearchive.core.infra.s3.manager.S3PreSignedUrlManager; @Component @@ -30,9 +32,11 @@ public Member OAuthToEntity( ) { return Member.builder() .authId(authId) - .socialType(socialType) + .nickname(MakeRandomNickNameUtil.makeRandomNickName()) .email(oAuth2UserInfo.getEmail()) .profileUrl(oAuth2UserInfo.getImageUrl()) + .socialType(socialType) + .tag(NanoIdUtils.randomNanoId()) .build(); } @@ -48,9 +52,11 @@ public SignUpRequestDto signUpRequestToDto(final SignUpRequest request) { public Member signUpRequestDtoToEntity(final SignUpRequestDto dto) { return Member.builder() .authId(dto.authId()) + .nickname(MakeRandomNickNameUtil.makeRandomNickName()) .email(dto.email()) .profileUrl(dto.profileUrl()) .socialType(dto.socialType()) + .tag(NanoIdUtils.randomNanoId()) .build(); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java index 97737fad8..d33cc0bf5 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java @@ -94,15 +94,16 @@ public class Member extends BaseEntity { private List histories; @Builder - private Member(String profileUrl, SocialType socialType, String email, String authId) { + private Member(String profileUrl, String nickname, SocialType socialType, String email, + String authId, String tag) { this.profileUrl = profileUrl; - this.nickname = randomNickName(); + this.nickname = nickname; this.socialType = socialType; this.email = email; this.isVerified = false; this.notificationEnabled = false; this.authId = authId; - this.tag = uniqueTag(); + this.tag = tag; } public void updateVerification() { @@ -116,12 +117,4 @@ public void updatePhoneNumber(byte[] phone) { public void updatePhoneHash(byte[] phone_hash) { this.phone_hash = phone_hash; } - - private String randomNickName() { - return MakeRandomNickNameUtil.makeRandomNickName(); - } - - private String uniqueTag() { - return NanoIdUtils.randomNanoId(); - } } From 5c911c2fdb415734090bbbcf68da83bca4eb9d46 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sun, 24 Mar 2024 14:12:17 +0900 Subject: [PATCH 114/314] =?UTF-8?q?fix=20:=20nickname=20nullable=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=EC=9C=BC=EB=A1=9C=EC=9D=B8=ED=95=9C=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../friend/repository/MemberFriendQueryRepositoryTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java index 136ce25b4..47acc8fc5 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java @@ -65,6 +65,7 @@ void setup(@Autowired EntityManager entityManager) { private Member getMember(int count) { return Member.builder() .socialType(SocialType.GOOGLE) + .nickname(count + "testNickname") .email(count + "test@google.com") .authId(count + "test") .profileUrl(count + "test.com") From fe2f2dd5c68b67096d33da038e40d184379e09be Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sun, 24 Mar 2024 14:49:00 +0900 Subject: [PATCH 115/314] =?UTF-8?q?fix=20:=20flyway=20test=20annotation=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../site/timecapsulearchive/core/common/RepositoryTest.java | 1 - .../friend/repository/MemberFriendQueryRepositoryTest.java | 2 ++ .../domain/member/repository/MemberQueryRepositoryTest.java | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/common/RepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/common/RepositoryTest.java index 8da3a3bc7..60b89badb 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/common/RepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/common/RepositoryTest.java @@ -11,7 +11,6 @@ @Import(JpaAuditingConfig.class) @DataJpaTest -@FlywayTest @FlywayTestExtension @ActiveProfiles("test") @AutoConfigureTestDatabase(replace = Replace.NONE) diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java index 136ce25b4..9b4491e93 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java @@ -8,6 +8,7 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Objects; +import org.flywaydb.test.annotation.FlywayTest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -25,6 +26,7 @@ import site.timecapsulearchive.core.domain.member.entity.Member; import site.timecapsulearchive.core.domain.member.entity.SocialType; +@FlywayTest @TestConstructor(autowireMode = AutowireMode.ALL) class MemberFriendQueryRepositoryTest extends RepositoryTest { diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryTest.java index bb729a946..b249a5f31 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryTest.java @@ -4,6 +4,7 @@ import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; +import org.flywaydb.test.annotation.FlywayTest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -14,6 +15,7 @@ import site.timecapsulearchive.core.domain.member.entity.Member; import site.timecapsulearchive.core.domain.member.entity.SocialType; +@FlywayTest @TestConstructor(autowireMode = AutowireMode.ALL) class MemberQueryRepositoryTest extends RepositoryTest { From bf5473b6f6cd13cbbc24960f1ad20759fd6c4e52 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sun, 24 Mar 2024 15:19:24 +0900 Subject: [PATCH 116/314] =?UTF-8?q?fix=20:=20=EC=A0=84=EC=B2=B4=20?= =?UTF-8?q?=EC=B9=9C=EA=B5=AC=20=EB=8C=80=EC=83=81=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/dto/SearchFriendSummaryDto.java | 10 +++ .../data/mapper/MemberFriendMapper.java | 12 ++- .../response/SearchFriendSummaryResponse.java | 21 +++++ .../data/response/SearchFriendsResponse.java | 5 +- .../MemberFriendQueryRepository.java | 14 ++-- .../domain/friend/service/FriendService.java | 5 +- .../core/common/RepositoryTest.java | 2 - .../MemberFriendQueryRepositoryTest.java | 76 ++++++++++++++----- .../friend/service/FriendServiceTest.java | 29 ++++--- 9 files changed, 129 insertions(+), 45 deletions(-) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/dto/SearchFriendSummaryDto.java create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/SearchFriendSummaryResponse.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/dto/SearchFriendSummaryDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/dto/SearchFriendSummaryDto.java new file mode 100644 index 000000000..ce23343df --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/dto/SearchFriendSummaryDto.java @@ -0,0 +1,10 @@ +package site.timecapsulearchive.core.domain.friend.data.dto; + +public record SearchFriendSummaryDto( + Long id, + String profileUrl, + String nickname, + Boolean isFriend +) { + +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java index c788b7a91..c0d957465 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java @@ -4,9 +4,11 @@ import org.springframework.data.domain.Slice; import org.springframework.stereotype.Component; import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; +import site.timecapsulearchive.core.domain.friend.data.dto.SearchFriendSummaryDto; import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendSummaryResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; +import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendSummaryResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; @Component @@ -37,10 +39,16 @@ public FriendRequestsSliceResponse friendRequestsSliceToResponse( return new FriendRequestsSliceResponse(friendRequests, hasNext); } - public SearchFriendsResponse friendSummaryDtosToResponse(List dtos) { + public SearchFriendsResponse searchFriendSummaryDtosToResponse( + List dtos) { return new SearchFriendsResponse(dtos.stream() - .map(this::friendsSummaryDtoToResponse) + .map(this::searchFriendSummaryDtoToResponse) .toList() ); } + + private SearchFriendSummaryResponse searchFriendSummaryDtoToResponse(SearchFriendSummaryDto dto) { + return new SearchFriendSummaryResponse(dto.id(), dto.profileUrl(), dto.nickname(), + dto.isFriend()); + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/SearchFriendSummaryResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/SearchFriendSummaryResponse.java new file mode 100644 index 000000000..b44ce60bf --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/SearchFriendSummaryResponse.java @@ -0,0 +1,21 @@ +package site.timecapsulearchive.core.domain.friend.data.response; + +import io.swagger.v3.oas.annotations.media.Schema; + +@Schema(description = "검색된 친구 정보") +public record SearchFriendSummaryResponse( + + @Schema(description = "검색된 사용자 아이디") + Long id, + + @Schema(description = "검색된 사용자 프로필") + String profileUrl, + + @Schema(description = "검색된 사용자 닉네임") + String nickname, + + @Schema(description = "친구 유무") + Boolean isFriend +) { + +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/SearchFriendsResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/SearchFriendsResponse.java index def572912..3ffd9ba74 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/SearchFriendsResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/SearchFriendsResponse.java @@ -2,12 +2,13 @@ import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; +import site.timecapsulearchive.core.domain.friend.data.dto.SearchFriendSummaryDto; -@Schema(description = "전화번호 리스트로 찾은 친구") +@Schema(description = "전화번호 목록으로 찾은 회원 요약 정보 리스트 응답") public record SearchFriendsResponse( @Schema(description = "회원 요약 정보") - List friends + List friends ) { } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java index 683a8778d..ec8d7e893 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java @@ -14,6 +14,7 @@ import org.springframework.data.domain.SliceImpl; import org.springframework.stereotype.Repository; import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; +import site.timecapsulearchive.core.domain.friend.data.dto.SearchFriendSummaryDto; import site.timecapsulearchive.core.domain.friend.entity.FriendStatus; @Repository @@ -88,20 +89,21 @@ public Slice findFriendRequestsSlice( return new SliceImpl<>(friends, Pageable.ofSize(size), hasNext); } - public List findFriendsByPhone(Long memberId, List hashes) { + public List findFriendsByPhone(Long memberId, List hashes) { return jpaQueryFactory .select( Projections.constructor( - FriendSummaryDto.class, + SearchFriendSummaryDto.class, member.id, member.profileUrl, member.nickname, - member.createdAt + memberFriend.id.isNotNull() ) ) - .from(memberFriend) - .innerJoin(memberFriend.friend, member) - .where(memberFriend.owner.id.eq(memberId).and(member.phone_hash.in(hashes))) + .from(member) + .leftJoin(memberFriend) + .on(memberFriend.friend.id.eq(member.id).and(memberFriend.owner.id.eq(memberId))) + .where(member.phone_hash.in(hashes)) .fetch(); } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java index 34b0b209f..44be1f53b 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -11,6 +11,7 @@ import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; +import site.timecapsulearchive.core.domain.friend.data.dto.SearchFriendSummaryDto; import site.timecapsulearchive.core.domain.friend.data.mapper.FriendMapper; import site.timecapsulearchive.core.domain.friend.data.mapper.MemberFriendMapper; import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; @@ -133,9 +134,9 @@ public SearchFriendsResponse findFriendsByPhone(Long memberId, List phon .map(phone -> hashEncryptionManager.encrypt(phone.getBytes(StandardCharsets.UTF_8))) .toList(); - List friends = memberFriendQueryRepository.findFriendsByPhone( + List friends = memberFriendQueryRepository.findFriendsByPhone( memberId, hashes); - return memberFriendMapper.friendSummaryDtosToResponse(friends); + return memberFriendMapper.searchFriendSummaryDtosToResponse(friends); } } diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/common/RepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/common/RepositoryTest.java index 8da3a3bc7..5cd789010 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/common/RepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/common/RepositoryTest.java @@ -1,6 +1,5 @@ package site.timecapsulearchive.core.common; -import org.flywaydb.test.annotation.FlywayTest; import org.flywaydb.test.junit5.annotation.FlywayTestExtension; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace; @@ -11,7 +10,6 @@ @Import(JpaAuditingConfig.class) @DataJpaTest -@FlywayTest @FlywayTestExtension @ActiveProfiles("test") @AutoConfigureTestDatabase(replace = Replace.NONE) diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java index ef6e6c12f..ae8248ee3 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java @@ -12,6 +12,7 @@ import java.util.List; import java.util.Objects; import java.util.stream.IntStream; +import org.flywaydb.test.annotation.FlywayTest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -23,6 +24,7 @@ import org.springframework.transaction.annotation.Transactional; import site.timecapsulearchive.core.common.RepositoryTest; import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; +import site.timecapsulearchive.core.domain.friend.data.dto.SearchFriendSummaryDto; import site.timecapsulearchive.core.domain.friend.entity.FriendInvite; import site.timecapsulearchive.core.domain.friend.entity.FriendStatus; import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; @@ -31,12 +33,15 @@ import site.timecapsulearchive.core.global.security.encryption.HashEncryptionManager; import site.timecapsulearchive.core.global.security.encryption.HashProperties; +@FlywayTest @TestConstructor(autowireMode = AutowireMode.ALL) class MemberFriendQueryRepositoryTest extends RepositoryTest { private final MemberFriendQueryRepository memberFriendQueryRepository; - private final HashEncryptionManager hash = new HashEncryptionManager(new HashProperties("test")); + private final HashEncryptionManager hash = new HashEncryptionManager( + new HashProperties("test")); private final int MAX_FRIEND_ID = 21; + private final int MAX_MEMBER_ID = 31; private Long ownerId; @@ -69,6 +74,11 @@ void setup(@Autowired EntityManager entityManager) { .build(); entityManager.persist(friendInvite); } + + for (int i = MAX_FRIEND_ID; i < MAX_FRIEND_ID + 10; i++) { + Member friend = getMember(i); + entityManager.persist(friend); + } } private Member getMember(int count) { @@ -91,7 +101,7 @@ private byte[] getPhoneBytes(int count) { @ParameterizedTest @ValueSource(ints = {20, 15, 10, 5}) - void 사용자의_친구_목록_조회_테스트(int size) { + void 특정_사용자로_친구_목록_조회하면_친구_목록_리스트가_나온다(int size) { //given ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(5); @@ -114,7 +124,7 @@ private byte[] getPhoneBytes(int count) { } @Test - void 유효하지_않은_시간으로_사용자의_친구_목록_조회_테스트() { + void 유효하지_않은_시간으로_사용자의_친구_목록_조회하면_빈_리스트가_나온다() { //given int size = 20; ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(5); @@ -131,7 +141,7 @@ private byte[] getPhoneBytes(int count) { } @Test - void 친구가_없는_사용자의_친구_목록_조회_테스트() { + void 친구가_없는_사용자로_친구_목록_조회하면_빈_리스트가_나온다() { //given int size = 20; ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(5); @@ -149,7 +159,7 @@ private byte[] getPhoneBytes(int count) { @ParameterizedTest @ValueSource(ints = {20, 15, 10, 5}) - void 사용자의_친구_요청_목록_조회_테스트(int size) { + void 특정_사용자로_친구_요청_목록_조회하면_친구_요청_목록_리스트가_나온다(int size) { //given ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).plusDays(5); @@ -172,7 +182,7 @@ private byte[] getPhoneBytes(int count) { } @Test - void 유효하지_않은_시간으로_사용자의_친구_요청_목록_조회_테스트() { + void 유효하지_않은_시간으로_사용자의_친구_요청_목록_조회하면_빈_리스트가_나온다() { //given int size = 20; ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(5); @@ -189,7 +199,7 @@ private byte[] getPhoneBytes(int count) { } @Test - void 친구가_없는_사용자의_친구_요청_목록_조회_테스트() { + void 친구가_없는_사용자로_친구_요청_목록_조회하면_빈_리스트가_나온다() { //given int size = 20; ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(5); @@ -206,29 +216,31 @@ private byte[] getPhoneBytes(int count) { } @Test - void 앱_사용자의_전화번호로만_사용자_리스트_조회_테스트() { + void 앱_사용자의_전화번호로만_주소록_기반_사용자_리스트_조회하면_조회하면_앱_사용자_리스트가_나온다() { //given - List phoneHashes = IntStream.range(1, MAX_FRIEND_ID) + List phoneHashes = IntStream.range(1, MAX_MEMBER_ID) .mapToObj(i -> hash.encrypt(getPhoneBytes(i))) .toList(); //when - List friends = memberFriendQueryRepository.findFriendsByPhone(ownerId, + List friends = memberFriendQueryRepository.findFriendsByPhone( + ownerId, phoneHashes); //then - assertThat(friends.size()).isGreaterThan(0); + assertThat(friends.size()).isSameAs(MAX_MEMBER_ID - 1); } @Test - void 앱_사용자의_전화번호가_아닌_경우_사용자_리스트_조회_테스트() { + void 앱_사용자의_전화번호가_아닌_경우_주소록_기반_사용자_리스트_조회하면_빈_리스트가_나온다() { //given - List phoneHashes = IntStream.range(1, MAX_FRIEND_ID) - .mapToObj(count -> hash.encrypt(getPhoneBytes(count + MAX_FRIEND_ID))) + List phoneHashes = IntStream.range(1, MAX_MEMBER_ID) + .mapToObj(count -> hash.encrypt(getPhoneBytes(MAX_MEMBER_ID + count))) .toList(); //when - List friends = memberFriendQueryRepository.findFriendsByPhone(ownerId, + List friends = memberFriendQueryRepository.findFriendsByPhone( + ownerId, phoneHashes); //then @@ -236,27 +248,51 @@ private byte[] getPhoneBytes(int count) { } @Test - void 친구가_없는_경우_사용자_리스트_조회_테스트() { + void 친구인_사용자로_주소록_기반_사용자_리스트_조회하면_친구인_앱_사용자_리스트가_나온다() { //given List phoneHashes = IntStream.range(1, MAX_FRIEND_ID) .mapToObj(count -> hash.encrypt(getPhoneBytes(count))) .toList(); //when - List friends = memberFriendQueryRepository.findFriendsByPhone(ownerId + MAX_FRIEND_ID, + List friends = memberFriendQueryRepository.findFriendsByPhone( + ownerId, phoneHashes); //then - assertThat(friends.size()).isSameAs(0); + assertSoftly(softly -> { + softly.assertThat(friends.size()).isSameAs(MAX_FRIEND_ID - 1); + softly.assertThat(friends).allMatch(friend -> friend.isFriend() == Boolean.TRUE); + }); } @Test - void 빈_전화번호_목록인_경우_사용자_리스트_조회_테스트() { + void 친구가_아닌_사용자로_주소록_기반_사용자_리스트_조회하면_앱_사용자_리스트가_나온다() { + //given + List phoneHashes = IntStream.range(MAX_FRIEND_ID, MAX_MEMBER_ID) + .mapToObj(count -> hash.encrypt(getPhoneBytes(count))) + .toList(); + + //when + List friends = memberFriendQueryRepository.findFriendsByPhone( + ownerId, + phoneHashes); + + //then + assertSoftly(softly -> { + assertThat(friends.size()).isSameAs(MAX_MEMBER_ID - MAX_FRIEND_ID); + softly.assertThat(friends).allMatch(friend -> friend.isFriend() == Boolean.FALSE); + }); + } + + @Test + void 빈_전화번호_목록으로_주소록_기반_사용자_리스트_조회하면_빈_리스트가_나온다() { //given List phoneHashes = Collections.emptyList(); //when - List friends = memberFriendQueryRepository.findFriendsByPhone(ownerId, + List friends = memberFriendQueryRepository.findFriendsByPhone( + ownerId, phoneHashes); //then diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/service/FriendServiceTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/service/FriendServiceTest.java index c424c8e92..d9e76fcaa 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/service/FriendServiceTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/service/FriendServiceTest.java @@ -6,13 +6,12 @@ import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; -import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.junit.jupiter.api.Test; import org.springframework.transaction.PlatformTransactionManager; -import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; +import site.timecapsulearchive.core.domain.friend.data.dto.SearchFriendSummaryDto; import site.timecapsulearchive.core.domain.friend.data.mapper.FriendMapper; import site.timecapsulearchive.core.domain.friend.data.mapper.MemberFriendMapper; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; @@ -41,12 +40,20 @@ class FriendServiceTest { private final HashEncryptionManager hashEncryptionManager = new HashEncryptionManager( new HashProperties("test_salt")); - private final FriendService friendService = new FriendService(memberFriendRepository, - memberFriendQueryRepository, memberFriendMapper, memberRepository, friendInviteRepository, - friendMapper, notificationManager, transactionTemplate, hashEncryptionManager); + private final FriendService friendService = new FriendService( + memberFriendRepository, + memberFriendQueryRepository, + memberFriendMapper, + memberRepository, + friendInviteRepository, + friendMapper, + notificationManager, + transactionTemplate, + hashEncryptionManager + ); @Test - void 사용자_핸드폰_번호로_친구_조회_테스트() { + void 앱_사용자_핸드폰_번호로_주소록_기반_사용자_리스트_조회_테스트() { //given Long memberId = 1L; List phones = getPhones(); @@ -73,18 +80,18 @@ private List getPhones() { ); } - private List getFriendSummaryDtos() { - List result = new ArrayList<>(); + private List getFriendSummaryDtos() { + List result = new ArrayList<>(); for (long i = 0; i < 8; i++) { - result.add(new FriendSummaryDto(i, i + "testProfile.com", i + "testNickname", - ZonedDateTime.now())); + result.add(new SearchFriendSummaryDto(i, i + "testProfile.com", i + "testNickname", + Boolean.TRUE)); } return result; } @Test - void 번호_없이_친구_조회_테스트() { + void 번호_없이_주소록_기반_사용자_리스트_조회_테스트() { //given Long memberId = 1L; List phones = Collections.emptyList(); From 72e9cccb42847bf85780732a6c089ca5eaa69ca5 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sun, 24 Mar 2024 15:23:19 +0900 Subject: [PATCH 117/314] =?UTF-8?q?test=20:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=9D=B4=EB=A6=84=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/core/src/main/resources/config | 2 +- .../repository/MemberQueryRepositoryTest.java | 4 ++-- .../domain/member/service/MemberServiceTest.java | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/backend/core/src/main/resources/config b/backend/core/src/main/resources/config index 236c790f5..22f616d77 160000 --- a/backend/core/src/main/resources/config +++ b/backend/core/src/main/resources/config @@ -1 +1 @@ -Subproject commit 236c790f5ace1e57ec8f2aa4d35e4a517e4e45b1 +Subproject commit 22f616d7743c5c149bcaa92c640d9727c22f6e17 diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryTest.java index b249a5f31..0c4825d68 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryTest.java @@ -43,7 +43,7 @@ private Member getMember() { } @Test - void 중복_이메일로_중복_체크_테스트() { + void 중복_이메일로_중복_체크하면_True가_반환된다() { //given String duplicatedEmail = "0test@google.com"; @@ -55,7 +55,7 @@ private Member getMember() { } @Test - void 고유한_이메일로_중복_체크_테스트() { + void 고유한_이메일로_중복_체크_테스트하면_False가_반환된다() { //given String uniqueEmail = "unique@google.com"; diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/service/MemberServiceTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/service/MemberServiceTest.java index ff49208a8..14a6300fd 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/service/MemberServiceTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/service/MemberServiceTest.java @@ -36,7 +36,7 @@ class MemberServiceTest { ); @Test - void 이메일과_패스워드로_존재하지_않는_회원_아이디_검색_테스트() { + void 이메일과_패스워드로_존재하지_않는_회원_아이디_검색하면_예외가_발생한다() { //given String email = "test@google.com"; String password = "test-password"; @@ -50,7 +50,7 @@ class MemberServiceTest { } @Test - void 이메일과_패스워드로_검증된_회원_아이디_검색_테스트() { + void 이메일과_패스워드로_검증된_회원_아이디_검색하면_올바른_아이디가_반환된다() { //given String email = "test@google.com"; String password = "test-password"; @@ -78,7 +78,7 @@ private Optional getVerifiedCheckDto(Boolean isVerified, } @Test - void 이메일과_패스워드로_검증되지_않은_회원_아이디_검색_테스트() { + void 이메일과_패스워드로_검증되지_않은_회원_아이디_검색하면_예외가_발생한다() { //given String email = "test@google.com"; String password = "test-password"; @@ -92,7 +92,7 @@ private Optional getVerifiedCheckDto(Boolean isVerified, } @Test - void 올바르지_않은_이메일로_검증된_회원_아이디_검색_테스트() { + void 올바르지_않은_이메일로_검증된_회원_아이디_검색하면_예외가_발생한다() { //given String email = "test@google.com"; String password = "test-password"; @@ -106,7 +106,7 @@ private Optional getVerifiedCheckDto(Boolean isVerified, } @Test - void 올바르지_않은_비밀번호로_검증된_회원_아이디_검색_테스트() { + void 올바르지_않은_비밀번호로_검증된_회원_아이디_검색하면_예외가_발생한다() { //given String email = "test@google.com"; String password = "test-password"; @@ -120,7 +120,7 @@ private Optional getVerifiedCheckDto(Boolean isVerified, } @Test - void 비밀번호가_없는_검증된_회원_아이디_검색_테스트() { + void 비밀번호가_없는_검증된_회원_아이디_검색하면_예외가_발생한다() { //given String email = "test@google.com"; String password = "test-password"; @@ -134,7 +134,7 @@ private Optional getVerifiedCheckDto(Boolean isVerified, } @Test - void 올바르지_않은_이메일과_비밀번호로_검증된_회원_아이디_검색_테스트() { + void 올바르지_않은_이메일과_비밀번호로_검증된_회원_아이디_검색하면_예외가_발생한다() { //given String email = "test@google.com"; String password = "test-password"; From c09d08d30ba727f9de2d0a73ab8529f8197b8689 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sun, 24 Mar 2024 16:27:44 +0900 Subject: [PATCH 118/314] =?UTF-8?q?fix=20:=20=EC=84=B8=EB=AF=B8=20?= =?UTF-8?q?=EC=BD=9C=EB=A1=A0=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20style=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timecapsulearchive/core/domain/friend/api/FriendApi.java | 3 +-- .../core/domain/friend/data/mapper/MemberFriendMapper.java | 5 +++-- .../domain/friend/data/response/SearchFriendsResponse.java | 1 - .../core/domain/friend/entity/MemberFriend.java | 2 -- .../core/domain/friend/service/FriendService.java | 3 +-- .../timecapsulearchive/core/domain/member/entity/Member.java | 2 -- .../core/infra/notification/manager/NotificationManager.java | 3 ++- 7 files changed, 7 insertions(+), 12 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java index 9e53fdb8d..8bea1efad 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java @@ -10,7 +10,6 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement; import java.time.ZonedDateTime; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import site.timecapsulearchive.core.domain.friend.data.reqeust.SearchFriendsRequest; import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; @@ -177,7 +176,7 @@ ResponseEntity> requestFriend( ResponseEntity> searchMembersByPhones( Long memberId, SearchFriendsRequest request - ) + ); @Operation( summary = "찬구 검색", diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java index f37cd6f96..50e9c81e8 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java @@ -53,11 +53,12 @@ public SearchFriendsResponse searchFriendSummaryDtosToResponse( ); } - private SearchFriendSummaryResponse searchFriendSummaryDtoToResponse(SearchFriendSummaryDto dto) { + private SearchFriendSummaryResponse searchFriendSummaryDtoToResponse( + SearchFriendSummaryDto dto) { return new SearchFriendSummaryResponse(dto.id(), dto.profileUrl(), dto.nickname(), dto.isFriend()); } - + public FriendSearchResponse friendSearchDtoToResponse(final Member friend, boolean isFriend) { return FriendSearchResponse.builder() .id(friend.getId()) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/SearchFriendsResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/SearchFriendsResponse.java index 3ffd9ba74..97590e7b8 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/SearchFriendsResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/SearchFriendsResponse.java @@ -2,7 +2,6 @@ import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; -import site.timecapsulearchive.core.domain.friend.data.dto.SearchFriendSummaryDto; @Schema(description = "전화번호 목록으로 찾은 회원 요약 정보 리스트 응답") public record SearchFriendsResponse( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java index f2bd29ef5..a905b810a 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/entity/MemberFriend.java @@ -2,8 +2,6 @@ import jakarta.persistence.Column; import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java index 574f60ea6..f575184a8 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -95,7 +95,6 @@ public void acceptFriend(final Long memberId, final Long friendId) { final MemberFriend ownerRelation = friendInvite.ownerRelation(); final MemberFriend friendRelation = friendInvite.friendRelation(); - transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { @@ -162,7 +161,7 @@ public SearchFriendsResponse findFriendsByPhone(Long memberId, List phon return memberFriendMapper.searchFriendSummaryDtosToResponse(friends); } - + @Transactional(readOnly = true) public FriendSearchResponse searchFriend(final Long memberId, final String tag) { final Member friend = memberRepository.findMemberByTag(tag) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java index d33cc0bf5..f0c4d181a 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java @@ -1,6 +1,5 @@ package site.timecapsulearchive.core.domain.member.entity; -import com.aventrix.jnanoid.jnanoid.NanoIdUtils; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -24,7 +23,6 @@ import site.timecapsulearchive.core.domain.group.entity.MemberGroup; import site.timecapsulearchive.core.domain.history.entity.History; import site.timecapsulearchive.core.global.entity.BaseEntity; -import site.timecapsulearchive.core.global.util.nickname.MakeRandomNickNameUtil; @Entity @Getter diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java index 791b7467f..a43b017f0 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/manager/NotificationManager.java @@ -37,7 +37,8 @@ public void sendFriendReqMessage(final Long friendId, final String ownerNickname @NotificationRequest public void sendFriendAcceptMessage(final Long friendId, final String ownerNickname) { - final FriendAcceptNotificationRequest request = notificationMapper.friendAcceptToMessage(friendId, + final FriendAcceptNotificationRequest request = notificationMapper.friendAcceptToMessage( + friendId, ownerNickname); aspect.sendNotification(request, notificationUrl.friendAcceptAlarmUrl()); From c1883376cc6f9605275930f35c9927bf32900613 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sun, 24 Mar 2024 16:29:11 +0900 Subject: [PATCH 119/314] =?UTF-8?q?fix=20:=20=EC=84=9C=EB=B9=84=EC=8A=A4?= =?UTF-8?q?=20&=20=EB=A0=88=ED=8F=AC=EC=A7=80=ED=86=A0=EB=A6=AC=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/auth/api/AuthApiController.java | 2 +- .../member/repository/MemberQueryRepository.java | 2 +- .../core/domain/member/service/MemberService.java | 4 ++-- .../domain/member/service/MemberServiceTest.java | 14 +++++++------- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApiController.java index d8b7f7766..73c08128a 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApiController.java @@ -213,7 +213,7 @@ public ResponseEntity> validVerificationMessage( public ResponseEntity> signUpWithEmail( @Valid @RequestBody final EmailSignUpRequest request ) { - final Long id = memberService.createMemberWithEmail(request.email(), request.password()); + final Long id = memberService.createMemberWithEmailAndPassword(request.email(), request.password()); return ResponseEntity.ok( ApiSpec.success( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java index ef55a4ca7..daa3ca044 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java @@ -113,7 +113,7 @@ private boolean canMoreRead(final int size, final int notificationSize) { return notificationSize > size; } - public Optional findEmailVerifiedCheckDtoByEmailAndPassword( + public Optional findEmailVerifiedCheckDtoByEmail( final String email ) { return Optional.ofNullable( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java index a22b168d2..96c3e7485 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java @@ -171,7 +171,7 @@ public MemberNotificationSliceResponse findNotificationSliceByMemberId( } @Transactional - public Long createMemberWithEmail(final String email, final String password) { + public Long createMemberWithEmailAndPassword(final String email, final String password) { final String encodedPassword = passwordEncoder.encode(password); final Member member = memberMapper.createMemberWithEmail(email, encodedPassword); @@ -181,7 +181,7 @@ public Long createMemberWithEmail(final String email, final String password) { } public Long findVerifiedMemberIdByEmailAndPassword(final String email, final String password) { - final EmailVerifiedCheckDto dto = memberQueryRepository.findEmailVerifiedCheckDtoByEmailAndPassword( + final EmailVerifiedCheckDto dto = memberQueryRepository.findEmailVerifiedCheckDtoByEmail( email) .orElseThrow(MemberNotFoundException::new); diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/service/MemberServiceTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/service/MemberServiceTest.java index 14a6300fd..546f848e9 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/service/MemberServiceTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/service/MemberServiceTest.java @@ -40,7 +40,7 @@ class MemberServiceTest { //given String email = "test@google.com"; String password = "test-password"; - given(memberQueryRepository.findEmailVerifiedCheckDtoByEmailAndPassword(anyString())) + given(memberQueryRepository.findEmailVerifiedCheckDtoByEmail(anyString())) .willReturn(Optional.empty()); //when, then @@ -54,7 +54,7 @@ class MemberServiceTest { //given String email = "test@google.com"; String password = "test-password"; - given(memberQueryRepository.findEmailVerifiedCheckDtoByEmailAndPassword(anyString())) + given(memberQueryRepository.findEmailVerifiedCheckDtoByEmail(anyString())) .willReturn(getVerifiedCheckDto(Boolean.TRUE, email, password)); //when @@ -82,7 +82,7 @@ private Optional getVerifiedCheckDto(Boolean isVerified, //given String email = "test@google.com"; String password = "test-password"; - given(memberQueryRepository.findEmailVerifiedCheckDtoByEmailAndPassword(anyString())) + given(memberQueryRepository.findEmailVerifiedCheckDtoByEmail(anyString())) .willReturn(getVerifiedCheckDto(Boolean.FALSE, email, password)); //when, then @@ -96,7 +96,7 @@ private Optional getVerifiedCheckDto(Boolean isVerified, //given String email = "test@google.com"; String password = "test-password"; - given(memberQueryRepository.findEmailVerifiedCheckDtoByEmailAndPassword(anyString())) + given(memberQueryRepository.findEmailVerifiedCheckDtoByEmail(anyString())) .willReturn(getVerifiedCheckDto(Boolean.TRUE, email, password)); //when, then @@ -110,7 +110,7 @@ private Optional getVerifiedCheckDto(Boolean isVerified, //given String email = "test@google.com"; String password = "test-password"; - given(memberQueryRepository.findEmailVerifiedCheckDtoByEmailAndPassword(anyString())) + given(memberQueryRepository.findEmailVerifiedCheckDtoByEmail(anyString())) .willReturn(getVerifiedCheckDto(Boolean.TRUE, email, password)); //when, then @@ -124,7 +124,7 @@ private Optional getVerifiedCheckDto(Boolean isVerified, //given String email = "test@google.com"; String password = "test-password"; - given(memberQueryRepository.findEmailVerifiedCheckDtoByEmailAndPassword(anyString())) + given(memberQueryRepository.findEmailVerifiedCheckDtoByEmail(anyString())) .willReturn(getVerifiedCheckDto(Boolean.TRUE, email, null)); //when, then @@ -138,7 +138,7 @@ private Optional getVerifiedCheckDto(Boolean isVerified, //given String email = "test@google.com"; String password = "test-password"; - given(memberQueryRepository.findEmailVerifiedCheckDtoByEmailAndPassword(anyString())) + given(memberQueryRepository.findEmailVerifiedCheckDtoByEmail(anyString())) .willReturn(getVerifiedCheckDto(Boolean.TRUE, email, password)); //when, then From 9a5c3ec9ede3fe9b4bcd74dfac23680e381b0dd5 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sun, 24 Mar 2024 17:37:56 +0900 Subject: [PATCH 120/314] =?UTF-8?q?fix=20:=20flyway=20=EC=98=A4=EB=A5=98?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/db/migration/V20__member_add_tag.sql | 3 ++- .../{V20__member_update.sql => V21__member_update.sql} | 0 2 files changed, 2 insertions(+), 1 deletion(-) rename backend/core/src/main/resources/db/migration/{V20__member_update.sql => V21__member_update.sql} (100%) diff --git a/backend/core/src/main/resources/db/migration/V20__member_add_tag.sql b/backend/core/src/main/resources/db/migration/V20__member_add_tag.sql index 6f681a0c1..0f685b7f9 100644 --- a/backend/core/src/main/resources/db/migration/V20__member_add_tag.sql +++ b/backend/core/src/main/resources/db/migration/V20__member_add_tag.sql @@ -1,2 +1,3 @@ ALTER TABLE member - ADD COLUMN tag VARCHAR(255); \ No newline at end of file + ADD COLUMN tag VARCHAR(255); +ALTER TABLE member MODIFY tag VARCHAR(255) NOT NULL, ADD CONSTRAINT unique_tag UNIQUE (tag); \ No newline at end of file diff --git a/backend/core/src/main/resources/db/migration/V20__member_update.sql b/backend/core/src/main/resources/db/migration/V21__member_update.sql similarity index 100% rename from backend/core/src/main/resources/db/migration/V20__member_update.sql rename to backend/core/src/main/resources/db/migration/V21__member_update.sql From 71aafe80fc417226f2787bfeeeddb55e25ba907d Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sun, 24 Mar 2024 17:38:15 +0900 Subject: [PATCH 121/314] =?UTF-8?q?fix=20:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/MemberFriendQueryRepositoryTest.java | 2 +- .../member/repository/MemberQueryRepositoryTest.java | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java index 7b129db27..81222ac1c 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java @@ -13,7 +13,6 @@ import java.util.Objects; import java.util.stream.IntStream; import org.flywaydb.test.annotation.FlywayTest; -import org.flywaydb.test.annotation.FlywayTest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -89,6 +88,7 @@ private Member getMember(int count) { .email(count + "test@google.com") .authId(count + "test") .profileUrl(count + "test.com") + .tag(count + "testTag") .build(); byte[] number = getPhoneBytes(count); diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryTest.java index 0c4825d68..1efaaef0f 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryTest.java @@ -36,16 +36,18 @@ void setup(@Autowired EntityManager entityManager) { private Member getMember() { return Member.builder() .socialType(SocialType.GOOGLE) - .email(0 + "test@google.com") - .authId(0 + "test") - .profileUrl(0 + "test.com") + .nickname("testNickname") + .email("test@google.com") + .authId("test") + .profileUrl("test.com") + .tag("testTag") .build(); } @Test void 중복_이메일로_중복_체크하면_True가_반환된다() { //given - String duplicatedEmail = "0test@google.com"; + String duplicatedEmail = "test@google.com"; //when Boolean isDuplicated = memberQueryRepository.checkEmailDuplication(duplicatedEmail); From c82e36b436455a990ab987bc996f6d7ce51ea304 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sun, 24 Mar 2024 17:38:27 +0900 Subject: [PATCH 122/314] =?UTF-8?q?fix=20:=20builder=20tag=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/member/data/mapper/MemberMapper.java | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java index 20b621a7f..4716160ad 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java @@ -92,6 +92,7 @@ public Member createMemberWithEmail(String email, String password) { .authId(String.valueOf(UUID.randomUUID())) .profileUrl("") .socialType(SocialType.EMAIL) + .tag(NanoIdUtils.randomNanoId()) .build(); } } \ No newline at end of file From 886e034c989aefed058caa818d0f67e51f971833 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 24 Mar 2024 19:31:57 +0900 Subject: [PATCH 123/314] =?UTF-8?q?refact:=20=EC=B9=9C=EA=B5=AC=20?= =?UTF-8?q?=ED=83=9C=EA=B7=B8=20=EA=B2=80=EC=83=89=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/api/FriendApi.java | 4 ++-- .../friend/api/FriendApiController.java | 4 ++-- .../data/response/FriendSearchResponse.java | 21 ------------------- 3 files changed, 4 insertions(+), 25 deletions(-) delete mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSearchResponse.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java index 8bea1efad..36d5f7422 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java @@ -14,8 +14,8 @@ import site.timecapsulearchive.core.domain.friend.data.reqeust.SearchFriendsRequest; import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; -import site.timecapsulearchive.core.domain.friend.data.response.FriendSearchResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; +import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendSummaryResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; import site.timecapsulearchive.core.global.common.response.ApiSpec; import site.timecapsulearchive.core.global.error.ErrorResponse; @@ -190,7 +190,7 @@ ResponseEntity> searchMembersByPhones( description = "ok" ) }) - ResponseEntity> searchFriendByTag( + ResponseEntity> searchFriendByTag( Long memberId, @Parameter(in = ParameterIn.QUERY, description = "페이지 크기", required = true) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java index 18190a621..153b1d064 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java @@ -16,8 +16,8 @@ import site.timecapsulearchive.core.domain.friend.data.reqeust.SearchFriendsRequest; import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; -import site.timecapsulearchive.core.domain.friend.data.response.FriendSearchResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; +import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendSummaryResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; import site.timecapsulearchive.core.domain.friend.service.FriendService; import site.timecapsulearchive.core.global.common.response.ApiSpec; @@ -134,7 +134,7 @@ public ResponseEntity> searchMembersByPhones( @PostMapping(value = "/search") @Override - public ResponseEntity> searchFriendByTag( + public ResponseEntity> searchFriendByTag( @AuthenticationPrincipal Long memberId, @RequestParam(value = "friend-tag") final String tag ) { diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSearchResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSearchResponse.java deleted file mode 100644 index ffe7f2448..000000000 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/FriendSearchResponse.java +++ /dev/null @@ -1,21 +0,0 @@ -package site.timecapsulearchive.core.domain.friend.data.response; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; - -@Builder -public record FriendSearchResponse( - @Schema(description = "친구 아이디") - Long id, - - @Schema(description = "친구 프로필") - String profileUrl, - - @Schema(description = "친구 닉네임") - String nickname, - - @Schema(description = "친구 관계") - Boolean isFriend -) { - -} From 33ec722a537b8532c7f091c6c0d0b36d902007e6 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 24 Mar 2024 19:32:52 +0900 Subject: [PATCH 124/314] =?UTF-8?q?refact:=20=ED=83=9C=EA=B7=B8=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20=EC=9D=91=EB=8B=B5=20=EC=BF=BC=EB=A6=AC=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/mapper/MemberFriendMapper.java | 19 ++++++----------- .../MemberFriendQueryRepository.java | 21 +++++++++++++++++++ .../domain/friend/service/FriendService.java | 14 +++++-------- 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java index 50e9c81e8..d8d577b3d 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java @@ -6,12 +6,10 @@ import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; import site.timecapsulearchive.core.domain.friend.data.dto.SearchFriendSummaryDto; import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; -import site.timecapsulearchive.core.domain.friend.data.response.FriendSearchResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendSummaryResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendSummaryResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; -import site.timecapsulearchive.core.domain.member.entity.Member; @Component public class MemberFriendMapper { @@ -53,18 +51,13 @@ public SearchFriendsResponse searchFriendSummaryDtosToResponse( ); } - private SearchFriendSummaryResponse searchFriendSummaryDtoToResponse( + public SearchFriendSummaryResponse searchFriendSummaryDtoToResponse( SearchFriendSummaryDto dto) { - return new SearchFriendSummaryResponse(dto.id(), dto.profileUrl(), dto.nickname(), - dto.isFriend()); - } - - public FriendSearchResponse friendSearchDtoToResponse(final Member friend, boolean isFriend) { - return FriendSearchResponse.builder() - .id(friend.getId()) - .profileUrl(friend.getProfileUrl()) - .nickname(friend.getNickname()) - .isFriend(isFriend) + return SearchFriendSummaryResponse.builder() + .id(dto.id()) + .profileUrl(dto.profileUrl()) + .nickname(dto.nickname()) + .isFriend(dto.isFriend()) .build(); } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java index ec8d7e893..c78a6eb84 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java @@ -8,6 +8,7 @@ import com.querydsl.jpa.impl.JPAQueryFactory; import java.time.ZonedDateTime; import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; @@ -106,4 +107,24 @@ public List findFriendsByPhone(Long memberId, List findFriendsByTag(final Long memberId, + final String tag) { + return Optional.ofNullable(jpaQueryFactory + .select( + Projections.constructor( + SearchFriendSummaryDto.class, + member.id, + member.profileUrl, + member.nickname, + memberFriend.id.isNotNull() + ) + ) + .from(member) + .leftJoin(memberFriend) + .on(memberFriend.friend.id.eq(member.id).and(memberFriend.owner.id.eq(memberId))) + .where(member.tag.eq(tag)) + .fetchOne() + ); + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java index f575184a8..800b97a7d 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -3,7 +3,6 @@ import java.nio.charset.StandardCharsets; import java.time.ZonedDateTime; import java.util.List; -import java.util.Optional; import org.springframework.data.domain.Slice; import org.springframework.stereotype.Service; import org.springframework.transaction.PlatformTransactionManager; @@ -17,8 +16,8 @@ import site.timecapsulearchive.core.domain.friend.data.mapper.MemberFriendMapper; import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; -import site.timecapsulearchive.core.domain.friend.data.response.FriendSearchResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendsSliceResponse; +import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendSummaryResponse; import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; import site.timecapsulearchive.core.domain.friend.entity.FriendInvite; import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; @@ -163,13 +162,10 @@ public SearchFriendsResponse findFriendsByPhone(Long memberId, List phon } @Transactional(readOnly = true) - public FriendSearchResponse searchFriend(final Long memberId, final String tag) { - final Member friend = memberRepository.findMemberByTag(tag) - .orElseThrow(MemberNotFoundException::new); + public SearchFriendSummaryResponse searchFriend(final Long memberId, final String tag) { + final SearchFriendSummaryDto friendSummaryDto = memberFriendQueryRepository + .findFriendsByTag(memberId, tag).orElseThrow(FriendNotFoundException::new); - final Optional memberFriend = memberFriendRepository - .findMemberFriendByOwnerIdAndFriendId(memberId, friend.getId()); - - return memberFriendMapper.friendSearchDtoToResponse(friend, memberFriend.isPresent()); + return memberFriendMapper.searchFriendSummaryDtoToResponse(friendSummaryDto); } } From 0f604233c3c5e0b73e31e67bf685359ca954aa10 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 24 Mar 2024 19:33:15 +0900 Subject: [PATCH 125/314] =?UTF-8?q?fix:=20=EA=B8=B0=ED=83=80=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../friend/data/response/SearchFriendSummaryResponse.java | 2 ++ .../core/domain/member/api/MemberApiController.java | 1 - .../timecapsulearchive/core/domain/member/entity/Member.java | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/SearchFriendSummaryResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/SearchFriendSummaryResponse.java index b44ce60bf..4f0276bd8 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/SearchFriendSummaryResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/response/SearchFriendSummaryResponse.java @@ -1,7 +1,9 @@ package site.timecapsulearchive.core.domain.friend.data.response; import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +@Builder @Schema(description = "검색된 친구 정보") public record SearchFriendSummaryResponse( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java index 3dec2cd5e..46e021333 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java @@ -1,7 +1,6 @@ package site.timecapsulearchive.core.domain.member.api; import jakarta.validation.Valid; -import jakarta.validation.constraints.Email; import java.time.ZonedDateTime; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java index 1fa441f4a..caa93a754 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Member.java @@ -95,8 +95,8 @@ public class Member extends BaseEntity { private List histories; @Builder - private Member(String profileUrl, String nickname, SocialType socialType, String email, String authId, - String password, String tag) { + private Member(String profileUrl, String nickname, SocialType socialType, String email, + String authId, String password, String tag) { this.profileUrl = profileUrl; this.nickname = nickname; this.socialType = socialType; From f446dfa33c4c8f5470d98679a16fc89cae215979 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 24 Mar 2024 19:47:17 +0900 Subject: [PATCH 126/314] =?UTF-8?q?refact:=20final=20=EB=88=84=EB=9D=BD=20?= =?UTF-8?q?=ED=82=A4=EC=9B=8C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../friend/data/mapper/MemberFriendMapper.java | 14 +++++++------- .../repository/MemberFriendQueryRepository.java | 15 ++++++++++----- .../core/domain/friend/service/FriendService.java | 6 +++--- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java index d8d577b3d..c57519c62 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/data/mapper/MemberFriendMapper.java @@ -14,8 +14,8 @@ @Component public class MemberFriendMapper { - public FriendsSliceResponse friendsSliceToResponse(Slice slice) { - List friends = slice.getContent() + public FriendsSliceResponse friendsSliceToResponse(final Slice slice) { + final List friends = slice.getContent() .stream() .map(this::friendsSummaryDtoToResponse) .toList(); @@ -23,7 +23,7 @@ public FriendsSliceResponse friendsSliceToResponse(Slice slice return new FriendsSliceResponse(friends, slice.hasNext()); } - private FriendSummaryResponse friendsSummaryDtoToResponse(FriendSummaryDto dto) { + private FriendSummaryResponse friendsSummaryDtoToResponse(final FriendSummaryDto dto) { return FriendSummaryResponse.builder() .id(dto.id()) .profileUrl(dto.profileUrl()) @@ -33,8 +33,8 @@ private FriendSummaryResponse friendsSummaryDtoToResponse(FriendSummaryDto dto) } public FriendRequestsSliceResponse friendRequestsSliceToResponse( - List content, - boolean hasNext + final List content, + final boolean hasNext ) { List friendRequests = content.stream() .map(this::friendsSummaryDtoToResponse) @@ -44,7 +44,7 @@ public FriendRequestsSliceResponse friendRequestsSliceToResponse( } public SearchFriendsResponse searchFriendSummaryDtosToResponse( - List dtos) { + final List dtos) { return new SearchFriendsResponse(dtos.stream() .map(this::searchFriendSummaryDtoToResponse) .toList() @@ -52,7 +52,7 @@ public SearchFriendsResponse searchFriendSummaryDtosToResponse( } public SearchFriendSummaryResponse searchFriendSummaryDtoToResponse( - SearchFriendSummaryDto dto) { + final SearchFriendSummaryDto dto) { return SearchFriendSummaryResponse.builder() .id(dto.id()) .profileUrl(dto.profileUrl()) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java index c78a6eb84..1dbc59458 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepository.java @@ -29,7 +29,7 @@ public Slice findFriendsSlice( final int size, final ZonedDateTime createdAt ) { - List friends = jpaQueryFactory + final List friends = jpaQueryFactory .select( Projections.constructor( FriendSummaryDto.class, @@ -63,7 +63,7 @@ public Slice findFriendRequestsSlice( final int size, final ZonedDateTime createdAt ) { - List friends = jpaQueryFactory + final List friends = jpaQueryFactory .select( Projections.constructor( FriendSummaryDto.class, @@ -90,7 +90,10 @@ public Slice findFriendRequestsSlice( return new SliceImpl<>(friends, Pageable.ofSize(size), hasNext); } - public List findFriendsByPhone(Long memberId, List hashes) { + public List findFriendsByPhone( + final Long memberId, + final List hashes + ) { return jpaQueryFactory .select( Projections.constructor( @@ -108,8 +111,10 @@ public List findFriendsByPhone(Long memberId, List findFriendsByTag(final Long memberId, - final String tag) { + public Optional findFriendsByTag( + final Long memberId, + final String tag + ) { return Optional.ofNullable(jpaQueryFactory .select( Projections.constructor( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java index 800b97a7d..c6624a262 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -150,12 +150,12 @@ public FriendRequestsSliceResponse findFriendRequestsSlice( } @Transactional(readOnly = true) - public SearchFriendsResponse findFriendsByPhone(Long memberId, List phones) { - List hashes = phones.stream() + public SearchFriendsResponse findFriendsByPhone(final Long memberId, final List phones) { + final List hashes = phones.stream() .map(phone -> hashEncryptionManager.encrypt(phone.getBytes(StandardCharsets.UTF_8))) .toList(); - List friends = memberFriendQueryRepository.findFriendsByPhone( + final List friends = memberFriendQueryRepository.findFriendsByPhone( memberId, hashes); return memberFriendMapper.searchFriendSummaryDtosToResponse(friends); From 5822d4d6c750a773172f7a6a66f89b03094c3d9d Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 24 Mar 2024 19:47:33 +0900 Subject: [PATCH 127/314] =?UTF-8?q?fix:=20=EC=95=88=EC=93=B0=EB=8A=94=20?= =?UTF-8?q?=EB=A0=88=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/auth/api/AuthApiController.java | 3 ++- .../data/dto/SecretCapsuleDetail.java | 20 ------------------- 2 files changed, 2 insertions(+), 21 deletions(-) delete mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/SecretCapsuleDetail.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApiController.java index 73c08128a..8ee51e993 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/auth/api/AuthApiController.java @@ -213,7 +213,8 @@ public ResponseEntity> validVerificationMessage( public ResponseEntity> signUpWithEmail( @Valid @RequestBody final EmailSignUpRequest request ) { - final Long id = memberService.createMemberWithEmailAndPassword(request.email(), request.password()); + final Long id = memberService.createMemberWithEmailAndPassword(request.email(), + request.password()); return ResponseEntity.ok( ApiSpec.success( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/SecretCapsuleDetail.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/SecretCapsuleDetail.java deleted file mode 100644 index 120625b4a..000000000 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/SecretCapsuleDetail.java +++ /dev/null @@ -1,20 +0,0 @@ -package site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto; - -import java.time.ZonedDateTime; -import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; - -public record SecretCapsuleDetail( - Long capsuleId, - String capsuleSkinUrl, - ZonedDateTime dueDate, - String nickname, - String profileUrl, - ZonedDateTime createdAt, - String address, - String title, - String content, - Boolean isOpened, - CapsuleType capsuleType -) { - -} From 3d81e0de577e535d6cb99e5c1576bfaeaac71b55 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 24 Mar 2024 20:38:23 +0900 Subject: [PATCH 128/314] =?UTF-8?q?test:=20=EC=B9=9C=EA=B5=AC=20=ED=83=9C?= =?UTF-8?q?=EA=B7=B8=20=EA=B2=80=EC=83=89=20=EC=BF=BC=EB=A6=AC=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MemberFriendQueryRepositoryTest.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java index 81222ac1c..cfffae92c 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java @@ -11,6 +11,7 @@ import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.stream.IntStream; import org.flywaydb.test.annotation.FlywayTest; import org.junit.jupiter.api.BeforeEach; @@ -300,4 +301,32 @@ private byte[] getPhoneBytes(int count) { //then assertThat(friends.size()).isSameAs(0); } + + @ParameterizedTest + @ValueSource(ints = {20, 15, 10, 5}) + void 사용자_아이디와_친구_태그로_친구관계를_조회하면_친구인_경우_True를_반환한다(int friendId) { + //given + Optional dto = memberFriendQueryRepository.findFriendsByTag( + ownerId, friendId+ "testTag"); + + //when + Boolean isFriend = dto.get().isFriend(); + + //then + assertThat(isFriend).isTrue(); + } + + @ParameterizedTest + @ValueSource(ints = {30, 28, 25, 21}) + void 사용자_아이디와_친구_태그로_친구관계를_조회하면_친구가_아닌_경우_False를_반환한다(int friendId) { + //given + Optional dto = memberFriendQueryRepository.findFriendsByTag( + ownerId, friendId + "testTag"); + + //when + Boolean isFriend = dto.get().isFriend(); + + //then + assertThat(isFriend).isFalse(); + } } \ No newline at end of file From 0d2f673faef2ecd402c9d2e4769f93639432a6e2 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 24 Mar 2024 20:38:52 +0900 Subject: [PATCH 129/314] =?UTF-8?q?test:=20=EC=82=AC=EC=9A=A9=EC=9E=90,=20?= =?UTF-8?q?=EC=B9=9C=EA=B5=AC=20=EC=95=84=EC=9D=B4=EB=94=94=EB=A1=9C=20?= =?UTF-8?q?=EC=B9=9C=EA=B5=AC=20=EA=B4=80=EA=B3=84=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=BF=BC=EB=A6=AC=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MemberFriendRepositoryTest.java | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepositoryTest.java diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepositoryTest.java new file mode 100644 index 000000000..16fadc91e --- /dev/null +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepositoryTest.java @@ -0,0 +1,75 @@ +package site.timecapsulearchive.core.domain.friend.repository; + +import static org.assertj.core.api.Assertions.assertThat; + +import jakarta.persistence.EntityManager; +import java.util.Optional; +import org.flywaydb.test.annotation.FlywayTest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.TestConstructor; +import org.springframework.test.context.TestConstructor.AutowireMode; +import org.springframework.transaction.annotation.Transactional; +import site.timecapsulearchive.core.common.RepositoryTest; +import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; +import site.timecapsulearchive.core.domain.member.entity.Member; +import site.timecapsulearchive.core.domain.member.entity.SocialType; + +@FlywayTest +@TestConstructor(autowireMode = AutowireMode.ALL) +class MemberFriendRepositoryTest extends RepositoryTest { + + private final MemberFriendRepository memberFriendRepository; + private Long ownerId; + private Long friendId; + + + MemberFriendRepositoryTest(MemberFriendRepository repository) { + this.memberFriendRepository = repository; + } + + @Transactional + @BeforeEach + void setup(@Autowired EntityManager entityManager) { + Member owner = getMember(0); + entityManager.persist(owner); + ownerId = owner.getId(); + + Member friend = getMember(1); + entityManager.persist(friend); + friendId = friend.getId(); + + MemberFriend memberFriend = MemberFriend.builder() + .owner(owner) + .friend(friend) + .build(); + entityManager.persist(memberFriend); + } + + private Member getMember(int count) { + return Member.builder() + .socialType(SocialType.GOOGLE) + .nickname(count + "testNickname") + .email(count + "test@google.com") + .authId(count + "test") + .profileUrl(count + "test.com") + .tag(count + "testTag") + .build(); + } + + @Test + void 사용자_아이디와_친구_아이디로_친구관계를_조회하여_친구관계를_확인한다() { + //given + Optional memberFriend = memberFriendRepository.findMemberFriendByOwnerIdAndFriendId( + ownerId, friendId); + + //when + Long actualFriendId = memberFriend.get().getFriend().getId(); + + //then + assertThat(actualFriendId).isEqualTo(friendId); + } + + +} From 73a288dc75b9195a2f3aa623b7a201867633127c Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 24 Mar 2024 21:07:38 +0900 Subject: [PATCH 130/314] =?UTF-8?q?fix:=20gradle=20jnanoid=20imple?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/core/build.gradle | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/core/build.gradle b/backend/core/build.gradle index e62f7ac25..f35c4a4fc 100644 --- a/backend/core/build.gradle +++ b/backend/core/build.gradle @@ -74,7 +74,9 @@ dependencies { //aop implementation 'org.springframework.boot:spring-boot-starter-aop' - compileOnly 'com.aventrix.jnanoid:jnanoid:2.0.0' + //jnanoid + implementation 'com.aventrix.jnanoid:jnanoid:2.0.0' + compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok' From 3f1f8afef7531754117c73af6d287f0b35cc49e6 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 24 Mar 2024 21:20:24 +0900 Subject: [PATCH 131/314] =?UTF-8?q?fix:=20final=20=ED=82=A4=EC=9B=8C?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/member/repository/MemberQueryRepository.java | 2 +- .../core/domain/member/service/MemberService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java index daa3ca044..b82fa9db0 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java @@ -134,7 +134,7 @@ public Optional findEmailVerifiedCheckDtoByEmail( } public Boolean checkEmailDuplication(final String email) { - Integer count = query.selectOne() + final Integer count = query.selectOne() .from(member) .where(member.email.eq(email)) .fetchFirst(); diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java index 96c3e7485..314027a0b 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java @@ -207,7 +207,7 @@ private boolean isNotMatched( !passwordEncoder.matches(inputPassword, password); } - public CheckEmailDuplicationResponse checkEmailDuplication(String email) { + public CheckEmailDuplicationResponse checkEmailDuplication(final String email) { Boolean isDuplicated = memberQueryRepository.checkEmailDuplication(email); return new CheckEmailDuplicationResponse(isDuplicated); From c749557ca65f64a91ee92d29f79b413f325a1476 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 24 Mar 2024 22:29:10 +0900 Subject: [PATCH 132/314] =?UTF-8?q?feat:=20=EC=95=8C=EB=A6=BC=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=20=ED=99=95=EC=9D=B8=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/member/api/MemberApi.java | 22 +++++++++++++++++++ .../member/api/MemberApiController.java | 13 +++++++++++ .../MemberNotificationStatusResponse.java | 7 ++++++ .../repository/MemberQueryRepository.java | 9 ++++++++ .../domain/member/service/MemberService.java | 8 +++++++ 5 files changed, 59 insertions(+) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/response/MemberNotificationStatusResponse.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApi.java index dfc4c058d..584ae1c73 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApi.java @@ -15,6 +15,7 @@ import site.timecapsulearchive.core.domain.member.data.response.CheckEmailDuplicationResponse; import site.timecapsulearchive.core.domain.member.data.response.MemberDetailResponse; import site.timecapsulearchive.core.domain.member.data.response.MemberNotificationSliceResponse; +import site.timecapsulearchive.core.domain.member.data.response.MemberNotificationStatusResponse; import site.timecapsulearchive.core.domain.member.data.response.MemberStatusResponse; import site.timecapsulearchive.core.global.common.response.ApiSpec; import site.timecapsulearchive.core.global.error.ErrorResponse; @@ -97,6 +98,27 @@ ResponseEntity> updateMemberNotificationEnabled( UpdateNotificationEnabledRequest updateNotificationEnabledRequest ); + @Operation( + summary = "회원 알림 수신 상태 확인", + description = "회원의 알림 수신 상태를 확인한다.", + security = {@SecurityRequirement(name = "member")}, + tags = {"member"} + ) + @ApiResponses(value = { + @ApiResponse( + responseCode = "200", + description = "처리 완료" + ), + @ApiResponse( + responseCode = "404", + description = "해당 멤버가 존재하지 않을 때 발생하는 예외", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)) + ), + }) + ResponseEntity> checkMemberNotificationStatus( + Long memberId + ); + @Operation( summary = "회원 알림 목록 조회", description = "회원의 알림 목록을 조회한다.", diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java index 3dec2cd5e..72a7c42ff 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java @@ -20,6 +20,7 @@ import site.timecapsulearchive.core.domain.member.data.response.CheckEmailDuplicationResponse; import site.timecapsulearchive.core.domain.member.data.response.MemberDetailResponse; import site.timecapsulearchive.core.domain.member.data.response.MemberNotificationSliceResponse; +import site.timecapsulearchive.core.domain.member.data.response.MemberNotificationStatusResponse; import site.timecapsulearchive.core.domain.member.data.response.MemberStatusResponse; import site.timecapsulearchive.core.domain.member.service.MemberService; import site.timecapsulearchive.core.global.common.response.ApiSpec; @@ -89,6 +90,18 @@ public ResponseEntity> updateMemberNotificationEnabled( return ResponseEntity.ok(ApiSpec.empty(SuccessCode.SUCCESS)); } + @Override + @PostMapping(value = "/notification_enabled") + public ResponseEntity> checkMemberNotificationStatus( + @AuthenticationPrincipal Long memberId) { + return ResponseEntity.ok( + ApiSpec.success( + SuccessCode.SUCCESS, + memberService.checkNotificationStatus(memberId) + ) + ); + } + @Override @GetMapping(value = "/notifications") public ResponseEntity> getMemberNotifications( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/response/MemberNotificationStatusResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/response/MemberNotificationStatusResponse.java new file mode 100644 index 000000000..a398e844c --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/response/MemberNotificationStatusResponse.java @@ -0,0 +1,7 @@ +package site.timecapsulearchive.core.domain.member.data.response; + +public record MemberNotificationStatusResponse( + Boolean notificationEnabled +) { + +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java index daa3ca044..2dc88448e 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java @@ -141,4 +141,13 @@ public Boolean checkEmailDuplication(final String email) { return count != null; } + + public Optional findIsAlarmByMemberId(final Long memberId) { + return Optional.ofNullable( + query.select(member.notificationEnabled) + .from(member) + .where(member.id.eq(memberId)) + .fetchOne() + ); + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java index 96c3e7485..1449fb5ba 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/service/MemberService.java @@ -16,6 +16,7 @@ import site.timecapsulearchive.core.domain.member.data.response.CheckEmailDuplicationResponse; import site.timecapsulearchive.core.domain.member.data.response.MemberDetailResponse; import site.timecapsulearchive.core.domain.member.data.response.MemberNotificationSliceResponse; +import site.timecapsulearchive.core.domain.member.data.response.MemberNotificationStatusResponse; import site.timecapsulearchive.core.domain.member.data.response.MemberStatusResponse; import site.timecapsulearchive.core.domain.member.entity.Member; import site.timecapsulearchive.core.domain.member.entity.SocialType; @@ -212,4 +213,11 @@ public CheckEmailDuplicationResponse checkEmailDuplication(String email) { return new CheckEmailDuplicationResponse(isDuplicated); } + + public MemberNotificationStatusResponse checkNotificationStatus(Long memberId) { + Boolean isAlarm = memberQueryRepository.findIsAlarmByMemberId(memberId) + .orElseThrow(MemberNotFoundException::new); + + return new MemberNotificationStatusResponse(isAlarm); + } } From 47a577142a267f06c8e9b7c942a27cf53fa2ada9 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 24 Mar 2024 23:38:24 +0900 Subject: [PATCH 133/314] =?UTF-8?q?refact:=20=EC=B9=9C=EA=B5=AC=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/MemberFriendRepository.java | 12 +++++- .../domain/friend/service/FriendService.java | 13 ++++--- .../MemberFriendRepositoryTest.java | 39 +++++++++++++++---- 3 files changed, 49 insertions(+), 15 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepository.java index a487ea212..9f5dac8e3 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepository.java @@ -1,12 +1,20 @@ package site.timecapsulearchive.core.domain.friend.repository; -import java.util.Optional; +import java.util.List; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.Repository; +import org.springframework.data.repository.query.Param; import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; public interface MemberFriendRepository extends Repository { - Optional findMemberFriendByOwnerIdAndFriendId(Long ownerId, Long friendId); + @Query("SELECT mf FROM MemberFriend mf " + + "WHERE (mf.owner.id = :memberId AND mf.friend.id = :friendId) " + + "OR (mf.owner.id = :friendId AND mf.friend.id = :memberId)") + List findMemberFriendByOwnerIdAndFriendId( + @Param("memberId") Long memberId, + @Param("friendId") Long friendId + ); void delete(MemberFriend memberFriend); diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java index c6624a262..7485b489b 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -116,12 +116,12 @@ public void denyRequestFriend(Long memberId, Long friendId) { } @Transactional - public void deleteFriend(final Long memberId, final Long friendId) { - final MemberFriend memberFriend = memberFriendRepository.findMemberFriendByOwnerIdAndFriendId( - memberId, friendId) - .orElseThrow(FriendNotFoundException::new); + public void deleteFriend(final Long memberId, final Long friend2Id) { + final List memberFriends = memberFriendRepository.findMemberFriendByOwnerIdAndFriendId( + memberId, friend2Id); - memberFriendRepository.delete(memberFriend); + memberFriends + .forEach(memberFriendRepository::delete); } @Transactional(readOnly = true) @@ -150,7 +150,8 @@ public FriendRequestsSliceResponse findFriendRequestsSlice( } @Transactional(readOnly = true) - public SearchFriendsResponse findFriendsByPhone(final Long memberId, final List phones) { + public SearchFriendsResponse findFriendsByPhone(final Long memberId, + final List phones) { final List hashes = phones.stream() .map(phone -> hashEncryptionManager.encrypt(phone.getBytes(StandardCharsets.UTF_8))) .toList(); diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepositoryTest.java index 16fadc91e..c921f7ae7 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepositoryTest.java @@ -1,9 +1,10 @@ package site.timecapsulearchive.core.domain.friend.repository; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.SoftAssertions.assertSoftly; import jakarta.persistence.EntityManager; -import java.util.Optional; +import java.util.List; import org.flywaydb.test.annotation.FlywayTest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -40,11 +41,17 @@ void setup(@Autowired EntityManager entityManager) { entityManager.persist(friend); friendId = friend.getId(); - MemberFriend memberFriend = MemberFriend.builder() + MemberFriend ownerRelation = MemberFriend.builder() .owner(owner) .friend(friend) .build(); - entityManager.persist(memberFriend); + + MemberFriend friendRelation = MemberFriend.builder() + .owner(friend) + .friend(owner) + .build(); + entityManager.persist(ownerRelation); + entityManager.persist(friendRelation); } private Member getMember(int count) { @@ -61,14 +68,32 @@ private Member getMember(int count) { @Test void 사용자_아이디와_친구_아이디로_친구관계를_조회하여_친구관계를_확인한다() { //given - Optional memberFriend = memberFriendRepository.findMemberFriendByOwnerIdAndFriendId( + List memberFriend = memberFriendRepository.findMemberFriendByOwnerIdAndFriendId( ownerId, friendId); //when - Long actualFriendId = memberFriend.get().getFriend().getId(); + Long actualFriendId = memberFriend.get(0).getFriend().getId(); + Long actualOwnerId = memberFriend.get(1).getFriend().getId(); + + //when + assertSoftly(softly -> { + softly.assertThat(memberFriend.size()).isEqualTo(2); + softly.assertThat(actualFriendId).isEqualTo(friendId); + softly.assertThat(actualOwnerId).isEqualTo(ownerId); + }); + } + + @Test + void 유효하지_않는_친구_아이디로_친구관계를_조회하면_빈_리스트를_반환한다() { + //given + Long friendId = -1L; + + //when + List memberFriend = memberFriendRepository.findMemberFriendByOwnerIdAndFriendId( + ownerId, friendId); - //then - assertThat(actualFriendId).isEqualTo(friendId); + //when + assertThat(memberFriend).isEmpty(); } From 983e560f885e294143b8b211300564e7fe99f7b7 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Mon, 25 Mar 2024 23:05:57 +0900 Subject: [PATCH 134/314] =?UTF-8?q?fix:=20=EC=B9=9C=EA=B5=AC=20=EA=B4=80?= =?UTF-8?q?=EA=B3=84=20=EC=82=AD=EC=A0=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/service/FriendService.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java index 7485b489b..80de8f96b 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -117,10 +117,8 @@ public void denyRequestFriend(Long memberId, Long friendId) { @Transactional public void deleteFriend(final Long memberId, final Long friend2Id) { - final List memberFriends = memberFriendRepository.findMemberFriendByOwnerIdAndFriendId( - memberId, friend2Id); - - memberFriends + memberFriendRepository + .findMemberFriendByOwnerIdAndFriendId(memberId, friend2Id) .forEach(memberFriendRepository::delete); } From bd59c41f90bb87b06b255ee672ebf6268e90cbc4 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Tue, 26 Mar 2024 00:04:15 +0900 Subject: [PATCH 135/314] =?UTF-8?q?fix:=20=EC=95=8C=EB=A6=BC=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=20=EC=B2=B4=ED=81=AC=20API=20HTTP=20Method=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/member/api/MemberApiController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java index 72a7c42ff..24c6e7e12 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java @@ -91,7 +91,7 @@ public ResponseEntity> updateMemberNotificationEnabled( } @Override - @PostMapping(value = "/notification_enabled") + @GetMapping(value = "/notification_enabled") public ResponseEntity> checkMemberNotificationStatus( @AuthenticationPrincipal Long memberId) { return ResponseEntity.ok( From 31a9c781ebbbdcb925ad9545c446eeec4ee012f2 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Thu, 28 Mar 2024 22:12:37 +0900 Subject: [PATCH 136/314] =?UTF-8?q?feat:=20CategoryName=20Friend=20?= =?UTF-8?q?=EC=86=8D=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timecapsulearchive/notification/entity/CategoryName.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/notification/src/main/java/site/timecapsulearchive/notification/entity/CategoryName.java b/backend/notification/src/main/java/site/timecapsulearchive/notification/entity/CategoryName.java index 29f8fd14e..a90a55eb4 100644 --- a/backend/notification/src/main/java/site/timecapsulearchive/notification/entity/CategoryName.java +++ b/backend/notification/src/main/java/site/timecapsulearchive/notification/entity/CategoryName.java @@ -1,5 +1,5 @@ package site.timecapsulearchive.notification.entity; public enum CategoryName { - CAPSULE_SKIN + CAPSULE_SKIN, FRIEND_REQUEST, FRIEND_ACCEPT } From 3ea8a4c2239e18bc1248029e6dd39c6fb53566be Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Thu, 28 Mar 2024 22:13:30 +0900 Subject: [PATCH 137/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EC=95=8C?= =?UTF-8?q?=EB=A6=BC=20dto=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/dto/FriendNotificationDto.java | 21 +++++++++++++++++++ .../request/FriendNotificationRequest.java | 12 +++++++++++ 2 files changed, 33 insertions(+) create mode 100644 backend/notification/src/main/java/site/timecapsulearchive/notification/data/dto/FriendNotificationDto.java create mode 100644 backend/notification/src/main/java/site/timecapsulearchive/notification/data/request/FriendNotificationRequest.java diff --git a/backend/notification/src/main/java/site/timecapsulearchive/notification/data/dto/FriendNotificationDto.java b/backend/notification/src/main/java/site/timecapsulearchive/notification/data/dto/FriendNotificationDto.java new file mode 100644 index 000000000..b37ff9c05 --- /dev/null +++ b/backend/notification/src/main/java/site/timecapsulearchive/notification/data/dto/FriendNotificationDto.java @@ -0,0 +1,21 @@ +package site.timecapsulearchive.notification.data.dto; + +import java.util.Objects; +import lombok.Builder; +import site.timecapsulearchive.notification.entity.NotificationStatus; + +@Builder +public record FriendNotificationDto( + Long memberId, + NotificationStatus status, + String text, + String title +) { + + public FriendNotificationDto { + Objects.requireNonNull(memberId); + Objects.requireNonNull(status); + Objects.requireNonNull(text); + Objects.requireNonNull(title); + } +} diff --git a/backend/notification/src/main/java/site/timecapsulearchive/notification/data/request/FriendNotificationRequest.java b/backend/notification/src/main/java/site/timecapsulearchive/notification/data/request/FriendNotificationRequest.java new file mode 100644 index 000000000..91a76dfec --- /dev/null +++ b/backend/notification/src/main/java/site/timecapsulearchive/notification/data/request/FriendNotificationRequest.java @@ -0,0 +1,12 @@ +package site.timecapsulearchive.notification.data.request; + +import site.timecapsulearchive.notification.entity.NotificationStatus; + +public record FriendNotificationRequest( + Long memberId, + NotificationStatus status, + String text, + String title +) { + +} From f7ec566c37679c82ee2ffe5031ea6bb484452859 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Thu, 28 Mar 2024 22:14:21 +0900 Subject: [PATCH 138/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EA=B4=80?= =?UTF-8?q?=EA=B3=84=20controller=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/NotificationController.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/backend/notification/src/main/java/site/timecapsulearchive/notification/api/NotificationController.java b/backend/notification/src/main/java/site/timecapsulearchive/notification/api/NotificationController.java index 586b54a93..00a6e8938 100644 --- a/backend/notification/src/main/java/site/timecapsulearchive/notification/api/NotificationController.java +++ b/backend/notification/src/main/java/site/timecapsulearchive/notification/api/NotificationController.java @@ -28,4 +28,25 @@ public ResponseEntity sendCapsuleSkinNotification( return ResponseEntity.noContent().build(); } + + @PostMapping("/friend-request/send") + public ResponseEntity sendFriendRequestNotification( + @Valid @RequestBody FriendNotificationRequest request + ) { + notificationService.sendFriendRequestsNotification( + notificationMapper.friendNotificationRequestToDto(request)); + + return ResponseEntity.noContent().build(); + } + + @PostMapping("/friend-accept/send") + public ResponseEntity sendFriendAcceptNotification( + @Valid @RequestBody FriendNotificationRequest request + ) { + notificationService.sendFriendAcceptNotification( + notificationMapper.friendNotificationRequestToDto(request)); + + return ResponseEntity.noContent().build(); + } + } From 6666b1e06a687dfcaa5b7b2cc97939d18e65f055 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Thu, 28 Mar 2024 22:15:50 +0900 Subject: [PATCH 139/314] =?UTF-8?q?feat:=20firebase=20=EC=95=8C=EB=A6=BC?= =?UTF-8?q?=20=EC=A0=84=EC=86=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/mapper/NotificationMapper.java | 32 ++++++++++++++++--- .../notification/entity/Notification.java | 1 + .../notification/infra/fcm/FCMManager.java | 32 +++++++++++++++---- 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/backend/notification/src/main/java/site/timecapsulearchive/notification/data/mapper/NotificationMapper.java b/backend/notification/src/main/java/site/timecapsulearchive/notification/data/mapper/NotificationMapper.java index 80f880b89..a3b030e17 100644 --- a/backend/notification/src/main/java/site/timecapsulearchive/notification/data/mapper/NotificationMapper.java +++ b/backend/notification/src/main/java/site/timecapsulearchive/notification/data/mapper/NotificationMapper.java @@ -2,7 +2,9 @@ import org.springframework.stereotype.Component; import site.timecapsulearchive.notification.data.dto.CapsuleSkinNotificationSendDto; +import site.timecapsulearchive.notification.data.dto.FriendNotificationDto; import site.timecapsulearchive.notification.data.request.CapsuleSkinNotificationSendRequest; +import site.timecapsulearchive.notification.data.request.FriendNotificationRequest; import site.timecapsulearchive.notification.entity.Notification; import site.timecapsulearchive.notification.entity.NotificationCategory; @@ -10,7 +12,7 @@ public class NotificationMapper { public CapsuleSkinNotificationSendDto capsuleSkinNotificationRequestToDto( - CapsuleSkinNotificationSendRequest request) { + final CapsuleSkinNotificationSendRequest request) { return CapsuleSkinNotificationSendDto.builder() .memberId(request.memberId()) .status(request.status()) @@ -21,15 +23,37 @@ public CapsuleSkinNotificationSendDto capsuleSkinNotificationRequestToDto( .build(); } - public Notification capsuleSkinNotificationSendDtoToEntity(CapsuleSkinNotificationSendDto dto, - NotificationCategory notificationCategory) { + public Notification capsuleSkinNotificationSendDtoToEntity( + final CapsuleSkinNotificationSendDto dto, + final NotificationCategory category) { return Notification.builder() .memberId(dto.memberId()) .title(dto.title()) .text(dto.text()) .imageUrl(dto.skinUrl()) - .notificationCategory(notificationCategory) + .notificationCategory(category) .status(dto.status()) .build(); } + + public FriendNotificationDto friendNotificationRequestToDto( + final FriendNotificationRequest request) { + return FriendNotificationDto.builder() + .memberId(request.memberId()) + .status(request.status()) + .title(request.title()) + .text(request.text()) + .build(); + } + + public Notification friendNotificationDtoToEntity(final FriendNotificationDto dto, + final NotificationCategory category) { + return Notification.builder() + .memberId(dto.memberId()) + .title(dto.title()) + .text(dto.text()) + .status(dto.status()) + .notificationCategory(category) + .build(); + } } diff --git a/backend/notification/src/main/java/site/timecapsulearchive/notification/entity/Notification.java b/backend/notification/src/main/java/site/timecapsulearchive/notification/entity/Notification.java index bd07d8d19..23dfff2fb 100644 --- a/backend/notification/src/main/java/site/timecapsulearchive/notification/entity/Notification.java +++ b/backend/notification/src/main/java/site/timecapsulearchive/notification/entity/Notification.java @@ -55,6 +55,7 @@ private Notification(String title, String text, String imageUrl, Long memberId, this.text = text; this.imageUrl = imageUrl; this.memberId = memberId; + this.status = status; this.notificationCategory = notificationCategory; } } diff --git a/backend/notification/src/main/java/site/timecapsulearchive/notification/infra/fcm/FCMManager.java b/backend/notification/src/main/java/site/timecapsulearchive/notification/infra/fcm/FCMManager.java index e22317fb0..ba75005fe 100644 --- a/backend/notification/src/main/java/site/timecapsulearchive/notification/infra/fcm/FCMManager.java +++ b/backend/notification/src/main/java/site/timecapsulearchive/notification/infra/fcm/FCMManager.java @@ -13,9 +13,8 @@ import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Component; import site.timecapsulearchive.notification.data.dto.CapsuleSkinNotificationSendDto; -import site.timecapsulearchive.notification.entity.NotificationStatus; +import site.timecapsulearchive.notification.data.dto.FriendNotificationDto; import site.timecapsulearchive.notification.entity.CategoryName; -import site.timecapsulearchive.notification.entity.Notification; import site.timecapsulearchive.notification.infra.exception.MessageNotSendableException; import site.timecapsulearchive.notification.infra.s3.S3PreSignedUrlManager; @@ -46,10 +45,10 @@ private InputStream getCredential() throws IOException { return new ClassPathResource(fcmProperties.secretKeyPath()).getInputStream(); } - public void send( - CapsuleSkinNotificationSendDto dto, - CategoryName categoryName, - String fcmToken + public void sendCapsuleSkinNotification( + final CapsuleSkinNotificationSendDto dto, + final CategoryName categoryName, + final String fcmToken ) { try { FirebaseMessaging.getInstance() @@ -67,4 +66,25 @@ public void send( throw new MessageNotSendableException(e); } } + + public void sendFriendNotification( + final FriendNotificationDto dto, + final CategoryName categoryName, + final String fcmToken + ) { + try { + FirebaseMessaging.getInstance() + .send( + Message.builder() + .putData(TOPIC_DATA_NAME, String.valueOf(categoryName)) + .putData(STATUS_DATA_NAME, String.valueOf(dto.status())) + .putData(TITLE_DATA_NAME, dto.title()) + .putData(TEXT_DATA_NAME, dto.text()) + .setToken(fcmToken) + .build() + ); + } catch (FirebaseMessagingException e) { + throw new MessageNotSendableException(e); + } + } } From dc685153b4ffcb58694c003079d7146dc301962b Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Thu, 28 Mar 2024 22:16:19 +0900 Subject: [PATCH 140/314] =?UTF-8?q?feat:=20=EC=B9=9C=EA=B5=AC=20=EA=B4=80?= =?UTF-8?q?=EA=B3=84=20=EC=95=8C=EB=A6=BC=20service=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/NotificationService.java | 51 ++++++++++++++++--- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/backend/notification/src/main/java/site/timecapsulearchive/notification/service/NotificationService.java b/backend/notification/src/main/java/site/timecapsulearchive/notification/service/NotificationService.java index 42d2141cd..4ba755ea6 100644 --- a/backend/notification/src/main/java/site/timecapsulearchive/notification/service/NotificationService.java +++ b/backend/notification/src/main/java/site/timecapsulearchive/notification/service/NotificationService.java @@ -4,6 +4,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import site.timecapsulearchive.notification.data.dto.CapsuleSkinNotificationSendDto; +import site.timecapsulearchive.notification.data.dto.FriendNotificationDto; import site.timecapsulearchive.notification.data.mapper.NotificationMapper; import site.timecapsulearchive.notification.entity.CategoryName; import site.timecapsulearchive.notification.entity.Notification; @@ -24,18 +25,56 @@ public class NotificationService { private final NotificationMapper notificationMapper; @Transactional - public void sendCapsuleSkinAlarm(CapsuleSkinNotificationSendDto dto) { - NotificationCategory notificationCategory = notificationCategoryRepository.findByCategoryName( - CategoryName.CAPSULE_SKIN); + public void sendCapsuleSkinAlarm(final CapsuleSkinNotificationSendDto dto) { + final CategoryName categoryName = CategoryName.CAPSULE_SKIN; + final NotificationCategory notificationCategory = notificationCategoryRepository.findByCategoryName( + categoryName); - Notification notification = notificationMapper.capsuleSkinNotificationSendDtoToEntity(dto, + final Notification notification = notificationMapper.capsuleSkinNotificationSendDtoToEntity( + dto, notificationCategory); notificationRepository.save(notification); - String fcmToken = memberRepository.findFCMToken(dto.memberId()); + final String fcmToken = memberRepository.findFCMToken(dto.memberId()); if (!fcmToken.isBlank()) { - fcmManager.send(dto, notificationCategory.getCategoryName(), fcmToken); + fcmManager.sendCapsuleSkinNotification(dto, categoryName, fcmToken); } } + + @Transactional + public void sendFriendRequestsNotification(final FriendNotificationDto dto) { + final CategoryName categoryName = CategoryName.FRIEND_REQUEST; + saveFriendNotification(categoryName, dto); + + sendFCM(dto, categoryName); + } + + private void saveFriendNotification( + final CategoryName categoryName, + final FriendNotificationDto dto + ) { + final NotificationCategory notificationCategory = notificationCategoryRepository.findByCategoryName( + categoryName); + + final Notification notification = notificationMapper.friendNotificationDtoToEntity(dto, + notificationCategory); + + notificationRepository.save(notification); + } + + private void sendFCM(FriendNotificationDto dto, CategoryName categoryName) { + final String fcmToken = memberRepository.findFCMToken(dto.memberId()); + if (!fcmToken.isBlank()) { + fcmManager.sendFriendNotification(dto, categoryName, fcmToken); + } + } + + @Transactional + public void sendFriendAcceptNotification(final FriendNotificationDto dto) { + final CategoryName categoryName = CategoryName.FRIEND_ACCEPT; + saveFriendNotification(categoryName, dto); + + sendFCM(dto, categoryName); + } } \ No newline at end of file From 20662c6440f6db5eedbb8bb90fbc1cbdc0ca24d5 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Thu, 28 Mar 2024 22:16:59 +0900 Subject: [PATCH 141/314] =?UTF-8?q?refact:=20=EC=95=8C=EB=A6=BC=20?= =?UTF-8?q?=EC=B9=B4=ED=85=8C=EA=B3=A0=EB=A6=AC=20=EB=8D=94=EB=AF=B8=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=82=BD=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/notification/src/main/resources/data.sql | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/backend/notification/src/main/resources/data.sql b/backend/notification/src/main/resources/data.sql index 199a45526..d8a19b6b1 100644 --- a/backend/notification/src/main/resources/data.sql +++ b/backend/notification/src/main/resources/data.sql @@ -1,3 +1,11 @@ INSERT INTO notification_category (category_name, category_description, created_at, updated_at) SELECT 'CAPSULE_SKIN', '캡슐 스킨 생성 관련', now(), now() WHERE NOT EXISTS(SELECT * FROM notification_category where category_name='CAPSULE_SKIN'); + +INSERT INTO notification_category (category_name, category_description, created_at, updated_at) +SELECT 'FRIEND_REQUEST', '친구 요청 관련', now(), now() +WHERE NOT EXISTS(SELECT * FROM notification_category where category_name='FRIEND_REQUEST'); + +INSERT INTO notification_category (category_name, category_description, created_at, updated_at) +SELECT 'FRIEND_ACCEPT', '친구 수락 관련', now(), now() +WHERE NOT EXISTS(SELECT * FROM notification_category where category_name='FRIEND_ACCEPT'); From 57d336fa1fae237417a43c8281ba7da5995d9c05 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Thu, 28 Mar 2024 22:20:09 +0900 Subject: [PATCH 142/314] =?UTF-8?q?feat:=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notification/api/NotificationController.java | 1 + .../timecapsulearchive/notification/infra/fcm/FCMManager.java | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/notification/src/main/java/site/timecapsulearchive/notification/api/NotificationController.java b/backend/notification/src/main/java/site/timecapsulearchive/notification/api/NotificationController.java index 00a6e8938..4132b451f 100644 --- a/backend/notification/src/main/java/site/timecapsulearchive/notification/api/NotificationController.java +++ b/backend/notification/src/main/java/site/timecapsulearchive/notification/api/NotificationController.java @@ -9,6 +9,7 @@ import org.springframework.web.bind.annotation.RestController; import site.timecapsulearchive.notification.data.mapper.NotificationMapper; import site.timecapsulearchive.notification.data.request.CapsuleSkinNotificationSendRequest; +import site.timecapsulearchive.notification.data.request.FriendNotificationRequest; import site.timecapsulearchive.notification.service.NotificationService; @RestController diff --git a/backend/notification/src/main/java/site/timecapsulearchive/notification/infra/fcm/FCMManager.java b/backend/notification/src/main/java/site/timecapsulearchive/notification/infra/fcm/FCMManager.java index ba75005fe..2a835f969 100644 --- a/backend/notification/src/main/java/site/timecapsulearchive/notification/infra/fcm/FCMManager.java +++ b/backend/notification/src/main/java/site/timecapsulearchive/notification/infra/fcm/FCMManager.java @@ -58,8 +58,9 @@ public void sendCapsuleSkinNotification( .putData(STATUS_DATA_NAME, String.valueOf(dto.status())) .putData(TITLE_DATA_NAME, dto.title()) .putData(TEXT_DATA_NAME, dto.text()) - .putData(IMAGE_DATA_NAME, s3PreSignedUrlManager.createS3PreSignedUrlForGet(dto.skinUrl())) .setToken(fcmToken) + .putData(IMAGE_DATA_NAME, + s3PreSignedUrlManager.createS3PreSignedUrlForGet(dto.skinUrl())) .build() ); } catch (FirebaseMessagingException e) { From 6526664db5bfdafd9246b91af15f824ab1fe66bc Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Thu, 28 Mar 2024 22:23:52 +0900 Subject: [PATCH 143/314] =?UTF-8?q?chore:=20config=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/core/src/main/resources/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/core/src/main/resources/config b/backend/core/src/main/resources/config index 22f616d77..2c258201f 160000 --- a/backend/core/src/main/resources/config +++ b/backend/core/src/main/resources/config @@ -1 +1 @@ -Subproject commit 22f616d7743c5c149bcaa92c640d9727c22f6e17 +Subproject commit 2c258201ff4a03d1a611098759694188b69b00e5 From 694e2556621e81e172b06a17f032b1a65d8b65cd Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Thu, 28 Mar 2024 22:45:40 +0900 Subject: [PATCH 144/314] =?UTF-8?q?refact:=20NotNull=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/CapsuleSkinNotificationSendRequest.java | 12 ++++++------ .../data/request/FriendNotificationRequest.java | 10 ++++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/backend/notification/src/main/java/site/timecapsulearchive/notification/data/request/CapsuleSkinNotificationSendRequest.java b/backend/notification/src/main/java/site/timecapsulearchive/notification/data/request/CapsuleSkinNotificationSendRequest.java index b7521ee92..cbad10cd3 100644 --- a/backend/notification/src/main/java/site/timecapsulearchive/notification/data/request/CapsuleSkinNotificationSendRequest.java +++ b/backend/notification/src/main/java/site/timecapsulearchive/notification/data/request/CapsuleSkinNotificationSendRequest.java @@ -6,22 +6,22 @@ public record CapsuleSkinNotificationSendRequest( - @NotNull + @NotNull(message = "멤버 아이디는 필수 입니다.") Long memberId, - @NotNull + @NotNull(message = "알림 상태는 필수 입니다.") NotificationStatus status, - @NotBlank + @NotBlank(message = "스킨 이름은 필수 입니다.") String skinName, - @NotBlank + @NotBlank(message = "알림 내용은 필수 입니다.") String title, - @NotBlank + @NotBlank(message = "알림 내용은 필수 입니다.") String text, - @NotBlank + @NotBlank(message = "스킨 URL은 필수 입니다.") String skinUrl ) { diff --git a/backend/notification/src/main/java/site/timecapsulearchive/notification/data/request/FriendNotificationRequest.java b/backend/notification/src/main/java/site/timecapsulearchive/notification/data/request/FriendNotificationRequest.java index 91a76dfec..185dbc7a5 100644 --- a/backend/notification/src/main/java/site/timecapsulearchive/notification/data/request/FriendNotificationRequest.java +++ b/backend/notification/src/main/java/site/timecapsulearchive/notification/data/request/FriendNotificationRequest.java @@ -1,11 +1,21 @@ package site.timecapsulearchive.notification.data.request; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import site.timecapsulearchive.notification.entity.NotificationStatus; public record FriendNotificationRequest( + + @NotNull(message = "멤버 아이디는 필수 입니다.") Long memberId, + + @NotNull(message = "알림 상태는 필수 입니다.") NotificationStatus status, + + @NotBlank(message = "알림 제목은 필수 입니다.") String text, + + @NotBlank(message = "알림 내용은 필수 입니다.") String title ) { From 99ecae89caff62c3589adae7c2a81ba3f6afd11c Mon Sep 17 00:00:00 2001 From: hong seokho Date: Thu, 28 Mar 2024 22:49:06 +0900 Subject: [PATCH 145/314] =?UTF-8?q?fix=20:=20=EC=9A=94=EC=B2=AD=20?= =?UTF-8?q?=ED=94=84=EB=A1=9C=ED=8D=BC=ED=8B=B0=20=EC=9D=B4=EB=A6=84=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/aop/aspect/NotificationRequestExceptionAspect.java | 2 -- .../data/dto/request/FriendAcceptNotificationRequest.java | 3 +-- .../data/dto/request/FriendReqNotificationRequest.java | 2 +- .../infra/notification/data/mapper/NotificationMapper.java | 4 ++-- backend/core/src/main/resources/config | 2 +- 5 files changed, 5 insertions(+), 8 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/aop/aspect/NotificationRequestExceptionAspect.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/aop/aspect/NotificationRequestExceptionAspect.java index 8eba031e7..499a320cb 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/aop/aspect/NotificationRequestExceptionAspect.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/aop/aspect/NotificationRequestExceptionAspect.java @@ -44,6 +44,4 @@ public void sendNotification(T request, String url) { throw new ExternalApiException(ErrorCode.EXTERNAL_API_ERROR); } } - - } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/dto/request/FriendAcceptNotificationRequest.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/dto/request/FriendAcceptNotificationRequest.java index 0b2dd1782..2455e5bc8 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/dto/request/FriendAcceptNotificationRequest.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/dto/request/FriendAcceptNotificationRequest.java @@ -4,11 +4,10 @@ @Builder public record FriendAcceptNotificationRequest( - Long memberId, + Long targetId, String status, String title, String text - ) { } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/dto/request/FriendReqNotificationRequest.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/dto/request/FriendReqNotificationRequest.java index 760f61b14..83ca1ffbd 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/dto/request/FriendReqNotificationRequest.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/dto/request/FriendReqNotificationRequest.java @@ -4,7 +4,7 @@ @Builder public record FriendReqNotificationRequest( - Long friendId, + Long targetId, String status, String title, String text diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java index 21d6bc799..26ae7e7ca 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/infra/notification/data/mapper/NotificationMapper.java @@ -34,7 +34,7 @@ public FriendReqNotificationRequest friendReqToMessage( final String ownerNickname ) { return FriendReqNotificationRequest.builder() - .friendId(friendId) + .targetId(friendId) .status(NOTIFICATION_SEND_SUCCESS) .title("친구 요청 알림") .text(ownerNickname + "로부터 친구 요청이 왔습니다. ARchive에서 확인해보세요!") @@ -46,7 +46,7 @@ public FriendAcceptNotificationRequest friendAcceptToMessage( final String ownerNickname ) { return FriendAcceptNotificationRequest.builder() - .memberId(friendId) + .targetId(friendId) .status(NOTIFICATION_SEND_SUCCESS) .title("친구 수락 알림") .text(ownerNickname + "님이 친구 요청을 수락하였습니다. ARchive에서 확인해보세요!") diff --git a/backend/core/src/main/resources/config b/backend/core/src/main/resources/config index 2c258201f..22f616d77 160000 --- a/backend/core/src/main/resources/config +++ b/backend/core/src/main/resources/config @@ -1 +1 @@ -Subproject commit 2c258201ff4a03d1a611098759694188b69b00e5 +Subproject commit 22f616d7743c5c149bcaa92c640d9727c22f6e17 From ab4807a6fcae78bd798f0e2a8381475a5b8d9c2f Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Thu, 28 Mar 2024 22:50:18 +0900 Subject: [PATCH 146/314] =?UTF-8?q?refact:=20memberId=20->=20targetId?= =?UTF-8?q?=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notification/data/dto/FriendNotificationDto.java | 4 ++-- .../notification/data/mapper/NotificationMapper.java | 4 ++-- .../notification/data/request/FriendNotificationRequest.java | 2 +- .../notification/service/NotificationService.java | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/notification/src/main/java/site/timecapsulearchive/notification/data/dto/FriendNotificationDto.java b/backend/notification/src/main/java/site/timecapsulearchive/notification/data/dto/FriendNotificationDto.java index b37ff9c05..51986dad1 100644 --- a/backend/notification/src/main/java/site/timecapsulearchive/notification/data/dto/FriendNotificationDto.java +++ b/backend/notification/src/main/java/site/timecapsulearchive/notification/data/dto/FriendNotificationDto.java @@ -6,14 +6,14 @@ @Builder public record FriendNotificationDto( - Long memberId, + Long targetId, NotificationStatus status, String text, String title ) { public FriendNotificationDto { - Objects.requireNonNull(memberId); + Objects.requireNonNull(targetId); Objects.requireNonNull(status); Objects.requireNonNull(text); Objects.requireNonNull(title); diff --git a/backend/notification/src/main/java/site/timecapsulearchive/notification/data/mapper/NotificationMapper.java b/backend/notification/src/main/java/site/timecapsulearchive/notification/data/mapper/NotificationMapper.java index a3b030e17..d25da32f0 100644 --- a/backend/notification/src/main/java/site/timecapsulearchive/notification/data/mapper/NotificationMapper.java +++ b/backend/notification/src/main/java/site/timecapsulearchive/notification/data/mapper/NotificationMapper.java @@ -39,7 +39,7 @@ public Notification capsuleSkinNotificationSendDtoToEntity( public FriendNotificationDto friendNotificationRequestToDto( final FriendNotificationRequest request) { return FriendNotificationDto.builder() - .memberId(request.memberId()) + .targetId(request.targetId()) .status(request.status()) .title(request.title()) .text(request.text()) @@ -49,7 +49,7 @@ public FriendNotificationDto friendNotificationRequestToDto( public Notification friendNotificationDtoToEntity(final FriendNotificationDto dto, final NotificationCategory category) { return Notification.builder() - .memberId(dto.memberId()) + .memberId(dto.targetId()) .title(dto.title()) .text(dto.text()) .status(dto.status()) diff --git a/backend/notification/src/main/java/site/timecapsulearchive/notification/data/request/FriendNotificationRequest.java b/backend/notification/src/main/java/site/timecapsulearchive/notification/data/request/FriendNotificationRequest.java index 185dbc7a5..44956bcd7 100644 --- a/backend/notification/src/main/java/site/timecapsulearchive/notification/data/request/FriendNotificationRequest.java +++ b/backend/notification/src/main/java/site/timecapsulearchive/notification/data/request/FriendNotificationRequest.java @@ -7,7 +7,7 @@ public record FriendNotificationRequest( @NotNull(message = "멤버 아이디는 필수 입니다.") - Long memberId, + Long targetId, @NotNull(message = "알림 상태는 필수 입니다.") NotificationStatus status, diff --git a/backend/notification/src/main/java/site/timecapsulearchive/notification/service/NotificationService.java b/backend/notification/src/main/java/site/timecapsulearchive/notification/service/NotificationService.java index 4ba755ea6..bf42b0a06 100644 --- a/backend/notification/src/main/java/site/timecapsulearchive/notification/service/NotificationService.java +++ b/backend/notification/src/main/java/site/timecapsulearchive/notification/service/NotificationService.java @@ -64,7 +64,7 @@ private void saveFriendNotification( } private void sendFCM(FriendNotificationDto dto, CategoryName categoryName) { - final String fcmToken = memberRepository.findFCMToken(dto.memberId()); + final String fcmToken = memberRepository.findFCMToken(dto.targetId()); if (!fcmToken.isBlank()) { fcmManager.sendFriendNotification(dto, categoryName, fcmToken); } From 20941b684c2ae76b1f3f7d2a47944ba966456c11 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Thu, 28 Mar 2024 23:13:16 +0900 Subject: [PATCH 147/314] =?UTF-8?q?chore:=20yml=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/core/src/main/resources/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/core/src/main/resources/config b/backend/core/src/main/resources/config index 22f616d77..2c258201f 160000 --- a/backend/core/src/main/resources/config +++ b/backend/core/src/main/resources/config @@ -1 +1 @@ -Subproject commit 22f616d7743c5c149bcaa92c640d9727c22f6e17 +Subproject commit 2c258201ff4a03d1a611098759694188b69b00e5 From 1c53971b341732c9726efa2f61e4bfb6d5b20ad7 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Thu, 28 Mar 2024 23:31:43 +0900 Subject: [PATCH 148/314] =?UTF-8?q?refact:=20=EC=B9=9C=EA=B5=AC=20?= =?UTF-8?q?=EC=95=84=EC=9D=B4=EB=94=94=20=EC=A4=91=EB=B3=B5=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/api/FriendApi.java | 6 +++--- .../exception/DuplicateFriendIdException.java | 11 +++++++++++ .../domain/friend/service/FriendService.java | 17 +++++++++++++++-- .../core/global/error/ErrorCode.java | 3 ++- 4 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/exception/DuplicateFriendIdException.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java index 36d5f7422..df0457460 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java @@ -41,8 +41,8 @@ public interface FriendApi { ResponseEntity> acceptFriendRequest( Long memberId, - @Parameter(in = ParameterIn.QUERY, required = true, schema = @Schema()) - @RequestParam(value = "friend_id") Long friendId + @Parameter(in = ParameterIn.PATH, required = true, schema = @Schema()) + Long friendId ); @@ -88,7 +88,7 @@ ResponseEntity> deleteFriend( ResponseEntity> denyFriendRequest( Long memberId, - @Parameter(in = ParameterIn.QUERY, required = true, schema = @Schema()) + @Parameter(in = ParameterIn.PATH, required = true, schema = @Schema()) Long friendId ); diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/exception/DuplicateFriendIdException.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/exception/DuplicateFriendIdException.java new file mode 100644 index 000000000..9c8afdb4e --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/exception/DuplicateFriendIdException.java @@ -0,0 +1,11 @@ +package site.timecapsulearchive.core.domain.friend.exception; + +import site.timecapsulearchive.core.global.error.ErrorCode; +import site.timecapsulearchive.core.global.error.exception.BusinessException; + +public class DuplicateFriendIdException extends BusinessException { + + public DuplicateFriendIdException() { + super(ErrorCode.FRIEND_DUPLICATE_ID_ERROR); + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java index 80de8f96b..f89205944 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -21,6 +21,7 @@ import site.timecapsulearchive.core.domain.friend.data.response.SearchFriendsResponse; import site.timecapsulearchive.core.domain.friend.entity.FriendInvite; import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; +import site.timecapsulearchive.core.domain.friend.exception.DuplicateFriendIdException; import site.timecapsulearchive.core.domain.friend.exception.FriendNotFoundException; import site.timecapsulearchive.core.domain.friend.repository.FriendInviteRepository; import site.timecapsulearchive.core.domain.friend.repository.MemberFriendQueryRepository; @@ -66,6 +67,9 @@ public FriendService( } public FriendReqStatusResponse requestFriend(final Long memberId, final Long friendId) { + if (memberId.equals(friendId)){ + throw new DuplicateFriendIdException(); + } final Member owner = memberRepository.findMemberById(memberId).orElseThrow( MemberNotFoundException::new); @@ -87,6 +91,9 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { } public void acceptFriend(final Long memberId, final Long friendId) { + if (memberId.equals(friendId)){ + throw new DuplicateFriendIdException(); + } final FriendInvite friendInvite = friendInviteRepository .findFriendInviteWithMembersByOwnerIdAndFriendId(memberId, friendId) .orElseThrow(FriendNotFoundException::new); @@ -108,6 +115,9 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { @Transactional public void denyRequestFriend(Long memberId, Long friendId) { + if (memberId.equals(friendId)){ + throw new DuplicateFriendIdException(); + } final FriendInvite friendInvite = friendInviteRepository .findFriendInviteByOwnerIdAndFriendId(memberId, friendId).orElseThrow( FriendNotFoundException::new); @@ -116,9 +126,12 @@ public void denyRequestFriend(Long memberId, Long friendId) { } @Transactional - public void deleteFriend(final Long memberId, final Long friend2Id) { + public void deleteFriend(final Long memberId, final Long friendId) { + if (memberId.equals(friendId)){ + throw new DuplicateFriendIdException(); + } memberFriendRepository - .findMemberFriendByOwnerIdAndFriendId(memberId, friend2Id) + .findMemberFriendByOwnerIdAndFriendId(memberId, friendId) .forEach(memberFriendRepository::delete); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java index 2a2807559..4bce626ea 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java @@ -53,7 +53,8 @@ public enum ErrorCode { CAPSULE_NOT_FOUND_ERROR(404, "CAPSULE-001", "캡슐을 찾지 못하였습니다."), //friend - FRIEND_NOT_FOUND_ERROR(404, "FRIEND-001", "친구를 찾지 못하였습니다"); + FRIEND_NOT_FOUND_ERROR(404, "FRIEND-001", "친구를 찾지 못하였습니다"), + FRIEND_DUPLICATE_ID_ERROR(404, "FRIEND-001", "친구 아이디가 중복되었습니다."); private final int status; private final String code; From fc0df543e04443f50c18ef92386985fe622470a0 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Fri, 29 Mar 2024 23:36:25 +0900 Subject: [PATCH 149/314] =?UTF-8?q?refact:=20Http=20=EB=A7=A4=ED=95=91=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EA=B5=AC=EA=B8=80=20=EC=9E=90?= =?UTF-8?q?=EB=B0=94=20=ED=98=95=EC=8B=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/friend/api/FriendApi.java | 3 +-- .../core/domain/friend/api/FriendApiController.java | 2 +- .../core/domain/friend/service/FriendService.java | 8 ++++---- .../resources/db/migration/V18__member_friend_update.sql | 4 ++-- .../main/resources/db/migration/V20__member_add_tag.sql | 4 +++- .../main/resources/db/migration/V21__member_update.sql | 7 +++++-- 6 files changed, 16 insertions(+), 12 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java index df0457460..78b329695 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApi.java @@ -10,7 +10,6 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement; import java.time.ZonedDateTime; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RequestParam; import site.timecapsulearchive.core.domain.friend.data.reqeust.SearchFriendsRequest; import site.timecapsulearchive.core.domain.friend.data.response.FriendReqStatusResponse; import site.timecapsulearchive.core.domain.friend.data.response.FriendRequestsSliceResponse; @@ -193,7 +192,7 @@ ResponseEntity> searchMembersByPhones( ResponseEntity> searchFriendByTag( Long memberId, - @Parameter(in = ParameterIn.QUERY, description = "페이지 크기", required = true) + @Parameter(in = ParameterIn.QUERY, description = "친구 태그", required = true) String tag ); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java index 153b1d064..07e6302d6 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/api/FriendApiController.java @@ -132,7 +132,7 @@ public ResponseEntity> searchMembersByPhones( ); } - @PostMapping(value = "/search") + @GetMapping(value = "/search") @Override public ResponseEntity> searchFriendByTag( @AuthenticationPrincipal Long memberId, diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java index f89205944..2ff2b889a 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/friend/service/FriendService.java @@ -67,7 +67,7 @@ public FriendService( } public FriendReqStatusResponse requestFriend(final Long memberId, final Long friendId) { - if (memberId.equals(friendId)){ + if (memberId.equals(friendId)) { throw new DuplicateFriendIdException(); } final Member owner = memberRepository.findMemberById(memberId).orElseThrow( @@ -91,7 +91,7 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { } public void acceptFriend(final Long memberId, final Long friendId) { - if (memberId.equals(friendId)){ + if (memberId.equals(friendId)) { throw new DuplicateFriendIdException(); } final FriendInvite friendInvite = friendInviteRepository @@ -115,7 +115,7 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { @Transactional public void denyRequestFriend(Long memberId, Long friendId) { - if (memberId.equals(friendId)){ + if (memberId.equals(friendId)) { throw new DuplicateFriendIdException(); } final FriendInvite friendInvite = friendInviteRepository @@ -127,7 +127,7 @@ public void denyRequestFriend(Long memberId, Long friendId) { @Transactional public void deleteFriend(final Long memberId, final Long friendId) { - if (memberId.equals(friendId)){ + if (memberId.equals(friendId)) { throw new DuplicateFriendIdException(); } memberFriendRepository diff --git a/backend/core/src/main/resources/db/migration/V18__member_friend_update.sql b/backend/core/src/main/resources/db/migration/V18__member_friend_update.sql index f16163578..eea55dfe6 100644 --- a/backend/core/src/main/resources/db/migration/V18__member_friend_update.sql +++ b/backend/core/src/main/resources/db/migration/V18__member_friend_update.sql @@ -7,9 +7,9 @@ ALTER TABLE member_friend ADD COLUMN owner_id BIGINT; ALTER TABLE member_friend ADD COLUMN friend_id BIGINT; - + ALTER TABLE member_friend ADD CONSTRAINT fk_member_friend_owner_id FOREIGN KEY (owner_id) REFERENCES member (member_id); -ALTER TABLE member_friend +ALTER TABLE member_friend ADD CONSTRAINT fk_member_friend_friend_id FOREIGN KEY (friend_id) REFERENCES member (member_id); diff --git a/backend/core/src/main/resources/db/migration/V20__member_add_tag.sql b/backend/core/src/main/resources/db/migration/V20__member_add_tag.sql index 0f685b7f9..28dff474c 100644 --- a/backend/core/src/main/resources/db/migration/V20__member_add_tag.sql +++ b/backend/core/src/main/resources/db/migration/V20__member_add_tag.sql @@ -1,3 +1,5 @@ ALTER TABLE member ADD COLUMN tag VARCHAR(255); -ALTER TABLE member MODIFY tag VARCHAR(255) NOT NULL, ADD CONSTRAINT unique_tag UNIQUE (tag); \ No newline at end of file +ALTER TABLE member + MODIFY tag VARCHAR(255) NOT NULL, + ADD CONSTRAINT unique_tag UNIQUE (tag); \ No newline at end of file diff --git a/backend/core/src/main/resources/db/migration/V21__member_update.sql b/backend/core/src/main/resources/db/migration/V21__member_update.sql index e260e9731..ece448d60 100644 --- a/backend/core/src/main/resources/db/migration/V21__member_update.sql +++ b/backend/core/src/main/resources/db/migration/V21__member_update.sql @@ -1,2 +1,5 @@ -ALTER TABLE member ADD COLUMN password VARCHAR(255); -ALTER TABLE member MODIFY email VARCHAR(255) NOT NULL, ADD CONSTRAINT unique_email UNIQUE (email); \ No newline at end of file +ALTER TABLE member + ADD COLUMN password VARCHAR(255); +ALTER TABLE member + MODIFY email VARCHAR(255) NOT NULL, + ADD CONSTRAINT unique_email UNIQUE (email); \ No newline at end of file From f3007c437e843e6af563b570758368431cd578c9 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 30 Mar 2024 10:25:58 +0900 Subject: [PATCH 150/314] =?UTF-8?q?fix=20:=20flyway=20schema=20validation?= =?UTF-8?q?=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/db/migration/V18__member_friend_update.sql | 4 ++-- .../main/resources/db/migration/V20__member_add_tag.sql | 4 +--- .../src/main/resources/db/migration/V21__member_update.sql | 7 ++----- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/backend/core/src/main/resources/db/migration/V18__member_friend_update.sql b/backend/core/src/main/resources/db/migration/V18__member_friend_update.sql index eea55dfe6..f16163578 100644 --- a/backend/core/src/main/resources/db/migration/V18__member_friend_update.sql +++ b/backend/core/src/main/resources/db/migration/V18__member_friend_update.sql @@ -7,9 +7,9 @@ ALTER TABLE member_friend ADD COLUMN owner_id BIGINT; ALTER TABLE member_friend ADD COLUMN friend_id BIGINT; - + ALTER TABLE member_friend ADD CONSTRAINT fk_member_friend_owner_id FOREIGN KEY (owner_id) REFERENCES member (member_id); -ALTER TABLE member_friend +ALTER TABLE member_friend ADD CONSTRAINT fk_member_friend_friend_id FOREIGN KEY (friend_id) REFERENCES member (member_id); diff --git a/backend/core/src/main/resources/db/migration/V20__member_add_tag.sql b/backend/core/src/main/resources/db/migration/V20__member_add_tag.sql index 28dff474c..0f685b7f9 100644 --- a/backend/core/src/main/resources/db/migration/V20__member_add_tag.sql +++ b/backend/core/src/main/resources/db/migration/V20__member_add_tag.sql @@ -1,5 +1,3 @@ ALTER TABLE member ADD COLUMN tag VARCHAR(255); -ALTER TABLE member - MODIFY tag VARCHAR(255) NOT NULL, - ADD CONSTRAINT unique_tag UNIQUE (tag); \ No newline at end of file +ALTER TABLE member MODIFY tag VARCHAR(255) NOT NULL, ADD CONSTRAINT unique_tag UNIQUE (tag); \ No newline at end of file diff --git a/backend/core/src/main/resources/db/migration/V21__member_update.sql b/backend/core/src/main/resources/db/migration/V21__member_update.sql index ece448d60..e260e9731 100644 --- a/backend/core/src/main/resources/db/migration/V21__member_update.sql +++ b/backend/core/src/main/resources/db/migration/V21__member_update.sql @@ -1,5 +1,2 @@ -ALTER TABLE member - ADD COLUMN password VARCHAR(255); -ALTER TABLE member - MODIFY email VARCHAR(255) NOT NULL, - ADD CONSTRAINT unique_email UNIQUE (email); \ No newline at end of file +ALTER TABLE member ADD COLUMN password VARCHAR(255); +ALTER TABLE member MODIFY email VARCHAR(255) NOT NULL, ADD CONSTRAINT unique_email UNIQUE (email); \ No newline at end of file From 030b3849acfa8780392956676752a53bff9b3a7f Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 30 Mar 2024 12:35:39 +0900 Subject: [PATCH 151/314] =?UTF-8?q?fix=20:=20=EC=95=8C=EB=A6=BC=20?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=A1=B0=ED=9A=8C=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 이미지가 null인 경우가 추가되어 null 예외 처리 --- .../member/api/MemberApiController.java | 2 +- .../member/data/mapper/MemberMapper.java | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java index c77dcc30a..1ab7132d2 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/api/MemberApiController.java @@ -106,7 +106,7 @@ public ResponseEntity> checkMemberNoti public ResponseEntity> getMemberNotifications( @AuthenticationPrincipal final Long memberId, @RequestParam(defaultValue = "20", value = "size") final int size, - @RequestParam(defaultValue = "0", value = "createdAt") final ZonedDateTime createdAt + @RequestParam(value = "createdAt") final ZonedDateTime createdAt ) { return ResponseEntity.ok( ApiSpec.success( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java index 4716160ad..d047d1819 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java @@ -73,12 +73,19 @@ public MemberNotificationSliceResponse notificationSliceToResponse( final boolean hasNext ) { List responses = content.stream() - .map(dto -> MemberNotificationResponse.builder() - .title(dto.title()) - .text(dto.text()) - .createdAt(dto.createdAt().withZoneSameInstant(ASIA_SEOUL)) - .imageUrl(s3PreSignedUrlManager.getS3PreSignedUrlForGet(dto.imageUrl())) - .build() + .map(dto -> { + String imageUrl = ""; + if (dto.imageUrl() != null) { + imageUrl = s3PreSignedUrlManager.getS3PreSignedUrlForGet(dto.imageUrl()); + } + + return MemberNotificationResponse.builder() + .title(dto.title()) + .text(dto.text()) + .createdAt(dto.createdAt().withZoneSameInstant(ASIA_SEOUL)) + .imageUrl(imageUrl) + .build(); + } ) .toList(); From fa4bc2b74c03c642a04706606e004d092e5ae8be Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 30 Mar 2024 12:36:44 +0900 Subject: [PATCH 152/314] =?UTF-8?q?test=20:=20=EC=95=8C=EB=A6=BC=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=EC=9A=A9=20=EB=A0=88=ED=8F=AC=EC=A7=80?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/data/MemberTestDataRepository.java | 96 +++++++++++++ .../MemberFriendQueryRepositoryTest.java | 136 ++++++------------ .../MemberFriendRepositoryTest.java | 49 ++----- .../repository/MemberQueryRepositoryTest.java | 75 ++++++++-- 4 files changed, 210 insertions(+), 146 deletions(-) create mode 100644 backend/core/src/test/java/site/timecapsulearchive/core/common/data/MemberTestDataRepository.java diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/common/data/MemberTestDataRepository.java b/backend/core/src/test/java/site/timecapsulearchive/core/common/data/MemberTestDataRepository.java new file mode 100644 index 000000000..5bf6dbea1 --- /dev/null +++ b/backend/core/src/test/java/site/timecapsulearchive/core/common/data/MemberTestDataRepository.java @@ -0,0 +1,96 @@ +package site.timecapsulearchive.core.common.data; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.Query; +import java.nio.charset.StandardCharsets; +import java.time.ZonedDateTime; +import site.timecapsulearchive.core.domain.friend.entity.FriendInvite; +import site.timecapsulearchive.core.domain.friend.entity.FriendStatus; +import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; +import site.timecapsulearchive.core.domain.member.entity.Member; +import site.timecapsulearchive.core.domain.member.entity.SocialType; +import site.timecapsulearchive.core.global.security.encryption.HashEncryptionManager; +import site.timecapsulearchive.core.global.security.encryption.HashProperties; + +public class MemberTestDataRepository { + + private final HashEncryptionManager hash = new HashEncryptionManager( + new HashProperties("test")); + + public Member insertAndGetMember(EntityManager entityManager, int dataPrefix) { + Member member = Member.builder() + .socialType(SocialType.GOOGLE) + .nickname(dataPrefix + "testNickname") + .email(dataPrefix + "test@google.com") + .authId(dataPrefix + "test") + .profileUrl(dataPrefix + "test.com") + .tag(dataPrefix + "testTag") + .build(); + + byte[] number = getPhoneBytes(dataPrefix); + member.updatePhoneHash(hash.encrypt(number)); + + entityManager.persist(member); + + return member; + } + + public byte[] getPhoneBytes(int dataPrefix) { + return ("0" + (1000000000 + dataPrefix)).getBytes(StandardCharsets.UTF_8); + } + + public void insertNotificationCategory(EntityManager entityManager) { + Query notificationCategoryInsert = entityManager.createNativeQuery( + "INSERT INTO notification_category(notification_category_id, category_name, category_description, created_at, updated_at) VALUES (?, ?, ?, ?, ?)"); + + ZonedDateTime now = ZonedDateTime.now(); + + notificationCategoryInsert.setParameter(1, 1L); + notificationCategoryInsert.setParameter(2, "test_category"); + notificationCategoryInsert.setParameter(3, "test_category"); + notificationCategoryInsert.setParameter(4, now); + notificationCategoryInsert.setParameter(5, now); + + notificationCategoryInsert.executeUpdate(); + } + + public void insertNotification(EntityManager entityManager, Long memberId, int size) { + for (int count = 0; count < size; count++) { + Query notificationInsert = entityManager.createNativeQuery( + "INSERT INTO notification(title, text, image_url, member_id, notification_category_id,created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)"); + + String imageUrl = null; + if (count % 2 == 0) { + imageUrl = "image"; + } + + ZonedDateTime now = ZonedDateTime.now(); + notificationInsert.setParameter(1, "title"); + notificationInsert.setParameter(2, "text"); + notificationInsert.setParameter(3, imageUrl); + notificationInsert.setParameter(4, memberId); + notificationInsert.setParameter(5, 1L); + notificationInsert.setParameter(6, now); + notificationInsert.setParameter(7, now); + + notificationInsert.executeUpdate(); + } + } + + public void insertMemberFriend(EntityManager entityManager, Member owner, Member friend) { + MemberFriend memberFriend = MemberFriend.builder() + .friend(friend) + .owner(owner) + .build(); + entityManager.persist(memberFriend); + } + + public void insertFriendInvite(EntityManager entityManager, Member owner, Member friend) { + FriendInvite friendInvite = FriendInvite.builder() + .friend(friend) + .owner(owner) + .friendStatus(FriendStatus.PENDING) + .build(); + entityManager.persist(friendInvite); + } +} diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java index cfffae92c..2488ebbe7 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendQueryRepositoryTest.java @@ -5,14 +5,13 @@ import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; -import java.nio.charset.StandardCharsets; import java.time.ZoneId; import java.time.ZonedDateTime; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.stream.IntStream; import org.flywaydb.test.annotation.FlywayTest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -24,27 +23,26 @@ import org.springframework.test.context.TestConstructor.AutowireMode; import org.springframework.transaction.annotation.Transactional; import site.timecapsulearchive.core.common.RepositoryTest; +import site.timecapsulearchive.core.common.data.MemberTestDataRepository; import site.timecapsulearchive.core.domain.friend.data.dto.FriendSummaryDto; import site.timecapsulearchive.core.domain.friend.data.dto.SearchFriendSummaryDto; -import site.timecapsulearchive.core.domain.friend.entity.FriendInvite; -import site.timecapsulearchive.core.domain.friend.entity.FriendStatus; -import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; import site.timecapsulearchive.core.domain.member.entity.Member; -import site.timecapsulearchive.core.domain.member.entity.SocialType; -import site.timecapsulearchive.core.global.security.encryption.HashEncryptionManager; -import site.timecapsulearchive.core.global.security.encryption.HashProperties; @FlywayTest @TestConstructor(autowireMode = AutowireMode.ALL) class MemberFriendQueryRepositoryTest extends RepositoryTest { + private static final int MAX_FRIEND_ID = 21; + private static final int MAX_MEMBER_ID = 31; + + private final List hashedNotMemberPhones = new ArrayList<>(); + private final List hashedFriendPhones = new ArrayList<>(); + private final List hashedNotFriendPhones = new ArrayList<>(); + private final MemberFriendQueryRepository memberFriendQueryRepository; - private final HashEncryptionManager hash = new HashEncryptionManager( - new HashProperties("test")); - private final int MAX_FRIEND_ID = 21; - private final int MAX_MEMBER_ID = 31; + private final MemberTestDataRepository memberTestDataRepository = new MemberTestDataRepository(); - private Long ownerId; + private Member owner; MemberFriendQueryRepositoryTest(EntityManager entityManager) { this.memberFriendQueryRepository = new MemberFriendQueryRepository( @@ -54,52 +52,28 @@ class MemberFriendQueryRepositoryTest extends RepositoryTest { @Transactional @BeforeEach void setup(@Autowired EntityManager entityManager) { - Member owner = getMember(0); - entityManager.persist(owner); - ownerId = owner.getId(); + owner = memberTestDataRepository.insertAndGetMember(entityManager, 0); + //owner와 친구, 친구 초대 데이터 for (int i = 1; i < MAX_FRIEND_ID; i++) { - Member friend = getMember(i); - entityManager.persist(friend); - - MemberFriend memberFriend = MemberFriend.builder() - .friend(friend) - .owner(owner) - .build(); - entityManager.persist(memberFriend); - - FriendInvite friendInvite = FriendInvite.builder() - .friend(friend) - .owner(owner) - .friendStatus(FriendStatus.PENDING) - .build(); - entityManager.persist(friendInvite); + Member friend = memberTestDataRepository.insertAndGetMember(entityManager, i); + hashedFriendPhones.add(friend.getPhone_hash()); + + memberTestDataRepository.insertMemberFriend(entityManager, owner, friend); + memberTestDataRepository.insertMemberFriend(entityManager, friend, owner); + memberTestDataRepository.insertFriendInvite(entityManager, owner, friend); } + //owner와 친구가 아닌 멤버 데이터 for (int i = MAX_FRIEND_ID; i < MAX_FRIEND_ID + 10; i++) { - Member friend = getMember(i); - entityManager.persist(friend); + Member notFriend = memberTestDataRepository.insertAndGetMember(entityManager, i); + hashedNotFriendPhones.add(notFriend.getPhone_hash()); } - } - private Member getMember(int count) { - Member member = Member.builder() - .socialType(SocialType.GOOGLE) - .nickname(count + "testNickname") - .email(count + "test@google.com") - .authId(count + "test") - .profileUrl(count + "test.com") - .tag(count + "testTag") - .build(); - - byte[] number = getPhoneBytes(count); - member.updatePhoneHash(hash.encrypt(number)); - - return member; - } - - private byte[] getPhoneBytes(int count) { - return ("0" + (1000000000 + count)).getBytes(StandardCharsets.UTF_8); + //회원이 아닌 휴대전화번호 데이터 + for (int i = MAX_FRIEND_ID + 20; i < MAX_FRIEND_ID + 30; i++) { + hashedNotMemberPhones.add(memberTestDataRepository.getPhoneBytes(i)); + } } @ParameterizedTest @@ -110,7 +84,7 @@ private byte[] getPhoneBytes(int count) { //when Slice slice = memberFriendQueryRepository.findFriendsSlice( - ownerId, + owner.getId(), size, now ); @@ -134,7 +108,7 @@ private byte[] getPhoneBytes(int count) { //when Slice slice = memberFriendQueryRepository.findFriendsSlice( - ownerId, + owner.getId(), size, now ); @@ -151,7 +125,7 @@ private byte[] getPhoneBytes(int count) { //when Slice slice = memberFriendQueryRepository.findFriendsSlice( - ownerId, + owner.getId(), size, now ); @@ -168,7 +142,7 @@ private byte[] getPhoneBytes(int count) { //when Slice slice = memberFriendQueryRepository.findFriendRequestsSlice( - ownerId, + owner.getId(), size, now ); @@ -192,7 +166,7 @@ private byte[] getPhoneBytes(int count) { //when Slice slice = memberFriendQueryRepository.findFriendRequestsSlice( - ownerId, + owner.getId(), size, now ); @@ -209,7 +183,7 @@ private byte[] getPhoneBytes(int count) { //when Slice slice = memberFriendQueryRepository.findFriendRequestsSlice( - ownerId, + owner.getId(), size, now ); @@ -218,33 +192,13 @@ private byte[] getPhoneBytes(int count) { assertThat(slice.getContent().size()).isEqualTo(0); } - @Test - void 앱_사용자의_전화번호로만_주소록_기반_사용자_리스트_조회하면_조회하면_앱_사용자_리스트가_나온다() { - //given - List phoneHashes = IntStream.range(1, MAX_MEMBER_ID) - .mapToObj(i -> hash.encrypt(getPhoneBytes(i))) - .toList(); - - //when - List friends = memberFriendQueryRepository.findFriendsByPhone( - ownerId, - phoneHashes); - - //then - assertThat(friends.size()).isSameAs(MAX_MEMBER_ID - 1); - } - @Test void 앱_사용자의_전화번호가_아닌_경우_주소록_기반_사용자_리스트_조회하면_빈_리스트가_나온다() { //given - List phoneHashes = IntStream.range(1, MAX_MEMBER_ID) - .mapToObj(count -> hash.encrypt(getPhoneBytes(MAX_MEMBER_ID + count))) - .toList(); - //when List friends = memberFriendQueryRepository.findFriendsByPhone( - ownerId, - phoneHashes); + owner.getId(), + hashedNotMemberPhones); //then assertThat(friends.size()).isSameAs(0); @@ -253,14 +207,10 @@ private byte[] getPhoneBytes(int count) { @Test void 친구인_사용자로_주소록_기반_사용자_리스트_조회하면_친구인_앱_사용자_리스트가_나온다() { //given - List phoneHashes = IntStream.range(1, MAX_FRIEND_ID) - .mapToObj(count -> hash.encrypt(getPhoneBytes(count))) - .toList(); - //when List friends = memberFriendQueryRepository.findFriendsByPhone( - ownerId, - phoneHashes); + owner.getId(), + hashedFriendPhones); //then assertSoftly(softly -> { @@ -272,14 +222,10 @@ private byte[] getPhoneBytes(int count) { @Test void 친구가_아닌_사용자로_주소록_기반_사용자_리스트_조회하면_앱_사용자_리스트가_나온다() { //given - List phoneHashes = IntStream.range(MAX_FRIEND_ID, MAX_MEMBER_ID) - .mapToObj(count -> hash.encrypt(getPhoneBytes(count))) - .toList(); - //when List friends = memberFriendQueryRepository.findFriendsByPhone( - ownerId, - phoneHashes); + owner.getId(), + hashedNotFriendPhones); //then assertSoftly(softly -> { @@ -295,7 +241,7 @@ private byte[] getPhoneBytes(int count) { //when List friends = memberFriendQueryRepository.findFriendsByPhone( - ownerId, + owner.getId(), phoneHashes); //then @@ -307,7 +253,7 @@ private byte[] getPhoneBytes(int count) { void 사용자_아이디와_친구_태그로_친구관계를_조회하면_친구인_경우_True를_반환한다(int friendId) { //given Optional dto = memberFriendQueryRepository.findFriendsByTag( - ownerId, friendId+ "testTag"); + owner.getId(), friendId + "testTag"); //when Boolean isFriend = dto.get().isFriend(); @@ -321,7 +267,7 @@ private byte[] getPhoneBytes(int count) { void 사용자_아이디와_친구_태그로_친구관계를_조회하면_친구가_아닌_경우_False를_반환한다(int friendId) { //given Optional dto = memberFriendQueryRepository.findFriendsByTag( - ownerId, friendId + "testTag"); + owner.getId(), friendId + "testTag"); //when Boolean isFriend = dto.get().isFriend(); diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepositoryTest.java index c921f7ae7..f612e9bc5 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/friend/repository/MemberFriendRepositoryTest.java @@ -13,6 +13,7 @@ import org.springframework.test.context.TestConstructor.AutowireMode; import org.springframework.transaction.annotation.Transactional; import site.timecapsulearchive.core.common.RepositoryTest; +import site.timecapsulearchive.core.common.data.MemberTestDataRepository; import site.timecapsulearchive.core.domain.friend.entity.MemberFriend; import site.timecapsulearchive.core.domain.member.entity.Member; import site.timecapsulearchive.core.domain.member.entity.SocialType; @@ -22,9 +23,10 @@ class MemberFriendRepositoryTest extends RepositoryTest { private final MemberFriendRepository memberFriendRepository; - private Long ownerId; - private Long friendId; - + private final MemberTestDataRepository memberTestDataRepository = new MemberTestDataRepository(); + + private Member owner; + private Member friend; MemberFriendRepositoryTest(MemberFriendRepository repository) { this.memberFriendRepository = repository; @@ -33,43 +35,18 @@ class MemberFriendRepositoryTest extends RepositoryTest { @Transactional @BeforeEach void setup(@Autowired EntityManager entityManager) { - Member owner = getMember(0); - entityManager.persist(owner); - ownerId = owner.getId(); - - Member friend = getMember(1); - entityManager.persist(friend); - friendId = friend.getId(); - - MemberFriend ownerRelation = MemberFriend.builder() - .owner(owner) - .friend(friend) - .build(); - - MemberFriend friendRelation = MemberFriend.builder() - .owner(friend) - .friend(owner) - .build(); - entityManager.persist(ownerRelation); - entityManager.persist(friendRelation); - } + owner = memberTestDataRepository.insertAndGetMember(entityManager, 0); + friend = memberTestDataRepository.insertAndGetMember(entityManager, 1); - private Member getMember(int count) { - return Member.builder() - .socialType(SocialType.GOOGLE) - .nickname(count + "testNickname") - .email(count + "test@google.com") - .authId(count + "test") - .profileUrl(count + "test.com") - .tag(count + "testTag") - .build(); + memberTestDataRepository.insertMemberFriend(entityManager, owner, friend); + memberTestDataRepository.insertMemberFriend(entityManager, friend, owner); } @Test void 사용자_아이디와_친구_아이디로_친구관계를_조회하여_친구관계를_확인한다() { //given List memberFriend = memberFriendRepository.findMemberFriendByOwnerIdAndFriendId( - ownerId, friendId); + owner.getId(), friend.getId()); //when Long actualFriendId = memberFriend.get(0).getFriend().getId(); @@ -78,8 +55,8 @@ private Member getMember(int count) { //when assertSoftly(softly -> { softly.assertThat(memberFriend.size()).isEqualTo(2); - softly.assertThat(actualFriendId).isEqualTo(friendId); - softly.assertThat(actualOwnerId).isEqualTo(ownerId); + softly.assertThat(actualFriendId).isEqualTo(friend.getId()); + softly.assertThat(actualOwnerId).isEqualTo(owner.getId()); }); } @@ -90,7 +67,7 @@ private Member getMember(int count) { //when List memberFriend = memberFriendRepository.findMemberFriendByOwnerIdAndFriendId( - ownerId, friendId); + owner.getId(), friendId); //when assertThat(memberFriend).isEmpty(); diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryTest.java b/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryTest.java index 1efaaef0f..06184fcb0 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryTest.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepositoryTest.java @@ -4,22 +4,31 @@ import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; +import java.time.ZonedDateTime; import org.flywaydb.test.annotation.FlywayTest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Slice; import org.springframework.test.context.TestConstructor; import org.springframework.test.context.TestConstructor.AutowireMode; import org.springframework.transaction.annotation.Transactional; import site.timecapsulearchive.core.common.RepositoryTest; +import site.timecapsulearchive.core.common.data.MemberTestDataRepository; +import site.timecapsulearchive.core.domain.member.data.dto.MemberNotificationDto; import site.timecapsulearchive.core.domain.member.entity.Member; -import site.timecapsulearchive.core.domain.member.entity.SocialType; @FlywayTest @TestConstructor(autowireMode = AutowireMode.ALL) class MemberQueryRepositoryTest extends RepositoryTest { private final MemberQueryRepository memberQueryRepository; + private final MemberTestDataRepository memberTestDataRepository = new MemberTestDataRepository(); + + private Member member; + private Member zeroNotificationMember; MemberQueryRepositoryTest(EntityManager entityManager) { this.memberQueryRepository = new MemberQueryRepository( @@ -29,25 +38,17 @@ class MemberQueryRepositoryTest extends RepositoryTest { @Transactional @BeforeEach void setup(@Autowired EntityManager entityManager) { - Member owner = getMember(); - entityManager.persist(owner); - } - - private Member getMember() { - return Member.builder() - .socialType(SocialType.GOOGLE) - .nickname("testNickname") - .email("test@google.com") - .authId("test") - .profileUrl("test.com") - .tag("testTag") - .build(); + member = memberTestDataRepository.insertAndGetMember(entityManager, 1); + zeroNotificationMember = memberTestDataRepository.insertAndGetMember(entityManager, 2); + + memberTestDataRepository.insertNotificationCategory(entityManager); + memberTestDataRepository.insertNotification(entityManager, member.getId(), 20); } @Test void 중복_이메일로_중복_체크하면_True가_반환된다() { //given - String duplicatedEmail = "test@google.com"; + String duplicatedEmail = "1test@google.com"; //when Boolean isDuplicated = memberQueryRepository.checkEmailDuplication(duplicatedEmail); @@ -67,4 +68,48 @@ private Member getMember() { //then assertThat(isDuplicated).isFalse(); } + + @Test + void 특정_사용자로_알림_목록을_조회하면_알림_리스트가_반환된다() { + int size = 20; + ZonedDateTime now = ZonedDateTime.now().plusMinutes(1); + + Slice slice = memberQueryRepository.findNotificationSliceByMemberId( + member.getId(), size, now); + + assertThat(slice.getContent()).allMatch(notification -> notification.createdAt().isBefore(now)); + } + + @ParameterizedTest + @ValueSource(ints = {20, 15, 10, 5, 1}) + void 원하는_크기로_알림_목록을_조회하면_크기에_맞는_알림_리스트가_반환된다(int size) { + ZonedDateTime now = ZonedDateTime.now().plusMinutes(1); + + Slice slice = memberQueryRepository.findNotificationSliceByMemberId( + member.getId(), size, now); + + assertThat(slice.getContent().size()).isEqualTo(size); + } + + @Test + void 유효하지_않은_시간으로_알림_목록을_조회하면_빈_알림_리스트가_반환된다() { + int size = 20; + ZonedDateTime now = ZonedDateTime.now().minusDays(5); + + Slice slice = memberQueryRepository.findNotificationSliceByMemberId( + member.getId(), size, now); + + assertThat(slice.getContent().size()).isEqualTo(0); + } + + @Test + void 알림이_존재하지_않는_사용자로_알림_목록을_조회하면_빈_알림_리스트가_반환된다() { + int size = 20; + ZonedDateTime now = ZonedDateTime.now().plusMinutes(1); + + Slice slice = memberQueryRepository.findNotificationSliceByMemberId( + zeroNotificationMember.getId(), size, now); + + assertThat(slice.getContent().size()).isEqualTo(0); + } } \ No newline at end of file From 1daea4df10a862f486853de78b8156e01cfdb346 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 30 Mar 2024 17:51:24 +0900 Subject: [PATCH 153/314] =?UTF-8?q?feat=20:=20=EA=B3=B5=EA=B0=9C=20?= =?UTF-8?q?=EC=BA=A1=EC=8A=90=20=EC=BF=BC=EB=A6=AC=20=EB=A0=88=ED=8F=AC?= =?UTF-8?q?=EC=A7=80=ED=86=A0=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../public_capsule/api/PublicCapsuleApi.java | 8 +-- .../data/dto/PublicCapsuleDetailDto.java | 23 +++++++ .../PublicCapsuleQueryRepository.java | 69 +++++++++++++++++++ 3 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/dto/PublicCapsuleDetailDto.java create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/PublicCapsuleQueryRepository.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApi.java index fc11b22d7..bc04d5135 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApi.java @@ -37,7 +37,7 @@ public interface PublicCapsuleApi { ) }) @PostMapping( - value = "/public/capsules", + value = "/capsules", consumes = {"multipart/form-data"} ) ResponseEntity createPublicCapsule( @@ -57,7 +57,7 @@ ResponseEntity createPublicCapsule( ) }) @GetMapping( - value = "/public/capsules/{capsule_id}", + value = "/capsules/{capsule_id}", produces = {"application/json"} ) ResponseEntity findPublicCapsuleById( @@ -78,7 +78,7 @@ ResponseEntity findPublicCapsuleById( ) }) @GetMapping( - value = "/public/capsules", + value = "/capsules", produces = {"application/json"} ) ResponseEntity getPublicCapsules( @@ -102,7 +102,7 @@ ResponseEntity getPublicCapsules( ) }) @PatchMapping( - value = "/public/capsules/{capsule_id}", + value = "/capsules/{capsule_id}", consumes = {"multipart/form-data"} ) ResponseEntity updatePublicCapsuleById( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/dto/PublicCapsuleDetailDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/dto/PublicCapsuleDetailDto.java new file mode 100644 index 000000000..f516bec84 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/dto/PublicCapsuleDetailDto.java @@ -0,0 +1,23 @@ +package site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto; + +import java.time.ZonedDateTime; +import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; + +public record PublicCapsuleDetailDto( + Long capsuleId, + String capsuleSkinUrl, + ZonedDateTime dueDate, + String nickname, + String profileUrl, + ZonedDateTime createdAt, + String address, + String title, + String content, + String images, + String videos, + Boolean isOpened, + CapsuleType capsuleType, + Boolean isFriend +) { + +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/PublicCapsuleQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/PublicCapsuleQueryRepository.java new file mode 100644 index 000000000..64fdbd36a --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/PublicCapsuleQueryRepository.java @@ -0,0 +1,69 @@ +package site.timecapsulearchive.core.domain.capsule.repository; + +import static site.timecapsulearchive.core.domain.capsule.entity.QCapsule.capsule; +import static site.timecapsulearchive.core.domain.capsule.entity.QImage.image; +import static site.timecapsulearchive.core.domain.capsule.entity.QVideo.video; +import static site.timecapsulearchive.core.domain.capsuleskin.entity.QCapsuleSkin.capsuleSkin; +import static site.timecapsulearchive.core.domain.friend.entity.QMemberFriend.memberFriend; +import static site.timecapsulearchive.core.domain.member.entity.QMember.member; + +import com.querydsl.core.types.Projections; +import com.querydsl.core.types.dsl.Expressions; +import com.querydsl.core.types.dsl.StringExpression; +import com.querydsl.jpa.impl.JPAQueryFactory; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; +import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; +import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleDetailDto; + +@Repository +@RequiredArgsConstructor +public class PublicCapsuleQueryRepository { + + private final JPAQueryFactory jpaQueryFactory; + + public Optional findPublicCapsuleDetailDtosByMemberIdAndCapsuleId( + final Long memberId, + final Long capsuleId + ) { + final PublicCapsuleDetailDto detailDto = jpaQueryFactory + .select( + Projections.constructor( + PublicCapsuleDetailDto.class, + capsule.id, + capsuleSkin.imageUrl, + capsule.dueDate, + member.nickname, + member.profileUrl, + capsule.createdAt, + capsule.address.fullRoadAddressName, + capsule.title, + capsule.content, + groupConcatDistinct(image.imageUrl), + groupConcatDistinct(video.videoUrl), + capsule.isOpened, + capsule.type, + memberFriend.id.isNotNull() + ) + ) + .from(capsule) + .join(member).on(capsule.member.id.eq(member.id)) + .join(member) + .on(memberFriend.friend.id.eq(member.id).and(memberFriend.owner.id.eq(memberId))) + .join(capsuleSkin).on(capsule.capsuleSkin.id.eq(capsuleSkin.id)) + .leftJoin(image).on(capsule.id.eq(image.capsule.id)) + .leftJoin(video).on(capsule.id.eq(video.capsule.id)) + .where(capsule.id.eq(capsuleId).and(capsule.type.eq(CapsuleType.SECRET))) + .fetchFirst(); + + if (detailDto.capsuleId() == null) { + return Optional.empty(); + } + return Optional.of(detailDto); + } + + private StringExpression groupConcatDistinct(final StringExpression expression) { + return Expressions.stringTemplate("GROUP_CONCAT(DISTINCT {0})", expression); + } +} From 26513c2fd9086d00203aa03a2c823c4ca84f8560 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 30 Mar 2024 17:59:29 +0900 Subject: [PATCH 154/314] =?UTF-8?q?refact=20:=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/capsule/mapper/CapsuleMapper.java | 10 +++++----- .../capsule/secret_capsule/api/SecretCapsuleApi.java | 4 ++-- .../secret_capsule/api/SecretCapsuleApiController.java | 4 ++-- ...eDetailResponse.java => CapsuleDetailResponse.java} | 2 +- .../domain/capsule/service/SecretCapsuleService.java | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) rename backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/{SecretCapsuleDetailResponse.java => CapsuleDetailResponse.java} (96%) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java index 06074fb89..a91bfa96c 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java @@ -18,7 +18,7 @@ import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.SecretCapsuleCreateRequest; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecreteCapsuleResponse; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.SecretCapsuleDetailResponse; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleDetailResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.SecretCapsuleSummaryResponse; import site.timecapsulearchive.core.domain.capsuleskin.entity.CapsuleSkin; import site.timecapsulearchive.core.domain.member.entity.Member; @@ -122,12 +122,12 @@ public SecretCapsuleSummaryResponse secretCapsuleSummaryDtoToResponse( .build(); } - public SecretCapsuleDetailResponse secretCapsuleDetailDtoToResponse( + public CapsuleDetailResponse secretCapsuleDetailDtoToResponse( final SecretCapsuleDetailDto dto, final List imageUrls, final List videoUrls ) { - return SecretCapsuleDetailResponse.builder() + return CapsuleDetailResponse.builder() .capsuleSkinUrl(s3PreSignedUrlManager.getS3PreSignedUrlForGet(dto.capsuleSkinUrl())) .dueDate(checkNullable(dto.dueDate())) .nickname(dto.nickname()) @@ -143,9 +143,9 @@ public SecretCapsuleDetailResponse secretCapsuleDetailDtoToResponse( .build(); } - public SecretCapsuleDetailResponse notOpenedSecretCapsuleDetailDtoToResponse( + public CapsuleDetailResponse notOpenedSecretCapsuleDetailDtoToResponse( final SecretCapsuleDetailDto dto) { - return SecretCapsuleDetailResponse.builder() + return CapsuleDetailResponse.builder() .capsuleSkinUrl(s3PreSignedUrlManager.getS3PreSignedUrlForGet(dto.capsuleSkinUrl())) .dueDate(checkNullable(dto.dueDate())) .nickname(dto.nickname()) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApi.java index a849cd876..f50826a47 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApi.java @@ -13,7 +13,7 @@ import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.SecretCapsuleCreateRequest; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.SecretCapsuleUpdateRequest; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.SecretCapsuleDetailResponse; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleDetailResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.SecretCapsuleSummaryResponse; import site.timecapsulearchive.core.global.common.response.ApiSpec; import site.timecapsulearchive.core.global.error.ErrorResponse; @@ -83,7 +83,7 @@ ResponseEntity> getSecretCapsuleSummary( content = @Content(schema = @Schema(implementation = ErrorResponse.class)) ) }) - ResponseEntity> getSecretCapsuleDetail( + ResponseEntity> getSecretCapsuleDetail( Long memberId, @Parameter(in = ParameterIn.PATH, description = "비밀 캡슐 아이디", required = true) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java index 4d17a9b43..ffd52e4d4 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java @@ -19,7 +19,7 @@ import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.SecretCapsuleCreateRequest; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.SecretCapsuleUpdateRequest; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.SecretCapsuleDetailResponse; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleDetailResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.SecretCapsuleSummaryResponse; import site.timecapsulearchive.core.domain.capsule.service.SecretCapsuleService; import site.timecapsulearchive.core.global.common.response.ApiSpec; @@ -72,7 +72,7 @@ public ResponseEntity> getSecretCapsuleSum @GetMapping(value = "/capsules/{capsule_id}/detail", produces = {"application/json"}) @Override - public ResponseEntity> getSecretCapsuleDetail( + public ResponseEntity> getSecretCapsuleDetail( @AuthenticationPrincipal final Long memberId, @PathVariable("capsule_id") final Long capsuleId ) { diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/SecretCapsuleDetailResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/CapsuleDetailResponse.java similarity index 96% rename from backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/SecretCapsuleDetailResponse.java rename to backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/CapsuleDetailResponse.java index 3be693d8a..d1804448b 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/SecretCapsuleDetailResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/CapsuleDetailResponse.java @@ -8,7 +8,7 @@ @Schema(description = "비밀 캡슐 상세 정보") @Builder -public record SecretCapsuleDetailResponse( +public record CapsuleDetailResponse( @Schema(description = "캡슐 스킨 url") String capsuleSkinUrl, diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/SecretCapsuleService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/SecretCapsuleService.java index a675feb4d..08bd53ffa 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/SecretCapsuleService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/SecretCapsuleService.java @@ -22,7 +22,7 @@ import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.SecretCapsuleDetailResponse; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleDetailResponse; import site.timecapsulearchive.core.domain.capsuleskin.entity.CapsuleSkin; import site.timecapsulearchive.core.domain.capsuleskin.exception.CapsuleSkinNotFoundException; import site.timecapsulearchive.core.domain.capsuleskin.repository.CapsuleSkinRepository; @@ -95,7 +95,7 @@ public SecretCapsuleSummaryDto findSecretCapsuleSummaryById( * @param capsuleId 캡슐 아이디 * @return 캡슐 상세 정보 */ - public SecretCapsuleDetailResponse findSecretCapsuleDetailById( + public CapsuleDetailResponse findSecretCapsuleDetailById( final Long memberId, final Long capsuleId ) { From 4fae926b5ea34781a9930ca3034dc5e876b718de Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 30 Mar 2024 18:12:05 +0900 Subject: [PATCH 155/314] =?UTF-8?q?feat=20:=20=EC=B9=9C=EA=B5=AC=20?= =?UTF-8?q?=EC=BA=A1=EC=8A=90=20=EC=83=81=EC=84=B8=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=84=9C=EB=B9=84=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NoCapsuleAuthorityException.java | 11 ++++ .../domain/capsule/mapper/CapsuleMapper.java | 57 +++++++++++++++++++ .../capsule/service/PublicCapsuleService.java | 48 ++++++++++++++++ .../core/global/error/ErrorCode.java | 1 + 4 files changed, 117 insertions(+) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/exception/NoCapsuleAuthorityException.java create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/PublicCapsuleService.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/exception/NoCapsuleAuthorityException.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/exception/NoCapsuleAuthorityException.java new file mode 100644 index 000000000..20a6b12da --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/exception/NoCapsuleAuthorityException.java @@ -0,0 +1,11 @@ +package site.timecapsulearchive.core.domain.capsule.exception; + +import site.timecapsulearchive.core.global.error.ErrorCode; +import site.timecapsulearchive.core.global.error.exception.BusinessException; + +public class NoCapsuleAuthorityException extends BusinessException { + + public NoCapsuleAuthorityException() { + super(ErrorCode.NO_CAPSULE_AUTHORITY_ERROR); + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java index a91bfa96c..d36c2c484 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java @@ -2,6 +2,7 @@ import java.time.ZoneId; import java.time.ZonedDateTime; +import java.util.Collections; import java.util.List; import lombok.RequiredArgsConstructor; import org.locationtech.jts.geom.Point; @@ -11,6 +12,7 @@ import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.CapsuleSummaryResponse; +import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.MySecreteCapsuleDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleCreateRequestDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleDetailDto; @@ -24,12 +26,15 @@ import site.timecapsulearchive.core.domain.member.entity.Member; import site.timecapsulearchive.core.global.geography.GeoTransformManager; import site.timecapsulearchive.core.infra.map.data.dto.AddressData; +import site.timecapsulearchive.core.infra.s3.data.dto.S3PreSignedUrlDto; +import site.timecapsulearchive.core.infra.s3.data.request.S3PreSignedUrlRequestDto; import site.timecapsulearchive.core.infra.s3.manager.S3PreSignedUrlManager; @Component @RequiredArgsConstructor public class CapsuleMapper { + private static final String DELIMITER = ","; private static final ZoneId ASIA_SEOUL = ZoneId.of("Asia/Seoul"); private final GeoTransformManager geoTransformManager; @@ -181,4 +186,56 @@ private MySecreteCapsuleResponse mySecreteCapsuleDtoToResponse(final MySecreteCa .type(dto.type()) .build(); } + + public CapsuleDetailResponse publicCapsuleDetailDtoToResponse( + PublicCapsuleDetailDto detailDto + ) { + final S3PreSignedUrlDto preSignedUrls = s3PreSignedUrlManager.getS3PreSignedUrlsForGet( + S3PreSignedUrlRequestDto.forGet( + splitFileNames(detailDto.images()), + splitFileNames(detailDto.videos()) + ) + ); + + return CapsuleDetailResponse.builder() + .capsuleSkinUrl(s3PreSignedUrlManager.getS3PreSignedUrlForGet(detailDto.capsuleSkinUrl())) + .dueDate(checkNullable(detailDto.dueDate())) + .nickname(detailDto.nickname()) + .profileUrl(detailDto.profileUrl()) + .createdDate(detailDto.createdAt().withZoneSameInstant(ASIA_SEOUL)) + .address(detailDto.address()) + .title(detailDto.title()) + .content(detailDto.content()) + .imageUrls(preSignedUrls.preSignedImageUrls()) + .videoUrls(preSignedUrls.preSignedVideoUrls()) + .isOpened(detailDto.isOpened()) + .capsuleType(detailDto.capsuleType()) + .build(); + } + + private List splitFileNames(String fileNames) { + if (fileNames == null) { + return Collections.emptyList(); + } + + return List.of(fileNames.split(DELIMITER)); + } + + public CapsuleDetailResponse notOpenedPublicCapsuleDetailDtoToResponse( + final PublicCapsuleDetailDto dto + ) { + return CapsuleDetailResponse.builder() + .capsuleSkinUrl(s3PreSignedUrlManager.getS3PreSignedUrlForGet(dto.capsuleSkinUrl())) + .dueDate(checkNullable(dto.dueDate())) + .nickname(dto.nickname()) + .profileUrl(dto.profileUrl()) + .address(dto.address()) + .isOpened(dto.isOpened()) + .createdDate(dto.createdAt().withZoneSameInstant(ASIA_SEOUL)) + .imageUrls(Collections.emptyList()) + .videoUrls(Collections.emptyList()) + .title(dto.title()) + .capsuleType(dto.capsuleType()) + .build(); + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/PublicCapsuleService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/PublicCapsuleService.java new file mode 100644 index 000000000..4815eb543 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/PublicCapsuleService.java @@ -0,0 +1,48 @@ +package site.timecapsulearchive.core.domain.capsule.service; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import site.timecapsulearchive.core.domain.capsule.exception.CapsuleNotFondException; +import site.timecapsulearchive.core.domain.capsule.exception.NoCapsuleAuthorityException; +import site.timecapsulearchive.core.domain.capsule.mapper.CapsuleMapper; +import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleDetailDto; +import site.timecapsulearchive.core.domain.capsule.repository.PublicCapsuleQueryRepository; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleDetailResponse; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class PublicCapsuleService { + + private final PublicCapsuleQueryRepository publicCapsuleQueryRepository; + private final CapsuleMapper capsuleMapper; + + public CapsuleDetailResponse findPublicCapsuleDetailByMemberIdAndCapsuleId(Long memberId, + Long capsuleId) { + PublicCapsuleDetailDto detailDto = publicCapsuleQueryRepository.findPublicCapsuleDetailDtosByMemberIdAndCapsuleId( + memberId, capsuleId) + .orElseThrow(CapsuleNotFondException::new); + + if (!detailDto.isFriend()) { + throw new NoCapsuleAuthorityException(); + } + + if (capsuleNotOpened(detailDto)) { + return capsuleMapper.notOpenedPublicCapsuleDetailDtoToResponse(detailDto); + } + + return capsuleMapper.publicCapsuleDetailDtoToResponse(detailDto); + } + + private boolean capsuleNotOpened(final PublicCapsuleDetailDto detailDto) { + if (detailDto.dueDate() == null) { + return false; + } + + return !detailDto.isOpened() || detailDto.dueDate() + .isAfter(ZonedDateTime.now(ZoneOffset.UTC)); + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java index 4bce626ea..56611c323 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/error/ErrorCode.java @@ -51,6 +51,7 @@ public enum ErrorCode { //capsule CAPSULE_NOT_FOUND_ERROR(404, "CAPSULE-001", "캡슐을 찾지 못하였습니다."), + NO_CAPSULE_AUTHORITY_ERROR(403, "CAPSULE-002", "캡슐에 접근 권한이 없습니다."), //friend FRIEND_NOT_FOUND_ERROR(404, "FRIEND-001", "친구를 찾지 못하였습니다"), From 346cd4507e74eebd01533a56fb732c7103d736a7 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 30 Mar 2024 18:20:46 +0900 Subject: [PATCH 156/314] =?UTF-8?q?refact=20:=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EC=9D=B4=EB=A6=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ummaryDto.java => NearbyCapsuleSummaryDto.java} | 2 +- .../data/response/NearbyCapsuleResponse.java | 4 ++-- ...onse.java => NearbyCapsuleSummaryResponse.java} | 2 +- .../core/domain/capsule/mapper/CapsuleMapper.java | 14 +++++++------- .../capsule/repository/CapsuleQueryRepository.java | 14 +++++++------- .../secret_capsule/api/SecretCapsuleApi.java | 6 +++--- .../api/SecretCapsuleApiController.java | 6 +++--- ...ryResponse.java => CapsuleSummaryResponse.java} | 2 +- 8 files changed, 25 insertions(+), 25 deletions(-) rename backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/dto/{CapsuleSummaryDto.java => NearbyCapsuleSummaryDto.java} (91%) rename backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/{CapsuleSummaryResponse.java => NearbyCapsuleSummaryResponse.java} (95%) rename backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/{SecretCapsuleSummaryResponse.java => CapsuleSummaryResponse.java} (95%) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/dto/CapsuleSummaryDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/dto/NearbyCapsuleSummaryDto.java similarity index 91% rename from backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/dto/CapsuleSummaryDto.java rename to backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/dto/NearbyCapsuleSummaryDto.java index dbbe2a346..23572ea21 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/dto/CapsuleSummaryDto.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/dto/NearbyCapsuleSummaryDto.java @@ -4,7 +4,7 @@ import org.locationtech.jts.geom.Point; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; -public record CapsuleSummaryDto( +public record NearbyCapsuleSummaryDto( Long id, Point point, String nickname, diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/NearbyCapsuleResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/NearbyCapsuleResponse.java index ac7c24161..c399735eb 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/NearbyCapsuleResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/NearbyCapsuleResponse.java @@ -7,10 +7,10 @@ public record NearbyCapsuleResponse( @Schema(description = "캡슐 요약 정보 리스트") - List capsules + List capsules ) { - public static NearbyCapsuleResponse from(List capsules) { + public static NearbyCapsuleResponse from(List capsules) { return new NearbyCapsuleResponse(capsules); } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/CapsuleSummaryResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/NearbyCapsuleSummaryResponse.java similarity index 95% rename from backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/CapsuleSummaryResponse.java rename to backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/NearbyCapsuleSummaryResponse.java index d003e230f..144d8abd6 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/CapsuleSummaryResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/response/NearbyCapsuleSummaryResponse.java @@ -7,7 +7,7 @@ @Schema(description = "캡슐 요약 정보") @Builder -public record CapsuleSummaryResponse( +public record NearbyCapsuleSummaryResponse( @Schema(description = "캡슐 아이디") Long id, diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java index d36c2c484..7d0308e03 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java @@ -10,8 +10,8 @@ import site.timecapsulearchive.core.domain.capsule.entity.Address; import site.timecapsulearchive.core.domain.capsule.entity.Capsule; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; -import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; -import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.CapsuleSummaryResponse; +import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.NearbyCapsuleSummaryDto; +import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.NearbyCapsuleSummaryResponse; import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.MySecreteCapsuleDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleCreateRequestDto; @@ -21,7 +21,7 @@ import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecreteCapsuleResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleDetailResponse; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.SecretCapsuleSummaryResponse; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleSummaryResponse; import site.timecapsulearchive.core.domain.capsuleskin.entity.CapsuleSkin; import site.timecapsulearchive.core.domain.member.entity.Member; import site.timecapsulearchive.core.global.geography.GeoTransformManager; @@ -90,10 +90,10 @@ private Address addressDataToEntity(final AddressData addressData) { .build(); } - public CapsuleSummaryResponse capsuleSummaryDtoToResponse(final CapsuleSummaryDto dto) { + public NearbyCapsuleSummaryResponse capsuleSummaryDtoToResponse(final NearbyCapsuleSummaryDto dto) { Point point = geoTransformManager.changePoint3857To4326(dto.point()); - return CapsuleSummaryResponse.builder() + return NearbyCapsuleSummaryResponse.builder() .id(dto.id()) .latitude(point.getX()) .longitude(point.getY()) @@ -112,9 +112,9 @@ private ZonedDateTime checkNullable(final ZonedDateTime zonedDateTime) { return null; } - public SecretCapsuleSummaryResponse secretCapsuleSummaryDtoToResponse( + public CapsuleSummaryResponse secretCapsuleSummaryDtoToResponse( final SecretCapsuleSummaryDto dto) { - return SecretCapsuleSummaryResponse.builder() + return CapsuleSummaryResponse.builder() .nickname(dto.nickname()) .profileUrl(dto.profileUrl()) .skinUrl(s3PreSignedUrlManager.getS3PreSignedUrlForGet(dto.skinUrl())) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/CapsuleQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/CapsuleQueryRepository.java index a78f16d9f..b812c7e38 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/CapsuleQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/CapsuleQueryRepository.java @@ -22,7 +22,7 @@ import org.springframework.data.domain.SliceImpl; import org.springframework.stereotype.Repository; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; -import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; +import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.NearbyCapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.MySecreteCapsuleDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleSummaryDto; @@ -42,12 +42,12 @@ public class CapsuleQueryRepository { * @param capsuleType 조회할 캡슐의 타입 * @return 범위 내에 조회된 캡슐들의 요약 정보들을 반환한다. */ - public List findCapsuleSummaryDtosByCurrentLocationAndCapsuleType( + public List findCapsuleSummaryDtosByCurrentLocationAndCapsuleType( final Long memberId, final Polygon mbr, final CapsuleType capsuleType ) { - final TypedQuery query = generateSelectQueryOnCapsuleSummaryDtoWith( + final TypedQuery query = generateSelectQueryOnCapsuleSummaryDtoWith( capsuleType); assignParameter(memberId, mbr, capsuleType, query); @@ -55,11 +55,11 @@ public List findCapsuleSummaryDtosByCurrentLocationAndCapsule return query.getResultList(); } - private TypedQuery generateSelectQueryOnCapsuleSummaryDtoWith( + private TypedQuery generateSelectQueryOnCapsuleSummaryDtoWith( final CapsuleType capsuleType ) { String queryString = """ - select new site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto( + select new site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.NearbyCapsuleSummaryDto( c.id, c.point, m.nickname, @@ -79,14 +79,14 @@ where ST_Contains(:mbr, c.point) and m.id=:memberId queryString += " and c.type = :capsuleType"; } - return entityManager.createQuery(queryString, CapsuleSummaryDto.class); + return entityManager.createQuery(queryString, NearbyCapsuleSummaryDto.class); } private void assignParameter( final Long memberId, final Polygon mbr, final CapsuleType capsuleType, - final TypedQuery query + final TypedQuery query ) { query.setParameter("mbr", mbr); query.setParameter("memberId", memberId); diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApi.java index f50826a47..5c89963eb 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApi.java @@ -14,7 +14,7 @@ import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.SecretCapsuleUpdateRequest; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleDetailResponse; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.SecretCapsuleSummaryResponse; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleSummaryResponse; import site.timecapsulearchive.core.global.common.response.ApiSpec; import site.timecapsulearchive.core.global.error.ErrorResponse; @@ -59,7 +59,7 @@ ResponseEntity> getMySecretCapsules( content = @Content(schema = @Schema(implementation = ErrorResponse.class)) ) }) - ResponseEntity> getSecretCapsuleSummary( + ResponseEntity> getSecretCapsuleSummary( Long memberId, @Parameter(in = ParameterIn.PATH, description = "비밀 캡슐 아이디", required = true) @@ -129,7 +129,7 @@ ResponseEntity> createSecretCapsule( description = "처리 완료" ) }) - ResponseEntity updateSecretCapsule( + ResponseEntity updateSecretCapsule( Long memberId, SecretCapsuleUpdateRequest request, @Parameter(in = ParameterIn.PATH, description = "비밀 캡슐 아이디", required = true) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java index ffd52e4d4..2a25cb1a3 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java @@ -20,7 +20,7 @@ import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.SecretCapsuleUpdateRequest; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleDetailResponse; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.SecretCapsuleSummaryResponse; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleSummaryResponse; import site.timecapsulearchive.core.domain.capsule.service.SecretCapsuleService; import site.timecapsulearchive.core.global.common.response.ApiSpec; import site.timecapsulearchive.core.global.common.response.SuccessCode; @@ -54,7 +54,7 @@ public ResponseEntity> getMySecretCapsules @GetMapping(value = "/capsules/{capsule_id}/summary", produces = {"application/json"}) @Override - public ResponseEntity> getSecretCapsuleSummary( + public ResponseEntity> getSecretCapsuleSummary( @AuthenticationPrincipal final Long memberId, @PathVariable("capsule_id") final Long capsuleId ) { @@ -104,7 +104,7 @@ public ResponseEntity> createSecretCapsule( @PatchMapping(value = "/capsules/{capsule_id}", consumes = {"multipart/form-data"}) @Override - public ResponseEntity updateSecretCapsule( + public ResponseEntity updateSecretCapsule( @AuthenticationPrincipal final Long memberId, @ModelAttribute final SecretCapsuleUpdateRequest request, @PathVariable("capsule_id") final Long capsuleId diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/SecretCapsuleSummaryResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/CapsuleSummaryResponse.java similarity index 95% rename from backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/SecretCapsuleSummaryResponse.java rename to backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/CapsuleSummaryResponse.java index 378c295e6..5223d749b 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/SecretCapsuleSummaryResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/response/CapsuleSummaryResponse.java @@ -6,7 +6,7 @@ @Schema(description = "비밀 캡슐 요약 정보") @Builder -public record SecretCapsuleSummaryResponse( +public record CapsuleSummaryResponse( @Schema(description = "생성자 닉네임") String nickname, From 0f5c944d531306a5e217b4cfa0088c9ea753a7ac Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 30 Mar 2024 18:28:00 +0900 Subject: [PATCH 157/314] =?UTF-8?q?feat=20:=20=EC=BA=A1=EC=8A=90=20?= =?UTF-8?q?=EC=9A=94=EC=95=BD=20=EC=A1=B0=ED=9A=8C=20=EC=BF=BC=EB=A6=AC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=BA=A1=EC=8A=90=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/dto/PublicCapsuleSummaryDto.java | 18 ++++++++++ .../PublicCapsuleQueryRepository.java | 36 ++++++++++++++++--- 2 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/dto/PublicCapsuleSummaryDto.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/dto/PublicCapsuleSummaryDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/dto/PublicCapsuleSummaryDto.java new file mode 100644 index 000000000..ce5f90b47 --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/data/dto/PublicCapsuleSummaryDto.java @@ -0,0 +1,18 @@ +package site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto; + +import java.time.ZonedDateTime; + +public record PublicCapsuleSummaryDto( + String nickname, + String profileUrl, + String skinUrl, + String title, + ZonedDateTime dueDate, + String address, + String roadName, + Boolean isOpened, + ZonedDateTime createdAt, + Boolean isFriend +) { + +} \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/PublicCapsuleQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/PublicCapsuleQueryRepository.java index 64fdbd36a..0ced8947f 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/PublicCapsuleQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/PublicCapsuleQueryRepository.java @@ -16,6 +16,7 @@ import org.springframework.stereotype.Repository; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleDetailDto; +import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleSummaryDto; @Repository @RequiredArgsConstructor @@ -54,16 +55,41 @@ public Optional findPublicCapsuleDetailDtosByMemberIdAnd .join(capsuleSkin).on(capsule.capsuleSkin.id.eq(capsuleSkin.id)) .leftJoin(image).on(capsule.id.eq(image.capsule.id)) .leftJoin(video).on(capsule.id.eq(video.capsule.id)) - .where(capsule.id.eq(capsuleId).and(capsule.type.eq(CapsuleType.SECRET))) + .where(capsule.id.eq(capsuleId).and(capsule.type.eq(CapsuleType.PUBLIC))) .fetchFirst(); - if (detailDto.capsuleId() == null) { - return Optional.empty(); - } - return Optional.of(detailDto); + return Optional.ofNullable(detailDto); } private StringExpression groupConcatDistinct(final StringExpression expression) { return Expressions.stringTemplate("GROUP_CONCAT(DISTINCT {0})", expression); } + + public Optional findPublicCapsuleSummaryDtosByMemberIdAndCapsuleId( + Long memberId, + Long capsuleId + ) { + return Optional.ofNullable( + jpaQueryFactory + .select( + Projections.constructor( + PublicCapsuleSummaryDto.class, + capsule.member.nickname, + capsule.member.profileUrl, + capsule.capsuleSkin.imageUrl, + capsule.title, + capsule.dueDate, + capsule.address.fullRoadAddressName, + capsule.address.roadName, + capsule.isOpened, + capsule.createdAt, + memberFriend.id.isNotNull() + ) + ) + .from(capsule) + .on(memberFriend.friend.id.eq(member.id).and(memberFriend.owner.id.eq(memberId))) + .where(capsule.id.eq(capsuleId).and(capsule.type.eq(CapsuleType.PUBLIC))) + .fetchOne() + ); + } } From 780ba060723ebdbcbfbd26aee161382810a4a470 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 30 Mar 2024 18:29:33 +0900 Subject: [PATCH 158/314] =?UTF-8?q?feat=20:=20=EC=BA=A1=EC=8A=90=20?= =?UTF-8?q?=EC=9A=94=EC=95=BD=20=EC=A1=B0=ED=9A=8C=20=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/capsule/mapper/CapsuleMapper.java | 17 +++++++++++++++++ .../capsule/service/PublicCapsuleService.java | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java index 7d0308e03..b417c089b 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java @@ -13,6 +13,7 @@ import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.NearbyCapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.NearbyCapsuleSummaryResponse; import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleDetailDto; +import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.MySecreteCapsuleDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleCreateRequestDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleDetailDto; @@ -238,4 +239,20 @@ public CapsuleDetailResponse notOpenedPublicCapsuleDetailDtoToResponse( .capsuleType(dto.capsuleType()) .build(); } + + public CapsuleSummaryResponse publicCapsuleSummaryToResponse( + PublicCapsuleSummaryDto summaryDto + ) { + return CapsuleSummaryResponse.builder() + .nickname(summaryDto.nickname()) + .profileUrl(summaryDto.profileUrl()) + .skinUrl(s3PreSignedUrlManager.getS3PreSignedUrlForGet(summaryDto.skinUrl())) + .title(summaryDto.title()) + .dueDate(checkNullable(summaryDto.dueDate())) + .address(summaryDto.address()) + .roadName(summaryDto.roadName()) + .isOpened(summaryDto.isOpened()) + .createdAt(summaryDto.createdAt().withZoneSameInstant(ASIA_SEOUL)) + .build(); + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/PublicCapsuleService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/PublicCapsuleService.java index 4815eb543..01384b6b5 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/PublicCapsuleService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/PublicCapsuleService.java @@ -9,8 +9,10 @@ import site.timecapsulearchive.core.domain.capsule.exception.NoCapsuleAuthorityException; import site.timecapsulearchive.core.domain.capsule.mapper.CapsuleMapper; import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleDetailDto; +import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.repository.PublicCapsuleQueryRepository; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleDetailResponse; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleSummaryResponse; @Service @Transactional(readOnly = true) @@ -45,4 +47,19 @@ private boolean capsuleNotOpened(final PublicCapsuleDetailDto detailDto) { return !detailDto.isOpened() || detailDto.dueDate() .isAfter(ZonedDateTime.now(ZoneOffset.UTC)); } + + public CapsuleSummaryResponse findPublicCapsuleSummaryByMemberIdAndCapsuleId( + Long memberId, + Long capsuleId + ) { + PublicCapsuleSummaryDto summaryDto = publicCapsuleQueryRepository.findPublicCapsuleSummaryDtosByMemberIdAndCapsuleId( + memberId, capsuleId) + .orElseThrow(CapsuleNotFondException::new); + + if (!summaryDto.isFriend()) { + throw new NoCapsuleAuthorityException(); + } + + return capsuleMapper.publicCapsuleSummaryToResponse(summaryDto); + } } From 80415955c5371b68fe384457445ab58c809bd318 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 30 Mar 2024 18:30:01 +0900 Subject: [PATCH 159/314] =?UTF-8?q?feat=20:=20=EC=BA=A1=EC=8A=90=20?= =?UTF-8?q?=EC=9A=94=EC=95=BD=20=EC=A1=B0=ED=9A=8C=20=EC=BB=A8=ED=8A=B8?= =?UTF-8?q?=EB=A1=A4=EB=9F=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../public_capsule/api/PublicCapsuleApi.java | 55 +++++++++++-- .../api/PublicCapsuleApiController.java | 77 +++++++++++++++++++ 2 files changed, 125 insertions(+), 7 deletions(-) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApiController.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApi.java index bc04d5135..72d79d2f5 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApi.java @@ -3,6 +3,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; @@ -18,9 +19,12 @@ import org.springframework.web.bind.annotation.RequestParam; import site.timecapsulearchive.core.domain.capsule.public_capsule.data.reqeust.PublicCapsuleCreateRequest; import site.timecapsulearchive.core.domain.capsule.public_capsule.data.reqeust.PublicCapsuleUpdateRequest; -import site.timecapsulearchive.core.domain.capsule.public_capsule.data.response.PublicCapsuleDetailResponse; import site.timecapsulearchive.core.domain.capsule.public_capsule.data.response.PublicCapsulePageResponse; import site.timecapsulearchive.core.domain.capsule.public_capsule.data.response.PublicCapsuleSummaryResponse; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleDetailResponse; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleSummaryResponse; +import site.timecapsulearchive.core.global.common.response.ApiSpec; +import site.timecapsulearchive.core.global.error.ErrorResponse; public interface PublicCapsuleApi { @@ -44,6 +48,35 @@ ResponseEntity createPublicCapsule( @ModelAttribute PublicCapsuleCreateRequest request ); + @Operation( + summary = "공개 캡슐 요약 조회", + description = "사용자의 친구들만 볼 수 있는 공개 캡슐 내용을 요약 조회한다.", + security = {@SecurityRequirement(name = "user_token")}, + tags = {"public capsule"} + ) + @ApiResponses(value = { + @ApiResponse( + responseCode = "200", + description = "ok" + ), + @ApiResponse( + responseCode = "403", + description = "해당 캡슐에 접근 권한이 없는 경우 발생하는 예외", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)) + ), + @ApiResponse( + responseCode = "404", + description = "해당 캡슐을 찾을 수 없을 경우 발생하는 예외", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)) + ) + }) + ResponseEntity> getPublicCapsuleSummaryById( + Long memberId, + + @Parameter(in = ParameterIn.PATH, description = "조회할 캡슐 아이디", required = true, schema = @Schema()) + Long capsuleId + ); + @Operation( summary = "공개 캡슐 상세 조회", description = "사용자의 친구들만 볼 수 있는 공개 캡슐 내용을 조회한다.", @@ -54,15 +87,23 @@ ResponseEntity createPublicCapsule( @ApiResponse( responseCode = "200", description = "ok" + ), + @ApiResponse( + responseCode = "403", + description = "해당 캡슐에 접근 권한이 없는 경우 발생하는 예외", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)) + ), + @ApiResponse( + responseCode = "404", + description = "해당 캡슐을 찾을 수 없을 경우 발생하는 예외", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)) ) }) - @GetMapping( - value = "/capsules/{capsule_id}", - produces = {"application/json"} - ) - ResponseEntity findPublicCapsuleById( + ResponseEntity> getPublicCapsuleDetailById( + Long memberId, + @Parameter(in = ParameterIn.PATH, description = "조회할 캡슐 아이디", required = true, schema = @Schema()) - @PathVariable("capsule_id") Long capsuleId + Long capsuleId ); @Operation( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApiController.java new file mode 100644 index 000000000..8d136b71e --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApiController.java @@ -0,0 +1,77 @@ +package site.timecapsulearchive.core.domain.capsule.public_capsule.api; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import site.timecapsulearchive.core.domain.capsule.public_capsule.data.reqeust.PublicCapsuleCreateRequest; +import site.timecapsulearchive.core.domain.capsule.public_capsule.data.reqeust.PublicCapsuleUpdateRequest; +import site.timecapsulearchive.core.domain.capsule.public_capsule.data.response.PublicCapsulePageResponse; +import site.timecapsulearchive.core.domain.capsule.public_capsule.data.response.PublicCapsuleSummaryResponse; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleDetailResponse; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleSummaryResponse; +import site.timecapsulearchive.core.domain.capsule.service.PublicCapsuleService; +import site.timecapsulearchive.core.global.common.response.ApiSpec; +import site.timecapsulearchive.core.global.common.response.SuccessCode; + +@RestController +@RequestMapping("/public") +@RequiredArgsConstructor +public class PublicCapsuleApiController implements PublicCapsuleApi { + + private final PublicCapsuleService publicCapsuleService; + + @Override + public ResponseEntity createPublicCapsule( + PublicCapsuleCreateRequest request) { + return null; + } + + @GetMapping( + value = "/capsules/{capsule_id}/summary", + produces = {"application/json"} + ) + @Override + public ResponseEntity> getPublicCapsuleSummaryById( + @AuthenticationPrincipal Long memberId, + @PathVariable("capsule_id") Long capsuleId + ) { + return ResponseEntity.ok( + ApiSpec.success( + SuccessCode.SUCCESS, + publicCapsuleService.findPublicCapsuleSummaryByMemberIdAndCapsuleId(memberId, capsuleId) + ) + ); + } + + @GetMapping( + value = "/capsules/{capsule_id}/detail", + produces = {"application/json"} + ) + @Override + public ResponseEntity> getPublicCapsuleDetailById( + @AuthenticationPrincipal Long memberId, + @PathVariable("capsule_id") Long capsuleId + ) { + return ResponseEntity.ok( + ApiSpec.success( + SuccessCode.SUCCESS, + publicCapsuleService.findPublicCapsuleDetailByMemberIdAndCapsuleId(memberId, capsuleId) + ) + ); + } + + @Override + public ResponseEntity getPublicCapsules(Long size, Long capsuleId) { + return null; + } + + @Override + public ResponseEntity updatePublicCapsuleById(Long capsuleId, + PublicCapsuleUpdateRequest request) { + return null; + } +} From fb4dde040e9350fde46ae62b47193597f97adf17 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 30 Mar 2024 19:01:31 +0900 Subject: [PATCH 160/314] =?UTF-8?q?fix=20:=20mapper=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20=ED=81=B4=EB=9E=98=EC=8A=A4?= =?UTF-8?q?=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/dto/CapsuleDetailDto.java} | 6 +- .../data/dto/CapsuleSummaryDto.java} | 4 +- .../domain/capsule/mapper/CapsuleMapper.java | 133 ++++++------------ .../repository/CapsuleQueryRepository.java | 14 +- .../api/SecretCapsuleApiController.java | 6 +- .../capsule/service/SecretCapsuleService.java | 40 +----- 6 files changed, 63 insertions(+), 140 deletions(-) rename backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/{secret_capsule/data/dto/SecretCapsuleDetailDto.java => generic_capsule/data/dto/CapsuleDetailDto.java} (73%) rename backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/{secret_capsule/data/dto/SecretCapsuleSummaryDto.java => generic_capsule/data/dto/CapsuleSummaryDto.java} (67%) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/SecretCapsuleDetailDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/dto/CapsuleDetailDto.java similarity index 73% rename from backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/SecretCapsuleDetailDto.java rename to backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/dto/CapsuleDetailDto.java index 0777e8e04..6ff434940 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/SecretCapsuleDetailDto.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/dto/CapsuleDetailDto.java @@ -1,11 +1,9 @@ -package site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto; +package site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto; import java.time.ZonedDateTime; -import lombok.Builder; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; -@Builder -public record SecretCapsuleDetailDto( +public record CapsuleDetailDto( Long capsuleId, String capsuleSkinUrl, ZonedDateTime dueDate, diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/SecretCapsuleSummaryDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/dto/CapsuleSummaryDto.java similarity index 67% rename from backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/SecretCapsuleSummaryDto.java rename to backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/dto/CapsuleSummaryDto.java index 621d4b503..517b9096e 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/SecretCapsuleSummaryDto.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/data/dto/CapsuleSummaryDto.java @@ -1,8 +1,8 @@ -package site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto; +package site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto; import java.time.ZonedDateTime; -public record SecretCapsuleSummaryDto( +public record CapsuleSummaryDto( String nickname, String profileUrl, String skinUrl, diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java index b417c089b..31ac57d40 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java @@ -12,12 +12,10 @@ import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.NearbyCapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.NearbyCapsuleSummaryResponse; -import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleDetailDto; -import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.MySecreteCapsuleDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleCreateRequestDto; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleDetailDto; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleSummaryDto; +import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleDetailDto; +import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.SecretCapsuleCreateRequest; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecreteCapsuleResponse; @@ -113,8 +111,8 @@ private ZonedDateTime checkNullable(final ZonedDateTime zonedDateTime) { return null; } - public CapsuleSummaryResponse secretCapsuleSummaryDtoToResponse( - final SecretCapsuleSummaryDto dto) { + public CapsuleSummaryResponse capsuleSummaryDtoToResponse( + final CapsuleSummaryDto dto) { return CapsuleSummaryResponse.builder() .nickname(dto.nickname()) .profileUrl(dto.profileUrl()) @@ -128,68 +126,8 @@ public CapsuleSummaryResponse secretCapsuleSummaryDtoToResponse( .build(); } - public CapsuleDetailResponse secretCapsuleDetailDtoToResponse( - final SecretCapsuleDetailDto dto, - final List imageUrls, - final List videoUrls - ) { - return CapsuleDetailResponse.builder() - .capsuleSkinUrl(s3PreSignedUrlManager.getS3PreSignedUrlForGet(dto.capsuleSkinUrl())) - .dueDate(checkNullable(dto.dueDate())) - .nickname(dto.nickname()) - .profileUrl(dto.profileUrl()) - .createdDate(dto.createdAt().withZoneSameInstant(ASIA_SEOUL)) - .address(dto.address()) - .title(dto.title()) - .content(dto.content()) - .imageUrls(imageUrls) - .videoUrls(videoUrls) - .isOpened(dto.isOpened()) - .capsuleType(dto.capsuleType()) - .build(); - } - - public CapsuleDetailResponse notOpenedSecretCapsuleDetailDtoToResponse( - final SecretCapsuleDetailDto dto) { - return CapsuleDetailResponse.builder() - .capsuleSkinUrl(s3PreSignedUrlManager.getS3PreSignedUrlForGet(dto.capsuleSkinUrl())) - .dueDate(checkNullable(dto.dueDate())) - .nickname(dto.nickname()) - .address(dto.address()) - .isOpened(dto.isOpened()) - .createdDate(dto.createdAt().withZoneSameInstant(ASIA_SEOUL)) - .title(dto.title()) - .build(); - } - - public MySecretCapsuleSliceResponse capsuleDetailSliceToResponse( - final List content, - final boolean hasNext - ) { - List responses = content.stream() - .map(this::mySecreteCapsuleDtoToResponse) - .toList(); - - return new MySecretCapsuleSliceResponse( - responses, - hasNext - ); - } - - private MySecreteCapsuleResponse mySecreteCapsuleDtoToResponse(final MySecreteCapsuleDto dto) { - return MySecreteCapsuleResponse.builder() - .capsuleId(dto.capsuleId()) - .SkinUrl(s3PreSignedUrlManager.getS3PreSignedUrlForGet(dto.skinUrl())) - .dueDate(dto.dueDate()) - .createdAt(dto.createdAt()) - .title(dto.title()) - .isOpened(dto.isOpened()) - .type(dto.type()) - .build(); - } - - public CapsuleDetailResponse publicCapsuleDetailDtoToResponse( - PublicCapsuleDetailDto detailDto + public CapsuleDetailResponse capsuleDetailDtoToResponse( + final CapsuleDetailDto detailDto ) { final S3PreSignedUrlDto preSignedUrls = s3PreSignedUrlManager.getS3PreSignedUrlsForGet( S3PreSignedUrlRequestDto.forGet( @@ -198,6 +136,7 @@ public CapsuleDetailResponse publicCapsuleDetailDtoToResponse( ) ); + return CapsuleDetailResponse.builder() .capsuleSkinUrl(s3PreSignedUrlManager.getS3PreSignedUrlForGet(detailDto.capsuleSkinUrl())) .dueDate(checkNullable(detailDto.dueDate())) @@ -214,6 +153,7 @@ public CapsuleDetailResponse publicCapsuleDetailDtoToResponse( .build(); } + private List splitFileNames(String fileNames) { if (fileNames == null) { return Collections.emptyList(); @@ -222,37 +162,48 @@ private List splitFileNames(String fileNames) { return List.of(fileNames.split(DELIMITER)); } - public CapsuleDetailResponse notOpenedPublicCapsuleDetailDtoToResponse( - final PublicCapsuleDetailDto dto + public CapsuleDetailResponse notOpenedCapsuleDetailDtoToResponse( + final CapsuleDetailDto detailDto ) { return CapsuleDetailResponse.builder() - .capsuleSkinUrl(s3PreSignedUrlManager.getS3PreSignedUrlForGet(dto.capsuleSkinUrl())) - .dueDate(checkNullable(dto.dueDate())) - .nickname(dto.nickname()) - .profileUrl(dto.profileUrl()) - .address(dto.address()) - .isOpened(dto.isOpened()) - .createdDate(dto.createdAt().withZoneSameInstant(ASIA_SEOUL)) + .capsuleSkinUrl(s3PreSignedUrlManager.getS3PreSignedUrlForGet(detailDto.capsuleSkinUrl())) + .dueDate(checkNullable(detailDto.dueDate())) + .nickname(detailDto.nickname()) + .profileUrl(detailDto.profileUrl()) + .createdDate(detailDto.createdAt().withZoneSameInstant(ASIA_SEOUL)) + .address(detailDto.address()) + .title("") + .content("") .imageUrls(Collections.emptyList()) .videoUrls(Collections.emptyList()) - .title(dto.title()) - .capsuleType(dto.capsuleType()) + .isOpened(detailDto.isOpened()) + .capsuleType(detailDto.capsuleType()) .build(); } - public CapsuleSummaryResponse publicCapsuleSummaryToResponse( - PublicCapsuleSummaryDto summaryDto + public MySecretCapsuleSliceResponse capsuleDetailSliceToResponse( + final List content, + final boolean hasNext ) { - return CapsuleSummaryResponse.builder() - .nickname(summaryDto.nickname()) - .profileUrl(summaryDto.profileUrl()) - .skinUrl(s3PreSignedUrlManager.getS3PreSignedUrlForGet(summaryDto.skinUrl())) - .title(summaryDto.title()) - .dueDate(checkNullable(summaryDto.dueDate())) - .address(summaryDto.address()) - .roadName(summaryDto.roadName()) - .isOpened(summaryDto.isOpened()) - .createdAt(summaryDto.createdAt().withZoneSameInstant(ASIA_SEOUL)) + List responses = content.stream() + .map(this::mySecreteCapsuleDtoToResponse) + .toList(); + + return new MySecretCapsuleSliceResponse( + responses, + hasNext + ); + } + + private MySecreteCapsuleResponse mySecreteCapsuleDtoToResponse(final MySecreteCapsuleDto dto) { + return MySecreteCapsuleResponse.builder() + .capsuleId(dto.capsuleId()) + .SkinUrl(s3PreSignedUrlManager.getS3PreSignedUrlForGet(dto.skinUrl())) + .dueDate(dto.dueDate()) + .createdAt(dto.createdAt()) + .title(dto.title()) + .isOpened(dto.isOpened()) + .type(dto.type()) .build(); } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/CapsuleQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/CapsuleQueryRepository.java index b812c7e38..27974d382 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/CapsuleQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/CapsuleQueryRepository.java @@ -24,8 +24,8 @@ import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.NearbyCapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.MySecreteCapsuleDto; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleDetailDto; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleSummaryDto; +import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleDetailDto; +import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; @Repository @RequiredArgsConstructor @@ -96,7 +96,7 @@ private void assignParameter( } } - public Optional findSecretCapsuleSummaryDtosByMemberIdAndCapsuleId( + public Optional findSecretCapsuleSummaryDtosByMemberIdAndCapsuleId( final Long memberId, final Long capsuleId ) { @@ -104,7 +104,7 @@ public Optional findSecretCapsuleSummaryDtosByMemberIdA jpaQueryFactory .select( Projections.constructor( - SecretCapsuleSummaryDto.class, + CapsuleSummaryDto.class, capsule.member.nickname, capsule.member.profileUrl, capsule.capsuleSkin.imageUrl, @@ -123,14 +123,14 @@ public Optional findSecretCapsuleSummaryDtosByMemberIdA ); } - public Optional findSecretCapsuleDetailDtosByMemberIdAndCapsuleId( + public Optional findSecretCapsuleDetailDtosByMemberIdAndCapsuleId( final Long memberId, final Long capsuleId ) { - final SecretCapsuleDetailDto detailDto = jpaQueryFactory + final CapsuleDetailDto detailDto = jpaQueryFactory .select( Projections.constructor( - SecretCapsuleDetailDto.class, + CapsuleDetailDto.class, capsule.id, capsuleSkin.imageUrl, capsule.dueDate, diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java index 2a25cb1a3..e518b4c30 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java @@ -15,7 +15,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import site.timecapsulearchive.core.domain.capsule.mapper.CapsuleMapper; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleSummaryDto; +import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.SecretCapsuleCreateRequest; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.SecretCapsuleUpdateRequest; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; @@ -58,14 +58,14 @@ public ResponseEntity> getSecretCapsuleSummary( @AuthenticationPrincipal final Long memberId, @PathVariable("capsule_id") final Long capsuleId ) { - final SecretCapsuleSummaryDto dto = secretCapsuleService.findSecretCapsuleSummaryById( + final CapsuleSummaryDto dto = secretCapsuleService.findSecretCapsuleSummaryById( memberId, capsuleId); return ResponseEntity.ok( ApiSpec.success( SuccessCode.SUCCESS, - capsuleMapper.secretCapsuleSummaryDtoToResponse(dto) + capsuleMapper.capsuleSummaryDtoToResponse(dto) ) ); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/SecretCapsuleService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/SecretCapsuleService.java index 08bd53ffa..4e85be325 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/SecretCapsuleService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/SecretCapsuleService.java @@ -2,7 +2,6 @@ import java.time.ZoneOffset; import java.time.ZonedDateTime; -import java.util.Collections; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Slice; @@ -19,8 +18,8 @@ import site.timecapsulearchive.core.domain.capsule.repository.VideoQueryRepository; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.MySecreteCapsuleDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleCreateRequestDto; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleDetailDto; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleSummaryDto; +import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleDetailDto; +import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleDetailResponse; import site.timecapsulearchive.core.domain.capsuleskin.entity.CapsuleSkin; @@ -29,8 +28,6 @@ import site.timecapsulearchive.core.domain.member.entity.Member; import site.timecapsulearchive.core.domain.member.exception.MemberNotFoundException; import site.timecapsulearchive.core.domain.member.repository.MemberRepository; -import site.timecapsulearchive.core.infra.s3.data.dto.S3PreSignedUrlDto; -import site.timecapsulearchive.core.infra.s3.data.request.S3PreSignedUrlRequestDto; import site.timecapsulearchive.core.infra.s3.manager.S3PreSignedUrlManager; @Service @@ -38,8 +35,6 @@ @RequiredArgsConstructor public class SecretCapsuleService { - private static final String DELIMITER = ","; - private final CapsuleQueryRepository capsuleQueryRepository; private final CapsuleRepository capsuleRepository; private final CapsuleSkinRepository capsuleSkinRepository; @@ -47,8 +42,6 @@ public class SecretCapsuleService { private final ImageQueryRepository imageQueryRepository; private final VideoQueryRepository videoQueryRepository; - private final S3PreSignedUrlManager s3PreSignedUrlManager; - private final CapsuleMapper capsuleMapper; private final ImageMapper imageMapper; private final VideoMapper videoMapper; @@ -79,7 +72,7 @@ public MySecretCapsuleSliceResponse findSecretCapsuleSliceByMemberId( * @param capsuleId 캡슐 아이디 * @return 캡슐 요약 정보 */ - public SecretCapsuleSummaryDto findSecretCapsuleSummaryById( + public CapsuleSummaryDto findSecretCapsuleSummaryById( final Long memberId, final Long capsuleId ) { @@ -99,37 +92,18 @@ public CapsuleDetailResponse findSecretCapsuleDetailById( final Long memberId, final Long capsuleId ) { - final SecretCapsuleDetailDto dto = capsuleQueryRepository.findSecretCapsuleDetailDtosByMemberIdAndCapsuleId( + final CapsuleDetailDto dto = capsuleQueryRepository.findSecretCapsuleDetailDtosByMemberIdAndCapsuleId( memberId, capsuleId) .orElseThrow(CapsuleNotFondException::new); if (capsuleNotOpened(dto)) { - return capsuleMapper.notOpenedSecretCapsuleDetailDtoToResponse(dto); - } - - final S3PreSignedUrlDto s3UrlsForGet = s3PreSignedUrlManager.getS3PreSignedUrlsForGet( - S3PreSignedUrlRequestDto.forGet( - splitFileNames(dto.images()), - splitFileNames(dto.videos()) - ) - ); - - return capsuleMapper.secretCapsuleDetailDtoToResponse( - dto, - s3UrlsForGet.preSignedImageUrls(), - s3UrlsForGet.preSignedVideoUrls() - ); - } - - private List splitFileNames(String fileNames) { - if (fileNames == null) { - return Collections.emptyList(); + return capsuleMapper.notOpenedCapsuleDetailDtoToResponse(dto); } - return List.of(fileNames.split(DELIMITER)); + return capsuleMapper.capsuleDetailDtoToResponse(dto); } - private boolean capsuleNotOpened(final SecretCapsuleDetailDto dto) { + private boolean capsuleNotOpened(final CapsuleDetailDto dto) { if (dto.dueDate() == null) { return false; } From c691f670c3ef523fcaeaa624a0393d2a0ac310b8 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 30 Mar 2024 19:02:21 +0900 Subject: [PATCH 161/314] =?UTF-8?q?fix=20:=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=BF=BC=EB=A6=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PublicCapsuleQueryRepository.java | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/PublicCapsuleQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/PublicCapsuleQueryRepository.java index 0ced8947f..e0214e232 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/PublicCapsuleQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/PublicCapsuleQueryRepository.java @@ -15,8 +15,8 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; -import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleDetailDto; -import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleSummaryDto; +import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleDetailDto; +import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; @Repository @RequiredArgsConstructor @@ -24,14 +24,14 @@ public class PublicCapsuleQueryRepository { private final JPAQueryFactory jpaQueryFactory; - public Optional findPublicCapsuleDetailDtosByMemberIdAndCapsuleId( + public Optional findPublicCapsuleDetailDtosByMemberIdAndCapsuleId( final Long memberId, final Long capsuleId ) { - final PublicCapsuleDetailDto detailDto = jpaQueryFactory + final CapsuleDetailDto detailDto = jpaQueryFactory .select( Projections.constructor( - PublicCapsuleDetailDto.class, + CapsuleDetailDto.class, capsule.id, capsuleSkin.imageUrl, capsule.dueDate, @@ -44,28 +44,31 @@ public Optional findPublicCapsuleDetailDtosByMemberIdAnd groupConcatDistinct(image.imageUrl), groupConcatDistinct(video.videoUrl), capsule.isOpened, - capsule.type, - memberFriend.id.isNotNull() + capsule.type ) ) .from(capsule) .join(member).on(capsule.member.id.eq(member.id)) - .join(member) - .on(memberFriend.friend.id.eq(member.id).and(memberFriend.owner.id.eq(memberId))) + .join(memberFriend).on(memberFriend.friend.id.eq(capsule.member.id) + .and(memberFriend.owner.id.eq(memberId))) .join(capsuleSkin).on(capsule.capsuleSkin.id.eq(capsuleSkin.id)) .leftJoin(image).on(capsule.id.eq(image.capsule.id)) .leftJoin(video).on(capsule.id.eq(video.capsule.id)) .where(capsule.id.eq(capsuleId).and(capsule.type.eq(CapsuleType.PUBLIC))) .fetchFirst(); - return Optional.ofNullable(detailDto); + if (detailDto.capsuleId() == null) { + return Optional.empty(); + } + + return Optional.of(detailDto); } private StringExpression groupConcatDistinct(final StringExpression expression) { return Expressions.stringTemplate("GROUP_CONCAT(DISTINCT {0})", expression); } - public Optional findPublicCapsuleSummaryDtosByMemberIdAndCapsuleId( + public Optional findPublicCapsuleSummaryDtosByMemberIdAndCapsuleId( Long memberId, Long capsuleId ) { @@ -73,7 +76,7 @@ public Optional findPublicCapsuleSummaryDtosByMemberIdA jpaQueryFactory .select( Projections.constructor( - PublicCapsuleSummaryDto.class, + CapsuleSummaryDto.class, capsule.member.nickname, capsule.member.profileUrl, capsule.capsuleSkin.imageUrl, @@ -82,12 +85,12 @@ public Optional findPublicCapsuleSummaryDtosByMemberIdA capsule.address.fullRoadAddressName, capsule.address.roadName, capsule.isOpened, - capsule.createdAt, - memberFriend.id.isNotNull() + capsule.createdAt ) ) .from(capsule) - .on(memberFriend.friend.id.eq(member.id).and(memberFriend.owner.id.eq(memberId))) + .join(memberFriend).on(memberFriend.friend.id.eq(capsule.member.id) + .and(memberFriend.owner.id.eq(memberId))) .where(capsule.id.eq(capsuleId).and(capsule.type.eq(CapsuleType.PUBLIC))) .fetchOne() ); From 2ab5a1c85a747d33eead12bf49477c471348058c Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 30 Mar 2024 19:02:33 +0900 Subject: [PATCH 162/314] =?UTF-8?q?fix=20:=20=EC=84=9C=EB=B9=84=EC=8A=A4?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../capsule/service/PublicCapsuleService.java | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/PublicCapsuleService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/PublicCapsuleService.java index 01384b6b5..1ef8d3997 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/PublicCapsuleService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/PublicCapsuleService.java @@ -6,11 +6,10 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import site.timecapsulearchive.core.domain.capsule.exception.CapsuleNotFondException; -import site.timecapsulearchive.core.domain.capsule.exception.NoCapsuleAuthorityException; import site.timecapsulearchive.core.domain.capsule.mapper.CapsuleMapper; -import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleDetailDto; -import site.timecapsulearchive.core.domain.capsule.public_capsule.data.dto.PublicCapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.repository.PublicCapsuleQueryRepository; +import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleDetailDto; +import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleDetailResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleSummaryResponse; @@ -24,22 +23,18 @@ public class PublicCapsuleService { public CapsuleDetailResponse findPublicCapsuleDetailByMemberIdAndCapsuleId(Long memberId, Long capsuleId) { - PublicCapsuleDetailDto detailDto = publicCapsuleQueryRepository.findPublicCapsuleDetailDtosByMemberIdAndCapsuleId( + CapsuleDetailDto detailDto = publicCapsuleQueryRepository.findPublicCapsuleDetailDtosByMemberIdAndCapsuleId( memberId, capsuleId) .orElseThrow(CapsuleNotFondException::new); - if (!detailDto.isFriend()) { - throw new NoCapsuleAuthorityException(); - } - if (capsuleNotOpened(detailDto)) { - return capsuleMapper.notOpenedPublicCapsuleDetailDtoToResponse(detailDto); + return capsuleMapper.notOpenedCapsuleDetailDtoToResponse(detailDto); } - return capsuleMapper.publicCapsuleDetailDtoToResponse(detailDto); + return capsuleMapper.capsuleDetailDtoToResponse(detailDto); } - private boolean capsuleNotOpened(final PublicCapsuleDetailDto detailDto) { + private boolean capsuleNotOpened(final CapsuleDetailDto detailDto) { if (detailDto.dueDate() == null) { return false; } @@ -52,14 +47,10 @@ public CapsuleSummaryResponse findPublicCapsuleSummaryByMemberIdAndCapsuleId( Long memberId, Long capsuleId ) { - PublicCapsuleSummaryDto summaryDto = publicCapsuleQueryRepository.findPublicCapsuleSummaryDtosByMemberIdAndCapsuleId( + CapsuleSummaryDto summaryDto = publicCapsuleQueryRepository.findPublicCapsuleSummaryDtosByMemberIdAndCapsuleId( memberId, capsuleId) .orElseThrow(CapsuleNotFondException::new); - if (!summaryDto.isFriend()) { - throw new NoCapsuleAuthorityException(); - } - - return capsuleMapper.publicCapsuleSummaryToResponse(summaryDto); + return capsuleMapper.capsuleSummaryDtoToResponse(summaryDto); } } From a814260525f410e001513162db7f2d5108faad11 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sat, 30 Mar 2024 19:03:18 +0900 Subject: [PATCH 163/314] =?UTF-8?q?style=20:=20=EA=B5=AC=EA=B8=80=20?= =?UTF-8?q?=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/capsule/mapper/CapsuleMapper.java | 18 ++++++++++-------- .../api/PublicCapsuleApiController.java | 6 ++++-- .../repository/CapsuleQueryRepository.java | 4 ++-- .../secret_capsule/api/SecretCapsuleApi.java | 2 +- .../api/SecretCapsuleApiController.java | 4 ++-- .../capsule/service/PublicCapsuleService.java | 4 ++-- .../capsule/service/SecretCapsuleService.java | 7 +++---- 7 files changed, 24 insertions(+), 21 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java index 31ac57d40..11e3c6e4d 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java @@ -10,17 +10,17 @@ import site.timecapsulearchive.core.domain.capsule.entity.Address; import site.timecapsulearchive.core.domain.capsule.entity.Capsule; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; +import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleDetailDto; +import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.NearbyCapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.NearbyCapsuleSummaryResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.MySecreteCapsuleDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleCreateRequestDto; -import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleDetailDto; -import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.SecretCapsuleCreateRequest; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecreteCapsuleResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleDetailResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleSummaryResponse; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecreteCapsuleResponse; import site.timecapsulearchive.core.domain.capsuleskin.entity.CapsuleSkin; import site.timecapsulearchive.core.domain.member.entity.Member; import site.timecapsulearchive.core.global.geography.GeoTransformManager; @@ -89,7 +89,8 @@ private Address addressDataToEntity(final AddressData addressData) { .build(); } - public NearbyCapsuleSummaryResponse capsuleSummaryDtoToResponse(final NearbyCapsuleSummaryDto dto) { + public NearbyCapsuleSummaryResponse capsuleSummaryDtoToResponse( + final NearbyCapsuleSummaryDto dto) { Point point = geoTransformManager.changePoint3857To4326(dto.point()); return NearbyCapsuleSummaryResponse.builder() @@ -136,9 +137,9 @@ public CapsuleDetailResponse capsuleDetailDtoToResponse( ) ); - return CapsuleDetailResponse.builder() - .capsuleSkinUrl(s3PreSignedUrlManager.getS3PreSignedUrlForGet(detailDto.capsuleSkinUrl())) + .capsuleSkinUrl( + s3PreSignedUrlManager.getS3PreSignedUrlForGet(detailDto.capsuleSkinUrl())) .dueDate(checkNullable(detailDto.dueDate())) .nickname(detailDto.nickname()) .profileUrl(detailDto.profileUrl()) @@ -166,7 +167,8 @@ public CapsuleDetailResponse notOpenedCapsuleDetailDtoToResponse( final CapsuleDetailDto detailDto ) { return CapsuleDetailResponse.builder() - .capsuleSkinUrl(s3PreSignedUrlManager.getS3PreSignedUrlForGet(detailDto.capsuleSkinUrl())) + .capsuleSkinUrl( + s3PreSignedUrlManager.getS3PreSignedUrlForGet(detailDto.capsuleSkinUrl())) .dueDate(checkNullable(detailDto.dueDate())) .nickname(detailDto.nickname()) .profileUrl(detailDto.profileUrl()) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApiController.java index 8d136b71e..61c791edf 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApiController.java @@ -42,7 +42,8 @@ public ResponseEntity> getPublicCapsuleSummaryBy return ResponseEntity.ok( ApiSpec.success( SuccessCode.SUCCESS, - publicCapsuleService.findPublicCapsuleSummaryByMemberIdAndCapsuleId(memberId, capsuleId) + publicCapsuleService.findPublicCapsuleSummaryByMemberIdAndCapsuleId(memberId, + capsuleId) ) ); } @@ -59,7 +60,8 @@ public ResponseEntity> getPublicCapsuleDetailById return ResponseEntity.ok( ApiSpec.success( SuccessCode.SUCCESS, - publicCapsuleService.findPublicCapsuleDetailByMemberIdAndCapsuleId(memberId, capsuleId) + publicCapsuleService.findPublicCapsuleDetailByMemberIdAndCapsuleId(memberId, + capsuleId) ) ); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/CapsuleQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/CapsuleQueryRepository.java index 27974d382..a8eda10a1 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/CapsuleQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/CapsuleQueryRepository.java @@ -22,10 +22,10 @@ import org.springframework.data.domain.SliceImpl; import org.springframework.stereotype.Repository; import site.timecapsulearchive.core.domain.capsule.entity.CapsuleType; -import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.NearbyCapsuleSummaryDto; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.MySecreteCapsuleDto; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; +import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.NearbyCapsuleSummaryDto; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.MySecreteCapsuleDto; @Repository @RequiredArgsConstructor diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApi.java index 5c89963eb..4313b209a 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApi.java @@ -12,9 +12,9 @@ import org.springframework.http.ResponseEntity; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.SecretCapsuleCreateRequest; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.SecretCapsuleUpdateRequest; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleDetailResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleSummaryResponse; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; import site.timecapsulearchive.core.global.common.response.ApiSpec; import site.timecapsulearchive.core.global.error.ErrorResponse; diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java index e518b4c30..208e07b9e 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java @@ -14,13 +14,13 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import site.timecapsulearchive.core.domain.capsule.mapper.CapsuleMapper; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; +import site.timecapsulearchive.core.domain.capsule.mapper.CapsuleMapper; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.SecretCapsuleCreateRequest; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.SecretCapsuleUpdateRequest; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleDetailResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleSummaryResponse; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; import site.timecapsulearchive.core.domain.capsule.service.SecretCapsuleService; import site.timecapsulearchive.core.global.common.response.ApiSpec; import site.timecapsulearchive.core.global.common.response.SuccessCode; diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/PublicCapsuleService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/PublicCapsuleService.java index 1ef8d3997..1d40c6726 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/PublicCapsuleService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/PublicCapsuleService.java @@ -6,10 +6,10 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import site.timecapsulearchive.core.domain.capsule.exception.CapsuleNotFondException; -import site.timecapsulearchive.core.domain.capsule.mapper.CapsuleMapper; -import site.timecapsulearchive.core.domain.capsule.repository.PublicCapsuleQueryRepository; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; +import site.timecapsulearchive.core.domain.capsule.mapper.CapsuleMapper; +import site.timecapsulearchive.core.domain.capsule.repository.PublicCapsuleQueryRepository; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleDetailResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleSummaryResponse; diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/SecretCapsuleService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/SecretCapsuleService.java index 4e85be325..e761303b5 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/SecretCapsuleService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/SecretCapsuleService.java @@ -9,6 +9,8 @@ import org.springframework.transaction.annotation.Transactional; import site.timecapsulearchive.core.domain.capsule.entity.Capsule; import site.timecapsulearchive.core.domain.capsule.exception.CapsuleNotFondException; +import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleDetailDto; +import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.mapper.CapsuleMapper; import site.timecapsulearchive.core.domain.capsule.mapper.ImageMapper; import site.timecapsulearchive.core.domain.capsule.mapper.VideoMapper; @@ -18,17 +20,14 @@ import site.timecapsulearchive.core.domain.capsule.repository.VideoQueryRepository; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.MySecreteCapsuleDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleCreateRequestDto; -import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleDetailDto; -import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.CapsuleDetailResponse; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; import site.timecapsulearchive.core.domain.capsuleskin.entity.CapsuleSkin; import site.timecapsulearchive.core.domain.capsuleskin.exception.CapsuleSkinNotFoundException; import site.timecapsulearchive.core.domain.capsuleskin.repository.CapsuleSkinRepository; import site.timecapsulearchive.core.domain.member.entity.Member; import site.timecapsulearchive.core.domain.member.exception.MemberNotFoundException; import site.timecapsulearchive.core.domain.member.repository.MemberRepository; -import site.timecapsulearchive.core.infra.s3.manager.S3PreSignedUrlManager; @Service @Transactional(readOnly = true) From 2a9970f59ae5678103101258efdd9e053ed9087e Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sat, 30 Mar 2024 23:54:32 +0900 Subject: [PATCH 164/314] =?UTF-8?q?refact=20:=20=EB=B9=84=EB=B0=80,=20?= =?UTF-8?q?=EC=B9=9C=EA=B5=AC=20=EC=BA=A1=EC=8A=90=20=EB=AC=B8=EC=84=9C?= =?UTF-8?q?=ED=99=94=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../generic_capsule/api/CapsuleApi.java | 55 +++++++++++++++++++ .../public_capsule/api/PublicCapsuleApi.java | 22 -------- .../secret_capsule/api/SecretCapsuleApi.java | 28 ---------- 3 files changed, 55 insertions(+), 50 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/api/CapsuleApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/api/CapsuleApi.java index 52348fc3a..8536dba3f 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/api/CapsuleApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/api/CapsuleApi.java @@ -13,6 +13,7 @@ import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.CapsuleOpenedResponse; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.ImagesPageResponse; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.NearbyCapsuleResponse; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.CapsuleCreateRequest; import site.timecapsulearchive.core.global.common.response.ApiSpec; import site.timecapsulearchive.core.global.error.ErrorResponse; @@ -93,5 +94,59 @@ ResponseEntity> updateCapsuleOpened( @Parameter(in = ParameterIn.PATH, description = "캡슐 아이디", required = true) Long capsuleId ); + + @Operation( + summary = "비밀 캡슐 생성", + description = "사용자만 볼 수 있는 비밀 캡슐을 생성한다.", + security = {@SecurityRequirement(name = "user_token")}, + tags = {"secret capsule"} + ) + @ApiResponses(value = { + @ApiResponse( + responseCode = "202", + description = "처리 시작" + ), + @ApiResponse( + responseCode = "400", + description = "좌표변환을 할 수 없을 때 발생하는 예외, 입력좌표 확인 요망", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)) + ), + @ApiResponse( + responseCode = "404", + description = "캡슐 스킨을 찾을 수 없을 경우 발생하는 예외", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)) + ) + }) + ResponseEntity> createSecretCapsule( + Long memberId, + CapsuleCreateRequest request + ); + + @Operation( + summary = "공개 캡슐 생성", + description = "사용자의 친구들만 볼 수 있는 공개 캡슐을 생성한다.", + security = {@SecurityRequirement(name = "user_token")}, + tags = {"public capsule"} + ) + @ApiResponses(value = { + @ApiResponse( + responseCode = "202", + description = "처리 시작" + ), + @ApiResponse( + responseCode = "400", + description = "좌표변환을 할 수 없을 때 발생하는 예외, 입력좌표 확인 요망", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)) + ), + @ApiResponse( + responseCode = "404", + description = "캡슐 스킨을 찾을 수 없을 경우 발생하는 예외", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)) + ) + }) + ResponseEntity> createPublicCapsule( + Long memberId, + CapsuleCreateRequest request + ); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApi.java index fc11b22d7..7b34eeb3f 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApi.java @@ -14,9 +14,7 @@ import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; -import site.timecapsulearchive.core.domain.capsule.public_capsule.data.reqeust.PublicCapsuleCreateRequest; import site.timecapsulearchive.core.domain.capsule.public_capsule.data.reqeust.PublicCapsuleUpdateRequest; import site.timecapsulearchive.core.domain.capsule.public_capsule.data.response.PublicCapsuleDetailResponse; import site.timecapsulearchive.core.domain.capsule.public_capsule.data.response.PublicCapsulePageResponse; @@ -24,26 +22,6 @@ public interface PublicCapsuleApi { - @Operation( - summary = "공개 캡슐 생성", - description = "사용자의 친구들만 볼 수 있는 공개 캡슐을 생성한다.", - security = {@SecurityRequirement(name = "user_token")}, - tags = {"public capsule"} - ) - @ApiResponses(value = { - @ApiResponse( - responseCode = "202", - description = "처리 시작" - ) - }) - @PostMapping( - value = "/public/capsules", - consumes = {"multipart/form-data"} - ) - ResponseEntity createPublicCapsule( - @ModelAttribute PublicCapsuleCreateRequest request - ); - @Operation( summary = "공개 캡슐 상세 조회", description = "사용자의 친구들만 볼 수 있는 공개 캡슐 내용을 조회한다.", diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApi.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApi.java index a849cd876..950c186ee 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApi.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApi.java @@ -10,7 +10,6 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement; import java.time.ZonedDateTime; import org.springframework.http.ResponseEntity; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.SecretCapsuleCreateRequest; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.SecretCapsuleUpdateRequest; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.SecretCapsuleDetailResponse; @@ -90,33 +89,6 @@ ResponseEntity> getSecretCapsuleDetail( Long capsuleId ); - @Operation( - summary = "비밀 캡슐 생성", - description = "사용자만 볼 수 있는 비밀 캡슐을 생성한다.", - security = {@SecurityRequirement(name = "user_token")}, - tags = {"secret capsule"} - ) - @ApiResponses(value = { - @ApiResponse( - responseCode = "202", - description = "처리 시작" - ), - @ApiResponse( - responseCode = "400", - description = "좌표변환을 할 수 없을 때 발생하는 예외, 입력좌표 확인 요망", - content = @Content(schema = @Schema(implementation = ErrorResponse.class)) - ), - @ApiResponse( - responseCode = "404", - description = "캡슐 스킨을 찾을 수 없을 경우 발생하는 예외", - content = @Content(schema = @Schema(implementation = ErrorResponse.class)) - ) - }) - ResponseEntity> createSecretCapsule( - Long memberId, - SecretCapsuleCreateRequest request - ); - @Operation( summary = "비밀 캡슐 수정", description = "사용자가 생성한 비밀 캡슐의 생성 시간이 24시간 이내라면 수정한다.", From c71e1a2b0f7803d284a0dfc1b8db07bb804ccf60 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sat, 30 Mar 2024 23:55:40 +0900 Subject: [PATCH 165/314] =?UTF-8?q?refact=20:=20=EB=B9=84=EB=B0=80=20?= =?UTF-8?q?=EC=BA=A1=EC=8A=90=20=EC=83=9D=EC=84=B1=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=9C=84=EC=B9=98=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/CapsuleApiController.java | 42 ++++++++++++++ .../api/PublicCapsuleApiController.java | 26 +++++++++ .../api/SecretCapsuleApiController.java | 22 -------- .../capsule/service/CapsuleService.java | 55 +++++++++++++++++++ .../capsule/service/SecretCapsuleService.java | 43 --------------- 5 files changed, 123 insertions(+), 65 deletions(-) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApiController.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/api/CapsuleApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/api/CapsuleApiController.java index 28682506f..26ce72f01 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/api/CapsuleApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/api/CapsuleApiController.java @@ -1,11 +1,14 @@ package site.timecapsulearchive.core.domain.capsule.generic_capsule.api; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -14,6 +17,8 @@ import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.CapsuleOpenedResponse; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.ImagesPageResponse; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.NearbyCapsuleResponse; +import site.timecapsulearchive.core.domain.capsule.mapper.CapsuleMapper; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.CapsuleCreateRequest; import site.timecapsulearchive.core.domain.capsule.service.CapsuleService; import site.timecapsulearchive.core.global.common.response.ApiSpec; import site.timecapsulearchive.core.global.common.response.SuccessCode; @@ -24,6 +29,7 @@ public class CapsuleApiController implements CapsuleApi { private final CapsuleService capsuleService; + private final CapsuleMapper capsuleMapper; @GetMapping(value = "/images", produces = {"application/json"}) @Override @@ -66,4 +72,40 @@ public ResponseEntity> updateCapsuleOpened( ) ); } + + + @PostMapping(value = "/secret", consumes = {"application/json"}) + @Override + public ResponseEntity> createSecretCapsule( + @AuthenticationPrincipal final Long memberId, + @Valid @RequestBody final CapsuleCreateRequest request + ) { + capsuleService.saveCapsule( + memberId, + capsuleMapper.CapsuleCreateRequestToDto(request) + ); + + return ResponseEntity.ok( + ApiSpec.empty( + SuccessCode.SUCCESS + ) + ); + } + @PostMapping(value = "/public", consumes = {"application/json"}) + @Override + public ResponseEntity> createPublicCapsule( + @AuthenticationPrincipal final Long memberId, + @Valid @RequestBody final CapsuleCreateRequest request) { + + capsuleService.saveCapsule( + memberId, + capsuleMapper.CapsuleCreateRequestToDto(request) + ); + + return ResponseEntity.ok( + ApiSpec.empty( + SuccessCode.SUCCESS + ) + ); + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApiController.java new file mode 100644 index 000000000..cebbc3edd --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/public_capsule/api/PublicCapsuleApiController.java @@ -0,0 +1,26 @@ +package site.timecapsulearchive.core.domain.capsule.public_capsule.api; + +import org.springframework.http.ResponseEntity; +import site.timecapsulearchive.core.domain.capsule.public_capsule.data.reqeust.PublicCapsuleUpdateRequest; +import site.timecapsulearchive.core.domain.capsule.public_capsule.data.response.PublicCapsuleDetailResponse; +import site.timecapsulearchive.core.domain.capsule.public_capsule.data.response.PublicCapsulePageResponse; +import site.timecapsulearchive.core.domain.capsule.public_capsule.data.response.PublicCapsuleSummaryResponse; + +public class PublicCapsuleApiController implements PublicCapsuleApi { + + @Override + public ResponseEntity findPublicCapsuleById(Long capsuleId) { + return null; + } + + @Override + public ResponseEntity getPublicCapsules(Long size, Long capsuleId) { + return null; + } + + @Override + public ResponseEntity updatePublicCapsuleById(Long capsuleId, + PublicCapsuleUpdateRequest request) { + return null; + } +} diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java index 4d17a9b43..51600f502 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/api/SecretCapsuleApiController.java @@ -1,6 +1,5 @@ package site.timecapsulearchive.core.domain.capsule.secret_capsule.api; -import jakarta.validation.Valid; import java.time.ZonedDateTime; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -9,14 +8,11 @@ import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import site.timecapsulearchive.core.domain.capsule.mapper.CapsuleMapper; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleSummaryDto; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.SecretCapsuleCreateRequest; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.SecretCapsuleUpdateRequest; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.SecretCapsuleDetailResponse; @@ -84,24 +80,6 @@ public ResponseEntity> getSecretCapsuleDeta ); } - @PostMapping(value = "/capsules", consumes = {"application/json"}) - @Override - public ResponseEntity> createSecretCapsule( - @AuthenticationPrincipal final Long memberId, - @Valid @RequestBody final SecretCapsuleCreateRequest request - ) { - secretCapsuleService.saveCapsule( - memberId, - capsuleMapper.secretCapsuleCreateRequestToDto(request) - ); - - return ResponseEntity.ok( - ApiSpec.empty( - SuccessCode.SUCCESS - ) - ); - } - @PatchMapping(value = "/capsules/{capsule_id}", consumes = {"multipart/form-data"}) @Override public ResponseEntity updateSecretCapsule( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/CapsuleService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/CapsuleService.java index 38e15f724..8faa740c9 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/CapsuleService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/CapsuleService.java @@ -1,5 +1,6 @@ package site.timecapsulearchive.core.domain.capsule.service; +import java.util.List; import lombok.RequiredArgsConstructor; import org.locationtech.jts.geom.Point; import org.locationtech.jts.geom.Polygon; @@ -12,8 +13,19 @@ import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.CapsuleOpenedResponse; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.NearbyCapsuleResponse; import site.timecapsulearchive.core.domain.capsule.mapper.CapsuleMapper; +import site.timecapsulearchive.core.domain.capsule.mapper.ImageMapper; +import site.timecapsulearchive.core.domain.capsule.mapper.VideoMapper; import site.timecapsulearchive.core.domain.capsule.repository.CapsuleQueryRepository; import site.timecapsulearchive.core.domain.capsule.repository.CapsuleRepository; +import site.timecapsulearchive.core.domain.capsule.repository.ImageQueryRepository; +import site.timecapsulearchive.core.domain.capsule.repository.VideoQueryRepository; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.CapsuleCreateRequestDto; +import site.timecapsulearchive.core.domain.capsuleskin.entity.CapsuleSkin; +import site.timecapsulearchive.core.domain.capsuleskin.exception.CapsuleSkinNotFoundException; +import site.timecapsulearchive.core.domain.capsuleskin.repository.CapsuleSkinRepository; +import site.timecapsulearchive.core.domain.member.entity.Member; +import site.timecapsulearchive.core.domain.member.exception.MemberNotFoundException; +import site.timecapsulearchive.core.domain.member.repository.MemberRepository; import site.timecapsulearchive.core.global.geography.GeoTransformManager; @Service @@ -23,7 +35,13 @@ public class CapsuleService { private final CapsuleQueryRepository capsuleQueryRepository; private final CapsuleRepository capsuleRepository; + private final MemberRepository memberRepository; + private final CapsuleSkinRepository capsuleSkinRepository; + private final ImageQueryRepository imageQueryRepository; + private final VideoQueryRepository videoQueryRepository; private final GeoTransformManager geoTransformManager; + private final ImageMapper imageMapper; + private final VideoMapper videoMapper; private final CapsuleMapper capsuleMapper; /** @@ -69,4 +87,41 @@ public CapsuleOpenedResponse updateCapsuleOpened(final Long memberId, final Long capsuleRepository.updateIsOpenedTrue(memberId, capsuleId); return CapsuleOpenedResponse.opened(); } + + /** + * 멤버 아이디와 캡슐 생성 포맷을 받아서 캡슐을 생성한다. + * + * @param memberId 캡슐을 생성할 멤버 아이디 + * @param dto 캡슐 생성 요청 포맷 + */ + @Transactional + public void saveCapsule(final Long memberId, final CapsuleCreateRequestDto dto) { + final Member foundMember = memberRepository.findMemberById(memberId) + .orElseThrow(MemberNotFoundException::new); + + final CapsuleSkin foundCapsuleSkin = capsuleSkinRepository + .findCapsuleSkinById(dto.capsuleSkinId()) + .orElseThrow(CapsuleSkinNotFoundException::new); + + final Capsule capsule = capsuleMapper.requestDtoToEntity(dto, foundMember, + foundCapsuleSkin); + + capsuleRepository.save(capsule); + + if (isNotEmpty(dto.imageNames())) { + imageQueryRepository.bulkSave( + imageMapper.toEntity(capsule, foundMember, dto.directory(), dto.imageNames()) + ); + } + + if (isNotEmpty(dto.videoNames())) { + videoQueryRepository.bulkSave( + videoMapper.toEntity(capsule, foundMember, dto.directory(), dto.videoNames()) + ); + } + } + + private boolean isNotEmpty(List fileNames) { + return fileNames != null && !fileNames.isEmpty(); + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/SecretCapsuleService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/SecretCapsuleService.java index a675feb4d..c3ecda20e 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/SecretCapsuleService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/SecretCapsuleService.java @@ -8,7 +8,6 @@ import org.springframework.data.domain.Slice; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import site.timecapsulearchive.core.domain.capsule.entity.Capsule; import site.timecapsulearchive.core.domain.capsule.exception.CapsuleNotFondException; import site.timecapsulearchive.core.domain.capsule.mapper.CapsuleMapper; import site.timecapsulearchive.core.domain.capsule.mapper.ImageMapper; @@ -18,16 +17,11 @@ import site.timecapsulearchive.core.domain.capsule.repository.ImageQueryRepository; import site.timecapsulearchive.core.domain.capsule.repository.VideoQueryRepository; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.MySecreteCapsuleDto; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleCreateRequestDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.SecretCapsuleDetailResponse; -import site.timecapsulearchive.core.domain.capsuleskin.entity.CapsuleSkin; -import site.timecapsulearchive.core.domain.capsuleskin.exception.CapsuleSkinNotFoundException; import site.timecapsulearchive.core.domain.capsuleskin.repository.CapsuleSkinRepository; -import site.timecapsulearchive.core.domain.member.entity.Member; -import site.timecapsulearchive.core.domain.member.exception.MemberNotFoundException; import site.timecapsulearchive.core.domain.member.repository.MemberRepository; import site.timecapsulearchive.core.infra.s3.data.dto.S3PreSignedUrlDto; import site.timecapsulearchive.core.infra.s3.data.request.S3PreSignedUrlRequestDto; @@ -136,42 +130,5 @@ private boolean capsuleNotOpened(final SecretCapsuleDetailDto dto) { return !dto.isOpened() || dto.dueDate().isAfter(ZonedDateTime.now(ZoneOffset.UTC)); } - - /** - * 멤버 아이디와 캡슐 생성 포맷을 받아서 캡슐을 생성한다. - * - * @param memberId 캡슐을 생성할 멤버 아이디 - * @param dto 캡슐 생성 요청 포맷 - */ - @Transactional - public void saveCapsule(final Long memberId, final SecretCapsuleCreateRequestDto dto) { - final Member foundMember = memberRepository.findMemberById(memberId) - .orElseThrow(MemberNotFoundException::new); - - final CapsuleSkin foundCapsuleSkin = capsuleSkinRepository - .findCapsuleSkinById(dto.capsuleSkinId()) - .orElseThrow(CapsuleSkinNotFoundException::new); - - final Capsule capsule = capsuleMapper.requestDtoToEntity(dto, foundMember, - foundCapsuleSkin); - - capsuleRepository.save(capsule); - - if (isNotEmpty(dto.imageNames())) { - imageQueryRepository.bulkSave( - imageMapper.toEntity(capsule, foundMember, dto.directory(), dto.imageNames()) - ); - } - - if (isNotEmpty(dto.videoNames())) { - videoQueryRepository.bulkSave( - videoMapper.toEntity(capsule, foundMember, dto.directory(), dto.videoNames()) - ); - } - } - - private boolean isNotEmpty(List fileNames) { - return fileNames != null && !fileNames.isEmpty(); - } } From c865b58068c530008839ce0e70211c35c6a88da5 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sat, 30 Mar 2024 23:55:57 +0900 Subject: [PATCH 166/314] =?UTF-8?q?fix=20:=20=EC=BA=A1=EC=8A=90=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20dto=20=EC=9D=B4=EB=A6=84=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/capsule/mapper/CapsuleMapper.java | 12 ++++++------ ...eRequestDto.java => CapsuleCreateRequestDto.java} | 2 +- ...eCreateRequest.java => CapsuleCreateRequest.java} | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) rename backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/{SecretCapsuleCreateRequestDto.java => CapsuleCreateRequestDto.java} (91%) rename backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/reqeust/{SecretCapsuleCreateRequest.java => CapsuleCreateRequest.java} (97%) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java index 06074fb89..8d95415e9 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java @@ -12,10 +12,10 @@ import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.dto.CapsuleSummaryDto; import site.timecapsulearchive.core.domain.capsule.generic_capsule.data.response.CapsuleSummaryResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.MySecreteCapsuleDto; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleCreateRequestDto; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.CapsuleCreateRequestDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleDetailDto; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.dto.SecretCapsuleSummaryDto; -import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.SecretCapsuleCreateRequest; +import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.reqeust.CapsuleCreateRequest; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecretCapsuleSliceResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.MySecreteCapsuleResponse; import site.timecapsulearchive.core.domain.capsule.secret_capsule.data.response.SecretCapsuleDetailResponse; @@ -35,9 +35,9 @@ public class CapsuleMapper { private final GeoTransformManager geoTransformManager; private final S3PreSignedUrlManager s3PreSignedUrlManager; - public SecretCapsuleCreateRequestDto secretCapsuleCreateRequestToDto( - final SecretCapsuleCreateRequest request) { - return SecretCapsuleCreateRequestDto.builder() + public CapsuleCreateRequestDto CapsuleCreateRequestToDto( + final CapsuleCreateRequest request) { + return CapsuleCreateRequestDto.builder() .capsuleSkinId(request.capsuleSkinId()) .title(request.title()) .content(request.content()) @@ -52,7 +52,7 @@ public SecretCapsuleCreateRequestDto secretCapsuleCreateRequestToDto( } public Capsule requestDtoToEntity( - final SecretCapsuleCreateRequestDto dto, + final CapsuleCreateRequestDto dto, final Member member, final CapsuleSkin capsuleSkin ) { diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/SecretCapsuleCreateRequestDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/CapsuleCreateRequestDto.java similarity index 91% rename from backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/SecretCapsuleCreateRequestDto.java rename to backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/CapsuleCreateRequestDto.java index de71e014f..fb7820225 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/SecretCapsuleCreateRequestDto.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/CapsuleCreateRequestDto.java @@ -6,7 +6,7 @@ import site.timecapsulearchive.core.infra.map.data.dto.AddressData; @Builder -public record SecretCapsuleCreateRequestDto( +public record CapsuleCreateRequestDto( Long capsuleSkinId, String title, String content, diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/reqeust/SecretCapsuleCreateRequest.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/reqeust/CapsuleCreateRequest.java similarity index 97% rename from backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/reqeust/SecretCapsuleCreateRequest.java rename to backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/reqeust/CapsuleCreateRequest.java index 29fabf689..bf739978a 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/reqeust/SecretCapsuleCreateRequest.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/reqeust/CapsuleCreateRequest.java @@ -11,7 +11,7 @@ import site.timecapsulearchive.core.infra.map.data.dto.AddressData; @Schema(description = "캡슐 생성 포맷") -public record SecretCapsuleCreateRequest( +public record CapsuleCreateRequest( @Schema(description = "이미지 이름들") List<@Image String> imageNames, From 723e6c9d5e21a9471e19ddbf1a198f740cb37409 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 31 Mar 2024 00:30:46 +0900 Subject: [PATCH 167/314] =?UTF-8?q?refact:=20=EC=9C=84=EB=8F=84,=20?= =?UTF-8?q?=EA=B2=BD=EB=8F=84=20=ED=83=80=EC=9E=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/dto/CapsuleCreateRequestDto.java | 4 ++-- .../data/reqeust/CapsuleCreateRequest.java | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/CapsuleCreateRequestDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/CapsuleCreateRequestDto.java index fb7820225..6f0e6efa4 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/CapsuleCreateRequestDto.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/dto/CapsuleCreateRequestDto.java @@ -10,8 +10,8 @@ public record CapsuleCreateRequestDto( Long capsuleSkinId, String title, String content, - double longitude, - double latitude, + Double longitude, + Double latitude, AddressData addressData, ZonedDateTime dueDate, List imageNames, diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/reqeust/CapsuleCreateRequest.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/reqeust/CapsuleCreateRequest.java index bf739978a..57c76e11c 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/reqeust/CapsuleCreateRequest.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/secret_capsule/data/reqeust/CapsuleCreateRequest.java @@ -6,6 +6,7 @@ import jakarta.validation.constraints.NotNull; import java.time.ZonedDateTime; import java.util.List; +import org.hibernate.validator.constraints.Range; import site.timecapsulearchive.core.global.common.valid.annotation.Image; import site.timecapsulearchive.core.global.common.valid.annotation.Video; import site.timecapsulearchive.core.infra.map.data.dto.AddressData; @@ -35,11 +36,15 @@ public record CapsuleCreateRequest( @NotBlank(message = "캡슐 내용은 필수 입니다.") String content, - @Schema(description = "현재 경도(wsg84)", requiredMode = RequiredMode.REQUIRED) - double longitude, + @Range(min = -180, max = 180) + @NotNull(message = "현재 경도는 필수 입니다.") + @Schema(description = "현재 경도(wsg84)") + Double longitude, + @Range(min = -90, max = 90) + @NotNull(message = "현재 경도는 필수 입니다.") @Schema(description = "현재 위도(wsg84)", requiredMode = RequiredMode.REQUIRED) - double latitude, + Double latitude, @Schema(description = "캡슐 생성 주소") @NotNull(message = "캡슐 생성 주소는 필수 입니다.") From d1c9b8d60c728aa2a0acc1da16b3278bc24eb557 Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 31 Mar 2024 00:31:15 +0900 Subject: [PATCH 168/314] =?UTF-8?q?refact=20:=20=EC=BA=A1=EC=8A=90=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EA=B8=B0=EB=8A=A5=20=EC=BA=A1=EC=8A=90=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../capsule/generic_capsule/api/CapsuleApiController.java | 6 ++++-- .../core/domain/capsule/mapper/CapsuleMapper.java | 7 ++++--- .../core/domain/capsule/service/CapsuleService.java | 8 ++++++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/api/CapsuleApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/api/CapsuleApiController.java index 26ce72f01..fc43b9dff 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/api/CapsuleApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/api/CapsuleApiController.java @@ -82,7 +82,8 @@ public ResponseEntity> createSecretCapsule( ) { capsuleService.saveCapsule( memberId, - capsuleMapper.CapsuleCreateRequestToDto(request) + capsuleMapper.capsuleCreateRequestToDto(request), + CapsuleType.SECRET ); return ResponseEntity.ok( @@ -99,7 +100,8 @@ public ResponseEntity> createPublicCapsule( capsuleService.saveCapsule( memberId, - capsuleMapper.CapsuleCreateRequestToDto(request) + capsuleMapper.capsuleCreateRequestToDto(request), + CapsuleType.PUBLIC ); return ResponseEntity.ok( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java index 8d95415e9..d20bf2766 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/mapper/CapsuleMapper.java @@ -35,7 +35,7 @@ public class CapsuleMapper { private final GeoTransformManager geoTransformManager; private final S3PreSignedUrlManager s3PreSignedUrlManager; - public CapsuleCreateRequestDto CapsuleCreateRequestToDto( + public CapsuleCreateRequestDto capsuleCreateRequestToDto( final CapsuleCreateRequest request) { return CapsuleCreateRequestDto.builder() .capsuleSkinId(request.capsuleSkinId()) @@ -54,7 +54,8 @@ public CapsuleCreateRequestDto CapsuleCreateRequestToDto( public Capsule requestDtoToEntity( final CapsuleCreateRequestDto dto, final Member member, - final CapsuleSkin capsuleSkin + final CapsuleSkin capsuleSkin, + final CapsuleType capsuleType ) { final Point point = geoTransformManager.changePoint4326To3857(dto.latitude(), dto.longitude()); @@ -64,7 +65,7 @@ public Capsule requestDtoToEntity( .content(dto.content()) .point(point) .address(addressDataToEntity(dto.addressData())) - .type(CapsuleType.SECRET) + .type(capsuleType) .member(member) .dueDate(dto.dueDate()) .capsuleSkin(capsuleSkin) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/CapsuleService.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/CapsuleService.java index 8faa740c9..ef58b9e10 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/CapsuleService.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/service/CapsuleService.java @@ -95,7 +95,11 @@ public CapsuleOpenedResponse updateCapsuleOpened(final Long memberId, final Long * @param dto 캡슐 생성 요청 포맷 */ @Transactional - public void saveCapsule(final Long memberId, final CapsuleCreateRequestDto dto) { + public void saveCapsule( + final Long memberId, + final CapsuleCreateRequestDto dto, + final CapsuleType capsuleType + ) { final Member foundMember = memberRepository.findMemberById(memberId) .orElseThrow(MemberNotFoundException::new); @@ -104,7 +108,7 @@ public void saveCapsule(final Long memberId, final CapsuleCreateRequestDto dto) .orElseThrow(CapsuleSkinNotFoundException::new); final Capsule capsule = capsuleMapper.requestDtoToEntity(dto, foundMember, - foundCapsuleSkin); + foundCapsuleSkin, capsuleType); capsuleRepository.save(capsule); From dffd3d09d400206894ea2201249e4d38e175ac54 Mon Sep 17 00:00:00 2001 From: hong seokho Date: Sun, 31 Mar 2024 00:33:02 +0900 Subject: [PATCH 169/314] =?UTF-8?q?feat=20:=20status,=20categoryName=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/data/dto/MemberNotificationDto.java | 6 +++++- .../domain/member/data/mapper/MemberMapper.java | 2 ++ .../data/response/MemberNotificationResponse.java | 6 +++++- .../core/domain/member/entity/CategoryName.java | 2 +- .../core/domain/member/entity/Notification.java | 8 +++++++- .../domain/member/entity/NotificationStatus.java | 5 +++++ .../member/repository/MemberQueryRepository.java | 13 +++++++------ 7 files changed, 32 insertions(+), 10 deletions(-) create mode 100644 backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/NotificationStatus.java diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/dto/MemberNotificationDto.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/dto/MemberNotificationDto.java index 3d5c1a230..c2759cf97 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/dto/MemberNotificationDto.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/dto/MemberNotificationDto.java @@ -1,12 +1,16 @@ package site.timecapsulearchive.core.domain.member.data.dto; import java.time.ZonedDateTime; +import site.timecapsulearchive.core.domain.member.entity.CategoryName; +import site.timecapsulearchive.core.domain.member.entity.NotificationStatus; public record MemberNotificationDto( String title, String text, ZonedDateTime createdAt, - String imageUrl + String imageUrl, + CategoryName categoryName, + NotificationStatus status ) { } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java index d047d1819..b4da5c44c 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/mapper/MemberMapper.java @@ -84,6 +84,8 @@ public MemberNotificationSliceResponse notificationSliceToResponse( .text(dto.text()) .createdAt(dto.createdAt().withZoneSameInstant(ASIA_SEOUL)) .imageUrl(imageUrl) + .categoryName(dto.categoryName()) + .status(dto.status()) .build(); } ) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/response/MemberNotificationResponse.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/response/MemberNotificationResponse.java index abe626582..93287c46e 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/response/MemberNotificationResponse.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/data/response/MemberNotificationResponse.java @@ -2,13 +2,17 @@ import java.time.ZonedDateTime; import lombok.Builder; +import site.timecapsulearchive.core.domain.member.entity.CategoryName; +import site.timecapsulearchive.core.domain.member.entity.NotificationStatus; @Builder public record MemberNotificationResponse( String title, String text, ZonedDateTime createdAt, - String imageUrl + String imageUrl, + CategoryName categoryName, + NotificationStatus status ) { } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/CategoryName.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/CategoryName.java index 76acda652..2fbdab7db 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/CategoryName.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/CategoryName.java @@ -1,5 +1,5 @@ package site.timecapsulearchive.core.domain.member.entity; public enum CategoryName { - CAPSULE_SKIN + CAPSULE_SKIN, FRIEND_REQUEST, FRIEND_ACCEPT, GROUP_REQUEST, GROUP_ACCEPT } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Notification.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Notification.java index 8afde5f1d..1e7f2a220 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Notification.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/Notification.java @@ -2,6 +2,8 @@ import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; @@ -38,7 +40,11 @@ public class Notification extends BaseEntity { @JoinColumn(name = "member_id", nullable = false) private Member member; + @Column(name = "status") + @Enumerated(EnumType.STRING) + private NotificationStatus status; + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "notification_category_id", nullable = false) private NotificationCategory notificationCategory; -} +} \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/NotificationStatus.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/NotificationStatus.java new file mode 100644 index 000000000..ecbf3995c --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/entity/NotificationStatus.java @@ -0,0 +1,5 @@ +package site.timecapsulearchive.core.domain.member.entity; + +public enum NotificationStatus { + SUCCESS, FAIL +} \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java index db36f04ff..b927c51d9 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/member/repository/MemberQueryRepository.java @@ -2,6 +2,7 @@ import static site.timecapsulearchive.core.domain.member.entity.QMember.member; import static site.timecapsulearchive.core.domain.member.entity.QNotification.notification; +import static site.timecapsulearchive.core.domain.member.entity.QNotificationCategory.notificationCategory; import com.querydsl.core.types.Projections; import com.querydsl.jpa.impl.JPAQueryFactory; @@ -17,6 +18,7 @@ import site.timecapsulearchive.core.domain.member.data.dto.MemberDetailResponseDto; import site.timecapsulearchive.core.domain.member.data.dto.MemberNotificationDto; import site.timecapsulearchive.core.domain.member.data.dto.VerifiedCheckDto; +import site.timecapsulearchive.core.domain.member.entity.QNotificationCategory; import site.timecapsulearchive.core.domain.member.entity.SocialType; @Repository @@ -79,7 +81,7 @@ public Slice findNotificationSliceByMemberId( final List notifications = findMemberNotificationDtos( memberId, size, createdAt); - final boolean hasNext = canMoreRead(size, notifications.size()); + final boolean hasNext = notifications.size() > size; if (hasNext) { notifications.remove(size); } @@ -99,20 +101,19 @@ private List findMemberNotificationDtos( notification.title, notification.text, notification.createdAt, - notification.imageUrl + notification.imageUrl, + notificationCategory.categoryName, + notification.status ) ) .from(notification) + .join(notification.notificationCategory, notificationCategory) .where(notification.createdAt.lt(createdAt).and(notification.member.id.eq(memberId))) .orderBy(notification.id.desc()) .limit(size + 1) .fetch(); } - private boolean canMoreRead(final int size, final int notificationSize) { - return notificationSize > size; - } - public Optional findEmailVerifiedCheckDtoByEmail( final String email ) { From f330b5ce95001337c085bca65472b02855629f9e Mon Sep 17 00:00:00 2001 From: GaBaljaintheroom Date: Sun, 31 Mar 2024 14:25:49 +0900 Subject: [PATCH 170/314] =?UTF-8?q?refact=20:=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80,=20=EB=B9=84=EB=94=94=EC=98=A4=20=EB=A0=88=ED=8F=AC?= =?UTF-8?q?=EC=A7=80=ED=86=A0=EB=A6=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../capsule/generic_capsule/api/CapsuleApiController.java | 3 +-- .../core/domain/capsule/repository/ImageQueryRepository.java | 4 ---- .../core/domain/capsule/repository/VideoQueryRepository.java | 4 ---- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/api/CapsuleApiController.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/api/CapsuleApiController.java index fc43b9dff..cbde1e3db 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/api/CapsuleApiController.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/generic_capsule/api/CapsuleApiController.java @@ -58,7 +58,6 @@ public ResponseEntity> getNearbyCapsules( ); } - @PatchMapping(value = "/{capsule_id}/opened", produces = {"application/json"}) @Override public ResponseEntity> updateCapsuleOpened( @@ -73,7 +72,6 @@ public ResponseEntity> updateCapsuleOpened( ); } - @PostMapping(value = "/secret", consumes = {"application/json"}) @Override public ResponseEntity> createSecretCapsule( @@ -92,6 +90,7 @@ public ResponseEntity> createSecretCapsule( ) ); } + @PostMapping(value = "/public", consumes = {"application/json"}) @Override public ResponseEntity> createPublicCapsule( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/ImageQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/ImageQueryRepository.java index 672791605..0b74d73c1 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/ImageQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/ImageQueryRepository.java @@ -19,10 +19,6 @@ public class ImageQueryRepository { private final JdbcTemplate jdbcTemplate; public void bulkSave(final List images) { - batchInsert(images); - } - - private void batchInsert(final List images) { jdbcTemplate.batchUpdate( """ INSERT INTO image ( diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/VideoQueryRepository.java b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/VideoQueryRepository.java index 02316b126..1b3728e67 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/VideoQueryRepository.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/domain/capsule/repository/VideoQueryRepository.java @@ -19,10 +19,6 @@ public class VideoQueryRepository { private final JdbcTemplate jdbcTemplate; public void bulkSave(final List