diff --git a/src/main/java/in/koreatech/koin/admin/history/aop/AdminActivityHistoryAspect.java b/src/main/java/in/koreatech/koin/admin/history/aop/AdminActivityHistoryAspect.java index 0b784c58d..720ae012c 100644 --- a/src/main/java/in/koreatech/koin/admin/history/aop/AdminActivityHistoryAspect.java +++ b/src/main/java/in/koreatech/koin/admin/history/aop/AdminActivityHistoryAspect.java @@ -12,6 +12,7 @@ import org.springframework.web.util.ContentCachingRequestWrapper; import in.koreatech.koin.admin.history.enums.DomainType; +import in.koreatech.koin.admin.history.enums.HttpMethodType; import in.koreatech.koin.admin.history.model.AdminActivityHistory; import in.koreatech.koin.admin.history.repository.AdminActivityHistoryRepository; import in.koreatech.koin.admin.user.model.Admin; @@ -58,7 +59,7 @@ private void excludeSpecificMethods() { public Object logAdminActivity(ProceedingJoinPoint joinPoint) throws Throwable { HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest(); String requestURI = request.getRequestURI(); - String requestMethod = request.getMethod(); + HttpMethodType requestMethod = HttpMethodType.valueOf(request.getMethod()); ContentCachingRequestWrapper cachingRequest = (ContentCachingRequestWrapper)request; String requestMessage = new String(cachingRequest.getContentAsByteArray()); @@ -72,9 +73,10 @@ public Object logAdminActivity(ProceedingJoinPoint joinPoint) throws Throwable { .domainId(domainInfo.domainId()) .admin(admin) .requestMethod(requestMethod) - .domainName(domainInfo.domainName()) + .domainName(DomainType.valueOf(domainInfo.domainName())) .requestMessage(requestMessage) - .build()); + .build() + ); return result; } diff --git a/src/main/java/in/koreatech/koin/admin/history/controller/HistoryApi.java b/src/main/java/in/koreatech/koin/admin/history/controller/HistoryApi.java index 70bdba8fd..fe0edc9b1 100644 --- a/src/main/java/in/koreatech/koin/admin/history/controller/HistoryApi.java +++ b/src/main/java/in/koreatech/koin/admin/history/controller/HistoryApi.java @@ -1,6 +1,7 @@ package in.koreatech.koin.admin.history.controller; import static in.koreatech.koin.domain.user.model.UserType.ADMIN; +import static in.koreatech.koin.global.model.Criteria.Sort; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -8,7 +9,9 @@ import org.springframework.web.bind.annotation.RequestParam; import in.koreatech.koin.admin.history.dto.AdminHistoryResponse; -import in.koreatech.koin.admin.history.dto.AdminHistorysResponse; +import in.koreatech.koin.admin.history.dto.AdminHistoriesResponse; +import in.koreatech.koin.admin.history.enums.DomainType; +import in.koreatech.koin.admin.history.enums.HttpMethodType; import in.koreatech.koin.global.auth.Auth; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; @@ -19,6 +22,7 @@ @Tag(name = "(Admin) History: 기록", description = "관리자 기록 관련 API") public interface HistoryApi { + @ApiResponses( value = { @ApiResponse(responseCode = "200"), @@ -29,13 +33,14 @@ public interface HistoryApi { } ) @Operation(summary = "히스토리 리스트 조회") - @GetMapping("/admin/historys") - ResponseEntity getHistorys( + @GetMapping("/admin/histories") + ResponseEntity getHistories( @RequestParam(required = false) Integer page, @RequestParam(required = false) Integer limit, - @RequestParam(required = false) String requestMethod, - @RequestParam(required = false) String domainName, + @RequestParam(required = false) HttpMethodType requestMethod, + @RequestParam(required = false) DomainType domainName, @RequestParam(required = false) Integer domainId, + @RequestParam(required = false) Sort sort, @Auth(permit = {ADMIN}) Integer adminId ); diff --git a/src/main/java/in/koreatech/koin/admin/history/controller/HistoryController.java b/src/main/java/in/koreatech/koin/admin/history/controller/HistoryController.java index efc11bbbf..01aaa834f 100644 --- a/src/main/java/in/koreatech/koin/admin/history/controller/HistoryController.java +++ b/src/main/java/in/koreatech/koin/admin/history/controller/HistoryController.java @@ -1,6 +1,7 @@ package in.koreatech.koin.admin.history.controller; import static in.koreatech.koin.domain.user.model.UserType.ADMIN; +import static in.koreatech.koin.global.model.Criteria.Sort; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -9,8 +10,10 @@ import org.springframework.web.bind.annotation.RestController; import in.koreatech.koin.admin.history.dto.AdminHistoryResponse; -import in.koreatech.koin.admin.history.dto.AdminHistorysCondition; -import in.koreatech.koin.admin.history.dto.AdminHistorysResponse; +import in.koreatech.koin.admin.history.dto.AdminHistoriesCondition; +import in.koreatech.koin.admin.history.dto.AdminHistoriesResponse; +import in.koreatech.koin.admin.history.enums.DomainType; +import in.koreatech.koin.admin.history.enums.HttpMethodType; import in.koreatech.koin.admin.history.service.HistoryService; import in.koreatech.koin.global.auth.Auth; import lombok.RequiredArgsConstructor; @@ -21,19 +24,20 @@ public class HistoryController implements HistoryApi { private final HistoryService historyService; - @GetMapping("/admin/historys") - public ResponseEntity getHistorys( + @GetMapping("/admin/histories") + public ResponseEntity getHistories( @RequestParam(required = false) Integer page, @RequestParam(required = false) Integer limit, - @RequestParam(required = false) String requestMethod, - @RequestParam(required = false) String domainName, + @RequestParam(required = false) HttpMethodType requestMethod, + @RequestParam(required = false) DomainType domainName, @RequestParam(required = false) Integer domainId, + @RequestParam(required = false) Sort sort, @Auth(permit = {ADMIN}) Integer adminId ) { - AdminHistorysCondition adminHistorysCondition = new AdminHistorysCondition(page, limit, requestMethod, - domainName, domainId); - AdminHistorysResponse historys = historyService.getHistorys(adminHistorysCondition); - return ResponseEntity.ok(historys); + AdminHistoriesCondition adminHistoriesCondition = new AdminHistoriesCondition(page, limit, requestMethod, + domainName, domainId, sort); + AdminHistoriesResponse histories = historyService.getHistories(adminHistoriesCondition); + return ResponseEntity.ok(histories); } @GetMapping("/admin/history/{id}") diff --git a/src/main/java/in/koreatech/koin/admin/history/dto/AdminHistorysCondition.java b/src/main/java/in/koreatech/koin/admin/history/dto/AdminHistoriesCondition.java similarity index 52% rename from src/main/java/in/koreatech/koin/admin/history/dto/AdminHistorysCondition.java rename to src/main/java/in/koreatech/koin/admin/history/dto/AdminHistoriesCondition.java index e738e5b10..e7e775554 100644 --- a/src/main/java/in/koreatech/koin/admin/history/dto/AdminHistorysCondition.java +++ b/src/main/java/in/koreatech/koin/admin/history/dto/AdminHistoriesCondition.java @@ -1,17 +1,22 @@ package in.koreatech.koin.admin.history.dto; import static com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; +import static in.koreatech.koin.global.model.Criteria.*; +import static in.koreatech.koin.global.model.Criteria.Sort.CREATED_AT_ASC; +import static in.koreatech.koin.global.model.Criteria.Sort.CREATED_AT_DESC; import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.NOT_REQUIRED; +import static org.springframework.data.domain.Sort.Direction; import java.util.Objects; import com.fasterxml.jackson.databind.annotation.JsonNaming; -import in.koreatech.koin.global.model.Criteria; +import in.koreatech.koin.admin.history.enums.DomainType; +import in.koreatech.koin.admin.history.enums.HttpMethodType; import io.swagger.v3.oas.annotations.media.Schema; @JsonNaming(value = SnakeCaseStrategy.class) -public record AdminHistorysCondition( +public record AdminHistoriesCondition( @Schema(description = "페이지", example = "1", defaultValue = "1", requiredMode = NOT_REQUIRED) Integer page, @@ -19,20 +24,33 @@ public record AdminHistorysCondition( Integer limit, @Schema(description = "HTTP 메소드", example = "POST", requiredMode = NOT_REQUIRED) - String requestMethod, + HttpMethodType requestMethod, @Schema(description = "도메인 이름", example = "NOTICE", requiredMode = NOT_REQUIRED) - String domainName, + DomainType domainName, @Schema(description = "특정 엔티티 id", requiredMode = NOT_REQUIRED) - Integer domainId + Integer domainId, + + @Schema(description = "정렬 기준", requiredMode = NOT_REQUIRED) + Sort sort ) { - public AdminHistorysCondition { + public AdminHistoriesCondition { if (Objects.isNull(page)) { - page = Criteria.DEFAULT_PAGE; + page = DEFAULT_PAGE; } if (Objects.isNull(limit)) { - limit = Criteria.DEFAULT_LIMIT; + limit = DEFAULT_LIMIT; + } + if (Objects.isNull(sort)) { + sort = CREATED_AT_DESC; + } + } + + public Direction getSortDir() { + if (sort == CREATED_AT_ASC) { + return Direction.ASC; } + return Direction.DESC; } } diff --git a/src/main/java/in/koreatech/koin/admin/history/dto/AdminHistorysResponse.java b/src/main/java/in/koreatech/koin/admin/history/dto/AdminHistoriesResponse.java similarity index 77% rename from src/main/java/in/koreatech/koin/admin/history/dto/AdminHistorysResponse.java rename to src/main/java/in/koreatech/koin/admin/history/dto/AdminHistoriesResponse.java index 26891b308..61e1a8722 100644 --- a/src/main/java/in/koreatech/koin/admin/history/dto/AdminHistorysResponse.java +++ b/src/main/java/in/koreatech/koin/admin/history/dto/AdminHistoriesResponse.java @@ -12,13 +12,11 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.databind.annotation.JsonNaming; -import in.koreatech.koin.admin.history.enums.DomainType; -import in.koreatech.koin.admin.history.enums.HttpMethodType; import in.koreatech.koin.admin.history.model.AdminActivityHistory; import io.swagger.v3.oas.annotations.media.Schema; @JsonNaming(value = SnakeCaseStrategy.class) -public record AdminHistorysResponse( +public record AdminHistoriesResponse( @Schema(description = "조건에 해당하는 히스토리 수", example = "10", requiredMode = REQUIRED) Long totalCount, @@ -32,10 +30,10 @@ public record AdminHistorysResponse( Integer currentPage, @Schema(description = "어드민 계정 리스트", requiredMode = REQUIRED) - List historys + List histories ) { @JsonNaming(value = SnakeCaseStrategy.class) - public record InnerAdminHistorysResponse( + public record InnerAdminHistoriesResponse( @Schema(description = "고유 id", example = "1", requiredMode = REQUIRED) Integer id, @@ -61,31 +59,31 @@ public record InnerAdminHistorysResponse( ) String requestMessage, - @Schema(description = "요청 시간", example = "2019-08-16-23-01-52", requiredMode = REQUIRED) - @JsonFormat(pattern = "yyyy-MM-dd-HH-mm-ss") + @Schema(description = "요청 시간", example = "2019-08-16 23:01:52", requiredMode = REQUIRED) + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime createdAt ) { - public static InnerAdminHistorysResponse from(AdminActivityHistory adminActivityHistory) { - return new InnerAdminHistorysResponse( + public static InnerAdminHistoriesResponse from(AdminActivityHistory adminActivityHistory) { + return new InnerAdminHistoriesResponse( adminActivityHistory.getId(), adminActivityHistory.getDomainId(), adminActivityHistory.getAdmin().getUser().getName(), - DomainType.valueOf(adminActivityHistory.getDomainName()).getDescription(), - HttpMethodType.valueOf(adminActivityHistory.getRequestMethod()).getValue(), + adminActivityHistory.getDomainName().getDescription(), + adminActivityHistory.getRequestMethod().getValue(), adminActivityHistory.getRequestMessage(), adminActivityHistory.getCreatedAt() ); } } - public static AdminHistorysResponse of(Page adminActivityHistoryPage) { - return new AdminHistorysResponse( + public static AdminHistoriesResponse from(Page adminActivityHistoryPage) { + return new AdminHistoriesResponse( adminActivityHistoryPage.getTotalElements(), adminActivityHistoryPage.getContent().size(), adminActivityHistoryPage.getTotalPages(), adminActivityHistoryPage.getNumber() + 1, adminActivityHistoryPage.getContent().stream() - .map(InnerAdminHistorysResponse::from) + .map(InnerAdminHistoriesResponse::from) .collect(Collectors.toList()) ); } diff --git a/src/main/java/in/koreatech/koin/admin/history/dto/AdminHistoryResponse.java b/src/main/java/in/koreatech/koin/admin/history/dto/AdminHistoryResponse.java index 406ce536a..035fa6e59 100644 --- a/src/main/java/in/koreatech/koin/admin/history/dto/AdminHistoryResponse.java +++ b/src/main/java/in/koreatech/koin/admin/history/dto/AdminHistoryResponse.java @@ -40,8 +40,8 @@ public record AdminHistoryResponse( ) String requestMessage, - @Schema(description = "요청 시간", example = "2019-08-16-23-01-52", requiredMode = REQUIRED) - @JsonFormat(pattern = "yyyy-MM-dd-HH-mm-ss") + @Schema(description = "요청 시간", example = "2019-08-16 23:01:52", requiredMode = REQUIRED) + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime createdAt ) { public static AdminHistoryResponse from(AdminActivityHistory adminActivityHistory) { @@ -49,8 +49,8 @@ public static AdminHistoryResponse from(AdminActivityHistory adminActivityHistor adminActivityHistory.getId(), adminActivityHistory.getDomainId(), adminActivityHistory.getAdmin().getUser().getName(), - DomainType.valueOf(adminActivityHistory.getDomainName()).getDescription(), - HttpMethodType.valueOf(adminActivityHistory.getRequestMethod()).getValue(), + adminActivityHistory.getDomainName().getDescription(), + adminActivityHistory.getRequestMethod().getValue(), adminActivityHistory.getRequestMessage(), adminActivityHistory.getCreatedAt() ); diff --git a/src/main/java/in/koreatech/koin/admin/history/model/AdminActivityHistory.java b/src/main/java/in/koreatech/koin/admin/history/model/AdminActivityHistory.java index 3ab600a04..afb88e2b4 100644 --- a/src/main/java/in/koreatech/koin/admin/history/model/AdminActivityHistory.java +++ b/src/main/java/in/koreatech/koin/admin/history/model/AdminActivityHistory.java @@ -3,17 +3,20 @@ import static jakarta.persistence.GenerationType.IDENTITY; import static lombok.AccessLevel.PROTECTED; +import in.koreatech.koin.admin.history.enums.DomainType; +import in.koreatech.koin.admin.history.enums.HttpMethodType; import in.koreatech.koin.admin.user.model.Admin; import in.koreatech.koin.global.domain.BaseEntity; import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -32,14 +35,14 @@ public class AdminActivityHistory extends BaseEntity { private Integer domainId; @NotNull - @Size(max = 10) + @Enumerated(value = EnumType.STRING) @Column(name = "request_method", nullable = false, length = 10) - private String requestMethod; + private HttpMethodType requestMethod; @NotNull - @Size(max = 20) + @Enumerated(value = EnumType.STRING) @Column(name = "domain_name", nullable = false, length = 20) - private String domainName; + private DomainType domainName; @Column(name = "request_message", columnDefinition = "TEXT") private String requestMessage; @@ -49,8 +52,13 @@ public class AdminActivityHistory extends BaseEntity { private Admin admin; @Builder - public AdminActivityHistory(Integer domainId, String requestMethod, String domainName, String requestMessage, - Admin admin) { + public AdminActivityHistory( + Integer domainId, + HttpMethodType requestMethod, + DomainType domainName, + String requestMessage, + Admin admin + ) { this.domainId = domainId; this.requestMethod = requestMethod; this.domainName = domainName; diff --git a/src/main/java/in/koreatech/koin/admin/history/repository/AdminActivityHistoryRepository.java b/src/main/java/in/koreatech/koin/admin/history/repository/AdminActivityHistoryRepository.java index eb0a9721f..01c6cf937 100644 --- a/src/main/java/in/koreatech/koin/admin/history/repository/AdminActivityHistoryRepository.java +++ b/src/main/java/in/koreatech/koin/admin/history/repository/AdminActivityHistoryRepository.java @@ -8,11 +8,12 @@ import org.springframework.data.repository.Repository; import org.springframework.data.repository.query.Param; -import in.koreatech.koin.admin.history.dto.AdminHistorysCondition; +import in.koreatech.koin.admin.history.dto.AdminHistoriesCondition; import in.koreatech.koin.admin.history.exception.AdminActivityHistoryNotFoundException; import in.koreatech.koin.admin.history.model.AdminActivityHistory; public interface AdminActivityHistoryRepository extends Repository { + AdminActivityHistory save(AdminActivityHistory adminActivityHistory); Optional findById(Integer id); @@ -27,10 +28,10 @@ default AdminActivityHistory getById(Integer id) { @Query(""" SELECT a FROM AdminActivityHistory a WHERE - (:#{#condition.requestMethod} IS NULL OR a.requestMethod = :#{#condition.requestMethod}) AND - (:#{#condition.domainName} IS NULL OR a.domainName = :#{#condition.domainName}) AND + (:#{#condition.requestMethod?.name()} IS NULL OR a.requestMethod = :#{#condition.requestMethod}) AND + (:#{#condition.domainName?.name()} IS NULL OR a.domainName = :#{#condition.domainName}) AND (:#{#condition.domainId} IS NULL OR a.domainId = :#{#condition.domainId}) """) - Page findByConditions(@Param("condition") AdminHistorysCondition adminsCondition, + Page findByConditions(@Param("condition") AdminHistoriesCondition adminsCondition, Pageable pageable); } diff --git a/src/main/java/in/koreatech/koin/admin/history/service/HistoryService.java b/src/main/java/in/koreatech/koin/admin/history/service/HistoryService.java index 84706bab5..124973a64 100644 --- a/src/main/java/in/koreatech/koin/admin/history/service/HistoryService.java +++ b/src/main/java/in/koreatech/koin/admin/history/service/HistoryService.java @@ -2,11 +2,12 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import in.koreatech.koin.admin.history.dto.AdminHistoryResponse; -import in.koreatech.koin.admin.history.dto.AdminHistorysCondition; -import in.koreatech.koin.admin.history.dto.AdminHistorysResponse; +import in.koreatech.koin.admin.history.dto.AdminHistoriesCondition; +import in.koreatech.koin.admin.history.dto.AdminHistoriesResponse; import in.koreatech.koin.admin.history.model.AdminActivityHistory; import in.koreatech.koin.admin.history.repository.AdminActivityHistoryRepository; import in.koreatech.koin.global.model.Criteria; @@ -18,16 +19,18 @@ public class HistoryService { private final AdminActivityHistoryRepository adminActivityHistoryRepository; - public AdminHistorysResponse getHistorys(AdminHistorysCondition condition) { + public AdminHistoriesResponse getHistories(AdminHistoriesCondition condition) { Integer total = adminActivityHistoryRepository.countAdminActivityHistory(); Criteria criteria = Criteria.of(condition.page(), condition.limit(), total); - PageRequest pageRequest = PageRequest.of(criteria.getPage(), criteria.getLimit()); - Page adminActivityHistoryRepositoryPage = adminActivityHistoryRepository.findByConditions( - condition, - pageRequest); + PageRequest pageRequest = PageRequest.of( + criteria.getPage(), criteria.getLimit(), + Sort.by(condition.getSortDir(), "createdAt") + ); + Page adminActivityHistoryPage = adminActivityHistoryRepository.findByConditions( + condition, pageRequest); - return AdminHistorysResponse.of(adminActivityHistoryRepositoryPage); + return AdminHistoriesResponse.from(adminActivityHistoryPage); } public AdminHistoryResponse getHistory(Integer id) {