diff --git a/AGENTS.md b/AGENTS.md index 4c2e832..d515ca5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,6 +9,7 @@ - 소스코드 변경 요청에서는 바로 구현하지 말고 `코드로 보여주기` 또는 `직접 작성하기` 중 원하는 방식을 먼저 확인한다. - Controller 는 요청/응답 조립과 인증 주체 확인에 집중하고, 복잡한 로직과 DB 처리는 Service 로 넘긴다. - 응답은 `ApiResponse` 와 `ApiResponseCode` 조합을 우선 사용한다. +- 신규/수정되는 Controller, Form, VO에는 Swagger 테스트 편의성을 위해 `@Tag`, `@Operation`, `@Schema` 설명과 예시를 남긴다. - 변경 후에는 가능하면 테스트 또는 최소 실행 검증 결과를 남기고, 미실행 항목은 사유를 분명히 적는다. ## 문서 인덱스 diff --git a/docs/code-conventions.md b/docs/code-conventions.md index cc6a826..bf9569e 100644 --- a/docs/code-conventions.md +++ b/docs/code-conventions.md @@ -20,6 +20,23 @@ - 외부 응답에 노출되면 안 되는 내부 필드는 응답에 사용될 수 있는 객체에서 `@JsonIgnore`로 숨긴다. - Form 에서 DTO 로 변환할 때는 검증과 `trim()`, 기본값 치환까지 같이 처리하는 현재 패턴을 우선 따른다. +## Swagger/OpenAPI 문서화 규칙 +- 신규 또는 수정되는 Controller, Form, VO에는 Swagger 테스트 편의성을 위한 설명을 반드시 남긴다. +- Controller 클래스에는 `@Tag`를 사용해 API 그룹명과 설명을 작성한다. +- Controller 메서드에는 `@Operation`으로 `summary`와 `description`을 작성한다. +- `@RequestBody` Form 클래스에는 클래스 레벨 `@Schema(description = "...")`를 작성한다. +- `@ModelAttribute` 검색 Form 필드에도 `@Schema`를 작성해 Swagger query parameter 설명과 예시가 보이게 한다. +- Form 필드에는 `@Schema`로 `description`, `example`을 작성한다. +- 필수 입력값은 Jakarta Validation 어노테이션과 `@Schema(requiredMode = Schema.RequiredMode.REQUIRED)`를 함께 사용한다. +- 코드값 필드는 허용 값을 `description`에 명시한다. 예: `userType: A 관리자, T 교사, S 학생`, `withdrawStatus: N 정상, P 탈퇴대기, Y 탈퇴완료`. +- VO 클래스에는 클래스 레벨 `@Schema(description = "...")`를 작성한다. +- VO 필드에는 `@Schema`로 응답 값의 의미를 작성한다. +- 토큰, 임시 비밀번호처럼 Swagger 테스트에 필요한 응답 필드는 VO에 명시하되 `description`에 용도를 적는다. +- 비밀번호, DB 조회용 내부 식별자, `resultCode`처럼 외부 응답에 노출하지 않는 필드는 `@JsonIgnore`를 사용하고 필요하면 `@Schema(hidden = true)`도 함께 사용한다. +- 클라이언트가 직접 전달하지 않는 내부 계산 필드나 서버 전용 getter는 `@Schema(hidden = true)`로 숨긴다. +- 페이징 요청에서 클라이언트는 `page`, `size`만 전달하고, `limit`, `offset`은 Swagger에 노출하지 않는다. +- 페이징 응답의 `rowStartNum`처럼 계산 방식이 필요한 값은 프론트 사용 방법까지 `description`에 남긴다. + ## Mapper/MyBatis 규칙 - Mapper 메서드명은 SQL 동작이 드러나도록 `select`, `insert`, `update` 접두어를 사용한다. - 삭제가 물리 삭제가 아니라 상태 변경이면 `delete` 대신 목적이 드러나는 `update...Canceled`, `update...DelYn` 같은 이름을 우선한다. diff --git a/src/main/java/com/alist/api/common/paging/PageRequest.java b/src/main/java/com/alist/api/common/paging/PageRequest.java new file mode 100644 index 0000000..741a483 --- /dev/null +++ b/src/main/java/com/alist/api/common/paging/PageRequest.java @@ -0,0 +1,32 @@ +package com.alist.api.common.paging; + +import com.alist.api.common.utils.PagingUtil; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Setter; + +@Setter +public class PageRequest { + @Schema(description = "페이지 번호", example = "1") + private Integer page; + + @Schema(description = "페이지 크기", example = "20") + private Integer size; + + public Integer getPage() { + return PagingUtil.getPage(page); + } + + public Integer getSize() { + return PagingUtil.getSize(size); + } + + @Schema(hidden = true) + public Integer getLimit() { + return PagingUtil.getLimit(size); + } + + @Schema(hidden = true) + public Integer getOffset() { + return PagingUtil.getOffset(page, size); + } +} diff --git a/src/main/java/com/alist/api/common/paging/PageResponse.java b/src/main/java/com/alist/api/common/paging/PageResponse.java new file mode 100644 index 0000000..7ad2496 --- /dev/null +++ b/src/main/java/com/alist/api/common/paging/PageResponse.java @@ -0,0 +1,36 @@ +package com.alist.api.common.paging; + +import com.alist.api.common.utils.PagingUtil; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class PageResponse { + @Schema(description = "현재 페이지 번호", example = "1") + private int page; + + @Schema(description = "페이지당 조회 개수", example = "20") + private int size; + + @Schema(description = "전체 데이터 개수", example = "100") + private int totalCount; + + @Schema(description = "전체 페이지 수", example = "5") + private int totalPage; + + @Schema( + description = "현재 페이지 첫 번째 row 번호. 각 row 번호는 rowStartNum - memberList index로 계산합니다.", + example = "100" + ) + private int rowStartNum; + + public void setPaging(PageRequest pageRequest, int totalCount) { + this.page = pageRequest.getPage(); + this.size = pageRequest.getSize(); + this.totalCount = totalCount; + this.totalPage = PagingUtil.getTotalPage(totalCount, pageRequest.getSize()); + this.rowStartNum = PagingUtil.getRowStartNum(totalCount, pageRequest.getPage(), pageRequest.getSize()); + } +} diff --git a/src/main/java/com/alist/api/common/utils/PagingUtil.java b/src/main/java/com/alist/api/common/utils/PagingUtil.java new file mode 100644 index 0000000..ba43525 --- /dev/null +++ b/src/main/java/com/alist/api/common/utils/PagingUtil.java @@ -0,0 +1,44 @@ +package com.alist.api.common.utils; + +public final class PagingUtil { + private static final int DEFAULT_PAGE = 1; + private static final int DEFAULT_SIZE = 10; + private static final int MAX_SIZE = 100; + + private PagingUtil() { + } + + public static int getPage(Integer page) { + return page == null || page < 1 ? DEFAULT_PAGE : page; + } + + public static int getSize(Integer size) { + if (size == null || size < 1) { + return DEFAULT_SIZE; + } + return Math.min(size, MAX_SIZE); + } + + public static int getLimit(Integer size) { + return getSize(size); + } + + public static int getOffset(Integer page, Integer size) { + return (getPage(page) - 1) * getSize(size); + } + + public static int getTotalPage(int totalCount, Integer size) { + return totalCount <= 0 ? 0 : (int) Math.ceil((double) totalCount / getSize(size)); + } + + public static int getRowStartNum(int totalCount, Integer page, Integer size) { + if (totalCount <= 0) { + return 0; + } + + int offset = getOffset(page, size); + int rowStartNum = totalCount - offset; + + return Math.max(rowStartNum, 0); + } +} diff --git a/src/main/java/com/alist/api/modules/admin/auth/AdminAuthController.java b/src/main/java/com/alist/api/modules/admin/auth/AdminAuthController.java index 53047f4..101be09 100644 --- a/src/main/java/com/alist/api/modules/admin/auth/AdminAuthController.java +++ b/src/main/java/com/alist/api/modules/admin/auth/AdminAuthController.java @@ -4,8 +4,10 @@ import com.alist.api.common.response.ApiResponse; import com.alist.api.common.response.ApiResponseCode; import com.alist.api.common.utils.SecurityUtil; import com.alist.api.common.utils.SessionUtil; +import com.alist.api.modules.admin.auth.form.AdminApiKeyLoginForm; import com.alist.api.modules.admin.auth.form.AdminLoginForm; import com.alist.api.modules.admin.auth.service.AdminAuthService; +import com.alist.api.modules.admin.auth.vo.AdminApiKeyLoginVo; import com.alist.api.modules.admin.auth.vo.AdminLoginVo; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -50,6 +52,23 @@ public class AdminAuthController { return ApiResponse.entity(result, ApiResponseCode.CODE_2001, "관리자 로그인"); } + @Operation( + summary = "admin API Key 로그인", + description = "Admin API Key로 인증하고 JSON으로 토큰을 반환합니다. Swagger 테스트용입니다." + ) + @PostMapping("/apiKeyLogin") + public ResponseEntity> adminApiKeyLogin( + @Valid @RequestBody AdminApiKeyLoginForm adminApiKeyLoginForm + ) { + AdminApiKeyLoginVo result = adminAuthService.adminApiKeyLogin(adminApiKeyLoginForm.toAdminApiKeyLoginDto()); + + if (result.getResultCode() == 2003) { + return ApiResponse.entity(result, ApiResponseCode.CODE_2003); + } + + return ApiResponse.entity(result, ApiResponseCode.CODE_2001, "관리자 엑세스 토큰"); + } + @Operation( summary = "admin 리프레시토큰 발급" , description = "엑세스 토큰 만료시 리프레시 토큰 발급 용도 api 입니다." diff --git a/src/main/java/com/alist/api/modules/admin/auth/dto/AdminApiKeyLoginDto.java b/src/main/java/com/alist/api/modules/admin/auth/dto/AdminApiKeyLoginDto.java new file mode 100644 index 0000000..a456d72 --- /dev/null +++ b/src/main/java/com/alist/api/modules/admin/auth/dto/AdminApiKeyLoginDto.java @@ -0,0 +1,16 @@ +package com.alist.api.modules.admin.auth.dto; + +import lombok.Getter; +import lombok.Setter; + +import java.time.Instant; + +@Getter +@Setter +public class AdminApiKeyLoginDto { + private String userApiKey; + private Integer userIdx; + private Integer userTokenIdx; + private String refreshToken; + private Instant expiresAt; +} diff --git a/src/main/java/com/alist/api/modules/admin/auth/form/AdminApiKeyLoginForm.java b/src/main/java/com/alist/api/modules/admin/auth/form/AdminApiKeyLoginForm.java new file mode 100644 index 0000000..15637a5 --- /dev/null +++ b/src/main/java/com/alist/api/modules/admin/auth/form/AdminApiKeyLoginForm.java @@ -0,0 +1,26 @@ +package com.alist.api.modules.admin.auth.form; + +import com.alist.api.modules.admin.auth.dto.AdminApiKeyLoginDto; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Getter; +import lombok.Setter; + +@Schema(description = "Admin API Key 로그인 요청 폼") +@Getter +@Setter +public class AdminApiKeyLoginForm { + @Schema( + description = "Admin API Key", + example = "ypdz9hl7WAp2D03HC5h9koEC49R6LAkLSuoSdgEwVQA", + requiredMode = Schema.RequiredMode.REQUIRED + ) + @NotBlank(message = "apiKey를 입력해주세요.") + private String userApiKey; + + public AdminApiKeyLoginDto toAdminApiKeyLoginDto() { + AdminApiKeyLoginDto adminApiKeyLoginDto = new AdminApiKeyLoginDto(); + adminApiKeyLoginDto.setUserApiKey(userApiKey.trim()); + return adminApiKeyLoginDto; + } +} diff --git a/src/main/java/com/alist/api/modules/admin/auth/form/AdminLoginForm.java b/src/main/java/com/alist/api/modules/admin/auth/form/AdminLoginForm.java index de99e3f..8d513bf 100644 --- a/src/main/java/com/alist/api/modules/admin/auth/form/AdminLoginForm.java +++ b/src/main/java/com/alist/api/modules/admin/auth/form/AdminLoginForm.java @@ -1,17 +1,29 @@ package com.alist.api.modules.admin.auth.form; import com.alist.api.modules.admin.auth.dto.AdminLoginDto; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; +@Schema(description = "Admin 로그인 요청 폼") @Getter @Setter public class AdminLoginForm { - @NotBlank + @Schema( + description = "관리자 아이디", + example = "admin", + requiredMode = Schema.RequiredMode.REQUIRED + ) + @NotBlank(message = "아이디는 필수입니다.") private String id; - @NotBlank + @Schema( + description = "관리자 비밀번호", + example = "password", + requiredMode = Schema.RequiredMode.REQUIRED + ) + @NotBlank(message = "비밀번호는 필수입니다.") private String password; public AdminLoginDto toAdminLoginDto() { diff --git a/src/main/java/com/alist/api/modules/admin/auth/mapper/AdminAuthMapper.java b/src/main/java/com/alist/api/modules/admin/auth/mapper/AdminAuthMapper.java index 7797e98..84d5450 100644 --- a/src/main/java/com/alist/api/modules/admin/auth/mapper/AdminAuthMapper.java +++ b/src/main/java/com/alist/api/modules/admin/auth/mapper/AdminAuthMapper.java @@ -1,6 +1,8 @@ package com.alist.api.modules.admin.auth.mapper; +import com.alist.api.modules.admin.auth.dto.AdminApiKeyLoginDto; import com.alist.api.modules.admin.auth.dto.AdminLoginDto; +import com.alist.api.modules.admin.auth.vo.AdminApiKeyLoginVo; import com.alist.api.modules.admin.auth.vo.AdminLoginVo; import org.apache.ibatis.annotations.Mapper; @@ -15,4 +17,8 @@ public interface AdminAuthMapper { AdminLoginVo selectAdminTokenByUserTokenIdx(Integer userTokenIdx); void clearAdminRefreshToken(Integer userTokenIdx); + + AdminApiKeyLoginVo selectAdminApiKeyLogin(AdminApiKeyLoginDto adminApiKeyLoginDto); + + void updateAdminApiKeyLoginRefreshToken(AdminApiKeyLoginDto adminApiKeyLoginDto); } diff --git a/src/main/java/com/alist/api/modules/admin/auth/service/AdminAuthService.java b/src/main/java/com/alist/api/modules/admin/auth/service/AdminAuthService.java index 843facf..b04ff14 100644 --- a/src/main/java/com/alist/api/modules/admin/auth/service/AdminAuthService.java +++ b/src/main/java/com/alist/api/modules/admin/auth/service/AdminAuthService.java @@ -2,8 +2,10 @@ package com.alist.api.modules.admin.auth.service; import com.alist.api.common.utils.SessionUtil; import com.alist.api.config.jwt.JwtTokenProvider; +import com.alist.api.modules.admin.auth.dto.AdminApiKeyLoginDto; import com.alist.api.modules.admin.auth.dto.AdminLoginDto; import com.alist.api.modules.admin.auth.mapper.AdminAuthMapper; +import com.alist.api.modules.admin.auth.vo.AdminApiKeyLoginVo; import com.alist.api.modules.admin.auth.vo.AdminLoginVo; import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Value; @@ -158,4 +160,33 @@ public class AdminAuthService { return adminAuthMapper.selectAdminTokenByUserTokenIdx(userTokenIdx); } + + @Transactional + public AdminApiKeyLoginVo adminApiKeyLogin(AdminApiKeyLoginDto adminApiKeyLoginDto) { + AdminApiKeyLoginVo result = adminAuthMapper.selectAdminApiKeyLogin(adminApiKeyLoginDto); + + if (result == null) { + AdminApiKeyLoginVo empty = new AdminApiKeyLoginVo(); + empty.setResultCode(2003); + empty.setLogin(false); + return empty; + } + + String accessToken = jwtTokenProvider.createAdminAccessToken(result.getUserTokenIdx()); + String refreshToken = jwtTokenProvider.createAdminRefreshToken(result.getUserTokenIdx()); + + adminApiKeyLoginDto.setUserTokenIdx(result.getUserTokenIdx()); + adminApiKeyLoginDto.setRefreshToken(refreshToken); + adminApiKeyLoginDto.setExpiresAt(Instant.now().plusSeconds(refreshTokenValiditySeconds)); + + adminAuthMapper.updateAdminApiKeyLoginRefreshToken(adminApiKeyLoginDto); + adminAuthMapper.updateAdminLastLoginAt(result.getUserIdx()); + + result.setAccessToken(accessToken); + result.setRefreshToken(refreshToken); + result.setResultCode(2001); + result.setLogin(true); + + return result; + } } diff --git a/src/main/java/com/alist/api/modules/admin/auth/vo/AdminApiKeyLoginVo.java b/src/main/java/com/alist/api/modules/admin/auth/vo/AdminApiKeyLoginVo.java new file mode 100644 index 0000000..6482e3f --- /dev/null +++ b/src/main/java/com/alist/api/modules/admin/auth/vo/AdminApiKeyLoginVo.java @@ -0,0 +1,40 @@ +package com.alist.api.modules.admin.auth.vo; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +@Schema(description = "Admin API Key 로그인 응답") +@Getter +@Setter +public class AdminApiKeyLoginVo { + @Schema(description = "로그인 성공 여부", example = "true") + private boolean login; + + @Schema(description = "회원 PK", example = "14") + private Integer userIdx; + + @Schema(description = "관리자 아이디", example = "admin") + private String id; + + @Schema(description = "관리자 권한 코드", example = "A") + private String userRole; + + @Schema(description = "회원 유형 코드. A: 관리자", example = "A") + private String userType; + + @Schema(description = "관리자 API 테스트용 Access Token") + private String accessToken; + + @Schema(description = "관리자 API 테스트용 Refresh Token") + private String refreshToken; + + @JsonIgnore + @Schema(hidden = true) + private Integer userTokenIdx; + + @JsonIgnore + @Schema(hidden = true) + private int resultCode; +} diff --git a/src/main/java/com/alist/api/modules/admin/auth/vo/AdminLoginVo.java b/src/main/java/com/alist/api/modules/admin/auth/vo/AdminLoginVo.java index 732464c..b1270b6 100644 --- a/src/main/java/com/alist/api/modules/admin/auth/vo/AdminLoginVo.java +++ b/src/main/java/com/alist/api/modules/admin/auth/vo/AdminLoginVo.java @@ -1,27 +1,42 @@ package com.alist.api.modules.admin.auth.vo; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +@Schema(description = "Admin 로그인 응답") @Setter @Getter public class AdminLoginVo { + @Schema(description = "로그인 성공 여부", example = "true") private boolean isLogin; + + @Schema(description = "회원 PK", example = "14") private Integer userIdx; + + @Schema(description = "관리자 아이디", example = "admin") private String id; + + @Schema(description = "관리자 권한 코드", example = "A") private String userRole; + + @Schema(description = "회원 유형 코드. A: 관리자", example = "A") private String userType; @JsonIgnore + @Schema(hidden = true) private String password; @JsonIgnore + @Schema(hidden = true) private Integer userTokenIdx; @JsonIgnore + @Schema(hidden = true) private String refreshToken; @JsonIgnore + @Schema(hidden = true) private int resultCode; } diff --git a/src/main/java/com/alist/api/modules/admin/member/AdminMemberController.java b/src/main/java/com/alist/api/modules/admin/member/AdminMemberController.java new file mode 100644 index 0000000..766e136 --- /dev/null +++ b/src/main/java/com/alist/api/modules/admin/member/AdminMemberController.java @@ -0,0 +1,79 @@ +package com.alist.api.modules.admin.member; + +import com.alist.api.common.response.ApiResponse; +import com.alist.api.common.response.ApiResponseCode; +import com.alist.api.modules.admin.member.form.AdminMemberSearchForm; +import com.alist.api.modules.admin.member.form.AdminMemberUpdateForm; +import com.alist.api.modules.admin.member.service.AdminMemberService; +import com.alist.api.modules.admin.member.vo.AdminMemberDetailVo; +import com.alist.api.modules.admin.member.vo.AdminMemberListVo; +import com.alist.api.modules.admin.member.vo.AdminMemberUpdateVo; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@Tag(name = "51. 회원 관리", description = "관리자 회원 관리 API") +@Slf4j +@RestController +@RequestMapping("/admin/member") +public class AdminMemberController { + private final AdminMemberService adminMemberService; + + public AdminMemberController(AdminMemberService adminMemberService) { + this.adminMemberService = adminMemberService; + } + + @Operation( + summary = "회원 목록 조회", + description = "관리자가 회원 목록을 검색 조건과 페이징으로 조회합니다." + ) + @GetMapping("/list") + public ResponseEntity> adminMemberList( + @ModelAttribute AdminMemberSearchForm adminMemberSearchForm + ) { + AdminMemberListVo result = adminMemberService.selectAdminMemberList(adminMemberSearchForm.toAdminMemberSearchDto()); + + if (result.getMemberList() == null || result.getMemberList().isEmpty()) { + return ApiResponse.entity(result, ApiResponseCode.CODE_2003); + } + + return ApiResponse.entity(result, ApiResponseCode.CODE_2001, "회원"); + } + + @Operation( + summary = "회원 상세 조회", + description = "관리자가 회원 PK 기준으로 회원 상세 정보를 조회합니다." + ) + @GetMapping("/detail") + public ResponseEntity> adminMemberDetail( + @RequestParam Integer userIdx + ) { + AdminMemberDetailVo result = adminMemberService.selectAdminMemberDetail(userIdx); + + if (result == null) { + return ApiResponse.entity((AdminMemberDetailVo) null, ApiResponseCode.CODE_2003); + } + + return ApiResponse.entity(result, ApiResponseCode.CODE_2001, "회원"); + } + + @Operation( + summary = "회원 정보 수정", + description = "관리자가 회원 PK 기준으로 회원 기본 정보와 권한 정보를 수정합니다." + ) + @PutMapping("/update") + public ResponseEntity> adminMemberUpdate( + @Valid @RequestBody AdminMemberUpdateForm adminMemberUpdateForm + ) { + AdminMemberUpdateVo result = adminMemberService.updateAdminMember(adminMemberUpdateForm.toAdminMemberUpdateDto()); + + if (!result.isMemberUpdated()) { + return ApiResponse.entity(result, ApiResponseCode.CODE_2003); + } + + return ApiResponse.entity(result, ApiResponseCode.CODE_2005, "회원 수정"); + } +} diff --git a/src/main/java/com/alist/api/modules/admin/member/dto/AdminMemberSearchDto.java b/src/main/java/com/alist/api/modules/admin/member/dto/AdminMemberSearchDto.java new file mode 100644 index 0000000..6594b79 --- /dev/null +++ b/src/main/java/com/alist/api/modules/admin/member/dto/AdminMemberSearchDto.java @@ -0,0 +1,15 @@ +package com.alist.api.modules.admin.member.dto; + +import com.alist.api.common.paging.PageRequest; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class AdminMemberSearchDto extends PageRequest { + private String keyword; + private String userRole; + private String userType; + private String dormantYn; + private String withdrawStatus; +} diff --git a/src/main/java/com/alist/api/modules/admin/member/dto/AdminMemberUpdateDto.java b/src/main/java/com/alist/api/modules/admin/member/dto/AdminMemberUpdateDto.java new file mode 100644 index 0000000..dcbb67d --- /dev/null +++ b/src/main/java/com/alist/api/modules/admin/member/dto/AdminMemberUpdateDto.java @@ -0,0 +1,14 @@ +package com.alist.api.modules.admin.member.dto; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class AdminMemberUpdateDto { + private Integer userIdx; + private String email; + private String hp; + private String userRole; + private String userType; +} diff --git a/src/main/java/com/alist/api/modules/admin/member/form/AdminMemberSearchForm.java b/src/main/java/com/alist/api/modules/admin/member/form/AdminMemberSearchForm.java new file mode 100644 index 0000000..279057d --- /dev/null +++ b/src/main/java/com/alist/api/modules/admin/member/form/AdminMemberSearchForm.java @@ -0,0 +1,39 @@ +package com.alist.api.modules.admin.member.form; + +import com.alist.api.common.paging.PageRequest; +import com.alist.api.modules.admin.member.dto.AdminMemberSearchDto; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +@Schema(description = "관리자 회원 목록 검색 조건") +@Getter +@Setter +public class AdminMemberSearchForm extends PageRequest { + @Schema(description = "검색어. 아이디, 이메일, 휴대폰 번호를 대상으로 검색합니다.", example = "admin") + private String keyword; + + @Schema(description = "회원 권한 코드(CCD/SCM/I/R/E)", example = "SCM") + private String userRole; + + @Schema(description = "회원 유형 코드. A: 관리자, T: 교사, S: 학생", example = "T") + private String userType; + + @Schema(description = "휴면 여부. N: 정상, Y: 휴면", example = "N") + private String dormantYn; + + @Schema(description = "탈퇴 상태. N: 정상, P: 탈퇴대기, Y: 탈퇴완료", example = "N") + private String withdrawStatus; + + public AdminMemberSearchDto toAdminMemberSearchDto() { + AdminMemberSearchDto adminMemberSearchDto = new AdminMemberSearchDto(); + adminMemberSearchDto.setPage(getPage()); + adminMemberSearchDto.setSize(getSize()); + adminMemberSearchDto.setKeyword(keyword); + adminMemberSearchDto.setUserRole(userRole); + adminMemberSearchDto.setUserType(userType); + adminMemberSearchDto.setDormantYn(dormantYn); + adminMemberSearchDto.setWithdrawStatus(withdrawStatus); + return adminMemberSearchDto; + } +} diff --git a/src/main/java/com/alist/api/modules/admin/member/form/AdminMemberUpdateForm.java b/src/main/java/com/alist/api/modules/admin/member/form/AdminMemberUpdateForm.java new file mode 100644 index 0000000..dbc338b --- /dev/null +++ b/src/main/java/com/alist/api/modules/admin/member/form/AdminMemberUpdateForm.java @@ -0,0 +1,40 @@ +package com.alist.api.modules.admin.member.form; + +import com.alist.api.modules.admin.member.dto.AdminMemberUpdateDto; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; + +@Schema(description = "관리자 회원 수정 요청 폼") +@Getter +@Setter +public class AdminMemberUpdateForm { + @Schema(description = "회원 PK", example = "15", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "회원 PK는 필수입니다.") + private Integer userIdx; + + @Schema(description = "이메일", example = "user@example.com") + @Email(message = "이메일 형식을 확인해주세요.") + private String email; + + @Schema(description = "휴대폰 번호", example = "01012345678") + private String hp; + + @Schema(description = "회원 권한 코드(CCD/SCM/I/R/E)", example = "CCM") + private String userRole; + + @Schema(description = "회원 유형 코드. A: 관리자, T: 교사, S: 학생", example = "T") + private String userType; + + public AdminMemberUpdateDto toAdminMemberUpdateDto() { + AdminMemberUpdateDto adminMemberUpdateDto = new AdminMemberUpdateDto(); + adminMemberUpdateDto.setUserIdx(userIdx); + adminMemberUpdateDto.setEmail(email); + adminMemberUpdateDto.setHp(hp); + adminMemberUpdateDto.setUserRole(userRole); + adminMemberUpdateDto.setUserType(userType); + return adminMemberUpdateDto; + } +} diff --git a/src/main/java/com/alist/api/modules/admin/member/mapper/AdminMemberMapper.java b/src/main/java/com/alist/api/modules/admin/member/mapper/AdminMemberMapper.java new file mode 100644 index 0000000..c217100 --- /dev/null +++ b/src/main/java/com/alist/api/modules/admin/member/mapper/AdminMemberMapper.java @@ -0,0 +1,20 @@ +package com.alist.api.modules.admin.member.mapper; + +import com.alist.api.modules.admin.member.dto.AdminMemberSearchDto; +import com.alist.api.modules.admin.member.dto.AdminMemberUpdateDto; +import com.alist.api.modules.admin.member.vo.AdminMemberDetailVo; +import com.alist.api.modules.admin.member.vo.AdminMemberVo; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface AdminMemberMapper { + int selectAdminMemberCount(AdminMemberSearchDto adminMemberSearchDto); + + List selectAdminMemberList(AdminMemberSearchDto adminMemberSearchDto); + + AdminMemberDetailVo selectAdminMemberDetail(Integer userIdx); + + int updateAdminMember(AdminMemberUpdateDto adminMemberUpdateDto); +} diff --git a/src/main/java/com/alist/api/modules/admin/member/service/AdminMemberService.java b/src/main/java/com/alist/api/modules/admin/member/service/AdminMemberService.java new file mode 100644 index 0000000..eb72c34 --- /dev/null +++ b/src/main/java/com/alist/api/modules/admin/member/service/AdminMemberService.java @@ -0,0 +1,48 @@ +package com.alist.api.modules.admin.member.service; + +import com.alist.api.modules.admin.member.dto.AdminMemberSearchDto; +import com.alist.api.modules.admin.member.dto.AdminMemberUpdateDto; +import com.alist.api.modules.admin.member.mapper.AdminMemberMapper; +import com.alist.api.modules.admin.member.vo.AdminMemberDetailVo; +import com.alist.api.modules.admin.member.vo.AdminMemberListVo; +import com.alist.api.modules.admin.member.vo.AdminMemberUpdateVo; +import com.alist.api.modules.admin.member.vo.AdminMemberVo; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +public class AdminMemberService { + private final AdminMemberMapper adminMemberMapper; + + public AdminMemberService(AdminMemberMapper adminMemberMapper) { + this.adminMemberMapper = adminMemberMapper; + } + + @Transactional(readOnly = true) + public AdminMemberListVo selectAdminMemberList(AdminMemberSearchDto adminMemberSearchDto) { + int totalCount = adminMemberMapper.selectAdminMemberCount(adminMemberSearchDto); + List memberList = adminMemberMapper.selectAdminMemberList(adminMemberSearchDto); + + AdminMemberListVo result = new AdminMemberListVo(); + result.setMemberList(memberList); + result.setPaging(adminMemberSearchDto, totalCount); + + return result; + } + + @Transactional(readOnly = true) + public AdminMemberDetailVo selectAdminMemberDetail(Integer userIdx) { + return adminMemberMapper.selectAdminMemberDetail(userIdx); + } + + @Transactional + public AdminMemberUpdateVo updateAdminMember(AdminMemberUpdateDto adminMemberUpdateDto) { + int updateCount = adminMemberMapper.updateAdminMember(adminMemberUpdateDto); + + AdminMemberUpdateVo result = new AdminMemberUpdateVo(); + result.setMemberUpdated(updateCount > 0); + return result; + } +} diff --git a/src/main/java/com/alist/api/modules/admin/member/vo/AdminMemberDetailVo.java b/src/main/java/com/alist/api/modules/admin/member/vo/AdminMemberDetailVo.java new file mode 100644 index 0000000..0040166 --- /dev/null +++ b/src/main/java/com/alist/api/modules/admin/member/vo/AdminMemberDetailVo.java @@ -0,0 +1,51 @@ +package com.alist.api.modules.admin.member.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDateTime; + +@Schema(description = "관리자 회원 상세 조회 응답") +@Getter +@Setter +public class AdminMemberDetailVo { + @Schema(description = "회원 PK", example = "15") + private Integer userIdx; + + @Schema(description = "회원 토큰 PK", example = "15") + private Integer userTokenIdx; + + @Schema(description = "회원 아이디", example = "admin") + private String id; + + @Schema(description = "이메일", example = "user@example.com") + private String email; + + @Schema(description = "휴대폰 번호", example = "01012345678") + private String hp; + + @Schema(description = "회원 권한 코드(CCD/SCM/I/R/E)", example = "SCM") + private String userRole; + + @Schema(description = "회원 유형 코드. A: 관리자, T: 교사, S: 학생", example = "T") + private String userType; + + @Schema(description = "휴면 여부. N: 정상, Y: 휴면", example = "N") + private String dormantYn; + + @Schema(description = "휴면 처리일") + private LocalDateTime dormantAt; + + @Schema(description = "탈퇴 상태. N: 정상, P: 탈퇴대기, Y: 탈퇴완료", example = "N") + private String withdrawStatus; + + @Schema(description = "탈퇴 신청일") + private LocalDateTime withdrawAt; + + @Schema(description = "가입일") + private LocalDateTime createAt; + + @Schema(description = "수정일") + private LocalDateTime updateAt; +} diff --git a/src/main/java/com/alist/api/modules/admin/member/vo/AdminMemberListVo.java b/src/main/java/com/alist/api/modules/admin/member/vo/AdminMemberListVo.java new file mode 100644 index 0000000..fb07a80 --- /dev/null +++ b/src/main/java/com/alist/api/modules/admin/member/vo/AdminMemberListVo.java @@ -0,0 +1,16 @@ +package com.alist.api.modules.admin.member.vo; + +import com.alist.api.common.paging.PageResponse; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Schema(description = "관리자 회원 목록 조회 응답") +@Getter +@Setter +public class AdminMemberListVo extends PageResponse { + @Schema(description = "회원 목록") + private List memberList; +} diff --git a/src/main/java/com/alist/api/modules/admin/member/vo/AdminMemberUpdateVo.java b/src/main/java/com/alist/api/modules/admin/member/vo/AdminMemberUpdateVo.java new file mode 100644 index 0000000..07796b7 --- /dev/null +++ b/src/main/java/com/alist/api/modules/admin/member/vo/AdminMemberUpdateVo.java @@ -0,0 +1,13 @@ +package com.alist.api.modules.admin.member.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +@Schema(description = "관리자 회원 수정 응답") +@Getter +@Setter +public class AdminMemberUpdateVo { + @Schema(description = "회원 수정 여부", example = "true") + private boolean memberUpdated; +} diff --git a/src/main/java/com/alist/api/modules/admin/member/vo/AdminMemberVo.java b/src/main/java/com/alist/api/modules/admin/member/vo/AdminMemberVo.java new file mode 100644 index 0000000..583ab7c --- /dev/null +++ b/src/main/java/com/alist/api/modules/admin/member/vo/AdminMemberVo.java @@ -0,0 +1,51 @@ +package com.alist.api.modules.admin.member.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDateTime; + +@Schema(description = "관리자 회원 목록 항목") +@Getter +@Setter +public class AdminMemberVo { + @Schema(description = "회원 PK", example = "15") + private Integer userIdx; + + @Schema(description = "회원 토큰 PK", example = "15") + private Integer userTokenIdx; + + @Schema(description = "회원 아이디", example = "admin") + private String id; + + @Schema(description = "이메일", example = "user@example.com") + private String email; + + @Schema(description = "휴대폰 번호", example = "01012345678") + private String hp; + + @Schema(description = "회원 권한 코드(CCD/SCM/I/R/E)", example = "SCM") + private String userRole; + + @Schema(description = "회원 유형 코드. A: 관리자, T: 교사, S: 학생", example = "T") + private String userType; + + @Schema(description = "휴면 여부. N: 정상, Y: 휴면", example = "N") + private String dormantYn; + + @Schema(description = "휴면 처리일") + private LocalDateTime dormantAt; + + @Schema(description = "탈퇴 상태. N: 정상, P: 탈퇴대기, Y: 탈퇴완료", example = "N") + private String withdrawStatus; + + @Schema(description = "탈퇴 신청일") + private LocalDateTime withdrawAt; + + @Schema(description = "가입일") + private LocalDateTime createAt; + + @Schema(description = "수정일") + private LocalDateTime updateAt; +} diff --git a/src/main/java/com/alist/api/modules/admin/user/dto/AdminUserDto.java b/src/main/java/com/alist/api/modules/admin/user/dto/AdminUserDto.java index d2e746e..9fe1794 100644 --- a/src/main/java/com/alist/api/modules/admin/user/dto/AdminUserDto.java +++ b/src/main/java/com/alist/api/modules/admin/user/dto/AdminUserDto.java @@ -1,6 +1,7 @@ package com.alist.api.modules.admin.user.dto; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; @@ -13,9 +14,14 @@ public class AdminUserDto { private String userType; @JsonIgnore + @Schema(hidden = true) private String newPassword; + @JsonIgnore + @Schema(hidden = true) private String password; + @JsonIgnore + @Schema(hidden = true) private int resultCode; } diff --git a/src/main/java/com/alist/api/modules/admin/user/vo/AdminUserVo.java b/src/main/java/com/alist/api/modules/admin/user/vo/AdminUserVo.java index 6461452..b656638 100644 --- a/src/main/java/com/alist/api/modules/admin/user/vo/AdminUserVo.java +++ b/src/main/java/com/alist/api/modules/admin/user/vo/AdminUserVo.java @@ -1,21 +1,35 @@ package com.alist.api.modules.admin.user.vo; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +@Schema(description = "Admin 사용자 회원가입 응답") @Setter @Getter public class AdminUserVo { + @Schema(description = "회원 PK", example = "14") private Integer userIdx; + + @Schema(description = "관리자 아이디", example = "admin") private String id; + + @Schema(description = "관리자 권한 코드", example = "A") private String userRole; + + @Schema(description = "회원 유형 코드. A: 관리자", example = "A") private String userType; @JsonIgnore + @Schema(hidden = true) private String newPassword; + @JsonIgnore + @Schema(hidden = true) private String password; + @JsonIgnore + @Schema(hidden = true) private int resultCode; } diff --git a/src/main/java/com/alist/api/modules/auth/dto/LoginDto.java b/src/main/java/com/alist/api/modules/auth/dto/LoginDto.java index 179bce9..0c05f3b 100644 --- a/src/main/java/com/alist/api/modules/auth/dto/LoginDto.java +++ b/src/main/java/com/alist/api/modules/auth/dto/LoginDto.java @@ -7,6 +7,7 @@ import lombok.Setter; import java.time.Instant; +@Schema(description = "API Key 로그인 응답") @Getter @Setter public class LoginDto { @@ -18,19 +19,34 @@ public class LoginDto { private String refreshToken; @JsonIgnore + @Schema(hidden = true) private String password; + @JsonIgnore + @Schema(hidden = true) private String userRole; + @JsonIgnore + @Schema(hidden = true) private String userType; + @JsonIgnore + @Schema(hidden = true) private String userApiKey; + @JsonIgnore + @Schema(hidden = true) private Integer userTokenIdx; + @JsonIgnore + @Schema(hidden = true) private Instant expiresAt; + @JsonIgnore + @Schema(hidden = true) private Integer userIdx; + @JsonIgnore + @Schema(hidden = true) private int resultCode; } diff --git a/src/main/java/com/alist/api/modules/auth/dto/SsoExchangeDto.java b/src/main/java/com/alist/api/modules/auth/dto/SsoExchangeDto.java index 4493aec..2fd498c 100644 --- a/src/main/java/com/alist/api/modules/auth/dto/SsoExchangeDto.java +++ b/src/main/java/com/alist/api/modules/auth/dto/SsoExchangeDto.java @@ -1,8 +1,10 @@ package com.alist.api.modules.auth.dto; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +@Schema(description = "SSO 인가 코드 교환 응답") @Getter @Setter public class SsoExchangeDto { @@ -10,10 +12,20 @@ public class SsoExchangeDto { private String code; private String clientId; + @Schema(description = "SSO 세션 ID") private String ssoSessionId; + + @Schema(description = "회원 PK", example = "1") private Integer userIdx; + private Integer userTokenIdx; + + @Schema(description = "회원 아이디", example = "test") private String userId; + + @Schema(description = "회원 권한 코드(CCD/SCM/I/R/E)", example = "SCM") private String userRole; + + @Schema(description = "회원 유형 코드. T: 교사, S: 학생", example = "T") private String userType; } diff --git a/src/main/java/com/alist/api/modules/auth/dto/SsoLoginCheckDto.java b/src/main/java/com/alist/api/modules/auth/dto/SsoLoginCheckDto.java index efc7818..7dd5002 100644 --- a/src/main/java/com/alist/api/modules/auth/dto/SsoLoginCheckDto.java +++ b/src/main/java/com/alist/api/modules/auth/dto/SsoLoginCheckDto.java @@ -1,14 +1,25 @@ package com.alist.api.modules.auth.dto; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +@Schema(description = "SSO 로그인 응답") @Getter @Setter public class SsoLoginCheckDto { + @Schema(description = "로그인 성공 여부", example = "true") private boolean loginIn; + + @Schema(description = "회원 아이디", example = "test") private String id; + + @Schema(description = "회원 PK", example = "1") private Integer userIdx; + + @Schema(description = "회원 권한 코드", example = "CCD/SCM/I/R/E") private String userRole; + + @Schema(description = "회원 유형 코드. T: 교사, S: 학생", example = "S") private String userType; } diff --git a/src/main/java/com/alist/api/modules/auth/dto/TokenDto.java b/src/main/java/com/alist/api/modules/auth/dto/TokenDto.java index b2dd435..b278606 100644 --- a/src/main/java/com/alist/api/modules/auth/dto/TokenDto.java +++ b/src/main/java/com/alist/api/modules/auth/dto/TokenDto.java @@ -7,6 +7,7 @@ import lombok.Setter; import java.time.Instant; +@Schema(description = "테스트용 토큰 발급 응답") @Getter @Setter public class TokenDto { @@ -18,5 +19,6 @@ public class TokenDto { private String refreshToken; @JsonIgnore + @Schema(hidden = true) private int resultCode; } diff --git a/src/main/java/com/alist/api/modules/auth/form/ApikeyLoginForm.java b/src/main/java/com/alist/api/modules/auth/form/ApikeyLoginForm.java index 9115423..2968cc9 100644 --- a/src/main/java/com/alist/api/modules/auth/form/ApikeyLoginForm.java +++ b/src/main/java/com/alist/api/modules/auth/form/ApikeyLoginForm.java @@ -6,12 +6,14 @@ import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; +@Schema(description = "API Key 로그인 요청 폼") @Getter @Setter public class ApikeyLoginForm { @Schema( - description = "api key", - example = "aaaa111dsddd" + description = "사용자 API Key", + example = "YjeWJr9-N-XaJ7ix2M2spnfjOyG9nTmRlY9t6sKw4_M", + requiredMode = Schema.RequiredMode.REQUIRED ) @NotBlank(message = "apiKey를 입력해주세요.") private String userApiKey; diff --git a/src/main/java/com/alist/api/modules/auth/form/SsoExchangeForm.java b/src/main/java/com/alist/api/modules/auth/form/SsoExchangeForm.java index 2d77108..c2af113 100644 --- a/src/main/java/com/alist/api/modules/auth/form/SsoExchangeForm.java +++ b/src/main/java/com/alist/api/modules/auth/form/SsoExchangeForm.java @@ -1,15 +1,29 @@ package com.alist.api.modules.auth.form; import com.alist.api.modules.auth.dto.SsoExchangeDto; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import lombok.Getter; +import lombok.Setter; +@Schema(description = "SSO 인가 코드 교환 요청 폼") @Getter +@Setter public class SsoExchangeForm { - @NotBlank + @Schema( + description = "SSO 인가 코드", + example = "authorization-code", + requiredMode = Schema.RequiredMode.REQUIRED + ) + @NotBlank(message = "인가 코드는 필수입니다.") private String code; - @NotBlank + @Schema( + description = "SSO 클라이언트 ID", + example = "alist-main", + requiredMode = Schema.RequiredMode.REQUIRED + ) + @NotBlank(message = "클라이언트 ID는 필수입니다.") private String clientId; public SsoExchangeDto toSsoExchangeDto() { diff --git a/src/main/java/com/alist/api/modules/auth/form/SsoLoginForm.java b/src/main/java/com/alist/api/modules/auth/form/SsoLoginForm.java index 186ac9a..26609ed 100644 --- a/src/main/java/com/alist/api/modules/auth/form/SsoLoginForm.java +++ b/src/main/java/com/alist/api/modules/auth/form/SsoLoginForm.java @@ -1,15 +1,29 @@ package com.alist.api.modules.auth.form; import com.alist.api.modules.auth.dto.SsoLoginDto; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import lombok.Getter; +import lombok.Setter; +@Schema(description = "SSO 로그인 요청 폼") @Getter +@Setter public class SsoLoginForm { - @NotBlank + @Schema( + description = "회원 아이디", + example = "test", + requiredMode = Schema.RequiredMode.REQUIRED + ) + @NotBlank(message = "아이디는 필수입니다.") private String id; - @NotBlank + @Schema( + description = "비밀번호", + example = "password1234", + requiredMode = Schema.RequiredMode.REQUIRED + ) + @NotBlank(message = "비밀번호는 필수입니다.") private String password; public SsoLoginDto toSsoLoginDto() { diff --git a/src/main/java/com/alist/api/modules/file/vo/FileUploadVo.java b/src/main/java/com/alist/api/modules/file/vo/FileUploadVo.java index b9deb4e..f46d5b5 100644 --- a/src/main/java/com/alist/api/modules/file/vo/FileUploadVo.java +++ b/src/main/java/com/alist/api/modules/file/vo/FileUploadVo.java @@ -1,17 +1,34 @@ package com.alist.api.modules.file.vo; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +@Schema(description = "파일 업로드 응답") @Getter @Setter public class FileUploadVo { + @Schema(description = "업로드 파일 접근 경로", example = "/upload/editor/2026/05/19") private String uploadPath; + + @Schema(description = "원본 파일명", example = "sample.png") private String originalFileName; + + @Schema(description = "저장 파일명", example = "a1b2c3d4.png") private String storedFileName; + + @Schema(description = "파일 확장자", example = "png") private String fileExtension; + + @Schema(description = "Content-Type", example = "image/png") private String contentType; + + @Schema(description = "파일 크기(byte)", example = "102400") private Long fileSize; + + @Schema(description = "이미지 너비(px)", example = "800") private Integer width; + + @Schema(description = "이미지 높이(px)", example = "600") private Integer height; } diff --git a/src/main/java/com/alist/api/modules/file/vo/SunEditorUploadVo.java b/src/main/java/com/alist/api/modules/file/vo/SunEditorUploadVo.java index 7d19a27..1e37b14 100644 --- a/src/main/java/com/alist/api/modules/file/vo/SunEditorUploadVo.java +++ b/src/main/java/com/alist/api/modules/file/vo/SunEditorUploadVo.java @@ -1,24 +1,33 @@ package com.alist.api.modules.file.vo; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; import java.util.List; +@Schema(description = "SunEditor 이미지 업로드 응답") @Getter @Setter public class SunEditorUploadVo { + @Schema(description = "업로드 결과 목록") private List result; public SunEditorUploadVo(List result) { this.result = result; } + @Schema(description = "SunEditor 업로드 파일 항목") @Getter @Setter public static class Item { + @Schema(description = "업로드 파일 URL", example = "https://api.alist.co.kr/upload/editor/sample.png") private String url; + + @Schema(description = "원본 파일명", example = "sample.png") private String name; + + @Schema(description = "파일 크기(byte)", example = "102400") private Long size; public Item(String url, String name, Long size) { diff --git a/src/main/java/com/alist/api/modules/main/MainController.java b/src/main/java/com/alist/api/modules/main/MainController.java index 8a69cd6..30b0c45 100644 --- a/src/main/java/com/alist/api/modules/main/MainController.java +++ b/src/main/java/com/alist/api/modules/main/MainController.java @@ -1,8 +1,10 @@ package com.alist.api.modules.main; +import io.swagger.v3.oas.annotations.Hidden; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; +@Hidden @Controller public class MainController { diff --git a/src/main/java/com/alist/api/modules/migration/alist/user/vo/AlistUserVo.java b/src/main/java/com/alist/api/modules/migration/alist/user/vo/AlistUserVo.java index 507a43b..9868787 100644 --- a/src/main/java/com/alist/api/modules/migration/alist/user/vo/AlistUserVo.java +++ b/src/main/java/com/alist/api/modules/migration/alist/user/vo/AlistUserVo.java @@ -1,15 +1,28 @@ package com.alist.api.modules.migration.alist.user.vo; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +@Schema(description = "ALIST 이전 회원 정보") @Getter @Setter public class AlistUserVo { + @Schema(description = "이전 회원 아이디", example = "test") private String id; + + @Schema(description = "이전 회원 이름", example = "홍길동") private String name; + + @Schema(description = "이전 회원 휴대폰 번호", example = "01012345678") private String hp; + + @Schema(description = "이전 회원 이메일", example = "user@example.com") private String email; + + @Schema(description = "이전 회원 구분", example = "T/S") private String type; + + @Schema(description = "이전 회원 가입일", example = "2026-05-19") private String joinDate; } diff --git a/src/main/java/com/alist/api/modules/migration/eltown/user/vo/EltownUserVo.java b/src/main/java/com/alist/api/modules/migration/eltown/user/vo/EltownUserVo.java index 411dd5d..b60962a 100644 --- a/src/main/java/com/alist/api/modules/migration/eltown/user/vo/EltownUserVo.java +++ b/src/main/java/com/alist/api/modules/migration/eltown/user/vo/EltownUserVo.java @@ -1,15 +1,28 @@ package com.alist.api.modules.migration.eltown.user.vo; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +@Schema(description = "ELTOWN 이전 회원 정보") @Getter @Setter public class EltownUserVo { + @Schema(description = "이전 회원 아이디", example = "test") private String id; + + @Schema(description = "이전 회원 이름", example = "홍길동") private String name; + + @Schema(description = "이전 회원 휴대폰 번호", example = "01012345678") private String hp; + + @Schema(description = "이전 회원 이메일", example = "user@example.com") private String email; + + @Schema(description = "이전 회원 구분", example = "S") private String type; + + @Schema(description = "이전 회원 가입일", example = "2026-05-19") private String joinDate; } diff --git a/src/main/java/com/alist/api/modules/tusFile/dto/FileDownloadDto.java b/src/main/java/com/alist/api/modules/tusFile/dto/FileDownloadDto.java index a455e1f..0c3aa3e 100644 --- a/src/main/java/com/alist/api/modules/tusFile/dto/FileDownloadDto.java +++ b/src/main/java/com/alist/api/modules/tusFile/dto/FileDownloadDto.java @@ -1,20 +1,33 @@ package com.alist.api.modules.tusFile.dto; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +@Schema(description = "파일 다운로드 처리 DTO") @Getter @Setter public class FileDownloadDto { + @Schema(description = "파일 상세 PK", example = "1") private Long fileDetailIdx; - private Long fileMasterIdx; - private String fileUuid; - private String originName; - private String contentType; - private Long sizeBytes; - private String savePath; + @Schema(description = "파일 마스터 PK", example = "1") + private Long fileMasterIdx; + + @Schema(description = "파일 UUID", example = "018f6f2d-7b5c-7d49-9c3a-8c0f4f9f9f10") + private String fileUuid; + + @Schema(description = "원본 파일명", example = "sample.png") + private String originName; + + @Schema(description = "Content-Type", example = "image/png") + private String contentType; + + @Schema(description = "파일 크기(byte)", example = "102400") + private Long sizeBytes; + + private String savePath; private Integer userIdx; private Integer userTokenIdx; private String eventType; @@ -23,5 +36,6 @@ public class FileDownloadDto { private String referer; @JsonIgnore + @Schema(hidden = true) private Integer resultCode; } diff --git a/src/main/java/com/alist/api/modules/tusFile/dto/FileDownloadItemDto.java b/src/main/java/com/alist/api/modules/tusFile/dto/FileDownloadItemDto.java index add6d5a..2eca5a2 100644 --- a/src/main/java/com/alist/api/modules/tusFile/dto/FileDownloadItemDto.java +++ b/src/main/java/com/alist/api/modules/tusFile/dto/FileDownloadItemDto.java @@ -1,17 +1,34 @@ package com.alist.api.modules.tusFile.dto; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +@Schema(description = "다운로드 파일 항목") @Getter @Setter public class FileDownloadItemDto { + @Schema(description = "파일 상세 PK", example = "1") private Long fileDetailIdx; + + @Schema(description = "파일 마스터 PK", example = "1") private Long fileMasterIdx; + + @Schema(description = "파일 UUID", example = "018f6f2d-7b5c-7d49-9c3a-8c0f4f9f9f10") private String fileUuid; + + @Schema(description = "원본 파일명", example = "sample.png") private String originName; + + @Schema(description = "Content-Type", example = "image/png") private String contentType; + + @Schema(description = "파일 크기(byte)", example = "102400") private Long sizeBytes; + + @Schema(description = "미리보기 URL") private String viewUrl; + + @Schema(description = "다운로드 URL") private String downloadUrl; } diff --git a/src/main/java/com/alist/api/modules/tusFile/dto/FileDownloadListDto.java b/src/main/java/com/alist/api/modules/tusFile/dto/FileDownloadListDto.java index 6a1e24f..f18d8fe 100644 --- a/src/main/java/com/alist/api/modules/tusFile/dto/FileDownloadListDto.java +++ b/src/main/java/com/alist/api/modules/tusFile/dto/FileDownloadListDto.java @@ -1,17 +1,23 @@ package com.alist.api.modules.tusFile.dto; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; import java.util.List; +@Schema(description = "파일 다운로드 목록 응답") @Getter @Setter public class FileDownloadListDto { + @Schema(description = "파일 마스터 PK", example = "1") private Long fileMasterIdx; + + @Schema(description = "다운로드 파일 목록") private List itemList; @JsonIgnore + @Schema(hidden = true) private Integer resultCode; } diff --git a/src/main/java/com/alist/api/modules/tusFile/dto/FileUploadDto.java b/src/main/java/com/alist/api/modules/tusFile/dto/FileUploadDto.java index c7b8518..8fe110d 100644 --- a/src/main/java/com/alist/api/modules/tusFile/dto/FileUploadDto.java +++ b/src/main/java/com/alist/api/modules/tusFile/dto/FileUploadDto.java @@ -1,29 +1,46 @@ package com.alist.api.modules.tusFile.dto; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; import java.util.List; +@Schema(description = "TUS 파일 업로드 초기화 응답") @Getter @Setter public class FileUploadDto { + @Schema(description = "파일 마스터 PK", example = "1") private Long fileMasterIdx; + + @Schema(description = "TUS 업로드 엔드포인트", example = "/tusFiles/upload") private String tusEndpoint; @JsonIgnore + @Schema(hidden = true) private String fileCategory; + @JsonIgnore + @Schema(hidden = true) private String folderPath; + @JsonIgnore + @Schema(hidden = true) private Integer userTokenIdx; + @JsonIgnore + @Schema(hidden = true) private Integer userIdx; + @JsonIgnore + @Schema(hidden = true) private Integer status; + @JsonIgnore + @Schema(hidden = true) private Integer totalCount; + @Schema(description = "업로드 파일 항목 목록") private List itemList; } diff --git a/src/main/java/com/alist/api/modules/tusFile/dto/FileUploadItemDto.java b/src/main/java/com/alist/api/modules/tusFile/dto/FileUploadItemDto.java index 24f8876..2043cda 100644 --- a/src/main/java/com/alist/api/modules/tusFile/dto/FileUploadItemDto.java +++ b/src/main/java/com/alist/api/modules/tusFile/dto/FileUploadItemDto.java @@ -1,23 +1,39 @@ package com.alist.api.modules.tusFile.dto; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +@Schema(description = "TUS 업로드 파일 항목 응답") @Getter @Setter public class FileUploadItemDto { + @Schema(description = "파일 순번", example = "1") private Integer fileSeq; + + @Schema(description = "파일 UUID", example = "018f6f2d-7b5c-7d49-9c3a-8c0f4f9f9f10") private String fileUuid; + + @Schema(description = "TUS 업로드 토큰") private String uploadToken; + + @Schema(description = "원본 파일명", example = "sample.png") private String originName; + + @Schema(description = "파일 크기(byte)", example = "102400") private Long sizeBytes; + + @Schema(description = "Content-Type", example = "image/png") private String contentType; @JsonIgnore + @Schema(hidden = true) private Long fileMasterIdx; @JsonIgnore + @Schema(hidden = true) private Integer userIdx; @JsonIgnore + @Schema(hidden = true) private Integer status; } diff --git a/src/main/java/com/alist/api/modules/tusFile/dto/UploadStatusDto.java b/src/main/java/com/alist/api/modules/tusFile/dto/UploadStatusDto.java index c4a9540..3aeb9a1 100644 --- a/src/main/java/com/alist/api/modules/tusFile/dto/UploadStatusDto.java +++ b/src/main/java/com/alist/api/modules/tusFile/dto/UploadStatusDto.java @@ -1,15 +1,28 @@ package com.alist.api.modules.tusFile.dto; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +@Schema(description = "업로드 상태 조회 응답") @Getter @Setter public class UploadStatusDto { + @Schema(description = "파일 UUID", example = "018f6f2d-7b5c-7d49-9c3a-8c0f4f9f9f10") private String fileUuid; + + @Schema(description = "업로드 상태. PENDING, UPLOADING, DONE, FAILED", example = "UPLOADING") private String status; // PENDING, UPLOADING, DONE, FAILED + + @Schema(description = "업로드 완료 byte", example = "51200") private Long uploadedBytes; + + @Schema(description = "전체 파일 크기 byte", example = "102400") private Long totalBytes; + + @Schema(description = "업로드 진행률", example = "50") private Integer percent; + + @Schema(description = "상태 갱신 시각", example = "2026-05-19T10:30:00") private String updatedAt; } diff --git a/src/main/java/com/alist/api/modules/tusFile/dto/UploadTokenDto.java b/src/main/java/com/alist/api/modules/tusFile/dto/UploadTokenDto.java index 2eba098..f157edd 100644 --- a/src/main/java/com/alist/api/modules/tusFile/dto/UploadTokenDto.java +++ b/src/main/java/com/alist/api/modules/tusFile/dto/UploadTokenDto.java @@ -1,23 +1,35 @@ package com.alist.api.modules.tusFile.dto; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +@Schema(description = "업로드 인증 토큰 정보") @Getter @Setter public class UploadTokenDto { private Integer userTokenIdx; + + @Schema(description = "파일 UUID", example = "018f6f2d-7b5c-7d49-9c3a-8c0f4f9f9f10") private String fileUuid; + + @Schema(description = "업로드 토큰") private String uploadToken; private String uploadMetadataRaw; private String uploadLengthRaw; + @Schema(description = "원본 파일명", example = "sample.png") private String originName; + + @Schema(description = "파일 크기(byte)", example = "102400") private Long sizeBytes; + + @Schema(description = "Content-Type", example = "image/png") private String contentType; @JsonIgnore + @Schema(hidden = true) private Integer resultCode; } diff --git a/src/main/java/com/alist/api/modules/tusFile/form/FileDeleteForm.java b/src/main/java/com/alist/api/modules/tusFile/form/FileDeleteForm.java index 8b7ea5e..5e82c30 100644 --- a/src/main/java/com/alist/api/modules/tusFile/form/FileDeleteForm.java +++ b/src/main/java/com/alist/api/modules/tusFile/form/FileDeleteForm.java @@ -1,14 +1,21 @@ package com.alist.api.modules.tusFile.form; import com.alist.api.modules.tusFile.dto.FileDeleteDto; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; +@Schema(description = "파일 삭제 요청 폼") @Getter @Setter public class FileDeleteForm { - @NotBlank + @Schema( + description = "파일 UUID", + example = "018f6f2d-7b5c-7d49-9c3a-8c0f4f9f9f10", + requiredMode = Schema.RequiredMode.REQUIRED + ) + @NotBlank(message = "파일 UUID는 필수입니다.") private String fileUuid; public FileDeleteDto toFileDeleteDto() { diff --git a/src/main/java/com/alist/api/modules/tusFile/form/FileUploadForm.java b/src/main/java/com/alist/api/modules/tusFile/form/FileUploadForm.java index ea02521..f6ac1d5 100644 --- a/src/main/java/com/alist/api/modules/tusFile/form/FileUploadForm.java +++ b/src/main/java/com/alist/api/modules/tusFile/form/FileUploadForm.java @@ -2,6 +2,7 @@ package com.alist.api.modules.tusFile.form; import com.alist.api.modules.tusFile.dto.FileUploadDto; import com.alist.api.modules.tusFile.dto.FileUploadItemDto; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotEmpty; @@ -11,15 +12,26 @@ import lombok.Setter; import java.util.ArrayList; import java.util.List; +@Schema(description = "TUS 파일 업로드 초기화 요청 폼") @Getter @Setter public class FileUploadForm { - @NotBlank + @Schema( + description = "파일 카테고리", + example = "BOARD", + requiredMode = Schema.RequiredMode.REQUIRED + ) + @NotBlank(message = "파일 카테고리는 필수입니다.") private String fileCategory; + @Schema(description = "업로드 폴더 경로. 미전달 시 / 로 처리됩니다.", example = "/board") private String folderPath; - @NotEmpty + @Schema( + description = "업로드 파일 목록", + requiredMode = Schema.RequiredMode.REQUIRED + ) + @NotEmpty(message = "업로드 파일 목록은 필수입니다.") @Valid private List itemList; diff --git a/src/main/java/com/alist/api/modules/tusFile/form/FileUploadItemForm.java b/src/main/java/com/alist/api/modules/tusFile/form/FileUploadItemForm.java index 84d1b19..c96ad66 100644 --- a/src/main/java/com/alist/api/modules/tusFile/form/FileUploadItemForm.java +++ b/src/main/java/com/alist/api/modules/tusFile/form/FileUploadItemForm.java @@ -1,21 +1,33 @@ package com.alist.api.modules.tusFile.form; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Positive; import lombok.Getter; import lombok.Setter; +@Schema(description = "TUS 업로드 파일 항목") @Getter @Setter public class FileUploadItemForm { - - @NotBlank + @Schema( + description = "원본 파일명", + example = "sample.png", + requiredMode = Schema.RequiredMode.REQUIRED + ) + @NotBlank(message = "원본 파일명은 필수입니다.") private String originName; - @NotNull - @Positive + @Schema( + description = "파일 크기(byte)", + example = "102400", + requiredMode = Schema.RequiredMode.REQUIRED + ) + @NotNull(message = "파일 크기는 필수입니다.") + @Positive(message = "파일 크기는 0보다 커야 합니다.") private Long sizeBytes; + @Schema(description = "Content-Type", example = "image/png") private String contentType; } diff --git a/src/main/java/com/alist/api/modules/tusFile/form/TusHookEventForm.java b/src/main/java/com/alist/api/modules/tusFile/form/TusHookEventForm.java index f096776..a16b343 100644 --- a/src/main/java/com/alist/api/modules/tusFile/form/TusHookEventForm.java +++ b/src/main/java/com/alist/api/modules/tusFile/form/TusHookEventForm.java @@ -2,13 +2,16 @@ package com.alist.api.modules.tusFile.form; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +@Schema(description = "TUS 훅 이벤트 상세 정보") @Getter @Setter @JsonIgnoreProperties(ignoreUnknown = true) public class TusHookEventForm { + @Schema(description = "TUS 업로드 정보") @JsonProperty("Upload") private TusHookUploadForm tusHookUploadForm; } diff --git a/src/main/java/com/alist/api/modules/tusFile/form/TusHookForm.java b/src/main/java/com/alist/api/modules/tusFile/form/TusHookForm.java index 2921e50..45ed80d 100644 --- a/src/main/java/com/alist/api/modules/tusFile/form/TusHookForm.java +++ b/src/main/java/com/alist/api/modules/tusFile/form/TusHookForm.java @@ -3,16 +3,20 @@ package com.alist.api.modules.tusFile.form; import com.alist.api.modules.tusFile.dto.TusHookDto; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +@Schema(description = "TUS 훅 요청 폼") @Getter @Setter @JsonIgnoreProperties(ignoreUnknown = true) public class TusHookForm { + @Schema(description = "TUS 훅 이벤트 타입", example = "post-finish") @JsonProperty("Type") private String type; + @Schema(description = "TUS 훅 이벤트 정보") @JsonProperty("Event") private TusHookEventForm tusHookEventForm; diff --git a/src/main/java/com/alist/api/modules/tusFile/form/TusHookUploadForm.java b/src/main/java/com/alist/api/modules/tusFile/form/TusHookUploadForm.java index 3124290..3a5a483 100644 --- a/src/main/java/com/alist/api/modules/tusFile/form/TusHookUploadForm.java +++ b/src/main/java/com/alist/api/modules/tusFile/form/TusHookUploadForm.java @@ -2,24 +2,33 @@ package com.alist.api.modules.tusFile.form; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; import java.util.Map; +@Schema(description = "TUS 훅 업로드 정보") @Getter @Setter @JsonIgnoreProperties(ignoreUnknown = true) public class TusHookUploadForm { + @Schema(description = "TUS 업로드 ID", example = "018f6f2d7b5c7d499c3a8c0f4f9f9f10") @JsonProperty("ID") private String id; + @Schema(description = "업로드 파일 전체 크기(byte)", example = "102400") @JsonProperty("Size") private Long size; + @Schema(description = "현재 업로드 offset(byte)", example = "102400") @JsonProperty("Offset") private Long offset; + @Schema( + description = "TUS 메타데이터. fileUuid, filename, filetype 등을 포함합니다.", + example = "{\"fileUuid\":\"018f6f2d-7b5c-7d49-9c3a-8c0f4f9f9f10\",\"filename\":\"sample.png\",\"filetype\":\"image/png\"}" + ) @JsonProperty("MetaData") private Map metaData; } diff --git a/src/main/java/com/alist/api/modules/tusFile/form/UploadCancelForm.java b/src/main/java/com/alist/api/modules/tusFile/form/UploadCancelForm.java index a47ddbd..72724c8 100644 --- a/src/main/java/com/alist/api/modules/tusFile/form/UploadCancelForm.java +++ b/src/main/java/com/alist/api/modules/tusFile/form/UploadCancelForm.java @@ -1,12 +1,19 @@ package com.alist.api.modules.tusFile.form; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; +@Schema(description = "업로드 취소 요청 폼") @Getter @Setter public class UploadCancelForm { - @NotBlank + @Schema( + description = "파일 UUID", + example = "018f6f2d-7b5c-7d49-9c3a-8c0f4f9f9f10", + requiredMode = Schema.RequiredMode.REQUIRED + ) + @NotBlank(message = "파일 UUID는 필수입니다.") private String fileUuid; } diff --git a/src/main/java/com/alist/api/modules/tusFile/form/UploadStatusForm.java b/src/main/java/com/alist/api/modules/tusFile/form/UploadStatusForm.java index 17f1836..f7bf635 100644 --- a/src/main/java/com/alist/api/modules/tusFile/form/UploadStatusForm.java +++ b/src/main/java/com/alist/api/modules/tusFile/form/UploadStatusForm.java @@ -1,14 +1,21 @@ package com.alist.api.modules.tusFile.form; import com.alist.api.modules.tusFile.dto.UploadStatusDto; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; +@Schema(description = "업로드 상태 조회 요청 폼") @Getter @Setter public class UploadStatusForm { - @NotBlank + @Schema( + description = "파일 UUID", + example = "018f6f2d-7b5c-7d49-9c3a-8c0f4f9f9f10", + requiredMode = Schema.RequiredMode.REQUIRED + ) + @NotBlank(message = "파일 UUID는 필수입니다.") private String fileUuid; public UploadStatusDto toUploadStatusDto() { diff --git a/src/main/java/com/alist/api/modules/user/dto/UserDto.java b/src/main/java/com/alist/api/modules/user/dto/UserDto.java index 5f59f24..24a284c 100644 --- a/src/main/java/com/alist/api/modules/user/dto/UserDto.java +++ b/src/main/java/com/alist/api/modules/user/dto/UserDto.java @@ -1,6 +1,7 @@ package com.alist.api.modules.user.dto; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; @@ -13,9 +14,14 @@ public class UserDto { private String userType; @JsonIgnore + @Schema(hidden = true) private String newPassword; + @JsonIgnore + @Schema(hidden = true) private String password; + @JsonIgnore + @Schema(hidden = true) private int resultCode; } diff --git a/src/main/java/com/alist/api/modules/user/form/UserPasswordChangeForm.java b/src/main/java/com/alist/api/modules/user/form/UserPasswordChangeForm.java index 190e813..65ebd24 100644 --- a/src/main/java/com/alist/api/modules/user/form/UserPasswordChangeForm.java +++ b/src/main/java/com/alist/api/modules/user/form/UserPasswordChangeForm.java @@ -1,16 +1,28 @@ package com.alist.api.modules.user.form; import com.alist.api.modules.user.dto.UserPasswordChangeDto; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; +@Schema(description = "사용자 비밀번호 수정 요청 폼") @Getter @Setter public class UserPasswordChangeForm { + @Schema( + description = "현재 비밀번호", + example = "password1234", + requiredMode = Schema.RequiredMode.REQUIRED + ) @NotBlank(message = "현재 비밀번호는 필수입니다.") private String currentPassword; + @Schema( + description = "새 비밀번호", + example = "newPassword1234", + requiredMode = Schema.RequiredMode.REQUIRED + ) @NotBlank(message = "새 비밀번호는 필수입니다.") private String newPassword; diff --git a/src/main/java/com/alist/api/modules/user/form/UserPasswordCheckForm.java b/src/main/java/com/alist/api/modules/user/form/UserPasswordCheckForm.java index 724019d..149a7bd 100644 --- a/src/main/java/com/alist/api/modules/user/form/UserPasswordCheckForm.java +++ b/src/main/java/com/alist/api/modules/user/form/UserPasswordCheckForm.java @@ -1,13 +1,20 @@ package com.alist.api.modules.user.form; import com.alist.api.modules.user.dto.UserPasswordCheckDto; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; +@Schema(description = "사용자 비밀번호 확인 요청 폼") @Getter @Setter public class UserPasswordCheckForm { + @Schema( + description = "현재 비밀번호", + example = "password1234", + requiredMode = Schema.RequiredMode.REQUIRED + ) @NotBlank(message = "비밀번호는 필수입니다.") private String password; diff --git a/src/main/java/com/alist/api/modules/user/form/UserProfileUpdateForm.java b/src/main/java/com/alist/api/modules/user/form/UserProfileUpdateForm.java index acfa0e7..6d0ffdd 100644 --- a/src/main/java/com/alist/api/modules/user/form/UserProfileUpdateForm.java +++ b/src/main/java/com/alist/api/modules/user/form/UserProfileUpdateForm.java @@ -1,20 +1,29 @@ package com.alist.api.modules.user.form; import com.alist.api.modules.user.dto.UserProfileUpdateDto; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; +@Schema(description = "사용자 개인정보 수정 요청 폼") @Getter @Setter public class UserProfileUpdateForm { + @Schema( + description = "현재 비밀번호", + example = "password1234", + requiredMode = Schema.RequiredMode.REQUIRED + ) @NotBlank(message = "현재 비밀번호는 필수입니다.") private String currentPassword; + @Schema(description = "이메일. 수정할 때만 전달합니다.", example = "user@example.com") @Email(message = "이메일 형식을 확인해주세요.") private String email; + @Schema(description = "휴대폰 번호. 수정할 때만 전달합니다.", example = "01012345678") private String hp; public UserProfileUpdateDto toUserProfileUpdateDto() { diff --git a/src/main/java/com/alist/api/modules/user/vo/MigrationUserVo.java b/src/main/java/com/alist/api/modules/user/vo/MigrationUserVo.java index 6136650..f0557ae 100644 --- a/src/main/java/com/alist/api/modules/user/vo/MigrationUserVo.java +++ b/src/main/java/com/alist/api/modules/user/vo/MigrationUserVo.java @@ -2,14 +2,19 @@ package com.alist.api.modules.user.vo; import com.alist.api.modules.migration.alist.user.vo.AlistUserVo; import com.alist.api.modules.migration.eltown.user.vo.EltownUserVo; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; import java.util.List; +@Schema(description = "이전 회원 조회 응답") @Getter @Setter public class MigrationUserVo { + @Schema(description = "ALIST 이전 회원 목록") List alistUserList; + + @Schema(description = "ELTOWN 이전 회원 목록") List eltownUserList; } diff --git a/src/main/java/com/alist/api/modules/user/vo/UserPasswordChangeVo.java b/src/main/java/com/alist/api/modules/user/vo/UserPasswordChangeVo.java index 2bc5af3..27476df 100644 --- a/src/main/java/com/alist/api/modules/user/vo/UserPasswordChangeVo.java +++ b/src/main/java/com/alist/api/modules/user/vo/UserPasswordChangeVo.java @@ -1,14 +1,18 @@ package com.alist.api.modules.user.vo; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +@Schema(description = "사용자 비밀번호 수정 응답") @Getter @Setter public class UserPasswordChangeVo { + @Schema(description = "비밀번호 수정 여부", example = "true") private boolean passwordChanged; @JsonIgnore + @Schema(hidden = true) private Integer resultCode; } diff --git a/src/main/java/com/alist/api/modules/user/vo/UserPasswordCheckVo.java b/src/main/java/com/alist/api/modules/user/vo/UserPasswordCheckVo.java index bb5d85b..e3b81e1 100644 --- a/src/main/java/com/alist/api/modules/user/vo/UserPasswordCheckVo.java +++ b/src/main/java/com/alist/api/modules/user/vo/UserPasswordCheckVo.java @@ -1,14 +1,18 @@ package com.alist.api.modules.user.vo; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +@Schema(description = "사용자 비밀번호 확인 응답") @Getter @Setter public class UserPasswordCheckVo { + @Schema(description = "비밀번호 일치 여부", example = "true") private boolean passwordMatched; @JsonIgnore + @Schema(hidden = true) private Integer resultCode; } diff --git a/src/main/java/com/alist/api/modules/user/vo/UserProfileUpdateVo.java b/src/main/java/com/alist/api/modules/user/vo/UserProfileUpdateVo.java index 080fd58..f333d10 100644 --- a/src/main/java/com/alist/api/modules/user/vo/UserProfileUpdateVo.java +++ b/src/main/java/com/alist/api/modules/user/vo/UserProfileUpdateVo.java @@ -1,14 +1,18 @@ package com.alist.api.modules.user.vo; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +@Schema(description = "사용자 개인정보 수정 응답") @Getter @Setter public class UserProfileUpdateVo { + @Schema(description = "개인정보 수정 여부", example = "true") private boolean profileUpdated; @JsonIgnore + @Schema(hidden = true) private Integer resultCode; } diff --git a/src/main/java/com/alist/api/modules/user/vo/UserVo.java b/src/main/java/com/alist/api/modules/user/vo/UserVo.java index b758c58..b5f68c6 100644 --- a/src/main/java/com/alist/api/modules/user/vo/UserVo.java +++ b/src/main/java/com/alist/api/modules/user/vo/UserVo.java @@ -1,21 +1,33 @@ package com.alist.api.modules.user.vo; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +@Schema(description = "사용자 회원가입 응답") @Setter @Getter public class UserVo { + @Schema(description = "회원 PK", example = "1") private Integer userIdx; + + @Schema(description = "회원 아이디", example = "test") private String id; + + @Schema(description = "회원 권한 코드", example = "CCD/SCM/I/R/E") private String userRole; + + @Schema(description = "회원 유형 코드. T: 교사, S: 학생", example = "S") private String userType; @JsonIgnore + @Schema(hidden = true) private String newPassword; @JsonIgnore + @Schema(hidden = true) private String password; @JsonIgnore + @Schema(hidden = true) private int resultCode; } diff --git a/src/main/resources/mapper/User/UserMapper.xml b/src/main/resources/mapper/User/UserMapper.xml index 7139120..8611ea2 100644 --- a/src/main/resources/mapper/User/UserMapper.xml +++ b/src/main/resources/mapper/User/UserMapper.xml @@ -26,10 +26,10 @@ UPDATE ALISTLMS.test_user ATU INNER JOIN ALISTLMS.test_user_token ATUT ON ATUT.user_idx = ATU.user_idx SET ATU.update_at = now() - + , ATU.email = #{email} - + , ATU.hp = #{hp} WHERE ATUT.user_token_idx = #{userTokenIdx} diff --git a/src/main/resources/mapper/admin/auth/AdminLoginMapper.xml b/src/main/resources/mapper/admin/auth/AdminLoginMapper.xml index bd03914..26e39dd 100644 --- a/src/main/resources/mapper/admin/auth/AdminLoginMapper.xml +++ b/src/main/resources/mapper/admin/auth/AdminLoginMapper.xml @@ -27,6 +27,15 @@ WHERE user_token_idx = #{userTokenIdx} AND user_type IN ('A') + + /*AdminLoginMapper.updateAdminApiKeyLoginRefreshToken*/ + UPDATE ALISTLMS.test_user_token + SET refresh_token = #{refreshToken} + , expires_at = #{expiresAt} + , updated_at = now() + WHERE user_token_idx = #{userTokenIdx} + AND user_type IN ('A') + + diff --git a/src/main/resources/mapper/admin/member/AdminMemberMapper.xml b/src/main/resources/mapper/admin/member/AdminMemberMapper.xml new file mode 100644 index 0000000..caaa600 --- /dev/null +++ b/src/main/resources/mapper/admin/member/AdminMemberMapper.xml @@ -0,0 +1,97 @@ + + + + + + FROM ALISTLMS.test_user ATU + INNER JOIN ALISTLMS.test_user_token ATUT ON ATUT.user_idx = ATU.user_idx + WHERE ATU.del_yn = 1 + + AND ( + ATU.id LIKE CONCAT('%', #{keyword}, '%') + OR ATU.email LIKE CONCAT('%', #{keyword}, '%') + OR ATU.hp LIKE CONCAT('%', #{keyword}, '%') + ) + + + AND ATUT.user_role = #{userRole} + + + AND ATUT.user_type = #{userType} + + + AND ATU.dormant_yn = #{dormantYn} + + + AND ATU.withdraw_status = #{withdrawStatus} + + + + /*AdminMemberMapper.updateAdminMember*/ + UPDATE ALISTLMS.test_user ATU + INNER JOIN ALISTLMS.test_user_token ATUT ON ATUT.user_idx = ATU.user_idx + SET ATU.update_at = now() + , ATUT.updated_at = now() + + , ATU.email = #{email} + + + , ATU.hp = #{hp} + + + , ATUT.user_role = #{userRole} + + + , ATUT.user_type = #{userType} + + WHERE ATU.user_idx = #{userIdx} + AND ATU.del_yn = 1 + + + + + + + \ No newline at end of file