diff --git a/operation-api/src/main/java/org/sopt/makers/operation/app/member/dto/response/AttendanceTotalResponseDTO.java b/operation-api/src/main/java/org/sopt/makers/operation/app/member/dto/response/AttendanceTotalResponseDTO.java index 1bf8f22a..74ccea8a 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/app/member/dto/response/AttendanceTotalResponseDTO.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/app/member/dto/response/AttendanceTotalResponseDTO.java @@ -3,7 +3,7 @@ import java.util.List; import lombok.Builder; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.member.domain.Member; import static lombok.AccessLevel.PRIVATE; diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/api/AlarmApi.java b/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/api/AlarmApi.java index ff41e779..a11f21b9 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/api/AlarmApi.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/api/AlarmApi.java @@ -2,10 +2,11 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; -import org.sopt.makers.operation.alarm.domain.Status; +import org.sopt.makers.operation.alarm.domain.AlarmStatus; import org.sopt.makers.operation.dto.BaseResponse; import org.sopt.makers.operation.web.alarm.dto.request.AlarmInstantSendRequest; import org.sopt.makers.operation.web.alarm.dto.request.AlarmScheduleSendRequest; +import org.sopt.makers.operation.web.alarm.dto.request.AlarmScheduleStatusUpdateRequest; import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; @@ -79,7 +80,7 @@ public interface AlarmApi { ) ResponseEntity> getAlarms( @RequestParam(required = false) Integer generation, - @RequestParam(required = false) Status status, + @RequestParam(required = false) AlarmStatus status, Pageable pageable ); @@ -120,4 +121,23 @@ ResponseEntity> getAlarms( } ) ResponseEntity> deleteAlarm(@PathVariable long alarmId); + + @Operation( + summary = "알림 상태 업데이트 API (Web Hook)", + responses = { + @ApiResponse( + responseCode = "204", + description = "알림 상태 업데이트 성공" + ), + @ApiResponse( + responseCode = "404", + description = "알림이 존재하지 않습니다." + ), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류" + ) + } + ) + ResponseEntity> updateAlarmStatus(@PathVariable long alarmId, @RequestBody AlarmScheduleStatusUpdateRequest updateRequest); } diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/api/AlarmApiController.java b/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/api/AlarmApiController.java index d7908dc7..de920e5b 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/api/AlarmApiController.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/api/AlarmApiController.java @@ -5,25 +5,21 @@ import static org.sopt.makers.operation.code.success.web.AlarmSuccessCode.SUCCESS_GET_ALARMS; import static org.sopt.makers.operation.code.success.web.AlarmSuccessCode.SUCCESS_SCHEDULE_ALARM; import static org.sopt.makers.operation.code.success.web.AlarmSuccessCode.SUCCESS_SEND_ALARM; +import static org.sopt.makers.operation.code.success.web.AlarmSuccessCode.SUCCESS_UPDATE_ALARM_STATUS; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.val; -import org.sopt.makers.operation.alarm.domain.Status; +import org.sopt.makers.operation.alarm.domain.AlarmStatus; import org.sopt.makers.operation.dto.BaseResponse; import org.sopt.makers.operation.util.ApiResponseUtil; import org.sopt.makers.operation.web.alarm.dto.request.AlarmInstantSendRequest; import org.sopt.makers.operation.web.alarm.dto.request.AlarmScheduleSendRequest; +import org.sopt.makers.operation.web.alarm.dto.request.AlarmScheduleStatusUpdateRequest; import org.sopt.makers.operation.web.alarm.service.AlarmService; import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; @RestController @RequiredArgsConstructor @@ -34,23 +30,27 @@ public class AlarmApiController implements AlarmApi { @Override @PostMapping("/send") - public ResponseEntity> sendInstantAlarm(@Valid AlarmInstantSendRequest request) { - alarmService.sendInstantAlarm(request); - return ApiResponseUtil.success(SUCCESS_SEND_ALARM); + public ResponseEntity> sendInstantAlarm( + @Valid @RequestBody AlarmInstantSendRequest request + ) { + val result = alarmService.sendInstantAlarm(request); + return ApiResponseUtil.success(SUCCESS_SEND_ALARM, result); } @Override @PostMapping("/schedule") - public ResponseEntity> sendScheduleAlarm(@Valid AlarmScheduleSendRequest request) { - alarmService.sendScheduleAlarm(request); - return ApiResponseUtil.success(SUCCESS_SCHEDULE_ALARM); + public ResponseEntity> sendScheduleAlarm( + @Valid @RequestBody AlarmScheduleSendRequest request + ) { + val result = alarmService.sendScheduleAlarm(request); + return ApiResponseUtil.success(SUCCESS_SCHEDULE_ALARM, result); } @Override @GetMapping public ResponseEntity> getAlarms( @RequestParam(required = false) Integer generation, - @RequestParam(required = false) Status status, + @RequestParam(required = false) AlarmStatus status, Pageable pageable ) { val response = alarmService.getAlarms(generation, status, pageable); @@ -70,4 +70,16 @@ public ResponseEntity> deleteAlarm(@PathVariable long alarmId) { alarmService.deleteAlarm(alarmId); return ApiResponseUtil.success(SUCCESS_DELETE_ALARM); } + + @Override + @PatchMapping("/{alarmId}") + public ResponseEntity> updateAlarmStatus( + @PathVariable long alarmId, + @RequestBody AlarmScheduleStatusUpdateRequest updateRequest + ) { + alarmService.updateScheduleAlarm(alarmId, updateRequest); + return ApiResponseUtil.success(SUCCESS_UPDATE_ALARM_STATUS); + } + + } diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/request/AlarmInstantSendRequest.java b/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/request/AlarmInstantSendRequest.java index e852da27..27665f9c 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/request/AlarmInstantSendRequest.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/request/AlarmInstantSendRequest.java @@ -2,39 +2,48 @@ import jakarta.validation.constraints.NotNull; import java.util.List; + import org.sopt.makers.operation.alarm.domain.Alarm; -import org.sopt.makers.operation.alarm.domain.AlarmType; -import org.sopt.makers.operation.alarm.domain.Category; -import org.sopt.makers.operation.alarm.domain.LinkType; -import org.sopt.makers.operation.alarm.domain.Status; -import org.sopt.makers.operation.alarm.domain.TargetType; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.alarm.domain.AlarmTarget; +import org.sopt.makers.operation.alarm.domain.AlarmContent; +import org.sopt.makers.operation.alarm.domain.AlarmCategory; +import org.sopt.makers.operation.alarm.domain.AlarmTargetType; +import org.sopt.makers.operation.alarm.domain.AlarmTargetPart; +import org.sopt.makers.operation.alarm.domain.AlarmLinkType; public record AlarmInstantSendRequest( - @NotNull Integer createdGeneration, @NotNull String title, @NotNull String content, - @NotNull Category category, - @NotNull TargetType targetType, + @NotNull AlarmCategory category, + @NotNull AlarmTargetType targetType, + AlarmTargetPart part, + Integer createdGeneration, List targetList, - Part part, - LinkType linkType, + AlarmLinkType linkType, String link ) { + private AlarmTarget toTargetEntity() { + return switch (this.targetType) { + case ALL -> this.part.equals(AlarmTargetPart.ALL) + ? AlarmTarget.all() + : AlarmTarget.partialForAll(this.part, this.targetList); + case ACTIVE -> AlarmTarget.partialForActive(this.createdGeneration, this.part, this.targetList); + case CSV -> AlarmTarget.partialForCsv(this.targetList); + }; + } + + private AlarmContent toContentEntity() { + return switch (this.linkType) { + case WEB -> AlarmContent.withWebLink(this.title, this.content, this.category, this.link); + case APP -> AlarmContent.withAppLink(this.title, this.content, this.category, this.link); + case NONE -> AlarmContent.withoutLink(this.title, this.content, this.category); + }; + } + public Alarm toEntity() { - return Alarm.builder() - .createdGeneration(this.createdGeneration) - .category(this.category) - .title(this.title) - .content(this.content) - .targetType(this.targetType) - .alarmType(AlarmType.INSTANT) - .link(this.link) - .linkType(linkType) - .part(this.part) - .status(Status.COMPLETED) - .targetList(this.targetList) - .build(); + AlarmTarget targetEntity = this.toTargetEntity(); + AlarmContent contentEntity = this.toContentEntity(); + return Alarm.instant(targetEntity, contentEntity); } } diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/request/AlarmScheduleSendRequest.java b/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/request/AlarmScheduleSendRequest.java index 8f75bc2a..1916cd38 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/request/AlarmScheduleSendRequest.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/request/AlarmScheduleSendRequest.java @@ -1,43 +1,63 @@ package org.sopt.makers.operation.web.alarm.dto.request; import jakarta.validation.constraints.NotNull; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; import java.util.List; + +import lombok.val; + import org.sopt.makers.operation.alarm.domain.Alarm; -import org.sopt.makers.operation.alarm.domain.AlarmType; -import org.sopt.makers.operation.alarm.domain.Category; -import org.sopt.makers.operation.alarm.domain.LinkType; -import org.sopt.makers.operation.alarm.domain.Status; -import org.sopt.makers.operation.alarm.domain.TargetType; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.alarm.domain.AlarmTarget; +import org.sopt.makers.operation.alarm.domain.AlarmContent; +import org.sopt.makers.operation.alarm.domain.AlarmCategory; +import org.sopt.makers.operation.alarm.domain.AlarmTargetType; +import org.sopt.makers.operation.alarm.domain.AlarmTargetPart; +import org.sopt.makers.operation.alarm.domain.AlarmLinkType; +import static org.sopt.makers.operation.constant.AlarmConstant.ALARM_REQUEST_DATE_FORMAT; +import static org.sopt.makers.operation.constant.AlarmConstant.ALARM_REQUEST_TIME_FORMAT; public record AlarmScheduleSendRequest( - @NotNull Integer createdGeneration, @NotNull String title, @NotNull String content, - @NotNull Category category, - @NotNull TargetType targetType, + @NotNull AlarmCategory category, + @NotNull AlarmTargetType targetType, List targetList, - Part part, - LinkType linkType, + AlarmTargetPart part, + Integer createdGeneration, + AlarmLinkType linkType, String link, @NotNull String postDate, @NotNull String postTime ) { + private AlarmTarget toTargetEntity() { + return switch (this.targetType) { + case ALL -> this.part.equals(AlarmTargetPart.ALL) + ? AlarmTarget.all() + : AlarmTarget.partialForAll(this.part, this.targetList); + case ACTIVE -> AlarmTarget.partialForActive(this.createdGeneration, this.part, this.targetList); + case CSV -> AlarmTarget.partialForCsv(this.targetList); + }; + } + + private AlarmContent toContentEntity() { + return switch (this.linkType) { + case WEB -> AlarmContent.withWebLink(this.title, this.content, this.category, this.link); + case APP -> AlarmContent.withAppLink(this.title, this.content, this.category, this.link); + case NONE -> AlarmContent.withoutLink(this.title, this.content, this.category); + }; + } + public Alarm toEntity() { - return Alarm.builder() - .createdGeneration(this.createdGeneration) - .category(this.category) - .title(this.title) - .content(this.content) - .targetType(this.targetType) - .alarmType(AlarmType.RESERVED) - .link(this.link) - .linkType(linkType) - .part(this.part) - .status(Status.SCHEDULED) - .targetList(this.targetList) - .build(); + AlarmTarget targetEntity = this.toTargetEntity(); + AlarmContent contentEntity = this.toContentEntity(); + val date = LocalDate.parse(postDate, DateTimeFormatter.ofPattern(ALARM_REQUEST_DATE_FORMAT)); + val time = LocalTime.parse(postTime, DateTimeFormatter.ofPattern(ALARM_REQUEST_TIME_FORMAT)); + return Alarm.scheduled(targetEntity, contentEntity, LocalDateTime.of(date, time)); } } diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/request/AlarmScheduleStatusUpdateRequest.java b/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/request/AlarmScheduleStatusUpdateRequest.java new file mode 100644 index 00000000..4ed5147c --- /dev/null +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/request/AlarmScheduleStatusUpdateRequest.java @@ -0,0 +1,10 @@ +package org.sopt.makers.operation.web.alarm.dto.request; + +import jakarta.validation.constraints.NotNull; + +import java.time.LocalDateTime; + +public record AlarmScheduleStatusUpdateRequest( + @NotNull LocalDateTime sendAt +) { +} diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/response/AlarmCreateResponse.java b/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/response/AlarmCreateResponse.java index d6e237c2..8c9d961d 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/response/AlarmCreateResponse.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/response/AlarmCreateResponse.java @@ -1,6 +1,6 @@ package org.sopt.makers.operation.web.alarm.dto.response; -import static lombok.AccessLevel.*; +import static lombok.AccessLevel.PRIVATE; import org.sopt.makers.operation.alarm.domain.Alarm; @@ -8,12 +8,12 @@ @Builder(access = PRIVATE) public record AlarmCreateResponse( - long alarmId + long id ) { public static AlarmCreateResponse of(Alarm alarm) { return AlarmCreateResponse.builder() - .alarmId(alarm.getId()) + .id(alarm.getId()) .build(); } } diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/response/AlarmGetResponse.java b/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/response/AlarmGetResponse.java index 34bbdd56..93cf479b 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/response/AlarmGetResponse.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/response/AlarmGetResponse.java @@ -1,48 +1,76 @@ package org.sopt.makers.operation.web.alarm.dto.response; import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; -import static java.util.Objects.nonNull; import static lombok.AccessLevel.PRIVATE; +import static org.sopt.makers.operation.constant.AlarmConstant.ALARM_RESPONSE_DATE_FORMAT; +import static org.sopt.makers.operation.constant.AlarmConstant.ALARM_RESPONSE_TIME_FORMAT; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.Builder; +import lombok.val; import org.sopt.makers.operation.alarm.domain.Alarm; -import org.sopt.makers.operation.alarm.domain.Category; -import org.sopt.makers.operation.alarm.domain.LinkType; -import org.sopt.makers.operation.alarm.domain.TargetType; -import org.sopt.makers.operation.common.domain.Part; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Objects; @Builder(access = PRIVATE) public record AlarmGetResponse( - Category category, + String status, + String sendType, + String targetType, + String targetPart, + @JsonInclude(value = NON_NULL) + Integer targetGeneration, + String createDate, + String createTime, + String intendDate, + String intendTime, + @JsonInclude(value = NON_NULL) + String sendDate, @JsonInclude(value = NON_NULL) - String part, - TargetType targetType, + String sendTime, String title, String content, + String category, String link, - LinkType linkType, - String createdAt, - @JsonInclude(value = NON_NULL) - String sendAt + String linkType ) { public static AlarmGetResponse of(Alarm alarm) { + val alarmContent = alarm.getContent(); + val alarmTarget = alarm.getTarget(); + val createdAt = alarm.getCreatedDate(); + val intendedAt = alarm.getIntendedAt(); + val sendAt = alarm.getSendAt(); return AlarmGetResponse.builder() - .category(alarm.getCategory()) - .part(getPartName(alarm.getPart())) - .targetType(alarm.getTargetType()) - .title(alarm.getTitle()) - .content(alarm.getContent()) - .link(alarm.getLink()) - .linkType(alarm.getLinkType()) - .createdAt(alarm.getCreatedDate().toString()) - .sendAt(alarm.getSendAt()) + .status(alarm.getStatus().getDescription()) + .sendType(alarm.getType().getDescription()) + .targetType(alarmTarget.getTargetType().getName()) + .targetPart(alarmTarget.getTargetPart().getName()) + .targetGeneration(alarmTarget.getGeneration()) + .createDate(covertToDate(createdAt)).createTime(covertToTime(createdAt)) + .intendDate(covertToDate(intendedAt)).intendTime(covertToTime(intendedAt)) + .sendDate(covertToDate(sendAt)).sendTime(covertToTime(sendAt)) + .category(alarmContent.getCategory().getName()) + .title(alarmContent.getTitle()).content(alarmContent.getContent()) + .link(alarmContent.getLinkPath()).linkType(alarmContent.getLinkType().getName()) .build(); } - private static String getPartName(Part part) { - return nonNull(part) ? part.getName() : null; + private static String covertToDate(LocalDateTime dateTime) { + if (Objects.isNull(dateTime)){ + return null; + } + return dateTime.toLocalDate() + .format(DateTimeFormatter.ofPattern(ALARM_RESPONSE_DATE_FORMAT)); } + private static String covertToTime(LocalDateTime dateTime) { + if (Objects.isNull(dateTime)){ + return null; + } + return dateTime.toLocalTime() + .format(DateTimeFormatter.ofPattern(ALARM_RESPONSE_TIME_FORMAT)); + } } diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/response/AlarmListGetResponse.java b/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/response/AlarmListGetResponse.java index 31e1e7fe..af9babc9 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/response/AlarmListGetResponse.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/dto/response/AlarmListGetResponse.java @@ -1,15 +1,18 @@ package org.sopt.makers.operation.web.alarm.dto.response; import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; -import static java.util.Objects.nonNull; import static lombok.AccessLevel.PRIVATE; +import static org.sopt.makers.operation.constant.AlarmConstant.*; import com.fasterxml.jackson.annotation.JsonInclude; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.List; import lombok.Builder; +import lombok.val; import org.sopt.makers.operation.alarm.domain.Alarm; -import org.sopt.makers.operation.alarm.domain.Status; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.constant.AlarmConstant; @Builder(access = PRIVATE) public record AlarmListGetResponse( @@ -18,42 +21,47 @@ public record AlarmListGetResponse( ) { public static AlarmListGetResponse of(List alarmList, int totalCount) { + val alarms = alarmList.stream().map(AlarmResponse::of).toList(); return AlarmListGetResponse.builder() - .alarms(alarmList.stream().map(AlarmResponse::of).toList()) + .alarms(alarms) .totalCount(totalCount) .build(); } @Builder(access = PRIVATE) private record AlarmResponse( - long alarmId, + long id, + String status, + String sendType, + String targetType, @JsonInclude(value = NON_NULL) - String part, + String targetPart, String category, - String title, - String content, + String intendAt, @JsonInclude(value = NON_NULL) String sendAt, - String alarmType, - Status status + String title, + String content ) { + private static final String DATETIME_FORMAT = String.join(" ", ALARM_RESPONSE_DATE_FORMAT, ALARM_RESPONSE_TIME_FORMAT); + private static String covertToResponseDateTime(LocalDateTime dateTime) { + return dateTime.format(DateTimeFormatter.ofPattern(DATETIME_FORMAT)); + } private static AlarmResponse of(Alarm alarm) { return AlarmResponse.builder() - .alarmId(alarm.getId()) - .part(getPartName(alarm.getPart())) - .category(alarm.getCategory().getName()) - .title(alarm.getTitle()) - .content(alarm.getContent()) - .sendAt(alarm.getSendAt()) - .alarmType(alarm.getAlarmType().getDescription()) - .status(alarm.getStatus()) + .id(alarm.getId()) + .status(alarm.getStatus().getDescription()) + .sendType(alarm.getType().getDescription()) + .targetType(alarm.getTarget().getTargetType().getName()) + .targetPart(alarm.getTarget().getTargetPart().getName()) + .category(alarm.getContent().getCategory().getName()) + .intendAt(covertToResponseDateTime(alarm.getIntendedAt())) + .sendAt(covertToResponseDateTime(alarm.getSendAt())) + .title(alarm.getContent().getTitle()) + .content(alarm.getContent().getContent()) .build(); } - private static String getPartName(Part part) { - return nonNull(part) ? part.getName() : null; - } - } } diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/service/AlarmService.java b/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/service/AlarmService.java index 732e5fdc..d967cee2 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/service/AlarmService.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/service/AlarmService.java @@ -1,21 +1,28 @@ package org.sopt.makers.operation.web.alarm.service; -import org.sopt.makers.operation.alarm.domain.Status; +import org.sopt.makers.operation.alarm.domain.AlarmStatus; + import org.sopt.makers.operation.web.alarm.dto.request.AlarmInstantSendRequest; import org.sopt.makers.operation.web.alarm.dto.request.AlarmScheduleSendRequest; + +import org.sopt.makers.operation.web.alarm.dto.request.AlarmScheduleStatusUpdateRequest; +import org.sopt.makers.operation.web.alarm.dto.response.AlarmCreateResponse; import org.sopt.makers.operation.web.alarm.dto.response.AlarmGetResponse; import org.sopt.makers.operation.web.alarm.dto.response.AlarmListGetResponse; + import org.springframework.data.domain.Pageable; public interface AlarmService { - void sendInstantAlarm(AlarmInstantSendRequest requestDTO); + AlarmCreateResponse sendInstantAlarm(AlarmInstantSendRequest requestDTO); - void sendScheduleAlarm(AlarmScheduleSendRequest request); + AlarmCreateResponse sendScheduleAlarm(AlarmScheduleSendRequest request); - AlarmListGetResponse getAlarms(Integer generation, Status status, Pageable pageable); + AlarmListGetResponse getAlarms(Integer generation, AlarmStatus status, Pageable pageable); AlarmGetResponse getAlarm(long alarmId); + void updateScheduleAlarm(long alarmId, AlarmScheduleStatusUpdateRequest request); + void deleteAlarm(long alarmId); } diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/service/AlarmServiceImpl.java b/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/service/AlarmServiceImpl.java index 9d79954c..908f5d29 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/service/AlarmServiceImpl.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/alarm/service/AlarmServiceImpl.java @@ -1,33 +1,34 @@ package org.sopt.makers.operation.web.alarm.service; -import static org.sopt.makers.operation.code.failure.AlarmFailureCode.INVALID_ALARM; +import static org.sopt.makers.operation.code.failure.AlarmFailureCode.NOT_FOUND_ALARM; import static org.sopt.makers.operation.code.failure.AlarmFailureCode.INVALID_ALARM_TARGET_TYPE; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Objects; import lombok.RequiredArgsConstructor; import lombok.val; + import org.sopt.makers.operation.alarm.domain.Alarm; -import org.sopt.makers.operation.alarm.domain.LinkType; -import org.sopt.makers.operation.alarm.domain.Status; -import org.sopt.makers.operation.alarm.domain.TargetType; +import org.sopt.makers.operation.alarm.domain.AlarmStatus; +import org.sopt.makers.operation.alarm.domain.AlarmTarget; +import org.sopt.makers.operation.alarm.domain.AlarmTargetType; import org.sopt.makers.operation.alarm.repository.AlarmRepository; -import org.sopt.makers.operation.client.alarm.AlarmManager; -import org.sopt.makers.operation.client.alarm.alarmServer.dto.AlarmSenderRequest; -import org.sopt.makers.operation.client.alarm.eventBridgeServer.dto.EventBridgeSenderRequest; -import org.sopt.makers.operation.common.domain.Part; -import org.sopt.makers.operation.config.ValueConfig; -import org.sopt.makers.operation.exception.AlarmException; +import org.sopt.makers.operation.client.alarm.dto.InstantAlarmRequest; +import org.sopt.makers.operation.client.alarm.dto.ScheduleAlarmRequest; import org.sopt.makers.operation.member.domain.Member; import org.sopt.makers.operation.member.repository.MemberRepository; + +import org.sopt.makers.operation.config.ValueConfig; +import org.sopt.makers.operation.client.alarm.AlarmManager; +import org.sopt.makers.operation.exception.AlarmException; + import org.sopt.makers.operation.web.alarm.dto.request.AlarmInstantSendRequest; import org.sopt.makers.operation.web.alarm.dto.request.AlarmScheduleSendRequest; +import org.sopt.makers.operation.web.alarm.dto.request.AlarmScheduleStatusUpdateRequest; import org.sopt.makers.operation.web.alarm.dto.response.AlarmGetResponse; +import org.sopt.makers.operation.web.alarm.dto.response.AlarmCreateResponse; import org.sopt.makers.operation.web.alarm.dto.response.AlarmListGetResponse; + import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -43,95 +44,82 @@ public class AlarmServiceImpl implements AlarmService { @Override @Transactional - public void sendInstantAlarm(AlarmInstantSendRequest request) { - val savedAlarm = alarmRepository.save(request.toEntity()); - val targets = getTargets(savedAlarm); - alarmManager.sendInstantAlarm(AlarmSenderRequest.of(savedAlarm, targets)); - savedAlarm.updateToSent(formatSendAt(LocalDateTime.now())); + public AlarmCreateResponse sendInstantAlarm(AlarmInstantSendRequest request) { + val alarm = request.toEntity(); + val alarmTarget = alarm.getTarget(); + + alarmTarget.setTargetIds(extractTargetIds(alarmTarget)); + + val savedAlarm = alarmRepository.save(alarm); + val alarmRequest = InstantAlarmRequest.of(savedAlarm); + + alarmManager.sendInstant(alarmRequest); + return AlarmCreateResponse.of(savedAlarm); } @Override @Transactional - public void sendScheduleAlarm(AlarmScheduleSendRequest request) { - val savedAlarm = alarmRepository.save(request.toEntity()); - val targets = getTargets(savedAlarm); - val sendAt = parseDateTime(request.postDate(), request.postTime()); - savedAlarm.updateToSent(formatSendAt(sendAt)); - - val linkType = request.linkType(); - val webLink = linkType == LinkType.WEB ? request.link() : null; - val deepLink = linkType == LinkType.APP ? request.link() : null; - - val eventBridgeRequest = EventBridgeSenderRequest.of( - valueConfig.getNOTIFICATION_KEY(), - valueConfig.getNOTIFICATION_HEADER_SERVICE(), - request.targetType().getAction(), - targets, - request.title(), - request.content(), - request.category(), - deepLink, - webLink - ); - - alarmManager.sendReservedAlarm(eventBridgeRequest, request.postDate(), request.postTime(), savedAlarm.getId()); + public AlarmCreateResponse sendScheduleAlarm(AlarmScheduleSendRequest request) { + val alarm = request.toEntity(); + val alarmTarget = alarm.getTarget(); + alarmTarget.setTargetIds(extractTargetIds(alarmTarget)); + val savedAlarm = alarmRepository.save(alarm); + + val scheduleAlarmRequest = ScheduleAlarmRequest.of(savedAlarm); + alarmManager.sendSchedule(scheduleAlarmRequest); + + return AlarmCreateResponse.of(savedAlarm); + } + + @Override + @Transactional(readOnly = true) + public AlarmGetResponse getAlarm(long alarmId) { + val alarm = findAlarm(alarmId); + return AlarmGetResponse.of(alarm); } @Override @Transactional(readOnly = true) - public AlarmListGetResponse getAlarms(Integer generation, Status status, Pageable pageable) { + public AlarmListGetResponse getAlarms(Integer generation, AlarmStatus status, Pageable pageable) { val alarms = alarmRepository.findOrderByCreatedDate(generation, status, pageable); val totalCount = alarmRepository.count(generation, status); return AlarmListGetResponse.of(alarms, totalCount); } @Override - @Transactional(readOnly = true) - public AlarmGetResponse getAlarm(long alarmId) { + @Transactional + public void deleteAlarm(long alarmId) { val alarm = findAlarm(alarmId); - return AlarmGetResponse.of(alarm); + alarmRepository.delete(alarm); } @Override @Transactional - public void deleteAlarm(long alarmId) { + public void updateScheduleAlarm(long alarmId, AlarmScheduleStatusUpdateRequest request) { val alarm = findAlarm(alarmId); - alarmRepository.delete(alarm); + alarm.updateStatusToComplete(request.sendAt()); } private Alarm findAlarm(long id) { return alarmRepository.findById(id) - .orElseThrow(() -> new AlarmException(INVALID_ALARM)); + .orElseThrow(() -> new AlarmException(NOT_FOUND_ALARM)); } - private List getTargets(Alarm alarm) { - return alarm.hasTargets() - ? alarm.getTargetList() - : getTargetsByActivityAndPart(alarm.getTargetType(), alarm.getPart()); - } + private List extractTargetIds(AlarmTarget target) { + val targetType = target.getTargetType(); + if (targetType.equals(AlarmTargetType.CSV)) { + return target.getTargetIds(); + } - private List getTargetsByActivityAndPart(TargetType targetType, Part part) { val members = switch (targetType) { - case ACTIVE -> memberRepository.find(valueConfig.getGENERATION(), part); case ALL -> memberRepository.findAll(); + case ACTIVE -> memberRepository.find(valueConfig.getGENERATION(), target.getTargetPart().toPartDomain()); default -> throw new AlarmException(INVALID_ALARM_TARGET_TYPE); }; - return members.stream() .map(Member::getPlaygroundId) .filter(Objects::nonNull) .map(String::valueOf) .toList(); } - - private LocalDateTime parseDateTime(String postDate, String postTime) { - val date = LocalDate.parse(postDate, DateTimeFormatter.ISO_LOCAL_DATE); - val time = LocalTime.parse(postTime, DateTimeFormatter.ofPattern("HH:mm")); - return LocalDateTime.of(date, time); - } - - private String formatSendAt(LocalDateTime dateTime) { - val formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm"); - return dateTime.format(formatter); - } } diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/attendnace/api/WebAttendanceApi.java b/operation-api/src/main/java/org/sopt/makers/operation/web/attendnace/api/WebAttendanceApi.java index 1efb6170..3964413e 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/attendnace/api/WebAttendanceApi.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/attendnace/api/WebAttendanceApi.java @@ -1,6 +1,6 @@ package org.sopt.makers.operation.web.attendnace.api; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.dto.BaseResponse; import org.sopt.makers.operation.web.attendnace.dto.request.SubAttendanceUpdateRequest; import org.springframework.data.domain.Pageable; diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/attendnace/api/WebAttendanceApiController.java b/operation-api/src/main/java/org/sopt/makers/operation/web/attendnace/api/WebAttendanceApiController.java index 062b682d..748d2e0e 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/attendnace/api/WebAttendanceApiController.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/attendnace/api/WebAttendanceApiController.java @@ -2,7 +2,7 @@ import static org.sopt.makers.operation.code.success.web.AttendanceSuccessCode.*; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.dto.BaseResponse; import org.sopt.makers.operation.util.ApiResponseUtil; import org.sopt.makers.operation.web.attendnace.dto.request.SubAttendanceUpdateRequest; diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/attendnace/service/WebAttendanceService.java b/operation-api/src/main/java/org/sopt/makers/operation/web/attendnace/service/WebAttendanceService.java index affade26..07fb9409 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/attendnace/service/WebAttendanceService.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/attendnace/service/WebAttendanceService.java @@ -1,6 +1,6 @@ package org.sopt.makers.operation.web.attendnace.service; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.web.attendnace.dto.request.SubAttendanceUpdateRequest; import org.sopt.makers.operation.web.attendnace.dto.response.AttendanceListByLectureGetResponse; import org.sopt.makers.operation.web.attendnace.dto.response.AttendanceListByMemberGetResponse; diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/attendnace/service/WebAttendanceServiceImpl.java b/operation-api/src/main/java/org/sopt/makers/operation/web/attendnace/service/WebAttendanceServiceImpl.java index b64ebca2..8c7e7db9 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/attendnace/service/WebAttendanceServiceImpl.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/attendnace/service/WebAttendanceServiceImpl.java @@ -4,7 +4,7 @@ import static org.sopt.makers.operation.code.failure.LectureFailureCode.*; import static org.sopt.makers.operation.code.failure.MemberFailureCode.*; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.attendance.domain.SubAttendance; import org.sopt.makers.operation.attendance.repository.attendance.AttendanceRepository; import org.sopt.makers.operation.attendance.repository.subAttendance.SubAttendanceRepository; diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/api/WebLectureApi.java b/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/api/WebLectureApi.java index 802ff563..5b2e5454 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/api/WebLectureApi.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/api/WebLectureApi.java @@ -1,6 +1,6 @@ package org.sopt.makers.operation.web.lecture.api; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.dto.BaseResponse; import org.sopt.makers.operation.web.lecture.dto.request.SubLectureStartRequest; import org.sopt.makers.operation.web.lecture.dto.request.LectureCreateRequest; diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/api/WebLectureApiController.java b/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/api/WebLectureApiController.java index 33913f1e..5b5a5a94 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/api/WebLectureApiController.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/api/WebLectureApiController.java @@ -2,7 +2,7 @@ import static org.sopt.makers.operation.code.success.web.LectureSuccessCode.*; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.dto.BaseResponse; import org.sopt.makers.operation.util.ApiResponseUtil; import org.sopt.makers.operation.web.lecture.dto.request.SubLectureStartRequest; diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/dto/request/LectureCreateRequest.java b/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/dto/request/LectureCreateRequest.java index 17c6f32c..ebd997b3 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/dto/request/LectureCreateRequest.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/dto/request/LectureCreateRequest.java @@ -6,7 +6,7 @@ import java.time.LocalDateTime; import java.time.format.DateTimeParseException; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.lecture.domain.Attribute; import org.sopt.makers.operation.lecture.domain.Lecture; import org.sopt.makers.operation.exception.DateTimeParseCustomException; diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/dto/response/LectureGetResponse.java b/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/dto/response/LectureGetResponse.java index c478c31a..77882e4a 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/dto/response/LectureGetResponse.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/dto/response/LectureGetResponse.java @@ -6,7 +6,7 @@ import java.time.LocalDateTime; import java.util.List; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.lecture.domain.Attribute; import org.sopt.makers.operation.lecture.domain.Lecture; import org.sopt.makers.operation.lecture.domain.LectureStatus; diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/dto/response/LectureListGetResponse.java b/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/dto/response/LectureListGetResponse.java index f1ef0c0f..3d030c49 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/dto/response/LectureListGetResponse.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/dto/response/LectureListGetResponse.java @@ -4,7 +4,7 @@ import java.util.List; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.lecture.domain.Attribute; import org.sopt.makers.operation.lecture.domain.Lecture; diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/service/WebLectureService.java b/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/service/WebLectureService.java index 8fa12dcb..a9a9b180 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/service/WebLectureService.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/service/WebLectureService.java @@ -1,6 +1,6 @@ package org.sopt.makers.operation.web.lecture.service; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.web.lecture.dto.request.SubLectureStartRequest; import org.sopt.makers.operation.web.lecture.dto.request.LectureCreateRequest; import org.sopt.makers.operation.web.lecture.dto.response.SubLectureStartResponse; diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/service/WebLectureServiceImpl.java b/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/service/WebLectureServiceImpl.java index 1ee5c9bf..21b9360a 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/service/WebLectureServiceImpl.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/lecture/service/WebLectureServiceImpl.java @@ -14,9 +14,9 @@ import org.sopt.makers.operation.attendance.domain.SubAttendance; import org.sopt.makers.operation.attendance.repository.attendance.AttendanceRepository; import org.sopt.makers.operation.attendance.repository.subAttendance.SubAttendanceRepository; -import org.sopt.makers.operation.client.alarm.alarmServer.AlarmSender; -import org.sopt.makers.operation.client.alarm.alarmServer.dto.AlarmSenderRequest; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.client.alarm.AlarmManager; +import org.sopt.makers.operation.client.alarm.dto.InstantAlarmRequest; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.config.ValueConfig; import org.sopt.makers.operation.exception.LectureException; import org.sopt.makers.operation.exception.SubLectureException; @@ -40,6 +40,8 @@ @RequiredArgsConstructor @Transactional(readOnly = true) public class WebLectureServiceImpl implements WebLectureService { + public static final String NULL = "null"; + public static final String WHITE_SPACE = " "; private final LectureRepository lectureRepository; private final SubLectureRepository subLectureRepository; @@ -47,7 +49,7 @@ public class WebLectureServiceImpl implements WebLectureService { private final SubAttendanceRepository subAttendanceRepository; private final MemberRepository memberRepository; - private final AlarmSender alarmSender; + private final AlarmManager alarmManager; private final ValueConfig valueConfig; @Override @@ -177,7 +179,14 @@ private Lecture getLectureReadyToEnd(long lectureId) { } private void sendAlarm(Lecture lecture) { - alarmSender.send(AlarmSenderRequest.of(lecture, valueConfig)); + val alarmMessageTitle = String.join(WHITE_SPACE, lecture.getName(), valueConfig.getALARM_MESSAGE_TITLE()); + val alarmMessageContent = valueConfig.getALARM_MESSAGE_CONTENT(); + val targets = lecture.getAttendances().stream() + .map(attendance -> String.valueOf(attendance.getMember().getPlaygroundId())) + .filter(id -> !id.equals(NULL)) + .toList(); + val alarmRequest = InstantAlarmRequest.of(alarmMessageTitle, alarmMessageContent, targets); + alarmManager.sendInstant(alarmRequest); } private Lecture getLectureToDelete(long lectureId) { diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/member/api/WebMemberApi.java b/operation-api/src/main/java/org/sopt/makers/operation/web/member/api/WebMemberApi.java index 9801990d..4a0a1f98 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/member/api/WebMemberApi.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/member/api/WebMemberApi.java @@ -1,6 +1,6 @@ package org.sopt.makers.operation.web.member.api; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.dto.BaseResponse; import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/member/api/WebMemberApiController.java b/operation-api/src/main/java/org/sopt/makers/operation/web/member/api/WebMemberApiController.java index 0f39709b..4200f4dc 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/member/api/WebMemberApiController.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/member/api/WebMemberApiController.java @@ -2,7 +2,7 @@ import static org.sopt.makers.operation.code.success.web.MemberSuccessCode.*; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.dto.BaseResponse; import org.sopt.makers.operation.util.ApiResponseUtil; import org.sopt.makers.operation.web.member.service.WebMemberService; diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/member/dto/response/MemberListGetResponse.java b/operation-api/src/main/java/org/sopt/makers/operation/web/member/dto/response/MemberListGetResponse.java index 477b28d9..330e52c9 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/member/dto/response/MemberListGetResponse.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/member/dto/response/MemberListGetResponse.java @@ -5,7 +5,7 @@ import java.util.List; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.attendance.domain.AttendanceStatus; import org.sopt.makers.operation.member.domain.Member; diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/member/service/WebMemberService.java b/operation-api/src/main/java/org/sopt/makers/operation/web/member/service/WebMemberService.java index 2c8edacb..42485d00 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/member/service/WebMemberService.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/member/service/WebMemberService.java @@ -1,6 +1,6 @@ package org.sopt.makers.operation.web.member.service; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.web.member.dto.response.MemberListGetResponse; import org.springframework.data.domain.Pageable; diff --git a/operation-api/src/main/java/org/sopt/makers/operation/web/member/service/WebMemberServiceImpl.java b/operation-api/src/main/java/org/sopt/makers/operation/web/member/service/WebMemberServiceImpl.java index c02a78eb..1ed17188 100644 --- a/operation-api/src/main/java/org/sopt/makers/operation/web/member/service/WebMemberServiceImpl.java +++ b/operation-api/src/main/java/org/sopt/makers/operation/web/member/service/WebMemberServiceImpl.java @@ -1,6 +1,6 @@ package org.sopt.makers.operation.web.member.service; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.member.repository.MemberRepository; import org.sopt.makers.operation.web.member.dto.response.MemberListGetResponse; import org.springframework.data.domain.Pageable; diff --git a/operation-common/src/main/java/org/sopt/makers/operation/code/failure/AlarmFailureCode.java b/operation-common/src/main/java/org/sopt/makers/operation/code/failure/AlarmFailureCode.java index 87c50ac8..d5ed7176 100644 --- a/operation-common/src/main/java/org/sopt/makers/operation/code/failure/AlarmFailureCode.java +++ b/operation-common/src/main/java/org/sopt/makers/operation/code/failure/AlarmFailureCode.java @@ -10,12 +10,19 @@ @RequiredArgsConstructor @Getter public enum AlarmFailureCode implements FailureCode { - FAIL_SEND_ALARM(BAD_REQUEST, "알림 즉시 발송에 실패하였습니다."), - FAIL_SCHEDULE_ALARM(BAD_REQUEST, "알림 예약 발송에 실패하였습니다."), - INVALID_ALARM(NOT_FOUND, "알림이 존재하지 않습니다."), + // 400 + INVALID_SEND_INSTANT_REQUEST(BAD_REQUEST, "유효하지 않은 요청 키/값이 존재합니다."), + INVALID_SEND_SCHEDULED_REQUEST(BAD_REQUEST, "유효하지 않은 요청 키/값이 존재합니다."), + INVALID_LINK(BAD_REQUEST, "지원하지 않는 링크입니다."), FAIL_INACTIVE_USERS(BAD_REQUEST, "비활동 유저 불러오기에 실패하였습니다."), INVALID_ALARM_TARGET_TYPE(BAD_REQUEST, "올바르지 않은 알림 타겟 타입입니다."), - INVALID_SCHEDULE_ALARM_FORMAT(BAD_REQUEST, "알림 예약 시간 포맷이 맞지 않습니다."); + INVALID_SCHEDULE_ALARM_FORMAT(BAD_REQUEST, "알림 예약 시간 포맷이 맞지 않습니다."), + FAIL_SEND_ALARM(BAD_REQUEST, "알림 즉시 발송에 실패하였습니다."), + FAIL_SCHEDULE_ALARM(BAD_REQUEST, "알림 예약 발송에 실패하였습니다."), + + // 404 + NOT_FOUND_ALARM(NOT_FOUND, "알림이 존재하지 않습니다."), + ; private final HttpStatus status; private final String message; diff --git a/operation-common/src/main/java/org/sopt/makers/operation/code/success/web/AlarmSuccessCode.java b/operation-common/src/main/java/org/sopt/makers/operation/code/success/web/AlarmSuccessCode.java index 37b16369..1e82f651 100644 --- a/operation-common/src/main/java/org/sopt/makers/operation/code/success/web/AlarmSuccessCode.java +++ b/operation-common/src/main/java/org/sopt/makers/operation/code/success/web/AlarmSuccessCode.java @@ -1,20 +1,27 @@ package org.sopt.makers.operation.code.success.web; -import static org.springframework.http.HttpStatus.OK; - import lombok.Getter; import lombok.RequiredArgsConstructor; import org.sopt.makers.operation.code.success.SuccessCode; import org.springframework.http.HttpStatus; +import static org.springframework.http.HttpStatus.*; + @RequiredArgsConstructor @Getter public enum AlarmSuccessCode implements SuccessCode { - SUCCESS_SEND_ALARM(OK, "알림 즉시 발송 성공"), - SUCCESS_GET_ALARMS(OK, "알림 리스트 조회 성공"), + // 200 SUCCESS_GET_ALARM(OK, "알림 상세 조회 성공"), - SUCCESS_DELETE_ALARM(OK, "알림 삭제 성공"), - SUCCESS_SCHEDULE_ALARM(OK, "알림 예약 발송 성공"); + SUCCESS_GET_ALARMS(OK, "알림 리스트 조회 성공"), + + // 201 + SUCCESS_SEND_ALARM(CREATED, "알림 즉시 발송 성공"), + SUCCESS_SCHEDULE_ALARM(CREATED, "알림 예약 발송 성공"), + + // 204 + SUCCESS_UPDATE_ALARM_STATUS(NO_CONTENT, "알림 상태 업데이트 성공"), + SUCCESS_DELETE_ALARM(NO_CONTENT, "알림 삭제 성공"), + ; private final HttpStatus status; private final String message; diff --git a/operation-common/src/main/java/org/sopt/makers/operation/constant/AlarmConstant.java b/operation-common/src/main/java/org/sopt/makers/operation/constant/AlarmConstant.java new file mode 100644 index 00000000..7082425b --- /dev/null +++ b/operation-common/src/main/java/org/sopt/makers/operation/constant/AlarmConstant.java @@ -0,0 +1,31 @@ +package org.sopt.makers.operation.constant; + +import lombok.RequiredArgsConstructor; + +import java.util.List; + +import static lombok.AccessLevel.PRIVATE; + +@RequiredArgsConstructor(access = PRIVATE) +public final class AlarmConstant { + private static final List SUPPORTED_APP_LINK = List.of( + "home", + "home/notification", + "home/mypage", + "home/attendance", + "home/attendance/attendance-modal", + "home/soptamp", + "home/soptamp/entire-ranking", + "home/soptamp/current-generation-ranking" + ); + + public static final String ALARM_REQUEST_DATE_FORMAT = "yyyy-MM-dd"; + public static final String ALARM_REQUEST_TIME_FORMAT = "HH:mm"; + public static final String ALARM_RESPONSE_DATE_FORMAT = "yyyy-MM-dd"; + public static final String ALARM_RESPONSE_TIME_FORMAT = "HH:mm"; + + public static boolean isSupportedAppLink(String link) { + return SUPPORTED_APP_LINK.contains(link); + } + +} diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/Alarm.java b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/Alarm.java index 4690d024..c8d9acc2 100644 --- a/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/Alarm.java +++ b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/Alarm.java @@ -1,117 +1,77 @@ package org.sopt.makers.operation.alarm.domain; -import static java.util.Objects.nonNull; - -import jakarta.persistence.Column; -import jakarta.persistence.Convert; +import jakarta.persistence.Id; +import jakarta.persistence.Table; import jakarta.persistence.Entity; +import jakarta.persistence.Embedded; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import lombok.Builder; + import lombok.Getter; +import lombok.Builder; import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; + import org.sopt.makers.operation.common.domain.BaseEntity; -import org.sopt.makers.operation.common.domain.Part; -import org.sopt.makers.operation.schedule.converter.StringListConverter; -@Entity -@NoArgsConstructor +import java.time.LocalDateTime; + +import static lombok.AccessLevel.PRIVATE; +import static lombok.AccessLevel.PROTECTED; + @Getter +@Entity +@Table(name = "alarms") +@Builder(access = PRIVATE) +@NoArgsConstructor(access = PROTECTED) +@AllArgsConstructor(access = PRIVATE) public class Alarm extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "alarm_id") private Long id; - private String title; - - @Column(columnDefinition = "TEXT") - private String content; - - @Column(nullable = false) - @Enumerated(value = EnumType.STRING) - private Category category; - - @Enumerated(value = EnumType.STRING) - private Part part; - - @Enumerated(value = EnumType.STRING) - private LinkType linkType; - - private String link; - - @Column(nullable = false) - @Enumerated(value = EnumType.STRING) - private AlarmType alarmType; - - @Enumerated(value = EnumType.STRING) - private TargetType targetType; - - @Enumerated(value = EnumType.STRING) - private Status status; - - @Column(columnDefinition = "TEXT", nullable = false) - @Convert(converter = StringListConverter.class) - private List targetList; - - private String sendAt; - - private Integer createdGeneration; - - @Builder - public Alarm( - Category category, - String title, - String content, - AlarmType alarmType, - String link, - LinkType linkType, - Part part, - Status status, - TargetType targetType, - List targetList, - Integer createdGeneration - ) { - this.category = category; - this.title = title; - this.content = content; - this.alarmType = alarmType; - this.linkType = linkType; - this.targetType = targetType; - setLink(link); - setTargetsInfo(part, targetList); - this.status = status; - this.createdGeneration = createdGeneration; - } + @Enumerated(EnumType.STRING) + private AlarmStatus status; - private void setLink(String link) { - if (nonNull(link)) { - this.link = link; - } - } + @Enumerated(EnumType.STRING) + private AlarmType type; + + @Embedded + private AlarmTarget target; - private void setTargetsInfo(Part part, List targetList) { - if (nonNull(targetList)) { - this.targetList = targetList; - } else { - this.part = part; - this.targetList = new ArrayList<>(); - } + @Embedded + private AlarmContent content; + + private LocalDateTime intendedAt; + + private LocalDateTime sendAt; + + public static Alarm instant(AlarmTarget target, AlarmContent content) { + return Alarm.builder() + .status(AlarmStatus.COMPLETED) + .type(AlarmType.INSTANT) + .target(target) + .content(content) + .intendedAt(LocalDateTime.now()) + .build(); } - public void updateToSent(String sendAt) { - this.sendAt = sendAt; - this.status = Status.COMPLETED; + public static Alarm scheduled(AlarmTarget target, AlarmContent content, LocalDateTime intendedAt) { + return Alarm.builder() + .status(AlarmStatus.SCHEDULED) + .type(AlarmType.RESERVED) + .target(target) + .content(content) + .intendedAt(intendedAt) + .build(); } - public boolean hasTargets() { - return Objects.nonNull(this.targetList) && this.targetList.size() > 0; + public void updateStatusToComplete(LocalDateTime successAt) { + this.status = AlarmStatus.COMPLETED; + this.sendAt = successAt; } + } diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/Category.java b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmCategory.java similarity index 88% rename from operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/Category.java rename to operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmCategory.java index 0e65900a..14ca9d40 100644 --- a/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/Category.java +++ b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmCategory.java @@ -5,7 +5,7 @@ @Getter @AllArgsConstructor -public enum Category { +public enum AlarmCategory { NOTICE("공지"), NEWS("소식"); diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmContent.java b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmContent.java new file mode 100644 index 00000000..3e99d472 --- /dev/null +++ b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmContent.java @@ -0,0 +1,73 @@ +package org.sopt.makers.operation.alarm.domain; + +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; + +import lombok.Getter; +import lombok.Builder; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; + +import org.sopt.makers.operation.exception.AlarmException; +import org.sopt.makers.operation.code.failure.AlarmFailureCode; + +import static lombok.AccessLevel.PRIVATE; +import static lombok.AccessLevel.PROTECTED; +import static org.sopt.makers.operation.constant.AlarmConstant.isSupportedAppLink; + +@Getter +@Builder(access = PRIVATE) +@NoArgsConstructor(access = PROTECTED) +@AllArgsConstructor(access = PRIVATE) +@Embeddable +public class AlarmContent { + + @Column(name = "category", nullable = false) + @Enumerated(EnumType.STRING) + AlarmCategory category; + + @Column(name = "title", nullable = false) + String title; + + @Column(name = "content", columnDefinition = "TEXT") + String content; + + @Column(name = "link_path", columnDefinition = "TEXT") + String linkPath; + + @Column(name = "link_type", nullable = false) + @Enumerated(EnumType.STRING) + AlarmLinkType linkType; + + public static AlarmContent withAppLink(String title, String content, AlarmCategory category, String link) { + if (!isSupportedAppLink(link)) { + throw new AlarmException(AlarmFailureCode.INVALID_LINK); + } + return AlarmContent.builder() + .title(title) + .content(content) + .linkPath(link) + .linkType(AlarmLinkType.APP) + .build(); + } + + public static AlarmContent withWebLink(String title, String content, AlarmCategory category, String link) { + return AlarmContent.builder() + .title(title) + .content(content) + .linkPath(link) + .linkType(AlarmLinkType.WEB) + .build(); + } + + public static AlarmContent withoutLink(String title, String content, AlarmCategory category) { + return AlarmContent.builder() + .title(title) + .content(content) + .linkType(AlarmLinkType.NONE) + .build(); + } + +} diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/LinkType.java b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmLinkType.java similarity index 55% rename from operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/LinkType.java rename to operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmLinkType.java index fcfeb5e3..4f419b5d 100644 --- a/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/LinkType.java +++ b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmLinkType.java @@ -5,6 +5,8 @@ @Getter @AllArgsConstructor -public enum LinkType { - WEB, APP +public enum AlarmLinkType { + WEB("웹"), APP("앱"), NONE("없음") + ; + private final String name; } diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmSendAction.java b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmSendAction.java new file mode 100644 index 00000000..07456eb2 --- /dev/null +++ b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmSendAction.java @@ -0,0 +1,13 @@ +package org.sopt.makers.operation.alarm.domain; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum AlarmSendAction { + SEND("send"), + SEND_ALL("sendAll"), + ; + private final String value; +} diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/Status.java b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmStatus.java similarity index 59% rename from operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/Status.java rename to operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmStatus.java index 40775c32..d1647433 100644 --- a/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/Status.java +++ b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmStatus.java @@ -5,9 +5,10 @@ @Getter @AllArgsConstructor -public enum Status { - SCHEDULED("발송 예약"), - COMPLETED("발송 완료"); +public enum AlarmStatus { + SCHEDULED("예약 완료"), + COMPLETED("발송 완료"), + FAILED("발송 실패"); private final String description; } diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmTarget.java b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmTarget.java new file mode 100644 index 00000000..d54165a0 --- /dev/null +++ b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmTarget.java @@ -0,0 +1,82 @@ +package org.sopt.makers.operation.alarm.domain; + +import jakarta.persistence.*; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; + +import org.sopt.makers.operation.schedule.converter.StringListConverter; + +import java.util.List; + +import static lombok.AccessLevel.PRIVATE; +import static lombok.AccessLevel.PROTECTED; + +@Getter +@Builder(access = PRIVATE) +@NoArgsConstructor(access = PROTECTED) +@AllArgsConstructor(access = PRIVATE) +@Embeddable +public class AlarmTarget { + + @Column(name = "action", nullable = false, updatable = false, insertable = false) + @Enumerated(EnumType.STRING) + private AlarmSendAction sendAction; + + @Column(name = "part", nullable = false, updatable = false, insertable = false) + @Enumerated(EnumType.STRING) + private AlarmTargetPart targetPart; + + @Column(name = "target_type", nullable = false, updatable = false, insertable = false) + @Enumerated(EnumType.STRING) + private AlarmTargetType targetType; + + @Column(name = "generation", updatable = false, insertable = false) + private Integer generation; + + @Setter + @Column(name = "targets", columnDefinition = "TEXT", updatable = false) + @Convert(converter = StringListConverter.class) + private List targetIds; + + public static AlarmTarget all() { + return AlarmTarget.builder() + .sendAction(AlarmSendAction.SEND_ALL) + .targetType(AlarmTargetType.ALL) + .targetPart(AlarmTargetPart.ALL) + .build(); + } + + public static AlarmTarget partialForAll(AlarmTargetPart targetPart, List targetIds) { + return AlarmTarget.builder() + .sendAction(AlarmSendAction.SEND) + .targetType(AlarmTargetType.ALL) + .targetPart(targetPart) + .targetIds(targetIds) + .build(); + } + + public static AlarmTarget partialForActive(int generation, AlarmTargetPart targetPart, List targetIds) { + return AlarmTarget.builder() + .sendAction(AlarmSendAction.SEND) + .targetType(AlarmTargetType.ACTIVE) + .generation(generation) + .targetPart(targetPart) + .targetIds(targetIds) + .build(); + } + + + public static AlarmTarget partialForCsv(List targetIds) { + return AlarmTarget.builder() + .sendAction(AlarmSendAction.SEND) + .targetType(AlarmTargetType.CSV) + .targetPart(AlarmTargetPart.UNDEFINED) + .targetIds(targetIds) + .build(); + } + +} diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmTargetPart.java b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmTargetPart.java new file mode 100644 index 00000000..0566681b --- /dev/null +++ b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmTargetPart.java @@ -0,0 +1,38 @@ +package org.sopt.makers.operation.alarm.domain; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.sopt.makers.operation.exception.AlarmException; +import org.sopt.makers.operation.member.domain.Part; + +import static lombok.AccessLevel.PRIVATE; +import static org.sopt.makers.operation.code.failure.AlarmFailureCode.INVALID_ALARM_TARGET_TYPE; + +@Getter +@RequiredArgsConstructor(access = PRIVATE) +public enum AlarmTargetPart { + ALL("전체"), + PLAN("기획"), + DESIGN("디자인"), + WEB("웹"), + ANDROID("안드로이드"), + iOS("iOS"), + SERVER("서버"), + UNDEFINED("없음") + ; + + private final String name; + + public Part toPartDomain() { + return switch (this) { + case ALL -> Part.ALL; + case PLAN -> Part.PLAN; + case DESIGN -> Part.DESIGN; + case ANDROID -> Part.ANDROID; + case iOS -> Part.IOS; + case WEB -> Part.WEB; + case SERVER -> Part.SERVER; + default -> throw new AlarmException(INVALID_ALARM_TARGET_TYPE); + }; + } +} diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmTargetType.java b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmTargetType.java new file mode 100644 index 00000000..7ec6c615 --- /dev/null +++ b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/AlarmTargetType.java @@ -0,0 +1,16 @@ +package org.sopt.makers.operation.alarm.domain; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum AlarmTargetType { + ALL("전체 회원", AlarmSendAction.SEND_ALL), + ACTIVE("활동 회원", AlarmSendAction.SEND), + CSV("CSV", AlarmSendAction.SEND), + ; + + private final String name; + private final AlarmSendAction action; +} diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/TargetType.java b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/TargetType.java deleted file mode 100644 index 371402d2..00000000 --- a/operation-domain/src/main/java/org/sopt/makers/operation/alarm/domain/TargetType.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.sopt.makers.operation.alarm.domain; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -@Getter -@AllArgsConstructor -public enum TargetType { - ALL("sendAll"), - ACTIVE("send"), - CSV("send"); - - private final String action; -} diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/alarm/repository/AlarmCustomRepository.java b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/repository/AlarmCustomRepository.java index 4b329f02..dc5e1269 100644 --- a/operation-domain/src/main/java/org/sopt/makers/operation/alarm/repository/AlarmCustomRepository.java +++ b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/repository/AlarmCustomRepository.java @@ -1,12 +1,13 @@ package org.sopt.makers.operation.alarm.repository; import java.util.List; + import org.sopt.makers.operation.alarm.domain.Alarm; -import org.sopt.makers.operation.alarm.domain.Status; +import org.sopt.makers.operation.alarm.domain.AlarmStatus; import org.springframework.data.domain.Pageable; public interface AlarmCustomRepository { - List findOrderByCreatedDate(Integer generation, Status status, Pageable pageable); + List findOrderByCreatedDate(Integer generation, AlarmStatus status, Pageable pageable); - int count(Integer generation, Status status); + int count(Integer generation, AlarmStatus status); } diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/alarm/repository/AlarmRepositoryImpl.java b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/repository/AlarmRepositoryImpl.java index 2c6c5456..48041aef 100644 --- a/operation-domain/src/main/java/org/sopt/makers/operation/alarm/repository/AlarmRepositoryImpl.java +++ b/operation-domain/src/main/java/org/sopt/makers/operation/alarm/repository/AlarmRepositoryImpl.java @@ -8,7 +8,7 @@ import java.util.List; import lombok.RequiredArgsConstructor; import org.sopt.makers.operation.alarm.domain.Alarm; -import org.sopt.makers.operation.alarm.domain.Status; +import org.sopt.makers.operation.alarm.domain.AlarmStatus; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Repository; @@ -18,7 +18,7 @@ public class AlarmRepositoryImpl implements AlarmCustomRepository { private final JPAQueryFactory queryFactory; @Override - public List findOrderByCreatedDate(Integer generation, Status status, Pageable pageable) { + public List findOrderByCreatedDate(Integer generation, AlarmStatus status, Pageable pageable) { return queryFactory .selectFrom(alarm) .where( @@ -32,7 +32,7 @@ public List findOrderByCreatedDate(Integer generation, Status status, Pag } @Override - public int count(Integer generation, Status status) { + public int count(Integer generation, AlarmStatus status) { return Math.toIntExact(queryFactory .select(alarm.count()) .from(alarm) @@ -44,10 +44,10 @@ public int count(Integer generation, Status status) { } private BooleanExpression generationEq(Integer generation) { - return nonNull(generation) ? alarm.createdGeneration.eq(generation) : null; + return nonNull(generation) ? alarm.target.generation.eq(generation) : null; } - private BooleanExpression statusEq(Status status) { + private BooleanExpression statusEq(AlarmStatus status) { return nonNull(status) ? alarm.status.eq(status) : null; } } diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/attendance/repository/attendance/AttendanceCustomRepository.java b/operation-domain/src/main/java/org/sopt/makers/operation/attendance/repository/attendance/AttendanceCustomRepository.java index 2dee226d..9e8ddcd2 100644 --- a/operation-domain/src/main/java/org/sopt/makers/operation/attendance/repository/attendance/AttendanceCustomRepository.java +++ b/operation-domain/src/main/java/org/sopt/makers/operation/attendance/repository/attendance/AttendanceCustomRepository.java @@ -2,7 +2,7 @@ import java.util.List; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.attendance.domain.Attendance; import org.sopt.makers.operation.lecture.domain.Lecture; import org.sopt.makers.operation.member.domain.Member; diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/attendance/repository/attendance/AttendanceRepositoryImpl.java b/operation-domain/src/main/java/org/sopt/makers/operation/attendance/repository/attendance/AttendanceRepositoryImpl.java index 9020a32e..10283ed7 100644 --- a/operation-domain/src/main/java/org/sopt/makers/operation/attendance/repository/attendance/AttendanceRepositoryImpl.java +++ b/operation-domain/src/main/java/org/sopt/makers/operation/attendance/repository/attendance/AttendanceRepositoryImpl.java @@ -1,10 +1,10 @@ package org.sopt.makers.operation.attendance.repository.attendance; -import static com.querydsl.core.types.dsl.Expressions.*; +import static com.querydsl.core.types.dsl.Expressions.stringTemplate; import static java.util.Objects.*; import static org.sopt.makers.operation.attendance.domain.QAttendance.*; import static org.sopt.makers.operation.attendance.domain.QSubAttendance.*; -import static org.sopt.makers.operation.common.domain.Part.*; +import static org.sopt.makers.operation.member.domain.Part.*; import static org.sopt.makers.operation.lecture.domain.QLecture.*; import static org.sopt.makers.operation.lecture.domain.QSubLecture.*; import static org.sopt.makers.operation.member.domain.QMember.*; @@ -15,7 +15,7 @@ import java.util.List; import org.sopt.makers.operation.config.ValueConfig; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.attendance.domain.Attendance; import org.sopt.makers.operation.lecture.domain.Lecture; import org.sopt.makers.operation.lecture.domain.LectureStatus; diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/lecture/domain/Lecture.java b/operation-domain/src/main/java/org/sopt/makers/operation/lecture/domain/Lecture.java index 29befe77..bd7e857b 100644 --- a/operation-domain/src/main/java/org/sopt/makers/operation/lecture/domain/Lecture.java +++ b/operation-domain/src/main/java/org/sopt/makers/operation/lecture/domain/Lecture.java @@ -7,7 +7,7 @@ import java.util.List; import org.sopt.makers.operation.common.domain.BaseEntity; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.attendance.domain.Attendance; import jakarta.persistence.Column; diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/lecture/repository/lecture/LectureCustomRepository.java b/operation-domain/src/main/java/org/sopt/makers/operation/lecture/repository/lecture/LectureCustomRepository.java index 738e1679..3de4beb5 100644 --- a/operation-domain/src/main/java/org/sopt/makers/operation/lecture/repository/lecture/LectureCustomRepository.java +++ b/operation-domain/src/main/java/org/sopt/makers/operation/lecture/repository/lecture/LectureCustomRepository.java @@ -1,9 +1,8 @@ package org.sopt.makers.operation.lecture.repository.lecture; import java.util.List; -import java.util.Optional; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.lecture.domain.Lecture; public interface LectureCustomRepository { diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/lecture/repository/lecture/LectureRepositoryImpl.java b/operation-domain/src/main/java/org/sopt/makers/operation/lecture/repository/lecture/LectureRepositoryImpl.java index 281831ae..4ead62b6 100644 --- a/operation-domain/src/main/java/org/sopt/makers/operation/lecture/repository/lecture/LectureRepositoryImpl.java +++ b/operation-domain/src/main/java/org/sopt/makers/operation/lecture/repository/lecture/LectureRepositoryImpl.java @@ -8,7 +8,7 @@ import java.time.LocalDateTime; import java.util.List; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.lecture.domain.Lecture; import org.sopt.makers.operation.lecture.domain.LectureStatus; import org.springframework.stereotype.Repository; diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/member/domain/Member.java b/operation-domain/src/main/java/org/sopt/makers/operation/member/domain/Member.java index b1f799b7..2109e027 100644 --- a/operation-domain/src/main/java/org/sopt/makers/operation/member/domain/Member.java +++ b/operation-domain/src/main/java/org/sopt/makers/operation/member/domain/Member.java @@ -4,7 +4,6 @@ import java.util.List; import org.sopt.makers.operation.attendance.domain.Attendance; -import org.sopt.makers.operation.common.domain.Part; import jakarta.persistence.Column; import jakarta.persistence.Entity; diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/common/domain/Part.java b/operation-domain/src/main/java/org/sopt/makers/operation/member/domain/Part.java similarity index 84% rename from operation-domain/src/main/java/org/sopt/makers/operation/common/domain/Part.java rename to operation-domain/src/main/java/org/sopt/makers/operation/member/domain/Part.java index e39f073c..a50b7740 100644 --- a/operation-domain/src/main/java/org/sopt/makers/operation/common/domain/Part.java +++ b/operation-domain/src/main/java/org/sopt/makers/operation/member/domain/Part.java @@ -1,4 +1,4 @@ -package org.sopt.makers.operation.common.domain; +package org.sopt.makers.operation.member.domain; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/member/repository/MemberCustomRepository.java b/operation-domain/src/main/java/org/sopt/makers/operation/member/repository/MemberCustomRepository.java index 93493bbe..af043ed1 100644 --- a/operation-domain/src/main/java/org/sopt/makers/operation/member/repository/MemberCustomRepository.java +++ b/operation-domain/src/main/java/org/sopt/makers/operation/member/repository/MemberCustomRepository.java @@ -2,7 +2,7 @@ import java.util.List; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.member.domain.Member; import org.springframework.data.domain.Pageable; diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/member/repository/MemberRepositoryImpl.java b/operation-domain/src/main/java/org/sopt/makers/operation/member/repository/MemberRepositoryImpl.java index 4f4a17f8..8e9dae26 100644 --- a/operation-domain/src/main/java/org/sopt/makers/operation/member/repository/MemberRepositoryImpl.java +++ b/operation-domain/src/main/java/org/sopt/makers/operation/member/repository/MemberRepositoryImpl.java @@ -1,12 +1,12 @@ package org.sopt.makers.operation.member.repository; import static java.util.Objects.*; -import static org.sopt.makers.operation.common.domain.Part.*; +import static org.sopt.makers.operation.member.domain.Part.*; import static org.sopt.makers.operation.member.domain.QMember.*; import java.util.List; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.member.domain.Member; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Repository; diff --git a/operation-domain/src/main/java/org/sopt/makers/operation/schedule/converter/StringListConverter.java b/operation-domain/src/main/java/org/sopt/makers/operation/schedule/converter/StringListConverter.java index 4f0fdc2d..cf6349e5 100644 --- a/operation-domain/src/main/java/org/sopt/makers/operation/schedule/converter/StringListConverter.java +++ b/operation-domain/src/main/java/org/sopt/makers/operation/schedule/converter/StringListConverter.java @@ -1,6 +1,7 @@ package org.sopt.makers.operation.schedule.converter; -import static com.fasterxml.jackson.databind.DeserializationFeature.*; +import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES; +import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES; import java.io.IOException; import java.util.List; @@ -9,7 +10,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; +@Converter public class StringListConverter implements AttributeConverter, String> { private static final ObjectMapper mapper = new ObjectMapper() .configure(FAIL_ON_UNKNOWN_PROPERTIES, false) @@ -26,8 +29,7 @@ public String convertToDatabaseColumn(List attribute) { @Override public List convertToEntityAttribute(String dbData) { - TypeReference> typeReference = new TypeReference<>() { - }; + TypeReference> typeReference = new TypeReference<>(){}; try { return mapper.readValue(dbData, typeReference); diff --git a/operation-domain/src/test/java/org/sopt/makers/operation/attendance/domain/AttendanceGetScoreTest.java b/operation-domain/src/test/java/org/sopt/makers/operation/attendance/domain/AttendanceGetScoreTest.java index 3d15bc1d..551bb16e 100644 --- a/operation-domain/src/test/java/org/sopt/makers/operation/attendance/domain/AttendanceGetScoreTest.java +++ b/operation-domain/src/test/java/org/sopt/makers/operation/attendance/domain/AttendanceGetScoreTest.java @@ -4,7 +4,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.dummy.AttendanceDummy; import org.sopt.makers.operation.dummy.LectureDummy; import org.sopt.makers.operation.dummy.MemberDummy; diff --git a/operation-domain/src/test/java/org/sopt/makers/operation/attendance/domain/AttendanceGetStatusTest.java b/operation-domain/src/test/java/org/sopt/makers/operation/attendance/domain/AttendanceGetStatusTest.java index a0877f15..eed7d5af 100644 --- a/operation-domain/src/test/java/org/sopt/makers/operation/attendance/domain/AttendanceGetStatusTest.java +++ b/operation-domain/src/test/java/org/sopt/makers/operation/attendance/domain/AttendanceGetStatusTest.java @@ -4,7 +4,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.dummy.AttendanceDummy; import org.sopt.makers.operation.dummy.LectureDummy; import org.sopt.makers.operation.dummy.MemberDummy; diff --git a/operation-domain/src/test/java/org/sopt/makers/operation/dummy/LectureDummy.java b/operation-domain/src/test/java/org/sopt/makers/operation/dummy/LectureDummy.java index 3527fd4c..f6e6981e 100644 --- a/operation-domain/src/test/java/org/sopt/makers/operation/dummy/LectureDummy.java +++ b/operation-domain/src/test/java/org/sopt/makers/operation/dummy/LectureDummy.java @@ -1,7 +1,7 @@ package org.sopt.makers.operation.dummy; import org.sopt.makers.operation.attendance.domain.Attendance; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.lecture.domain.Attribute; import org.sopt.makers.operation.lecture.domain.Lecture; import org.sopt.makers.operation.lecture.domain.LectureStatus; diff --git a/operation-domain/src/test/java/org/sopt/makers/operation/dummy/MemberDummy.java b/operation-domain/src/test/java/org/sopt/makers/operation/dummy/MemberDummy.java index c27010e9..d18a24d1 100644 --- a/operation-domain/src/test/java/org/sopt/makers/operation/dummy/MemberDummy.java +++ b/operation-domain/src/test/java/org/sopt/makers/operation/dummy/MemberDummy.java @@ -2,7 +2,7 @@ import lombok.Builder; import org.sopt.makers.operation.attendance.domain.Attendance; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.member.domain.Member; import org.sopt.makers.operation.member.domain.ObYb; diff --git a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/AlarmManager.java b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/AlarmManager.java index facd07a8..cfed0df0 100644 --- a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/AlarmManager.java +++ b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/AlarmManager.java @@ -1,24 +1,24 @@ package org.sopt.makers.operation.client.alarm; import lombok.RequiredArgsConstructor; -import org.sopt.makers.operation.client.alarm.alarmServer.AlarmSenderImpl; -import org.sopt.makers.operation.client.alarm.alarmServer.dto.AlarmSenderRequest; -import org.sopt.makers.operation.client.alarm.eventBridgeServer.EventBridgeSenderImpl; -import org.sopt.makers.operation.client.alarm.eventBridgeServer.dto.EventBridgeSenderRequest; +import org.sopt.makers.operation.alarm.domain.Alarm; +import org.sopt.makers.operation.client.alarm.dto.InstantAlarmRequest; +import org.sopt.makers.operation.client.alarm.dto.ScheduleAlarmRequest; import org.springframework.stereotype.Component; +import java.util.List; + @Component @RequiredArgsConstructor public class AlarmManager { + private final InstantAlarmSender instantAlarmSender; + private final ScheduleAlarmSender scheduleAlarmSender; - private final AlarmSenderImpl alarmSender; - private final EventBridgeSenderImpl eventBridgeSender; - - public void sendInstantAlarm(AlarmSenderRequest request) { - alarmSender.send(request); + public void sendInstant(InstantAlarmRequest alarmRequest) { + instantAlarmSender.sendAlarm(alarmRequest); } - - public void sendReservedAlarm(EventBridgeSenderRequest request, String postDate, String postTime, Long alarmId) { - eventBridgeSender.scheduleAlarm(request, postDate, postTime, alarmId); + public void sendSchedule(ScheduleAlarmRequest alarmRequest) { + scheduleAlarmSender.sendAlarm(alarmRequest); } + } diff --git a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/AlarmSender.java b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/AlarmSender.java new file mode 100644 index 00000000..d4b14ea1 --- /dev/null +++ b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/AlarmSender.java @@ -0,0 +1,7 @@ +package org.sopt.makers.operation.client.alarm; + +import org.sopt.makers.operation.client.alarm.dto.AlarmRequest; + +interface AlarmSender { + void sendAlarm(AlarmRequest alarmRequest); +} diff --git a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/InstantAlarmSender.java b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/InstantAlarmSender.java new file mode 100644 index 00000000..db24b6b0 --- /dev/null +++ b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/InstantAlarmSender.java @@ -0,0 +1,90 @@ +package org.sopt.makers.operation.client.alarm; + +import lombok.RequiredArgsConstructor; +import lombok.val; +import org.sopt.makers.operation.alarm.domain.AlarmLinkType; +import org.sopt.makers.operation.alarm.domain.AlarmTargetType; +import org.sopt.makers.operation.client.alarm.dto.AlarmRequest; +import org.sopt.makers.operation.client.alarm.dto.InstantAlarmRequest; +import org.sopt.makers.operation.config.ValueConfig; +import org.sopt.makers.operation.exception.AlarmException; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.RestTemplate; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static java.util.UUID.randomUUID; +import static org.sopt.makers.operation.code.failure.AlarmFailureCode.FAIL_SEND_ALARM; +import static org.springframework.http.MediaType.APPLICATION_JSON; + +@Component +@RequiredArgsConstructor +class InstantAlarmSender implements AlarmSender{ + private final RestTemplate restTemplate; + private final ValueConfig valueConfig; + + @Override + public void sendAlarm(AlarmRequest alarmRequest) { + val instantRequest = (InstantAlarmRequest) alarmRequest; + try { + val host = valueConfig.getNOTIFICATION_URL(); + val body = generateBody(instantRequest); + val headers = generateHeader(instantRequest); + val request = new HttpEntity<>(body, headers); + + restTemplate.postForEntity(host, request, InstantAlarmRequest.class); + } catch (HttpServerErrorException | HttpClientErrorException e) { + throw new AlarmException(FAIL_SEND_ALARM); + } + } + + private Map generateBody(InstantAlarmRequest instantRequest) { + val body = new HashMap<>(); + putRequiredAttributes(instantRequest, body); + putOptionalAttributes(instantRequest, body); + return body; + } + + private static void putRequiredAttributes(InstantAlarmRequest instantRequest, HashMap body) { + body.put("title", instantRequest.title()); + body.put("content", instantRequest.content()); + body.put("category", instantRequest.category()); + } + + private static void putOptionalAttributes(InstantAlarmRequest instantRequest, HashMap body) { + val isTargetAll = instantRequest.targetType().equals(AlarmTargetType.ALL); + val isWebLink = instantRequest.linkType().equals(AlarmLinkType.WEB); + val isAppLink = instantRequest.linkType().equals(AlarmLinkType.APP); + + if (!isTargetAll) { + body.put("userIds", instantRequest.targets()); + } + if (isWebLink) { + body.put("webLink", instantRequest.link()); + } else if (isAppLink) { + body.put("appLink", instantRequest.link()); + } + } + + private HttpHeaders generateHeader(InstantAlarmRequest instantRequest) { + val headers = new HttpHeaders(); + val apiKey = valueConfig.getNOTIFICATION_KEY(); + val actionValue = instantRequest.targetType().getAction().getValue(); + + headers.setContentType(APPLICATION_JSON); + headers.setAccept(Collections.singletonList(APPLICATION_JSON)); + + headers.add("action", actionValue); + headers.add("transactionId", randomUUID().toString()); + headers.add("service", "operation"); + headers.add("x-api-key", apiKey); + return headers; + } + +} diff --git a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/ScheduleAlarmSender.java b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/ScheduleAlarmSender.java new file mode 100644 index 00000000..5b2979c3 --- /dev/null +++ b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/ScheduleAlarmSender.java @@ -0,0 +1,143 @@ +package org.sopt.makers.operation.client.alarm; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import lombok.val; +import org.sopt.makers.operation.alarm.domain.AlarmLinkType; +import org.sopt.makers.operation.client.alarm.dto.AlarmRequest; +import org.sopt.makers.operation.client.alarm.dto.ScheduleAlarmRequest; +import org.sopt.makers.operation.client.alarm.dto.eventbridge.AlarmScheduleEventBridgeRequest; +import org.sopt.makers.operation.client.alarm.dto.eventbridge.AlarmScheduleEventBridgeBody; +import org.sopt.makers.operation.client.alarm.dto.eventbridge.AlarmScheduleEventBridgeHeader; +import org.sopt.makers.operation.code.failure.AlarmFailureCode; +import org.sopt.makers.operation.config.ValueConfig; +import org.sopt.makers.operation.exception.AlarmException; +import org.springframework.stereotype.Component; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.scheduler.SchedulerClient; +import software.amazon.awssdk.services.scheduler.model.CreateScheduleRequest; +import software.amazon.awssdk.services.scheduler.model.FlexibleTimeWindow; +import software.amazon.awssdk.services.scheduler.model.FlexibleTimeWindowMode; +import software.amazon.awssdk.services.scheduler.model.Target; + +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.UUID; + +import static org.sopt.makers.operation.constant.AlarmConstant.ALARM_REQUEST_DATE_FORMAT; +import static org.sopt.makers.operation.constant.AlarmConstant.ALARM_REQUEST_TIME_FORMAT; + +@Component +@RequiredArgsConstructor +class ScheduleAlarmSender implements AlarmSender{ + private final ValueConfig valueConfig; + private SchedulerClient schedulerClient; + private ObjectMapper objectMapper; + + @PostConstruct + private void init() { + val awsCredentials = AwsBasicCredentials.create(valueConfig.getAccessKey(), + valueConfig.getSecretKey()); + this.schedulerClient = SchedulerClient.builder() + .region(Region.AP_NORTHEAST_2) + .credentialsProvider(StaticCredentialsProvider.create(awsCredentials)) + .build(); + this.objectMapper = new ObjectMapper(); + } + + @Override + public void sendAlarm(AlarmRequest alarmRequest) { + ScheduleAlarmRequest scheduleRequest = (ScheduleAlarmRequest) alarmRequest; + try { + val name = generateEventName(scheduleRequest); + val cronExpression = generateScheduleCronExpression(scheduleRequest); + val eventJson = generateEventJson(scheduleRequest); + val target = generateEventTarget(eventJson); + + val createScheduleRequest = generateEvent(name, target, cronExpression); + schedulerClient.createSchedule(createScheduleRequest); + } catch (Exception e) { + e.printStackTrace(); + throw new AlarmException(AlarmFailureCode.FAIL_SCHEDULE_ALARM); + } + } + + private CreateScheduleRequest generateEvent(String eventName, Target eventTarget, String eventCronExpression) { + return CreateScheduleRequest.builder() + .name(eventName) + .target(eventTarget) + .scheduleExpression(eventCronExpression) + .actionAfterCompletion("DELETE") + .flexibleTimeWindow(FlexibleTimeWindow.builder() + .mode(FlexibleTimeWindowMode.OFF) + .build()) + .build(); + } + + private Target generateEventTarget(String eventJson) { + return Target.builder() + .roleArn(valueConfig.getEventBridgeRoleArn()) + .arn(valueConfig.getNotificationLambdaArn()) + .input(eventJson) + .build(); + } + + private String generateEventName(ScheduleAlarmRequest request) { + val dateData = request.scheduleDateTime().toLocalDate().format(DateTimeFormatter.ofPattern(ALARM_REQUEST_DATE_FORMAT)); + val timeData = request.scheduleDateTime().toLocalTime().format(DateTimeFormatter.ofPattern(ALARM_REQUEST_TIME_FORMAT)); + return String.format("%s_%s_%d", dateData, timeData, request.alarmId()); + } + + private String generateScheduleCronExpression(ScheduleAlarmRequest request) { + try { + val localDateTime = request.scheduleDateTime(); + val utcDateTime = localDateTime.atZone(ZoneId.systemDefault()) + .withZoneSameInstant(ZoneId.of("UTC")); + + return String.format("cron(%d %d %d %d ? %d)", + utcDateTime.getMinute(), + utcDateTime.getHour(), + utcDateTime.getDayOfMonth(), + utcDateTime.getMonthValue(), + utcDateTime.getYear()); + } catch (Exception e) { + throw new AlarmException(AlarmFailureCode.INVALID_SCHEDULE_ALARM_FORMAT); + } + } + + private String generateEventJson(ScheduleAlarmRequest request) throws JsonProcessingException { + val eventBody = convertToEventBridgeBody(request); + val eventHeader = convertToEventBridgeHeader(request); + + val eventBridgeRequest = AlarmScheduleEventBridgeRequest.of(eventHeader, eventBody); + return String.format("{\"detail\": %s}", objectMapper.writeValueAsString(eventBridgeRequest)); + } + + private AlarmScheduleEventBridgeHeader convertToEventBridgeHeader(ScheduleAlarmRequest request) { + return AlarmScheduleEventBridgeHeader.builder() + .alarmId(request.alarmId()) + .action(request.targetType().getAction().getValue()) + .xApiKey(valueConfig.getNOTIFICATION_KEY()) + .transactionId(UUID.randomUUID().toString()) + .service(valueConfig.getNOTIFICATION_HEADER_SERVICE()) + .build(); + } + + private AlarmScheduleEventBridgeBody convertToEventBridgeBody(ScheduleAlarmRequest request) { + val deepLink = request.linkType().equals(AlarmLinkType.APP) ? request.link() : null; + val webLink = request.linkType().equals(AlarmLinkType.WEB) ? request.link() : null; + return AlarmScheduleEventBridgeBody.builder() + .userIds(request.targets()) + .title(request.title()) + .content(request.content()) + .category(request.category()) + .deepLink(deepLink) + .webLink(webLink) + .build(); + } + +} diff --git a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/alarmServer/AlarmSender.java b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/alarmServer/AlarmSender.java deleted file mode 100644 index 8ef650d2..00000000 --- a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/alarmServer/AlarmSender.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.sopt.makers.operation.client.alarm.alarmServer; - -import org.sopt.makers.operation.client.alarm.alarmServer.dto.AlarmSenderRequest; - -public interface AlarmSender { - void send(AlarmSenderRequest request); -} diff --git a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/alarmServer/AlarmSenderImpl.java b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/alarmServer/AlarmSenderImpl.java deleted file mode 100644 index 3583effb..00000000 --- a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/alarmServer/AlarmSenderImpl.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.sopt.makers.operation.client.alarm.alarmServer; - -import static java.util.Objects.nonNull; -import static java.util.UUID.randomUUID; -import static org.sopt.makers.operation.code.failure.AlarmFailureCode.FAIL_SEND_ALARM; -import static org.springframework.http.MediaType.APPLICATION_JSON; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import lombok.RequiredArgsConstructor; -import lombok.val; -import org.sopt.makers.operation.client.alarm.alarmServer.dto.AlarmSenderRequest; -import org.sopt.makers.operation.config.ValueConfig; -import org.sopt.makers.operation.exception.AlarmException; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.stereotype.Component; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.HttpServerErrorException; -import org.springframework.web.client.RestTemplate; - -@Component -@RequiredArgsConstructor -public class AlarmSenderImpl implements AlarmSender { - - private final RestTemplate restTemplate; - private final ValueConfig valueConfig; - - @Override - public void send(AlarmSenderRequest request) { - try { - val host = valueConfig.getNOTIFICATION_URL(); - val entity = getEntity(request); - restTemplate.postForEntity(host, entity, AlarmSenderRequest.class); - } catch (HttpServerErrorException | HttpClientErrorException e) { - throw new AlarmException(FAIL_SEND_ALARM); - } - } - - private HttpEntity> getEntity(AlarmSenderRequest request) { - val alarmRequest = getAlarmRequest(request); - val headers = getHeaders(); - return new HttpEntity<>(alarmRequest, headers); - } - - private Map getAlarmRequest(AlarmSenderRequest request) { - val alarmRequest = new HashMap<>(); - val link = request.link(); - val linkKey = getLinkKey(link); - - if (!linkKey.isEmpty()) { - alarmRequest.put(linkKey, link); - } - - alarmRequest.put("userIds", request.targetList()); - alarmRequest.put("title", request.title()); - alarmRequest.put("content", request.content()); - alarmRequest.put("category", request.attribute()); - - return alarmRequest; - } - - private String getLinkKey(String link) { - val appLinkList = valueConfig.getAPP_LINK_LIST(); - val webLinkList = valueConfig.getWEB_LINK_LIST(); - - if (nonNull(link)) { - if (appLinkList.contains(link)) { - return "appLink"; - } else if (webLinkList.contains(link)) { - return "webLink"; - } - } - return ""; - } - - private HttpHeaders getHeaders() { - val headers = new HttpHeaders(); - val key = valueConfig.getNOTIFICATION_KEY(); - - headers.setContentType(APPLICATION_JSON); - headers.setAccept(Collections.singletonList(APPLICATION_JSON)); - headers.add("action", "send"); - headers.add("transactionId", randomUUID().toString()); - headers.add("service", "operation"); - headers.add("x-api-key", key); - - return headers; - } -} diff --git a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/alarmServer/dto/AlarmSenderRequest.java b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/alarmServer/dto/AlarmSenderRequest.java deleted file mode 100644 index 225fc992..00000000 --- a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/alarmServer/dto/AlarmSenderRequest.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.sopt.makers.operation.client.alarm.alarmServer.dto; - -import static org.sopt.makers.operation.alarm.domain.Category.NEWS; - -import java.util.List; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.val; -import org.sopt.makers.operation.alarm.domain.Alarm; -import org.sopt.makers.operation.alarm.domain.Category; -import org.sopt.makers.operation.config.ValueConfig; -import org.sopt.makers.operation.lecture.domain.Lecture; - -@Builder(access = AccessLevel.PRIVATE) -public record AlarmSenderRequest( - String title, - String content, - List targetList, - Category attribute, - String link -) { - - public static AlarmSenderRequest of(Alarm alarm, List targetList) { - return AlarmSenderRequest.builder() - .title(alarm.getTitle()) - .content(alarm.getContent()) - .targetList(targetList) - .attribute(alarm.getCategory()) - .link(alarm.getLink()) - .build(); - } - - public static AlarmSenderRequest of(Lecture lecture, ValueConfig valueConfig) { - val title = lecture.getName() + " " + valueConfig.getALARM_MESSAGE_TITLE(); - val content = valueConfig.getALARM_MESSAGE_CONTENT(); - val targetList = getTargetsFromLecture(lecture); - return AlarmSenderRequest.builder() - .title(title) - .content(content) - .targetList(targetList) - .attribute(NEWS) - .build(); - } - - private static List getTargetsFromLecture(Lecture lecture) { - return lecture.getAttendances().stream() - .map(attendance -> String.valueOf(attendance.getMember().getPlaygroundId())) - .filter(id -> !id.equals("null")) - .toList(); - } - -} diff --git a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/dto/AlarmRequest.java b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/dto/AlarmRequest.java new file mode 100644 index 00000000..19fe4831 --- /dev/null +++ b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/dto/AlarmRequest.java @@ -0,0 +1,4 @@ +package org.sopt.makers.operation.client.alarm.dto; + +public interface AlarmRequest { +} diff --git a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/dto/InstantAlarmRequest.java b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/dto/InstantAlarmRequest.java new file mode 100644 index 00000000..aeaec3da --- /dev/null +++ b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/dto/InstantAlarmRequest.java @@ -0,0 +1,48 @@ +package org.sopt.makers.operation.client.alarm.dto; + +import lombok.Builder; +import lombok.val; +import org.sopt.makers.operation.alarm.domain.Alarm; +import org.sopt.makers.operation.alarm.domain.AlarmCategory; +import org.sopt.makers.operation.alarm.domain.AlarmLinkType; +import org.sopt.makers.operation.alarm.domain.AlarmTargetType; + +import java.util.List; + +import static lombok.AccessLevel.PRIVATE; +import static org.sopt.makers.operation.alarm.domain.AlarmCategory.NEWS; + +@Builder(access = PRIVATE) +public record InstantAlarmRequest( + String title, + String content, + AlarmTargetType targetType, + List targets, + AlarmCategory category, + String link, + AlarmLinkType linkType + +) implements AlarmRequest { + + public static InstantAlarmRequest of(Alarm alarm) { + val content = alarm.getContent(); + return InstantAlarmRequest.builder() + .targetType(alarm.getTarget().getTargetType()) + .targets(alarm.getTarget().getTargetIds()) + .title(content.getTitle()) + .content(content.getContent()) + .category(content.getCategory()) + .linkType(content.getLinkType()).link(content.getLinkPath()) + .build(); + } + + public static InstantAlarmRequest of(String title, String content, List targetList) { + return InstantAlarmRequest.builder() + .targets(targetList) + .title(title) + .content(content) + .category(NEWS) + .build(); + } + +} diff --git a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/dto/ScheduleAlarmRequest.java b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/dto/ScheduleAlarmRequest.java new file mode 100644 index 00000000..7783e3cf --- /dev/null +++ b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/dto/ScheduleAlarmRequest.java @@ -0,0 +1,40 @@ +package org.sopt.makers.operation.client.alarm.dto; + +import lombok.AccessLevel; +import lombok.Builder; +import org.sopt.makers.operation.alarm.domain.Alarm; +import org.sopt.makers.operation.alarm.domain.AlarmCategory; +import org.sopt.makers.operation.alarm.domain.AlarmLinkType; +import org.sopt.makers.operation.alarm.domain.AlarmTargetType; + +import java.time.LocalDateTime; +import java.util.List; + +import static lombok.AccessLevel.PRIVATE; + +@Builder(access = PRIVATE) +public record ScheduleAlarmRequest( + long alarmId, + String title, + String content, + AlarmCategory category, + String link, + AlarmLinkType linkType, + AlarmTargetType targetType, + List targets, + LocalDateTime scheduleDateTime +) implements AlarmRequest { + public static ScheduleAlarmRequest of(Alarm alarm) { + return ScheduleAlarmRequest.builder() + .alarmId(alarm.getId()) + .title(alarm.getContent().getTitle()) + .content(alarm.getContent().getContent()) + .category(alarm.getContent().getCategory()) + .link(alarm.getContent().getLinkPath()) + .linkType(alarm.getContent().getLinkType()) + .targetType(alarm.getTarget().getTargetType()) + .targets(alarm.getTarget().getTargetIds()) + .scheduleDateTime(alarm.getIntendedAt()) + .build(); + } +} diff --git a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/dto/eventbridge/AlarmScheduleEventBridgeBody.java b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/dto/eventbridge/AlarmScheduleEventBridgeBody.java new file mode 100644 index 00000000..c84deb0c --- /dev/null +++ b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/dto/eventbridge/AlarmScheduleEventBridgeBody.java @@ -0,0 +1,17 @@ +package org.sopt.makers.operation.client.alarm.dto.eventbridge; + +import java.util.List; + +import lombok.Builder; +import org.sopt.makers.operation.alarm.domain.AlarmCategory; + +@Builder +public record AlarmScheduleEventBridgeBody( + List userIds, + String title, + String content, + AlarmCategory category, + String deepLink, + String webLink +) { +} diff --git a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/dto/eventbridge/AlarmScheduleEventBridgeHeader.java b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/dto/eventbridge/AlarmScheduleEventBridgeHeader.java new file mode 100644 index 00000000..89e12495 --- /dev/null +++ b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/dto/eventbridge/AlarmScheduleEventBridgeHeader.java @@ -0,0 +1,13 @@ +package org.sopt.makers.operation.client.alarm.dto.eventbridge; + +import lombok.Builder; + +@Builder +public record AlarmScheduleEventBridgeHeader( + String action, + String xApiKey, + String transactionId, + String service, + long alarmId +) { +} diff --git a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/dto/eventbridge/AlarmScheduleEventBridgeRequest.java b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/dto/eventbridge/AlarmScheduleEventBridgeRequest.java new file mode 100644 index 00000000..e491c1e6 --- /dev/null +++ b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/dto/eventbridge/AlarmScheduleEventBridgeRequest.java @@ -0,0 +1,13 @@ +package org.sopt.makers.operation.client.alarm.dto.eventbridge; + +public record AlarmScheduleEventBridgeRequest( + AlarmScheduleEventBridgeHeader header, + AlarmScheduleEventBridgeBody body +) { + public static AlarmScheduleEventBridgeRequest of( + AlarmScheduleEventBridgeHeader header, + AlarmScheduleEventBridgeBody body + ) { + return new AlarmScheduleEventBridgeRequest(header, body); + } +} diff --git a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/eventBridgeServer/EventBridgeSender.java b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/eventBridgeServer/EventBridgeSender.java deleted file mode 100644 index 1542906b..00000000 --- a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/eventBridgeServer/EventBridgeSender.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.sopt.makers.operation.client.alarm.eventBridgeServer; - - -import org.sopt.makers.operation.client.alarm.eventBridgeServer.dto.EventBridgeSenderRequest; - -public interface EventBridgeSender { - - void scheduleAlarm(EventBridgeSenderRequest request, String postDate, String postTime, Long alarmId); - -} diff --git a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/eventBridgeServer/EventBridgeSenderImpl.java b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/eventBridgeServer/EventBridgeSenderImpl.java deleted file mode 100644 index beaf7c7a..00000000 --- a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/eventBridgeServer/EventBridgeSenderImpl.java +++ /dev/null @@ -1,102 +0,0 @@ -package org.sopt.makers.operation.client.alarm.eventBridgeServer; - -import com.fasterxml.jackson.databind.ObjectMapper; -import jakarta.annotation.PostConstruct; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import lombok.RequiredArgsConstructor; -import lombok.val; -import org.sopt.makers.operation.client.alarm.eventBridgeServer.dto.EventBridgeSenderRequest; -import org.sopt.makers.operation.code.failure.AlarmFailureCode; -import org.sopt.makers.operation.config.ValueConfig; -import org.sopt.makers.operation.exception.AlarmException; -import org.springframework.stereotype.Component; -import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; -import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; -import software.amazon.awssdk.regions.Region; -import software.amazon.awssdk.services.scheduler.SchedulerClient; -import software.amazon.awssdk.services.scheduler.model.CreateScheduleRequest; -import software.amazon.awssdk.services.scheduler.model.FlexibleTimeWindow; -import software.amazon.awssdk.services.scheduler.model.FlexibleTimeWindowMode; -import software.amazon.awssdk.services.scheduler.model.Target; - -@Component -@RequiredArgsConstructor -public class EventBridgeSenderImpl implements EventBridgeSender { - - private SchedulerClient schedulerClient; - private final ValueConfig valueConfig; - private ObjectMapper objectMapper; - - @PostConstruct - private void init() { - val awsCredentials = AwsBasicCredentials.create(valueConfig.getAccessKey(), - valueConfig.getSecretKey()); - this.schedulerClient = SchedulerClient.builder() - .region(Region.AP_NORTHEAST_2) - .credentialsProvider(StaticCredentialsProvider.create(awsCredentials)) - .build(); - this.objectMapper = new ObjectMapper(); - } - - @Override - public void scheduleAlarm(EventBridgeSenderRequest request, String postDate, String postTime, Long alarmId) { - try { - val eventJson = String.format("{\"detail\": %s}", objectMapper.writeValueAsString(request)); - val formattedDate = formatCronExpression(postDate, postTime); - val scheduleName = createScheduleName(postDate, postTime, alarmId); - val target = createEventBridgeTarget(eventJson); - val createScheduleRequest = createScheduleRequest(target, scheduleName, formattedDate); - schedulerClient.createSchedule(createScheduleRequest); - } catch (Exception e) { - e.printStackTrace(); - throw new AlarmException(AlarmFailureCode.FAIL_SCHEDULE_ALARM); - } - } - - private String formatCronExpression(String postDate, String postTime) { - try { - val dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); - val localDateTime = LocalDateTime.parse(postDate + " " + postTime, dateFormatter); - - val utcDateTime = localDateTime.atZone(ZoneId.systemDefault()) - .withZoneSameInstant(ZoneId.of("UTC")); - - return String.format("cron(%d %d %d %d ? %d)", - utcDateTime.getMinute(), - utcDateTime.getHour(), - utcDateTime.getDayOfMonth(), - utcDateTime.getMonthValue(), - utcDateTime.getYear()); - } catch (Exception e) { - throw new AlarmException(AlarmFailureCode.INVALID_SCHEDULE_ALARM_FORMAT); - } - } - - private String createScheduleName(String postDate, String postTime, Long alarmId) { - val formattedTime = postTime.replace(":", "-"); - return String.format("%s_%s_%d", postDate, formattedTime, alarmId); - } - - private Target createEventBridgeTarget(String eventJson) { - return Target.builder() - .roleArn(valueConfig.getEventBridgeRoleArn()) - .arn(valueConfig.getNotificationLambdaArn()) - .input(eventJson) - .build(); - } - - private CreateScheduleRequest createScheduleRequest(Target target, String scheduleName, String formattedDate) { - return CreateScheduleRequest.builder() - .name(scheduleName) - .scheduleExpression(formattedDate) - .target(target) - .actionAfterCompletion("DELETE") - .flexibleTimeWindow(FlexibleTimeWindow.builder() - .mode(FlexibleTimeWindowMode.OFF) - .build()) - .build(); - } -} - diff --git a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/eventBridgeServer/dto/EventBridgeSenderRequest.java b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/eventBridgeServer/dto/EventBridgeSenderRequest.java deleted file mode 100644 index c22f37a1..00000000 --- a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/eventBridgeServer/dto/EventBridgeSenderRequest.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.sopt.makers.operation.client.alarm.eventBridgeServer.dto; - -import java.util.List; -import lombok.val; -import org.sopt.makers.operation.alarm.domain.Category; - -public record EventBridgeSenderRequest( - EventBridgeSenderRequestHeader header, - EventBridgeSenderRequestBody body -) { - public static EventBridgeSenderRequest of( - EventBridgeSenderRequestHeader header, - EventBridgeSenderRequestBody body - ) { - return new EventBridgeSenderRequest(header, body); - } - - public static EventBridgeSenderRequest of( - String xApiKey, String service, String action, - List userIds, String title, String content, Category category, String deepLink, String webLink - ) { - val header = EventBridgeSenderRequestHeader.of(xApiKey, action, service); - val body = EventBridgeSenderRequestBody.of(userIds, title, content, category, deepLink, - webLink); - return new EventBridgeSenderRequest(header, body); - } -} diff --git a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/eventBridgeServer/dto/EventBridgeSenderRequestBody.java b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/eventBridgeServer/dto/EventBridgeSenderRequestBody.java deleted file mode 100644 index 716eced9..00000000 --- a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/eventBridgeServer/dto/EventBridgeSenderRequestBody.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.sopt.makers.operation.client.alarm.eventBridgeServer.dto; - -import java.util.List; -import org.sopt.makers.operation.alarm.domain.Category; - -public record EventBridgeSenderRequestBody( - List userIds, - String title, - String content, - Category category, - String deepLink, - String webLink -) { - public static EventBridgeSenderRequestBody of(List userIds, String title, String content, Category category, - String deepLink, String webLink) { - return new EventBridgeSenderRequestBody(userIds, title, content, category, deepLink, webLink); - } -} diff --git a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/eventBridgeServer/dto/EventBridgeSenderRequestHeader.java b/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/eventBridgeServer/dto/EventBridgeSenderRequestHeader.java deleted file mode 100644 index ce7c997b..00000000 --- a/operation-external/src/main/java/org/sopt/makers/operation/client/alarm/eventBridgeServer/dto/EventBridgeSenderRequestHeader.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.sopt.makers.operation.client.alarm.eventBridgeServer.dto; - -import java.util.UUID; -import lombok.val; - -public record EventBridgeSenderRequestHeader( - String action, - String xApiKey, - String transactionId, - String service -) { - public static EventBridgeSenderRequestHeader of(String xApiKey, String action, String service) { - val transactionId = UUID.randomUUID().toString(); - return new EventBridgeSenderRequestHeader(action, xApiKey, transactionId, service); - } -} diff --git a/operation-external/src/main/java/org/sopt/makers/operation/client/playground/PlayGroundServer.java b/operation-external/src/main/java/org/sopt/makers/operation/client/playground/PlayGroundServer.java index 9230281e..c2f15036 100644 --- a/operation-external/src/main/java/org/sopt/makers/operation/client/playground/PlayGroundServer.java +++ b/operation-external/src/main/java/org/sopt/makers/operation/client/playground/PlayGroundServer.java @@ -1,7 +1,7 @@ package org.sopt.makers.operation.client.playground; import org.sopt.makers.operation.client.playground.dto.MemberListGetResponse; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; public interface PlayGroundServer { MemberListGetResponse getMembers(int generation, Part part); diff --git a/operation-external/src/main/java/org/sopt/makers/operation/client/playground/PlayGroundServerImpl.java b/operation-external/src/main/java/org/sopt/makers/operation/client/playground/PlayGroundServerImpl.java index c48cd3f7..1048c678 100644 --- a/operation-external/src/main/java/org/sopt/makers/operation/client/playground/PlayGroundServerImpl.java +++ b/operation-external/src/main/java/org/sopt/makers/operation/client/playground/PlayGroundServerImpl.java @@ -1,11 +1,11 @@ package org.sopt.makers.operation.client.playground; import static org.sopt.makers.operation.code.failure.AlarmFailureCode.*; -import static org.sopt.makers.operation.common.domain.Part.*; +import static org.sopt.makers.operation.member.domain.Part.*; import static org.springframework.http.HttpMethod.*; import org.sopt.makers.operation.client.playground.dto.MemberListGetResponse; -import org.sopt.makers.operation.common.domain.Part; +import org.sopt.makers.operation.member.domain.Part; import org.sopt.makers.operation.config.ValueConfig; import org.sopt.makers.operation.exception.AlarmException; import org.springframework.http.HttpEntity;