Skip to content

Commit

Permalink
Merge pull request #25 from Bamdoliro/feat/#23
Browse files Browse the repository at this point in the history
[새기능] 알림 전체 발송
  • Loading branch information
cabbage16 authored Nov 24, 2024
2 parents fb3ba48 + e7bf6fe commit bd92e27
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 4 deletions.
19 changes: 19 additions & 0 deletions src/docs/asciidoc/notification.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,25 @@ include::{snippets}/notification-controller-test/유저에_해당하는_fcm_토
===== FCM 메시지 발송 과정에서 오류가 발생한 경우
include::{snippets}/notification-controller-test/모종의_이유로_fcm_알림_발송과정에서_문제가_발생하면_에러가_발생한다/http-response.adoc[]

=== 알림 전체 발송
어드민은 모든 유저에게 알림을 발송할 수 있습니다.

==== 요청 형식

===== Request Header
include::{snippets}/notification-controller-test/fcm_토큰을_가진_유저_전체에게_알림을_발송한다/request-headers.adoc[]

===== Request Body
include::{snippets}/notification-controller-test/fcm_토큰을_가진_유저_전체에게_알림을_발송한다/request-fields.adoc[]

==== 응답

===== 정상 응답
include::{snippets}/notification-controller-test/fcm_토큰을_가진_유저_전체에게_알림을_발송한다/http-response.adoc[]

===== 모종의 이유로 알림 발송에 실패한 경우
include::{snippets}/notification-controller-test/fcm_토큰을_가진_유저_전체에게_알림발송_과정에서_문제가_발생하면_에러가_발생한다/http-response.adoc[]

=== 알림 전체 조회
유저는 알림을 전체 조회할 수 있습니다.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.bamdoliro.sinabro.infrastructure.persistence.diary.DiaryRepository;
import com.bamdoliro.sinabro.infrastructure.persistence.letter.LetterRepository;
import com.bamdoliro.sinabro.shared.annotation.UseCase;
import com.bamdoliro.sinabro.shared.response.IdResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -26,14 +27,16 @@ public class GenerateLetterUseCase {
private final CharacterFacade characterFacade;

@Transactional
public void execute(User user) {
public IdResponse execute(User user) {
Character character = characterFacade.getCharacter(user);
List<EmotionAndKeyword> emotionAndKeywords = extractEmotionAndKeywords(user);
GenerateLetterResponse response = aiService.generateLetter(character.getType().getId(), character.getFriendship(), emotionAndKeywords);

letterRepository.save(new Letter(response.getContent(), user));
Letter letter = letterRepository.save(new Letter(response.getContent(), user));

character.increaseFriendShip();

return new IdResponse(letter);
}

private List<EmotionAndKeyword> extractEmotionAndKeywords(User user) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.bamdoliro.sinabro.application.notification;

import com.bamdoliro.sinabro.domain.notification.domain.Notification;
import com.bamdoliro.sinabro.infrastructure.fcm.FCMService;
import com.bamdoliro.sinabro.infrastructure.persistence.fcm.token.FCMTokenRepository;
import com.bamdoliro.sinabro.infrastructure.persistence.notification.NotificationRepository;
import com.bamdoliro.sinabro.presentation.notification.dto.request.SendNotificationRequest;
import com.bamdoliro.sinabro.shared.annotation.UseCase;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;

@RequiredArgsConstructor
@UseCase
public class SendNotificationToAllUserUseCase {

private final FCMService fcmService;
private final NotificationRepository notificationRepository;
private final FCMTokenRepository fcmTokenRepository;

@Transactional
public void execute(SendNotificationRequest request) {
fcmTokenRepository.findAll()
.forEach(fcmToken -> {
fcmService.sendMessageTo(fcmToken.getToken(), request.getTitle(), request.getBody());
notificationRepository.save(new Notification(request.getTitle(), request.getBody(), fcmToken.getUser()));
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.bamdoliro.sinabro.presentation.letter.dto.response.LetterResponse;
import com.bamdoliro.sinabro.presentation.letter.dto.response.ListLetterResponse;
import com.bamdoliro.sinabro.shared.auth.AuthenticationPrincipal;
import com.bamdoliro.sinabro.shared.response.IdResponse;
import com.bamdoliro.sinabro.shared.response.ListCommonResponse;
import com.bamdoliro.sinabro.shared.response.SingleCommonResponse;
import lombok.RequiredArgsConstructor;
Expand All @@ -24,10 +25,10 @@ public class LetterController {

@ResponseStatus(HttpStatus.CREATED)
@PostMapping
public void generateLetter(
public IdResponse generateLetter(
@AuthenticationPrincipal User user
) {
generateLetterUseCase.execute(user);
return generateLetterUseCase.execute(user);
}

@GetMapping
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.bamdoliro.sinabro.presentation.notification;

import com.bamdoliro.sinabro.application.notification.QueryNotificationListUseCase;
import com.bamdoliro.sinabro.application.notification.SendNotificationToAllUserUseCase;
import com.bamdoliro.sinabro.application.notification.SendNotificationUseCase;
import com.bamdoliro.sinabro.domain.user.domain.User;
import com.bamdoliro.sinabro.presentation.notification.dto.request.SendNotificationRequest;
import com.bamdoliro.sinabro.presentation.notification.dto.response.ListNotificationResponse;
import com.bamdoliro.sinabro.shared.auth.AuthenticationPrincipal;
import com.bamdoliro.sinabro.shared.auth.Authority;
import com.bamdoliro.sinabro.shared.response.CommonResponse;
import com.bamdoliro.sinabro.shared.response.ListCommonResponse;
import jakarta.validation.Valid;
Expand All @@ -19,6 +21,7 @@
public class NotificationController {

private final SendNotificationUseCase sendNotificationUseCase;
private final SendNotificationToAllUserUseCase sendNotificationToAllUserUseCase;
private final QueryNotificationListUseCase queryNotificationListUseCase;

@ResponseStatus(HttpStatus.NO_CONTENT)
Expand All @@ -30,6 +33,15 @@ public void sendNotification(
sendNotificationUseCase.execute(user, request);
}

@ResponseStatus(HttpStatus.NO_CONTENT)
@PostMapping("/all")
public void sendNotificationToAllUser(
@AuthenticationPrincipal(authority = Authority.ADMIN) User user,
@RequestBody @Valid SendNotificationRequest request
) {
sendNotificationToAllUserUseCase.execute(request);
}

@GetMapping
public ListCommonResponse<ListNotificationResponse> queryNotification(
@AuthenticationPrincipal User user
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package com.bamdoliro.sinabro.presentation.notification.dto.request;

import jakarta.validation.constraints.NotBlank;
import lombok.*;

@Getter
@ToString
@AllArgsConstructor
public class SendNotificationRequest {

@NotBlank(message = "필수값입니다.")
private String title;

@NotBlank(message = "필수값입니다.")
private String body;
}

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.bamdoliro.sinabro.shared.response;

import com.bamdoliro.sinabro.domain.diary.domain.Diary;
import com.bamdoliro.sinabro.domain.letter.domain.Letter;
import com.bamdoliro.sinabro.domain.question.domain.Question;
import lombok.AllArgsConstructor;
import lombok.Getter;
Expand All @@ -15,6 +16,10 @@ public IdResponse(Diary diary) {
this.id = diary.getId();
}

public IdResponse(Letter letter) {
this.id = letter.getId();
}

public IdResponse(Question question) {
this.id = question.getId();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,60 @@ public class NotificationControllerTest extends RestDocsTestSupport {

verify(queryNotificationListUseCase, times(1)).execute(any(User.class));
}

@Test
void FCM_토큰을_가진_유저_전체에게_알림을_발송한다() throws Exception {
User user = UserFixture.createAdmin();
SendNotificationRequest request = new SendNotificationRequest("당신에게 편지가 왔어요.", "편지가 왔어요 어서 확인해보세요!");

given(authenticationArgumentResolver.supportsParameter(any(MethodParameter.class))).willReturn(true);
given(authenticationArgumentResolver.resolveArgument(any(), any(), any(), any())).willReturn(user);

mockMvc.perform(post("/notifications/all")
.header(HttpHeaders.AUTHORIZATION, AuthFixture.createAuthHeader())
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(toJson(request))
)

.andExpect(status().isNoContent())

.andDo(restDocs.document(
requestHeaders(
headerWithName(HttpHeaders.AUTHORIZATION)
.description("Bearer token")
),
requestFields(
fieldWithPath("title")
.description("알림 제목"),
fieldWithPath("body")
.description("알림 내용")
)
));

verify(sendNotificationToAllUserUseCase, times(1)).execute(any(SendNotificationRequest.class));
}

@Test
void FCM_토큰을_가진_유저_전체에게_알림발송_과정에서_문제가_발생하면_에러가_발생한다() throws Exception {
User user = UserFixture.createAdmin();
SendNotificationRequest request = new SendNotificationRequest("당신에게 편지가 왔어요.", "편지가 왔어요 어서 확인해보세요!");

given(authenticationArgumentResolver.supportsParameter(any(MethodParameter.class))).willReturn(true);
given(authenticationArgumentResolver.resolveArgument(any(), any(), any(), any())).willReturn(user);
willThrow(new FailedToSendException()).given(sendNotificationToAllUserUseCase).execute(any(SendNotificationRequest.class));

mockMvc.perform(post("/notifications/all")
.header(HttpHeaders.AUTHORIZATION, AuthFixture.createAuthHeader())
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(toJson(request))
)

.andExpect(status().isInternalServerError())

.andDo(restDocs.document());

verify(sendNotificationToAllUserUseCase, times(1)).execute(any(SendNotificationRequest.class));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.bamdoliro.sinabro.application.auth.*;
import com.bamdoliro.sinabro.application.character.GetCharacterUseCase;
import com.bamdoliro.sinabro.application.diary.*;
import com.bamdoliro.sinabro.application.notification.SendNotificationToAllUserUseCase;
import com.bamdoliro.sinabro.application.question.*;
import com.bamdoliro.sinabro.domain.auth.service.TokenService;
import com.bamdoliro.sinabro.presentation.auth.AuthController;
Expand Down Expand Up @@ -101,6 +102,9 @@ public abstract class ControllerTest {
@MockBean
protected QueryNotificationListUseCase queryNotificationListUseCase;

@MockBean
protected SendNotificationToAllUserUseCase sendNotificationToAllUserUseCase;

@MockBean
protected SaveFCMTokenUseCase saveFCMTokenUseCase;

Expand Down

0 comments on commit bd92e27

Please sign in to comment.