Skip to content

Commit

Permalink
Merge pull request #18 from MealTokTok/feature/alarm-sender
Browse files Browse the repository at this point in the history
[#17] [FEATURE] 푸시 알림 구현
  • Loading branch information
JiwonKKang authored Jul 26, 2024
2 parents af754ba + b5f08ee commit b8ba444
Show file tree
Hide file tree
Showing 19 changed files with 145 additions and 116 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package core.startup.mealtoktok.api.auth;

import core.startup.mealtoktok.api.dto.SignupRequest;
import core.startup.mealtoktok.api.dto.OAuthLoginResponse;
import core.startup.mealtoktok.api.auth.dto.SignupRequest;
import core.startup.mealtoktok.api.auth.dto.OAuthLoginResponse;
import core.startup.mealtoktok.common.dto.Response;
import core.startup.mealtoktok.domain.auth.AuthService;
import core.startup.mealtoktok.domain.auth.JwtTokens;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package core.startup.mealtoktok.api.auth;

import core.startup.mealtoktok.api.dto.SignupRequest;
import core.startup.mealtoktok.api.dto.OAuthLoginResponse;
import core.startup.mealtoktok.api.auth.dto.SignupRequest;
import core.startup.mealtoktok.api.auth.dto.OAuthLoginResponse;
import core.startup.mealtoktok.common.dto.Response;
import core.startup.mealtoktok.domain.auth.OAuthTokens;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.RequestParam;

@Tag(name = "인증 API")
public interface AuthApiDocs {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package core.startup.mealtoktok.api.dto;
package core.startup.mealtoktok.api.auth.dto;

public record OAuthLoginResponse(
String link
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package core.startup.mealtoktok.api.dto;
package core.startup.mealtoktok.api.auth.dto;

import core.startup.mealtoktok.domain.auth.OAuthTokens;
import core.startup.mealtoktok.domain.user.AddressWithCoordinate;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import core.startup.mealtoktok.domain.auth.exception.AuthErrorCode;

public class ExpiredTokenException extends WebException {

public static final ExpiredTokenException EXCEPTION = new ExpiredTokenException();

private ExpiredTokenException() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,11 @@
@RestControllerAdvice
public class GlobalControllerAdvice {

@ExceptionHandler(value = WebException.class)
public ResponseEntity<?> customError(WebException e, HttpServletRequest request) {
@ExceptionHandler(value = CustomException.class)
public ResponseEntity<?> customError(CustomException e, HttpServletRequest request) {
return ResponseEntity
.status(e.getStatus())
.body(Response.error(e.getErrorCode().getErrorReason(), request.getRequestURI(), e.getMessage()));
}

@ExceptionHandler(value = DomainException.class)
public ResponseEntity<?> domainError(DomainException e, HttpServletRequest request) {
return ResponseEntity
.status(e.getStatus())
.body(Response.error(e.getErrorCode().getErrorReason(), request.getRequestURI(), e.getMessage()));
}

@ExceptionHandler(value = InfraException.class)
public ResponseEntity<?> infraError(InfraException e, HttpServletRequest request) {
return ResponseEntity
.status(e.getStatus())
.body(Response.error(e.getErrorCode().getErrorReason(), request.getRequestURI(), e.getMessage()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ public JwtAuthenticationEntryPoint(@Qualifier("handlerExceptionResolver") Handle

@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException){

if (isExceptionInSecurityFilter(request)) {
resolver.resolveException(request, response, null, (Exception) request.getAttribute("exception"));
return;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
);

http.addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class);
// http.addFilterBefore(new JwtExceptionHandleFilter(), JwtTokenFilter.class);
return http.build();
}

Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package core.startup.mealtoktok.domain.alarm;

public record Alarm (
String title,
String body
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package core.startup.mealtoktok.domain.alarm;

import core.startup.mealtoktok.domain.user.User;

public interface AlarmSender {
void send(User user, Alarm alarm);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package core.startup.mealtoktok.domain.alarm.exception;

import core.startup.mealtoktok.common.exception.BaseErrorCode;
import core.startup.mealtoktok.common.exception.ErrorReason;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum AlarmErrorCode implements BaseErrorCode {
ALARM_SEND_FAIL(500, "ALARM_500_1", "알람 전송에 실패했습니다.");

private final Integer status;
private final String errorCode;
private final String message;

@Override
public ErrorReason getErrorReason() {
return ErrorReason.of(status, errorCode, message);
}
}
3 changes: 3 additions & 0 deletions infra/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ dependencies {
implementation group: 'org.springframework.cloud', name: 'spring-cloud-starter-openfeign', version: '4.1.3'
implementation 'org.springframework.cloud:spring-cloud-commons:4.1.4'

//FCM
implementation group: 'com.google.firebase', name: 'firebase-admin', version: '9.3.0'

//redis & cache
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-json'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package core.startup.mealtoktok.infra.notification;

import com.google.firebase.messaging.FirebaseMessaging;
import com.google.firebase.messaging.FirebaseMessagingException;
import com.google.firebase.messaging.MulticastMessage;
import com.google.firebase.messaging.Notification;
import core.startup.mealtoktok.domain.alarm.Alarm;
import core.startup.mealtoktok.domain.alarm.AlarmSender;
import core.startup.mealtoktok.domain.user.User;
import core.startup.mealtoktok.infra.notification.exception.AlarmSendFailException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
@Slf4j
public class FcmAlarmSender implements AlarmSender {

private final FirebaseMessaging firebaseMessaging;

@Override
public void send(User user, Alarm alarm) {
MulticastMessage message = makeMessage(user, alarm);
try {
firebaseMessaging.sendEachForMulticast(message);
} catch (FirebaseMessagingException e) {
log.error("userId : {} 님에게 알람 전송을 실패하였습니다.", user.getUserId(), e);
throw AlarmSendFailException.EXCEPTION;
}
}

private MulticastMessage makeMessage(User user, Alarm alarm) {
Notification notification = Notification.builder()
.setTitle(alarm.title())
.setBody(alarm.body())
.build();

return MulticastMessage.builder()
.setNotification(notification)
.addAllTokens(user.getDeviceTokens())
.build();
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package core.startup.mealtoktok.infra.notification.config;

import com.google.auth.oauth2.GoogleCredentials;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import com.google.firebase.messaging.FirebaseMessaging;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Base64;

@Configuration
public class FcmConfig {

@Value("${fcm.secret-key}")
private String fcmSecretKey;

@Bean
public FirebaseApp firebaseApp() throws IOException {
FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(getDecodedCredentials(fcmSecretKey))
.build();
return FirebaseApp.initializeApp(options);
}

@Bean
public FirebaseMessaging firebaseMessaging(FirebaseApp firebaseApp) {
return FirebaseMessaging.getInstance(firebaseApp);
}

private GoogleCredentials getDecodedCredentials(String encodedKey) throws IOException {
byte[] decodedKey = Base64.getDecoder().decode(encodedKey);
return GoogleCredentials.fromStream(new ByteArrayInputStream(decodedKey));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package core.startup.mealtoktok.infra.notification.exception;

import core.startup.mealtoktok.common.exception.InfraException;
import core.startup.mealtoktok.domain.alarm.exception.AlarmErrorCode;

public class AlarmSendFailException extends InfraException {

public static final AlarmSendFailException EXCEPTION = new AlarmSendFailException();

private AlarmSendFailException() {
super(AlarmErrorCode.ALARM_SEND_FAIL);
}
}
2 changes: 2 additions & 0 deletions infra/src/main/resources/application-infra.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ spring:
jpa:
open-in-view: false

fcm:
secret-key: ${FCM_SECRET_KEY}
---
spring:
config:
Expand Down

0 comments on commit b8ba444

Please sign in to comment.