Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • aolda/proxy-manager-backend
1 result
Select Git revision
Show changes
Commits on Source (5)
Showing
with 651 additions and 42 deletions
......@@ -30,12 +30,19 @@ dependencies {
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
runtimeOnly 'com.mysql:mysql-connector-j'
implementation 'org.pacesys:openstack4j:3.1.0'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
}
tasks.named('test') {
useJUnitPlatform()
}
clean {
delete file('src/main/generated')
}
\ No newline at end of file
package com.aolda.itda.aspect;
import com.aolda.itda.dto.forwarding.ForwardingDTO;
import com.aolda.itda.entity.forwarding.Forwarding;
import com.aolda.itda.entity.log.Action;
import com.aolda.itda.entity.log.Log;
import com.aolda.itda.entity.log.ObjectType;
import com.aolda.itda.entity.user.User;
import com.aolda.itda.exception.CustomException;
import com.aolda.itda.exception.ErrorCode;
import com.aolda.itda.repository.certificate.CertificateRepository;
import com.aolda.itda.repository.forwarding.ForwardingRepository;
import com.aolda.itda.repository.log.LogRepository;
import com.aolda.itda.repository.routing.RoutingRepository;
import com.aolda.itda.repository.user.UserRepository;
import com.aolda.itda.service.AuthService;
import jakarta.persistence.EntityManager;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.Map;
import java.util.Objects;
@Aspect
@Component
@RequiredArgsConstructor
public class ForwardingLogAspect {
private final ForwardingRepository forwardingRepository;
private final LogRepository logRepository;
private final EntityManager entityManager;
private final UserRepository userRepository;
/* Create 로깅 */
@AfterReturning(pointcut = "execution(* com.aolda.itda.service.forwarding.*Service.*create*(..))"
, returning = "result")
public void createLogging(JoinPoint joinPoint, ForwardingDTO result) {
/* 사용자 조회 */
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
Map<String, String> tmp = (Map<String, String>) request.getAttribute("user");
User user = userRepository.findByKeystoneId(tmp.get("id")).orElseThrow(
() -> new CustomException(ErrorCode.NOT_FOUND_USER)
);
/* 생성된 엔티티 조회 */
Forwarding forwarding = forwardingRepository.findByForwardingIdAndIsDeleted(result.getId(), false).orElse(null);
/* 로그 메세지 작성 */
String description = "name: " + forwarding.getName() + "\n"
+ "serverPort: " + forwarding.getServerPort() + "\n"
+ "instanceIp: " + forwarding.getInstanceIp() + "\n"
+ "instancePort: " + forwarding.getInstancePort();
/* 로그 엔티티 저장 */
logRepository.save(Log.builder()
.user(user)
.objectType(ObjectType.FORWARDING)
.objectId(forwarding.getForwardingId())
.action(Action.CREATE)
.projectId(forwarding.getProjectId())
.description(description)
.build());
}
/* Delete 로깅 */
@AfterReturning(pointcut = "execution(* com.aolda.itda.service.forwarding.*Service.*delete*(..))")
public void deleteLogging(JoinPoint joinPoint) {
/* 사용자 조회 */
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
Map<String, String> tmp = (Map<String, String>) request.getAttribute("user");
User user = userRepository.findByKeystoneId(tmp.get("id")).orElseThrow(
() -> new CustomException(ErrorCode.NOT_FOUND_USER)
);
/* 삭제된 엔티티 조회 */
Object[] args = joinPoint.getArgs();
Long id = (Long) args[0];
Forwarding forwarding = forwardingRepository.findByForwardingIdAndIsDeleted(id, true).orElse(null);
/* 로그 메세지 작성 */
String description = "name: " + forwarding.getName() + "\n"
+ "serverPort: " + forwarding.getServerPort() + "\n"
+ "instanceIp: " + forwarding.getInstanceIp() + "\n"
+ "instancePort: " + forwarding.getInstancePort();
/* 로그 엔티티 저장 */
logRepository.save(Log.builder()
.user(user)
.objectType(ObjectType.FORWARDING)
.objectId(forwarding.getForwardingId())
.action(Action.DELETE)
.projectId(forwarding.getProjectId())
.description(description)
.build());
}
/* Update(edit) 로깅 */
@Around("execution(* com.aolda.itda.service.forwarding.*Service.*edit*(..))")
public Object editLogging(ProceedingJoinPoint joinPoint) throws Throwable {
/* 사용자 조회 */
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
Map<String, String> tmp = (Map<String, String>) request.getAttribute("user");
User user = userRepository.findByKeystoneId(tmp.get("id")).orElseThrow(
() -> new CustomException(ErrorCode.NOT_FOUND_USER)
);
/* 변경 전 엔티티 조회 */
Object[] args = joinPoint.getArgs();
Long id = (Long) args[0];
Forwarding old = forwardingRepository.findByForwardingIdAndIsDeleted(id, false).orElse(null);
if (old != null) {
entityManager.detach(old);
}
/* 메소드 진행 */
Object result = joinPoint.proceed();
/* 변경 후 엔티티 조회*/
Forwarding newObj = forwardingRepository.findByForwardingIdAndIsDeleted(id, false).orElse(null);
/* 로그 메세지 작성 */
String description = "name: " + old.getName() + (old.getName().equals(newObj.getName()) ? "" : (" -> " + newObj.getName())) + "\n"
+ "serverPort: " + old.getServerPort() + (old.getServerPort().equals(newObj.getServerPort()) ? "" : (" -> " + newObj.getServerPort())) + "\n"
+ "instanceIp: " + old.getInstanceIp() + (old.getInstanceIp().equals(newObj.getInstanceIp()) ? "" : (" -> " + newObj.getInstanceIp())) + "\n"
+ "instancePort: " + old.getInstancePort() + (old.getInstancePort().equals(newObj.getInstancePort()) ? "" : (" -> " + newObj.getInstancePort()));
/* 로그 엔티티 저장 */
logRepository.save(Log.builder()
.user(user)
.objectType(ObjectType.FORWARDING)
.objectId(newObj.getForwardingId())
.action(Action.UPDATE)
.projectId(newObj.getProjectId())
.description(description)
.build());
return result;
}
}
package com.aolda.itda.aspect;
import com.aolda.itda.dto.forwarding.ForwardingDTO;
import com.aolda.itda.dto.routing.RoutingDTO;
import com.aolda.itda.entity.forwarding.Forwarding;
import com.aolda.itda.entity.log.Action;
import com.aolda.itda.entity.log.Log;
import com.aolda.itda.entity.log.ObjectType;
import com.aolda.itda.entity.routing.Routing;
import com.aolda.itda.entity.user.User;
import com.aolda.itda.exception.CustomException;
import com.aolda.itda.exception.ErrorCode;
import com.aolda.itda.repository.forwarding.ForwardingRepository;
import com.aolda.itda.repository.log.LogRepository;
import com.aolda.itda.repository.routing.RoutingRepository;
import com.aolda.itda.repository.user.UserRepository;
import jakarta.persistence.EntityManager;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.Map;
import java.util.Objects;
@Aspect
@Component
@RequiredArgsConstructor
public class RoutingLogAspect {
private final RoutingRepository routingRepository;
private final UserRepository userRepository;
private final LogRepository logRepository;
private final EntityManager entityManager;
/* Create 로깅 */
@AfterReturning(pointcut = "execution(* com.aolda.itda.service.routing.*Service.*create*(..))"
, returning = "result")
public void createLogging(JoinPoint joinPoint, RoutingDTO result) {
/* 사용자 조회 */
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
Map<String, String> tmp = (Map<String, String>) request.getAttribute("user");
User user = userRepository.findByKeystoneId(tmp.get("id")).orElseThrow(
() -> new CustomException(ErrorCode.NOT_FOUND_USER)
);
/* 생성된 엔티티 조회 */
Routing routing = routingRepository.findByRoutingIdAndIsDeleted(result.getId(), false).orElse(null);
/* 로그 메세지 작성 */
String description = "name: " + routing.getName() + "\n"
+ "domain: " + routing.getDomain() + "\n"
+ "ip: " + routing.getInstanceIp() + "\n"
+ "port: " + routing.getInstancePort() + "\n"
+ (routing.getCertificate() != null ? ("certificateId: " + routing.getCertificate().getCertificateId() + "\n") : "")
+ "caching: " + routing.getCaching() + "\n";
/* 로그 엔티티 저장 */
logRepository.save(Log.builder()
.user(user)
.objectType(ObjectType.ROUTING)
.objectId(routing.getRoutingId())
.action(Action.CREATE)
.projectId(routing.getProjectId())
.description(description)
.build());
}
/* Delete 로깅 */
@AfterReturning(pointcut = "execution(* com.aolda.itda.service.routing.*Service.*delete*(..))")
public void deleteLogging(JoinPoint joinPoint) {
/* 사용자 조회 */
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
Map<String, String> tmp = (Map<String, String>) request.getAttribute("user");
User user = userRepository.findByKeystoneId(tmp.get("id")).orElseThrow(
() -> new CustomException(ErrorCode.NOT_FOUND_USER)
);
/* 삭제된 엔티티 조회 */
Object[] args = joinPoint.getArgs();
Long id = (Long) args[0];
Routing routing = routingRepository.findByRoutingIdAndIsDeleted(id, true).orElse(null);
/* 로그 메세지 작성 */
String description = "name: " + routing.getName() + "\n"
+ "domain: " + routing.getDomain() + "\n"
+ "ip: " + routing.getInstanceIp() + "\n"
+ "port: " + routing.getInstancePort() + "\n"
+ (routing.getCertificate() != null ? ("certificateId: " + routing.getCertificate().getCertificateId() + "\n") : "")
+ "caching: " + routing.getCaching() + "\n";
/* 로그 엔티티 저장 */
logRepository.save(Log.builder()
.user(user)
.objectType(ObjectType.ROUTING)
.objectId(routing.getRoutingId())
.action(Action.DELETE)
.projectId(routing.getProjectId())
.description(description)
.build());
}
/* Update(edit) 로깅 */
@Around("execution(* com.aolda.itda.service.routing.*Service.*edit*(..))")
public Object editLogging(ProceedingJoinPoint joinPoint) throws Throwable {
/* 사용자 조회 */
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
Map<String, String> tmp = (Map<String, String>) request.getAttribute("user");
User user = userRepository.findByKeystoneId(tmp.get("id")).orElseThrow(
() -> new CustomException(ErrorCode.NOT_FOUND_USER)
);
/* 변경 전 엔티티 조회 */
Object[] args = joinPoint.getArgs();
Long id = (Long) args[0];
Routing old = routingRepository.findByRoutingIdAndIsDeleted(id, false).orElse(null);
if (old != null) {
entityManager.detach(old);
}
/* 메소드 진행 */
Object result = joinPoint.proceed();
/* 변경 후 엔티티 조회 */
Routing newObj = routingRepository.findByRoutingIdAndIsDeleted(id, false).orElse(null);
/* 로그 메세지 작성 */
String description = "name: " + old.getName() + (old.getName().equals(newObj.getName()) ? "" : " -> " + newObj.getName()) + "\n"
+ "domain: " + old.getDomain() + (old.getDomain().equals(newObj.getDomain()) ? "" : " -> " + newObj.getDomain()) + "\n"
+ "ip: " + old.getInstanceIp() + (old.getInstanceIp().equals(newObj.getInstanceIp()) ? "" : " -> " + newObj.getInstanceIp()) + "\n"
+ "port: " + old.getInstancePort() + (old.getInstancePort().equals(newObj.getInstancePort()) ? "" : " -> " + newObj.getInstancePort()) + "\n";
if (old.getCertificate() == null) {
if (newObj.getCertificate() != null) {
description = description + "certificateId: null -> " + newObj.getCertificate().getCertificateId() + "\n";
}
}
else {
if (newObj.getCertificate() == null) {
description = description + "certificateId: " + old.getCertificate().getCertificateId() + " -> null\n";
}
else {
description = description + "certificateId: " + old.getCertificate().getCertificateId() + " -> " + newObj.getCertificate().getCertificateId() + "\n";
}
}
description = description + "caching: " + (old.getCaching() == newObj.getCaching() ? newObj.getCaching() : (" -> " + newObj.getCaching()));
/* 로그 엔티티 저장 */
logRepository.save(Log.builder()
.user(user)
.objectType(ObjectType.ROUTING)
.objectId(newObj.getRoutingId())
.action(Action.UPDATE)
.projectId(newObj.getProjectId())
.description(description)
.build());
return result;
}
}
package com.aolda.itda.config;
import com.aolda.itda.dto.auth.IdAndNameDTO;
import com.aolda.itda.exception.CustomException;
import com.aolda.itda.exception.ErrorCode;
import com.aolda.itda.service.AuthService;
......@@ -10,6 +11,9 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import java.util.List;
import java.util.Map;
@RequiredArgsConstructor
@Component
@Slf4j
......@@ -20,18 +24,44 @@ public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("X-Subject-Token");
/* 토큰 헤더 검증 */
if (token == null || token.isEmpty()) {
throw new CustomException(ErrorCode.INVALID_TOKEN, request.getRequestURI());
}
// 어드민과 일반 유저 구분 필요
try {
if (authService.validateTokenAndGetUserId(token) != null) {
return true;
}
} catch (Exception e) {
log.error("Token validation failed for URI {}: {}", request.getRequestURI(), e.getMessage(), e);
/* 유효 토큰 검증 */
String userId = authService.validateTokenAndGetUserId(token);
if (userId == null) {
log.error("Token validation failed for URI {}: {}", request.getRequestURI(), request.getRemoteAddr());
throw new CustomException(ErrorCode.INVALID_TOKEN, request.getRequestURI());
}
throw new CustomException(ErrorCode.INVALID_TOKEN, request.getRequestURI());
/* 프로젝트 권한 검증 */
String projectId = request.getParameter("projectId");
if (projectId != null) {
try {
String role = authService.getBestRoleWithinProject(token, projectId).get("role");
if (!role.equals("admin")) {
log.error("Unauthorized Token for URI {}: {}", request.getRequestURI(), request.getRemoteAddr());
throw new CustomException(ErrorCode.UNAUTHORIZED_USER, request.getRequestURI());
}
} catch (Exception e) {
throw new CustomException(ErrorCode.UNAUTHORIZED_USER, request.getRequestURI());
}
}
/* 프로젝트 리스트 조회 */
List<String> projects = authService.getProjectsWithUser(Map.of("id", userId, "token", token))
.stream().map(IdAndNameDTO::getId)
.toList();
request.setAttribute("projects", projects);
request.setAttribute("user", Map.of("id", userId, "token", token));
return true;
}
}
package com.aolda.itda.config;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
......@@ -25,10 +28,15 @@ public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
String[] excludeAuth = {"/error", "/api/auth/*", "/api/*" };
String[] excludeAuth = {"/error", "/api/auth/*" };
registry.addInterceptor(authInterceptor)
.addPathPatterns("/**")
.excludePathPatterns(excludeAuth);
}
@Bean
public JPAQueryFactory jpaQueryFactory(EntityManager em) {
return new JPAQueryFactory(em);
}
}
......@@ -2,11 +2,14 @@ package com.aolda.itda.controller.forwarding;
import com.aolda.itda.dto.forwarding.ForwardingDTO;
import com.aolda.itda.service.forwarding.ForwardingService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
......@@ -22,8 +25,8 @@ public class ForwardingController {
}
@GetMapping("/forwarding")
public ResponseEntity<Object> view(@RequestParam Long forwardingId) {
return ResponseEntity.ok(forwardingService.getForwarding(forwardingId));
public ResponseEntity<Object> view(@RequestParam Long forwardingId, HttpServletRequest request) {
return ResponseEntity.ok(forwardingService.getForwarding(forwardingId, (List<String>) request.getAttribute("projects")));
}
@GetMapping("/forwardings")
......@@ -33,14 +36,16 @@ public class ForwardingController {
@PatchMapping("/forwarding")
public ResponseEntity<Object> edit(@RequestParam Long forwardingId,
@RequestBody ForwardingDTO dto) {
forwardingService.editForwarding(forwardingId, dto);
@RequestBody ForwardingDTO dto,
HttpServletRequest request) {
forwardingService.editForwarding(forwardingId, dto, (List<String>) request.getAttribute("projects") );
return ResponseEntity.ok().build();
}
@DeleteMapping("/forwarding")
public ResponseEntity<Object> delete(@RequestParam Long forwardingId) {
forwardingService.deleteForwarding(forwardingId);
public ResponseEntity<Object> delete(@RequestParam Long forwardingId,
HttpServletRequest request) {
forwardingService.deleteForwarding(forwardingId, (List<String>) request.getAttribute("projects"));
return ResponseEntity.ok().build();
}
......
package com.aolda.itda.controller.log;
import com.aolda.itda.service.log.LogService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class LogController {
private final LogService logService;
@GetMapping("/log")
public ResponseEntity<Object> view(@RequestParam Long logId, HttpServletRequest request) {
return ResponseEntity.ok(logService.getLog(logId, (List<String>) request.getAttribute("projects")));
}
@GetMapping("/logs")
public ResponseEntity<Object> lists(@RequestParam(required = false) String projectId
,@RequestParam(required = false) String type
,@RequestParam(required = false) String username
,@RequestParam(required = false) String action
,@RequestParam(defaultValue = "false") boolean isASC
,@PageableDefault(size = 10) Pageable pageable
,HttpServletRequest request) {
return ResponseEntity.ok(logService.getLogs(projectId, type, username, action, isASC, pageable,
(Map<String, String>) request.getAttribute("user")));
}
}
......@@ -3,10 +3,13 @@ package com.aolda.itda.controller.routing;
import com.aolda.itda.dto.forwarding.ForwardingDTO;
import com.aolda.itda.dto.routing.RoutingDTO;
import com.aolda.itda.service.routing.RoutingService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
......@@ -14,7 +17,7 @@ public class RoutingController {
private final RoutingService routingService;
@PostMapping("/forwarding")
@PostMapping("/routing")
public ResponseEntity<Object> create(@RequestParam String projectId,
@RequestBody RoutingDTO dto) {
routingService.createRouting(projectId, dto);
......@@ -22,8 +25,9 @@ public class RoutingController {
}
@GetMapping("/routing")
public ResponseEntity<Object> view(@RequestParam Long routingId) {
return ResponseEntity.ok(routingService.getRouting(routingId));
public ResponseEntity<Object> view(@RequestParam Long routingId,
HttpServletRequest request) {
return ResponseEntity.ok(routingService.getRouting(routingId, (List<String>) request.getAttribute("projects")));
}
@GetMapping("/routings")
......@@ -33,14 +37,16 @@ public class RoutingController {
@PatchMapping("/routing")
public ResponseEntity<Object> edit(@RequestParam Long routingId,
@RequestBody RoutingDTO dto) {
routingService.editRouting(routingId, dto);
@RequestBody RoutingDTO dto,
HttpServletRequest request) {
routingService.editRouting(routingId, dto, (List<String>) request.getAttribute("projects"));
return ResponseEntity.ok().build();
}
@DeleteMapping("/routing")
public ResponseEntity<Object> delete(@RequestParam Long routingId) {
routingService.deleteRouting(routingId);
public ResponseEntity<Object> delete(@RequestParam Long routingId,
HttpServletRequest request) {
routingService.deleteRouting(routingId, (List<String>) request.getAttribute("projects"));
return ResponseEntity.ok().build();
}
......
......@@ -15,7 +15,7 @@ import java.util.List;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class PageResp<T> {
private Integer totalPages;
private Integer totalElements;
private Long totalElements;
private Integer size;
private List<T> contents;
private Boolean first;
......
package com.aolda.itda.dto.auth;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.querydsl.core.annotations.QueryProjection;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
......@@ -7,10 +9,16 @@ import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ProjectIdAndNameDTO {
@JsonInclude(JsonInclude.Include.NON_NULL)
public class IdAndNameDTO {
private String id;
private String name;
@QueryProjection
public IdAndNameDTO(String id, String name) {
this.id = id;
this.name = name;
}
}
......@@ -13,5 +13,5 @@ import java.util.List;
@Builder
public class LoginResponseDTO {
private Boolean isAdmin;
private List<ProjectIdAndNameDTO> projects;
private List<IdAndNameDTO> projects;
}
package com.aolda.itda.dto.log;
import com.aolda.itda.dto.auth.IdAndNameDTO;
import com.aolda.itda.entity.log.Action;
import com.aolda.itda.entity.log.ObjectType;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.querydsl.core.annotations.QueryProjection;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
public class LogDTO {
private Long id;
private IdAndNameDTO user;
private Action action;
private ObjectType type;
private Long objectId;
private String description;
private LocalDateTime createdAt;
@QueryProjection
public LogDTO(Long id, IdAndNameDTO user, Action action, ObjectType type, Long objectId, String description, LocalDateTime createdAt) {
this.id = id;
this.user = user;
this.action = action;
this.type = type;
this.objectId = objectId;
this.description = description;
this.createdAt = createdAt;
}
}
......@@ -25,7 +25,7 @@ public class RoutingDTO {
@NotBlank
private String port;
private Long id;
@NotBlank
@NotNull
private Long certificateId;
private LocalDateTime createdAt;
......
package com.aolda.itda.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.persistence.Column;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
......@@ -17,10 +18,12 @@ public abstract class BaseTimeEntity {
@CreatedDate
@Column(updatable = false)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
private LocalDateTime createdAt;
@LastModifiedDate
@Column(name = "updated_at")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Seoul")
private LocalDateTime updatedAt;
}
......@@ -23,7 +23,7 @@ public class Certificate extends BaseTimeEntity {
@Column(nullable = false)
private Long certificateId;
@OneToOne
@ManyToOne
@JoinColumn(nullable = false, name = "user_id")
private User user;
......
......@@ -4,10 +4,7 @@ import com.aolda.itda.dto.forwarding.ForwardingDTO;
import com.aolda.itda.entity.BaseTimeEntity;
import com.aolda.itda.entity.user.User;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.*;
@Entity
@Table(name = "forwarding")
......@@ -15,6 +12,7 @@ import lombok.NoArgsConstructor;
@Builder
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Forwarding extends BaseTimeEntity {
@Id
......@@ -22,10 +20,6 @@ public class Forwarding extends BaseTimeEntity {
@Column(nullable = false)
private Long forwardingId;
@OneToOne
@JoinColumn(name = "user_id")
private User user;
private String projectId;
private String serverIp;
......@@ -40,6 +34,17 @@ public class Forwarding extends BaseTimeEntity {
private String name;
public Forwarding(Forwarding forwarding) {
this.forwardingId = forwarding.getForwardingId();
this.projectId = forwarding.getProjectId();
this.serverIp = forwarding.getServerIp();
this.serverPort = forwarding.getServerPort();
this.instanceIp = forwarding.getInstanceIp();
this.instancePort = forwarding.getInstancePort();
this.isDeleted = forwarding.getIsDeleted();
this.name = forwarding.getName();
}
public ForwardingDTO toForwardingDTO() {
return ForwardingDTO.builder()
.id(forwardingId)
......
package com.aolda.itda.entity.log;
import com.aolda.itda.dto.auth.IdAndNameDTO;
import com.aolda.itda.dto.log.LogDTO;
import com.aolda.itda.entity.BaseTimeEntity;
import com.aolda.itda.entity.user.User;
import jakarta.persistence.*;
......@@ -21,7 +23,7 @@ public class Log extends BaseTimeEntity {
@Column(nullable = false)
private Long logId;
@OneToOne
@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private User user;
......@@ -37,4 +39,16 @@ public class Log extends BaseTimeEntity {
private String description;
public LogDTO toLogDTO() {
return LogDTO.builder()
.id(logId)
.user(IdAndNameDTO.builder().id(user.getKeystoneId()).name(user.getKeystoneUsername()).build())
.action(action)
.type(objectType)
.objectId(objectId)
.description(description)
.createdAt(getCreatedAt())
.build();
}
}
......@@ -24,12 +24,8 @@ public class Routing extends BaseTimeEntity {
@Column(nullable = false)
private Long routingId;
@OneToOne
@JoinColumn(name = "user_id", nullable = false)
private User user;
@OneToOne
@JoinColumn(name = "certificate_id", nullable = false)
@ManyToOne
@JoinColumn(name = "certificate_id")
private Certificate certificate;
private String projectId;
......
......@@ -10,6 +10,8 @@ public enum ErrorCode {
// User
INVALID_USER_INFO(HttpStatus.BAD_REQUEST, "잘못된 회원 정보입니다"),
NOT_FOUND_USER(HttpStatus.BAD_REQUEST, "존재하지 않는 사용자입니다"),
UNAUTHORIZED_USER(HttpStatus.BAD_REQUEST, "권한이 없는 사용자입니다"),
// Token
INVALID_TOKEN(HttpStatus.BAD_REQUEST, "잘못된 토큰입니다"),
......@@ -19,6 +21,9 @@ public enum ErrorCode {
// Routing
NOT_FOUND_ROUTING(HttpStatus.BAD_REQUEST, "라우팅 파일이 존재하지 않습니다"),
// Routing
NOT_FOUND_LOG(HttpStatus.BAD_REQUEST, "로그가 존재하지 않습니다"),
// Certificate
NOT_FOUND_CERTIFICATE(HttpStatus.BAD_REQUEST, "SSL 인증서가 존재하지 않습니다"),
......
package com.aolda.itda.repository.log;
import com.aolda.itda.dto.PageResp;
import com.aolda.itda.dto.auth.QIdAndNameDTO;
import com.aolda.itda.dto.log.LogDTO;
import com.aolda.itda.dto.log.QLogDTO;
import com.aolda.itda.entity.log.Action;
import com.aolda.itda.entity.log.ObjectType;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.stereotype.Repository;
import java.util.List;
import static com.aolda.itda.entity.log.QLog.*;
import static com.aolda.itda.entity.user.QUser.*;
@Repository
@RequiredArgsConstructor
public class LogQueryDSL {
private final JPAQueryFactory jpaQueryFactory;
/* log 목록 반환 */
public PageResp<LogDTO> getLogs(String projectId, String type,
String username, String action, Boolean isASC, Pageable pageable) {
List<LogDTO> content = jpaQueryFactory
.select(new QLogDTO(
log.logId,
new QIdAndNameDTO(user.keystoneId, user.keystoneUsername),
log.action,
log.objectType,
log.objectId,
log.description,
log.createdAt
)).from(log)
.join(log.user, user).on(log.user.eq(user))
.where(getFilter(projectId, type, username, action))
.orderBy(isASC ? log.logId.asc() : log.logId.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
JPAQuery<Long> cnt = jpaQueryFactory
.select(log.count())
.from(log)
.where(getFilter(projectId, type, username, action));
Page<LogDTO> page = PageableExecutionUtils.getPage(content, pageable, cnt::fetchOne);
return PageResp.<LogDTO>builder()
.contents(page.getContent())
.first(page.isFirst())
.last(page.isLast())
.size(page.getSize())
.totalPages(page.getTotalPages())
.totalElements(page.getTotalElements())
.build();
}
/* Where 필터 */
private BooleanBuilder getFilter(String projectId, String type,
String username, String action) {
BooleanBuilder builder = new BooleanBuilder();
/* 프로젝트 조건 */
if (projectId != null) {
builder.and(log.projectId.eq(projectId));
}
/* 오브젝트 타입 조건 */
if (type != null) {
switch (type) {
case "certificate" -> builder.and(log.objectType.eq(ObjectType.CERTIFICATE));
case "forwarding" -> builder.and(log.objectType.eq(ObjectType.FORWARDING));
case "routing" -> builder.and(log.objectType.eq(ObjectType.ROUTING));
}
}
/* 사용자 ID 조건 */
if (username != null) {
builder.and(log.user.keystoneUsername.eq(username));
}
/* CUD 조건 */
if (action != null) {
switch (action) {
case "create" -> builder.and(log.action.eq(Action.CREATE));
case "update" -> builder.and(log.action.eq(Action.UPDATE));
case "delete" -> builder.and(log.action.eq(Action.DELETE));
}
}
return builder;
}
}