Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] Alert api #202 #204

Merged
merged 15 commits into from
Aug 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
package com.kustacks.kuring.admin.adapter.in.web;

import static com.kustacks.kuring.common.dto.ResponseCodeAndMessages.ADMIN_REAL_NOTICE_CREATE_SUCCESS;
import static com.kustacks.kuring.common.dto.ResponseCodeAndMessages.ADMIN_TEST_NOTICE_CREATE_SUCCESS;

import com.google.firebase.database.annotations.NotNull;
import com.kustacks.kuring.admin.adapter.in.web.dto.RealNotificationRequest;
import com.kustacks.kuring.admin.adapter.in.web.dto.TestNotificationRequest;
import com.kustacks.kuring.admin.application.port.in.AdminCommandUseCase;
import com.kustacks.kuring.admin.application.port.in.dto.RealNotificationCommand;
import com.kustacks.kuring.admin.domain.AdminRole;
import com.kustacks.kuring.alert.adapter.in.web.dto.AlertCreateRequest;
import com.kustacks.kuring.alert.application.port.in.dto.AlertCreateCommand;
import com.kustacks.kuring.auth.authorization.AuthenticationPrincipal;
import com.kustacks.kuring.auth.context.Authentication;
import com.kustacks.kuring.auth.secured.Secured;
import com.kustacks.kuring.common.dto.BaseResponse;
import com.kustacks.kuring.common.utils.converter.StringToDateTimeConverter;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

import static com.kustacks.kuring.common.dto.ResponseCodeAndMessages.ADMIN_REAL_NOTICE_CREATE_SUCCESS;
import static com.kustacks.kuring.common.dto.ResponseCodeAndMessages.ADMIN_TEST_NOTICE_CREATE_SUCCESS;

@Tag(name = "Admin-Command", description = "관리자가 주체가 되는 정보 수정")
@Validated
Expand Down Expand Up @@ -59,6 +61,33 @@ public ResponseEntity<BaseResponse<String>> createRealNotice(
return ResponseEntity.ok().body(new BaseResponse<>(ADMIN_REAL_NOTICE_CREATE_SUCCESS, null));
}

@Operation(summary = "예약 알림 등록", description = "서버에 예약 알림을 등록한다")
@SecurityRequirement(name = "JWT")
@Secured(AdminRole.ROLE_ROOT)
@PostMapping("/alerts")
public ResponseEntity<BaseResponse<String>> createAlert(
@RequestBody AlertCreateRequest request
) {
AlertCreateCommand command = new AlertCreateCommand(
request.title(), request.content(),
StringToDateTimeConverter.convert(request.alertTime())
);

adminCommandUseCase.addAlertSchedule(command);
return ResponseEntity.ok().body(new BaseResponse<>(ADMIN_REAL_NOTICE_CREATE_SUCCESS, null));
}

@Operation(summary = "예약 알림 삭제", description = "서버에 예약되어 있는 특정 알림을 삭제한다")
@SecurityRequirement(name = "JWT")
@Secured(AdminRole.ROLE_ROOT)
@ResponseStatus(HttpStatus.NO_CONTENT)
@DeleteMapping("/alerts/{id}")
public void cancelAlert(
@Parameter(description = "알림 아이디") @NotNull @PathVariable("id") Long id
) {
adminCommandUseCase.cancelAlertSchedule(id);
}

@Hidden
@Secured(AdminRole.ROLE_ROOT)
@GetMapping("/subscribe/all")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.kustacks.kuring.admin.adapter.in.web;

import com.kustacks.kuring.admin.adapter.in.web.dto.AdminAlertResponse;
import com.kustacks.kuring.admin.application.port.in.AdminQueryUseCase;
import com.kustacks.kuring.admin.domain.AdminRole;
import com.kustacks.kuring.auth.authorization.AuthenticationPrincipal;
Expand All @@ -25,8 +26,7 @@

import java.util.List;

import static com.kustacks.kuring.common.dto.ResponseCodeAndMessages.AUTH_AUTHENTICATION_SUCCESS;
import static com.kustacks.kuring.common.dto.ResponseCodeAndMessages.FEEDBACK_SEARCH_SUCCESS;
import static com.kustacks.kuring.common.dto.ResponseCodeAndMessages.*;

@Tag(name = "Admin-Query", description = "관리자가 주체가 되는 정보 조회")
@Validated
Expand All @@ -43,11 +43,24 @@ public class AdminQueryApiV2 {
@GetMapping("/feedbacks")
public ResponseEntity<BaseResponse<List<AdminFeedbacksResult>>> getFeedbacks(
@Parameter(description = "페이지") @RequestParam(name = "page") @Min(0) int page,
@Parameter(description = "단일 페이지의 사이즈, 1 ~ 30까지 허용") @RequestParam(name = "size") @Min(1) @Max(30) int size) {
@Parameter(description = "단일 페이지의 사이즈, 1 ~ 30까지 허용") @RequestParam(name = "size") @Min(1) @Max(30) int size
) {
List<AdminFeedbacksResult> feedbacks = adminQueryUseCase.lookupFeedbacks(page, size);
return ResponseEntity.ok().body(new BaseResponse<>(FEEDBACK_SEARCH_SUCCESS, feedbacks));
}

@Operation(summary = "예약 알림 조회", description = "어드민이 등록한 모든 예약 알림을 조회한다")
@SecurityRequirement(name = "JWT")
@Secured(AdminRole.ROLE_ROOT)
@GetMapping("/alerts")
public ResponseEntity<BaseResponse<List<AdminAlertResponse>>> getAlerts(
@Parameter(description = "페이지") @RequestParam(name = "page") @Min(0) int page,
@Parameter(description = "단일 페이지의 사이즈, 1 ~ 30까지 허용") @RequestParam(name = "size") @Min(1) @Max(30) int size
) {
List<AdminAlertResponse> alerts = adminQueryUseCase.lookupAlerts(page, size);
return ResponseEntity.ok().body(new BaseResponse<>(ALERT_SEARCH_SUCCESS, alerts));
}

/**
* Root 이상만 호출 가능한 테스트 API
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.kustacks.kuring.admin.adapter.in.web.dto;

import com.kustacks.kuring.alert.domain.AlertStatus;

import java.time.LocalDateTime;

public record AdminAlertResponse(
Long id,
String title,
String content,
AlertStatus status,
LocalDateTime wakeTime
) {
public static AdminAlertResponse of(
Long id, String title, String content,
AlertStatus status, LocalDateTime alertTime
) {
return new AdminAlertResponse(id, title, content, status, alertTime);
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.kustacks.kuring.admin.adapter.out.event;

import com.kustacks.kuring.admin.application.port.out.AdminAlertEventPort;
import com.kustacks.kuring.alert.adapter.in.event.dto.AlertCreateEvent;
import com.kustacks.kuring.alert.adapter.in.event.dto.AlertDeleteEvent;
import com.kustacks.kuring.common.domain.Events;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

@Component
public class AdminAdminAlertEventAdapter implements AdminAlertEventPort {

@Override
public void addAlertSchedule(String title, String content, LocalDateTime alertTime) {
Events.raise(new AlertCreateEvent(title, content, alertTime));
}

@Override
public void cancelAlertSchedule(Long id) {
Events.raise(new AlertDeleteEvent(id));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@

import com.kustacks.kuring.admin.application.port.in.dto.RealNotificationCommand;
import com.kustacks.kuring.admin.application.port.in.dto.TestNotificationCommand;
import com.kustacks.kuring.alert.application.port.in.dto.AlertCreateCommand;

public interface AdminCommandUseCase {
void createTestNotice(TestNotificationCommand command);
void createRealNoticeForAllUser(RealNotificationCommand command);
void subscribeAllUserSameTopic();

void addAlertSchedule(AlertCreateCommand command);

void cancelAlertSchedule(Long id);
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.kustacks.kuring.admin.application.port.in;

import com.kustacks.kuring.admin.adapter.in.web.dto.AdminAlertResponse;
import com.kustacks.kuring.user.application.port.in.dto.AdminFeedbacksResult;

import java.util.List;

public interface AdminQueryUseCase {
List<AdminFeedbacksResult> lookupFeedbacks(int page, int size);

List<AdminAlertResponse> lookupAlerts(int page, int size);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.kustacks.kuring.admin.application.port.out;

import java.time.LocalDateTime;

public interface AdminAlertEventPort {
void addAlertSchedule(String title, String content, LocalDateTime alertTime);

void cancelAlertSchedule(Long id);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.kustacks.kuring.admin.application.port.out;

import com.kustacks.kuring.alert.domain.Alert;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

public interface AdminAlertQueryPort {
Page<Alert> findAllAlertByPageRequest(Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
import com.kustacks.kuring.admin.application.port.in.AdminCommandUseCase;
import com.kustacks.kuring.admin.application.port.in.dto.RealNotificationCommand;
import com.kustacks.kuring.admin.application.port.in.dto.TestNotificationCommand;
import com.kustacks.kuring.admin.application.port.out.AdminAlertEventPort;
import com.kustacks.kuring.admin.application.port.out.AdminEventPort;
import com.kustacks.kuring.admin.application.port.out.AdminUserFeedbackPort;
import com.kustacks.kuring.admin.domain.Admin;
import com.kustacks.kuring.alert.application.port.in.dto.AlertCreateCommand;
import com.kustacks.kuring.auth.userdetails.UserDetailsServicePort;
import com.kustacks.kuring.common.annotation.UseCase;
import com.kustacks.kuring.common.properties.ServerProperties;
Expand All @@ -29,6 +31,7 @@ public class AdminCommandService implements AdminCommandUseCase {

private final UserDetailsServicePort userDetailsServicePort;
private final AdminUserFeedbackPort adminUserFeedbackPort;
private final AdminAlertEventPort adminAlertEventPort;
private final AdminEventPort adminEventPort;
private final NoticeProperties noticeProperties;
private final ServerProperties serverProperties;
Expand Down Expand Up @@ -66,6 +69,16 @@ public void createRealNoticeForAllUser(RealNotificationCommand command) {
adminEventPort.sendNotificationByAdmin(command.title(), command.body(), command.url());
}

@Override
public void addAlertSchedule(AlertCreateCommand command) {
adminAlertEventPort.addAlertSchedule(command.title(), command.content(), command.alertTime());
}

@Override
public void cancelAlertSchedule(Long id) {
adminAlertEventPort.cancelAlertSchedule(id);
}

/**
* TODO : 1회성 API - client v2 배포 후, 단 한번 모든 사용자를 공통 topic에 구독시킨 후 제거 예정
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package com.kustacks.kuring.admin.application.service;

import com.kustacks.kuring.admin.adapter.in.web.dto.AdminAlertResponse;
import com.kustacks.kuring.admin.application.port.in.AdminQueryUseCase;
import com.kustacks.kuring.admin.application.port.out.AdminAlertQueryPort;
import com.kustacks.kuring.admin.application.port.out.AdminUserFeedbackPort;
import com.kustacks.kuring.common.annotation.UseCase;
import com.kustacks.kuring.user.application.port.in.dto.AdminFeedbacksResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
Expand All @@ -17,6 +20,7 @@
public class AdminQueryService implements AdminQueryUseCase {

private final AdminUserFeedbackPort adminUserFeedbackPort;
private final AdminAlertQueryPort adminAlertQueryPort;

@Transactional(readOnly = true)
@Override
Expand All @@ -31,4 +35,19 @@ public List<AdminFeedbacksResult> lookupFeedbacks(int page, int size) {
))
.toList();
}

@Override
public List<AdminAlertResponse> lookupAlerts(int page, int size) {
PageRequest pageRequest = PageRequest.of(page, size, Sort.by(Sort.Order.desc("createdAt")));
return adminAlertQueryPort.findAllAlertByPageRequest(pageRequest)
.stream()
.map(alert -> AdminAlertResponse.of(
alert.getId(),
alert.getTitle(),
alert.getContent(),
alert.getStatus(),
alert.getAlertTime()
))
.toList();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.kustacks.kuring.alert.adapter.in.event;

import com.kustacks.kuring.alert.adapter.in.event.dto.AlertCreateEvent;
import com.kustacks.kuring.alert.adapter.in.event.dto.AlertDeleteEvent;
import com.kustacks.kuring.alert.application.port.in.AlertCommandUseCase;
import com.kustacks.kuring.alert.application.port.in.dto.AlertCreateCommand;
import lombok.RequiredArgsConstructor;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class AlertCommandEventListener {

private final AlertCommandUseCase alertCommandUseCase;

@EventListener
public void createAlert(
AlertCreateEvent event
) {
AlertCreateCommand command = new AlertCreateCommand(
event.title(), event.content(), event.alertTime()
);

alertCommandUseCase.addAlertSchedule(command);
}

@EventListener
public void cancelAlert(
AlertDeleteEvent event
) {
alertCommandUseCase.cancelAlertSchedule(event.id());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.kustacks.kuring.alert.adapter.in.event.dto;

import java.time.LocalDateTime;

public record AlertCreateEvent(
String title,
String content,
LocalDateTime alertTime
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.kustacks.kuring.alert.adapter.in.event.dto;

public record AlertDeleteEvent(
Long id
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.kustacks.kuring.alert.adapter.in.web;

import com.google.firebase.database.annotations.NotNull;
import com.kustacks.kuring.alert.adapter.in.web.dto.AlertCreateRequest;
import com.kustacks.kuring.alert.application.port.in.AlertCommandUseCase;
import com.kustacks.kuring.alert.application.port.in.dto.AlertCreateCommand;
import com.kustacks.kuring.common.annotation.RestWebAdapter;
import com.kustacks.kuring.common.utils.converter.StringToDateTimeConverter;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

@Tag(name = "Alert-Command", description = "알림 에약")
@Validated
@RequiredArgsConstructor
@RestWebAdapter(path = "/api/v2/alerts")
public class AlertCommandApiV2 {

private final AlertCommandUseCase alertCommandUseCase;

@Operation(summary = "예약 알림 등록", description = "서버에 예약 알림을 등록한다")
@PostMapping
public void createAlert(
@RequestBody AlertCreateRequest request
) {
AlertCreateCommand command = new AlertCreateCommand(
request.title(), request.content(),
StringToDateTimeConverter.convert(request.alertTime())
);

alertCommandUseCase.addAlertSchedule(command);
}

@Operation(summary = "예약 알림 삭제", description = "서버에 예약되어 있는 특정 알림을 삭제한다")
@DeleteMapping("/{id}")
public void cancelAlert(
@Parameter(description = "알림 아이디") @NotNull @PathVariable Long id
) {
alertCommandUseCase.cancelAlertSchedule(id);
}
}
Loading
Loading