Skip to content

Commit

Permalink
Merge pull request #179 from FOREGG-DEV/dev
Browse files Browse the repository at this point in the history
✨[feat] 챌린지 찌르기 기능 생성
  • Loading branch information
DongJun1110 authored Nov 20, 2024
2 parents bf6d446 + 96b731a commit ea92885
Show file tree
Hide file tree
Showing 13 changed files with 212 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public enum ErrorStatus implements BaseErrorCode {


//챌린지 관련 에러
CHALLENGE_NOT_FOUND(BAD_REQUEST, "CHALLENGE4001", "존재하지 않는 챌린지입니다"),
CHALLENGE_NOT_FOUND(BAD_REQUEST, "CHALLENGE4002", "존재하지 않는 챌린지입니다"),
NOT_FOUND_MY_CHALLENGE(BAD_REQUEST, "CHALLENGE4002", "나의 챌린지가 존재하지 않습니다"),
NO_PARTICIPATING_CHALLENGE(BAD_REQUEST, "CHALLENGE4003", "참여하고 있는 챌린지가 아닙니다"),
ALREADY_PARTICIPATING(BAD_REQUEST, "CHALLENGE4004", "이미 참여하고 있는 챌린지입니다"),
Expand All @@ -62,6 +62,10 @@ public enum ErrorStatus implements BaseErrorCode {
ALREADY_OPEN(BAD_REQUEST, "CHALLENGE4010", "이미 오픈된 챌린지입니다"),
MAKE_NICKNAME_FIRST(BAD_REQUEST, "CHALLENGE4011", "챌린지 닉네임을 먼저 만들어주세요"),
OUT_OF_VALIDATE_DAYS(BAD_REQUEST, "CHALLENGE4012", "오늘, 어제 날짜 이외에는 챌린지 성공 할 수 없습니다"),
NO_MORE_THAN_THIRD_TIME(BAD_REQUEST, "CHALLENGE4013", "응원과 박수는 각각 하루에 세 번까지 가능합니다"),
ALREADY_SEND_CHEER(BAD_REQUEST, "CHALLENGE4014", "이미 오늘 찌르기를 한 유저입니다"),
UNABLE_TO_SEND_CLAP(BAD_REQUEST, "CHALLENGE4015", "성공하지 않은 유저에게는 박수를 보낼 수 없습니다"),
UNABLE_TO_SEND_SUPPORT(BAD_REQUEST, "CHALLENGE4016", "성공한 유저에게는 응원을 보낼 수 없습니다"),


//가계부 관련 에러
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package foregg.foreggserver.controller;

import foregg.foreggserver.apiPayload.ApiResponse;
import foregg.foreggserver.domain.enums.NotificationType;
import foregg.foreggserver.domain.enums.ChallengeSuccessDayType;
import foregg.foreggserver.dto.challengeDTO.ChallengeRequestDTO.ChallengeCreateRequestDTO;
import foregg.foreggserver.dto.challengeDTO.ChallengeRequestDTO.ChallengeNameRequestDTO;
import foregg.foreggserver.dto.challengeDTO.ChallengeResponseDTO;
import foregg.foreggserver.dto.challengeDTO.ChallengeResponseDTO.ChallengeCheerResponseDTO;
import foregg.foreggserver.dto.challengeDTO.ChallengeResponseDTO.MyChallengeDTO;
import foregg.foreggserver.service.challengeService.ChallengeQueryService;
import foregg.foreggserver.service.challengeService.ChallengeService;
Expand Down Expand Up @@ -179,4 +181,34 @@ public ApiResponse<String> getChallengeName() {
return ApiResponse.onSuccess(userQueryService.getChallengeName());
}

@Operation(summary = "챌린지 찌르기 리스트")
@GetMapping("{id}/participantsList")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "CHALLENGE4002", description = "존재하지 않는 챌린지입니다"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "CHALLENGE4003", description = "참여히고 있는 챌린지가 아닙니다")
})
public ApiResponse<List<ChallengeCheerResponseDTO>> getParticipantsList(@PathVariable(name = "id") Long id) {
List<ChallengeCheerResponseDTO> result = challengeQueryService.getParticipantsList(id);
return ApiResponse.onSuccess(result);
}

@Operation(summary = "챌린지 찌르기")
@PostMapping("{challengeId}")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "CHALLENGE4002", description = "존재하지 않는 챌린지입니다"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "CHALLENGE4003", description = "참여하고 있는 챌린지가 아닙니다"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "CHALLENGE4013", description = "응원과 박수는 각각 하루에 세 번까지 가능합니다"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "CHALLENGE4014", description = "이미 오늘 찌르기를 한 유저입니다"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "CHALLENGE4015", description = "성공하지 않은 유저에게는 박수를 보낼 수 없습니다"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "CHALLENGE4016", description = "성공한 유저에게는 응원을 보낼 수 없습니다"),
})
public ApiResponse<String> cheer(@PathVariable(name = "challengeId") Long challengeId,
@RequestParam(name = "cheerType") NotificationType cheerType,
@RequestParam(name = "receiverId") Long receiverId) {
challengeService.cheer(receiverId, cheerType, challengeId);
return ApiResponse.onSuccess();
}

}
24 changes: 15 additions & 9 deletions src/main/java/foregg/foreggserver/domain/Notification.java
Original file line number Diff line number Diff line change
@@ -1,31 +1,37 @@
package foregg.foreggserver.domain;

import foregg.foreggserver.domain.common.BaseEntity;
import foregg.foreggserver.domain.enums.NotifType;
import foregg.foreggserver.domain.enums.NotificationType;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@AllArgsConstructor
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Getter
public class Notification extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Enumerated(EnumType.STRING)
private NotifType notificationType;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "sender_id")
private User sender;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "receiver_id")
private User receiver;

@Column(nullable = false)
private String content;
private String date; // String -> LocalDateTime으로 변경

@Enumerated(EnumType.STRING)
private NotificationType notificationType;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
}

2 changes: 1 addition & 1 deletion src/main/java/foregg/foreggserver/domain/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public class User extends BaseEntity implements UserDetails {
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Schedule> schedules;

@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
@OneToMany(mappedBy = "receiver", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Notification> notifications;

@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
Expand Down
7 changes: 0 additions & 7 deletions src/main/java/foregg/foreggserver/domain/enums/NotifType.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package foregg.foreggserver.domain.enums;

public enum NotificationType {
CLAP, SUPPORT, REPLY
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,17 @@ public static class MyChallengeDTO {
private List<String> successDays;
}

@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static class ChallengeCheerResponseDTO {
private Long id;
private String challengeNickname;
private String thought;
private boolean success;
private boolean clap;
private boolean support;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package foregg.foreggserver.repository;

import foregg.foreggserver.domain.Notification;
import foregg.foreggserver.domain.User;
import foregg.foreggserver.domain.enums.NotificationType;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface NotificationRepository extends JpaRepository<Notification, Long> {

List<Notification> findBySenderAndReceiverAndDate(User sender, User receiver, String date);

Notification findBySenderAndReceiverAndDateAndNotificationType(User sender, User receiver, String date, NotificationType notificationType);

List<Notification> findBySenderAndDateAndNotificationType(User sender, String date, NotificationType notificationType);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
import foregg.foreggserver.converter.ChallengeConverter;
import foregg.foreggserver.domain.Challenge;
import foregg.foreggserver.domain.ChallengeParticipation;
import foregg.foreggserver.domain.Notification;
import foregg.foreggserver.domain.User;
import foregg.foreggserver.dto.challengeDTO.ChallengeMyResponseDTO;
import foregg.foreggserver.domain.enums.NotificationType;
import foregg.foreggserver.dto.challengeDTO.ChallengeResponseDTO;
import foregg.foreggserver.dto.challengeDTO.ChallengeResponseDTO.ChallengeCheerResponseDTO;
import foregg.foreggserver.dto.challengeDTO.ChallengeResponseDTO.ChallengeDTO;
import foregg.foreggserver.dto.challengeDTO.ChallengeResponseDTO.MyChallengeDTO;
import foregg.foreggserver.jwt.SecurityUtil;
import foregg.foreggserver.repository.NotificationRepository;
import foregg.foreggserver.repository.ChallengeParticipationRespository;
import foregg.foreggserver.repository.ChallengeRepository;
import foregg.foreggserver.service.userService.UserQueryService;
Expand All @@ -23,8 +26,7 @@
import java.util.*;
import java.util.stream.Collectors;

import static foregg.foreggserver.apiPayload.code.status.ErrorStatus.MAKE_NICKNAME_FIRST;
import static foregg.foreggserver.apiPayload.code.status.ErrorStatus.NOT_FOUND_MY_CHALLENGE;
import static foregg.foreggserver.apiPayload.code.status.ErrorStatus.*;

@Transactional(readOnly = true)
@Service
Expand All @@ -35,6 +37,7 @@ public class ChallengeQueryService {
private final ChallengeRepository challengeRepository;
private final ChallengeParticipationRespository challengeParticipationRespository;
private final UserQueryService userQueryService;
private final NotificationRepository notificationRepository;

public ChallengeResponseDTO challengeMain() {
User user = userQueryService.getUser(SecurityUtil.getCurrentUser());
Expand Down Expand Up @@ -76,6 +79,59 @@ public List<MyChallengeDTO> getMyChallenges() {
return result;
}

public List<ChallengeCheerResponseDTO> getParticipantsList(Long id) {
User currentUser = userQueryService.getUser(SecurityUtil.getCurrentUser());
Challenge challenge = challengeRepository.findById(id)
.orElseThrow(() -> new ChallengeHandler(CHALLENGE_NOT_FOUND));

ChallengeParticipation challengeParticipation = challengeParticipationRespository.findByUserAndChallenge(currentUser, challenge)
.orElseThrow(() -> new ChallengeHandler(NO_PARTICIPATING_CHALLENGE));

if (!challengeParticipation.isParticipating()) {
throw new ChallengeHandler(NO_PARTICIPATING_CHALLENGE);
}

String today = LocalDate.now().toString();
List<ChallengeParticipation> challengeParticipations = challengeParticipationRespository.findByChallenge(challenge)
.orElseThrow(()-> new ChallengeHandler(CHALLENGE_NOT_FOUND));

// 자신을 제외한 참여자 리스트
challengeParticipations.removeIf(cp -> cp.getUser().equals(currentUser));
if (challengeParticipations.isEmpty()) {
return null;
}

return challengeParticipations.stream()
.map(cp -> createChallengeCheerResponseDTO(currentUser, cp, today))
.collect(Collectors.toList());
}

private ChallengeCheerResponseDTO createChallengeCheerResponseDTO(User sender, ChallengeParticipation cp, String today) {
boolean success = cp.getSuccessDays().contains(DateUtil.getTodayDayOfWeek());
boolean clap = false;
boolean support = false;
List<Notification> notifications = notificationRepository.findBySenderAndReceiverAndDate(sender, cp.getUser(), today);

for (Notification notification : notifications) {
if (notification.getNotificationType().equals(NotificationType.CLAP)) {
clap = true;
}
if (notification.getNotificationType().equals(NotificationType.SUPPORT)) {
support = true;
}
}

return ChallengeCheerResponseDTO.builder()
.id(cp.getUser().getId())
.challengeNickname(cp.getUser().getChallengeName())
.thought(cp.getThoughts())
.success(success)
.clap(clap)
.support(support)
.build();
}


//챌린지 검색 메서드
public ChallengeResponseDTO searchChallenge(String keyword) {
User user = userQueryService.getUser(SecurityUtil.getCurrentUser());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
package foregg.foreggserver.service.challengeService;

import foregg.foreggserver.apiPayload.exception.handler.ChallengeHandler;
import foregg.foreggserver.apiPayload.exception.handler.UserHandler;
import foregg.foreggserver.converter.ChallengeConverter;
import foregg.foreggserver.domain.Challenge;
import foregg.foreggserver.domain.ChallengeParticipation;
import foregg.foreggserver.domain.Notification;
import foregg.foreggserver.domain.User;
import foregg.foreggserver.domain.enums.NotificationType;
import foregg.foreggserver.dto.challengeDTO.ChallengeResponseDTO.MyChallengeDTO;
import foregg.foreggserver.jwt.SecurityUtil;
import foregg.foreggserver.repository.ChallengeParticipationRespository;
import foregg.foreggserver.repository.ChallengeRepository;
import foregg.foreggserver.repository.NotificationRepository;
import foregg.foreggserver.repository.UserRepository;
import foregg.foreggserver.service.notificationService.NotificationService;
import foregg.foreggserver.service.userService.UserQueryService;
import foregg.foreggserver.util.DateUtil;
import lombok.RequiredArgsConstructor;
Expand All @@ -36,6 +41,8 @@ public class ChallengeService {
private final UserQueryService userQueryService;
private final UserRepository userRepository;
private final ChallengeQueryService challengeQueryService;
private final NotificationService notificationService;
private final NotificationRepository notificationRepository;

public void participate(Long id) {
User user = userQueryService.getUser(SecurityUtil.getCurrentUser());
Expand Down Expand Up @@ -154,4 +161,43 @@ public void initSuccessDays() {
}
challengeParticipationRepository.saveAll(challengeParticipations); // 변경 사항 저장
}

public void cheer(Long id, NotificationType type, Long challengeId) {
User receiver = userRepository.findById(id).orElseThrow(() -> new UserHandler(USER_NOT_FOUND));
User sender = userQueryService.getUser(SecurityUtil.getCurrentUser());
Challenge challenge = challengeRepository.findById(challengeId).orElseThrow(() -> new ChallengeHandler(CHALLENGE_NOT_FOUND));

ChallengeParticipation cp = challengeParticipationRepository.findByUserAndChallenge(sender, challenge).orElseThrow(() -> new ChallengeHandler(NO_PARTICIPATING_CHALLENGE));
if (!cp.isParticipating()) {
throw new ChallengeHandler(NO_PARTICIPATING_CHALLENGE);
}
ChallengeParticipation challengeParticipation = challengeParticipationRepository.findByUserAndChallenge(receiver, challenge).orElseThrow(() -> new ChallengeHandler(NO_PARTICIPATING_CHALLENGE));
if (!challengeParticipation.isParticipating()) {
throw new ChallengeHandler(NO_PARTICIPATING_CHALLENGE);
}

catchCheerException(challengeParticipation, type);

List<Notification> notificationList = notificationRepository.findBySenderAndDateAndNotificationType(sender, LocalDate.now().toString(), type);
if (notificationList.size() >= 3) {
throw new ChallengeHandler(NO_MORE_THAN_THIRD_TIME);
}

if (notificationRepository.findBySenderAndReceiverAndDateAndNotificationType(sender, receiver, LocalDate.now().toString(), type) != null) {
throw new ChallengeHandler(ALREADY_SEND_CHEER);
}

Notification notification = notificationService.createNotification(type, receiver, sender);
notificationRepository.save(notification);
}

private void catchCheerException(ChallengeParticipation challengeParticipation, NotificationType notificationType) {
if (challengeParticipation.getSuccessDays().contains(DateUtil.getTodayDayOfWeek()) && notificationType.equals(NotificationType.SUPPORT)) {
throw new ChallengeHandler(UNABLE_TO_SEND_SUPPORT);
}

if (!challengeParticipation.getSuccessDays().contains(DateUtil.getTodayDayOfWeek()) && notificationType.equals(NotificationType.CLAP)) {
throw new ChallengeHandler(UNABLE_TO_SEND_CLAP);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ private String getAccessToken() throws IOException {

private String makeMessage(String fcmToken, String title, String body, String type, String targetId, String time, Boolean vibration) throws JsonProcessingException {
ObjectMapper om = new ObjectMapper();
String vib = null;
if (vibration != null) {
vib = vibration.toString();
}
FcmMessageDTO fcmMessageDto = FcmMessageDTO.builder()
.message(FcmMessageDTO.Message.builder()
.token(fcmToken)
Expand All @@ -77,7 +81,7 @@ private String makeMessage(String fcmToken, String title, String body, String ty
.type(type)
.targetId(targetId)
.time(time)
.vibration(vibration.toString())
.vibration(vib)
.build()
)
.android(FcmMessageDTO.Android.builder()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package foregg.foreggserver.service.notificationService;

import foregg.foreggserver.domain.Notification;
import foregg.foreggserver.domain.Record;
import foregg.foreggserver.domain.RepeatTime;
import foregg.foreggserver.domain.User;
import foregg.foreggserver.domain.enums.NotificationType;
import foregg.foreggserver.repository.UserRepository;
import foregg.foreggserver.service.fcmService.FcmService;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -179,6 +181,14 @@ public void cancelScheduledTasks(Long recordId) {
}
}


//알림 만드는 로직
public Notification createNotification(NotificationType notificationType, User receiver, User sender) {
return Notification.builder()
.notificationType(notificationType)
.receiver(receiver)
.sender(sender)
.date(LocalDate.now().toString())
.build();
}

}
Loading

0 comments on commit ea92885

Please sign in to comment.