Merge branch 'feat/dev_251201' of https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice into feat/dev_251201
This commit is contained in:
@@ -32,7 +32,7 @@ public class CustomAuthenticationProvider implements AuthenticationProvider {
|
|||||||
|
|
||||||
// 미사용 상태
|
// 미사용 상태
|
||||||
if (member.getStatus().equals(StatusType.INACTIVE.getId())) {
|
if (member.getStatus().equals(StatusType.INACTIVE.getId())) {
|
||||||
throw new CustomApiException(AuthErrorCode.LOGIN_ID_NOT_FOUND);
|
throw new CustomApiException(AuthErrorCode.INACTIVE_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// jBCrypt + 커스텀 salt 로 저장된 패스워드 비교
|
// jBCrypt + 커스텀 salt 로 저장된 패스워드 비교
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
|||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.AntPathMatcher;
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@@ -19,6 +20,10 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
|
|
||||||
private final JwtTokenProvider jwtTokenProvider;
|
private final JwtTokenProvider jwtTokenProvider;
|
||||||
private final UserDetailsService userDetailsService;
|
private final UserDetailsService userDetailsService;
|
||||||
|
private static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
|
||||||
|
private static final String[] EXCLUDE_PATHS = {
|
||||||
|
"/api/auth/signin", "/api/auth/refresh", "/api/auth/logout", "/api/members/*/password"
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doFilterInternal(
|
protected void doFilterInternal(
|
||||||
@@ -44,9 +49,15 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
String path = request.getServletPath();
|
String path = request.getServletPath();
|
||||||
|
|
||||||
// JWT 필터를 타지 않게 할 URL 패턴들
|
// JWT 필터를 타지 않게 할 URL 패턴들
|
||||||
return path.startsWith("/api/auth/signin") || path.startsWith("/api/auth/refresh");
|
for (String pattern : EXCLUDE_PATHS) {
|
||||||
|
if (PATH_MATCHER.match(pattern, path)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /api/members/{memberId}/password
|
||||||
private String resolveToken(HttpServletRequest request) {
|
private String resolveToken(HttpServletRequest request) {
|
||||||
String bearer = request.getHeader("Authorization");
|
String bearer = request.getHeader("Authorization");
|
||||||
if (bearer != null && bearer.startsWith("Bearer ")) {
|
if (bearer != null && bearer.startsWith("Bearer ")) {
|
||||||
|
|||||||
@@ -224,7 +224,8 @@ public class CommonCodeApiController {
|
|||||||
commonCodeUtil.getChildCodesByParentCode("0000").stream()
|
commonCodeUtil.getChildCodesByParentCode("0000").stream()
|
||||||
.map(
|
.map(
|
||||||
child ->
|
child ->
|
||||||
new CommonCodeDto.Clazzes(child.getCode(), child.getName(), child.getOrder()))
|
new CommonCodeDto.Clazzes(
|
||||||
|
child.getCode(), child.getName(), child.getOrder(), child.getProps2()))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
return ApiResponseDto.ok(list);
|
return ApiResponseDto.ok(list);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.kamco.cd.kamcoback.code.dto;
|
package com.kamco.cd.kamcoback.code.dto;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
import com.kamco.cd.kamcoback.common.utils.html.HtmlEscapeDeserializer;
|
import com.kamco.cd.kamcoback.common.utils.html.HtmlEscapeDeserializer;
|
||||||
@@ -155,7 +154,7 @@ public class CommonCodeDto {
|
|||||||
String[] sortParams = sort.split(",");
|
String[] sortParams = sort.split(",");
|
||||||
String property = sortParams[0];
|
String property = sortParams[0];
|
||||||
Sort.Direction direction =
|
Sort.Direction direction =
|
||||||
sortParams.length > 1 ? Sort.Direction.fromString(sortParams[1]) : Sort.Direction.ASC;
|
sortParams.length > 1 ? Sort.Direction.fromString(sortParams[1]) : Sort.Direction.ASC;
|
||||||
return PageRequest.of(page, size, Sort.by(direction, property));
|
return PageRequest.of(page, size, Sort.by(direction, property));
|
||||||
}
|
}
|
||||||
return PageRequest.of(page, size);
|
return PageRequest.of(page, size);
|
||||||
@@ -167,16 +166,14 @@ public class CommonCodeDto {
|
|||||||
|
|
||||||
private String code;
|
private String code;
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
|
||||||
private Double score;
|
|
||||||
|
|
||||||
private Integer order;
|
private Integer order;
|
||||||
|
private String color;
|
||||||
|
|
||||||
public Clazzes(String code, String name, Integer order) {
|
public Clazzes(String code, String name, Integer order, String color) {
|
||||||
this.code = code;
|
this.code = code;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.order = order;
|
this.order = order;
|
||||||
|
this.color = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ public enum AuthErrorCode implements ErrorCode {
|
|||||||
|
|
||||||
LOGIN_PASSWORD_MISMATCH("LOGIN_PASSWORD_MISMATCH", HttpStatus.UNAUTHORIZED),
|
LOGIN_PASSWORD_MISMATCH("LOGIN_PASSWORD_MISMATCH", HttpStatus.UNAUTHORIZED),
|
||||||
|
|
||||||
LOGIN_PASSWORD_EXCEEDED("LOGIN_PASSWORD_EXCEEDED", HttpStatus.UNAUTHORIZED);
|
LOGIN_PASSWORD_EXCEEDED("LOGIN_PASSWORD_EXCEEDED", HttpStatus.UNAUTHORIZED),
|
||||||
|
|
||||||
|
INACTIVE_ID("INACTIVE_ID", HttpStatus.UNAUTHORIZED);
|
||||||
|
|
||||||
private final String code;
|
private final String code;
|
||||||
private final HttpStatus status;
|
private final HttpStatus status;
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
package com.kamco.cd.kamcoback.common.utils;
|
package com.kamco.cd.kamcoback.common.utils;
|
||||||
|
|
||||||
|
import com.kamco.cd.kamcoback.auth.BCryptSaltGenerator;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import org.mindrot.jbcrypt.BCrypt;
|
||||||
|
|
||||||
public class CommonStringUtils {
|
public class CommonStringUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 영문, 숫자, 특수문자를 모두 포함하여 8~20자 이내의 비밀번호
|
* 영문, 숫자, 특수문자를 모두 포함하여 8~20자 이내의 비밀번호
|
||||||
*
|
*
|
||||||
* @param password
|
* @param password 벨리데이션 필요한 패스워드
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static boolean isValidPassword(String password) {
|
public static boolean isValidPassword(String password) {
|
||||||
@@ -15,4 +17,16 @@ public class CommonStringUtils {
|
|||||||
"^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-\\[\\]{};':\"\\\\|,.<>/?]).{8,20}$";
|
"^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-\\[\\]{};':\"\\\\|,.<>/?]).{8,20}$";
|
||||||
return Pattern.matches(passwordPattern, password);
|
return Pattern.matches(passwordPattern, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 패스워드 암호화
|
||||||
|
*
|
||||||
|
* @param password 암호화 필요한 패스워드
|
||||||
|
* @param employeeNo salt 생성에 필요한 사원번호
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String hashPassword(String password, String employeeNo) {
|
||||||
|
String salt = BCryptSaltGenerator.generateSaltWithEmployeeNo(employeeNo.trim());
|
||||||
|
return BCrypt.hashpw(password.trim(), salt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,8 +161,6 @@ public class GlobalExceptionHandler {
|
|||||||
errorLog.getId());
|
errorLog.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
|
@ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
|
||||||
@ExceptionHandler(DataIntegrityViolationException.class)
|
@ExceptionHandler(DataIntegrityViolationException.class)
|
||||||
public ApiResponseDto<String> handlerDataIntegrityViolationException(
|
public ApiResponseDto<String> handlerDataIntegrityViolationException(
|
||||||
@@ -278,8 +276,8 @@ public class GlobalExceptionHandler {
|
|||||||
String codeName = "";
|
String codeName = "";
|
||||||
|
|
||||||
switch (e.getField()) {
|
switch (e.getField()) {
|
||||||
case USER_ID -> {
|
case EMPLOYEE_NO -> {
|
||||||
codeName = "DUPLICATE_DATA";
|
codeName = "DUPLICATE_EMPLOYEEID";
|
||||||
}
|
}
|
||||||
default -> {
|
default -> {
|
||||||
codeName = "DUPLICATE_DATA";
|
codeName = "DUPLICATE_DATA";
|
||||||
|
|||||||
@@ -6,16 +6,30 @@ import io.swagger.v3.oas.models.info.Info;
|
|||||||
import io.swagger.v3.oas.models.security.SecurityRequirement;
|
import io.swagger.v3.oas.models.security.SecurityRequirement;
|
||||||
import io.swagger.v3.oas.models.security.SecurityScheme;
|
import io.swagger.v3.oas.models.security.SecurityScheme;
|
||||||
import io.swagger.v3.oas.models.servers.Server;
|
import io.swagger.v3.oas.models.servers.Server;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public class OpenApiConfig {
|
public class OpenApiConfig {
|
||||||
|
|
||||||
|
@Value("${server.port}")
|
||||||
|
private String serverPort;
|
||||||
|
|
||||||
|
@Value("${spring.profiles.active:local}")
|
||||||
|
private String profile;
|
||||||
|
|
||||||
|
@Value("${swagger.dev-url:https://kamco.dev-api.gs.dabeeo.com}")
|
||||||
|
private String devUrl;
|
||||||
|
|
||||||
|
@Value("${swagger.prod-url:https://api.kamco.com}")
|
||||||
|
private String prodUrl;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public OpenAPI kamcoOpenAPI() {
|
public OpenAPI kamcoOpenAPI() {
|
||||||
// 🔹 1) SecurityScheme 정의 (Bearer JWT)
|
// 1) SecurityScheme 정의 (Bearer JWT)
|
||||||
SecurityScheme bearerAuth =
|
SecurityScheme bearerAuth =
|
||||||
new SecurityScheme()
|
new SecurityScheme()
|
||||||
.type(SecurityScheme.Type.HTTP)
|
.type(SecurityScheme.Type.HTTP)
|
||||||
@@ -24,12 +38,21 @@ public class OpenApiConfig {
|
|||||||
.in(SecurityScheme.In.HEADER)
|
.in(SecurityScheme.In.HEADER)
|
||||||
.name("Authorization");
|
.name("Authorization");
|
||||||
|
|
||||||
// 🔹 2) SecurityRequirement (기본으로 BearerAuth 사용)
|
// 2) SecurityRequirement (기본으로 BearerAuth 사용)
|
||||||
SecurityRequirement securityRequirement = new SecurityRequirement().addList("BearerAuth");
|
SecurityRequirement securityRequirement = new SecurityRequirement().addList("BearerAuth");
|
||||||
|
|
||||||
// 🔹 3) Components 에 SecurityScheme 등록
|
// 3) Components 에 SecurityScheme 등록
|
||||||
Components components = new Components().addSecuritySchemes("BearerAuth", bearerAuth);
|
Components components = new Components().addSecuritySchemes("BearerAuth", bearerAuth);
|
||||||
|
|
||||||
|
// profile 별 server url 분기
|
||||||
|
List<Server> servers = new ArrayList<>();
|
||||||
|
switch (profile) {
|
||||||
|
case "prod" -> servers.add(new Server().url(prodUrl).description("운영 서버"));
|
||||||
|
case "dev" -> servers.add(new Server().url(devUrl).description("개발 서버"));
|
||||||
|
default ->
|
||||||
|
servers.add(new Server().url("http://localhost:" + serverPort).description("로컬 개발 서버"));
|
||||||
|
}
|
||||||
|
|
||||||
return new OpenAPI()
|
return new OpenAPI()
|
||||||
.info(
|
.info(
|
||||||
new Info()
|
new Info()
|
||||||
@@ -38,19 +61,10 @@ public class OpenApiConfig {
|
|||||||
"KAMCO 변화 탐지 시스템 API 문서\n\n"
|
"KAMCO 변화 탐지 시스템 API 문서\n\n"
|
||||||
+ "이 API는 지리공간 데이터를 활용한 변화 탐지 시스템을 제공합니다.\n"
|
+ "이 API는 지리공간 데이터를 활용한 변화 탐지 시스템을 제공합니다.\n"
|
||||||
+ "GeoJSON 형식의 공간 데이터를 처리하며, PostgreSQL/PostGIS 기반으로 동작합니다.")
|
+ "GeoJSON 형식의 공간 데이터를 처리하며, PostgreSQL/PostGIS 기반으로 동작합니다.")
|
||||||
.version("v1.0.0")
|
.version("v1.0.0"))
|
||||||
// .contact(new Contact().name("KAMCO Development
|
.servers(servers)
|
||||||
// Team").email("dev@kamco.com").url("https://kamco.com"))
|
// 만들어둔 components를 넣어야 함
|
||||||
// .license(new License().name("Proprietary").url("https://kamco.com/license"))
|
.components(components)
|
||||||
)
|
|
||||||
.servers(
|
|
||||||
List.of(
|
|
||||||
new Server().url("http://localhost:8080").description("로컬 개발 서버"),
|
|
||||||
new Server().url("https://kamco.dev-api.gs.dabeeo.com").description("개발 서버")
|
|
||||||
// , new Server().url("https://api.kamco.com").description("운영 서버")
|
|
||||||
))
|
|
||||||
.components(new Components())
|
|
||||||
// 🔥 여기 한 줄이 "모든 API 기본적으로 BearerAuth 요구" 의미
|
|
||||||
.addSecurityItem(securityRequirement);
|
.addSecurityItem(securityRequirement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ public class SecurityConfig {
|
|||||||
.requestMatchers(
|
.requestMatchers(
|
||||||
"/api/auth/signin",
|
"/api/auth/signin",
|
||||||
"/api/auth/refresh",
|
"/api/auth/refresh",
|
||||||
|
"/api/auth/logout",
|
||||||
"/swagger-ui/**",
|
"/swagger-ui/**",
|
||||||
"/api/members/*/password",
|
"/api/members/*/password",
|
||||||
"/v3/api-docs/**")
|
"/v3/api-docs/**")
|
||||||
@@ -99,7 +100,7 @@ public class SecurityConfig {
|
|||||||
public CorsConfigurationSource corsConfigurationSource() {
|
public CorsConfigurationSource corsConfigurationSource() {
|
||||||
CorsConfiguration config = new CorsConfiguration(); // CORS 객체 생성
|
CorsConfiguration config = new CorsConfiguration(); // CORS 객체 생성
|
||||||
config.setAllowedOriginPatterns(List.of("*")); // 도메인 허용
|
config.setAllowedOriginPatterns(List.of("*")); // 도메인 허용
|
||||||
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
|
config.setAllowedMethods(List.of("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
|
||||||
config.setAllowedHeaders(List.of("*")); // 헤더요청 Authorization, Content-Type, X-Custom-Header
|
config.setAllowedHeaders(List.of("*")); // 헤더요청 Authorization, Content-Type, X-Custom-Header
|
||||||
config.setAllowCredentials(true); // 쿠키, Authorization 헤더, Bearer Token 등 자격증명 포함 요청을 허용할지 설정
|
config.setAllowCredentials(true); // 쿠키, Authorization 헤더, Bearer Token 등 자격증명 포함 요청을 허용할지 설정
|
||||||
|
|
||||||
|
|||||||
@@ -167,6 +167,7 @@ public class ApiResponseDto<T> {
|
|||||||
LOGIN_ID_NOT_FOUND("아이디를 잘못 입력하셨습니다."),
|
LOGIN_ID_NOT_FOUND("아이디를 잘못 입력하셨습니다."),
|
||||||
LOGIN_PASSWORD_MISMATCH("비밀번호를 잘못 입력하셨습니다."),
|
LOGIN_PASSWORD_MISMATCH("비밀번호를 잘못 입력하셨습니다."),
|
||||||
LOGIN_PASSWORD_EXCEEDED("비밀번호 오류 횟수를 초과하여 이용하실 수 없습니다.\n로그인 오류에 대해 관리자에게 문의하시기 바랍니다."),
|
LOGIN_PASSWORD_EXCEEDED("비밀번호 오류 횟수를 초과하여 이용하실 수 없습니다.\n로그인 오류에 대해 관리자에게 문의하시기 바랍니다."),
|
||||||
|
INACTIVE_ID("사용할 수 없는 계정입니다."),
|
||||||
INVALID_EMAIL_TOKEN(
|
INVALID_EMAIL_TOKEN(
|
||||||
"You can only reset your password within 24 hours from when the email was sent.\n"
|
"You can only reset your password within 24 hours from when the email was sent.\n"
|
||||||
+ "To reset your password again, please submit a new request through \"Forgot"
|
+ "To reset your password again, please submit a new request through \"Forgot"
|
||||||
|
|||||||
@@ -76,8 +76,24 @@ public class MapSheetMngFileCheckerApiController {
|
|||||||
public ApiResponseDto<String> uploadFile(
|
public ApiResponseDto<String> uploadFile(
|
||||||
@RequestPart("file") MultipartFile file,
|
@RequestPart("file") MultipartFile file,
|
||||||
@RequestParam("targetPath") String targetPath,
|
@RequestParam("targetPath") String targetPath,
|
||||||
@RequestParam(value = "overwrite", required = false, defaultValue = "false") boolean overwrite) {
|
@RequestParam(value = "overwrite", required = false, defaultValue = "false")
|
||||||
return ApiResponseDto.createOK(mapSheetMngFileCheckerService.uploadFile(file, targetPath, overwrite));
|
boolean overwrite,
|
||||||
|
@RequestParam(value = "hstUid", required = false) Long hstUid) {
|
||||||
|
return ApiResponseDto.createOK(
|
||||||
|
mapSheetMngFileCheckerService.uploadFile(file, targetPath, overwrite, hstUid));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "페어 파일 업로드", description = "TFW/TIF 두 파일을 쌍으로 업로드 및 검증")
|
||||||
|
@PostMapping(value = "/upload-pair", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
|
public ApiResponseDto<String> uploadPair(
|
||||||
|
@RequestPart("tfw") MultipartFile tfwFile,
|
||||||
|
@RequestPart("tif") MultipartFile tifFile,
|
||||||
|
@RequestParam("targetPath") String targetPath,
|
||||||
|
@RequestParam(value = "overwrite", required = false, defaultValue = "false")
|
||||||
|
boolean overwrite,
|
||||||
|
@RequestParam(value = "hstUid", required = false) Long hstUid) {
|
||||||
|
return ApiResponseDto.createOK(
|
||||||
|
mapSheetMngFileCheckerService.uploadPair(tfwFile, tifFile, targetPath, overwrite, hstUid));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "파일 삭제", description = "중복 파일 등 파일 삭제")
|
@Operation(summary = "파일 삭제", description = "중복 파일 등 파일 삭제")
|
||||||
@@ -86,6 +102,14 @@ public class MapSheetMngFileCheckerApiController {
|
|||||||
return ApiResponseDto.createOK(mapSheetMngFileCheckerService.deleteFile(dto.getDirPath()));
|
return ApiResponseDto.createOK(mapSheetMngFileCheckerService.deleteFile(dto.getDirPath()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "중복 파일 삭제", description = "중복 데이터 발견 시 기존 데이터를 삭제")
|
||||||
|
@PostMapping(value = "/delete-file")
|
||||||
|
public ApiResponseDto<String> deleteDuplicateFile(
|
||||||
|
@RequestParam("filePath") String filePath, @RequestParam("fileName") String fileName) {
|
||||||
|
return ApiResponseDto.createOK(
|
||||||
|
mapSheetMngFileCheckerService.deleteDuplicate(filePath, fileName));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@Operation(summary = "지정폴더(하위폴더포함) 파일목록 조회", description = "지정폴더(하위폴더포함) 파일목록 조회")
|
@Operation(summary = "지정폴더(하위폴더포함) 파일목록 조회", description = "지정폴더(하위폴더포함) 파일목록 조회")
|
||||||
@ApiResponses(
|
@ApiResponses(
|
||||||
|
|||||||
@@ -316,7 +316,7 @@ public class MapSheetMngFileCheckerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public String uploadFile(MultipartFile file, String targetPath, boolean overwrite) {
|
public String uploadFile(MultipartFile file, String targetPath, boolean overwrite, Long hstUid) {
|
||||||
try {
|
try {
|
||||||
Path path = Paths.get(targetPath);
|
Path path = Paths.get(targetPath);
|
||||||
if (Files.isDirectory(path)) {
|
if (Files.isDirectory(path)) {
|
||||||
@@ -368,11 +368,11 @@ public class MapSheetMngFileCheckerService {
|
|||||||
// 안내: 같은 베이스의 TIF가 없으면 추후 TIF 업로드 필요
|
// 안내: 같은 베이스의 TIF가 없으면 추후 TIF 업로드 필요
|
||||||
if (!Files.exists(tifPath)) {
|
if (!Files.exists(tifPath)) {
|
||||||
// DB 메타 저장은 진행 (향후 쌍 검증 위해)
|
// DB 메타 저장은 진행 (향후 쌍 검증 위해)
|
||||||
saveUploadMeta(path);
|
saveUploadMeta(path, hstUid);
|
||||||
return "TFW 업로드 성공 (매칭되는 TIF가 아직 없습니다).";
|
return "TFW 업로드 성공 (매칭되는 TIF가 아직 없습니다).";
|
||||||
}
|
}
|
||||||
// TIF가 존재하면 쌍 요건 충족
|
// TIF가 존재하면 쌍 요건 충족
|
||||||
saveUploadMeta(path);
|
saveUploadMeta(path, hstUid);
|
||||||
return "TFW 업로드 성공";
|
return "TFW 업로드 성공";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,12 +395,12 @@ public class MapSheetMngFileCheckerService {
|
|||||||
throw new ValidationException(
|
throw new ValidationException(
|
||||||
"유효하지 않은 TFW 파일입니다 (6줄 숫자 형식 검증 실패): " + tfwPath.getFileName());
|
"유효하지 않은 TFW 파일입니다 (6줄 숫자 형식 검증 실패): " + tfwPath.getFileName());
|
||||||
}
|
}
|
||||||
saveUploadMeta(path);
|
saveUploadMeta(path, hstUid);
|
||||||
return "TIF 업로드 성공";
|
return "TIF 업로드 성공";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 기타 확장자: 저장만 하고 메타 기록
|
// 기타 확장자: 저장만 하고 메타 기록
|
||||||
saveUploadMeta(path);
|
saveUploadMeta(path, hstUid);
|
||||||
|
|
||||||
return "업로드 성공";
|
return "업로드 성공";
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -408,35 +408,123 @@ public class MapSheetMngFileCheckerService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveUploadMeta(Path savedPath) {
|
@Transactional
|
||||||
|
public String uploadPair(
|
||||||
|
MultipartFile tfwFile,
|
||||||
|
MultipartFile tifFile,
|
||||||
|
String targetPath,
|
||||||
|
boolean overwrite,
|
||||||
|
Long hstUid) {
|
||||||
|
try {
|
||||||
|
Path basePath = Paths.get(targetPath);
|
||||||
|
if (Files.isDirectory(basePath)) {
|
||||||
|
// 디렉토리인 경우 파일명 기준으로 경로 생성
|
||||||
|
Path tfwPath = basePath.resolve(tfwFile.getOriginalFilename());
|
||||||
|
Path tifPath = basePath.resolve(tifFile.getOriginalFilename());
|
||||||
|
// 동일 베이스명 확인
|
||||||
|
String tfwBase = FilenameUtils.getBaseName(tfwPath.getFileName().toString());
|
||||||
|
String tifBase = FilenameUtils.getBaseName(tifPath.getFileName().toString());
|
||||||
|
if (!tfwBase.equalsIgnoreCase(tifBase)) {
|
||||||
|
throw new ValidationException("TFW/TIF 파일명이 동일한 베이스가 아닙니다.");
|
||||||
|
}
|
||||||
|
// 디렉토리 생성
|
||||||
|
if (tfwPath.getParent() != null) Files.createDirectories(tfwPath.getParent());
|
||||||
|
if (tifPath.getParent() != null) Files.createDirectories(tifPath.getParent());
|
||||||
|
|
||||||
|
// DB 중복 체크 및 overwrite 처리 (각 파일별)
|
||||||
|
String parentPathStr = basePath.toString();
|
||||||
|
String tfwName = tfwPath.getFileName().toString();
|
||||||
|
String tifName = tifPath.getFileName().toString();
|
||||||
|
boolean tfwDbExists =
|
||||||
|
mapSheetMngFileRepository.existsByFileNameAndFilePath(tfwName, parentPathStr);
|
||||||
|
boolean tifDbExists =
|
||||||
|
mapSheetMngFileRepository.existsByFileNameAndFilePath(tifName, parentPathStr);
|
||||||
|
if (!overwrite && (tfwDbExists || tifDbExists)) {
|
||||||
|
throw new DuplicateFileException("동일한 파일이 이미 존재합니다 (DB): " + tfwName + ", " + tifName);
|
||||||
|
}
|
||||||
|
if (overwrite) {
|
||||||
|
if (tfwDbExists)
|
||||||
|
mapSheetMngFileRepository.deleteByFileNameAndFilePath(tfwName, parentPathStr);
|
||||||
|
if (tifDbExists)
|
||||||
|
mapSheetMngFileRepository.deleteByFileNameAndFilePath(tifName, parentPathStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 파일 저장
|
||||||
|
tfwFile.transferTo(tfwPath.toFile());
|
||||||
|
tifFile.transferTo(tifPath.toFile());
|
||||||
|
|
||||||
|
// 검증
|
||||||
|
boolean tfwOk = FIleChecker.checkTfw(tfwPath.toString());
|
||||||
|
if (!tfwOk) {
|
||||||
|
Files.deleteIfExists(tfwPath);
|
||||||
|
Files.deleteIfExists(tifPath);
|
||||||
|
throw new ValidationException("유효하지 않은 TFW 파일입니다 (6줄 숫자 형식 검증 실패): " + tfwName);
|
||||||
|
}
|
||||||
|
boolean isValidTif = FIleChecker.cmmndGdalInfo(tifPath.toString());
|
||||||
|
if (!isValidTif) {
|
||||||
|
Files.deleteIfExists(tfwPath);
|
||||||
|
Files.deleteIfExists(tifPath);
|
||||||
|
throw new ValidationException("유효하지 않은 TIF 파일입니다 (GDAL 검증 실패): " + tifName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 메타 저장 (두 파일 각각 저장)
|
||||||
|
saveUploadMeta(tfwPath, hstUid);
|
||||||
|
saveUploadMeta(tifPath, hstUid);
|
||||||
|
return "TFW/TIF 페어 업로드 성공";
|
||||||
|
} else {
|
||||||
|
throw new ValidationException("targetPath는 디렉토리여야 합니다.");
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new IllegalArgumentException("파일 I/O 처리 실패: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveUploadMeta(Path savedPath, Long hstUid) {
|
||||||
String fullPath = savedPath.toAbsolutePath().toString();
|
String fullPath = savedPath.toAbsolutePath().toString();
|
||||||
String fileName = savedPath.getFileName().toString();
|
String fileName = savedPath.getFileName().toString();
|
||||||
String ext = FilenameUtils.getExtension(fileName);
|
String ext = FilenameUtils.getExtension(fileName);
|
||||||
|
|
||||||
// 연도(mng_yyyy) 추출: 경로 내의 연도 폴더명을 찾음 (예: .../original-images/2022/2022_25cm/...)
|
MapSheetMngFileEntity entity = new MapSheetMngFileEntity();
|
||||||
Integer mngYyyy = extractYearFromPath(fullPath);
|
|
||||||
|
|
||||||
// 도엽번호(map_sheet_num) 추정: 파일명 내 숫자 연속 부분을 추출해 정수화
|
if (hstUid != null) {
|
||||||
String mapSheetNum = extractMapSheetNumFromFileName(fileName);
|
// 히스토리에서 메타 가져오기
|
||||||
|
var hstOpt = mapSheetMngFileCheckerCoreService.findHstByUid(hstUid);
|
||||||
// ref_map_sheet_num: 1000으로 나눈 값(파일명 규칙에 따라 추정)
|
hstOpt.ifPresent(
|
||||||
String refMapSheetNum = null;
|
hst -> {
|
||||||
if (mapSheetNum != null && !mapSheetNum.isEmpty()) {
|
entity.setHstUid(hst.getHstUid());
|
||||||
try {
|
entity.setMngYyyy(hst.getMngYyyy());
|
||||||
long num = Long.parseLong(mapSheetNum);
|
entity.setMapSheetNum(hst.getMapSheetNum());
|
||||||
refMapSheetNum = String.valueOf(num / 1000);
|
entity.setRefMapSheetNum(hst.getRefMapSheetNum());
|
||||||
} catch (NumberFormatException ignored) {
|
});
|
||||||
|
} else {
|
||||||
|
// 기존 추정 로직 유지
|
||||||
|
Integer mngYyyy = extractYearFromPath(fullPath);
|
||||||
|
String mapSheetNum = extractMapSheetNumFromFileName(fileName);
|
||||||
|
String refMapSheetNum = null;
|
||||||
|
if (mapSheetNum != null && !mapSheetNum.isEmpty()) {
|
||||||
|
try {
|
||||||
|
long num = Long.parseLong(mapSheetNum);
|
||||||
|
refMapSheetNum = String.valueOf(num / 1000);
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
entity.setMngYyyy(mngYyyy);
|
||||||
|
entity.setMapSheetNum(mapSheetNum);
|
||||||
|
entity.setRefMapSheetNum(refMapSheetNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
MapSheetMngFileEntity entity = new MapSheetMngFileEntity();
|
|
||||||
entity.setMngYyyy(mngYyyy);
|
|
||||||
entity.setMapSheetNum(mapSheetNum);
|
|
||||||
entity.setRefMapSheetNum(refMapSheetNum);
|
|
||||||
entity.setFilePath(savedPath.getParent() != null ? savedPath.getParent().toString() : "");
|
entity.setFilePath(savedPath.getParent() != null ? savedPath.getParent().toString() : "");
|
||||||
entity.setFileName(fileName);
|
entity.setFileName(fileName);
|
||||||
entity.setFileExt(ext);
|
entity.setFileExt(ext);
|
||||||
|
|
||||||
|
// 파일 크기 설정
|
||||||
|
try {
|
||||||
|
long size = Files.size(savedPath);
|
||||||
|
entity.setFileSize(size);
|
||||||
|
} catch (IOException e) {
|
||||||
|
entity.setFileSize(0L);
|
||||||
|
}
|
||||||
|
|
||||||
mapSheetMngFileRepository.save(entity);
|
mapSheetMngFileRepository.save(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,4 +580,17 @@ public class MapSheetMngFileCheckerService {
|
|||||||
}
|
}
|
||||||
return all;
|
return all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public String deleteDuplicate(String filePath, String fileName) {
|
||||||
|
try {
|
||||||
|
Path path = Paths.get(filePath, fileName);
|
||||||
|
boolean deleted = Files.deleteIfExists(path);
|
||||||
|
// DB에서도 삭제
|
||||||
|
mapSheetMngFileRepository.deleteByFileNameAndFilePath(fileName, filePath);
|
||||||
|
return deleted ? "파일 및 DB 레코드 삭제 완료" : "DB 레코드 삭제 완료 (파일 미존재)";
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("중복 파일 삭제 실패: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
|
|||||||
import com.kamco.cd.kamcoback.members.dto.MembersDto;
|
import com.kamco.cd.kamcoback.members.dto.MembersDto;
|
||||||
import com.kamco.cd.kamcoback.members.service.AdminService;
|
import com.kamco.cd.kamcoback.members.service.AdminService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.media.Content;
|
import io.swagger.v3.oas.annotations.media.Content;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
@@ -12,6 +13,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.PutMapping;
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
@@ -86,4 +88,25 @@ public class AdminApiController {
|
|||||||
adminService.updateMembers(uuid, updateReq);
|
adminService.updateMembers(uuid, updateReq);
|
||||||
return ApiResponseDto.createOK(UUID.randomUUID());
|
return ApiResponseDto.createOK(UUID.randomUUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "사번 중복 체크", description = "사번 중복 체크")
|
||||||
|
@ApiResponses(
|
||||||
|
value = {
|
||||||
|
@ApiResponse(
|
||||||
|
responseCode = "200",
|
||||||
|
description = "조회 성공",
|
||||||
|
content =
|
||||||
|
@Content(
|
||||||
|
mediaType = "application/json",
|
||||||
|
schema = @Schema(implementation = Boolean.class))),
|
||||||
|
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
|
||||||
|
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
|
||||||
|
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
|
||||||
|
})
|
||||||
|
@GetMapping("/{employeeNo}")
|
||||||
|
public ApiResponseDto<Boolean> checkEmployeeNo(
|
||||||
|
@Parameter(description = "중복 체크할 사번", required = true, example = "1234567") @PathVariable
|
||||||
|
String employeeNo) {
|
||||||
|
return ApiResponseDto.ok(adminService.existsByEmployeeNo(employeeNo));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import com.kamco.cd.kamcoback.auth.CustomUserDetails;
|
|||||||
import com.kamco.cd.kamcoback.auth.JwtTokenProvider;
|
import com.kamco.cd.kamcoback.auth.JwtTokenProvider;
|
||||||
import com.kamco.cd.kamcoback.auth.RefreshTokenService;
|
import com.kamco.cd.kamcoback.auth.RefreshTokenService;
|
||||||
import com.kamco.cd.kamcoback.common.enums.StatusType;
|
import com.kamco.cd.kamcoback.common.enums.StatusType;
|
||||||
import com.kamco.cd.kamcoback.common.enums.error.AuthErrorCode;
|
|
||||||
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
|
|
||||||
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
|
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
|
||||||
import com.kamco.cd.kamcoback.members.dto.MembersDto;
|
import com.kamco.cd.kamcoback.members.dto.MembersDto;
|
||||||
import com.kamco.cd.kamcoback.members.dto.SignInRequest;
|
import com.kamco.cd.kamcoback.members.dto.SignInRequest;
|
||||||
@@ -112,23 +110,9 @@ public class AuthController {
|
|||||||
Authentication authentication = null;
|
Authentication authentication = null;
|
||||||
MembersDto.Member member = new MembersDto.Member();
|
MembersDto.Member member = new MembersDto.Member();
|
||||||
|
|
||||||
// 비활성 상태면 임시패스워드를 비교함
|
authentication =
|
||||||
if (StatusType.PENDING.getId().equals(status)) {
|
authenticationManager.authenticate(
|
||||||
if (!authService.isTempPasswordValid(request)) {
|
new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword()));
|
||||||
throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_MISMATCH);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
authentication =
|
|
||||||
authenticationManager.authenticate(
|
|
||||||
new UsernamePasswordAuthenticationToken(
|
|
||||||
request.getUsername(), request.getPassword()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// PENDING 비활성 상태(새로운 패스워드 입력 해야함)
|
|
||||||
if (StatusType.PENDING.getId().equals(status)) {
|
|
||||||
member.setEmployeeNo(request.getUsername());
|
|
||||||
return ApiResponseDto.ok(new TokenResponse(status, null, null, member));
|
|
||||||
}
|
|
||||||
|
|
||||||
String username = authentication.getName(); // UserDetailsService 에서 사용한 username
|
String username = authentication.getName(); // UserDetailsService 에서 사용한 username
|
||||||
|
|
||||||
@@ -156,6 +140,12 @@ public class AuthController {
|
|||||||
member.setName(user.getMember().getName());
|
member.setName(user.getMember().getName());
|
||||||
member.setEmployeeNo(user.getMember().getEmployeeNo());
|
member.setEmployeeNo(user.getMember().getEmployeeNo());
|
||||||
|
|
||||||
|
// PENDING 비활성 상태(새로운 패스워드 입력 해야함)
|
||||||
|
if (StatusType.PENDING.getId().equals(status)) {
|
||||||
|
member.setEmployeeNo(request.getUsername());
|
||||||
|
return ApiResponseDto.ok(new TokenResponse(status, accessToken, refreshToken, member));
|
||||||
|
}
|
||||||
|
|
||||||
// 인증 성공 로그인 시간 저장
|
// 인증 성공 로그인 시간 저장
|
||||||
authService.saveLogin(UUID.fromString(username));
|
authService.saveLogin(UUID.fromString(username));
|
||||||
|
|
||||||
@@ -215,7 +205,7 @@ public class AuthController {
|
|||||||
@ApiResponse(
|
@ApiResponse(
|
||||||
responseCode = "200",
|
responseCode = "200",
|
||||||
description = "로그아웃 성공",
|
description = "로그아웃 성공",
|
||||||
content = @Content(schema = @Schema(implementation = Void.class)))
|
content = @Content(schema = @Schema(implementation = Object.class)))
|
||||||
})
|
})
|
||||||
public ApiResponseDto<ResponseEntity<Object>> logout(
|
public ApiResponseDto<ResponseEntity<Object>> logout(
|
||||||
Authentication authentication, HttpServletResponse response) {
|
Authentication authentication, HttpServletResponse response) {
|
||||||
|
|||||||
@@ -28,43 +28,37 @@ public class MembersDto {
|
|||||||
private String userRole;
|
private String userRole;
|
||||||
private String userRoleName;
|
private String userRoleName;
|
||||||
private String name;
|
private String name;
|
||||||
private String userId;
|
|
||||||
private String employeeNo;
|
private String employeeNo;
|
||||||
private String tempPassword;
|
|
||||||
private String status;
|
private String status;
|
||||||
private String statusName;
|
private String statusName;
|
||||||
@JsonFormatDttm private ZonedDateTime createdDttm;
|
@JsonFormatDttm private ZonedDateTime createdDttm;
|
||||||
@JsonFormatDttm private ZonedDateTime updatedDttm;
|
|
||||||
@JsonFormatDttm private ZonedDateTime firstLoginDttm;
|
@JsonFormatDttm private ZonedDateTime firstLoginDttm;
|
||||||
@JsonFormatDttm private ZonedDateTime lastLoginDttm;
|
@JsonFormatDttm private ZonedDateTime lastLoginDttm;
|
||||||
|
@JsonFormatDttm private ZonedDateTime statusChgDttm;
|
||||||
|
|
||||||
public Basic(
|
public Basic(
|
||||||
Long id,
|
Long id,
|
||||||
UUID uuid,
|
UUID uuid,
|
||||||
String userRole,
|
String userRole,
|
||||||
String name,
|
String name,
|
||||||
String userId,
|
|
||||||
String employeeNo,
|
String employeeNo,
|
||||||
String tempPassword,
|
|
||||||
String status,
|
String status,
|
||||||
ZonedDateTime createdDttm,
|
ZonedDateTime createdDttm,
|
||||||
ZonedDateTime updatedDttm,
|
|
||||||
ZonedDateTime firstLoginDttm,
|
ZonedDateTime firstLoginDttm,
|
||||||
ZonedDateTime lastLoginDttm) {
|
ZonedDateTime lastLoginDttm,
|
||||||
|
ZonedDateTime statusChgDttm) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
this.userRole = userRole;
|
this.userRole = userRole;
|
||||||
this.userRoleName = getUserRoleName(userRole);
|
this.userRoleName = getUserRoleName(userRole);
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.userId = userId;
|
|
||||||
this.employeeNo = employeeNo;
|
this.employeeNo = employeeNo;
|
||||||
this.tempPassword = tempPassword;
|
|
||||||
this.status = status;
|
this.status = status;
|
||||||
this.statusName = getStatusName(status);
|
this.statusName = getStatusName(status);
|
||||||
this.createdDttm = createdDttm;
|
this.createdDttm = createdDttm;
|
||||||
this.updatedDttm = updatedDttm;
|
|
||||||
this.firstLoginDttm = firstLoginDttm;
|
this.firstLoginDttm = firstLoginDttm;
|
||||||
this.lastLoginDttm = lastLoginDttm;
|
this.lastLoginDttm = lastLoginDttm;
|
||||||
|
this.statusChgDttm = statusChgDttm;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getUserRoleName(String roleId) {
|
private String getUserRoleName(String roleId) {
|
||||||
@@ -120,14 +114,16 @@ public class MembersDto {
|
|||||||
@Size(min = 2, max = 100)
|
@Size(min = 2, max = 100)
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@Schema(description = "임시 비밀번호", example = "q!w@e#r4")
|
@NotBlank
|
||||||
private String tempPassword;
|
@Schema(description = "패스워드", example = "")
|
||||||
|
@Size(max = 255)
|
||||||
|
private String password;
|
||||||
|
|
||||||
public AddReq(String userRole, String employeeNo, String name, String tempPassword) {
|
public AddReq(String userRole, String employeeNo, String name, String password) {
|
||||||
this.userRole = userRole;
|
this.userRole = userRole;
|
||||||
this.employeeNo = employeeNo;
|
this.employeeNo = employeeNo;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.tempPassword = tempPassword;
|
this.password = password;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,18 +135,18 @@ public class MembersDto {
|
|||||||
@Size(min = 2, max = 100)
|
@Size(min = 2, max = 100)
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@Schema(description = "패스워드", example = "")
|
|
||||||
@Size(max = 255)
|
|
||||||
private String tempPassword;
|
|
||||||
|
|
||||||
@Schema(description = "상태", example = "ACTIVE")
|
@Schema(description = "상태", example = "ACTIVE")
|
||||||
@EnumValid(enumClass = StatusType.class, message = "status는 ACTIVE, INACTIVE, DELETED 만 가능합니다.")
|
@EnumValid(enumClass = StatusType.class, message = "status는 ACTIVE, INACTIVE, DELETED 만 가능합니다.")
|
||||||
private String status;
|
private String status;
|
||||||
|
|
||||||
public UpdateReq(String name, String tempPassword, String status) {
|
@Schema(description = "패스워드", example = "")
|
||||||
|
@Size(max = 255)
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
public UpdateReq(String name, String status, String password) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.tempPassword = tempPassword;
|
|
||||||
this.status = status;
|
this.status = status;
|
||||||
|
this.password = password;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,14 +154,15 @@ public class MembersDto {
|
|||||||
@Setter
|
@Setter
|
||||||
public static class InitReq {
|
public static class InitReq {
|
||||||
|
|
||||||
@Schema(description = "변경 패스워드", example = "")
|
@Schema(description = "기존 패스워드", example = "")
|
||||||
@Size(max = 255)
|
@Size(max = 255)
|
||||||
@NotBlank
|
@NotBlank
|
||||||
private String password;
|
private String oldPassword;
|
||||||
|
|
||||||
@Schema(description = "초기 패스워드", example = "")
|
@Schema(description = "신규 패스워드", example = "")
|
||||||
|
@Size(max = 255)
|
||||||
@NotBlank
|
@NotBlank
|
||||||
private String tempPassword;
|
private String newPassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.kamco.cd.kamcoback.members.service;
|
package com.kamco.cd.kamcoback.members.service;
|
||||||
|
|
||||||
import com.kamco.cd.kamcoback.common.enums.StatusType;
|
|
||||||
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
|
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
|
||||||
import com.kamco.cd.kamcoback.common.utils.CommonStringUtils;
|
import com.kamco.cd.kamcoback.common.utils.CommonStringUtils;
|
||||||
import com.kamco.cd.kamcoback.members.dto.MembersDto;
|
import com.kamco.cd.kamcoback.members.dto.MembersDto;
|
||||||
@@ -26,7 +25,7 @@ public class AdminService {
|
|||||||
*/
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
public Long saveMember(MembersDto.AddReq addReq) {
|
public Long saveMember(MembersDto.AddReq addReq) {
|
||||||
if (!CommonStringUtils.isValidPassword(addReq.getTempPassword())) {
|
if (!CommonStringUtils.isValidPassword(addReq.getPassword())) {
|
||||||
throw new CustomApiException("WRONG_PASSWORD", HttpStatus.BAD_REQUEST);
|
throw new CustomApiException("WRONG_PASSWORD", HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,12 +40,16 @@ public class AdminService {
|
|||||||
*/
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
public void updateMembers(UUID uuid, MembersDto.UpdateReq updateReq) {
|
public void updateMembers(UUID uuid, MembersDto.UpdateReq updateReq) {
|
||||||
if (StatusType.INACTIVE.getId().equals(updateReq.getStatus())) {
|
membersCoreService.updateMembers(uuid, updateReq);
|
||||||
// 미사용 처리
|
}
|
||||||
membersCoreService.deleteMember(uuid);
|
|
||||||
} else {
|
/**
|
||||||
// 수정
|
* 사번 중복 체크
|
||||||
membersCoreService.updateMembers(uuid, updateReq);
|
*
|
||||||
}
|
* @param employeeNo
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean existsByEmployeeNo(String employeeNo) {
|
||||||
|
return membersCoreService.existsByEmployeeNo(employeeNo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,14 +33,4 @@ public class AuthService {
|
|||||||
public String getUserStatus(SignInRequest request) {
|
public String getUserStatus(SignInRequest request) {
|
||||||
return membersCoreService.getUserStatus(request);
|
return membersCoreService.getUserStatus(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 임시 패스워드 비교
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public boolean isTempPasswordValid(SignInRequest request) {
|
|
||||||
return membersCoreService.isTempPasswordValid(request);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public class MembersService {
|
|||||||
@Transactional
|
@Transactional
|
||||||
public void resetPassword(String id, MembersDto.InitReq initReq) {
|
public void resetPassword(String id, MembersDto.InitReq initReq) {
|
||||||
|
|
||||||
if (!CommonStringUtils.isValidPassword(initReq.getPassword())) {
|
if (!CommonStringUtils.isValidPassword(initReq.getNewPassword())) {
|
||||||
throw new CustomApiException("WRONG_PASSWORD", HttpStatus.BAD_REQUEST);
|
throw new CustomApiException("WRONG_PASSWORD", HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
membersCoreService.resetPassword(id, initReq);
|
membersCoreService.resetPassword(id, initReq);
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ package com.kamco.cd.kamcoback.postgres.core;
|
|||||||
|
|
||||||
import com.kamco.cd.kamcoback.code.dto.CommonCodeDto;
|
import com.kamco.cd.kamcoback.code.dto.CommonCodeDto;
|
||||||
import com.kamco.cd.kamcoback.code.dto.CommonCodeDto.Basic;
|
import com.kamco.cd.kamcoback.code.dto.CommonCodeDto.Basic;
|
||||||
|
import com.kamco.cd.kamcoback.code.dto.CommonCodeDto.SearchReq;
|
||||||
import com.kamco.cd.kamcoback.common.service.BaseCoreService;
|
import com.kamco.cd.kamcoback.common.service.BaseCoreService;
|
||||||
import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ApiResponseCode;
|
import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ApiResponseCode;
|
||||||
import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ResponseObj;
|
import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ResponseObj;
|
||||||
import com.kamco.cd.kamcoback.postgres.entity.CommonCodeEntity;
|
import com.kamco.cd.kamcoback.postgres.entity.CommonCodeEntity;
|
||||||
import com.kamco.cd.kamcoback.postgres.repository.code.CommonCodeRepository;
|
import com.kamco.cd.kamcoback.postgres.repository.code.CommonCodeRepository;
|
||||||
import com.kamco.cd.kamcoback.code.dto.CommonCodeDto.SearchReq;
|
|
||||||
import jakarta.persistence.EntityNotFoundException;
|
import jakarta.persistence.EntityNotFoundException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|||||||
@@ -52,10 +52,7 @@ public class MapSheetMngCoreService {
|
|||||||
.findMapSheetMngHstInfo(hstUid)
|
.findMapSheetMngHstInfo(hstUid)
|
||||||
.orElseThrow(EntityNotFoundException::new));
|
.orElseThrow(EntityNotFoundException::new));
|
||||||
|
|
||||||
// TODO: local TEST 시 각자 경로 수정하기
|
|
||||||
// TODO: application.yml 에 active profile : local 로 임시 변경하여 테스트
|
|
||||||
String localPath = "";
|
String localPath = "";
|
||||||
// String localPath = "C:\\Users\\gypark\\Desktop\\file";
|
|
||||||
String rootDir = ORIGINAL_IMAGES_PATH + "/" + entity.get().getMngYyyy();
|
String rootDir = ORIGINAL_IMAGES_PATH + "/" + entity.get().getMngYyyy();
|
||||||
if (activeEnv.equals("local")) {
|
if (activeEnv.equals("local")) {
|
||||||
rootDir = localPath + rootDir;
|
rootDir = localPath + rootDir;
|
||||||
@@ -68,6 +65,59 @@ public class MapSheetMngCoreService {
|
|||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 파일 크기 계산 및 저장
|
||||||
|
try (Stream<Path> paths = Files.walk(Paths.get(rootDir))) {
|
||||||
|
List<Path> matched =
|
||||||
|
paths
|
||||||
|
.filter(Files::isRegularFile)
|
||||||
|
.filter(
|
||||||
|
p -> {
|
||||||
|
String name = p.getFileName().toString();
|
||||||
|
return name.equals(filename + ".tif") || name.equals(filename + ".tfw");
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
long tifSize =
|
||||||
|
matched.stream()
|
||||||
|
.filter(p -> p.getFileName().toString().endsWith(".tif"))
|
||||||
|
.mapToLong(
|
||||||
|
p -> {
|
||||||
|
try {
|
||||||
|
return Files.size(p);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.sum();
|
||||||
|
|
||||||
|
long tfwSize =
|
||||||
|
matched.stream()
|
||||||
|
.filter(p -> p.getFileName().toString().endsWith(".tfw"))
|
||||||
|
.mapToLong(
|
||||||
|
p -> {
|
||||||
|
try {
|
||||||
|
return Files.size(p);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.sum();
|
||||||
|
|
||||||
|
entity.get().setTifSizeBytes(tifSize);
|
||||||
|
entity.get().setTfwSizeBytes(tfwSize);
|
||||||
|
entity.get().setTotalSizeBytes(tifSize + tfwSize);
|
||||||
|
|
||||||
|
// 엔터티 저장 -> 커스텀 업데이트로 변경
|
||||||
|
mapSheetMngRepository.updateHstFileSizes(
|
||||||
|
entity.get().getHstUid(), tifSize, tfwSize, tifSize + tfwSize);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// 크기 계산 실패 시 0으로 저장
|
||||||
|
entity.get().setTifSizeBytes(0L);
|
||||||
|
entity.get().setTfwSizeBytes(0L);
|
||||||
|
entity.get().setTotalSizeBytes(0L);
|
||||||
|
mapSheetMngRepository.updateHstFileSizes(entity.get().getHstUid(), 0L, 0L, 0L);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
MapSheetMngDto.DataState dataState =
|
MapSheetMngDto.DataState dataState =
|
||||||
flag ? MapSheetMngDto.DataState.SUCCESS : MapSheetMngDto.DataState.FAIL;
|
flag ? MapSheetMngDto.DataState.SUCCESS : MapSheetMngDto.DataState.FAIL;
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ package com.kamco.cd.kamcoback.postgres.core;
|
|||||||
|
|
||||||
import com.kamco.cd.kamcoback.common.utils.FIleChecker;
|
import com.kamco.cd.kamcoback.common.utils.FIleChecker;
|
||||||
import com.kamco.cd.kamcoback.mapsheet.dto.ImageryDto;
|
import com.kamco.cd.kamcoback.mapsheet.dto.ImageryDto;
|
||||||
|
import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngHstEntity;
|
||||||
import com.kamco.cd.kamcoback.postgres.repository.mapsheet.MapSheetMngFileCheckerRepository;
|
import com.kamco.cd.kamcoback.postgres.repository.mapsheet.MapSheetMngFileCheckerRepository;
|
||||||
|
import com.kamco.cd.kamcoback.postgres.repository.mapsheet.MapSheetMngRepository;
|
||||||
|
import java.util.Optional;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
@@ -13,6 +16,7 @@ import org.springframework.stereotype.Service;
|
|||||||
public class MapSheetMngFileCheckerCoreService {
|
public class MapSheetMngFileCheckerCoreService {
|
||||||
|
|
||||||
private final MapSheetMngFileCheckerRepository mapSheetMngFileCheckerRepository;
|
private final MapSheetMngFileCheckerRepository mapSheetMngFileCheckerRepository;
|
||||||
|
private final MapSheetMngRepository mapSheetMngRepository;
|
||||||
|
|
||||||
private static final String ORIGINAL_IMAGES_PATH = "/app/original-images";
|
private static final String ORIGINAL_IMAGES_PATH = "/app/original-images";
|
||||||
|
|
||||||
@@ -50,4 +54,8 @@ public class MapSheetMngFileCheckerCoreService {
|
|||||||
|
|
||||||
return new ImageryDto.SyncReturn(flag, syncCnt, tfwErrCnt, tifErrCnt);
|
return new ImageryDto.SyncReturn(flag, syncCnt, tfwErrCnt, tifErrCnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<MapSheetMngHstEntity> findHstByUid(Long hstUid) {
|
||||||
|
return mapSheetMngRepository.findMapSheetMngHstInfo(hstUid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,16 +45,16 @@ public class MembersCoreService {
|
|||||||
// salt 생성, 사번이 salt
|
// salt 생성, 사번이 salt
|
||||||
String salt = BCryptSaltGenerator.generateSaltWithEmployeeNo(addReq.getEmployeeNo().trim());
|
String salt = BCryptSaltGenerator.generateSaltWithEmployeeNo(addReq.getEmployeeNo().trim());
|
||||||
// 패스워드 암호화, 초기 패스워드 고정
|
// 패스워드 암호화, 초기 패스워드 고정
|
||||||
String hashedPassword = BCrypt.hashpw(addReq.getTempPassword(), salt);
|
String hashedPassword = BCrypt.hashpw(addReq.getPassword(), salt);
|
||||||
|
|
||||||
MemberEntity memberEntity = new MemberEntity();
|
MemberEntity memberEntity = new MemberEntity();
|
||||||
memberEntity.setUserId(addReq.getEmployeeNo());
|
memberEntity.setUserId(addReq.getEmployeeNo());
|
||||||
memberEntity.setUserRole(addReq.getUserRole());
|
memberEntity.setUserRole(addReq.getUserRole());
|
||||||
memberEntity.setTempPassword(addReq.getTempPassword().trim()); // 임시 패스워드는 암호화 하지 않음
|
|
||||||
memberEntity.setPassword(hashedPassword);
|
memberEntity.setPassword(hashedPassword);
|
||||||
memberEntity.setName(addReq.getName());
|
memberEntity.setName(addReq.getName());
|
||||||
memberEntity.setEmployeeNo(addReq.getEmployeeNo());
|
memberEntity.setEmployeeNo(addReq.getEmployeeNo());
|
||||||
memberEntity.setRgstrUidl(userUtil.getId());
|
memberEntity.setRgstrUidl(userUtil.getId());
|
||||||
|
memberEntity.setStatus(StatusType.PENDING.getId());
|
||||||
|
|
||||||
return membersRepository.save(memberEntity).getId();
|
return membersRepository.save(memberEntity).getId();
|
||||||
}
|
}
|
||||||
@@ -73,37 +73,26 @@ public class MembersCoreService {
|
|||||||
memberEntity.setName(updateReq.getName());
|
memberEntity.setName(updateReq.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 임시 패스워드는 암호화 하지 않음
|
if (StringUtils.isNotBlank(updateReq.getStatus())) {
|
||||||
if (StringUtils.isNotBlank(updateReq.getTempPassword())) {
|
memberEntity.changeStatus(updateReq.getStatus());
|
||||||
/**
|
}
|
||||||
* 임시 패스워드가 기존과 다르면 패스워드 변경으로 처리함 상태 PENDING 으로 변경하여 사용자가 로그인할때 패스워드 변경하게함 패스워드 리셋이므로 로그인
|
|
||||||
* 실패카운트 초기화처리함
|
|
||||||
*/
|
|
||||||
if (!memberEntity.getTempPassword().equals(updateReq.getTempPassword().trim())) {
|
|
||||||
// 패스워드 유효성 검사
|
|
||||||
if (!CommonStringUtils.isValidPassword(updateReq.getTempPassword())) {
|
|
||||||
throw new CustomApiException("WRONG_PASSWORD", HttpStatus.BAD_REQUEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
memberEntity.setStatus(StatusType.PENDING.getId());
|
if (StringUtils.isNotBlank(updateReq.getPassword())) {
|
||||||
memberEntity.setLoginFailCount(0);
|
|
||||||
|
// 패스워드 유효성 검사
|
||||||
|
if (!CommonStringUtils.isValidPassword(updateReq.getPassword())) {
|
||||||
|
throw new CustomApiException("WRONG_PASSWORD", HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
memberEntity.setTempPassword(updateReq.getTempPassword().trim());
|
|
||||||
|
String password =
|
||||||
|
CommonStringUtils.hashPassword(updateReq.getPassword(), memberEntity.getEmployeeNo());
|
||||||
|
|
||||||
|
memberEntity.setStatus(StatusType.PENDING.getId());
|
||||||
|
memberEntity.setLoginFailCount(0);
|
||||||
|
memberEntity.setPassword(password);
|
||||||
|
memberEntity.setPwdResetYn("Y");
|
||||||
}
|
}
|
||||||
memberEntity.setUpdtrUid(userUtil.getId());
|
memberEntity.setUpdtrUid(userUtil.getId());
|
||||||
|
|
||||||
membersRepository.save(memberEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 미사용 처리
|
|
||||||
*
|
|
||||||
* @param uuid
|
|
||||||
*/
|
|
||||||
public void deleteMember(UUID uuid) {
|
|
||||||
MemberEntity memberEntity =
|
|
||||||
membersRepository.findByUUID(uuid).orElseThrow(MemberNotFoundException::new);
|
|
||||||
memberEntity.setStatus(StatusType.INACTIVE.getId());
|
|
||||||
membersRepository.save(memberEntity);
|
membersRepository.save(memberEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,20 +105,19 @@ public class MembersCoreService {
|
|||||||
MemberEntity memberEntity =
|
MemberEntity memberEntity =
|
||||||
membersRepository.findByEmployeeNo(id).orElseThrow(() -> new MemberNotFoundException());
|
membersRepository.findByEmployeeNo(id).orElseThrow(() -> new MemberNotFoundException());
|
||||||
|
|
||||||
// 임시 패스워드 확인
|
// 기존 패스워드 확인
|
||||||
if (!memberEntity.getTempPassword().equals(initReq.getTempPassword())) {
|
if (!BCrypt.checkpw(initReq.getOldPassword(), memberEntity.getPassword())) {
|
||||||
throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_MISMATCH);
|
throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_MISMATCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
String salt =
|
String password =
|
||||||
BCryptSaltGenerator.generateSaltWithEmployeeNo(memberEntity.getEmployeeNo().trim());
|
CommonStringUtils.hashPassword(initReq.getNewPassword(), memberEntity.getEmployeeNo());
|
||||||
// 패스워드 암호화
|
|
||||||
String hashedPassword = BCrypt.hashpw(initReq.getPassword(), salt);
|
|
||||||
|
|
||||||
memberEntity.setPassword(hashedPassword);
|
memberEntity.setPassword(password);
|
||||||
memberEntity.setStatus("ACTIVE");
|
memberEntity.setStatus(StatusType.ACTIVE.getId());
|
||||||
memberEntity.setUpdatedDttm(ZonedDateTime.now());
|
memberEntity.setUpdatedDttm(ZonedDateTime.now());
|
||||||
memberEntity.setUpdtrUid(memberEntity.getId());
|
memberEntity.setUpdtrUid(memberEntity.getId());
|
||||||
|
memberEntity.setPwdResetYn("N");
|
||||||
membersRepository.save(memberEntity);
|
membersRepository.save(memberEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,21 +147,6 @@ public class MembersCoreService {
|
|||||||
return memberEntity.getStatus();
|
return memberEntity.getStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 임시 패스워드 비교
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public boolean isTempPasswordValid(SignInRequest request) {
|
|
||||||
MemberEntity memberEntity =
|
|
||||||
membersRepository
|
|
||||||
.findByUserId(request.getUsername())
|
|
||||||
.orElseThrow(MemberNotFoundException::new);
|
|
||||||
|
|
||||||
return memberEntity.getTempPassword().equals(request.getPassword().trim());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 최초 로그인 저장 마지막 로그인 저장
|
* 최초 로그인 저장 마지막 로그인 저장
|
||||||
*
|
*
|
||||||
@@ -190,4 +163,14 @@ public class MembersCoreService {
|
|||||||
memberEntity.setLoginFailCount(0);
|
memberEntity.setLoginFailCount(0);
|
||||||
membersRepository.save(memberEntity);
|
membersRepository.save(memberEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 사번 중복체크
|
||||||
|
*
|
||||||
|
* @param employeeNo
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean existsByEmployeeNo(String employeeNo) {
|
||||||
|
return membersRepository.existsByEmployeeNo(employeeNo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,14 @@ import lombok.NoArgsConstructor;
|
|||||||
@Table(name = "tb_audit_log")
|
@Table(name = "tb_audit_log")
|
||||||
public class AuditLogEntity extends CommonCreateEntity {
|
public class AuditLogEntity extends CommonCreateEntity {
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(
|
||||||
@Column(name = "audit_log_uid")
|
strategy = GenerationType.SEQUENCE,
|
||||||
|
generator = "tb_audit_log_audit_log_uid_seq_gen")
|
||||||
|
@SequenceGenerator(
|
||||||
|
name = "tb_audit_log_audit_log_uid_seq_gen",
|
||||||
|
sequenceName = "tb_audit_log_audit_log_uid_seq",
|
||||||
|
allocationSize = 1)
|
||||||
|
@Column(name = "audit_log_uid", nullable = false)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Column(name = "user_uid")
|
@Column(name = "user_uid")
|
||||||
|
|||||||
@@ -16,8 +16,14 @@ import lombok.NoArgsConstructor;
|
|||||||
@Table(name = "tb_error_log")
|
@Table(name = "tb_error_log")
|
||||||
public class ErrorLogEntity extends CommonCreateEntity {
|
public class ErrorLogEntity extends CommonCreateEntity {
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(
|
||||||
@Column(name = "error_log_uid")
|
strategy = GenerationType.SEQUENCE,
|
||||||
|
generator = "tb_error_log_error_log_uid_seq_gen")
|
||||||
|
@SequenceGenerator(
|
||||||
|
name = "tb_error_log_error_log_uid_seq_gen",
|
||||||
|
sequenceName = "tb_error_log_error_log_uid_seq",
|
||||||
|
allocationSize = 1)
|
||||||
|
@Column(name = "error_log_uid", nullable = false)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Column(name = "request_id")
|
@Column(name = "request_id")
|
||||||
|
|||||||
@@ -50,10 +50,4 @@ public class MapSheetMngFileEntity {
|
|||||||
|
|
||||||
@Column(name = "file_size")
|
@Column(name = "file_size")
|
||||||
private Long fileSize;
|
private Long fileSize;
|
||||||
|
|
||||||
|
|
||||||
@Size(max = 20)
|
|
||||||
@Column(name = "file_state", length = 20)
|
|
||||||
private String fileState;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,4 +78,13 @@ public class MapSheetMngHstEntity extends CommonDateEntity {
|
|||||||
|
|
||||||
@Column(name = "sync_check_end_dttm")
|
@Column(name = "sync_check_end_dttm")
|
||||||
private ZonedDateTime syncCheckEndDttm;
|
private ZonedDateTime syncCheckEndDttm;
|
||||||
|
|
||||||
|
@Column(name = "tif_size_bytes")
|
||||||
|
private Long tifSizeBytes;
|
||||||
|
|
||||||
|
@Column(name = "tfw_size_bytes")
|
||||||
|
private Long tfwSizeBytes;
|
||||||
|
|
||||||
|
@Column(name = "total_size_bytes")
|
||||||
|
private Long totalSizeBytes;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
package com.kamco.cd.kamcoback.postgres.entity;
|
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
|
||||||
import jakarta.persistence.EmbeddedId;
|
|
||||||
import jakarta.persistence.Entity;
|
|
||||||
import jakarta.persistence.Table;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import jakarta.validation.constraints.Size;
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import org.hibernate.annotations.ColumnDefault;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
@Entity
|
|
||||||
@Table(name = "tb_member_archived")
|
|
||||||
public class MemberArchivedEntity {
|
|
||||||
|
|
||||||
@EmbeddedId private MemberArchivedEntityId id;
|
|
||||||
|
|
||||||
@Size(max = 50)
|
|
||||||
@Column(name = "employee_no", length = 50)
|
|
||||||
private String employeeNo;
|
|
||||||
|
|
||||||
@Size(max = 100)
|
|
||||||
@NotNull
|
|
||||||
@Column(name = "name", nullable = false, length = 100)
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@Size(max = 255)
|
|
||||||
@NotNull
|
|
||||||
@Column(name = "password", nullable = false)
|
|
||||||
private String password;
|
|
||||||
|
|
||||||
@Size(max = 100)
|
|
||||||
@NotNull
|
|
||||||
@Column(name = "email", nullable = false, length = 100)
|
|
||||||
private String email;
|
|
||||||
|
|
||||||
@Size(max = 20)
|
|
||||||
@Column(name = "status", length = 20)
|
|
||||||
private String status;
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Column(name = "created_dttm", nullable = false)
|
|
||||||
private ZonedDateTime createdDttm;
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@ColumnDefault("now()")
|
|
||||||
@Column(name = "archived_dttm", nullable = false)
|
|
||||||
private ZonedDateTime archivedDttm;
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
package com.kamco.cd.kamcoback.postgres.entity;
|
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
|
||||||
import jakarta.persistence.Embeddable;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.UUID;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import org.hibernate.Hibernate;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
@Embeddable
|
|
||||||
public class MemberArchivedEntityId implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = -7102800377481389036L;
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Column(name = "user_id", nullable = false)
|
|
||||||
private Long userId;
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Column(name = "uuid", nullable = false)
|
|
||||||
private UUID uuid;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
MemberArchivedEntityId entity = (MemberArchivedEntityId) o;
|
|
||||||
return Objects.equals(this.userId, entity.userId) && Objects.equals(this.uuid, entity.uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(userId, uuid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,11 +9,14 @@ import jakarta.persistence.Id;
|
|||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import jakarta.validation.constraints.Size;
|
import jakarta.validation.constraints.Size;
|
||||||
|
import java.sql.Types;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.hibernate.annotations.ColumnDefault;
|
import org.hibernate.annotations.ColumnDefault;
|
||||||
|
import org.hibernate.annotations.JdbcTypeCode;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@@ -51,18 +54,12 @@ public class MemberEntity {
|
|||||||
@Column(name = "name", nullable = false, length = 100)
|
@Column(name = "name", nullable = false, length = 100)
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@Size(max = 255)
|
|
||||||
@NotNull
|
|
||||||
@Column(name = "temp_password", nullable = false)
|
|
||||||
private String tempPassword;
|
|
||||||
|
|
||||||
@Size(max = 255)
|
@Size(max = 255)
|
||||||
@NotNull
|
@NotNull
|
||||||
@Column(name = "password", nullable = false)
|
@Column(name = "password", nullable = false)
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
@Size(max = 20)
|
@Size(max = 20)
|
||||||
@ColumnDefault("'INACTIVE'")
|
|
||||||
@Column(name = "status", length = 20)
|
@Column(name = "status", length = 20)
|
||||||
private String status = StatusType.PENDING.getId();
|
private String status = StatusType.PENDING.getId();
|
||||||
|
|
||||||
@@ -90,4 +87,20 @@ public class MemberEntity {
|
|||||||
|
|
||||||
@Column(name = "updtr_uid")
|
@Column(name = "updtr_uid")
|
||||||
private Long updtrUid;
|
private Long updtrUid;
|
||||||
|
|
||||||
|
@Column(name = "status_chg_dttm")
|
||||||
|
private ZonedDateTime statusChgDttm;
|
||||||
|
|
||||||
|
@JdbcTypeCode(Types.CHAR)
|
||||||
|
@Column(name = "pwd_reset_yn", columnDefinition = "CHAR(1)")
|
||||||
|
private String pwdResetYn;
|
||||||
|
|
||||||
|
public void changeStatus(String newStatus) {
|
||||||
|
// 같은 값 보내도 무시
|
||||||
|
if (Objects.equals(this.status, newStatus)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.status = newStatus;
|
||||||
|
this.statusChgDttm = ZonedDateTime.now();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,4 +24,6 @@ public interface MapSheetMngRepositoryCustom {
|
|||||||
|
|
||||||
Page<MapSheetMngDto.ErrorDataDto> findMapSheetErrorList(
|
Page<MapSheetMngDto.ErrorDataDto> findMapSheetErrorList(
|
||||||
MapSheetMngDto.@Valid ErrorSearchReq searchReq);
|
MapSheetMngDto.@Valid ErrorSearchReq searchReq);
|
||||||
|
|
||||||
|
void updateHstFileSizes(Long hstUid, long tifSizeBytes, long tfwSizeBytes, long totalSizeBytes);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -266,6 +266,19 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport
|
|||||||
.fetchOne());
|
.fetchOne());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateHstFileSizes(
|
||||||
|
Long hstUid, long tifSizeBytes, long tfwSizeBytes, long totalSizeBytes) {
|
||||||
|
String sql =
|
||||||
|
"UPDATE tb_map_sheet_mng_hst SET tif_size_bytes = :tif, tfw_size_bytes = :tfw, total_size_bytes = :tot WHERE hst_uid = :uid";
|
||||||
|
Query query = (Query) em.createNativeQuery(sql);
|
||||||
|
query.setParameter("tif", tifSizeBytes);
|
||||||
|
query.setParameter("tfw", tfwSizeBytes);
|
||||||
|
query.setParameter("tot", totalSizeBytes);
|
||||||
|
query.setParameter("uid", hstUid);
|
||||||
|
query.executeUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
private NumberExpression<Integer> rowNum() {
|
private NumberExpression<Integer> rowNum() {
|
||||||
return Expressions.numberTemplate(
|
return Expressions.numberTemplate(
|
||||||
Integer.class, "row_number() over(order by {0} desc)", mapSheetMngHstEntity.createdDate);
|
Integer.class, "row_number() over(order by {0} desc)", mapSheetMngHstEntity.createdDate);
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
package com.kamco.cd.kamcoback.postgres.repository.members;
|
|
||||||
|
|
||||||
import com.kamco.cd.kamcoback.postgres.entity.MemberArchivedEntity;
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
|
||||||
|
|
||||||
public interface MembersArchivedRepository
|
|
||||||
extends JpaRepository<MemberArchivedEntity, Long>, MembersArchivedRepositoryCustom {}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
package com.kamco.cd.kamcoback.postgres.repository.members;
|
|
||||||
|
|
||||||
public interface MembersArchivedRepositoryCustom {}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
package com.kamco.cd.kamcoback.postgres.repository.members;
|
|
||||||
|
|
||||||
import org.springframework.stereotype.Repository;
|
|
||||||
|
|
||||||
@Repository
|
|
||||||
public class MembersArchivedRepositoryImpl implements MembersArchivedRepositoryCustom {}
|
|
||||||
@@ -120,14 +120,12 @@ public class MembersRepositoryImpl implements MembersRepositoryCustom {
|
|||||||
memberEntity.uuid,
|
memberEntity.uuid,
|
||||||
memberEntity.userRole,
|
memberEntity.userRole,
|
||||||
memberEntity.name,
|
memberEntity.name,
|
||||||
memberEntity.userId,
|
|
||||||
memberEntity.employeeNo,
|
memberEntity.employeeNo,
|
||||||
memberEntity.tempPassword,
|
|
||||||
memberEntity.status,
|
memberEntity.status,
|
||||||
memberEntity.createdDttm,
|
memberEntity.createdDttm,
|
||||||
memberEntity.updatedDttm,
|
|
||||||
memberEntity.firstLoginDttm,
|
memberEntity.firstLoginDttm,
|
||||||
memberEntity.lastLoginDttm))
|
memberEntity.lastLoginDttm,
|
||||||
|
memberEntity.statusChgDttm))
|
||||||
.from(memberEntity)
|
.from(memberEntity)
|
||||||
.where(builder)
|
.where(builder)
|
||||||
.offset(pageable.getOffset())
|
.offset(pageable.getOffset())
|
||||||
|
|||||||
@@ -48,22 +48,27 @@ server:
|
|||||||
|
|
||||||
jwt:
|
jwt:
|
||||||
secret: "kamco_token_9b71e778-19a3-4c1d-97bf-2d687de17d5b"
|
secret: "kamco_token_9b71e778-19a3-4c1d-97bf-2d687de17d5b"
|
||||||
#access-token-validity-in-ms: 86400000 # 1일
|
access-token-validity-in-ms: 86400000 # 1일
|
||||||
#refresh-token-validity-in-ms: 604800000 # 7일
|
refresh-token-validity-in-ms: 604800000 # 7일
|
||||||
access-token-validity-in-ms: 60000 # 1분
|
#access-token-validity-in-ms: 60000 # 1분
|
||||||
refresh-token-validity-in-ms: 300000 # 5분
|
#refresh-token-validity-in-ms: 300000 # 5분
|
||||||
|
|
||||||
token:
|
token:
|
||||||
refresh-cookie-name: kamco-dev # 개발용 쿠키 이름
|
refresh-cookie-name: kamco-dev # 개발용 쿠키 이름
|
||||||
refresh-cookie-secure: false # 로컬 http 테스트면 false
|
refresh-cookie-secure: false # 로컬 http 테스트면 false
|
||||||
|
|
||||||
|
springdoc:
|
||||||
|
swagger-ui:
|
||||||
|
persist-authorization: true # 스웨거 새로고침해도 토큰 유지, 로컬스토리지에 저장
|
||||||
|
|
||||||
logging:
|
logging:
|
||||||
level:
|
level:
|
||||||
org:
|
org:
|
||||||
springframework:
|
springframework:
|
||||||
security: DEBUG
|
security: DEBUG
|
||||||
org.springframework.security: DEBUG
|
org.springframework.security: DEBUG
|
||||||
|
|
||||||
|
|
||||||
mapsheet:
|
mapsheet:
|
||||||
upload:
|
upload:
|
||||||
skipGdalValidation: true
|
skipGdalValidation: true
|
||||||
|
|||||||
@@ -38,4 +38,10 @@ token:
|
|||||||
refresh-cookie-name: kamco-local # 개발용 쿠키 이름
|
refresh-cookie-name: kamco-local # 개발용 쿠키 이름
|
||||||
refresh-cookie-secure: false # 로컬 http 테스트면 false
|
refresh-cookie-secure: false # 로컬 http 테스트면 false
|
||||||
|
|
||||||
|
springdoc:
|
||||||
|
swagger-ui:
|
||||||
|
persist-authorization: true # 스웨거 새로고침해도 토큰 유지, 로컬스토리지에 저장
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
-- Fix timestamp column type conversion issue
|
|
||||||
-- Run this if the Hibernate automatic schema update still fails
|
|
||||||
|
|
||||||
-- For tb_map_sheet_anal_data
|
|
||||||
ALTER TABLE tb_map_sheet_anal_data
|
|
||||||
ALTER COLUMN anal_end_dttm SET DATA TYPE TIMESTAMP WITH TIME ZONE
|
|
||||||
USING anal_end_dttm::TIMESTAMP WITH TIME ZONE;
|
|
||||||
|
|
||||||
ALTER TABLE tb_map_sheet_anal_data
|
|
||||||
ALTER COLUMN anal_strt_dttm SET DATA TYPE TIMESTAMP WITH TIME ZONE
|
|
||||||
USING anal_strt_dttm::TIMESTAMP WITH TIME ZONE;
|
|
||||||
|
|
||||||
ALTER TABLE tb_map_sheet_anal_data
|
|
||||||
ALTER COLUMN created_dttm SET DATA TYPE TIMESTAMP WITH TIME ZONE
|
|
||||||
USING created_dttm::TIMESTAMP WITH TIME ZONE;
|
|
||||||
|
|
||||||
ALTER TABLE tb_map_sheet_anal_data
|
|
||||||
ALTER COLUMN updated_dttm SET DATA TYPE TIMESTAMP WITH TIME ZONE
|
|
||||||
USING updated_dttm::TIMESTAMP WITH TIME ZONE;
|
|
||||||
|
|
||||||
ALTER TABLE tb_map_sheet_anal_data
|
|
||||||
ALTER COLUMN data_state_dttm SET DATA TYPE TIMESTAMP WITH TIME ZONE
|
|
||||||
USING data_state_dttm::TIMESTAMP WITH TIME ZONE;
|
|
||||||
|
|
||||||
-- For tb_map_sheet_learn_data
|
|
||||||
ALTER TABLE tb_map_sheet_learn_data
|
|
||||||
ALTER COLUMN anal_end_dttm SET DATA TYPE TIMESTAMP WITH TIME ZONE
|
|
||||||
USING anal_end_dttm::TIMESTAMP WITH TIME ZONE;
|
|
||||||
|
|
||||||
ALTER TABLE tb_map_sheet_learn_data
|
|
||||||
ALTER COLUMN anal_strt_dttm SET DATA TYPE TIMESTAMP WITH TIME ZONE
|
|
||||||
USING anal_strt_dttm::TIMESTAMP WITH TIME ZONE;
|
|
||||||
|
|
||||||
ALTER TABLE tb_map_sheet_learn_data
|
|
||||||
ALTER COLUMN created_dttm SET DATA TYPE TIMESTAMP WITH TIME ZONE
|
|
||||||
USING created_dttm::TIMESTAMP WITH TIME ZONE;
|
|
||||||
|
|
||||||
ALTER TABLE tb_map_sheet_learn_data
|
|
||||||
ALTER COLUMN updated_dttm SET DATA TYPE TIMESTAMP WITH TIME ZONE
|
|
||||||
USING updated_dttm::TIMESTAMP WITH TIME ZONE;
|
|
||||||
|
|
||||||
ALTER TABLE tb_map_sheet_learn_data
|
|
||||||
ALTER COLUMN data_state_dttm SET DATA TYPE TIMESTAMP WITH TIME ZONE
|
|
||||||
USING data_state_dttm::TIMESTAMP WITH TIME ZONE;
|
|
||||||
|
|
||||||
ALTER TABLE tb_map_sheet_learn_data
|
|
||||||
ALTER COLUMN gukuin_used_dttm SET DATA TYPE TIMESTAMP WITH TIME ZONE
|
|
||||||
USING gukuin_used_dttm::TIMESTAMP WITH TIME ZONE;
|
|
||||||
|
|
||||||
-- For tb_map_sheet_learn_data_geom
|
|
||||||
ALTER TABLE tb_map_sheet_learn_data_geom
|
|
||||||
ALTER COLUMN created_dttm SET DATA TYPE TIMESTAMP WITH TIME ZONE
|
|
||||||
USING created_dttm::TIMESTAMP WITH TIME ZONE;
|
|
||||||
|
|
||||||
ALTER TABLE tb_map_sheet_learn_data_geom
|
|
||||||
ALTER COLUMN updated_dttm SET DATA TYPE TIMESTAMP WITH TIME ZONE
|
|
||||||
USING updated_dttm::TIMESTAMP WITH TIME ZONE;
|
|
||||||
|
|
||||||
-- For tb_map_sheet_anal_data_geom
|
|
||||||
ALTER TABLE tb_map_sheet_anal_data_geom
|
|
||||||
ALTER COLUMN created_dttm SET DATA TYPE TIMESTAMP WITH TIME ZONE
|
|
||||||
USING created_dttm::TIMESTAMP WITH TIME ZONE;
|
|
||||||
|
|
||||||
ALTER TABLE tb_map_sheet_anal_data_geom
|
|
||||||
ALTER COLUMN updated_dttm SET DATA TYPE TIMESTAMP WITH TIME ZONE
|
|
||||||
USING updated_dttm::TIMESTAMP WITH TIME ZONE;
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
-- GeoJSON 모니터링 시스템을 위한 필수 테이블 생성 스크립트
|
|
||||||
-- dump-kamco_cds-202511201730.sql에서 추출
|
|
||||||
|
|
||||||
-- 1. 시퀀스 생성
|
|
||||||
CREATE SEQUENCE IF NOT EXISTS public.tb_map_sheet_learn_data_data_uid
|
|
||||||
START WITH 1
|
|
||||||
INCREMENT BY 1
|
|
||||||
NO MINVALUE
|
|
||||||
NO MAXVALUE
|
|
||||||
CACHE 1;
|
|
||||||
|
|
||||||
-- 2. tb_map_sheet_learn_data 테이블 생성
|
|
||||||
CREATE TABLE IF NOT EXISTS public.tb_map_sheet_learn_data (
|
|
||||||
data_uid bigint DEFAULT nextval('public.tb_map_sheet_learn_data_data_uid'::regclass) NOT NULL,
|
|
||||||
data_name character varying(128),
|
|
||||||
data_path character varying(255),
|
|
||||||
data_type character varying(128),
|
|
||||||
data_crs_type character varying(128),
|
|
||||||
data_crs_type_name character varying(255),
|
|
||||||
created_dttm timestamp without time zone DEFAULT now(),
|
|
||||||
created_uid bigint,
|
|
||||||
updated_dttm timestamp without time zone DEFAULT now(),
|
|
||||||
updated_uid bigint,
|
|
||||||
compare_yyyy integer,
|
|
||||||
data_yyyy integer,
|
|
||||||
data_json json,
|
|
||||||
data_state character varying(20),
|
|
||||||
data_state_dttm timestamp without time zone DEFAULT now(),
|
|
||||||
data_title character varying(255),
|
|
||||||
anal_map_sheet character varying(255),
|
|
||||||
anal_strt_dttm timestamp without time zone,
|
|
||||||
anal_end_dttm time without time zone,
|
|
||||||
anal_sec bigint,
|
|
||||||
gukuin_used character varying(20),
|
|
||||||
gukuin_used_dttm timestamp without time zone,
|
|
||||||
anal_state character varying(20),
|
|
||||||
CONSTRAINT tb_map_sheet_learn_data_pkey PRIMARY KEY (data_uid)
|
|
||||||
);
|
|
||||||
|
|
||||||
-- 3. 시퀀스 생성 (Geometry용)
|
|
||||||
CREATE SEQUENCE IF NOT EXISTS public.tb_map_sheet_learn_data_geom_geom_uid
|
|
||||||
START WITH 1
|
|
||||||
INCREMENT BY 1
|
|
||||||
NO MINVALUE
|
|
||||||
NO MAXVALUE
|
|
||||||
CACHE 1;
|
|
||||||
|
|
||||||
-- 4. tb_map_sheet_learn_data_geom 테이블 생성
|
|
||||||
CREATE TABLE IF NOT EXISTS public.tb_map_sheet_learn_data_geom (
|
|
||||||
geo_uid bigint DEFAULT nextval('public.tb_map_sheet_learn_data_geom_geom_uid'::regclass) NOT NULL,
|
|
||||||
cd_prob double precision,
|
|
||||||
class_before_name character varying(100),
|
|
||||||
class_before_prob double precision,
|
|
||||||
class_after_name character varying(100),
|
|
||||||
class_after_prob double precision,
|
|
||||||
map_sheet_num bigint,
|
|
||||||
before_yyyy integer,
|
|
||||||
after_yyyy integer,
|
|
||||||
area double precision,
|
|
||||||
geom public.geometry,
|
|
||||||
geo_type character varying(100),
|
|
||||||
data_uid bigint,
|
|
||||||
created_dttm timestamp without time zone,
|
|
||||||
created_uid bigint,
|
|
||||||
updated_dttm timestamp without time zone,
|
|
||||||
updated_uid bigint,
|
|
||||||
CONSTRAINT tb_map_sheet_learn_data_geom_pkey PRIMARY KEY (geo_uid)
|
|
||||||
);
|
|
||||||
|
|
||||||
-- 5. 외래 키 제약 조건
|
|
||||||
ALTER TABLE ONLY public.tb_map_sheet_learn_data_geom
|
|
||||||
ADD CONSTRAINT fk_learn_data_geom_data_uid
|
|
||||||
FOREIGN KEY (data_uid) REFERENCES public.tb_map_sheet_learn_data(data_uid) ON DELETE CASCADE;
|
|
||||||
|
|
||||||
-- 6. 인덱스 생성
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_tb_map_sheet_learn_data_data_state ON public.tb_map_sheet_learn_data(data_state);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_tb_map_sheet_learn_data_anal_state ON public.tb_map_sheet_learn_data(anal_state);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_tb_map_sheet_learn_data_data_path ON public.tb_map_sheet_learn_data(data_path);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_tb_map_sheet_learn_data_geom_data_uid ON public.tb_map_sheet_learn_data_geom(data_uid);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_tb_map_sheet_learn_data_geom_geo_type ON public.tb_map_sheet_learn_data_geom(geo_type);
|
|
||||||
|
|
||||||
-- 7. 테이블 코멘트
|
|
||||||
COMMENT ON TABLE public.tb_map_sheet_learn_data IS '학습데이터';
|
|
||||||
COMMENT ON COLUMN public.tb_map_sheet_learn_data.data_uid IS '식별키';
|
|
||||||
COMMENT ON COLUMN public.tb_map_sheet_learn_data.data_name IS '데이타명';
|
|
||||||
COMMENT ON COLUMN public.tb_map_sheet_learn_data.data_path IS '경로';
|
|
||||||
COMMENT ON COLUMN public.tb_map_sheet_learn_data.data_type IS '타입';
|
|
||||||
COMMENT ON COLUMN public.tb_map_sheet_learn_data.data_state IS '처리상태';
|
|
||||||
COMMENT ON COLUMN public.tb_map_sheet_learn_data.anal_state IS '분석상태';
|
|
||||||
|
|
||||||
COMMENT ON TABLE public.tb_map_sheet_learn_data_geom IS '학습데이터GEOM정보';
|
|
||||||
COMMENT ON COLUMN public.tb_map_sheet_learn_data_geom.geo_uid IS '식별키';
|
|
||||||
COMMENT ON COLUMN public.tb_map_sheet_learn_data_geom.geom IS 'geometry정보';
|
|
||||||
COMMENT ON COLUMN public.tb_map_sheet_learn_data_geom.data_uid IS '데이터식별키';
|
|
||||||
|
|
||||||
-- 완료 메시지
|
|
||||||
SELECT 'GeoJSON 모니터링 시스템 테이블 생성 완료' as message;
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
-- PostGIS extension 및 기본 설정 확인
|
|
||||||
-- 이 스크립트를 PostgreSQL에서 실행하여 PostGIS가 설치되어 있는지 확인
|
|
||||||
|
|
||||||
-- 1. PostGIS extension 설치 (이미 설치되어 있다면 무시됨)
|
|
||||||
CREATE EXTENSION IF NOT EXISTS postgis;
|
|
||||||
CREATE EXTENSION IF NOT EXISTS postgis_topology;
|
|
||||||
|
|
||||||
-- 2. 현재 설치된 확장 확인
|
|
||||||
SELECT name, default_version, installed_version
|
|
||||||
FROM pg_available_extensions
|
|
||||||
WHERE name LIKE '%postgis%';
|
|
||||||
|
|
||||||
-- 3. Geometry 타입이 사용 가능한지 확인
|
|
||||||
SELECT typname
|
|
||||||
FROM pg_type
|
|
||||||
WHERE typname = 'geometry';
|
|
||||||
|
|
||||||
-- 4. 테스트용 geometry 컬럼 생성 확인
|
|
||||||
DO $$
|
|
||||||
BEGIN
|
|
||||||
-- 임시 테스트 테이블로 geometry 타입 확인
|
|
||||||
DROP TABLE IF EXISTS temp_geom_test;
|
|
||||||
CREATE TEMP TABLE temp_geom_test (
|
|
||||||
id serial,
|
|
||||||
test_geom geometry(Point, 4326)
|
|
||||||
);
|
|
||||||
RAISE NOTICE 'PostGIS geometry 타입이 정상적으로 작동합니다.';
|
|
||||||
EXCEPTION
|
|
||||||
WHEN OTHERS THEN
|
|
||||||
RAISE NOTICE 'PostGIS 설정에 문제가 있습니다: %', SQLERRM;
|
|
||||||
END
|
|
||||||
$$;
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
-- Fix geometry column type in tb_map_sheet_learn_data_geom table
|
|
||||||
-- The table was incorrectly created with 'bytea' type instead of 'geometry' type
|
|
||||||
|
|
||||||
-- 1. First ensure PostGIS is enabled
|
|
||||||
CREATE EXTENSION IF NOT EXISTS postgis;
|
|
||||||
|
|
||||||
-- 2. Check if column needs to be recreated (only if it's bytea type)
|
|
||||||
-- Only clear data if the column type is incorrect and needs conversion
|
|
||||||
DO $$
|
|
||||||
BEGIN
|
|
||||||
-- Only delete data if geom column exists and is bytea type
|
|
||||||
IF EXISTS (
|
|
||||||
SELECT 1 FROM information_schema.columns
|
|
||||||
WHERE table_name = 'tb_map_sheet_learn_data_geom'
|
|
||||||
AND column_name = 'geom'
|
|
||||||
AND data_type = 'bytea'
|
|
||||||
) THEN
|
|
||||||
DELETE FROM public.tb_map_sheet_learn_data_geom WHERE geom IS NOT NULL;
|
|
||||||
RAISE NOTICE 'Cleared incorrect bytea geometry data for conversion';
|
|
||||||
ELSE
|
|
||||||
RAISE NOTICE 'Geometry column is already correct type, skipping data deletion';
|
|
||||||
END IF;
|
|
||||||
END $$;
|
|
||||||
|
|
||||||
-- 3. Drop and recreate the geom column with correct PostGIS geometry type (only if needed)
|
|
||||||
ALTER TABLE public.tb_map_sheet_learn_data_geom DROP COLUMN IF EXISTS geom;
|
|
||||||
ALTER TABLE public.tb_map_sheet_learn_data_geom ADD COLUMN geom geometry(Polygon, 5186);
|
|
||||||
|
|
||||||
-- 4. Create spatial index for performance
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_tb_map_sheet_learn_data_geom_spatial
|
|
||||||
ON public.tb_map_sheet_learn_data_geom USING GIST (geom);
|
|
||||||
|
|
||||||
-- 5. Update column comment
|
|
||||||
COMMENT ON COLUMN public.tb_map_sheet_learn_data_geom.geom IS 'PostGIS geometry 정보 (Polygon, EPSG:5186)';
|
|
||||||
|
|
||||||
-- 6. Verify the column type is correct
|
|
||||||
SELECT column_name, data_type, udt_name
|
|
||||||
FROM information_schema.columns
|
|
||||||
WHERE table_name = 'tb_map_sheet_learn_data_geom' AND column_name = 'geom';
|
|
||||||
|
|
||||||
SELECT 'Geometry column type fixed successfully' as message;
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user