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
2 changes: 1 addition & 1 deletion backend-env
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

import org.example.skuhomepage.domain.firebase.dto.TokenRequestDTO;
import org.example.skuhomepage.domain.firebase.dto.TopicRequestDTO;
import org.example.skuhomepage.domain.firebase.service.FCMService;
import org.example.skuhomepage.domain.firebase.service.FCMTopicService;
import org.example.skuhomepage.domain.firebase.service.DeviceTokenService;
import org.example.skuhomepage.domain.firebase.service.KeywordService;
import org.example.skuhomepage.global.apiPayload.ApiResponse;
import org.example.skuhomepage.global.enums.TopicGroup;
import org.example.skuhomepage.global.security.CustomUserDetails;
import org.springframework.web.bind.annotation.RestController;

Expand All @@ -15,44 +14,47 @@
@RequiredArgsConstructor
public class FCMController implements FCMControllerSpec {

private final FCMService fcmService;
private final FCMTopicService fcmTopicService;
// private final FCMService fcmService;
private final DeviceTokenService deviceTokenService;
private final KeywordService keywordService;

// private final FCMTopicService fcmTopicService;

@Override
public ApiResponse<Void> registerToken(TokenRequestDTO tokenReq, CustomUserDetails userDetails) {

fcmService.registerToken(tokenReq, userDetails.getUserId());
return ApiResponse.onSuccess(null);
}

@Override
public ApiResponse<Void> sendTestMessage(
TokenRequestDTO tokenReq, CustomUserDetails userDetails) {
fcmService.sendTestMessage(tokenReq);
deviceTokenService.registerToken(tokenReq, userDetails);
return ApiResponse.onSuccess(null);
}

@Override
public ApiResponse<Void> sendTestTopicMessage(
TopicRequestDTO topicReq, CustomUserDetails userDetails) {
fcmService.sendTestTopicMessage(topicReq);
return ApiResponse.onSuccess(null);
}
// @Override
// public ApiResponse<Void> sendTestMessage(
// TokenRequestDTO tokenReq, CustomUserDetails userDetails) {
// fcmService.sendTestMessage(tokenReq);
// return ApiResponse.onSuccess(null);
// }
//
// @Override
// public ApiResponse<Void> sendTestTopicMessage(
// TopicRequestDTO topicReq, CustomUserDetails userDetails) {
// fcmService.sendTestTopicMessage(topicReq);
// return ApiResponse.onSuccess(null);
// }

@Override
public ApiResponse<Void> topicRegister(TopicRequestDTO topicReq, CustomUserDetails userDetails) {
fcmTopicService.registerTopic(topicReq, userDetails.getUserId());
return ApiResponse.onSuccess(null);
}

@Override
public ApiResponse<Void> topicDelete(TopicRequestDTO topicReq, CustomUserDetails userDetails) {
fcmTopicService.deleteTopic(topicReq, userDetails.getUserId());
keywordService.registerKeyword(topicReq, userDetails);
return ApiResponse.onSuccess(null);
}

@Override
public ApiResponse<Void> topicList(TopicGroup topicGroup, CustomUserDetails userDetails) {
public ApiResponse<Void> topicDelete(String keyword, CustomUserDetails userDetails) {
keywordService.deleteKeyword(keyword, userDetails);
return ApiResponse.onSuccess(null);
}
//
// @Override
// public ApiResponse<Void> topicList(TopicGroup topicGroup, CustomUserDetails userDetails) {
// return ApiResponse.onSuccess(null);
// }
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
import org.example.skuhomepage.domain.firebase.dto.TokenRequestDTO;
import org.example.skuhomepage.domain.firebase.dto.TopicRequestDTO;
import org.example.skuhomepage.global.apiPayload.ApiResponse;
import org.example.skuhomepage.global.enums.TopicGroup;
import org.example.skuhomepage.global.security.CustomUserDetails;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;

@Tag(name = "알림", description = "FCM 알림 관련 API")
Expand All @@ -21,15 +19,15 @@ public interface FCMControllerSpec {
ApiResponse<Void> registerToken(
@RequestBody TokenRequestDTO req, @AuthenticationPrincipal CustomUserDetails userDetails);

@PostMapping("/test/send-token")
@Operation(summary = "테스트 알림 전송", description = "테스트 알림을 전송하는 API")
ApiResponse<Void> sendTestMessage(
@RequestBody TokenRequestDTO req, @AuthenticationPrincipal CustomUserDetails userDetails);

@PostMapping("/test/send-topic")
@Operation(summary = "테스트 토픽 알림 전송", description = "테스트 토픽 알림을 전송하는 API")
ApiResponse<Void> sendTestTopicMessage(
@RequestBody TopicRequestDTO req, @AuthenticationPrincipal CustomUserDetails userDetails);
// @PostMapping("/test/send-token")
// @Operation(summary = "테스트 알림 전송", description = "테스트 알림을 전송하는 API")
// ApiResponse<Void> sendTestMessage(
// @RequestBody TokenRequestDTO req, @AuthenticationPrincipal CustomUserDetails userDetails);
//
// @PostMapping("/test/send-topic")
// @Operation(summary = "테스트 토픽 알림 전송", description = "테스트 토픽 알림을 전송하는 API")
// ApiResponse<Void> sendTestTopicMessage(
// @RequestBody TopicRequestDTO req, @AuthenticationPrincipal CustomUserDetails userDetails);

@PostMapping("/keyword")
@Operation(summary = "키워드 등록", description = "키워드를 등록하는 API")
Expand All @@ -40,14 +38,13 @@ ApiResponse<Void> topicRegister(
@DeleteMapping("/keyword")
@Operation(summary = "키워드 삭제", description = "키워드를 삭제하는 API")
ApiResponse<Void> topicDelete(
@RequestBody TopicRequestDTO keywordReq,
@AuthenticationPrincipal CustomUserDetails userDetails);

@GetMapping("/keyword")
@Operation(summary = "키워드 조회", description = "키워드를 조회하는 API")
ApiResponse<Void> topicList(
@Parameter(description = "주제", example = "SKU_NOTICE", required = true) @RequestParam
TopicGroup topicGroup,
@Parameter(description = "사용자 정보", hidden = true) @AuthenticationPrincipal
CustomUserDetails userDetails);
@RequestBody String keyword, @AuthenticationPrincipal CustomUserDetails userDetails);

// @GetMapping("/keyword")
// @Operation(summary = "키워드 조회", description = "키워드를 조회하는 API")
// ApiResponse<Void> topicList(
// @Parameter(description = "주제", example = "SKU_NOTICE", required = true) @RequestParam
// TopicGroup topicGroup,
// @Parameter(description = "사용자 정보", hidden = true) @AuthenticationPrincipal
// CustomUserDetails userDetails);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
@Schema(description = "토큰 요청 DTO")
public class TokenRequestDTO {
@Schema(description = "토큰", example = "fcm_token")
private String token;
private String fcmToken;
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
package org.example.skuhomepage.domain.firebase.dto;

import org.example.skuhomepage.global.enums.TopicGroup;
import jakarta.validation.constraints.NotBlank;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
@Schema(description = "키워드 요청 DTO")
@NoArgsConstructor
public class TopicRequestDTO {
@Schema(description = "키워드", example = "장학금")
private String keyword;

@Schema(description = "토픽 그룹", example = "SKU_NOTICE")
private TopicGroup topicGroup;
@NotBlank private String keyword;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,23 @@
package org.example.skuhomepage.domain.firebase.entity;

public class UserDeviceToken {
import jakarta.persistence.*;

import org.example.skuhomepage.domain.mypage.entity.User;
import org.example.skuhomepage.global.common.BaseTimeEntity;

import lombok.*;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
public class UserDeviceToken extends BaseTimeEntity {
@Id @GeneratedValue private Long id;

@ManyToOne(fetch = FetchType.LAZY)
private User user;

@Column(nullable = false, unique = true)
private String fcmToken;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,26 @@
package org.example.skuhomepage.domain.firebase.entity;

public class UserKeyword {
import jakarta.persistence.*;

import org.example.skuhomepage.domain.mypage.entity.User;
import org.example.skuhomepage.global.common.BaseTimeEntity;

import lombok.*;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
public class UserKeyword extends BaseTimeEntity {
@Id @GeneratedValue private Long id;

@ManyToOne(fetch = FetchType.LAZY)
private User user;

@Column(nullable = false)
private String keyword;

@Column(nullable = false)
private String topicGroup;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,34 @@
package org.example.skuhomepage.domain.firebase.exception;

public class FirebaseErrorStatus {
import org.example.skuhomepage.global.apiPayload.code.BaseErrorCode;
import org.example.skuhomepage.global.apiPayload.code.ErrorReasonDTO;
import org.springframework.http.HttpStatus;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum FirebaseErrorStatus implements BaseErrorCode {
KEYWORD_NOT_VALID(HttpStatus.BAD_REQUEST, "KEYWORD404001", "중복된 키워드입니다"),
KEYWORD_NOT_FOUND(HttpStatus.NOT_FOUND, "KEYWORD404002", "존재하지 않는 키워드입니다.");

private final HttpStatus httpStatus;
private final String code;
private final String message;

@Override
public ErrorReasonDTO getReason() {
return ErrorReasonDTO.builder().message(message).code(code).isSuccess(false).build();
}

@Override
public ErrorReasonDTO getReasonHttpStatus() {
return ErrorReasonDTO.builder()
.message(message)
.code(code)
.isSuccess(false)
.httpStatus(httpStatus)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
package org.example.skuhomepage.domain.firebase.repository;

public interface UserDeviceTokenRepository {
import java.util.List;
import java.util.Optional;

import org.example.skuhomepage.domain.firebase.entity.UserDeviceToken;
import org.example.skuhomepage.domain.mypage.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserDeviceTokenRepository extends JpaRepository<UserDeviceToken, Long> {
boolean existsByFcmToken(String fcmToken);

Optional<UserDeviceToken> findByFcmToken(String fcmToken);

List<UserDeviceToken> findAllByUser(User user);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
package org.example.skuhomepage.domain.firebase.repository;

public interface UserKeywordRepository {
import java.util.List;
import java.util.Optional;

import org.example.skuhomepage.domain.firebase.entity.UserKeyword;
import org.example.skuhomepage.domain.mypage.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserKeywordRepository extends JpaRepository<UserKeyword, Long> {
boolean existsByUserAndKeyword(User user, String keyword);

List<UserKeyword> findAllByUser(User user);

Optional<UserKeyword> findByUserAndKeyword(User user, String keyword);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,51 @@
package org.example.skuhomepage.domain.firebase.service;

import org.example.skuhomepage.domain.firebase.dto.TokenRequestDTO;
import org.example.skuhomepage.domain.firebase.entity.UserDeviceToken;
import org.example.skuhomepage.domain.firebase.repository.UserDeviceTokenRepository;
import org.example.skuhomepage.domain.mypage.entity.User;
import org.example.skuhomepage.domain.mypage.exception.MyPageErrorStatus;
import org.example.skuhomepage.domain.mypage.repository.UserRepository;
import org.example.skuhomepage.global.exception.GeneralException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class DeviceTokenService {

private final UserRepository userRepository;
private final UserDeviceTokenRepository tokenRepository;

public void registerToken(TokenRequestDTO request, UserDetails userDetails) {
User user =
userRepository
.findByAccount(userDetails.getUsername())
.orElseThrow(() -> new GeneralException(MyPageErrorStatus.USER_NOT_FOUND));

tokenRepository
.findByFcmToken(request.getFcmToken())
.ifPresentOrElse(
existingToken -> {
// 이미 등록된 경우
if (!existingToken.getUser().getId().equals(user.getId())) {
existingToken =
UserDeviceToken.builder()
.id(existingToken.getId())
.fcmToken(existingToken.getFcmToken())
.user(user)
.build();
tokenRepository.save(existingToken);
}
},
() -> {
// 새로 등록
UserDeviceToken token =
UserDeviceToken.builder().user(user).fcmToken(request.getFcmToken()).build();

tokenRepository.save(token);
});
}
}
Loading
Loading