Merge remote-tracking branch 'origin/feat/dev_251201' into feat/dev_251201
# Conflicts: # src/main/java/com/kamco/cd/kamcoback/mapsheet/MapSheetMngFileCheckerApiController.java # src/main/resources/application-local.yml
This commit is contained in:
@@ -30,8 +30,8 @@ public class CustomAuthenticationProvider implements AuthenticationProvider {
|
|||||||
.findByUserId(username)
|
.findByUserId(username)
|
||||||
.orElseThrow(() -> new CustomApiException(AuthErrorCode.LOGIN_ID_NOT_FOUND));
|
.orElseThrow(() -> new CustomApiException(AuthErrorCode.LOGIN_ID_NOT_FOUND));
|
||||||
|
|
||||||
// 삭제 상태
|
// 미사용 상태
|
||||||
if (member.getStatus().equals(StatusType.DELETED.getId())) {
|
if (member.getStatus().equals(StatusType.INACTIVE.getId())) {
|
||||||
throw new CustomApiException(AuthErrorCode.LOGIN_ID_NOT_FOUND);
|
throw new CustomApiException(AuthErrorCode.LOGIN_ID_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,15 +39,12 @@ public class CustomAuthenticationProvider implements AuthenticationProvider {
|
|||||||
if (!BCrypt.checkpw(rawPassword, member.getPassword())) {
|
if (!BCrypt.checkpw(rawPassword, member.getPassword())) {
|
||||||
// 실패 카운트 저장
|
// 실패 카운트 저장
|
||||||
int cnt = member.getLoginFailCount() + 1;
|
int cnt = member.getLoginFailCount() + 1;
|
||||||
if (cnt >= 5) {
|
|
||||||
member.setStatus(StatusType.INACTIVE.getId());
|
|
||||||
}
|
|
||||||
member.setLoginFailCount(cnt);
|
member.setLoginFailCount(cnt);
|
||||||
membersRepository.save(member);
|
membersRepository.save(member);
|
||||||
throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_MISMATCH);
|
throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_MISMATCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 패스워드 실패 횟수 체크
|
// 로그인 실패 체크
|
||||||
if (member.getLoginFailCount() >= 5) {
|
if (member.getLoginFailCount() >= 5) {
|
||||||
throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_EXCEEDED);
|
throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_EXCEEDED);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ import lombok.AllArgsConstructor;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
|
|
||||||
public class CommonCodeDto {
|
public class CommonCodeDto {
|
||||||
|
|
||||||
@@ -132,6 +135,33 @@ public class CommonCodeDto {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Schema(name = "SearchReq", description = "검색 요청")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class SearchReq {
|
||||||
|
|
||||||
|
// 검색 조건
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
// 페이징 파라미터
|
||||||
|
private int page = 0;
|
||||||
|
private int size = 20;
|
||||||
|
private String sort;
|
||||||
|
|
||||||
|
public Pageable toPageable() {
|
||||||
|
if (sort != null && !sort.isEmpty()) {
|
||||||
|
String[] sortParams = sort.split(",");
|
||||||
|
String property = sortParams[0];
|
||||||
|
Sort.Direction direction =
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public static class Clazzes {
|
public static class Clazzes {
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import lombok.Getter;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum StatusType implements EnumType {
|
public enum StatusType implements EnumType {
|
||||||
ACTIVE("활성"),
|
ACTIVE("활성"),
|
||||||
INACTIVE("비활성"),
|
INACTIVE("미사용"),
|
||||||
DELETED("삭제");
|
PENDING("보류");
|
||||||
|
|
||||||
private final String desc;
|
private final String desc;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.kamco.cd.kamcoback.common.utils;
|
||||||
|
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class CommonStringUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 영문, 숫자, 특수문자를 모두 포함하여 8~20자 이내의 비밀번호
|
||||||
|
*
|
||||||
|
* @param password
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean isValidPassword(String password) {
|
||||||
|
String passwordPattern =
|
||||||
|
"^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-\\[\\]{};':\"\\\\|,.<>/?]).{8,20}$";
|
||||||
|
return Pattern.matches(passwordPattern, password);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -472,23 +472,38 @@ public class GlobalExceptionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(CustomApiException.class)
|
@ExceptionHandler(CustomApiException.class)
|
||||||
public ResponseEntity<ApiResponseDto<String>> handleCustomApiException(
|
public ApiResponseDto<String> handleCustomApiException(
|
||||||
CustomApiException e, HttpServletRequest request) {
|
CustomApiException e, HttpServletRequest request) {
|
||||||
log.warn("[CustomApiException] resource : {}", e.getMessage());
|
log.warn("[CustomApiException] resource : {}", e.getMessage());
|
||||||
|
|
||||||
String codeName = e.getCodeName();
|
String codeName = e.getCodeName();
|
||||||
HttpStatus status = e.getStatus();
|
HttpStatus status = e.getStatus();
|
||||||
String message = e.getMessage() == null ? ApiResponseCode.getMessage(codeName) : e.getMessage();
|
// String message = e.getMessage() == null ? ApiResponseCode.getMessage(codeName) :
|
||||||
|
// e.getMessage();
|
||||||
ApiResponseCode apiCode = ApiResponseCode.getCode(codeName);
|
//
|
||||||
|
// ApiResponseCode apiCode = ApiResponseCode.getCode(codeName);
|
||||||
|
//
|
||||||
|
// ErrorLogEntity errorLog =
|
||||||
|
// saveErrorLogData(
|
||||||
|
// request, apiCode, status, ErrorLogDto.LogErrorLevel.WARNING, e.getStackTrace());
|
||||||
|
//
|
||||||
|
// ApiResponseDto<String> body =
|
||||||
|
// ApiResponseDto.createException(apiCode, message, status, errorLog.getId());
|
||||||
|
|
||||||
ErrorLogEntity errorLog =
|
ErrorLogEntity errorLog =
|
||||||
saveErrorLogData(
|
saveErrorLogData(
|
||||||
request, apiCode, status, ErrorLogDto.LogErrorLevel.WARNING, e.getStackTrace());
|
request,
|
||||||
|
ApiResponseCode.getCode(codeName),
|
||||||
|
HttpStatus.valueOf(status.value()),
|
||||||
|
ErrorLogDto.LogErrorLevel.WARNING,
|
||||||
|
e.getStackTrace());
|
||||||
|
|
||||||
ApiResponseDto<String> body =
|
return ApiResponseDto.createException(
|
||||||
ApiResponseDto.createException(apiCode, message, status, errorLog.getId());
|
ApiResponseCode.getCode(codeName),
|
||||||
|
ApiResponseCode.getMessage(codeName),
|
||||||
|
HttpStatus.valueOf(status.value()),
|
||||||
|
errorLog.getId());
|
||||||
|
|
||||||
return new ResponseEntity<>(body, status);
|
// return new ResponseEntity<>(body, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,8 @@ public class SecurityConfig {
|
|||||||
// ADMIN, REVIEWER 접근
|
// ADMIN, REVIEWER 접근
|
||||||
.requestMatchers("/api/test/review")
|
.requestMatchers("/api/test/review")
|
||||||
.hasAnyRole("ADMIN", "REVIEWER")
|
.hasAnyRole("ADMIN", "REVIEWER")
|
||||||
|
.requestMatchers("/error")
|
||||||
|
.permitAll()
|
||||||
.requestMatchers(HttpMethod.OPTIONS, "/**")
|
.requestMatchers(HttpMethod.OPTIONS, "/**")
|
||||||
.permitAll() // preflight 허용
|
.permitAll() // preflight 허용
|
||||||
.requestMatchers(
|
.requestMatchers(
|
||||||
|
|||||||
@@ -14,14 +14,13 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
|||||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import java.util.List;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RequestPart;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
@@ -75,12 +74,9 @@ public class MapSheetMngFileCheckerApiController {
|
|||||||
@Operation(summary = "파일 업로드", description = "파일 업로드 및 TIF 검증")
|
@Operation(summary = "파일 업로드", description = "파일 업로드 및 TIF 검증")
|
||||||
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
public ApiResponseDto<String> uploadFile(
|
public ApiResponseDto<String> uploadFile(
|
||||||
@RequestParam("file") MultipartFile file,
|
@RequestPart("file") MultipartFile file,
|
||||||
@RequestParam("targetPath") String targetPath,
|
@RequestParam("targetPath") String targetPath) {
|
||||||
@RequestParam(name = "overwrite", required = false, defaultValue = "true")
|
return ApiResponseDto.createOK(mapSheetMngFileCheckerService.uploadFile(file, targetPath));
|
||||||
boolean overwrite) {
|
|
||||||
return ApiResponseDto.createOK(
|
|
||||||
mapSheetMngFileCheckerService.uploadFile(file, targetPath, overwrite));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "파일 삭제", description = "중복 파일 등 파일 삭제")
|
@Operation(summary = "파일 삭제", description = "중복 파일 등 파일 삭제")
|
||||||
@@ -130,8 +126,4 @@ public class MapSheetMngFileCheckerApiController {
|
|||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
@PostMapping("/upload-test")
|
|
||||||
public String uploadTest(@RequestParam("name") String name) {
|
|
||||||
return "RECV:" + name;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ 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.DeleteMapping;
|
|
||||||
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;
|
||||||
@@ -87,24 +86,4 @@ 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 = "201",
|
|
||||||
description = "관리자 계정 미사용 처리",
|
|
||||||
content =
|
|
||||||
@Content(
|
|
||||||
mediaType = "application/json",
|
|
||||||
schema = @Schema(implementation = UUID.class))),
|
|
||||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
|
|
||||||
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
|
|
||||||
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
|
|
||||||
})
|
|
||||||
@DeleteMapping("/delete/{uuid}")
|
|
||||||
public ApiResponseDto<UUID> deleteAccount(@PathVariable UUID uuid) {
|
|
||||||
adminService.deleteAccount(uuid);
|
|
||||||
return ApiResponseDto.createOK(uuid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ public class AuthController {
|
|||||||
MembersDto.Member member = new MembersDto.Member();
|
MembersDto.Member member = new MembersDto.Member();
|
||||||
|
|
||||||
// 비활성 상태면 임시패스워드를 비교함
|
// 비활성 상태면 임시패스워드를 비교함
|
||||||
if (StatusType.INACTIVE.getId().equals(status)) {
|
if (StatusType.PENDING.getId().equals(status)) {
|
||||||
if (!authService.isTempPasswordValid(request)) {
|
if (!authService.isTempPasswordValid(request)) {
|
||||||
throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_MISMATCH);
|
throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_MISMATCH);
|
||||||
}
|
}
|
||||||
@@ -124,8 +124,9 @@ public class AuthController {
|
|||||||
request.getUsername(), request.getPassword()));
|
request.getUsername(), request.getPassword()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// INACTIVE 비활성 상태(새로운 패스워드 입력 해야함), DELETED 탈퇴
|
// PENDING 비활성 상태(새로운 패스워드 입력 해야함)
|
||||||
if (!StatusType.ACTIVE.getId().equals(status)) {
|
if (StatusType.PENDING.getId().equals(status)) {
|
||||||
|
member.setEmployeeNo(request.getUsername());
|
||||||
return ApiResponseDto.ok(new TokenResponse(status, null, null, member));
|
return ApiResponseDto.ok(new TokenResponse(status, null, null, member));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import org.springdoc.core.annotations.ParameterObject;
|
import org.springdoc.core.annotations.ParameterObject;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PatchMapping;
|
import org.springframework.web.bind.annotation.PatchMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
@@ -70,10 +69,6 @@ public class MembersApiController {
|
|||||||
@PatchMapping("/{memberId}/password")
|
@PatchMapping("/{memberId}/password")
|
||||||
public ApiResponseDto<String> resetPassword(
|
public ApiResponseDto<String> resetPassword(
|
||||||
@PathVariable String memberId, @RequestBody @Valid MembersDto.InitReq initReq) {
|
@PathVariable String memberId, @RequestBody @Valid MembersDto.InitReq initReq) {
|
||||||
|
|
||||||
authenticationManager.authenticate(
|
|
||||||
new UsernamePasswordAuthenticationToken(memberId, initReq.getTempPassword()));
|
|
||||||
|
|
||||||
membersService.resetPassword(memberId, initReq);
|
membersService.resetPassword(memberId, initReq);
|
||||||
return ApiResponseDto.createOK(memberId);
|
return ApiResponseDto.createOK(memberId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,32 +108,26 @@ public class MembersDto {
|
|||||||
|
|
||||||
@Schema(description = "관리자 유형", example = "ADMIN")
|
@Schema(description = "관리자 유형", example = "ADMIN")
|
||||||
@NotBlank
|
@NotBlank
|
||||||
@EnumValid(enumClass = RoleType.class, message = "userRole은 ADMIN, LABELER, REVIEWER만 가능합니다.")
|
@EnumValid(enumClass = RoleType.class, message = "userRole은 ADMIN, LABELER, REVIEWER 만 가능합니다.")
|
||||||
private String userRole;
|
private String userRole;
|
||||||
|
|
||||||
|
@Schema(description = "사번", example = "K20251212001")
|
||||||
|
@Size(max = 50)
|
||||||
|
private String employeeNo;
|
||||||
|
|
||||||
@Schema(description = "이름", example = "홍길동")
|
@Schema(description = "이름", example = "홍길동")
|
||||||
@NotBlank
|
@NotBlank
|
||||||
@Size(min = 2, max = 100)
|
@Size(min = 2, max = 100)
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@Schema(description = "ID", example = "gildong")
|
|
||||||
@NotBlank
|
|
||||||
@Size(min = 2, max = 50)
|
|
||||||
private String userId;
|
|
||||||
|
|
||||||
@Schema(description = "임시 비밀번호", example = "q!w@e#r4")
|
@Schema(description = "임시 비밀번호", example = "q!w@e#r4")
|
||||||
private String tempPassword;
|
private String tempPassword;
|
||||||
|
|
||||||
@Schema(description = "사번", example = "123456")
|
public AddReq(String userRole, String employeeNo, String name, String tempPassword) {
|
||||||
private String employeeNo;
|
|
||||||
|
|
||||||
public AddReq(
|
|
||||||
String userRole, String name, String userId, String tempPassword, String employeeNo) {
|
|
||||||
this.userRole = userRole;
|
this.userRole = userRole;
|
||||||
this.name = name;
|
|
||||||
this.userId = userId;
|
|
||||||
this.tempPassword = tempPassword;
|
|
||||||
this.employeeNo = employeeNo;
|
this.employeeNo = employeeNo;
|
||||||
|
this.name = name;
|
||||||
|
this.tempPassword = tempPassword;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,10 +135,6 @@ public class MembersDto {
|
|||||||
@Setter
|
@Setter
|
||||||
public static class UpdateReq {
|
public static class UpdateReq {
|
||||||
|
|
||||||
@Schema(description = "사번, 패스워드 변경시 필수 값", example = "11111")
|
|
||||||
@Size(max = 50)
|
|
||||||
private String employeeNo;
|
|
||||||
|
|
||||||
@Schema(description = "이름", example = "홍길동")
|
@Schema(description = "이름", example = "홍길동")
|
||||||
@Size(min = 2, max = 100)
|
@Size(min = 2, max = 100)
|
||||||
private String name;
|
private String name;
|
||||||
@@ -157,8 +147,7 @@ public class MembersDto {
|
|||||||
@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 employeeNo, String name, String tempPassword, String status) {
|
public UpdateReq(String name, String tempPassword, String status) {
|
||||||
this.employeeNo = employeeNo;
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.tempPassword = tempPassword;
|
this.tempPassword = tempPassword;
|
||||||
this.status = status;
|
this.status = status;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ public class MemberException {
|
|||||||
|
|
||||||
public enum Field {
|
public enum Field {
|
||||||
USER_ID,
|
USER_ID,
|
||||||
|
EMPLOYEE_NO,
|
||||||
DEFAULT
|
DEFAULT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
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.utils.CommonStringUtils;
|
||||||
import com.kamco.cd.kamcoback.members.dto.MembersDto;
|
import com.kamco.cd.kamcoback.members.dto.MembersDto;
|
||||||
import com.kamco.cd.kamcoback.postgres.core.MembersCoreService;
|
import com.kamco.cd.kamcoback.postgres.core.MembersCoreService;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@@ -22,6 +26,10 @@ public class AdminService {
|
|||||||
*/
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
public Long saveMember(MembersDto.AddReq addReq) {
|
public Long saveMember(MembersDto.AddReq addReq) {
|
||||||
|
if (!CommonStringUtils.isValidPassword(addReq.getTempPassword())) {
|
||||||
|
throw new CustomApiException("WRONG_PASSWORD", HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
return membersCoreService.saveMembers(addReq);
|
return membersCoreService.saveMembers(addReq);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,16 +41,12 @@ public class AdminService {
|
|||||||
*/
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
public void updateMembers(UUID uuid, MembersDto.UpdateReq updateReq) {
|
public void updateMembers(UUID uuid, MembersDto.UpdateReq updateReq) {
|
||||||
membersCoreService.updateMembers(uuid, updateReq);
|
if (StatusType.INACTIVE.getId().equals(updateReq.getStatus())) {
|
||||||
}
|
// 미사용 처리
|
||||||
|
membersCoreService.deleteMember(uuid);
|
||||||
/**
|
} else {
|
||||||
* 관리자 계정 미사용 처리
|
// 수정
|
||||||
*
|
membersCoreService.updateMembers(uuid, updateReq);
|
||||||
* @param uuid
|
}
|
||||||
*/
|
|
||||||
@Transactional
|
|
||||||
public void deleteAccount(UUID uuid) {
|
|
||||||
membersCoreService.deleteAccount(uuid);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.kamco.cd.kamcoback.members.service;
|
package com.kamco.cd.kamcoback.members.service;
|
||||||
|
|
||||||
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.members.dto.MembersDto;
|
import com.kamco.cd.kamcoback.members.dto.MembersDto;
|
||||||
import com.kamco.cd.kamcoback.members.dto.MembersDto.Basic;
|
import com.kamco.cd.kamcoback.members.dto.MembersDto.Basic;
|
||||||
import com.kamco.cd.kamcoback.postgres.core.MembersCoreService;
|
import com.kamco.cd.kamcoback.postgres.core.MembersCoreService;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
@@ -37,21 +37,9 @@ public class MembersService {
|
|||||||
@Transactional
|
@Transactional
|
||||||
public void resetPassword(String id, MembersDto.InitReq initReq) {
|
public void resetPassword(String id, MembersDto.InitReq initReq) {
|
||||||
|
|
||||||
if (!isValidPassword(initReq.getPassword())) {
|
if (!CommonStringUtils.isValidPassword(initReq.getPassword())) {
|
||||||
throw new CustomApiException("WRONG_PASSWORD", HttpStatus.BAD_REQUEST);
|
throw new CustomApiException("WRONG_PASSWORD", HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
membersCoreService.resetPassword(id, initReq);
|
membersCoreService.resetPassword(id, initReq);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 영문, 숫자, 특수문자를 모두 포함하여 8~20자 이내의 비밀번호
|
|
||||||
*
|
|
||||||
* @param password
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private boolean isValidPassword(String password) {
|
|
||||||
String passwordPattern =
|
|
||||||
"^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-\\[\\]{};':\"\\\\|,.<>/?]).{8,20}$";
|
|
||||||
return Pattern.matches(passwordPattern, password);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ 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.zoo.dto.AnimalDto.SearchReq;
|
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;
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ package com.kamco.cd.kamcoback.postgres.core;
|
|||||||
|
|
||||||
import com.kamco.cd.kamcoback.auth.BCryptSaltGenerator;
|
import com.kamco.cd.kamcoback.auth.BCryptSaltGenerator;
|
||||||
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.common.utils.CommonStringUtils;
|
||||||
import com.kamco.cd.kamcoback.common.utils.UserUtil;
|
import com.kamco.cd.kamcoback.common.utils.UserUtil;
|
||||||
import com.kamco.cd.kamcoback.members.dto.MembersDto;
|
import com.kamco.cd.kamcoback.members.dto.MembersDto;
|
||||||
import com.kamco.cd.kamcoback.members.dto.MembersDto.AddReq;
|
import com.kamco.cd.kamcoback.members.dto.MembersDto.AddReq;
|
||||||
@@ -18,6 +21,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.mindrot.jbcrypt.BCrypt;
|
import org.mindrot.jbcrypt.BCrypt;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@@ -34,8 +38,8 @@ public class MembersCoreService {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Long saveMembers(AddReq addReq) {
|
public Long saveMembers(AddReq addReq) {
|
||||||
if (membersRepository.existsByUserId(addReq.getUserId())) {
|
if (membersRepository.existsByEmployeeNo(addReq.getEmployeeNo())) {
|
||||||
throw new DuplicateMemberException(Field.USER_ID, addReq.getUserId());
|
throw new DuplicateMemberException(Field.EMPLOYEE_NO, addReq.getEmployeeNo());
|
||||||
}
|
}
|
||||||
|
|
||||||
// salt 생성, 사번이 salt
|
// salt 생성, 사번이 salt
|
||||||
@@ -44,7 +48,7 @@ public class MembersCoreService {
|
|||||||
String hashedPassword = BCrypt.hashpw(addReq.getTempPassword(), salt);
|
String hashedPassword = BCrypt.hashpw(addReq.getTempPassword(), salt);
|
||||||
|
|
||||||
MemberEntity memberEntity = new MemberEntity();
|
MemberEntity memberEntity = new MemberEntity();
|
||||||
memberEntity.setUserId(addReq.getUserId());
|
memberEntity.setUserId(addReq.getEmployeeNo());
|
||||||
memberEntity.setUserRole(addReq.getUserRole());
|
memberEntity.setUserRole(addReq.getUserRole());
|
||||||
memberEntity.setTempPassword(addReq.getTempPassword().trim()); // 임시 패스워드는 암호화 하지 않음
|
memberEntity.setTempPassword(addReq.getTempPassword().trim()); // 임시 패스워드는 암호화 하지 않음
|
||||||
memberEntity.setPassword(hashedPassword);
|
memberEntity.setPassword(hashedPassword);
|
||||||
@@ -71,41 +75,35 @@ public class MembersCoreService {
|
|||||||
|
|
||||||
// 임시 패스워드는 암호화 하지 않음
|
// 임시 패스워드는 암호화 하지 않음
|
||||||
if (StringUtils.isNotBlank(updateReq.getTempPassword())) {
|
if (StringUtils.isNotBlank(updateReq.getTempPassword())) {
|
||||||
// 임시 패스워드가 기존과 다르면 패스워드 변경으로 처리함
|
/**
|
||||||
// 상태 INACTIVE로 변경하여 사용자가 로그인할때 패스워드 변경하게함
|
* 임시 패스워드가 기존과 다르면 패스워드 변경으로 처리함 상태 PENDING 으로 변경하여 사용자가 로그인할때 패스워드 변경하게함 패스워드 리셋이므로 로그인
|
||||||
// 패스워드 리셋이므로 로그인 실패카운트 초기화처리함
|
* 실패카운트 초기화처리함
|
||||||
|
*/
|
||||||
if (!memberEntity.getTempPassword().equals(updateReq.getTempPassword().trim())) {
|
if (!memberEntity.getTempPassword().equals(updateReq.getTempPassword().trim())) {
|
||||||
memberEntity.setStatus(StatusType.INACTIVE.getId());
|
// 패스워드 유효성 검사
|
||||||
|
if (!CommonStringUtils.isValidPassword(updateReq.getTempPassword())) {
|
||||||
|
throw new CustomApiException("WRONG_PASSWORD", HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
memberEntity.setStatus(StatusType.PENDING.getId());
|
||||||
memberEntity.setLoginFailCount(0);
|
memberEntity.setLoginFailCount(0);
|
||||||
}
|
}
|
||||||
memberEntity.setTempPassword(updateReq.getTempPassword().trim());
|
memberEntity.setTempPassword(updateReq.getTempPassword().trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(updateReq.getEmployeeNo())) {
|
|
||||||
memberEntity.setEmployeeNo(updateReq.getEmployeeNo());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(updateReq.getStatus())) {
|
|
||||||
memberEntity.setStatus(updateReq.getStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
memberEntity.setUpdtrUid(userUtil.getId());
|
memberEntity.setUpdtrUid(userUtil.getId());
|
||||||
|
|
||||||
membersRepository.save(memberEntity);
|
membersRepository.save(memberEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 관리자 계정 삭제 처리
|
* 미사용 처리
|
||||||
*
|
*
|
||||||
* @param uuid
|
* @param uuid
|
||||||
*/
|
*/
|
||||||
public void deleteAccount(UUID uuid) {
|
public void deleteMember(UUID uuid) {
|
||||||
MemberEntity memberEntity =
|
MemberEntity memberEntity =
|
||||||
membersRepository.findByUUID(uuid).orElseThrow(() -> new MemberNotFoundException());
|
membersRepository.findByUUID(uuid).orElseThrow(MemberNotFoundException::new);
|
||||||
|
memberEntity.setStatus(StatusType.INACTIVE.getId());
|
||||||
memberEntity.setStatus(StatusType.DELETED.getId());
|
|
||||||
memberEntity.setUpdatedDttm(ZonedDateTime.now());
|
|
||||||
memberEntity.setUpdtrUid(userUtil.getId());
|
|
||||||
membersRepository.save(memberEntity);
|
membersRepository.save(memberEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +114,12 @@ public class MembersCoreService {
|
|||||||
*/
|
*/
|
||||||
public void resetPassword(String id, MembersDto.InitReq initReq) {
|
public void resetPassword(String id, MembersDto.InitReq initReq) {
|
||||||
MemberEntity memberEntity =
|
MemberEntity memberEntity =
|
||||||
membersRepository.findByUserId(id).orElseThrow(() -> new MemberNotFoundException());
|
membersRepository.findByEmployeeNo(id).orElseThrow(() -> new MemberNotFoundException());
|
||||||
|
|
||||||
|
// 임시 패스워드 확인
|
||||||
|
if (!memberEntity.getTempPassword().equals(initReq.getTempPassword())) {
|
||||||
|
throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_MISMATCH);
|
||||||
|
}
|
||||||
|
|
||||||
String salt =
|
String salt =
|
||||||
BCryptSaltGenerator.generateSaltWithEmployeeNo(memberEntity.getEmployeeNo().trim());
|
BCryptSaltGenerator.generateSaltWithEmployeeNo(memberEntity.getEmployeeNo().trim());
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ public class MemberEntity {
|
|||||||
@Size(max = 20)
|
@Size(max = 20)
|
||||||
@ColumnDefault("'INACTIVE'")
|
@ColumnDefault("'INACTIVE'")
|
||||||
@Column(name = "status", length = 20)
|
@Column(name = "status", length = 20)
|
||||||
private String status = StatusType.INACTIVE.getId();
|
private String status = StatusType.PENDING.getId();
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@ColumnDefault("now()")
|
@ColumnDefault("now()")
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ public interface MembersRepositoryCustom {
|
|||||||
|
|
||||||
boolean existsByUserId(String userId);
|
boolean existsByUserId(String userId);
|
||||||
|
|
||||||
|
boolean existsByEmployeeNo(String employeeNo);
|
||||||
|
|
||||||
|
Optional<MemberEntity> findByEmployeeNo(String employeeNo);
|
||||||
|
|
||||||
Optional<MemberEntity> findByUserId(String userId);
|
Optional<MemberEntity> findByUserId(String userId);
|
||||||
|
|
||||||
Optional<MemberEntity> findByUUID(UUID uuid);
|
Optional<MemberEntity> findByUUID(UUID uuid);
|
||||||
|
|||||||
@@ -40,6 +40,22 @@ public class MembersRepositoryImpl implements MembersRepositoryCustom {
|
|||||||
!= null;
|
!= null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 사용자 사번 조회
|
||||||
|
*
|
||||||
|
* @param employeeNo
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean existsByEmployeeNo(String employeeNo) {
|
||||||
|
return queryFactory
|
||||||
|
.selectOne()
|
||||||
|
.from(memberEntity)
|
||||||
|
.where(memberEntity.employeeNo.eq(employeeNo))
|
||||||
|
.fetchFirst()
|
||||||
|
!= null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 사용자 조회 user id
|
* 사용자 조회 user id
|
||||||
*
|
*
|
||||||
@@ -52,6 +68,21 @@ public class MembersRepositoryImpl implements MembersRepositoryCustom {
|
|||||||
queryFactory.selectFrom(memberEntity).where(memberEntity.userId.eq(userId)).fetchOne());
|
queryFactory.selectFrom(memberEntity).where(memberEntity.userId.eq(userId)).fetchOne());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 사용자 조회 employeed no
|
||||||
|
*
|
||||||
|
* @param employeeNo
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Optional<MemberEntity> findByEmployeeNo(String employeeNo) {
|
||||||
|
return Optional.ofNullable(
|
||||||
|
queryFactory
|
||||||
|
.selectFrom(memberEntity)
|
||||||
|
.where(memberEntity.employeeNo.eq(employeeNo))
|
||||||
|
.fetchOne());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 회원정보 목록 조회
|
* 회원정보 목록 조회
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -29,17 +29,6 @@ spring:
|
|||||||
port: 6379
|
port: 6379
|
||||||
password: 1234
|
password: 1234
|
||||||
|
|
||||||
servlet:
|
|
||||||
multipart:
|
|
||||||
enabled: true
|
|
||||||
max-file-size: 1024MB
|
|
||||||
max-request-size: 2048MB
|
|
||||||
file-size-threshold: 10MB
|
|
||||||
|
|
||||||
server:
|
|
||||||
tomcat:
|
|
||||||
max-swallow-size: 2097152000 # 약 2GB
|
|
||||||
|
|
||||||
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일
|
||||||
@@ -49,13 +38,4 @@ token:
|
|||||||
refresh-cookie-name: kamco-local # 개발용 쿠키 이름
|
refresh-cookie-name: kamco-local # 개발용 쿠키 이름
|
||||||
refresh-cookie-secure: false # 로컬 http 테스트면 false
|
refresh-cookie-secure: false # 로컬 http 테스트면 false
|
||||||
|
|
||||||
logging:
|
|
||||||
level:
|
|
||||||
org:
|
|
||||||
springframework:
|
|
||||||
security: DEBUG
|
|
||||||
org.springframework.security: DEBUG
|
|
||||||
|
|
||||||
mapsheet:
|
|
||||||
upload:
|
|
||||||
skipGdalValidation: true
|
|
||||||
|
|||||||
Reference in New Issue
Block a user