Skip to content

Commit

Permalink
Merge pull request #267 from depromeet/dev
Browse files Browse the repository at this point in the history
  • Loading branch information
leeseojune53 authored Jan 4, 2023
2 parents 2a5e91c + b5f153a commit a93f7fb
Show file tree
Hide file tree
Showing 13 changed files with 120 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
package io.github.depromeet.knockknockbackend.domain.group.domain.repository;


import io.github.depromeet.knockknockbackend.domain.group.domain.Group;
import io.github.depromeet.knockknockbackend.domain.group.domain.GroupUser;
import io.github.depromeet.knockknockbackend.domain.user.domain.User;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;

public interface GroupUserRepository
extends JpaRepository<GroupUser, Long>, CustomGroupUserRepository {}
extends JpaRepository<GroupUser, Long>, CustomGroupUserRepository {

Optional<GroupUser> findByGroupAndUser(Group group, User user);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@DynamicUpdate
@Table(name = "tbl_reservation")
@Table(
name = "tbl_reservation",
uniqueConstraints = {@UniqueConstraint(columnNames = {"group_id", "send_user_id"})})
@Entity
public class Reservation extends BaseTimeEntity {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
import io.github.depromeet.knockknockbackend.domain.user.domain.User;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;

public interface ReservationRepository extends CrudRepository<Reservation, Long> {
List<Reservation> findByGroupAndSendUserOrderBySendAtAsc(Group group, User sendUser);
Optional<Reservation> findByGroupAndSendUser(Group group, User sendUser);

List<Reservation> findBySendAtLessThan(LocalDateTime sendAt);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.github.depromeet.knockknockbackend.domain.notification.exception;


import io.github.depromeet.knockknockbackend.global.error.exception.ErrorCode;
import io.github.depromeet.knockknockbackend.global.error.exception.KnockException;

public class ReservationAlreadyExistException extends KnockException {
public static final KnockException EXCEPTION = new ReservationAlreadyExistException();

private ReservationAlreadyExistException() {
super(ErrorCode.RESERVATION_ALREADY_EXIST);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.github.depromeet.knockknockbackend.domain.notification.presentation.dto.response;


import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.data.domain.Slice;
Expand All @@ -10,6 +9,6 @@
@AllArgsConstructor
public class QueryNotificationListResponse {

private final List<QueryReservationListResponseElement> reservations;
private final QueryReservationListResponseElement reservations;
private final Slice<QueryNotificationListResponseElement> notifications;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@


import io.github.depromeet.knockknockbackend.domain.group.domain.Group;
import io.github.depromeet.knockknockbackend.domain.group.domain.GroupType;
import io.github.depromeet.knockknockbackend.domain.group.domain.repository.GroupUserRepository;
import io.github.depromeet.knockknockbackend.domain.group.exception.NotMemberException;
import io.github.depromeet.knockknockbackend.domain.group.presentation.dto.response.GroupInfoForNotificationDto;
import io.github.depromeet.knockknockbackend.domain.group.service.GroupService;
import io.github.depromeet.knockknockbackend.domain.notification.domain.*;
import io.github.depromeet.knockknockbackend.domain.notification.domain.Notification;
import io.github.depromeet.knockknockbackend.domain.notification.domain.repository.DeviceTokenRepository;
Expand Down Expand Up @@ -38,11 +42,13 @@ public class NotificationService implements NotificationUtils {
private static final boolean CREATED_DELETED_STATUS = false;
private final EntityManager entityManager;
private final FcmService fcmService;
private final GroupService groupService;
private final NotificationRepository notificationRepository;
private final DeviceTokenRepository deviceTokenRepository;
private final NotificationReactionRepository notificationReactionRepository;
private final ReservationRepository reservationRepository;
private final NotificationExperienceRepository notificationExperienceRepository;
private final GroupUserRepository groupUserRepository;

@Transactional(readOnly = true)
public QueryNotificationListLatestResponse queryListLatest() {
Expand Down Expand Up @@ -79,11 +85,10 @@ public QueryNotificationListResponse queryListByGroupId(Pageable pageable, Long
getQueryNotificationListResponseElements(
notification, myNotificationReactions));

List<Reservation> reservations =
reservationRepository.findByGroupAndSendUserOrderBySendAtAsc(
Group.of(groupId), User.of(SecurityUtils.getCurrentUserId()));
List<QueryReservationListResponseElement> queryReservationListResponseElements =
reservations.stream()
QueryReservationListResponseElement queryReservationListResponseElement =
reservationRepository
.findByGroupAndSendUser(
Group.of(groupId), User.of(SecurityUtils.getCurrentUserId()))
.map(
reservation ->
QueryReservationListResponseElement.builder()
Expand All @@ -93,10 +98,10 @@ public QueryNotificationListResponse queryListByGroupId(Pageable pageable, Long
.imageUrl(reservation.getImageUrl())
.sendAt(reservation.getSendAt())
.build())
.collect(Collectors.toList());
.orElse(null);

return new QueryNotificationListResponse(
queryReservationListResponseElements, queryNotificationListResponseElements);
queryReservationListResponseElement, queryNotificationListResponseElements);
}

public QueryNotificationListResponseElement getQueryNotificationListResponseElements(
Expand Down Expand Up @@ -168,9 +173,10 @@ public void registerFcmToken(RegisterFcmTokenRequest request) {

@Transactional
public void sendInstance(SendInstanceRequest request) {
Long sendUserId = SecurityUtils.getCurrentUserId();
Long currentUserId = SecurityUtils.getCurrentUserId();
validateSendNotificationPermission(request.getGroupId(), currentUserId);

List<DeviceToken> deviceTokens = getDeviceTokens(request.getGroupId(), sendUserId);
List<DeviceToken> deviceTokens = getDeviceTokens(request.getGroupId(), currentUserId);
List<String> tokens = getFcmTokens(deviceTokens);
if (tokens.isEmpty()) {
return;
Expand All @@ -185,7 +191,7 @@ public void sendInstance(SendInstanceRequest request) {
request.getContent(),
request.getImageUrl(),
Group.of(request.getGroupId()),
User.of(sendUserId),
User.of(currentUserId),
null);
}

Expand Down Expand Up @@ -241,6 +247,19 @@ private void validateDeletePermission(Notification notification) {
}
}

public void validateSendNotificationPermission(Long groupId, Long userId) {
Group group = groupService.queryGroup(groupId);
// 홀로외침방이면 방장인지
if (GroupType.OPEN.equals(group.getGroupType())) group.validUserIsHost(userId);
// 친구방이면 그룹 소속원인지
if (GroupType.FRIEND.equals(group.getGroupType())) {
// group.validUserIsMemberOfGroup(userId); //todo: 해당 부분 호춣시 불필요한 쿼리 발생.
groupUserRepository
.findByGroupAndUser(group, User.of(userId))
.orElseThrow(() -> NotMemberException.EXCEPTION);
}
}

@Override
public Notification queryNotificationById(Long notificationId) {
return notificationRepository
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import io.github.depromeet.knockknockbackend.domain.notification.domain.DeviceToken;
import io.github.depromeet.knockknockbackend.domain.notification.domain.Reservation;
import io.github.depromeet.knockknockbackend.domain.notification.domain.repository.ReservationRepository;
import io.github.depromeet.knockknockbackend.domain.notification.exception.ReservationAlreadyExistException;
import io.github.depromeet.knockknockbackend.domain.notification.exception.ReservationForbiddenException;
import io.github.depromeet.knockknockbackend.domain.notification.exception.ReservationNotFoundException;
import io.github.depromeet.knockknockbackend.domain.notification.presentation.dto.request.ChangeSendAtReservationRequest;
Expand Down Expand Up @@ -32,6 +33,16 @@ public class ReservationService {

public void sendReservation(SendReservationRequest request) {
Long currentUserId = SecurityUtils.getCurrentUserId();
notificationService.validateSendNotificationPermission(request.getGroupId(), currentUserId);
Reservation reservation =
reservationRepository
.findByGroupAndSendUser(
Group.of(request.getGroupId()), User.of(currentUserId))
.orElse(null);

if (reservation != null) {
throw ReservationAlreadyExistException.EXCEPTION;
}

reservationRepository.save(
Reservation.of(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ Optional<Relation> findRelationBySendUserIdAndReceiveUserId(
Long sendUserId, Long receiveUserId);

boolean isFriend(Long currentUserId, Long userId);

Long getRelationIdByUserId(Long currentUserId, Long userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,17 @@ public boolean isFriend(Long currentUserId, Long userId) {
.fetchFirst();
}

@Override
public Long getRelationIdByUserId(Long currentUserId, Long userId) {
return queryFactory
.select(relation.id)
.from(relation)
.where(
friendPredicated(currentUserId, userId)
.or(friendPredicated(userId, currentUserId)))
.fetchFirst();
}

private BooleanExpression friendPredicated(Long senderUserId, Long receiveUserId) {
return relation.sendUser.id.eq(senderUserId).and(relation.receiveUser.id.eq(receiveUserId));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.github.depromeet.knockknockbackend.domain.relation.exception;


import io.github.depromeet.knockknockbackend.global.error.exception.ErrorCode;
import io.github.depromeet.knockknockbackend.global.error.exception.KnockException;

public class NotFriendRelationException extends KnockException {

public static final KnockException EXCEPTION = new NotFriendRelationException();

private NotFriendRelationException() {
super(ErrorCode.NOT_FRIEND_RELATION);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ public ResponseEntity<Void> sendUserRequest(@RequestBody @Valid FriendRequest re
return new ResponseEntity<>(relationService.sendFriendRequest(request));
}

@Operation(summary = "친구를 삭제하는 Api입니다. - 친구목록")
@ResponseStatus(HttpStatus.NO_CONTENT)
@DeleteMapping
public void deleteRelation(@RequestBody @Valid FriendRequest request) {
relationService.deleteRelation(request);
}

@Operation(summary = "친구 요청을 수락하는 Api입니다. - 메인 알림")
@ResponseStatus(HttpStatus.CREATED)
@PostMapping("/requests")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import io.github.depromeet.knockknockbackend.domain.relation.exception.AlreadyFriendException;
import io.github.depromeet.knockknockbackend.domain.relation.exception.AlreadySendRequestException;
import io.github.depromeet.knockknockbackend.domain.relation.exception.FriendRequestNotFoundException;
import io.github.depromeet.knockknockbackend.domain.relation.exception.NotFriendRelationException;
import io.github.depromeet.knockknockbackend.domain.relation.presentation.dto.request.FriendRequest;
import io.github.depromeet.knockknockbackend.domain.relation.presentation.dto.response.QueryFriendListResponse;
import io.github.depromeet.knockknockbackend.domain.relation.presentation.dto.response.QueryFriendListResponseElement;
Expand Down Expand Up @@ -77,6 +78,14 @@ public HttpStatus sendFriendRequest(FriendRequest request) {
return HttpStatus.CREATED;
}

public void deleteRelation(FriendRequest request) {
if (!getIsFriend(request.getUserId())) {
throw NotFriendRelationException.EXCEPTION;
}

relationRepository.deleteById(getRelationId(request.getUserId()));
}

public void acceptRequest(FriendRequest request) {
updateIsFriendWithValidate(request, true);
}
Expand All @@ -89,6 +98,10 @@ public boolean getIsFriend(Long userId) {
return relationRepository.isFriend(SecurityUtils.getCurrentUserId(), userId);
}

private Long getRelationId(Long userId) {
return relationRepository.getRelationIdByUserId(SecurityUtils.getCurrentUserId(), userId);
}

private void updateIsFriendWithValidate(FriendRequest request, boolean isFriend) {
if (!getIsFriend(request.getUserId())) {
throw AlreadyFriendException.EXCEPTION;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public enum ErrorCode {
ALREADY_SEND_REQUEST(400, "RELATION-400-1", "Already Send Request."),
ALREADY_FRIEND_REQUEST(400, "RELATION-400-1", "Already Friend Request."),
FRIEND_REQUEST_NOT_FOUND(404, "RELATION-404-1", "Friend Request Not Found."),
NOT_FRIEND_RELATION(404, "RELATION-404-2", "Not Friend Relation."),

OPTION_NOT_FOUND(404, "OPTION-404-1", "Option Not Found."),

Expand Down Expand Up @@ -64,12 +65,16 @@ public enum ErrorCode {
NOTIFICATION_FCM_FAIL_SEND(
HttpStatus.INTERNAL_SERVER_ERROR.value(), "NOTIFICATION-500-1", "FCM ERROR"),

RESERVATION_NOT_FOUND(
HttpStatus.NOT_FOUND.value(), "RESERVATION-404-1", "Reservation Not Found"),
RESERVATION_FORBIDDEN(
HttpStatus.FORBIDDEN.value(),
"RESERVATION-403-1",
"The user has no access to the reservation"),
RESERVATION_ALREADY_EXIST(
HttpStatus.FORBIDDEN.value(),
"RESERVATION-403-2",
"The user already registered reservation"),
RESERVATION_NOT_FOUND(
HttpStatus.NOT_FOUND.value(), "RESERVATION-404-1", "Reservation Not Found"),

STORAGE_FORBIDDEN(
HttpStatus.FORBIDDEN.value(), "STORAGE-403-1", "The user has no access to the storage"),
Expand Down

0 comments on commit a93f7fb

Please sign in to comment.