Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,9 @@ public void contactCoach(User user, Long coachId) {
newMatching.getUserCoachMatchingId());
Long chatRoomId = chatRoomService.createChatRoom(chatRoomRequest);

notificationService.createNotification(user.getUserId(), coachId, RelationFunctionEnum.ask);
notificationService.createNotification(user.getUserId(), coach.getUser().getUserId(),
RelationFunctionEnum.request);
notificationService.createNotification(user.getUserId(), coach.getUser().getUserId(), RelationFunctionEnum.ask);
}

@Transactional
Expand All @@ -165,9 +167,9 @@ public void deleteMatching(Long coachUserId, Long userId) {
boolean isMatching = matching.getIsMatching();
matchingRepository.delete(matching);
if (isMatching) {
notificationService.createNotification(userId, coach.getCoachId(), RelationFunctionEnum.cancel);
notificationService.createNotification(userId, coach.getUser().getUserId(), RelationFunctionEnum.cancel);
} else {
notificationService.createNotification(userId, coach.getCoachId(), RelationFunctionEnum.refusal);
notificationService.createNotification(userId, coach.getUser().getUserId(), RelationFunctionEnum.refusal);
}
}

Expand Down Expand Up @@ -274,6 +276,7 @@ public void addCoachToFavorites(Long userId, Long coachId) {
if (!userCoachLikeRepository.existsByUser_UserIdAndCoach_CoachId(userId, coachId)) {
userCoachLikeRepository.save(new UserCoachLike(null, user, coach));
}
notificationService.createNotification(userId, coach.getUser().getUserId(), RelationFunctionEnum.like);
}

@Transactional
Expand All @@ -286,7 +289,6 @@ public void deleteCoachToFavorites(Long userId, Long coachId) {
}
}


public List<MatchingUserResponseDto> getMatchingUsersByCoachId(Long coachUserId) {
Long coachId = coachRepository.findCoachIdByUserId(coachUserId)
.orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_COACH));
Expand Down Expand Up @@ -321,7 +323,6 @@ private MatchingUserResponseDto buildMatchingUserResponseDto(Matching matching)
);
}


@Transactional
public void addReview(Long userId, Long coachId, ReviewRequestDto requestDto) {
User user = getUserById(userId);
Expand All @@ -342,7 +343,8 @@ public void addReview(Long userId, Long coachId, ReviewRequestDto requestDto) {
Review review = new Review(null, coach, user, requestDto.contents(), requestDto.stars());

reviewRepository.save(review);
notificationService.createNotification(user.getUserId(), coachId, RelationFunctionEnum.review);
notificationService.createNotification(user.getUserId(), coach.getUser().getUserId(),
RelationFunctionEnum.review);
}

@Transactional
Expand Down Expand Up @@ -567,6 +569,6 @@ public void updateMatchingStatus(Long coachUserId, Long userId) {

matching.markAsMatched();
coach.increaseTotalUserCount();
notificationService.createNotification(userId, coach.getCoachId(), RelationFunctionEnum.match);
notificationService.createNotification(userId, coachUserId, RelationFunctionEnum.match);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package site.coach_coach.coach_coach_server.common.domain;

public enum RelationFunctionEnum {
review, ask, like, match, refusal, cancel
review, ask, like, match, refusal, cancel, routine, request
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@

@Getter
public enum NotificationMessage {
REVIEW_MESSAGE("새로운 리뷰가 작성되었습니다."),
ASK_MESSAGE("매칭을 신청하였습니다."),
LIKE_MESSAGE("회원님을 관심 코치로 등록하였습니다."),
MATCH_MESSAGE("회원님의 매칭 신청을 수락하셨습니다."),
REFUSAL_MESSAGE("매칭 신청을 거절하였습니다."),
REVIEW_MESSAGE("새로운 리뷰가 작성되었습니다!"),
ASK_MESSAGE("코치 매칭을 요청했어요!"),
LIKE_MESSAGE("회원님을 관심 코치로 등록했어요!"),
MATCH_MESSAGE("코치 매칭을 수락했어요!"),
MATCH_REQUEST_MESSAGE(" 님께 코치 매칭을 요청했어요! 답변이 오면 빠르게 알려드릴게요 :)"),
REFUSAL_MESSAGE("매칭 요청을 거절하였습니다."),
CANCEL_MESSAGE("매칭을 취소하였습니다."),
USER_MESSAGE("님이 ");
ROUTINE_MESSAGE("새로운 루틴을 등록했어요."),
USER_MESSAGE(" 님이 ");

private final String message;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
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.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
Expand Down Expand Up @@ -52,4 +53,23 @@ public ResponseEntity<SuccessResponse> deleteNotification(
new SuccessResponse(HttpStatus.OK.value(), SuccessMessage.DELETE_NOTIFICATION_SUCCESS.getMessage())
);
}

@PatchMapping("/v1/notifications/{notificationId}")
public ResponseEntity<Void> markNotificationAsRead(
@AuthenticationPrincipal CustomUserDetails userDetails,
@PathVariable(name = "notificationId") Long notificationId
) {
Long userId = userDetails.getUserId();
notificationService.markNotificationAsRead(userId, notificationId);
return ResponseEntity.noContent().build();
}

@PatchMapping("/v1/notifications")
public ResponseEntity<Void> markAllNotificationsAsRead(
@AuthenticationPrincipal CustomUserDetails userDetails
) {
Long userId = userDetails.getUserId();
notificationService.markAllNotificationsAsRead(userId);
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ public class Notification extends DateEntity {
@JoinColumn(name = "user_id")
private User user;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "coach_id")
private User coach;

@NotBlank
@Column(name = "message", nullable = false, length = 100)
@Size(max = 100)
Expand All @@ -48,4 +52,12 @@ public class Notification extends DateEntity {
@Column(name = "relation_function")
@Enumerated(EnumType.STRING)
private RelationFunctionEnum relationFunction;

@NotNull
@Column(name = "is_read")
private boolean isRead;

public void markAsRead() {
this.isRead = true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,15 @@

import lombok.Builder;
import site.coach_coach.coach_coach_server.common.domain.RelationFunctionEnum;
import site.coach_coach.coach_coach_server.notification.domain.Notification;

@Builder
public record NotificationListResponse(
Long notificationId,
String nickname,
String profileImageUrl,
String message,
RelationFunctionEnum relationFunction,
boolean isRead,
LocalDateTime createdAt
) {
public static NotificationListResponse from(Notification notification) {
return new NotificationListResponse(
notification.getNotificationId(),
notification.getMessage(),
notification.getRelationFunction(),
notification.getCreatedAt()
);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
package site.coach_coach.coach_coach_server.notification.repository;

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 site.coach_coach.coach_coach_server.notification.domain.Notification;

public interface NotificationRepository extends JpaRepository<Notification, Long> {
int countByUser_UserId(Long userId);
int countByUser_UserIdAndIsReadFalse(Long userId);

@Modifying
@Query("UPDATE Notification n SET n.isRead = TRUE WHERE n.user.userId = :userId AND n.isRead = FALSE")
void updateIsReadByUserID(@Param("userId") Long userId);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package site.coach_coach.coach_coach_server.notification.service;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Service;
Expand Down Expand Up @@ -37,7 +36,7 @@ public List<NotificationListResponse> getAllNotifications(Long userId) {

return user.getNotifications()
.stream()
.map(NotificationListResponse::from)
.map(this::buildNotificationResponse)
.toList();
}

Expand All @@ -53,23 +52,17 @@ public void createNotification(Long userId, Long coachId, RelationFunctionEnum r
throw new InvalidInputException(ErrorMessage.INVALID_REQUEST);
}

User receiver;

if (relationFunction == RelationFunctionEnum.match || relationFunction == RelationFunctionEnum.refusal
|| relationFunction == RelationFunctionEnum.cancel) {
receiver = user;
} else {
receiver = coach;
}

Notification notification = Notification.builder()
.user(receiver)
.user(user)
.coach(coach)
.message(message)
.relationFunction(relationFunction)
.isRead(false)
.build();
notificationRepository.save(notification);
}

@Transactional
public void deleteNotification(Long userId, Long notificationId) {
Notification notification = notificationRepository.findById(notificationId)
.orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_NOTIFICATION));
Expand All @@ -82,25 +75,79 @@ public void deleteNotification(Long userId, Long notificationId) {

public void deleteAllNotifications(Long userId) {
User user = userRepository.findById(userId).orElseThrow(UserNotFoundException::new);
List<Notification> notifications = new ArrayList<>(user.getNotifications());
if (!notifications.isEmpty()) {
notificationRepository.deleteAll(notifications);
notificationRepository.deleteAll(user.getNotifications());
}

@Transactional
public void markNotificationAsRead(Long userId, Long notificationId) {
Notification notification = notificationRepository.findById(notificationId)
.orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_NOTIFICATION));

if (!notification.getUser().getUserId().equals(userId)) {
throw new AccessDeniedException();
}
notification.markAsRead();
notificationRepository.save(notification);
}

@Transactional
public void markAllNotificationsAsRead(Long userId) {
notificationRepository.updateIsReadByUserID(userId);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

읽지 않은 모든 알람들의 is_read값을 true로 바꾸시려는 의도라면,
현재(조회 -> 수정 -> 저장) 방법도 좋지만, Update 쿼리(수정)를 사용하는 방법도 추천드려봅니다!

제가 루틴 완료를 매일 초기화하는 로직과 유사한 것 같아서 생각났습니다!

Update notifications n SET n.isRead = TRUE WHERE n.userId = :userId AND n.isRead IS FALSE

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 추천감사합니당!


private String createMessage(User user, User coach, RelationFunctionEnum relationFunction) {
return switch (relationFunction) {
case ask -> user.getNickname() + NotificationMessage.USER_MESSAGE.getMessage()
+ NotificationMessage.ASK_MESSAGE.getMessage();
case like -> user.getNickname() + NotificationMessage.USER_MESSAGE.getMessage()
+ NotificationMessage.LIKE_MESSAGE.getMessage();
case ask -> String.format(
"%s%s%s", user.getNickname(), NotificationMessage.USER_MESSAGE.getMessage(),
NotificationMessage.ASK_MESSAGE.getMessage()
);
case like -> String.format(
"%s%s%s", user.getNickname(), NotificationMessage.USER_MESSAGE.getMessage(),
NotificationMessage.LIKE_MESSAGE.getMessage()
);
case review -> NotificationMessage.REVIEW_MESSAGE.getMessage();
case match -> coach.getNickname() + NotificationMessage.USER_MESSAGE.getMessage()
+ NotificationMessage.MATCH_MESSAGE.getMessage();
case refusal -> coach.getNickname() + NotificationMessage.USER_MESSAGE.getMessage()
+ NotificationMessage.REFUSAL_MESSAGE.getMessage();
case cancel -> coach.getNickname() + NotificationMessage.USER_MESSAGE.getMessage()
+ NotificationMessage.CANCEL_MESSAGE.getMessage();
case match -> String.format(
"%s%s%s", coach.getNickname(), NotificationMessage.USER_MESSAGE.getMessage(),
NotificationMessage.MATCH_MESSAGE.getMessage()
);
case refusal -> String.format(
"%s%s%s", coach.getNickname(), NotificationMessage.USER_MESSAGE.getMessage(),
NotificationMessage.REFUSAL_MESSAGE.getMessage()
);
case cancel -> String.format(
"%s%s%s", coach.getNickname(), NotificationMessage.USER_MESSAGE.getMessage(),
NotificationMessage.CANCEL_MESSAGE.getMessage()
);
case routine -> String.format(
"%s%s%s", coach.getNickname(), NotificationMessage.USER_MESSAGE.getMessage(),
NotificationMessage.ROUTINE_MESSAGE.getMessage()
);
case request -> coach.getNickname() + NotificationMessage.MATCH_REQUEST_MESSAGE.getMessage();
};
}

private NotificationListResponse buildNotificationResponse(Notification notification) {
User sender;
if (isCoachSender(notification.getRelationFunction())) {
sender = notification.getCoach();
} else {
sender = notification.getUser();
}
return NotificationListResponse.builder()
.notificationId(notification.getNotificationId())
.nickname(sender.getNickname())
.profileImageUrl(sender.getProfileImageUrl())
.message(notification.getMessage())
.relationFunction(notification.getRelationFunction())
.isRead(notification.isRead())
.createdAt(notification.getCreatedAt())
.build();
}

private boolean isCoachSender(RelationFunctionEnum relationFunction) {
return switch (relationFunction) {
case match, refusal, cancel, request, routine -> true;
default -> false;
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
import site.coach_coach.coach_coach_server.coach.domain.Coach;
import site.coach_coach.coach_coach_server.coach.repository.CoachRepository;
import site.coach_coach.coach_coach_server.common.constants.ErrorMessage;
import site.coach_coach.coach_coach_server.common.domain.RelationFunctionEnum;
import site.coach_coach.coach_coach_server.common.exception.AccessDeniedException;
import site.coach_coach.coach_coach_server.common.exception.NotFoundException;
import site.coach_coach.coach_coach_server.matching.domain.Matching;
import site.coach_coach.coach_coach_server.matching.repository.MatchingRepository;
import site.coach_coach.coach_coach_server.notification.service.NotificationService;
import site.coach_coach.coach_coach_server.routine.domain.Routine;
import site.coach_coach.coach_coach_server.routine.dto.CreateRoutineRequest;
import site.coach_coach.coach_coach_server.routine.dto.RoutineCreatorDto;
Expand All @@ -38,6 +40,7 @@ public class RoutineService {
private final CoachRepository coachRepository;
private final UserRepository userRepository;
private final SportRepository sportRepository;
private final NotificationService notificationService;
private int numberOfCompletedRoutine;

public void checkIsMatching(Long userId, Long coachId) {
Expand Down Expand Up @@ -130,6 +133,8 @@ public Routine createRoutine(CreateRoutineRequest createRoutineRequest, Long use
Coach coach = coachRepository.findById(coachId)
.orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_COACH));
routineBuilder.coach(coach);
notificationService.createNotification(createRoutineRequest.userId(), userIdByJwt,
RelationFunctionEnum.routine);
}

return routineRepository.save(routineBuilder.build());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ private AuthResponse getLoggedInUserAuthStatus(User user) {
GenderEnum gender = user.getGender();
String profileImageUrl = user.getProfileImageUrl();
boolean isCoach = user.getIsCoach();
int countOfNotifications = notificationRepository.countByUser_UserId(user.getUserId());
int countOfNotifications = notificationRepository.countByUser_UserIdAndIsReadFalse(user.getUserId());
return AuthResponse.builder()
.isLogin(true)
.nickname(nickname)
Expand Down
13 changes: 13 additions & 0 deletions src/main/resources/db/migration/V23__modify_notification_table.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
ALTER TABLE `coachcoach`.`notifications`
ADD COLUMN `is_read` BIT(1) NOT NULL DEFAULT b'0' AFTER `relation_function`,
CHANGE COLUMN `message` `message` VARCHAR(200) NOT NULL ,
CHANGE COLUMN `relation_function` `relation_function` ENUM('ask', 'like', 'review', 'match', 'refusal', 'cancel', 'routine', 'request') NOT NULL ;

ALTER TABLE `coachcoach`.`notifications`
ADD COLUMN `coach_id` BIGINT NOT NULL AFTER `user_id`;
ALTER TABLE `coachcoach`.`notifications`
ADD INDEX `fk_notifications_coach_id_idx` (`coach_id` ASC) VISIBLE;
ALTER TABLE `coachcoach`.`notifications`
ADD CONSTRAINT `fk_notifications_coach_id`
FOREIGN KEY (`coach_id`)
REFERENCES `coachcoach`.`users` (`user_id`);