diff --git a/eeos/build.gradle.kts b/eeos/build.gradle.kts index 058c2f17..9f8bc691 100644 --- a/eeos/build.gradle.kts +++ b/eeos/build.gradle.kts @@ -63,6 +63,10 @@ dependencies { // OpenFeign implementation(libs.spring.cloud.starter.openfeign) + + // Firebase Admin SDK + implementation(libs.firebase.admin) + } dependencyManagement { diff --git a/eeos/gradle/libs.versions.toml b/eeos/gradle/libs.versions.toml index f147f0d7..67f0a322 100644 --- a/eeos/gradle/libs.versions.toml +++ b/eeos/gradle/libs.versions.toml @@ -10,6 +10,7 @@ spotless = "7.2.1" asciidoctor = "4.0.2" epages-restdocs = "0.18.2" swagger = "5.10.3" +firebase-admin = "9.2.0" # Security jwt = "0.12.6" @@ -57,6 +58,9 @@ jbcrypt = { group = "org.mindrot", name = "jbcrypt", version.ref = "jbcrypt" } # Lombok lombok = { group = "org.projectlombok", name = "lombok" } +# Firebase Admin SDK +firebase-admin = { group = "com.google.firebase", name = "firebase-admin", version.ref = "firebase-admin" } + [plugins] spring-boot = { id = "org.springframework.boot", version.ref = "spring-boot" } spring-dependency-management = { id = "io.spring.dependency-management", version.ref = "spring-dependency-management" } diff --git a/eeos/src/main/java/com/blackcompany/eeos/config/security/SecurityFilterChainConfig.java b/eeos/src/main/java/com/blackcompany/eeos/config/security/SecurityFilterChainConfig.java index 891f53ce..8d90ee87 100644 --- a/eeos/src/main/java/com/blackcompany/eeos/config/security/SecurityFilterChainConfig.java +++ b/eeos/src/main/java/com/blackcompany/eeos/config/security/SecurityFilterChainConfig.java @@ -87,7 +87,8 @@ SecurityFilterChain authenticated(HttpSecurity httpSecurity) throws Exception { .requestMatchers("/api/admin/**") .requestMatchers("/api/team-building/**") .requestMatchers("/api/semester-periods/**") - .requestMatchers("/api/calendars/**"); + .requestMatchers("/api/calendars/**") + .requestMatchers("/api/pushToken", "/api/pushToken/**"); }); httpSecurity.authorizeHttpRequests( diff --git a/eeos/src/main/java/com/blackcompany/eeos/notification/application/dto/CreateMemberPushTokenRequest.java b/eeos/src/main/java/com/blackcompany/eeos/notification/application/dto/CreateMemberPushTokenRequest.java new file mode 100644 index 00000000..92d330a3 --- /dev/null +++ b/eeos/src/main/java/com/blackcompany/eeos/notification/application/dto/CreateMemberPushTokenRequest.java @@ -0,0 +1,16 @@ +package com.blackcompany.eeos.notification.application.dto; + +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Builder(toBuilder = true) +public class CreateMemberPushTokenRequest { + @NotBlank private String pushToken; + @NotBlank private String provider; +} diff --git a/eeos/src/main/java/com/blackcompany/eeos/notification/application/dto/DeleteMemberPushTokenRequest.java b/eeos/src/main/java/com/blackcompany/eeos/notification/application/dto/DeleteMemberPushTokenRequest.java new file mode 100644 index 00000000..78652475 --- /dev/null +++ b/eeos/src/main/java/com/blackcompany/eeos/notification/application/dto/DeleteMemberPushTokenRequest.java @@ -0,0 +1,15 @@ +package com.blackcompany.eeos.notification.application.dto; + +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Builder(toBuilder = true) +public class DeleteMemberPushTokenRequest { + @NotBlank private String pushToken; +} diff --git a/eeos/src/main/java/com/blackcompany/eeos/notification/application/exception/DeniedDeletePushTokenException.java b/eeos/src/main/java/com/blackcompany/eeos/notification/application/exception/DeniedDeletePushTokenException.java new file mode 100644 index 00000000..785c1a55 --- /dev/null +++ b/eeos/src/main/java/com/blackcompany/eeos/notification/application/exception/DeniedDeletePushTokenException.java @@ -0,0 +1,17 @@ +package com.blackcompany.eeos.notification.application.exception; + +import com.blackcompany.eeos.common.exception.BusinessException; +import org.springframework.http.HttpStatus; + +public class DeniedDeletePushTokenException extends BusinessException { + private static final String FAIL_CODE = "5008"; + + public DeniedDeletePushTokenException() { + super(FAIL_CODE, HttpStatus.FORBIDDEN); + } + + @Override + public String getMessage() { + return "토큰 수정 권한이 없습니다."; + } +} diff --git a/eeos/src/main/java/com/blackcompany/eeos/notification/application/exception/NotFoundNotificationProviderException.java b/eeos/src/main/java/com/blackcompany/eeos/notification/application/exception/NotFoundNotificationProviderException.java new file mode 100644 index 00000000..8e7bfecf --- /dev/null +++ b/eeos/src/main/java/com/blackcompany/eeos/notification/application/exception/NotFoundNotificationProviderException.java @@ -0,0 +1,20 @@ +package com.blackcompany.eeos.notification.application.exception; + +import com.blackcompany.eeos.common.exception.BusinessException; +import org.springframework.http.HttpStatus; + +public class NotFoundNotificationProviderException extends BusinessException { + + private static final String FAIL_CODE = "5006"; + private final String provider; + + public NotFoundNotificationProviderException(String provider) { + super(FAIL_CODE, HttpStatus.NOT_FOUND); + this.provider = provider; + } + + @Override + public String getMessage() { + return String.format("%s 는 존재하지 않는 외부 제공자 입니다.", provider); + } +} diff --git a/eeos/src/main/java/com/blackcompany/eeos/notification/application/exception/NotFoundPushTokenException.java b/eeos/src/main/java/com/blackcompany/eeos/notification/application/exception/NotFoundPushTokenException.java new file mode 100644 index 00000000..b9eb5272 --- /dev/null +++ b/eeos/src/main/java/com/blackcompany/eeos/notification/application/exception/NotFoundPushTokenException.java @@ -0,0 +1,19 @@ +package com.blackcompany.eeos.notification.application.exception; + +import com.blackcompany.eeos.common.exception.BusinessException; +import org.springframework.http.HttpStatus; + +public class NotFoundPushTokenException extends BusinessException { + + private static final String FAIL_CODE = "5007"; + + public NotFoundPushTokenException() { + + super(FAIL_CODE, HttpStatus.NOT_FOUND); + } + + @Override + public String getMessage() { + return "존재하지 않는 알림토큰 입니다."; + } +} diff --git a/eeos/src/main/java/com/blackcompany/eeos/notification/application/model/MemberPushTokenModel.java b/eeos/src/main/java/com/blackcompany/eeos/notification/application/model/MemberPushTokenModel.java new file mode 100644 index 00000000..8f5b3b6f --- /dev/null +++ b/eeos/src/main/java/com/blackcompany/eeos/notification/application/model/MemberPushTokenModel.java @@ -0,0 +1,24 @@ +package com.blackcompany.eeos.notification.application.model; + +import com.blackcompany.eeos.common.support.AbstractModel; +import java.time.LocalDateTime; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Builder(toBuilder = true) +@AllArgsConstructor +@NoArgsConstructor +public class MemberPushTokenModel implements AbstractModel { + private Long id; + private Long memberId; + private NotificationProvider notificationProvider; + private String pushToken; + private LocalDateTime lastActiveAt; + + public MemberPushTokenModel renew(Long memberId) { + return this.toBuilder().memberId(memberId).lastActiveAt(LocalDateTime.now()).build(); + } +} diff --git a/eeos/src/main/java/com/blackcompany/eeos/notification/application/model/NotificationProvider.java b/eeos/src/main/java/com/blackcompany/eeos/notification/application/model/NotificationProvider.java new file mode 100644 index 00000000..a7a9c6ec --- /dev/null +++ b/eeos/src/main/java/com/blackcompany/eeos/notification/application/model/NotificationProvider.java @@ -0,0 +1,24 @@ +package com.blackcompany.eeos.notification.application.model; + +import com.blackcompany.eeos.notification.application.exception.NotFoundNotificationProviderException; +import java.util.Arrays; +import lombok.Getter; + +@Getter +public enum NotificationProvider { + FCM("fcm"), + ETC("etc"); + + private final String provider; + + NotificationProvider(String provider) { + this.provider = provider; + } + + public static NotificationProvider find(String name) { + return Arrays.stream(NotificationProvider.values()) + .filter(provider -> provider.name().equalsIgnoreCase(name)) + .findFirst() + .orElseThrow(() -> new NotFoundNotificationProviderException(name)); + } +} diff --git a/eeos/src/main/java/com/blackcompany/eeos/notification/application/model/converter/MemberPushTokenEntityConverter.java b/eeos/src/main/java/com/blackcompany/eeos/notification/application/model/converter/MemberPushTokenEntityConverter.java new file mode 100644 index 00000000..ff1ee0c8 --- /dev/null +++ b/eeos/src/main/java/com/blackcompany/eeos/notification/application/model/converter/MemberPushTokenEntityConverter.java @@ -0,0 +1,33 @@ +package com.blackcompany.eeos.notification.application.model.converter; + +import com.blackcompany.eeos.common.support.converter.AbstractEntityConverter; +import com.blackcompany.eeos.notification.application.model.MemberPushTokenModel; +import com.blackcompany.eeos.notification.persistence.MemberPushTokenEntity; +import org.springframework.stereotype.Component; + +@Component +public class MemberPushTokenEntityConverter + implements AbstractEntityConverter { + + @Override + public MemberPushTokenModel from(MemberPushTokenEntity source) { + return MemberPushTokenModel.builder() + .id(source.getId()) + .memberId(source.getMemberId()) + .notificationProvider(source.getProvider()) + .pushToken(source.getPushToken()) + .lastActiveAt(source.getLastActiveAt()) + .build(); + } + + @Override + public MemberPushTokenEntity toEntity(MemberPushTokenModel source) { + return MemberPushTokenEntity.builder() + .id(source.getId()) + .memberId(source.getMemberId()) + .pushToken(source.getPushToken()) + .provider(source.getNotificationProvider()) + .lastActiveAt(source.getLastActiveAt()) + .build(); + } +} diff --git a/eeos/src/main/java/com/blackcompany/eeos/notification/application/repository/MemberPushTokenRepository.java b/eeos/src/main/java/com/blackcompany/eeos/notification/application/repository/MemberPushTokenRepository.java new file mode 100644 index 00000000..b7754175 --- /dev/null +++ b/eeos/src/main/java/com/blackcompany/eeos/notification/application/repository/MemberPushTokenRepository.java @@ -0,0 +1,26 @@ +package com.blackcompany.eeos.notification.application.repository; + +import com.blackcompany.eeos.notification.application.model.MemberPushTokenModel; +import com.blackcompany.eeos.notification.application.model.NotificationProvider; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; + +public interface MemberPushTokenRepository { + Optional findByPushToken(String pushToken); + + List findByMemberId(Long memberId); + + List findByMemberIdAndProvider( + Long memberId, NotificationProvider provider); + + Optional findByMemberIdAndPushToken(Long memberId, String pushToken); + + void deleteByPushToken(String pushToken); + + void deleteByMemberId(Long memberId); + + int deleteByUpdatedDateBefore(LocalDateTime updatedDate); + + MemberPushTokenModel save(MemberPushTokenModel memberPushToken); +} diff --git a/eeos/src/main/java/com/blackcompany/eeos/notification/application/service/NotificationTokenService.java b/eeos/src/main/java/com/blackcompany/eeos/notification/application/service/NotificationTokenService.java new file mode 100644 index 00000000..bdb01e86 --- /dev/null +++ b/eeos/src/main/java/com/blackcompany/eeos/notification/application/service/NotificationTokenService.java @@ -0,0 +1,67 @@ +package com.blackcompany.eeos.notification.application.service; + +import com.blackcompany.eeos.notification.application.dto.CreateMemberPushTokenRequest; +import com.blackcompany.eeos.notification.application.dto.DeleteMemberPushTokenRequest; +import com.blackcompany.eeos.notification.application.exception.DeniedDeletePushTokenException; +import com.blackcompany.eeos.notification.application.exception.NotFoundPushTokenException; +import com.blackcompany.eeos.notification.application.model.MemberPushTokenModel; +import com.blackcompany.eeos.notification.application.model.NotificationProvider; +import com.blackcompany.eeos.notification.application.repository.MemberPushTokenRepository; +import com.blackcompany.eeos.notification.application.usecase.CreateMemberPushTokenUsecase; +import com.blackcompany.eeos.notification.application.usecase.DeleteAllMemberPushTokensUsecase; +import com.blackcompany.eeos.notification.application.usecase.DeleteMemberPushTokenUsecase; +import java.time.LocalDateTime; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class NotificationTokenService + implements CreateMemberPushTokenUsecase, + DeleteAllMemberPushTokensUsecase, + DeleteMemberPushTokenUsecase { + + private final MemberPushTokenRepository memberPushTokenRepository; + + @Override + @Transactional + public void create(Long memberId, CreateMemberPushTokenRequest request) { + NotificationProvider provider = NotificationProvider.find(request.getProvider()); + + MemberPushTokenModel model = + memberPushTokenRepository + .findByMemberIdAndPushToken(memberId, request.getPushToken()) + .map(existingModel -> existingModel.renew(memberId)) + .orElseGet( + () -> + MemberPushTokenModel.builder() + .memberId(memberId) + .pushToken(request.getPushToken()) + .notificationProvider(provider) + .lastActiveAt(LocalDateTime.now()) + .build()); + + memberPushTokenRepository.save(model); + } + + @Override + @Transactional + public void deleteAllMemberPushTokens(Long memberId) { + memberPushTokenRepository.deleteByMemberId(memberId); + } + + @Override + @Transactional + public void delete(Long memberId, DeleteMemberPushTokenRequest request) { + MemberPushTokenModel model = + memberPushTokenRepository + .findByPushToken(request.getPushToken()) + .orElseThrow(NotFoundPushTokenException::new); + if (!model.getMemberId().equals(memberId)) { + throw new DeniedDeletePushTokenException(); + } + memberPushTokenRepository.deleteByPushToken(request.getPushToken()); + } +} diff --git a/eeos/src/main/java/com/blackcompany/eeos/notification/application/usecase/CreateMemberPushTokenUsecase.java b/eeos/src/main/java/com/blackcompany/eeos/notification/application/usecase/CreateMemberPushTokenUsecase.java new file mode 100644 index 00000000..fa8bdcd1 --- /dev/null +++ b/eeos/src/main/java/com/blackcompany/eeos/notification/application/usecase/CreateMemberPushTokenUsecase.java @@ -0,0 +1,7 @@ +package com.blackcompany.eeos.notification.application.usecase; + +import com.blackcompany.eeos.notification.application.dto.CreateMemberPushTokenRequest; + +public interface CreateMemberPushTokenUsecase { + void create(Long memberId, CreateMemberPushTokenRequest request); +} diff --git a/eeos/src/main/java/com/blackcompany/eeos/notification/application/usecase/DeleteAllMemberPushTokensUsecase.java b/eeos/src/main/java/com/blackcompany/eeos/notification/application/usecase/DeleteAllMemberPushTokensUsecase.java new file mode 100644 index 00000000..f7c0d0d6 --- /dev/null +++ b/eeos/src/main/java/com/blackcompany/eeos/notification/application/usecase/DeleteAllMemberPushTokensUsecase.java @@ -0,0 +1,5 @@ +package com.blackcompany.eeos.notification.application.usecase; + +public interface DeleteAllMemberPushTokensUsecase { + void deleteAllMemberPushTokens(Long memberId); +} diff --git a/eeos/src/main/java/com/blackcompany/eeos/notification/application/usecase/DeleteMemberPushTokenUsecase.java b/eeos/src/main/java/com/blackcompany/eeos/notification/application/usecase/DeleteMemberPushTokenUsecase.java new file mode 100644 index 00000000..088c02da --- /dev/null +++ b/eeos/src/main/java/com/blackcompany/eeos/notification/application/usecase/DeleteMemberPushTokenUsecase.java @@ -0,0 +1,7 @@ +package com.blackcompany.eeos.notification.application.usecase; + +import com.blackcompany.eeos.notification.application.dto.DeleteMemberPushTokenRequest; + +public interface DeleteMemberPushTokenUsecase { + void delete(Long memberId, DeleteMemberPushTokenRequest request); +} diff --git a/eeos/src/main/java/com/blackcompany/eeos/notification/persistence/JpaMemberPushTokenRepository.java b/eeos/src/main/java/com/blackcompany/eeos/notification/persistence/JpaMemberPushTokenRepository.java new file mode 100644 index 00000000..bc8a0eb1 --- /dev/null +++ b/eeos/src/main/java/com/blackcompany/eeos/notification/persistence/JpaMemberPushTokenRepository.java @@ -0,0 +1,30 @@ +package com.blackcompany.eeos.notification.persistence; + +import com.blackcompany.eeos.notification.application.model.NotificationProvider; +import java.sql.Timestamp; +import java.util.List; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +public interface JpaMemberPushTokenRepository extends JpaRepository { + + Optional findByPushToken(String token); + + List findByMemberId(Long memberId); + + List findByMemberIdAndProvider( + Long memberId, NotificationProvider provider); + + Optional findByMemberIdAndPushToken(Long memberId, String token); + + @Modifying + @Query("DELETE FROM MemberPushTokenEntity t WHERE t.memberId = :memberId") + void deleteByMemberId(@Param("memberId") Long memberId); + + void deleteByPushToken(String token); + + int deleteByUpdatedDateBefore(Timestamp updatedDate); +} diff --git a/eeos/src/main/java/com/blackcompany/eeos/notification/persistence/MemberPushTokenEntity.java b/eeos/src/main/java/com/blackcompany/eeos/notification/persistence/MemberPushTokenEntity.java new file mode 100644 index 00000000..c4f3bdaa --- /dev/null +++ b/eeos/src/main/java/com/blackcompany/eeos/notification/persistence/MemberPushTokenEntity.java @@ -0,0 +1,49 @@ +package com.blackcompany.eeos.notification.persistence; + +import com.blackcompany.eeos.common.persistence.BaseEntity; +import com.blackcompany.eeos.notification.application.model.NotificationProvider; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import java.time.LocalDateTime; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import lombok.experimental.SuperBuilder; + +@Getter +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@ToString +@SuperBuilder(toBuilder = true) +@Table(name = "member_push_token") +public class MemberPushTokenEntity extends BaseEntity { + + public static final String ENTITY_PREFIX = "member_push_token"; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = ENTITY_PREFIX + "_id", nullable = false) + private Long id; + + @Column(name = ENTITY_PREFIX + "_member_id", nullable = false) + private Long memberId; + + @Column(name = ENTITY_PREFIX + "_provider", nullable = false) + @Enumerated(EnumType.STRING) + private NotificationProvider provider; + + @Column(name = ENTITY_PREFIX + "_push_token", nullable = false, unique = true) + private String pushToken; + + @Column(name = ENTITY_PREFIX + "_last_activate_at", nullable = false) + private LocalDateTime lastActiveAt; +} diff --git a/eeos/src/main/java/com/blackcompany/eeos/notification/persistence/MemberPushTokenRepositoryImpl.java b/eeos/src/main/java/com/blackcompany/eeos/notification/persistence/MemberPushTokenRepositoryImpl.java new file mode 100644 index 00000000..f449b2dd --- /dev/null +++ b/eeos/src/main/java/com/blackcompany/eeos/notification/persistence/MemberPushTokenRepositoryImpl.java @@ -0,0 +1,68 @@ +package com.blackcompany.eeos.notification.persistence; + +import com.blackcompany.eeos.notification.application.model.MemberPushTokenModel; +import com.blackcompany.eeos.notification.application.model.NotificationProvider; +import com.blackcompany.eeos.notification.application.model.converter.MemberPushTokenEntityConverter; +import com.blackcompany.eeos.notification.application.repository.MemberPushTokenRepository; +import java.sql.Timestamp; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class MemberPushTokenRepositoryImpl implements MemberPushTokenRepository { + + private final JpaMemberPushTokenRepository jpaRepository; + + private final MemberPushTokenEntityConverter converter; + + @Override + public Optional findByPushToken(String pushToken) { + return jpaRepository.findByPushToken(pushToken).map(converter::from); + } + + @Override + public List findByMemberId(Long memberId) { + return jpaRepository.findByMemberId(memberId).stream().map(converter::from).toList(); + } + + @Override + public Optional findByMemberIdAndPushToken( + Long memberId, String pushToken) { + return jpaRepository.findByMemberIdAndPushToken(memberId, pushToken).map(converter::from); + } + + @Override + public List findByMemberIdAndProvider( + Long memberId, NotificationProvider provider) { + return jpaRepository.findByMemberIdAndProvider(memberId, provider).stream() + .map(converter::from) + .toList(); + } + + @Override + public void deleteByPushToken(String pushToken) { + jpaRepository.deleteByPushToken(pushToken); + } + + @Override + public void deleteByMemberId(Long memberId) { + jpaRepository.deleteByMemberId(memberId); + } + + @Override + public int deleteByUpdatedDateBefore(LocalDateTime updatedDate) { + Timestamp timestamp = Timestamp.valueOf(updatedDate); + return jpaRepository.deleteByUpdatedDateBefore(timestamp); + } + + @Override + public MemberPushTokenModel save(MemberPushTokenModel memberPushToken) { + MemberPushTokenEntity memberPushTokenEntity = converter.toEntity(memberPushToken); + MemberPushTokenEntity saved = jpaRepository.save(memberPushTokenEntity); + return converter.from(saved); + } +} diff --git a/eeos/src/main/java/com/blackcompany/eeos/notification/presentation/controller/MemberPushTokenController.java b/eeos/src/main/java/com/blackcompany/eeos/notification/presentation/controller/MemberPushTokenController.java new file mode 100644 index 00000000..9c10838e --- /dev/null +++ b/eeos/src/main/java/com/blackcompany/eeos/notification/presentation/controller/MemberPushTokenController.java @@ -0,0 +1,54 @@ +package com.blackcompany.eeos.notification.presentation.controller; + +import com.blackcompany.eeos.auth.presentation.support.Member; +import com.blackcompany.eeos.common.presentation.response.ApiResponse; +import com.blackcompany.eeos.common.presentation.response.ApiResponseBody.SuccessBody; +import com.blackcompany.eeos.common.presentation.response.ApiResponseGenerator; +import com.blackcompany.eeos.common.presentation.response.MessageCode; +import com.blackcompany.eeos.notification.application.dto.CreateMemberPushTokenRequest; +import com.blackcompany.eeos.notification.application.dto.DeleteMemberPushTokenRequest; +import com.blackcompany.eeos.notification.application.usecase.CreateMemberPushTokenUsecase; +import com.blackcompany.eeos.notification.application.usecase.DeleteAllMemberPushTokensUsecase; +import com.blackcompany.eeos.notification.application.usecase.DeleteMemberPushTokenUsecase; +import com.blackcompany.eeos.notification.presentation.docs.MemberPushTokenApi; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/pushToken") +public class MemberPushTokenController implements MemberPushTokenApi { + + private final CreateMemberPushTokenUsecase createMemberPushTokenUsecase; + private final DeleteMemberPushTokenUsecase deleteMemberPushTokenUsecase; + private final DeleteAllMemberPushTokensUsecase deleteAllMemberPushTokensUsecase; + + @Override + @PostMapping + public ApiResponse> create( + @Member Long memberId, @RequestBody @Valid CreateMemberPushTokenRequest request) { + createMemberPushTokenUsecase.create(memberId, request); + return ApiResponseGenerator.success(HttpStatus.CREATED, MessageCode.CREATE); + } + + @Override + @DeleteMapping + public ApiResponse> delete( + @Member Long memberId, @RequestBody @Valid DeleteMemberPushTokenRequest request) { + deleteMemberPushTokenUsecase.delete(memberId, request); + return ApiResponseGenerator.success(HttpStatus.OK, MessageCode.DELETE); + } + + @Override + @DeleteMapping("/all") + public ApiResponse> deleteAll(@Member Long memberId) { + deleteAllMemberPushTokensUsecase.deleteAllMemberPushTokens(memberId); + return ApiResponseGenerator.success(HttpStatus.OK, MessageCode.DELETE); + } +} diff --git a/eeos/src/main/java/com/blackcompany/eeos/notification/presentation/docs/MemberPushTokenApi.java b/eeos/src/main/java/com/blackcompany/eeos/notification/presentation/docs/MemberPushTokenApi.java new file mode 100644 index 00000000..b8c96d12 --- /dev/null +++ b/eeos/src/main/java/com/blackcompany/eeos/notification/presentation/docs/MemberPushTokenApi.java @@ -0,0 +1,25 @@ +package com.blackcompany.eeos.notification.presentation.docs; + +import com.blackcompany.eeos.common.presentation.response.ApiResponse; +import com.blackcompany.eeos.common.presentation.response.ApiResponseBody.SuccessBody; +import com.blackcompany.eeos.notification.application.dto.CreateMemberPushTokenRequest; +import com.blackcompany.eeos.notification.application.dto.DeleteMemberPushTokenRequest; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; + +@Tag(name = "알림토큰", description = "알림 토큰 API") +public interface MemberPushTokenApi { + + @Operation(summary = "알림 토큰 등록", description = "사용자의 기기 알림 토큰을 등록한다.") + ApiResponse> create( + @Parameter(hidden = true) Long memberId, @Valid CreateMemberPushTokenRequest request); + + @Operation(summary = "특정 기기 알림 토큰 삭제", description = "특정 기기 알림 토큰을 삭제한다.") + ApiResponse> delete( + @Parameter(hidden = true) Long memberId, @Valid DeleteMemberPushTokenRequest request); + + @Operation(summary = "알림 토큰 전체 삭제", description = "특정 유저의 알림토큰을 모두 삭제한다.") + ApiResponse> deleteAll(@Parameter(hidden = true) Long memberId); +}