Skip to content

Commit

Permalink
Merge pull request #166 from depromeet/dev
Browse files Browse the repository at this point in the history
  • Loading branch information
leeseojune53 authored Dec 18, 2022
2 parents c0221be + 8cee60d commit 7b08553
Show file tree
Hide file tree
Showing 18 changed files with 135 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RequestMapping("/asset")
@RequestMapping("/api/v1/asset")
@RestController
@Tag(name = "이미지 관련 컨트롤러", description = "")
@SecurityRequirement(name = "access-token")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/credentials")
@RequestMapping("/api/v1/credentials")
@RequiredArgsConstructor
@Tag(name = "인증 관련 컨트롤러", description = "oauth, token refresh 기능을 담당합니다")
public class CredentialController {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

@RequiredArgsConstructor
@RestController
@RequestMapping("/groups")
@RequestMapping("/api/v1/groups")
@Tag(name = "그룹 관련 컨트롤러", description = "")
@SecurityRequirement(name = "access-token")
public class GroupController {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import org.springframework.web.multipart.MultipartFile;

@RequiredArgsConstructor
@RequestMapping("/images")
@RequestMapping("/api/v1/images")
@RestController
public class ImageController {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.util.List;
import java.util.Objects;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
Expand Down Expand Up @@ -56,13 +57,17 @@ public class Notification extends BaseTimeEntity {
private User sendUser;

@Builder.Default
@OneToMany(mappedBy = "notification", fetch = FetchType.LAZY)
@OneToMany(mappedBy = "notification", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<NotificationReceiver> receivers = new ArrayList<>();

@Builder.Default
@OneToMany(mappedBy = "notification", fetch = FetchType.LAZY)
private Set<NotificationReaction> notificationReactions = new HashSet<>();

public void addReceivers(List<NotificationReceiver> receivers) {
this.receivers.addAll(receivers);
}

public static Notification of(Long notificationId) {
return Notification.builder().id(notificationId).build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@


import io.github.depromeet.knockknockbackend.domain.user.domain.User;
import io.github.depromeet.knockknockbackend.global.database.BaseTimeEntity;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
Expand All @@ -23,7 +24,7 @@
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "tbl_notification_receiver")
@Entity
public class NotificationReceiver {
public class NotificationReceiver extends BaseTimeEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Expand All @@ -36,4 +37,12 @@ public class NotificationReceiver {
@JoinColumn(name = "receiver_user_id")
@OneToOne(fetch = FetchType.LAZY)
private User receiver;

private String fcmToken;

public NotificationReceiver(Notification notification, User receiver, String fcmToken) {
this.notification = notification;
this.receiver = receiver;
this.fcmToken = fcmToken;
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package io.github.depromeet.knockknockbackend.domain.notification.domain.repository;


import io.github.depromeet.knockknockbackend.domain.notification.domain.DeviceToken;
import io.github.depromeet.knockknockbackend.domain.notification.domain.Notification;
import java.util.List;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;

public interface CustomNotificationRepository {

Slice<Notification> findSliceFromStorage(
Long userId, Long groupId, Integer periodOfMonth, Pageable pageable);

List<DeviceToken> findTokenByGroupAndOptionAndNonBlock(
Long userId, Long groupId, Boolean nightOption);
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package io.github.depromeet.knockknockbackend.domain.notification.domain.repository;

import static io.github.depromeet.knockknockbackend.domain.group.domain.QGroupUser.groupUser;
import static io.github.depromeet.knockknockbackend.domain.notification.domain.QDeviceToken.deviceToken;
import static io.github.depromeet.knockknockbackend.domain.notification.domain.QNotification.notification;
import static io.github.depromeet.knockknockbackend.domain.option.domain.QOption.option;
import static io.github.depromeet.knockknockbackend.domain.relation.domain.QBlockUser.blockUser;
import static io.github.depromeet.knockknockbackend.domain.storage.domain.QStorage.storage;

import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.JPAExpressions;
import com.querydsl.jpa.impl.JPAQueryFactory;
import io.github.depromeet.knockknockbackend.domain.notification.domain.DeviceToken;
import io.github.depromeet.knockknockbackend.domain.notification.domain.Notification;
import java.time.LocalDate;
import java.util.List;
Expand Down Expand Up @@ -53,6 +59,35 @@ public Slice<Notification> findSliceFromStorage(
return new SliceImpl<>(notifications, pageable, hasNext(notifications, pageable));
}

@Override
public List<DeviceToken> findTokenByGroupAndOptionAndNonBlock(
Long userId, Long groupId, Boolean nightOption) {
return queryFactory
.select(deviceToken)
.from(deviceToken)
.leftJoin(groupUser)
.on(deviceToken.user.id.eq(groupUser.user.id))
.innerJoin(option)
.on(groupUser.user.id.eq(option.userId))
.where(
groupUser.group.id.eq(groupId),
option.newOption.eq(true),
eqNightOption(nightOption),
JPAExpressions.selectFrom(blockUser)
.where(
blockUser.user.eq(groupUser.user),
blockUser.blockedUser.id.eq(userId))
.notExists())
.fetch();
}

private BooleanExpression eqNightOption(Boolean nightOption) {
if (nightOption == null) {
return null;
}
return option.nightOption.eq(nightOption);
}

private BooleanExpression eqGroupId(Long groupId) {
if (groupId == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
@SecurityRequirement(name = "access-token")
@Tag(name = "푸쉬알림 관련 컨트롤러", description = "")
@RequiredArgsConstructor
@RequestMapping("/notifications")
@RequestMapping("/api/v1/notifications")
@RestController
public class NotificationController {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.github.depromeet.knockknockbackend.domain.notification.domain.DeviceToken;
import io.github.depromeet.knockknockbackend.domain.notification.domain.NightCondition;
import io.github.depromeet.knockknockbackend.domain.notification.domain.Notification;
import io.github.depromeet.knockknockbackend.domain.notification.domain.NotificationReceiver;
import io.github.depromeet.knockknockbackend.domain.notification.domain.repository.DeviceTokenRepository;
import io.github.depromeet.knockknockbackend.domain.notification.domain.repository.NotificationRepository;
import io.github.depromeet.knockknockbackend.domain.notification.domain.vo.NotificationReactionCountInfoVo;
Expand Down Expand Up @@ -97,28 +98,39 @@ public void registerFcmToken(RegisterFcmTokenRequest request) {
public void sendInstance(SendInstanceRequest request) {
Long sendUserId = SecurityUtils.getCurrentUserId();

List<String> tokens = getTokens(request, sendUserId);
List<DeviceToken> deviceTokens = getDeviceTokens(request, sendUserId);
List<String> tokens = getTokens(deviceTokens);
MulticastMessage multicastMessage = makeMulticastMessageForFcm(request, tokens);

try {
BatchResponse batchResponse =
FirebaseMessaging.getInstance().sendMulticast(multicastMessage);
if (batchResponse.getFailureCount() >= 1) {
handleFcmMessagingException(batchResponse);
logFcmMessagingException(batchResponse);
}
} catch (FirebaseMessagingException e) {
log.error("[**FCM notification sending Error] {} ", e.getMessage());
throw FcmResponseException.EXCEPTION;
}

notificationRepository.save(
Notification notification =
Notification.of(
request.getTitle(),
request.getContent(),
request.getImageUrl(),
Group.of(request.getGroupId()),
User.of(sendUserId),
LocalDateTime.now()));
LocalDateTime.now());
notification.addReceivers(
deviceTokens.stream()
.map(
deviceToken ->
new NotificationReceiver(
notification,
User.of(deviceToken.getUserId()),
deviceToken.getToken()))
.collect(Collectors.toList()));
notificationRepository.save(notification);
}

public Slice<QueryNotificationListResponseElement> getNotificationListResponseElements(
Expand Down Expand Up @@ -177,21 +189,19 @@ public Slice<QueryNotificationListResponseElement> getNotificationListResponseEl
});
}

private void handleFcmMessagingException(BatchResponse batchResponse) {
private void logFcmMessagingException(BatchResponse batchResponse) {
log.error(
"[**FCM notification sending Error] successCount : {}, failureCount : {} ",
batchResponse.getSuccessCount(),
batchResponse.getFailureCount());
batchResponse
.getResponses()
batchResponse.getResponses().stream()
.filter(sendResponse -> sendResponse.getException() != null)
.forEach(
sendResponse ->
log.error(
"[**FCM notification sending Error] errorCode: {}, errorMessage : {}",
sendResponse.getException().getErrorCode(),
sendResponse.getException().getMessage()));

throw FcmResponseException.EXCEPTION;
}

private MulticastMessage makeMulticastMessageForFcm(
Expand All @@ -207,23 +217,18 @@ private MulticastMessage makeMulticastMessageForFcm(
.build();
}

private List<String> getTokens(SendInstanceRequest request, Long sendUserId) {
List<DeviceToken> deviceTokens =
getDeviceTokensOfGroupUserSettingAlarm(request.getGroupId());

return deviceTokens.stream()
.filter(deviceToken -> !deviceToken.getUserId().equals(sendUserId))
.map(DeviceToken::getToken)
.collect(Collectors.toList());
}

private List<DeviceToken> getDeviceTokensOfGroupUserSettingAlarm(Long groupId) {
private List<DeviceToken> getDeviceTokens(SendInstanceRequest request, Long sendUserId) {
Boolean nightOption = null;
if (NightCondition.isNight()) {
nightOption = true;
}

return deviceTokenRepository.findUserByGroupIdAndNewOption(groupId, true, nightOption);
return notificationRepository.findTokenByGroupAndOptionAndNonBlock(
sendUserId, request.getGroupId(), nightOption);
}

private List<String> getTokens(List<DeviceToken> deviceTokens) {
return deviceTokens.stream().map(DeviceToken::getToken).collect(Collectors.toList());
}

private Slice<NotificationReaction> retrieveNotificationReactions(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
@Tag(name = "알림 설정 관련 컨트롤러", description = "")
@SecurityRequirement(name = "access-token")
@RequiredArgsConstructor
@RequestMapping("/options")
@RequestMapping("/api/v1/options")
@RestController
public class OptionController {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
@SecurityRequirement(name = "access-token")
@Tag(name = "리액션 관련 컨트롤러", description = "")
@RequiredArgsConstructor
@RequestMapping("/reactions")
@RequestMapping("/api/v1/reactions")
@RestController
public class ReactionController {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
@SecurityRequirement(name = "access-token")
@Tag(name = "추천메세지 관련 컨트롤러", description = "")
@RequiredArgsConstructor
@RequestMapping("/recommendmessage")
@RequestMapping("/api/v1/recommendmessage")
@RestController
public class RecommendMessageController {

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


import io.github.depromeet.knockknockbackend.domain.user.domain.User;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "tbl_block_user")
@Entity
public class BlockUser {

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

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

@JoinColumn(name = "blocked_user_id")
@OneToOne(fetch = FetchType.LAZY)
private User blockedUser;
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
@Tag(name = "유저 관련 컨트롤러", description = "")
@SecurityRequirement(name = "access-token")
@RequiredArgsConstructor
@RequestMapping("/relations")
@RequestMapping("/api/v1/relations")
@RestController
public class RelationController {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
@SecurityRequirement(name = "access-token")
@Tag(name = "보관함 관련 컨트롤러", description = "")
@RequiredArgsConstructor
@RequestMapping("/storages")
@RequestMapping("/api/v1/storages")
@RestController
public class StorageController {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
@Tag(name = "유저 관련 컨트롤러", description = "")
@SecurityRequirement(name = "access-token")
@RequiredArgsConstructor
@RequestMapping("/users")
@RequestMapping("/api/v1/users")
@SecurityRequirement(name = "access-token")
@RestController
public class UserController {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.formLogin().disable().cors().and().csrf().disable();

http.authorizeHttpRequests()
.antMatchers("/")
.antMatchers("/api/v1/")
.permitAll()
.antMatchers(SwaggerPatterns)
.permitAll()
.antMatchers("/actuator/**")
.antMatchers("/api/v1/actuator/**")
.permitAll()
.antMatchers("/credentials/**")
.antMatchers("/api/v1/credentials/**")
.permitAll()
.antMatchers("/asset/version")
.antMatchers("/api/v1/asset/version")
.permitAll()
.anyRequest()
.authenticated();
Expand Down

0 comments on commit 7b08553

Please sign in to comment.