From b2a996244ca8e2c67ec4e7780b422e86210c043b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=9D=80=EB=B9=84?= <69096886+eunbc@users.noreply.github.com> Date: Fri, 12 Jan 2024 11:34:13 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20=ED=9A=8C=EC=9B=90=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20swagger=20=EC=B6=94=EA=B0=80,=20ddl=20=EC=BB=AC?= =?UTF-8?q?=EB=9F=BC=20=ED=81=AC=EA=B8=B0=20=EC=A1=B0=EC=A0=95=20(#237)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: http Authorization 헤더 추가 * docs: ddl 컬럼 크기 변경 * docs: 컨트롤러 스웨거 추가 * chore: swagger 권한 설정 * chore: permitAll 로 임시 변경 --- .../apimember/controller/AdminController.java | 7 ++++ .../controller/AdminManagementController.java | 7 ++++ .../apimember/controller/AuthController.java | 7 +++- .../controller/MemberController.java | 13 ++++++- .../security/config/WebSecurityConfig.java | 22 +++++++----- db/initdb.d/1-schema.sql | 36 +++++++++---------- http/bingterpark.http | 8 +++-- 7 files changed, 69 insertions(+), 31 deletions(-) diff --git a/api/api-member/src/main/java/com/pgms/apimember/controller/AdminController.java b/api/api-member/src/main/java/com/pgms/apimember/controller/AdminController.java index 46f6a70e..4aff33b4 100644 --- a/api/api-member/src/main/java/com/pgms/apimember/controller/AdminController.java +++ b/api/api-member/src/main/java/com/pgms/apimember/controller/AdminController.java @@ -19,9 +19,12 @@ import com.pgms.coredomain.response.ApiResponse; import com.pgms.coresecurity.security.resolver.CurrentAccount; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +@Tag(name = "관리자", description = "관리자 관련 API 입니다.") @RestController @RequestMapping("/api/v1/admin") @RequiredArgsConstructor @@ -29,23 +32,27 @@ public class AdminController { private final AdminService adminService; + @Operation(summary = "회원 목록 조회", description = "회원 목록 조회 API 입니다.") @GetMapping("/members") public ResponseEntity>> getMembers( @ModelAttribute @Valid PageCondition pageCondition) { return ResponseEntity.ok(ApiResponse.ok(adminService.getMembers(pageCondition))); } + @Operation(summary = "회원 상세 조회", description = "회원 상세 조회 API 입니다.") @GetMapping("/members/details") public ResponseEntity>> getMemberDetails( @RequestParam List memberIds) { return ResponseEntity.ok(ApiResponse.ok(adminService.getMemberDetails(memberIds))); } + @Operation(summary = "관리자 본인 정보 조회", description = "관리자 본인 정보 조회 API 입니다.") @GetMapping("/me") public ResponseEntity> getMyInfo(@CurrentAccount Long adminId) { return ResponseEntity.ok(ApiResponse.ok(adminService.getAdmin(adminId))); } + @Operation(summary = "관리자 본인 삭제", description = "관리자 본인 삭제 API 입니다.") @DeleteMapping("/me") public ResponseEntity> deleteMyAccount(@CurrentAccount Long adminId) { adminService.deleteAdmins(Collections.singletonList(adminId)); diff --git a/api/api-member/src/main/java/com/pgms/apimember/controller/AdminManagementController.java b/api/api-member/src/main/java/com/pgms/apimember/controller/AdminManagementController.java index 4c06dbec..238f7b94 100644 --- a/api/api-member/src/main/java/com/pgms/apimember/controller/AdminManagementController.java +++ b/api/api-member/src/main/java/com/pgms/apimember/controller/AdminManagementController.java @@ -23,10 +23,13 @@ import com.pgms.apimember.service.AdminService; import com.pgms.coredomain.response.ApiResponse; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; +@Tag(name = "슈퍼관리자", description = "슈퍼관리자 관련 API 입니다.") @RestController @RequestMapping("/api/v1/admin/management") @RequiredArgsConstructor @@ -38,6 +41,7 @@ public class AdminManagementController { // 슈퍼관리자 전용 컨트롤러 * 관리자 CRUD */ + @Operation(summary = "관리자 생성", description = "관리자 생성 API 입니다.") @PostMapping public ResponseEntity> createAdmin(@RequestBody @Valid AdminCreateRequest requestDto) { final Long adminId = adminService.createAdmin(requestDto); @@ -47,12 +51,14 @@ public ResponseEntity> createAdmin(@RequestBody @Valid AdminCr return ResponseEntity.created(uri).body(ApiResponse.created(adminId)); } + @Operation(summary = "관리자 목록 조회", description = "관리자 목록 조회 API 입니다.") @GetMapping public ResponseEntity>> getAdmins( @ModelAttribute @Valid PageCondition pageCondition) { return ResponseEntity.ok(ApiResponse.ok(adminService.getAdmins(pageCondition))); } + @Operation(summary = "관리자 수정", description = "관리자 수정 API 입니다.") @PatchMapping("/{adminId}") public ResponseEntity> updateAdmin( @PathVariable Long adminId, @@ -61,6 +67,7 @@ public ResponseEntity> updateAdmin( return ResponseEntity.noContent().build(); } + @Operation(summary = "관리자 삭제", description = "관리자 삭제 API 입니다.") @DeleteMapping public ResponseEntity> deleteAdmins(@RequestParam List adminIds) { adminService.deleteAdmins(adminIds); diff --git a/api/api-member/src/main/java/com/pgms/apimember/controller/AuthController.java b/api/api-member/src/main/java/com/pgms/apimember/controller/AuthController.java index fd8c985f..9f2b17a2 100644 --- a/api/api-member/src/main/java/com/pgms/apimember/controller/AuthController.java +++ b/api/api-member/src/main/java/com/pgms/apimember/controller/AuthController.java @@ -13,9 +13,12 @@ import com.pgms.coredomain.domain.member.enums.Role; import com.pgms.coredomain.response.ApiResponse; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +@Tag(name = "인증", description = "인증 관련 API 입니다.") @RestController @RequestMapping("/api/v1/auth") @RequiredArgsConstructor @@ -26,15 +29,16 @@ public class AuthController { /** * 로그인 */ + @Operation(summary = "관리자 로그인", description = "관리자 로그인 API 입니다.") @PostMapping("/admin/login") public ResponseEntity> adminLogin(@Valid @RequestBody LoginRequest request) { AuthResponse response = authService.login(request, Role.ROLE_ADMIN); return ResponseEntity.ok(ApiResponse.ok(response)); } + @Operation(summary = "회원 로그인", description = "회원 로그인 API 입니다.") @PostMapping("/members/login") public ResponseEntity> memberLogin(@Valid @RequestBody LoginRequest request) { - // TODO: 나중에 enum으로..? AuthResponse response = authService.login(request, Role.ROLE_USER); return ResponseEntity.ok(ApiResponse.ok(response)); } @@ -42,6 +46,7 @@ public ResponseEntity> memberLogin(@Valid @RequestBody /** * 토큰 재발급 */ + @Operation(summary = "토큰 재발급", description = "토큰 재발급 API 입니다.") @PostMapping("/refresh") public ResponseEntity> refresh(@RequestBody RefreshTokenRequest request) { AuthResponse response = authService.refresh(request); diff --git a/api/api-member/src/main/java/com/pgms/apimember/controller/MemberController.java b/api/api-member/src/main/java/com/pgms/apimember/controller/MemberController.java index 2bf0d1e5..fb7f06d5 100644 --- a/api/api-member/src/main/java/com/pgms/apimember/controller/MemberController.java +++ b/api/api-member/src/main/java/com/pgms/apimember/controller/MemberController.java @@ -20,9 +20,12 @@ import com.pgms.coredomain.response.ApiResponse; import com.pgms.coresecurity.security.resolver.CurrentAccount; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +@Tag(name = "회원", description = "회원 관련 API 입니다.") @RestController @RequestMapping("/api/v1/members") @RequiredArgsConstructor @@ -30,16 +33,19 @@ public class MemberController { private final MemberService memberService; + @Operation(summary = "회원가입", description = "회원가입 API 입니다.") @PostMapping("/signup") public ResponseEntity> signUp(@RequestBody @Valid MemberSignUpRequest requestDto) { return ResponseEntity.ok(ApiResponse.ok(memberService.signUp(requestDto))); } + @Operation(summary = "회원 정보 조회", description = "회원 정보 조회 API 입니다.") @GetMapping("/me") public ResponseEntity> getMyInfo(@CurrentAccount Long memberId) { return ResponseEntity.ok(ApiResponse.ok(memberService.getMemberDetail(memberId))); } + @Operation(summary = "회원 수정", description = "회원 수정 API 입니다.") @PatchMapping("/me") public ResponseEntity updateMyInfo( @CurrentAccount Long memberId, @@ -48,6 +54,7 @@ public ResponseEntity updateMyInfo( return ResponseEntity.noContent().build(); } + @Operation(summary = "비밀번호 수정", description = "비밀번호 수정 API 입니다.") @PatchMapping("/me/password") public ResponseEntity updatePassword( @CurrentAccount Long memberId, @@ -56,6 +63,7 @@ public ResponseEntity updatePassword( return ResponseEntity.noContent().build(); } + @Operation(summary = "비밀번호 확인", description = "비밀번호 확인 API 입니다.") @PostMapping("/me/verify-password") public ResponseEntity verifyPassword(@CurrentAccount Long memberId, @RequestBody MemberPasswordVerifyRequest requestDto) { @@ -63,18 +71,21 @@ public ResponseEntity verifyPassword(@CurrentAccount Long memberId, return ResponseEntity.noContent().build(); } + @Operation(summary = "회원 탈퇴", description = "회원 탈퇴 API 입니다.") @DeleteMapping("/me") public ResponseEntity> deleteMyAccount(@CurrentAccount Long memberId) { memberService.deleteMember(memberId); return ResponseEntity.noContent().build(); } - @PostMapping("send-restore-email") + @Operation(summary = "휴면 해제 메일 전송", description = "휴면 해제 메일 전송 API 입니다.") + @PostMapping("/send-restore-email") public ResponseEntity> sendRestoreEmail(@RequestBody @Valid MemberRestoreRequest requestDto) { memberService.sendRestoreEmail(requestDto); return ResponseEntity.noContent().build(); } + @Operation(summary = "휴면 해제 본인 인증", description = "휴면 해제 본인 인증 API 입니다.") @PatchMapping("/confirm-restore") public ResponseEntity> confirmRestore(@RequestBody @Valid ConfirmRestoreRequest requestDto) { memberService.confirmRestoreMember(requestDto); diff --git a/core/core-security/src/main/java/com/pgms/coresecurity/security/config/WebSecurityConfig.java b/core/core-security/src/main/java/com/pgms/coresecurity/security/config/WebSecurityConfig.java index c72eadb1..c8958999 100644 --- a/core/core-security/src/main/java/com/pgms/coresecurity/security/config/WebSecurityConfig.java +++ b/core/core-security/src/main/java/com/pgms/coresecurity/security/config/WebSecurityConfig.java @@ -93,8 +93,12 @@ private RequestMatcher[] requestPermitAll() { antMatcher(GET, "/api/*/events/*/seat-area"), // 공연 좌석 구역 목록 조회 // DOCS - antMatcher("/v3/api-docs/**"), - antMatcher("/swagger-ui/**") + antMatcher("/swagger-ui/**"), + antMatcher("/swagger-ui"), + antMatcher("/swagger-ui.html"), + antMatcher("/v2/api-docs"), + antMatcher("/v3/api-docs"), + antMatcher("/webjars/**") ); return requestMatchers.toArray(RequestMatcher[]::new); } @@ -217,13 +221,13 @@ public SecurityFilterChain securityFilterChainDefault(HttpSecurity http) throws configureCommonSecuritySettings(http); http .authorizeHttpRequests() - .anyRequest().authenticated() - .and() - .addFilterAfter(jwtAuthenticationFilter, ExceptionTranslationFilter.class) - .exceptionHandling(exception -> { - exception.authenticationEntryPoint(jwtAuthenticationEntryPoint); - exception.accessDeniedHandler(jwtAccessDeniedHandler); - }); + .anyRequest().permitAll(); + // .and() + // .addFilterAfter(jwtAuthenticationFilter, ExceptionTranslationFilter.class) + // .exceptionHandling(exception -> { + // exception.authenticationEntryPoint(jwtAuthenticationEntryPoint); + // exception.accessDeniedHandler(jwtAccessDeniedHandler); + // }); return http.build(); } diff --git a/db/initdb.d/1-schema.sql b/db/initdb.d/1-schema.sql index d1cc973b..1c7c6ce3 100644 --- a/db/initdb.d/1-schema.sql +++ b/db/initdb.d/1-schema.sql @@ -5,12 +5,12 @@ CREATE TABLE admin updated_at TIMESTAMP(6), last_login_at TIMESTAMP(6) NOT NULL, last_password_updated_at TIMESTAMP(6) NOT NULL, - email VARCHAR(255) NOT NULL, - name VARCHAR(255) NOT NULL, - password VARCHAR(255) NOT NULL, - phone_number VARCHAR(255) NOT NULL, - role VARCHAR(255), - status VARCHAR(255) NOT NULL + email VARCHAR(50) NOT NULL, + name VARCHAR(20) NOT NULL, + password VARCHAR(100) NOT NULL, + phone_number VARCHAR(20) NOT NULL, + role VARCHAR(20), + status VARCHAR(10) NOT NULL ); CREATE TABLE member @@ -20,18 +20,18 @@ CREATE TABLE member updated_at TIMESTAMP(6), last_login_at TIMESTAMP(6) NOT NULL, last_password_updated_at TIMESTAMP(6) NOT NULL, - birth_date VARCHAR(255), - detail_address VARCHAR(255), - email VARCHAR(255) NOT NULL, - gender VARCHAR(255), - name VARCHAR(255) NOT NULL, - password VARCHAR(255), - phone_number VARCHAR(255), - provider VARCHAR(255), - role VARCHAR(255), - status VARCHAR(255) NOT NULL, - street_address VARCHAR(255), - zip_code VARCHAR(255) + birth_date DATE, + detail_address VARCHAR(50), + email VARCHAR(50) NOT NULL, + gender VARCHAR(10), + name VARCHAR(20) NOT NULL, + password VARCHAR(100), + phone_number VARCHAR(20), + provider VARCHAR(10), + role VARCHAR(20), + status VARCHAR(10) NOT NULL, + street_address VARCHAR(50), + zip_code VARCHAR(5) ); CREATE TABLE event diff --git a/http/bingterpark.http b/http/bingterpark.http index 5188fa2f..4481b668 100644 --- a/http/bingterpark.http +++ b/http/bingterpark.http @@ -12,7 +12,7 @@ Content-Type: application/json ### 공연장 등록 POST http://localhost:8080/api/v1/event-halls Content-Type: application/json -Authorization: Bearer eyJhbGciOiJIUzM4NCJ9.eyJpZCI6Miwic3ViIjoiYWRtaW5AZXhhbXBsZS5jb20iLCJpYXQiOjE3MDUwMjQxNzgsImV4cCI6MTcwNTAyNTk3OCwiYXV0aG9yaXR5IjoiUk9MRV9BRE1JTiJ9.V5-9yIMRhoIB2ivtCvrZV7I4fTVvlkKyJ6nwA5UpijOolOj8xfc-6WevHDyn5hkc +Authorization: Bearer {{adminToken}} { "name": "잠실 종합운동장", @@ -36,6 +36,7 @@ Authorization: Bearer eyJhbGciOiJIUzM4NCJ9.eyJpZCI6Miwic3ViIjoiYWRtaW5AZXhhbXBsZ ### 공연 등록 POST http://localhost:8080/api/v1/events Content-Type: application/json +Authorization: Bearer {{adminToken}} { "title": "히사이시 조 영화음악 콘서트", @@ -53,6 +54,7 @@ Content-Type: application/json ### 공연 회차 생성 POST http://localhost:8080/api/v1/event-times/2 Content-Type: application/json +Authorization: Bearer {{adminToken}} { "round": 1, @@ -63,6 +65,7 @@ Content-Type: application/json ### 공연 좌석 구역 생성 POST http://localhost:8080/api/v1/events/2/seat-area Content-Type: application/json +Authorization: Bearer {{adminToken}} { "requests": [ @@ -80,6 +83,7 @@ Content-Type: application/json ### 공연 좌석 생성 POST http://localhost:8080/api/v1/event-seats/events/2 Content-Type: application/json +Authorization: Bearer {{adminToken}} [ { @@ -147,7 +151,7 @@ http://localhost:8081/login ### 내 정보 확인 GET http://localhost:8081/api/v1/members/me -Authorization: Bearer {{accessToken}} +Authorization: Bearer {{token}} ### 공연 목록 - 리뷰순 GET http://localhost:8080/api/v1/events/sort/ranking?page=1&size=10&genreType=CONCERT&dateOffset=7