diff --git a/src/main/java/com/listywave/alarm/application/domain/Alarm.java b/src/main/java/com/listywave/alarm/application/domain/Alarm.java index c10c958f..a897e7c4 100644 --- a/src/main/java/com/listywave/alarm/application/domain/Alarm.java +++ b/src/main/java/com/listywave/alarm/application/domain/Alarm.java @@ -9,6 +9,7 @@ import com.listywave.list.application.domain.comment.Comment; import com.listywave.list.application.domain.list.ListEntity; import com.listywave.list.application.domain.reply.Reply; +import com.listywave.notice.application.domain.Notice; import com.listywave.user.application.domain.User; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -44,7 +45,7 @@ public class Alarm { @JoinColumn(name = "send_user_id", nullable = false) private User sendUser; - @Column(nullable = false) + @Column(nullable = true) private Long receiveUserId; @ManyToOne(fetch = LAZY) @@ -59,6 +60,10 @@ public class Alarm { @JoinColumn(name = "reply_id", nullable = true, foreignKey = @ForeignKey(name = "alarm_reply_fk")) private Reply reply; + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "notice_id", nullable = true, foreignKey = @ForeignKey(name = "alarm_notice_fk")) + private Notice notice; + @Column(nullable = false) @Enumerated(value = STRING) private AlarmType type; diff --git a/src/main/java/com/listywave/alarm/application/domain/AlarmCreateEvent.java b/src/main/java/com/listywave/alarm/application/domain/AlarmCreateEvent.java index 44957069..92d4d19f 100644 --- a/src/main/java/com/listywave/alarm/application/domain/AlarmCreateEvent.java +++ b/src/main/java/com/listywave/alarm/application/domain/AlarmCreateEvent.java @@ -3,12 +3,14 @@ import static com.listywave.alarm.application.domain.AlarmType.COLLECT; import static com.listywave.alarm.application.domain.AlarmType.COMMENT; import static com.listywave.alarm.application.domain.AlarmType.FOLLOW; +import static com.listywave.alarm.application.domain.AlarmType.NOTICE; import static com.listywave.alarm.application.domain.AlarmType.REPLY; import com.listywave.list.application.domain.comment.Comment; import com.listywave.list.application.domain.list.ListEntity; import com.listywave.list.application.domain.reply.Reply; import com.listywave.mention.Mention; +import com.listywave.notice.application.domain.Notice; import com.listywave.user.application.domain.User; import java.util.List; import lombok.Builder; @@ -21,6 +23,7 @@ public record AlarmCreateEvent( Comment comment, Reply reply, List mentions, + Notice notice, AlarmType alarmType ) { @@ -32,6 +35,7 @@ public Alarm toEntity() { .comment(comment) .reply(reply) .type(alarmType) + .notice(notice) .isChecked(false) .build(); } @@ -76,6 +80,14 @@ public static AlarmCreateEvent collect(User publisher, ListEntity list) { .build(); } + public static AlarmCreateEvent notice(User user, Notice notice) { + return AlarmCreateEvent.builder() + .publisher(user) + .notice(notice) + .alarmType(NOTICE) + .build(); + } + public boolean isToMyself() { return this.publisher.isSame(listenerId); } diff --git a/src/main/java/com/listywave/alarm/application/domain/AlarmType.java b/src/main/java/com/listywave/alarm/application/domain/AlarmType.java index 613e02a2..163758ba 100644 --- a/src/main/java/com/listywave/alarm/application/domain/AlarmType.java +++ b/src/main/java/com/listywave/alarm/application/domain/AlarmType.java @@ -11,5 +11,6 @@ public enum AlarmType { REPLY, MENTION, COLLABORATOR, + NOTICE, ; } diff --git a/src/main/java/com/listywave/alarm/application/dto/AlarmFindResponse.java b/src/main/java/com/listywave/alarm/application/dto/AlarmFindResponse.java index 9fc49755..f7ea3041 100644 --- a/src/main/java/com/listywave/alarm/application/dto/AlarmFindResponse.java +++ b/src/main/java/com/listywave/alarm/application/dto/AlarmFindResponse.java @@ -6,7 +6,9 @@ import com.listywave.list.application.domain.list.ListEntity; import com.listywave.list.application.domain.reply.Reply; import com.listywave.mention.Mention; +import com.listywave.notice.application.domain.Notice; import com.listywave.user.application.domain.User; +import jakarta.annotation.Nullable; import java.time.LocalDateTime; import java.util.List; import lombok.Builder; @@ -18,9 +20,10 @@ public record AlarmFindResponse( @JsonProperty("checked") boolean isChecked, String type, UserDto sendUser, - ListDto list, - CommentDto comment, - ReplyDto reply + @Nullable ListDto list, + @Nullable CommentDto comment, + @Nullable ReplyDto reply, + @Nullable NoticeDto notice ) { public static List toList(List alarms) { @@ -34,6 +37,7 @@ public static List toList(List alarms) { .list(ListDto.of(alarm.getList())) .comment(CommentDto.of(alarm.getComment())) .reply(ReplyDto.of(alarm.getReply())) + .notice(NoticeDto.of(alarm.getNotice())) .build() ).toList(); } @@ -54,7 +58,7 @@ public record ListDto( String title ) { - public static ListDto of(ListEntity list) { + public static ListDto of(@Nullable ListEntity list) { if (list == null) { return null; } @@ -68,7 +72,7 @@ public record CommentDto( List mentions ) { - public static CommentDto of(Comment comment) { + public static CommentDto of(@Nullable Comment comment) { if (comment == null) { return null; } @@ -82,7 +86,7 @@ public record ReplyDto( List mentions ) { - public static ReplyDto of(Reply reply) { + public static ReplyDto of(@Nullable Reply reply) { if (reply == null) { return null; } @@ -105,5 +109,28 @@ public static List toList(List mentions) { } } - // TODO: notice + @Builder + public record NoticeDto( + Long id, + String categoryCode, + String categoryViewName, + String title, + String description, + LocalDateTime createdDate + ) { + + public static NoticeDto of(@Nullable Notice notice) { + if (notice == null) { + return null; + } + return NoticeDto.builder() + .id(notice.getId()) + .categoryCode(String.valueOf(notice.getType().getCode())) + .categoryViewName(notice.getType().getViewName()) + .title(notice.getTitle().getValue()) + .description(notice.getDescription().getValue()) + .createdDate(notice.getCreatedDate()) + .build(); + } + } } diff --git a/src/main/java/com/listywave/alarm/application/service/AlarmService.java b/src/main/java/com/listywave/alarm/application/service/AlarmService.java index 73e351ed..a642b73b 100644 --- a/src/main/java/com/listywave/alarm/application/service/AlarmService.java +++ b/src/main/java/com/listywave/alarm/application/service/AlarmService.java @@ -2,6 +2,7 @@ import static com.listywave.alarm.application.domain.AlarmType.COMMENT; import static com.listywave.alarm.application.domain.AlarmType.MENTION; +import static com.listywave.alarm.application.domain.AlarmType.NOTICE; import static com.listywave.alarm.application.domain.AlarmType.REPLY; import static org.springframework.transaction.annotation.Propagation.REQUIRED; import static org.springframework.transaction.annotation.Propagation.REQUIRES_NEW; @@ -126,7 +127,7 @@ public void save(AlarmCreateEvent event) { @Transactional(readOnly = true) public List findAllBy(Long userId) { userRepository.getById(userId); - List alarms = alarmRepository.findAllBy(userId, LocalDateTime.now().minusDays(30)); + List alarms = alarmRepository.findAllBy(userId, LocalDateTime.now().minusDays(30), NOTICE); return AlarmFindResponse.toList(alarms); } diff --git a/src/main/java/com/listywave/alarm/repository/AlarmRepository.java b/src/main/java/com/listywave/alarm/repository/AlarmRepository.java index 72db3f75..c3abadd7 100644 --- a/src/main/java/com/listywave/alarm/repository/AlarmRepository.java +++ b/src/main/java/com/listywave/alarm/repository/AlarmRepository.java @@ -1,6 +1,7 @@ package com.listywave.alarm.repository; import com.listywave.alarm.application.domain.Alarm; +import com.listywave.alarm.application.domain.AlarmType; import com.listywave.alarm.repository.custom.CustomAlarmRepository; import com.listywave.common.exception.CustomException; import com.listywave.common.exception.ErrorCode; @@ -49,14 +50,13 @@ select case when count(*) > 0 then false else true end left join ListEntity l on a.list = l left join Comment c on a.comment = c left join Reply r on a.reply = r - where a.receiveUserId = :receiveUserId and a.createdDate >= :thirtyDaysAgo + left join Notice n on a.notice = n + where a.createdDate >= :thirtyDaysAgo and (a.receiveUserId = :receiveUserId or a.type = :type) order by a.createdDate desc """) - List findAllBy(Long receiveUserId, LocalDateTime thirtyDaysAgo); + List findAllBy(Long receiveUserId, LocalDateTime thirtyDaysAgo, AlarmType type); List findAllByReply(Reply reply); - void deleteByComment(Comment comment); - void deleteAllByCommentAndReceiveUserId(Comment comment, Long receiveUserId); } diff --git a/src/main/java/com/listywave/collection/application/domain/Folder.java b/src/main/java/com/listywave/collection/application/domain/Folder.java index 10f87a61..9cc308f6 100644 --- a/src/main/java/com/listywave/collection/application/domain/Folder.java +++ b/src/main/java/com/listywave/collection/application/domain/Folder.java @@ -1,5 +1,8 @@ package com.listywave.collection.application.domain; +import static com.listywave.common.exception.ErrorCode.INVALID_ACCESS; +import static lombok.AccessLevel.PROTECTED; + import com.listywave.common.BaseEntity; import com.listywave.common.exception.CustomException; import jakarta.persistence.Column; @@ -10,9 +13,6 @@ import lombok.Getter; import lombok.NoArgsConstructor; -import static com.listywave.common.exception.ErrorCode.INVALID_ACCESS; -import static lombok.AccessLevel.PROTECTED; - @Entity @Getter @AllArgsConstructor diff --git a/src/main/java/com/listywave/collection/application/domain/FolderName.java b/src/main/java/com/listywave/collection/application/domain/FolderName.java index 9019e4be..64c22850 100644 --- a/src/main/java/com/listywave/collection/application/domain/FolderName.java +++ b/src/main/java/com/listywave/collection/application/domain/FolderName.java @@ -1,5 +1,7 @@ package com.listywave.collection.application.domain; +import static com.listywave.common.exception.ErrorCode.LENGTH_EXCEEDED_EXCEPTION; + import com.listywave.common.exception.CustomException; import jakarta.persistence.Column; import jakarta.persistence.Embeddable; @@ -8,8 +10,6 @@ import lombok.Getter; import lombok.NoArgsConstructor; -import static com.listywave.common.exception.ErrorCode.LENGTH_EXCEEDED_EXCEPTION; - @Getter @Embeddable @EqualsAndHashCode diff --git a/src/main/java/com/listywave/collection/application/dto/FindFolderResponse.java b/src/main/java/com/listywave/collection/application/dto/FindFolderResponse.java index 48491a48..6b0871fe 100644 --- a/src/main/java/com/listywave/collection/application/dto/FindFolderResponse.java +++ b/src/main/java/com/listywave/collection/application/dto/FindFolderResponse.java @@ -6,7 +6,7 @@ public record FindFolderResponse( List folders ) { - public static FindFolderResponse of(List list){ + public static FindFolderResponse of(List list) { return new FindFolderResponse(list); } } diff --git a/src/main/java/com/listywave/collection/presentation/dto/FolderCreateRequest.java b/src/main/java/com/listywave/collection/presentation/dto/FolderCreateRequest.java index 7e7b1070..592b35df 100644 --- a/src/main/java/com/listywave/collection/presentation/dto/FolderCreateRequest.java +++ b/src/main/java/com/listywave/collection/presentation/dto/FolderCreateRequest.java @@ -1,6 +1,6 @@ package com.listywave.collection.presentation.dto; public record FolderCreateRequest( - String folderName + String folderName ) { } diff --git a/src/main/java/com/listywave/collection/presentation/dto/FolderUpdateRequest.java b/src/main/java/com/listywave/collection/presentation/dto/FolderUpdateRequest.java index 5e21dd58..05d1023a 100644 --- a/src/main/java/com/listywave/collection/presentation/dto/FolderUpdateRequest.java +++ b/src/main/java/com/listywave/collection/presentation/dto/FolderUpdateRequest.java @@ -1,6 +1,6 @@ package com.listywave.collection.presentation.dto; public record FolderUpdateRequest( - String folderName + String folderName ) { } diff --git a/src/main/java/com/listywave/collection/repository/CollectionRepository.java b/src/main/java/com/listywave/collection/repository/CollectionRepository.java index d87c5ee9..104aa83f 100644 --- a/src/main/java/com/listywave/collection/repository/CollectionRepository.java +++ b/src/main/java/com/listywave/collection/repository/CollectionRepository.java @@ -4,11 +4,11 @@ import com.listywave.collection.application.domain.Folder; import com.listywave.collection.repository.custom.CustomCollectionRepository; import com.listywave.list.application.domain.list.ListEntity; +import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import java.util.List; public interface CollectionRepository extends JpaRepository, CustomCollectionRepository { diff --git a/src/main/java/com/listywave/collection/repository/custom/CustomFolderRepository.java b/src/main/java/com/listywave/collection/repository/custom/CustomFolderRepository.java index 7079829f..b7cfb874 100644 --- a/src/main/java/com/listywave/collection/repository/custom/CustomFolderRepository.java +++ b/src/main/java/com/listywave/collection/repository/custom/CustomFolderRepository.java @@ -1,7 +1,6 @@ package com.listywave.collection.repository.custom; import com.listywave.collection.application.dto.FolderResponse; - import java.util.List; public interface CustomFolderRepository { diff --git a/src/main/java/com/listywave/collection/repository/custom/impl/CustomFolderRepositoryImpl.java b/src/main/java/com/listywave/collection/repository/custom/impl/CustomFolderRepositoryImpl.java index 8eb66424..10da21b2 100644 --- a/src/main/java/com/listywave/collection/repository/custom/impl/CustomFolderRepositoryImpl.java +++ b/src/main/java/com/listywave/collection/repository/custom/impl/CustomFolderRepositoryImpl.java @@ -1,8 +1,8 @@ package com.listywave.collection.repository.custom.impl; -import static com.listywave.collection.application.domain.QCollect.*; -import static com.listywave.collection.application.domain.QFolder.*; -import static com.querydsl.jpa.JPAExpressions.*; +import static com.listywave.collection.application.domain.QCollect.collect; +import static com.listywave.collection.application.domain.QFolder.folder; +import static com.querydsl.jpa.JPAExpressions.select; import com.listywave.collection.application.dto.FolderResponse; import com.listywave.collection.repository.custom.CustomFolderRepository; @@ -11,8 +11,8 @@ import com.querydsl.core.types.dsl.Expressions; import com.querydsl.core.types.dsl.NumberPath; import com.querydsl.jpa.impl.JPAQueryFactory; -import lombok.RequiredArgsConstructor; import java.util.List; +import lombok.RequiredArgsConstructor; @RequiredArgsConstructor public class CustomFolderRepositoryImpl implements CustomFolderRepository { diff --git a/src/main/java/com/listywave/common/exception/CustomException.java b/src/main/java/com/listywave/common/exception/CustomException.java index 3d72a463..2c9c6004 100644 --- a/src/main/java/com/listywave/common/exception/CustomException.java +++ b/src/main/java/com/listywave/common/exception/CustomException.java @@ -1,14 +1,17 @@ package com.listywave.common.exception; -import lombok.AllArgsConstructor; import lombok.Getter; @Getter -@AllArgsConstructor public class CustomException extends RuntimeException { private final ErrorCode errorCode; + public CustomException(ErrorCode errorCode) { + super(errorCode.getDetail()); + this.errorCode = errorCode; + } + public CustomException(ErrorCode errorCode, String message) { super(message); this.errorCode = errorCode; diff --git a/src/main/java/com/listywave/common/exception/ErrorCode.java b/src/main/java/com/listywave/common/exception/ErrorCode.java index 4e429d42..385b7daa 100644 --- a/src/main/java/com/listywave/common/exception/ErrorCode.java +++ b/src/main/java/com/listywave/common/exception/ErrorCode.java @@ -46,6 +46,7 @@ public enum ErrorCode { DUPLICATE_FOLDER_NAME_EXCEPTION(BAD_REQUEST, "중복된 폴더명입니다."), NULL_OR_BLANK_EXCEPTION(BAD_REQUEST, "값이 null이거나 공백일 수 없습니다."), NOT_EXIST_CODE(BAD_REQUEST, "존재하지 않는 코드입니다."), + ALREADY_SENT_ALARM_NOTICE(BAD_REQUEST, "이미 발송된 공지입니다."), // S3 S3_DELETE_OBJECTS_EXCEPTION(INTERNAL_SERVER_ERROR, "S3의 이미지를 삭제 요청하는 과정에서 에러가 발생했습니다."), diff --git a/src/main/java/com/listywave/list/application/dto/response/RecommendedListResponse.java b/src/main/java/com/listywave/list/application/dto/response/RecommendedListResponse.java index 68fce2a7..a076d627 100644 --- a/src/main/java/com/listywave/list/application/dto/response/RecommendedListResponse.java +++ b/src/main/java/com/listywave/list/application/dto/response/RecommendedListResponse.java @@ -2,9 +2,8 @@ import com.listywave.list.application.domain.item.Item; import com.listywave.list.application.domain.list.ListEntity; -import lombok.Builder; - import java.util.List; +import lombok.Builder; @Builder public record RecommendedListResponse( diff --git a/src/main/java/com/listywave/notice/application/domain/Notice.java b/src/main/java/com/listywave/notice/application/domain/Notice.java index 56bc399f..b48c0d73 100644 --- a/src/main/java/com/listywave/notice/application/domain/Notice.java +++ b/src/main/java/com/listywave/notice/application/domain/Notice.java @@ -1,10 +1,12 @@ package com.listywave.notice.application.domain; +import static com.listywave.common.exception.ErrorCode.ALREADY_SENT_ALARM_NOTICE; import static jakarta.persistence.CascadeType.ALL; import static jakarta.persistence.FetchType.LAZY; import static lombok.AccessLevel.PROTECTED; import com.listywave.common.BaseEntity; +import com.listywave.common.exception.CustomException; import jakarta.persistence.Column; import jakarta.persistence.Embedded; import jakarta.persistence.Entity; @@ -67,4 +69,11 @@ public void update(NoticeType type, NoticeTitle title, NoticeDescription descrip public void changeExposure() { this.isExposed = !this.isExposed; } + + public void sendAlarm() { + if (this.didSendAlarm) { + throw new CustomException(ALREADY_SENT_ALARM_NOTICE); + } + this.didSendAlarm = true; + } } diff --git a/src/main/java/com/listywave/notice/application/service/NoticeService.java b/src/main/java/com/listywave/notice/application/service/NoticeService.java index d67fd331..49ebc814 100644 --- a/src/main/java/com/listywave/notice/application/service/NoticeService.java +++ b/src/main/java/com/listywave/notice/application/service/NoticeService.java @@ -1,5 +1,6 @@ package com.listywave.notice.application.service; +import com.listywave.alarm.application.domain.AlarmCreateEvent; import com.listywave.notice.application.domain.Notice; import com.listywave.notice.application.domain.NoticeContent; import com.listywave.notice.application.domain.NoticeDescription; @@ -11,8 +12,11 @@ import com.listywave.notice.application.service.dto.NoticeFindResponse; import com.listywave.notice.application.service.dto.NoticeUpdateRequest; import com.listywave.notice.repository.NoticeRepository; +import com.listywave.user.application.domain.User; +import com.listywave.user.repository.user.UserRepository; import java.util.List; import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -21,7 +25,11 @@ @RequiredArgsConstructor public class NoticeService { + private static final String OFFICIAL_USER_NICKNAME = "ListyWave"; + + private final UserRepository userRepository; private final NoticeRepository noticeRepository; + private final ApplicationEventPublisher applicationEventPublisher; public Long create(NoticeCreateRequest request) { Notice notice = request.toNotice(); @@ -70,4 +78,13 @@ public void updateExposure(Long id) { public void delete(Long id) { noticeRepository.deleteById(id); } + + public void sendAlarm(Long id) { + User officialUser = userRepository.findByNicknameValue(OFFICIAL_USER_NICKNAME); + Notice notice = noticeRepository.getById(id); + notice.sendAlarm(); + + AlarmCreateEvent event = AlarmCreateEvent.notice(officialUser, notice); + applicationEventPublisher.publishEvent(event); + } } diff --git a/src/main/java/com/listywave/notice/presentation/NoticeController.java b/src/main/java/com/listywave/notice/presentation/NoticeController.java index f7fa8ff1..fa60e37f 100644 --- a/src/main/java/com/listywave/notice/presentation/NoticeController.java +++ b/src/main/java/com/listywave/notice/presentation/NoticeController.java @@ -76,4 +76,10 @@ ResponseEntity delete(@PathVariable Long noticeId) { noticeService.delete(noticeId); return ResponseEntity.noContent().build(); } + + @PostMapping("/admin/notices/{noticeId}/alarm") + ResponseEntity sendAlarm(@PathVariable Long noticeId) { + noticeService.sendAlarm(noticeId); + return ResponseEntity.noContent().build(); + } } diff --git a/src/main/java/com/listywave/user/application/service/UserService.java b/src/main/java/com/listywave/user/application/service/UserService.java index 2367562b..e6e92535 100644 --- a/src/main/java/com/listywave/user/application/service/UserService.java +++ b/src/main/java/com/listywave/user/application/service/UserService.java @@ -11,9 +11,9 @@ import com.listywave.user.application.domain.User; import com.listywave.user.application.dto.FollowersResponse; import com.listywave.user.application.dto.FollowingsResponse; -import com.listywave.user.application.dto.UsersRecommendedResponse; import com.listywave.user.application.dto.UserInfoResponse; import com.listywave.user.application.dto.UserProflieUpdateCommand; +import com.listywave.user.application.dto.UsersRecommendedResponse; import com.listywave.user.application.dto.search.UserElasticSearchResponse; import com.listywave.user.application.dto.search.UserSearchResponse; import com.listywave.user.application.dto.search.UserSearchResult; @@ -122,7 +122,7 @@ public FollowersResponse getFollowers(Long userId, Pageable pageable, String sea @Transactional(readOnly = true) public List getRecommendedUsers(Long loginUserId) { - if(loginUserId == null){ + if (loginUserId == null) { List recommendUsers = userRepository.getRecommendUsers(List.of(), null); return toUsersRecommendedResponse(recommendUsers); } diff --git a/src/main/java/com/listywave/user/application/vo/Nickname.java b/src/main/java/com/listywave/user/application/vo/Nickname.java index 7cd7e0c6..b485b755 100644 --- a/src/main/java/com/listywave/user/application/vo/Nickname.java +++ b/src/main/java/com/listywave/user/application/vo/Nickname.java @@ -24,7 +24,7 @@ public class Nickname { private static final int LENGTH_LIMIT = 10; private static final Set BLACK_LIST = Set.of( "운영자", "관리자", "admin", "listy", "L1sty", "에잇", "eight", "리스티", "관리인", "운영인", "관ㄹi자", "관ㄹl자", - "관ㄹI자", "관리ㅈr", "운영ㅈr", "관ㄹ1자", "adm1n", "관리요원" + "관ㄹI자", "관리ㅈr", "운영ㅈr", "관ㄹ1자", "adm1n", "관리요원", "공식계정", "official", "Official" ); @Column(name = "nickname", unique = true, length = LENGTH_LIMIT, nullable = false) diff --git a/src/main/java/com/listywave/user/presentation/UserController.java b/src/main/java/com/listywave/user/presentation/UserController.java index f5dd6989..54b9be2d 100644 --- a/src/main/java/com/listywave/user/presentation/UserController.java +++ b/src/main/java/com/listywave/user/presentation/UserController.java @@ -15,7 +15,14 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.web.PageableDefault; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +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.RequestParam; +import org.springframework.web.bind.annotation.RestController; @RestController @RequiredArgsConstructor diff --git a/src/main/java/com/listywave/user/repository/user/UserRepository.java b/src/main/java/com/listywave/user/repository/user/UserRepository.java index 1924a869..c7c33226 100644 --- a/src/main/java/com/listywave/user/repository/user/UserRepository.java +++ b/src/main/java/com/listywave/user/repository/user/UserRepository.java @@ -36,4 +36,6 @@ default User getById(Long id) { where u.isDelete = false """) List findAll(); + + User findByNicknameValue(String nickname); } diff --git a/src/test/java/com/listywave/acceptance/collection/CollectionAcceptanceTestHelper.java b/src/test/java/com/listywave/acceptance/collection/CollectionAcceptanceTestHelper.java index 0b810503..1293e75e 100644 --- a/src/test/java/com/listywave/acceptance/collection/CollectionAcceptanceTestHelper.java +++ b/src/test/java/com/listywave/acceptance/collection/CollectionAcceptanceTestHelper.java @@ -1,12 +1,12 @@ package com.listywave.acceptance.collection; +import static com.listywave.acceptance.common.CommonAcceptanceHelper.given; +import static org.springframework.http.HttpHeaders.AUTHORIZATION; + import com.listywave.collection.presentation.dto.FolderSelectionRequest; import io.restassured.response.ExtractableResponse; import io.restassured.response.Response; -import static com.listywave.acceptance.common.CommonAcceptanceHelper.given; -import static org.springframework.http.HttpHeaders.AUTHORIZATION; - public abstract class CollectionAcceptanceTestHelper { public static ExtractableResponse 콜렉트_또는_콜렉트취소_API_호출(String accessToken, Long listId, FolderSelectionRequest request) { diff --git a/src/test/java/com/listywave/acceptance/common/DatabaseCleaner.java b/src/test/java/com/listywave/acceptance/common/DatabaseCleaner.java index cc9aa9c4..cf39d3a5 100644 --- a/src/test/java/com/listywave/acceptance/common/DatabaseCleaner.java +++ b/src/test/java/com/listywave/acceptance/common/DatabaseCleaner.java @@ -14,7 +14,7 @@ public DatabaseCleaner(JdbcTemplate jdbcTemplate) { SELECT Concat('TRUNCATE TABLE ', TABLE_NAME, ';') AS query FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'PUBLIC' - """, String.class + """, String.class ); } diff --git a/src/test/java/com/listywave/acceptance/folder/FolderAcceptanceTest.java b/src/test/java/com/listywave/acceptance/folder/FolderAcceptanceTest.java index 5bd40897..fe27892e 100644 --- a/src/test/java/com/listywave/acceptance/folder/FolderAcceptanceTest.java +++ b/src/test/java/com/listywave/acceptance/folder/FolderAcceptanceTest.java @@ -1,25 +1,35 @@ package com.listywave.acceptance.folder; -import com.listywave.acceptance.common.AcceptanceTest; -import com.listywave.collection.application.dto.FindFolderResponse; -import com.listywave.collection.application.dto.FolderCreateResponse; -import com.listywave.list.application.dto.response.ListCreateResponse; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; - -import java.util.List; - import static com.listywave.acceptance.collection.CollectionAcceptanceTestHelper.콜렉트_또는_콜렉트취소_API_호출; import static com.listywave.acceptance.common.CommonAcceptanceHelper.HTTP_상태_코드를_검증한다; -import static com.listywave.acceptance.folder.FolderAcceptanceTestHelper.*; -import static com.listywave.acceptance.list.ListAcceptanceTestHelper.*; +import static com.listywave.acceptance.folder.FolderAcceptanceTestHelper.폴더_삭제_API_호출; +import static com.listywave.acceptance.folder.FolderAcceptanceTestHelper.폴더_생성_API_호출; +import static com.listywave.acceptance.folder.FolderAcceptanceTestHelper.폴더_생성_요청_데이터; +import static com.listywave.acceptance.folder.FolderAcceptanceTestHelper.폴더_선택_요청_데이터; +import static com.listywave.acceptance.folder.FolderAcceptanceTestHelper.폴더_수정_API_호출; +import static com.listywave.acceptance.folder.FolderAcceptanceTestHelper.폴더_수정_요청_데이터; +import static com.listywave.acceptance.folder.FolderAcceptanceTestHelper.폴더_조회_API_호출; +import static com.listywave.acceptance.list.ListAcceptanceTestHelper.가장_좋아하는_견종_TOP3_생성_요청_데이터; +import static com.listywave.acceptance.list.ListAcceptanceTestHelper.리스트_저장_API_호출; +import static com.listywave.acceptance.list.ListAcceptanceTestHelper.회원용_리스트_상세_조회_API_호출; import static com.listywave.list.fixture.ListFixture.지정된_개수만큼_리스트를_생성한다; import static com.listywave.user.fixture.UserFixture.동호; import static com.listywave.user.fixture.UserFixture.정수; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; -import static org.springframework.http.HttpStatus.*; +import static org.springframework.http.HttpStatus.BAD_REQUEST; +import static org.springframework.http.HttpStatus.CREATED; +import static org.springframework.http.HttpStatus.FORBIDDEN; +import static org.springframework.http.HttpStatus.NO_CONTENT; + +import com.listywave.acceptance.common.AcceptanceTest; +import com.listywave.collection.application.dto.FindFolderResponse; +import com.listywave.collection.application.dto.FolderCreateResponse; +import com.listywave.list.application.dto.response.ListCreateResponse; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; @DisplayName("폴더 관련 인수테스트") public class FolderAcceptanceTest extends AcceptanceTest { diff --git a/src/test/java/com/listywave/acceptance/folder/FolderAcceptanceTestHelper.java b/src/test/java/com/listywave/acceptance/folder/FolderAcceptanceTestHelper.java index cf0319a5..790a5bf4 100644 --- a/src/test/java/com/listywave/acceptance/folder/FolderAcceptanceTestHelper.java +++ b/src/test/java/com/listywave/acceptance/folder/FolderAcceptanceTestHelper.java @@ -1,14 +1,14 @@ package com.listywave.acceptance.folder; +import static com.listywave.acceptance.common.CommonAcceptanceHelper.given; +import static org.springframework.http.HttpHeaders.AUTHORIZATION; + import com.listywave.collection.presentation.dto.FolderCreateRequest; import com.listywave.collection.presentation.dto.FolderSelectionRequest; import com.listywave.collection.presentation.dto.FolderUpdateRequest; import io.restassured.response.ExtractableResponse; import io.restassured.response.Response; -import static com.listywave.acceptance.common.CommonAcceptanceHelper.given; -import static org.springframework.http.HttpHeaders.AUTHORIZATION; - public abstract class FolderAcceptanceTestHelper { public static ExtractableResponse 폴더_생성_API_호출(String accessToken, FolderCreateRequest request) { diff --git a/src/test/java/com/listywave/alarm/AlarmServiceTest.java b/src/test/java/com/listywave/alarm/AlarmServiceTest.java index b4a89589..78747612 100644 --- a/src/test/java/com/listywave/alarm/AlarmServiceTest.java +++ b/src/test/java/com/listywave/alarm/AlarmServiceTest.java @@ -4,15 +4,23 @@ import static com.listywave.alarm.application.domain.AlarmType.COMMENT; import static com.listywave.alarm.application.domain.AlarmType.FOLLOW; import static com.listywave.alarm.application.domain.AlarmType.MENTION; +import static com.listywave.alarm.application.domain.AlarmType.NOTICE; import static com.listywave.alarm.application.domain.AlarmType.REPLY; +import static com.listywave.common.exception.ErrorCode.ALREADY_SENT_ALARM_NOTICE; import static java.util.Collections.EMPTY_LIST; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertThrows; +import com.listywave.alarm.application.domain.AlarmCreateEvent; import com.listywave.alarm.application.dto.AlarmCheckResponse; import com.listywave.alarm.application.dto.AlarmFindResponse; import com.listywave.common.IntegrationTest; +import com.listywave.common.exception.CustomException; +import com.listywave.common.exception.ErrorCode; import com.listywave.list.application.dto.ReplyDeleteCommand; +import com.listywave.notice.application.domain.Notice; +import com.listywave.notice.application.service.dto.NoticeCreateRequest; import java.util.List; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Nested; @@ -254,6 +262,69 @@ class 팔로우 { assertThat(result.get(0).sendUser().id()).isEqualTo(js.getId()); } } + + @Nested + class 공지 { + + @Test + void 공지_알람을_발송한다() { + // given + NoticeCreateRequest noticeCreateRequest = createNoticeCreateRequest(); + Long noticeId = noticeService.create(noticeCreateRequest); + Notice notice = noticeRepository.getById(noticeId); + + // when + AlarmCreateEvent event = AlarmCreateEvent.notice(dh, notice); + alarmService.save(event); + + // then + List jsAlarms = alarmService.findAllBy(js.getId()); + List ejAlarms = alarmService.findAllBy(ej.getId()); + List syAlarms = alarmService.findAllBy(sy.getId()); + assertAll( + () -> assertThat(jsAlarms.size()).isEqualTo(ejAlarms.size()).isEqualTo(syAlarms.size()).isOne(), + () -> { + AlarmFindResponse jsAlarm = jsAlarms.get(0); + AlarmFindResponse ejAlarm = ejAlarms.get(0); + AlarmFindResponse syAlarm = syAlarms.get(0); + + assertThat(jsAlarm.type()).isEqualTo(ejAlarm.type()).isEqualTo(syAlarm.type()).isEqualTo(NOTICE.name()); + assertThat(jsAlarm.sendUser().nickname()).isEqualTo(ejAlarm.sendUser().nickname()).isEqualTo(syAlarm.sendUser().nickname()).isEqualTo(dh.getNickname()); + assertThat(jsAlarm.notice().title()).isEqualTo(ejAlarm.notice().title()).isEqualTo(syAlarm.notice().title()).isEqualTo("공지입니다"); + } + ); + } + + @Test + void 공지는_1개당_최대_1회만_알람을_보낼_수_있다() { + // given + NoticeCreateRequest noticeCreateRequest = createNoticeCreateRequest(); + Long noticeId = noticeService.create(noticeCreateRequest); + noticeService.sendAlarm(noticeId); + + // when + ErrorCode result = assertThrows(CustomException.class, () -> noticeService.sendAlarm(noticeId)) + .getErrorCode(); + + // then + assertThat(result).isEqualTo(ALREADY_SENT_ALARM_NOTICE); + } + + private NoticeCreateRequest createNoticeCreateRequest() { + return new NoticeCreateRequest( + 1, + "공지입니다", + "공지에요", + List.of( + new NoticeCreateRequest.ContentDto(1, "subtitle", "소제목입니다", null, null, null), + new NoticeCreateRequest.ContentDto(2, "body", "본문입니다", null, null, null), + new NoticeCreateRequest.ContentDto(3, "image", "이미지입니다", "https://image.com", null, null), + new NoticeCreateRequest.ContentDto(4, "button", "버튼입니다", null, "버튼 이름", "https://buttonLink.com"), + new NoticeCreateRequest.ContentDto(5, "note", "유의사항입니다", null, null, null) + ) + ); + } + } } @Nested @@ -266,9 +337,6 @@ class 알람_조회 { commentService.create(list.getId(), ej.getId(), "유진 댓글", EMPTY_LIST); commentService.create(list.getId(), sy.getId(), "서영 댓글", EMPTY_LIST); - // when - //commit(); - // then List result = alarmService.findAllBy(dh.getId()); assertThat(result.get(0).sendUser().id()).isEqualTo(sy.getId()); @@ -284,7 +352,6 @@ class 알람_읽기 { void 알람을_읽기_처리한다() { // when commentService.create(list.getId(), js.getId(), "댓글~!", EMPTY_LIST); - //commit(); // when AlarmFindResponse alarm = alarmService.findAllBy(dh.getId()).get(0); @@ -300,7 +367,6 @@ class 알람_읽기 { void 신규_알람_조회_시에_읽지_않은_알람이_있는_경우_true를_반환한다() { // when commentService.create(list.getId(), js.getId(), "댓글~!", EMPTY_LIST); - //commit(); AlarmFindResponse dhAlarm = alarmService.findAllBy(dh.getId()).get(0); alarmService.check(dhAlarm.id()); @@ -316,7 +382,6 @@ class 알람_읽기 { void 신규_알람_조회_시에_읽지_않은_알람이_없는_경우_false를_반환한다() { // when commentService.create(list.getId(), js.getId(), "댓글~!", EMPTY_LIST); - //commit(); // when AlarmCheckResponse result = alarmService.isAllChecked(dh.getId()); @@ -332,8 +397,6 @@ class 알람_읽기 { commentService.create(list.getId(), ej.getId(), "유진 댓글", EMPTY_LIST); commentService.create(list.getId(), sy.getId(), "서영 댓글", EMPTY_LIST); - //commit(); - assertThat(alarmService.isAllChecked(dh.getId()).isAllChecked()).isFalse(); // when @@ -350,11 +413,7 @@ class 알람_삭제 { @Test @Disabled void _30일이_지난_알람은_자동_삭제된다() { - // when - - // when - - // then + // TODO: 테스트 작성 } @Test diff --git a/src/test/java/com/listywave/collection/application/domain/FolderNameTest.java b/src/test/java/com/listywave/collection/application/domain/FolderNameTest.java index 0b67c2cb..732e3d3a 100644 --- a/src/test/java/com/listywave/collection/application/domain/FolderNameTest.java +++ b/src/test/java/com/listywave/collection/application/domain/FolderNameTest.java @@ -2,13 +2,13 @@ import static com.listywave.common.exception.ErrorCode.LENGTH_EXCEEDED_EXCEPTION; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertThrows; import com.listywave.common.exception.CustomException; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; import java.util.stream.Collectors; import java.util.stream.IntStream; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; @DisplayName("FolderName은 ") class FolderNameTest { diff --git a/src/test/java/com/listywave/collection/application/domain/FolderTest.java b/src/test/java/com/listywave/collection/application/domain/FolderTest.java index 92686045..6c933540 100644 --- a/src/test/java/com/listywave/collection/application/domain/FolderTest.java +++ b/src/test/java/com/listywave/collection/application/domain/FolderTest.java @@ -1,10 +1,5 @@ package com.listywave.collection.application.domain; -import com.listywave.common.exception.CustomException; -import com.listywave.user.application.domain.User; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - import static com.listywave.common.exception.ErrorCode.INVALID_ACCESS; import static com.listywave.user.fixture.UserFixture.동호; import static com.listywave.user.fixture.UserFixture.정수; @@ -12,6 +7,11 @@ import static org.assertj.core.api.Assertions.assertThatNoException; import static org.junit.jupiter.api.Assertions.assertThrows; +import com.listywave.common.exception.CustomException; +import com.listywave.user.application.domain.User; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + @DisplayName("Folder는 ") class FolderTest { diff --git a/src/test/java/com/listywave/common/IntegrationTest.java b/src/test/java/com/listywave/common/IntegrationTest.java index 56ce1507..b6c66878 100644 --- a/src/test/java/com/listywave/common/IntegrationTest.java +++ b/src/test/java/com/listywave/common/IntegrationTest.java @@ -105,6 +105,7 @@ public abstract class IntegrationTest { @BeforeEach void setUp() { + alarmRepository.deleteAllInBatch(); noticeRepository.deleteAll(); adminRepository.deleteAllInBatch(); historyRepository.deleteAll(); @@ -113,7 +114,6 @@ void setUp() { topicRepository.deleteAllInBatch(); followRepository.deleteAllInBatch(); collectionRepository.deleteAllInBatch(); - alarmRepository.deleteAllInBatch(); mentionRepository.deleteAllInBatch(); replyRepository.deleteAllInBatch(); commentRepository.deleteAllInBatch();