From 5a09934866e18e2cb1e43889283c31b9220adf56 Mon Sep 17 00:00:00 2001 From: Tim <135014430+nagisa77@users.noreply.github.com> Date: Sun, 31 Aug 2025 01:49:37 +0800 Subject: [PATCH] refactor poll and lottery forms, add poll notifications --- .../openisle/controller/PostController.java | 2 +- .../main/java/com/openisle/dto/PollDto.java | 1 - .../java/com/openisle/dto/PostRequest.java | 1 - .../java/com/openisle/mapper/PostMapper.java | 1 - .../com/openisle/model/NotificationType.java | 6 + .../java/com/openisle/model/PollPost.java | 7 +- .../repository/PollPostRepository.java | 6 + .../com/openisle/service/PostService.java | 40 +- .../controller/PostControllerTest.java | 4 +- .../com/openisle/service/PostServiceTest.java | 2 +- frontend_nuxt/components/LotteryForm.vue | 189 ++++++++++ frontend_nuxt/components/PollForm.vue | 90 +++++ frontend_nuxt/pages/message.vue | 38 ++ frontend_nuxt/pages/new-post.vue | 353 +++--------------- frontend_nuxt/utils/notification.js | 18 + 15 files changed, 442 insertions(+), 316 deletions(-) create mode 100644 frontend_nuxt/components/LotteryForm.vue create mode 100644 frontend_nuxt/components/PollForm.vue diff --git a/backend/src/main/java/com/openisle/controller/PostController.java b/backend/src/main/java/com/openisle/controller/PostController.java index 90c892834..92981bb3f 100644 --- a/backend/src/main/java/com/openisle/controller/PostController.java +++ b/backend/src/main/java/com/openisle/controller/PostController.java @@ -44,7 +44,7 @@ public class PostController { req.getType(), req.getPrizeDescription(), req.getPrizeIcon(), req.getPrizeCount(), req.getPointCost(), req.getStartTime(), req.getEndTime(), - req.getQuestion(), req.getOptions()); + req.getOptions()); draftService.deleteDraft(auth.getName()); PostDetailDto dto = postMapper.toDetailDto(post, auth.getName()); dto.setReward(levelService.awardForPost(auth.getName())); diff --git a/backend/src/main/java/com/openisle/dto/PollDto.java b/backend/src/main/java/com/openisle/dto/PollDto.java index 04e80915e..889b7a5c9 100644 --- a/backend/src/main/java/com/openisle/dto/PollDto.java +++ b/backend/src/main/java/com/openisle/dto/PollDto.java @@ -8,7 +8,6 @@ import java.util.Map; @Data public class PollDto { - private String question; private List options; private Map votes; private LocalDateTime endTime; diff --git a/backend/src/main/java/com/openisle/dto/PostRequest.java b/backend/src/main/java/com/openisle/dto/PostRequest.java index 7e6619e2a..cd48888fc 100644 --- a/backend/src/main/java/com/openisle/dto/PostRequest.java +++ b/backend/src/main/java/com/openisle/dto/PostRequest.java @@ -27,7 +27,6 @@ public class PostRequest { private LocalDateTime startTime; private LocalDateTime endTime; // fields for poll posts - private String question; private List options; } diff --git a/backend/src/main/java/com/openisle/mapper/PostMapper.java b/backend/src/main/java/com/openisle/mapper/PostMapper.java index 49d0ccb7d..8c8bd223b 100644 --- a/backend/src/main/java/com/openisle/mapper/PostMapper.java +++ b/backend/src/main/java/com/openisle/mapper/PostMapper.java @@ -103,7 +103,6 @@ public class PostMapper { if (post instanceof PollPost pp) { PollDto p = new PollDto(); - p.setQuestion(pp.getQuestion()); p.setOptions(pp.getOptions()); p.setVotes(pp.getVotes()); p.setEndTime(pp.getEndTime()); diff --git a/backend/src/main/java/com/openisle/model/NotificationType.java b/backend/src/main/java/com/openisle/model/NotificationType.java index c4b4e0e25..ccfd57eb7 100644 --- a/backend/src/main/java/com/openisle/model/NotificationType.java +++ b/backend/src/main/java/com/openisle/model/NotificationType.java @@ -40,6 +40,12 @@ public enum NotificationType { LOTTERY_WIN, /** Your lottery post was drawn */ LOTTERY_DRAW, + /** Someone participated in your poll */ + POLL_VOTE, + /** Your poll post has concluded */ + POLL_RESULT_OWNER, + /** A poll you participated in has concluded */ + POLL_RESULT_PARTICIPANT, /** Your post was featured */ POST_FEATURED, /** You were mentioned in a post or comment */ diff --git a/backend/src/main/java/com/openisle/model/PollPost.java b/backend/src/main/java/com/openisle/model/PollPost.java index c19978c21..c9a5363f1 100644 --- a/backend/src/main/java/com/openisle/model/PollPost.java +++ b/backend/src/main/java/com/openisle/model/PollPost.java @@ -15,10 +15,6 @@ import java.util.*; @NoArgsConstructor @PrimaryKeyJoinColumn(name = "post_id") public class PollPost extends Post { - - @Column(nullable = false) - private String question; - @ElementCollection @CollectionTable(name = "poll_post_options", joinColumns = @JoinColumn(name = "post_id")) @Column(name = "option_text") @@ -38,4 +34,7 @@ public class PollPost extends Post { @Column private LocalDateTime endTime; + + @Column + private boolean resultAnnounced = false; } diff --git a/backend/src/main/java/com/openisle/repository/PollPostRepository.java b/backend/src/main/java/com/openisle/repository/PollPostRepository.java index d0985fe4b..853009946 100644 --- a/backend/src/main/java/com/openisle/repository/PollPostRepository.java +++ b/backend/src/main/java/com/openisle/repository/PollPostRepository.java @@ -3,5 +3,11 @@ package com.openisle.repository; import com.openisle.model.PollPost; import org.springframework.data.jpa.repository.JpaRepository; +import java.time.LocalDateTime; +import java.util.List; + public interface PollPostRepository extends JpaRepository { + List findByEndTimeAfterAndResultAnnouncedFalse(LocalDateTime now); + + List findByEndTimeBeforeAndResultAnnouncedFalse(LocalDateTime now); } diff --git a/backend/src/main/java/com/openisle/service/PostService.java b/backend/src/main/java/com/openisle/service/PostService.java index 59d00e4f6..76873f858 100644 --- a/backend/src/main/java/com/openisle/service/PostService.java +++ b/backend/src/main/java/com/openisle/service/PostService.java @@ -135,6 +135,15 @@ public class PostService { for (LotteryPost lp : lotteryPostRepository.findByEndTimeBeforeAndWinnersIsEmpty(now)) { applicationContext.getBean(PostService.class).finalizeLottery(lp.getId()); } + for (PollPost pp : pollPostRepository.findByEndTimeAfterAndResultAnnouncedFalse(now)) { + ScheduledFuture future = taskScheduler.schedule( + () -> applicationContext.getBean(PostService.class).finalizePoll(pp.getId()), + java.util.Date.from(pp.getEndTime().atZone(ZoneId.systemDefault()).toInstant())); + scheduledFinalizations.put(pp.getId(), future); + } + for (PollPost pp : pollPostRepository.findByEndTimeBeforeAndResultAnnouncedFalse(now)) { + applicationContext.getBean(PostService.class).finalizePoll(pp.getId()); + } } public PublishMode getPublishMode() { @@ -177,7 +186,6 @@ public class PostService { Integer pointCost, LocalDateTime startTime, LocalDateTime endTime, - String question, java.util.List options) { long recent = postRepository.countByAuthorAfter(username, java.time.LocalDateTime.now().minusMinutes(5)); @@ -217,7 +225,6 @@ public class PostService { throw new IllegalArgumentException("At least two options required"); } PollPost pp = new PollPost(); - pp.setQuestion(question); pp.setOptions(options); pp.setEndTime(endTime); post = pp; @@ -269,6 +276,11 @@ public class PostService { () -> applicationContext.getBean(PostService.class).finalizeLottery(lp.getId()), java.util.Date.from(lp.getEndTime().atZone(ZoneId.systemDefault()).toInstant())); scheduledFinalizations.put(lp.getId(), future); + } else if (post instanceof PollPost pp && pp.getEndTime() != null) { + ScheduledFuture future = taskScheduler.schedule( + () -> applicationContext.getBean(PostService.class).finalizePoll(pp.getId()), + java.util.Date.from(pp.getEndTime().atZone(ZoneId.systemDefault()).toInstant())); + scheduledFinalizations.put(pp.getId(), future); } return post; } @@ -311,7 +323,29 @@ public class PostService { vote.setUser(user); vote.setOptionIndex(optionIndex); pollVoteRepository.save(vote); - return pollPostRepository.save(post); + PollPost saved = pollPostRepository.save(post); + if (post.getAuthor() != null && !post.getAuthor().getId().equals(user.getId())) { + notificationService.createNotification(post.getAuthor(), NotificationType.POLL_VOTE, post, null, null, user, null, null); + } + return saved; + } + + @Transactional + public void finalizePoll(Long postId) { + scheduledFinalizations.remove(postId); + pollPostRepository.findById(postId).ifPresent(pp -> { + if (pp.isResultAnnounced()) { + return; + } + pp.setResultAnnounced(true); + pollPostRepository.save(pp); + if (pp.getAuthor() != null) { + notificationService.createNotification(pp.getAuthor(), NotificationType.POLL_RESULT_OWNER, pp, null, null, null, null, null); + } + for (User participant : pp.getParticipants()) { + notificationService.createNotification(participant, NotificationType.POLL_RESULT_PARTICIPANT, pp, null, null, null, null, null); + } + }); } @Transactional diff --git a/backend/src/test/java/com/openisle/controller/PostControllerTest.java b/backend/src/test/java/com/openisle/controller/PostControllerTest.java index 90779b57e..f55c2d497 100644 --- a/backend/src/test/java/com/openisle/controller/PostControllerTest.java +++ b/backend/src/test/java/com/openisle/controller/PostControllerTest.java @@ -76,7 +76,7 @@ class PostControllerTest { post.setTags(Set.of(tag)); when(postService.createPost(eq("alice"), eq(1L), eq("t"), eq("c"), eq(List.of(1L)), - isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull())).thenReturn(post); + isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull(), isNull())).thenReturn(post); when(postService.viewPost(eq(1L), any())).thenReturn(post); when(commentService.getCommentsForPost(eq(1L), any())).thenReturn(List.of()); when(commentService.getParticipants(anyLong(), anyInt())).thenReturn(List.of()); @@ -187,7 +187,7 @@ class PostControllerTest { .andExpect(status().isBadRequest()); verify(postService, never()).createPost(any(), any(), any(), any(), any(), - any(), any(), any(), any(), any(), any(), any()); + any(), any(), any(), any(), any(), any(), any(), any()); } @Test diff --git a/backend/src/test/java/com/openisle/service/PostServiceTest.java b/backend/src/test/java/com/openisle/service/PostServiceTest.java index a7bf71caa..f21155f35 100644 --- a/backend/src/test/java/com/openisle/service/PostServiceTest.java +++ b/backend/src/test/java/com/openisle/service/PostServiceTest.java @@ -146,7 +146,7 @@ class PostServiceTest { assertThrows(RateLimitException.class, () -> service.createPost("alice", 1L, "t", "c", List.of(1L), - null, null, null, null, null, null, null)); + null, null, null, null, null, null, null, null)); } @Test diff --git a/frontend_nuxt/components/LotteryForm.vue b/frontend_nuxt/components/LotteryForm.vue new file mode 100644 index 000000000..30bcdcd8b --- /dev/null +++ b/frontend_nuxt/components/LotteryForm.vue @@ -0,0 +1,189 @@ + + + + + diff --git a/frontend_nuxt/components/PollForm.vue b/frontend_nuxt/components/PollForm.vue new file mode 100644 index 000000000..fe8454505 --- /dev/null +++ b/frontend_nuxt/components/PollForm.vue @@ -0,0 +1,90 @@ + + + + + diff --git a/frontend_nuxt/pages/message.vue b/frontend_nuxt/pages/message.vue index 6da9ce0ef..29dd1b2c8 100644 --- a/frontend_nuxt/pages/message.vue +++ b/frontend_nuxt/pages/message.vue @@ -195,6 +195,44 @@ 已开奖 + + +