state-check 스케줄 추가, pnu-update 수정
This commit is contained in:
@@ -1,54 +0,0 @@
|
||||
package com.kamco.cd.kamcoback.common.utils;
|
||||
|
||||
import com.kamco.cd.kamcoback.auth.CustomUserDetails;
|
||||
import com.kamco.cd.kamcoback.members.dto.MembersDto;
|
||||
import com.kamco.cd.kamcoback.postgres.entity.MemberEntity;
|
||||
import java.util.Optional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class UserUtil {
|
||||
|
||||
public MembersDto.Member getCurrentUser() {
|
||||
return Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
|
||||
.filter(auth -> auth.getPrincipal() instanceof CustomUserDetails)
|
||||
.map(
|
||||
auth -> {
|
||||
CustomUserDetails user = (CustomUserDetails) auth.getPrincipal();
|
||||
MemberEntity m = user.getMember();
|
||||
return new MembersDto.Member(
|
||||
m.getId(), m.getName(), m.getEmployeeNo(), m.getUserRole());
|
||||
})
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
MembersDto.Member user = getCurrentUser();
|
||||
return user != null ? user.getId() : null;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
MembersDto.Member user = getCurrentUser();
|
||||
return user != null ? user.getName() : null;
|
||||
}
|
||||
|
||||
public String getEmployeeNo() {
|
||||
MembersDto.Member user = getCurrentUser();
|
||||
return user != null ? user.getEmployeeNo() : null;
|
||||
}
|
||||
|
||||
public String getRole() {
|
||||
MembersDto.Member user = getCurrentUser();
|
||||
return user != null ? user.getRole() : null;
|
||||
}
|
||||
|
||||
public String getIp() {
|
||||
return Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
|
||||
.map(auth -> auth.getDetails())
|
||||
.map(Object::toString)
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
package com.kamco.cd.kamcoback.config.api;
|
||||
|
||||
import com.kamco.cd.kamcoback.log.dto.EventStatus;
|
||||
import com.kamco.cd.kamcoback.log.dto.EventType;
|
||||
import com.kamco.cd.kamcoback.menu.dto.MenuDto;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.util.ContentCachingRequestWrapper;
|
||||
|
||||
@Slf4j
|
||||
public class ApiLogFunction {
|
||||
|
||||
// 클라이언트 IP 추출
|
||||
public static String getClientIp(HttpServletRequest request) {
|
||||
String[] headers = {
|
||||
"X-Forwarded-For",
|
||||
"Proxy-Client-IP",
|
||||
"WL-Proxy-Client-IP",
|
||||
"HTTP_CLIENT_IP",
|
||||
"HTTP_X_FORWARDED_FOR"
|
||||
};
|
||||
for (String header : headers) {
|
||||
String ip = request.getHeader(header);
|
||||
if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
|
||||
return ip.split(",")[0];
|
||||
}
|
||||
}
|
||||
String ip = request.getRemoteAddr();
|
||||
if ("0:0:0:0:0:0:0:1".equals(ip)) { // local 일 때
|
||||
ip = "127.0.0.1";
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
public static String getXFowardedForIp(HttpServletRequest request) {
|
||||
String ip = request.getHeader("X-Forwarded-For");
|
||||
if (ip != null) {
|
||||
ip = ip.split(",")[0].trim();
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
// 사용자 ID 추출 예시 (Spring Security 기준)
|
||||
public static String getUserId(HttpServletRequest request) {
|
||||
try {
|
||||
return request.getUserPrincipal() != null ? request.getUserPrincipal().getName() : null;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static EventType getEventType(HttpServletRequest request) {
|
||||
String method = request.getMethod().toUpperCase();
|
||||
String uri = request.getRequestURI().toLowerCase();
|
||||
|
||||
// URL 기반 DOWNLOAD/PRINT 분류 -> /download는 FileDownloadInterceptor로 옮김
|
||||
if (uri.contains("/download") || uri.contains("/export")) {
|
||||
return EventType.DOWNLOAD;
|
||||
}
|
||||
if (uri.contains("/print")) {
|
||||
return EventType.OTHER;
|
||||
}
|
||||
|
||||
// 일반 CRUD
|
||||
return switch (method) {
|
||||
case "POST" -> EventType.ADDED;
|
||||
case "GET" -> EventType.LIST;
|
||||
case "DELETE" -> EventType.REMOVE;
|
||||
case "PUT", "PATCH" -> EventType.MODIFIED;
|
||||
default -> EventType.OTHER;
|
||||
};
|
||||
}
|
||||
|
||||
public static String getRequestBody(
|
||||
HttpServletRequest servletRequest, ContentCachingRequestWrapper contentWrapper) {
|
||||
StringBuilder resultBody = new StringBuilder();
|
||||
// GET, form-urlencoded POST 파라미터
|
||||
Map<String, String[]> paramMap = servletRequest.getParameterMap();
|
||||
|
||||
String queryParams =
|
||||
paramMap.entrySet().stream()
|
||||
.map(e -> e.getKey() + "=" + String.join(",", e.getValue()))
|
||||
.collect(Collectors.joining("&"));
|
||||
|
||||
resultBody.append(queryParams.isEmpty() ? "" : queryParams);
|
||||
|
||||
// JSON Body
|
||||
if ("POST".equalsIgnoreCase(servletRequest.getMethod())
|
||||
&& servletRequest.getContentType() != null
|
||||
&& servletRequest.getContentType().contains("application/json")) {
|
||||
try {
|
||||
// json인 경우는 Wrapper를 통해 가져오기
|
||||
resultBody.append(getBodyData(contentWrapper));
|
||||
|
||||
} catch (Exception e) {
|
||||
resultBody.append("cannot read JSON body ").append(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// Multipart form-data
|
||||
if ("POST".equalsIgnoreCase(servletRequest.getMethod())
|
||||
&& servletRequest.getContentType() != null
|
||||
&& servletRequest.getContentType().startsWith("multipart/form-data")) {
|
||||
resultBody.append("multipart/form-data request");
|
||||
}
|
||||
|
||||
return resultBody.toString();
|
||||
}
|
||||
|
||||
// JSON Body 읽기
|
||||
public static String getBodyData(ContentCachingRequestWrapper request) {
|
||||
byte[] buf = request.getContentAsByteArray();
|
||||
if (buf.length == 0) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new String(buf, request.getCharacterEncoding());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return new String(buf);
|
||||
}
|
||||
}
|
||||
|
||||
// ApiResponse 의 Status가 2xx 범위이면 SUCCESS, 아니면 FAILED
|
||||
public static EventStatus isSuccessFail(ApiResponseDto<?> apiResponse) {
|
||||
return apiResponse.getHttpStatus().is2xxSuccessful() ? EventStatus.SUCCESS : EventStatus.FAILED;
|
||||
}
|
||||
|
||||
public static String getUriMenuInfo(List<MenuDto.Basic> menuList, String uri) {
|
||||
|
||||
String normalizedUri = uri.replace("/api", "");
|
||||
MenuDto.Basic basic =
|
||||
menuList.stream()
|
||||
.filter(
|
||||
menu -> menu.getMenuUrl() != null && normalizedUri.startsWith(menu.getMenuUrl()))
|
||||
.max(Comparator.comparingInt(m -> m.getMenuUrl().length()))
|
||||
.orElse(null);
|
||||
|
||||
return basic != null ? basic.getMenuUid() : "SYSTEM";
|
||||
}
|
||||
|
||||
public static String cutRequestBody(String value) {
|
||||
int MAX_LEN = 255;
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return value.length() <= MAX_LEN ? value : value.substring(0, MAX_LEN);
|
||||
}
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
package com.kamco.cd.kamcoback.postgres.entity;
|
||||
|
||||
import com.kamco.cd.kamcoback.log.dto.AuditLogDto;
|
||||
import com.kamco.cd.kamcoback.log.dto.EventStatus;
|
||||
import com.kamco.cd.kamcoback.log.dto.EventType;
|
||||
import com.kamco.cd.kamcoback.postgres.CommonCreateEntity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.UUID;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Entity
|
||||
@Getter
|
||||
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
@Table(name = "tb_audit_log")
|
||||
public class AuditLogEntity extends CommonCreateEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "audit_log_uid", nullable = false)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "user_uid")
|
||||
private Long userUid;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private EventType eventType;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private EventStatus eventStatus;
|
||||
|
||||
@Column(name = "menu_uid")
|
||||
private String menuUid;
|
||||
|
||||
@Column(name = "ip_address")
|
||||
private String ipAddress;
|
||||
|
||||
@Column(name = "request_uri")
|
||||
private String requestUri;
|
||||
|
||||
@Column(name = "request_body")
|
||||
private String requestBody;
|
||||
|
||||
@Column(name = "error_log_uid")
|
||||
private Long errorLogUid;
|
||||
|
||||
@Column(name = "download_uuid")
|
||||
private UUID downloadUuid;
|
||||
|
||||
@Column(name = "login_attempt_id")
|
||||
private String loginAttemptId;
|
||||
|
||||
public AuditLogEntity(
|
||||
Long userUid,
|
||||
EventType eventType,
|
||||
EventStatus eventStatus,
|
||||
String menuUid,
|
||||
String ipAddress,
|
||||
String requestUri,
|
||||
String requestBody,
|
||||
Long errorLogUid,
|
||||
UUID downloadUuid,
|
||||
String loginAttemptId) {
|
||||
this.userUid = userUid;
|
||||
this.eventType = eventType;
|
||||
this.eventStatus = eventStatus;
|
||||
this.menuUid = menuUid;
|
||||
this.ipAddress = ipAddress;
|
||||
this.requestUri = requestUri;
|
||||
this.requestBody = requestBody;
|
||||
this.errorLogUid = errorLogUid;
|
||||
this.downloadUuid = downloadUuid;
|
||||
this.loginAttemptId = loginAttemptId;
|
||||
}
|
||||
|
||||
/** 파일 다운로드 이력 생성 */
|
||||
public static AuditLogEntity forFileDownload(
|
||||
Long userId,
|
||||
String requestUri,
|
||||
String menuUid,
|
||||
String ip,
|
||||
int httpStatus,
|
||||
UUID downloadUuid) {
|
||||
|
||||
return new AuditLogEntity(
|
||||
userId,
|
||||
EventType.DOWNLOAD, // 이벤트 타입 고정
|
||||
httpStatus < 400 ? EventStatus.SUCCESS : EventStatus.FAILED, // 성공 여부
|
||||
menuUid,
|
||||
ip,
|
||||
requestUri,
|
||||
null, // requestBody 없음
|
||||
null, // errorLogUid 없음
|
||||
downloadUuid,
|
||||
null // loginAttemptId 없음
|
||||
);
|
||||
}
|
||||
|
||||
public AuditLogDto.Basic toDto() {
|
||||
return new AuditLogDto.Basic(
|
||||
this.id,
|
||||
this.userUid,
|
||||
this.eventType,
|
||||
this.eventStatus,
|
||||
this.menuUid,
|
||||
this.ipAddress,
|
||||
this.requestUri,
|
||||
this.requestBody,
|
||||
this.errorLogUid,
|
||||
super.getCreatedDate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(this.id)
|
||||
.append("\n")
|
||||
.append(this.userUid)
|
||||
.append("\n")
|
||||
.append(this.eventType)
|
||||
.append("\n")
|
||||
.append(this.eventStatus)
|
||||
.append("\n")
|
||||
.append(this.menuUid)
|
||||
.append("\n")
|
||||
.append(this.ipAddress)
|
||||
.append("\n")
|
||||
.append(this.requestUri)
|
||||
.append("\n")
|
||||
.append(this.requestBody)
|
||||
.append("\n")
|
||||
.append(this.errorLogUid);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.kamco.cd.kamcoback.postgres.repository.log;
|
||||
|
||||
import com.kamco.cd.kamcoback.postgres.entity.AuditLogEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface AuditLogRepository
|
||||
extends JpaRepository<AuditLogEntity, Long>, AuditLogRepositoryCustom {}
|
||||
@@ -1,29 +0,0 @@
|
||||
package com.kamco.cd.kamcoback.postgres.repository.log;
|
||||
|
||||
import com.kamco.cd.kamcoback.log.dto.AuditLogDto;
|
||||
import com.kamco.cd.kamcoback.log.dto.AuditLogDto.DownloadReq;
|
||||
import java.time.LocalDate;
|
||||
import org.springframework.data.domain.Page;
|
||||
|
||||
public interface AuditLogRepositoryCustom {
|
||||
|
||||
Page<AuditLogDto.DailyAuditList> findLogByDaily(
|
||||
AuditLogDto.searchReq searchReq, LocalDate startDate, LocalDate endDate);
|
||||
|
||||
Page<AuditLogDto.MenuAuditList> findLogByMenu(
|
||||
AuditLogDto.searchReq searchReq, String searchValue);
|
||||
|
||||
Page<AuditLogDto.UserAuditList> findLogByAccount(
|
||||
AuditLogDto.searchReq searchReq, String searchValue);
|
||||
|
||||
Page<AuditLogDto.DownloadRes> findDownloadLog(
|
||||
AuditLogDto.searchReq searchReq, DownloadReq downloadReq);
|
||||
|
||||
Page<AuditLogDto.DailyDetail> findLogByDailyResult(
|
||||
AuditLogDto.searchReq searchReq, LocalDate logDate);
|
||||
|
||||
Page<AuditLogDto.MenuDetail> findLogByMenuResult(AuditLogDto.searchReq searchReq, String menuId);
|
||||
|
||||
Page<AuditLogDto.UserDetail> findLogByAccountResult(
|
||||
AuditLogDto.searchReq searchReq, Long accountId);
|
||||
}
|
||||
@@ -1,523 +0,0 @@
|
||||
package com.kamco.cd.kamcoback.postgres.repository.log;
|
||||
|
||||
import static com.kamco.cd.kamcoback.postgres.entity.QAuditLogEntity.auditLogEntity;
|
||||
import static com.kamco.cd.kamcoback.postgres.entity.QErrorLogEntity.errorLogEntity;
|
||||
import static com.kamco.cd.kamcoback.postgres.entity.QMemberEntity.memberEntity;
|
||||
import static com.kamco.cd.kamcoback.postgres.entity.QMenuEntity.menuEntity;
|
||||
|
||||
import com.kamco.cd.kamcoback.log.dto.AuditLogDto;
|
||||
import com.kamco.cd.kamcoback.log.dto.AuditLogDto.DownloadReq;
|
||||
import com.kamco.cd.kamcoback.log.dto.ErrorLogDto;
|
||||
import com.kamco.cd.kamcoback.log.dto.EventStatus;
|
||||
import com.kamco.cd.kamcoback.log.dto.EventType;
|
||||
import com.kamco.cd.kamcoback.postgres.entity.AuditLogEntity;
|
||||
import com.kamco.cd.kamcoback.postgres.entity.QMenuEntity;
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import com.querydsl.core.types.Projections;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import com.querydsl.core.types.dsl.CaseBuilder;
|
||||
import com.querydsl.core.types.dsl.Expressions;
|
||||
import com.querydsl.core.types.dsl.NumberExpression;
|
||||
import com.querydsl.core.types.dsl.StringExpression;
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
import io.micrometer.common.util.StringUtils;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
|
||||
|
||||
public class AuditLogRepositoryImpl extends QuerydslRepositorySupport
|
||||
implements AuditLogRepositoryCustom {
|
||||
|
||||
private static final ZoneId ZONE = ZoneId.of("Asia/Seoul");
|
||||
private final JPAQueryFactory queryFactory;
|
||||
private final StringExpression NULL_STRING = Expressions.stringTemplate("cast(null as text)");
|
||||
|
||||
public AuditLogRepositoryImpl(JPAQueryFactory queryFactory) {
|
||||
super(AuditLogEntity.class);
|
||||
this.queryFactory = queryFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<AuditLogDto.DailyAuditList> findLogByDaily(
|
||||
AuditLogDto.searchReq searchReq, LocalDate startDate, LocalDate endDate) {
|
||||
StringExpression groupDateTime =
|
||||
Expressions.stringTemplate("to_char({0}, 'YYYY-MM-DD')", auditLogEntity.createdDate);
|
||||
|
||||
Pageable pageable = searchReq.toPageable();
|
||||
List<AuditLogDto.DailyAuditList> foundContent =
|
||||
queryFactory
|
||||
.select(
|
||||
Projections.constructor(
|
||||
AuditLogDto.DailyAuditList.class,
|
||||
readCount().as("readCount"),
|
||||
cudCount().as("cudCount"),
|
||||
printCount().as("printCount"),
|
||||
downloadCount().as("downloadCount"),
|
||||
auditLogEntity.count().as("totalCount"),
|
||||
groupDateTime.as("baseDate")))
|
||||
.from(auditLogEntity)
|
||||
.where(eventEndedAtBetween(startDate, endDate))
|
||||
.groupBy(groupDateTime)
|
||||
.offset(pageable.getOffset())
|
||||
.limit(pageable.getPageSize())
|
||||
.orderBy(groupDateTime.desc())
|
||||
.fetch();
|
||||
|
||||
Long countQuery =
|
||||
queryFactory
|
||||
.select(groupDateTime.countDistinct())
|
||||
.from(auditLogEntity)
|
||||
.where(eventEndedAtBetween(startDate, endDate))
|
||||
.fetchOne();
|
||||
|
||||
return new PageImpl<>(foundContent, pageable, countQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<AuditLogDto.MenuAuditList> findLogByMenu(
|
||||
AuditLogDto.searchReq searchReq, String searchValue) {
|
||||
Pageable pageable = searchReq.toPageable();
|
||||
List<AuditLogDto.MenuAuditList> foundContent =
|
||||
queryFactory
|
||||
.select(
|
||||
Projections.constructor(
|
||||
AuditLogDto.MenuAuditList.class,
|
||||
auditLogEntity.menuUid.as("menuId"),
|
||||
menuEntity.menuNm.max().as("menuName"),
|
||||
readCount().as("readCount"),
|
||||
cudCount().as("cudCount"),
|
||||
printCount().as("printCount"),
|
||||
downloadCount().as("downloadCount"),
|
||||
auditLogEntity.count().as("totalCount")))
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(menuEntity)
|
||||
.on(auditLogEntity.menuUid.eq(menuEntity.menuUid))
|
||||
.where(auditLogEntity.menuUid.ne("SYSTEM"), menuNameEquals(searchValue))
|
||||
.groupBy(auditLogEntity.menuUid)
|
||||
.offset(pageable.getOffset())
|
||||
.limit(pageable.getPageSize())
|
||||
.orderBy(auditLogEntity.createdDate.max().desc())
|
||||
.fetch();
|
||||
|
||||
// count query group by 를 지정하면 하나의 row 가 아니라 그룹핑된 여러 row 가 나올 수 있다.
|
||||
// select query 의 group by 대상의 컬럼을 count query 에선 select distinct 로 처리 한다.
|
||||
Long countQuery =
|
||||
queryFactory
|
||||
.select(auditLogEntity.menuUid.countDistinct())
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(menuEntity)
|
||||
.on(auditLogEntity.menuUid.eq(menuEntity.menuUid))
|
||||
.where(menuNameEquals(searchValue))
|
||||
.fetchOne();
|
||||
|
||||
return new PageImpl<>(foundContent, pageable, countQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<AuditLogDto.UserAuditList> findLogByAccount(
|
||||
AuditLogDto.searchReq searchReq, String searchValue) {
|
||||
Pageable pageable = searchReq.toPageable();
|
||||
List<AuditLogDto.UserAuditList> foundContent =
|
||||
queryFactory
|
||||
.select(
|
||||
Projections.constructor(
|
||||
AuditLogDto.UserAuditList.class,
|
||||
auditLogEntity.userUid.as("accountId"),
|
||||
memberEntity.employeeNo.as("loginId"),
|
||||
memberEntity.name.as("username"),
|
||||
readCount().as("readCount"),
|
||||
cudCount().as("cudCount"),
|
||||
printCount().as("printCount"),
|
||||
downloadCount().as("downloadCount"),
|
||||
auditLogEntity.count().as("totalCount")))
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(memberEntity)
|
||||
.on(auditLogEntity.userUid.eq(memberEntity.id))
|
||||
.where(auditLogEntity.userUid.isNotNull(), loginIdOrUsernameContains(searchValue))
|
||||
.groupBy(auditLogEntity.userUid, memberEntity.employeeNo, memberEntity.name)
|
||||
.offset(pageable.getOffset())
|
||||
.limit(pageable.getPageSize())
|
||||
// .orderBy(auditLogEntity.eventEndedAt.max().desc())
|
||||
.fetch();
|
||||
|
||||
Long countQuery =
|
||||
queryFactory
|
||||
.select(auditLogEntity.userUid.countDistinct())
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(memberEntity)
|
||||
.on(auditLogEntity.userUid.eq(memberEntity.id))
|
||||
.where(loginIdOrUsernameContains(searchValue))
|
||||
.fetchOne();
|
||||
|
||||
return new PageImpl<>(foundContent, pageable, countQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<AuditLogDto.DownloadRes> findDownloadLog(
|
||||
AuditLogDto.searchReq searchReq, DownloadReq req) {
|
||||
Pageable pageable = searchReq.toPageable();
|
||||
|
||||
BooleanBuilder whereBuilder = new BooleanBuilder();
|
||||
|
||||
whereBuilder.and(auditLogEntity.eventStatus.ne(EventStatus.valueOf("FAILED")));
|
||||
whereBuilder.and(auditLogEntity.eventType.eq(EventType.valueOf("DOWNLOAD")));
|
||||
|
||||
if (req.getMenuId() != null && !req.getMenuId().isEmpty()) {
|
||||
whereBuilder.and(auditLogEntity.menuUid.eq(req.getMenuId()));
|
||||
}
|
||||
|
||||
if (req.getUuid() != null) {
|
||||
whereBuilder.and(auditLogEntity.requestUri.contains("/api/inference/download/"));
|
||||
whereBuilder.and(auditLogEntity.requestUri.endsWith(String.valueOf(req.getUuid())));
|
||||
}
|
||||
|
||||
if (req.getSearchValue() != null && !req.getSearchValue().isEmpty()) {
|
||||
whereBuilder.and(
|
||||
memberEntity
|
||||
.name
|
||||
.contains(req.getSearchValue())
|
||||
.or(memberEntity.employeeNo.contains(req.getSearchValue())));
|
||||
}
|
||||
|
||||
List<AuditLogDto.DownloadRes> foundContent =
|
||||
queryFactory
|
||||
.select(
|
||||
Projections.constructor(
|
||||
AuditLogDto.DownloadRes.class,
|
||||
memberEntity.name,
|
||||
memberEntity.employeeNo,
|
||||
auditLogEntity.createdDate.as("downloadDttm")))
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(memberEntity)
|
||||
.on(auditLogEntity.userUid.eq(memberEntity.id))
|
||||
.where(whereBuilder, createdDateBetween(req.getStartDate(), req.getEndDate()))
|
||||
.offset(pageable.getOffset())
|
||||
.limit(pageable.getPageSize())
|
||||
.orderBy(auditLogEntity.createdDate.desc())
|
||||
.fetch();
|
||||
|
||||
Long countQuery =
|
||||
queryFactory
|
||||
.select(auditLogEntity.userUid.countDistinct())
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(memberEntity)
|
||||
.on(auditLogEntity.userUid.eq(memberEntity.id))
|
||||
.where(whereBuilder, createdDateBetween(req.getStartDate(), req.getEndDate()))
|
||||
.fetchOne();
|
||||
|
||||
return new PageImpl<>(foundContent, pageable, countQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<AuditLogDto.DailyDetail> findLogByDailyResult(
|
||||
AuditLogDto.searchReq searchReq, LocalDate logDate) {
|
||||
Pageable pageable = searchReq.toPageable();
|
||||
QMenuEntity parent = new QMenuEntity("parent");
|
||||
// 1depth menu name
|
||||
StringExpression parentMenuName =
|
||||
new CaseBuilder()
|
||||
.when(parent.menuUid.isNull())
|
||||
.then(menuEntity.menuNm)
|
||||
.otherwise(parent.menuNm);
|
||||
|
||||
// 2depth menu name
|
||||
StringExpression menuName =
|
||||
new CaseBuilder()
|
||||
.when(parent.menuUid.isNull())
|
||||
.then(NULL_STRING)
|
||||
.otherwise(menuEntity.menuNm);
|
||||
|
||||
List<AuditLogDto.DailyDetail> foundContent =
|
||||
queryFactory
|
||||
.select(
|
||||
Projections.constructor(
|
||||
AuditLogDto.DailyDetail.class,
|
||||
auditLogEntity.id.as("logId"),
|
||||
memberEntity.name.as("userName"),
|
||||
memberEntity.employeeNo.as("loginId"),
|
||||
menuEntity.menuNm.as("menuName"),
|
||||
auditLogEntity.eventType.as("eventType"),
|
||||
Expressions.stringTemplate(
|
||||
"to_char({0}, 'YYYY-MM-DD HH24:MI')", auditLogEntity.createdDate)
|
||||
.as("logDateTime"),
|
||||
Projections.constructor(
|
||||
AuditLogDto.LogDetail.class,
|
||||
Expressions.constant("한국자산관리공사"), // serviceName
|
||||
parentMenuName.as("parentMenuName"),
|
||||
menuName,
|
||||
menuEntity.menuUrl.as("menuUrl"),
|
||||
menuEntity.description.as("menuDescription"),
|
||||
menuEntity.menuOrder.as("sortOrder"),
|
||||
menuEntity.isUse.as("used")))) // TODO
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(menuEntity)
|
||||
.on(auditLogEntity.menuUid.eq(menuEntity.menuUid))
|
||||
.leftJoin(menuEntity.parent, parent)
|
||||
.leftJoin(memberEntity)
|
||||
.on(auditLogEntity.userUid.eq(memberEntity.id))
|
||||
.where(eventEndedAtEqDate(logDate))
|
||||
.offset(pageable.getOffset())
|
||||
.limit(pageable.getPageSize())
|
||||
.orderBy(auditLogEntity.createdDate.desc())
|
||||
.fetch();
|
||||
|
||||
Long countQuery =
|
||||
queryFactory
|
||||
.select(auditLogEntity.id.countDistinct())
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(menuEntity)
|
||||
.on(auditLogEntity.menuUid.eq(menuEntity.menuUid))
|
||||
.leftJoin(menuEntity.parent, parent)
|
||||
.leftJoin(memberEntity)
|
||||
.on(auditLogEntity.userUid.eq(memberEntity.id))
|
||||
.where(eventEndedAtEqDate(logDate))
|
||||
.fetchOne();
|
||||
|
||||
return new PageImpl<>(foundContent, pageable, countQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<AuditLogDto.MenuDetail> findLogByMenuResult(
|
||||
AuditLogDto.searchReq searchReq, String menuUid) {
|
||||
Pageable pageable = searchReq.toPageable();
|
||||
QMenuEntity parent = new QMenuEntity("parent");
|
||||
// 1depth menu name
|
||||
StringExpression parentMenuName =
|
||||
new CaseBuilder()
|
||||
.when(parent.menuUid.isNull())
|
||||
.then(menuEntity.menuNm)
|
||||
.otherwise(parent.menuNm);
|
||||
|
||||
// 2depth menu name
|
||||
StringExpression menuName =
|
||||
new CaseBuilder()
|
||||
.when(parent.menuUid.isNull())
|
||||
.then(NULL_STRING)
|
||||
.otherwise(menuEntity.menuNm);
|
||||
|
||||
List<AuditLogDto.MenuDetail> foundContent =
|
||||
queryFactory
|
||||
.select(
|
||||
Projections.constructor(
|
||||
AuditLogDto.MenuDetail.class,
|
||||
auditLogEntity.id.as("logId"),
|
||||
Expressions.stringTemplate(
|
||||
"to_char({0}, 'YYYY-MM-DD HH24:MI')", auditLogEntity.createdDate)
|
||||
.as("logDateTime"),
|
||||
memberEntity.name.as("userName"),
|
||||
memberEntity.employeeNo.as("loginId"),
|
||||
auditLogEntity.eventType.as("eventType"),
|
||||
Projections.constructor(
|
||||
AuditLogDto.LogDetail.class,
|
||||
Expressions.constant("한국자산관리공사"), // serviceName
|
||||
parentMenuName.as("parentMenuName"),
|
||||
menuName,
|
||||
menuEntity.menuUrl.as("menuUrl"),
|
||||
menuEntity.description.as("menuDescription"),
|
||||
menuEntity.menuOrder.as("sortOrder"),
|
||||
menuEntity.isUse.as("used"))))
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(menuEntity)
|
||||
.on(auditLogEntity.menuUid.eq(menuEntity.menuUid))
|
||||
.leftJoin(menuEntity.parent, parent)
|
||||
.leftJoin(memberEntity)
|
||||
.on(auditLogEntity.userUid.eq(memberEntity.id))
|
||||
.where(menuUidEq(menuUid))
|
||||
.offset(pageable.getOffset())
|
||||
.limit(pageable.getPageSize())
|
||||
.orderBy(auditLogEntity.createdDate.desc())
|
||||
.fetch();
|
||||
|
||||
Long countQuery =
|
||||
queryFactory
|
||||
.select(auditLogEntity.id.countDistinct())
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(menuEntity)
|
||||
.on(auditLogEntity.menuUid.eq(menuEntity.menuUid))
|
||||
.leftJoin(menuEntity.parent, parent)
|
||||
.leftJoin(memberEntity)
|
||||
.on(auditLogEntity.userUid.eq(memberEntity.id))
|
||||
.where(menuUidEq(menuUid))
|
||||
.fetchOne();
|
||||
|
||||
return new PageImpl<>(foundContent, pageable, countQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<AuditLogDto.UserDetail> findLogByAccountResult(
|
||||
AuditLogDto.searchReq searchReq, Long userUid) {
|
||||
Pageable pageable = searchReq.toPageable();
|
||||
QMenuEntity parent = new QMenuEntity("parent");
|
||||
// 1depth menu name
|
||||
StringExpression parentMenuName =
|
||||
new CaseBuilder()
|
||||
.when(parent.menuUid.isNull())
|
||||
.then(menuEntity.menuNm)
|
||||
.otherwise(parent.menuNm);
|
||||
|
||||
// 2depth menu name
|
||||
StringExpression menuName =
|
||||
new CaseBuilder()
|
||||
.when(parent.menuUid.isNull())
|
||||
.then(NULL_STRING)
|
||||
.otherwise(menuEntity.menuNm);
|
||||
|
||||
List<AuditLogDto.UserDetail> foundContent =
|
||||
queryFactory
|
||||
.select(
|
||||
Projections.constructor(
|
||||
AuditLogDto.UserDetail.class,
|
||||
auditLogEntity.id.as("logId"),
|
||||
Expressions.stringTemplate(
|
||||
"to_char({0}, 'YYYY-MM-DD HH24:MI')", auditLogEntity.createdDate)
|
||||
.as("logDateTime"),
|
||||
menuEntity.menuNm.as("menuName"),
|
||||
auditLogEntity.eventType.as("eventType"),
|
||||
Projections.constructor(
|
||||
AuditLogDto.LogDetail.class,
|
||||
Expressions.constant("한국자산관리공사"), // serviceName
|
||||
parentMenuName.as("parentMenuName"),
|
||||
menuName,
|
||||
menuEntity.menuUrl.as("menuUrl"),
|
||||
menuEntity.description.as("menuDescription"),
|
||||
menuEntity.menuOrder.as("sortOrder"),
|
||||
menuEntity.isUse.as("used"))))
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(menuEntity)
|
||||
.on(auditLogEntity.menuUid.eq(menuEntity.menuUid))
|
||||
.leftJoin(menuEntity.parent, parent)
|
||||
.leftJoin(memberEntity)
|
||||
.on(auditLogEntity.userUid.eq(memberEntity.id))
|
||||
.where(userUidEq(userUid))
|
||||
.offset(pageable.getOffset())
|
||||
.limit(pageable.getPageSize())
|
||||
.orderBy(auditLogEntity.createdDate.desc())
|
||||
.fetch();
|
||||
|
||||
Long countQuery =
|
||||
queryFactory
|
||||
.select(auditLogEntity.id.countDistinct())
|
||||
.from(auditLogEntity)
|
||||
.leftJoin(menuEntity)
|
||||
.on(auditLogEntity.menuUid.eq(menuEntity.menuUid))
|
||||
.leftJoin(menuEntity.parent, parent)
|
||||
.leftJoin(memberEntity)
|
||||
.on(auditLogEntity.userUid.eq(memberEntity.id))
|
||||
.where(userUidEq(userUid))
|
||||
.fetchOne();
|
||||
|
||||
return new PageImpl<>(foundContent, pageable, countQuery);
|
||||
}
|
||||
|
||||
private BooleanExpression eventEndedAtBetween(LocalDate startDate, LocalDate endDate) {
|
||||
if (Objects.isNull(startDate) || Objects.isNull(endDate)) {
|
||||
return null;
|
||||
}
|
||||
ZoneId zoneId = ZoneId.of("Asia/Seoul");
|
||||
ZonedDateTime startDateTime = startDate.atStartOfDay(zoneId);
|
||||
ZonedDateTime endDateTime = endDate.plusDays(1).atStartOfDay(zoneId);
|
||||
return auditLogEntity
|
||||
.createdDate
|
||||
.goe(startDateTime)
|
||||
.and(auditLogEntity.createdDate.lt(endDateTime));
|
||||
}
|
||||
|
||||
private BooleanExpression createdDateBetween(LocalDate startDate, LocalDate endDate) {
|
||||
if (startDate == null || endDate == null) {
|
||||
return null;
|
||||
}
|
||||
ZonedDateTime start = startDate.atStartOfDay(ZONE);
|
||||
ZonedDateTime endExclusive = endDate.plusDays(1).atStartOfDay(ZONE);
|
||||
|
||||
return auditLogEntity.createdDate.goe(start).and(auditLogEntity.createdDate.lt(endExclusive));
|
||||
}
|
||||
|
||||
private BooleanExpression menuNameEquals(String searchValue) {
|
||||
if (StringUtils.isBlank(searchValue)) {
|
||||
return null;
|
||||
}
|
||||
return menuEntity.menuNm.contains(searchValue);
|
||||
}
|
||||
|
||||
private BooleanExpression loginIdOrUsernameContains(String searchValue) {
|
||||
if (StringUtils.isBlank(searchValue)) {
|
||||
return null;
|
||||
}
|
||||
return memberEntity
|
||||
.employeeNo
|
||||
.contains(searchValue)
|
||||
.or(memberEntity.name.contains(searchValue));
|
||||
}
|
||||
|
||||
private BooleanExpression eventStatusEqFailed() {
|
||||
return auditLogEntity.eventStatus.eq(EventStatus.FAILED);
|
||||
}
|
||||
|
||||
private BooleanExpression eventTypeEq(EventType eventType) {
|
||||
if (Objects.isNull(eventType)) {
|
||||
return null;
|
||||
}
|
||||
return auditLogEntity.eventType.eq(eventType);
|
||||
}
|
||||
|
||||
private BooleanExpression errorLevelEq(ErrorLogDto.LogErrorLevel level) {
|
||||
if (Objects.isNull(level)) {
|
||||
return null;
|
||||
}
|
||||
return errorLogEntity.errorLevel.eq(ErrorLogDto.LogErrorLevel.valueOf(level.name()));
|
||||
}
|
||||
|
||||
private BooleanExpression eventEndedAtEqDate(LocalDate logDate) {
|
||||
ZoneId zoneId = ZoneId.of("Asia/Seoul");
|
||||
ZonedDateTime start = logDate.atStartOfDay(zoneId);
|
||||
ZonedDateTime end = logDate.plusDays(1).atStartOfDay(zoneId);
|
||||
|
||||
return auditLogEntity.createdDate.goe(start).and(auditLogEntity.createdDate.lt(end));
|
||||
}
|
||||
|
||||
private BooleanExpression menuUidEq(String menuUid) {
|
||||
return auditLogEntity.menuUid.eq(menuUid);
|
||||
}
|
||||
|
||||
private BooleanExpression userUidEq(Long userUid) {
|
||||
return auditLogEntity.userUid.eq(userUid);
|
||||
}
|
||||
|
||||
private NumberExpression<Integer> readCount() {
|
||||
return new CaseBuilder()
|
||||
.when(auditLogEntity.eventType.in(EventType.LIST, EventType.DETAIL))
|
||||
.then(1)
|
||||
.otherwise(0)
|
||||
.sum();
|
||||
}
|
||||
|
||||
private NumberExpression<Integer> cudCount() {
|
||||
return new CaseBuilder()
|
||||
.when(auditLogEntity.eventType.in(EventType.ADDED, EventType.MODIFIED, EventType.REMOVE))
|
||||
.then(1)
|
||||
.otherwise(0)
|
||||
.sum();
|
||||
}
|
||||
|
||||
private NumberExpression<Integer> printCount() {
|
||||
return new CaseBuilder()
|
||||
.when(auditLogEntity.eventType.eq(EventType.OTHER))
|
||||
.then(1)
|
||||
.otherwise(0)
|
||||
.sum();
|
||||
}
|
||||
|
||||
private NumberExpression<Integer> downloadCount() {
|
||||
return new CaseBuilder()
|
||||
.when(auditLogEntity.eventType.eq(EventType.DOWNLOAD))
|
||||
.then(1)
|
||||
.otherwise(0)
|
||||
.sum();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.kamco.cd.kamcoback.scheduler.service;
|
||||
|
||||
import com.kamco.cd.kamcoback.common.utils.NetUtils;
|
||||
import com.kamco.cd.kamcoback.common.utils.UserUtil;
|
||||
import com.kamco.cd.kamcoback.config.api.ApiLogFunction;
|
||||
import com.kamco.cd.kamcoback.config.resttemplate.ExternalHttpClient;
|
||||
import com.kamco.cd.kamcoback.config.resttemplate.ExternalHttpClient.ExternalCallResult;
|
||||
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectContDto;
|
||||
@@ -12,11 +10,7 @@ import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto;
|
||||
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.LearnKeyDto;
|
||||
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.ResultDto;
|
||||
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinStatus;
|
||||
import com.kamco.cd.kamcoback.log.dto.EventStatus;
|
||||
import com.kamco.cd.kamcoback.log.dto.EventType;
|
||||
import com.kamco.cd.kamcoback.postgres.core.GukYuinPnuJobCoreService;
|
||||
import com.kamco.cd.kamcoback.postgres.entity.AuditLogEntity;
|
||||
import com.kamco.cd.kamcoback.postgres.repository.log.AuditLogRepository;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
@@ -24,8 +18,6 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Log4j2
|
||||
@Service
|
||||
@@ -35,9 +27,6 @@ public class GukYuinApiPnuJobService {
|
||||
private final GukYuinPnuJobCoreService gukYuinPnuJobCoreService;
|
||||
private final ExternalHttpClient externalHttpClient;
|
||||
private final NetUtils netUtils = new NetUtils();
|
||||
private final AuditLogRepository auditLogRepository;
|
||||
|
||||
private final UserUtil userUtil;
|
||||
|
||||
@Value("${spring.profiles.active}")
|
||||
private String profile;
|
||||
@@ -97,14 +86,6 @@ public class GukYuinApiPnuJobService {
|
||||
externalHttpClient.call(
|
||||
url, HttpMethod.GET, null, netUtils.jsonHeaders(), ChngDetectMastDto.ResultDto.class);
|
||||
|
||||
this.insertGukyuinAuditLog(
|
||||
EventType.DETAIL.getId(),
|
||||
netUtils.getLocalIP(),
|
||||
userUtil.getId(),
|
||||
url.replace(gukyuinUrl, ""),
|
||||
null,
|
||||
response.body().getSuccess());
|
||||
|
||||
ResultDto result = response.body();
|
||||
if (result == null || result.getResult() == null || result.getResult().isEmpty()) {
|
||||
return succCnt;
|
||||
@@ -161,14 +142,6 @@ public class GukYuinApiPnuJobService {
|
||||
}
|
||||
}
|
||||
|
||||
this.insertGukyuinAuditLog(
|
||||
EventType.LIST.getId(),
|
||||
netUtils.getLocalIP(),
|
||||
userUtil.getId(),
|
||||
url.replace(gukyuinUrl, ""),
|
||||
null,
|
||||
response.body().getSuccess());
|
||||
|
||||
ResultContDto cont = response.body();
|
||||
if (cont == null || cont.getResult().isEmpty()) {
|
||||
return result; // 외부 API 이상 방어
|
||||
@@ -188,33 +161,4 @@ public class GukYuinApiPnuJobService {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = false)
|
||||
public void insertGukyuinAuditLog(
|
||||
String actionType,
|
||||
String myIp,
|
||||
Long userUid,
|
||||
String requestUri,
|
||||
Object requestBody,
|
||||
boolean successFail) {
|
||||
try {
|
||||
AuditLogEntity log =
|
||||
new AuditLogEntity(
|
||||
userUid,
|
||||
EventType.fromName(actionType),
|
||||
successFail ? EventStatus.SUCCESS : EventStatus.FAILED,
|
||||
"GUKYUIN", // 메뉴도 국유인으로 하나 따기
|
||||
myIp,
|
||||
requestUri,
|
||||
requestBody == null ? null : ApiLogFunction.cutRequestBody(requestBody.toString()),
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
auditLogRepository.save(log);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user