From 158538fd82c528a1f5de8e18187f7042f20d5ee0 Mon Sep 17 00:00:00 2001 From: tkdwns414 Date: Thu, 18 Jan 2024 21:18:25 +0900 Subject: [PATCH 1/2] [feat] fix swagger's config --- .../pingleserver/config/SwaggerConfig.java | 13 ++++++++++++- .../pingle/pingleserver/constant/Constants.java | 12 ++++++++++++ .../security/config/SecurityConfig.java | 16 +++------------- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/pingle/pingleserver/config/SwaggerConfig.java b/src/main/java/org/pingle/pingleserver/config/SwaggerConfig.java index 23e522d..cd9cdff 100644 --- a/src/main/java/org/pingle/pingleserver/config/SwaggerConfig.java +++ b/src/main/java/org/pingle/pingleserver/config/SwaggerConfig.java @@ -1,13 +1,24 @@ package org.pingle.pingleserver.config; +import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; +import io.swagger.v3.oas.annotations.security.SecurityScheme; +import io.swagger.v3.oas.annotations.security.SecuritySchemes; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Info; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration +@SecuritySchemes({ + @SecurityScheme( + name = "JWT Authorization", + type = SecuritySchemeType.HTTP, + bearerFormat = "JWT", + scheme = "Bearer" + ) +}) public class SwaggerConfig { - private static final String VERSION = "0.0.1"; + private static final String VERSION = "1.0.0"; @Bean public OpenAPI openAPI() { diff --git a/src/main/java/org/pingle/pingleserver/constant/Constants.java b/src/main/java/org/pingle/pingleserver/constant/Constants.java index 8bc9b39..19df2f3 100644 --- a/src/main/java/org/pingle/pingleserver/constant/Constants.java +++ b/src/main/java/org/pingle/pingleserver/constant/Constants.java @@ -12,5 +12,17 @@ public class Constants { public static final String APPLE_ISSUER_NAME = "iss"; public static final String APPLE_AUDIENCE_NAME = "aud"; public static final String APPLE_SUBJECT_NAME = "sub"; + public static final String[] AUTH_WHITELIST = { + "/v1/auth/login", + "/v1/auth/reissue", + "/actuator/health", + "/test/**", + "/qr/**", + + "/v3/api-docs.html", + "/v3/api-docs/**", + "/swagger-ui/**", + "/swagger-ui.html", + }; } diff --git a/src/main/java/org/pingle/pingleserver/security/config/SecurityConfig.java b/src/main/java/org/pingle/pingleserver/security/config/SecurityConfig.java index 6511d71..86e35ba 100644 --- a/src/main/java/org/pingle/pingleserver/security/config/SecurityConfig.java +++ b/src/main/java/org/pingle/pingleserver/security/config/SecurityConfig.java @@ -1,6 +1,7 @@ package org.pingle.pingleserver.security.config; import lombok.RequiredArgsConstructor; +import org.pingle.pingleserver.constant.Constants; import org.pingle.pingleserver.security.filter.CustomJwtAuthenticationEntryPoint; import org.pingle.pingleserver.security.filter.JwtAuthenticationFilter; import org.springframework.context.annotation.Bean; @@ -20,21 +21,10 @@ public class SecurityConfig { private final JwtAuthenticationFilter jwtAuthenticationFilter; private final CustomJwtAuthenticationEntryPoint customJwtAuthenticationEntryPoint; - private static final String[] AUTH_WHITELIST = { - "/v1/auth/login", - "/v1/auth/reissue", - "/actuator/health", - "/test/**", - "/qr/**", - - "/api-docs.html", - "/api-docs/**", - "/swagger-ui/**" - }; - @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { return http + .cors(AbstractHttpConfigurer::disable) .formLogin(AbstractHttpConfigurer::disable) .httpBasic(AbstractHttpConfigurer::disable) .csrf(AbstractHttpConfigurer::disable) @@ -44,7 +34,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { exceptionHandlingConfigurer.authenticationEntryPoint(customJwtAuthenticationEntryPoint)) .authorizeHttpRequests(authorizationManagerRequestMatcherRegistry -> authorizationManagerRequestMatcherRegistry - .requestMatchers(AUTH_WHITELIST).permitAll() + .requestMatchers(Constants.AUTH_WHITELIST).permitAll() .anyRequest().authenticated()) .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) .build(); From 80462f8643ac6ee21090505be267b96b1ea4dcdc Mon Sep 17 00:00:00 2001 From: tkdwns414 Date: Thu, 18 Jan 2024 22:35:32 +0900 Subject: [PATCH 2/2] [feat] add Swagger annotations --- .../controller/AuthController.java | 3 +- .../controller/MeetingController.java | 3 +- .../controller/OpenApiController.java | 3 +- .../controller/PinController.java | 3 +- .../pingleserver/controller/QrController.java | 3 ++ .../controller/TeamController.java | 3 +- .../controller/TestController.java | 1 + .../controller/UserController.java | 3 +- .../controller/swagger/AuthApi.java | 30 +++++++++++++++++ .../controller/swagger/MeetingApi.java | 30 +++++++++++++++++ .../controller/swagger/OpenApi.java | 16 +++++++++ .../controller/swagger/PinApi.java | 27 +++++++++++++++ .../controller/swagger/TeamApi.java | 33 +++++++++++++++++++ .../controller/swagger/UserApi.java | 30 +++++++++++++++++ 14 files changed, 182 insertions(+), 6 deletions(-) create mode 100644 src/main/java/org/pingle/pingleserver/controller/swagger/AuthApi.java create mode 100644 src/main/java/org/pingle/pingleserver/controller/swagger/MeetingApi.java create mode 100644 src/main/java/org/pingle/pingleserver/controller/swagger/OpenApi.java create mode 100644 src/main/java/org/pingle/pingleserver/controller/swagger/PinApi.java create mode 100644 src/main/java/org/pingle/pingleserver/controller/swagger/TeamApi.java create mode 100644 src/main/java/org/pingle/pingleserver/controller/swagger/UserApi.java diff --git a/src/main/java/org/pingle/pingleserver/controller/AuthController.java b/src/main/java/org/pingle/pingleserver/controller/AuthController.java index e0bd48e..214cccc 100644 --- a/src/main/java/org/pingle/pingleserver/controller/AuthController.java +++ b/src/main/java/org/pingle/pingleserver/controller/AuthController.java @@ -5,6 +5,7 @@ import lombok.RequiredArgsConstructor; import org.pingle.pingleserver.annotation.UserId; import org.pingle.pingleserver.constant.Constants; +import org.pingle.pingleserver.controller.swagger.AuthApi; import org.pingle.pingleserver.dto.common.ApiResponse; import org.pingle.pingleserver.dto.request.LoginRequest; import org.pingle.pingleserver.dto.response.JwtTokenResponse; @@ -15,7 +16,7 @@ @RestController @RequestMapping("/v1/auth") @RequiredArgsConstructor -public class AuthController { +public class AuthController implements AuthApi { private final AuthService authService; diff --git a/src/main/java/org/pingle/pingleserver/controller/MeetingController.java b/src/main/java/org/pingle/pingleserver/controller/MeetingController.java index 4cc5067..f774d61 100644 --- a/src/main/java/org/pingle/pingleserver/controller/MeetingController.java +++ b/src/main/java/org/pingle/pingleserver/controller/MeetingController.java @@ -6,6 +6,7 @@ import org.pingle.pingleserver.annotation.UserId; import org.pingle.pingleserver.annotation.GUserId; import org.pingle.pingleserver.constant.Constants; +import org.pingle.pingleserver.controller.swagger.MeetingApi; import org.pingle.pingleserver.domain.Meeting; import org.pingle.pingleserver.domain.Pin; import org.pingle.pingleserver.dto.common.ApiResponse; @@ -21,7 +22,7 @@ @RestController @RequestMapping("/v1/meetings") @RequiredArgsConstructor -public class MeetingController { +public class MeetingController implements MeetingApi { private final MeetingService meetingService; private final UserMeetingService userMeetingService; diff --git a/src/main/java/org/pingle/pingleserver/controller/OpenApiController.java b/src/main/java/org/pingle/pingleserver/controller/OpenApiController.java index febef35..dce9867 100644 --- a/src/main/java/org/pingle/pingleserver/controller/OpenApiController.java +++ b/src/main/java/org/pingle/pingleserver/controller/OpenApiController.java @@ -1,6 +1,7 @@ package org.pingle.pingleserver.controller; import lombok.RequiredArgsConstructor; +import org.pingle.pingleserver.controller.swagger.OpenApi; import org.pingle.pingleserver.dto.common.ApiResponse; import org.pingle.pingleserver.dto.reponse.LocationResponse; import org.pingle.pingleserver.dto.type.SuccessMessage; @@ -15,7 +16,7 @@ @RestController @RequestMapping("/v1") @RequiredArgsConstructor -public class OpenApiController { +public class OpenApiController implements OpenApi { private final NaverUtil naverUtil; diff --git a/src/main/java/org/pingle/pingleserver/controller/PinController.java b/src/main/java/org/pingle/pingleserver/controller/PinController.java index 6edd7ee..df2a34f 100644 --- a/src/main/java/org/pingle/pingleserver/controller/PinController.java +++ b/src/main/java/org/pingle/pingleserver/controller/PinController.java @@ -3,6 +3,7 @@ import jakarta.annotation.Nullable; import lombok.RequiredArgsConstructor; import org.pingle.pingleserver.annotation.UserId; +import org.pingle.pingleserver.controller.swagger.PinApi; import org.pingle.pingleserver.domain.enums.MCategory; import org.pingle.pingleserver.dto.common.ApiResponse; import org.pingle.pingleserver.dto.reponse.MeetingResponse; @@ -16,7 +17,7 @@ @RestController @RequestMapping("/v1/teams/{teamId}/pins") @RequiredArgsConstructor -public class PinController { +public class PinController implements PinApi { private final PinService pinService; diff --git a/src/main/java/org/pingle/pingleserver/controller/QrController.java b/src/main/java/org/pingle/pingleserver/controller/QrController.java index face717..fa512f5 100644 --- a/src/main/java/org/pingle/pingleserver/controller/QrController.java +++ b/src/main/java/org/pingle/pingleserver/controller/QrController.java @@ -1,5 +1,6 @@ package org.pingle.pingleserver.controller; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; @@ -8,6 +9,7 @@ import java.io.IOException; +@Tag(name = "데모데이용 QR code", description = "데모데이 X 배너용 qrcode(redirect)") @RestController @RequestMapping("/qr") public class QrController { @@ -17,6 +19,7 @@ public class QrController { @Value("${qr.android}") private String androidQr; + @GetMapping("/iOS") public void getiOSQr(HttpServletResponse httpServletResponse) throws IOException { httpServletResponse.sendRedirect(iOSQr); diff --git a/src/main/java/org/pingle/pingleserver/controller/TeamController.java b/src/main/java/org/pingle/pingleserver/controller/TeamController.java index 88e61fe..b1d5390 100644 --- a/src/main/java/org/pingle/pingleserver/controller/TeamController.java +++ b/src/main/java/org/pingle/pingleserver/controller/TeamController.java @@ -4,6 +4,7 @@ import jakarta.validation.constraints.NotBlank; import lombok.RequiredArgsConstructor; import org.pingle.pingleserver.annotation.UserId; +import org.pingle.pingleserver.controller.swagger.TeamApi; import org.pingle.pingleserver.dto.common.ApiResponse; import org.pingle.pingleserver.dto.request.TeamRegisterRequest; import org.pingle.pingleserver.dto.response.SelectedTeamResponse; @@ -18,7 +19,7 @@ @RestController @RequestMapping("v1/teams") @RequiredArgsConstructor -public class TeamController { +public class TeamController implements TeamApi { private final TeamService teamService; diff --git a/src/main/java/org/pingle/pingleserver/controller/TestController.java b/src/main/java/org/pingle/pingleserver/controller/TestController.java index 4000608..f49e5d2 100644 --- a/src/main/java/org/pingle/pingleserver/controller/TestController.java +++ b/src/main/java/org/pingle/pingleserver/controller/TestController.java @@ -3,6 +3,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.pingle.pingleserver.annotation.UserId; +import org.pingle.pingleserver.controller.swagger.TeamApi; import org.pingle.pingleserver.domain.User; import org.pingle.pingleserver.dto.response.JwtTokenResponse; import org.pingle.pingleserver.exception.CustomException; diff --git a/src/main/java/org/pingle/pingleserver/controller/UserController.java b/src/main/java/org/pingle/pingleserver/controller/UserController.java index 7165f06..04fb7a8 100644 --- a/src/main/java/org/pingle/pingleserver/controller/UserController.java +++ b/src/main/java/org/pingle/pingleserver/controller/UserController.java @@ -6,6 +6,7 @@ import org.pingle.pingleserver.annotation.GUserId; import org.pingle.pingleserver.annotation.UserId; import org.pingle.pingleserver.constant.Constants; +import org.pingle.pingleserver.controller.swagger.UserApi; import org.pingle.pingleserver.dto.common.ApiResponse; import org.pingle.pingleserver.dto.response.MyPingleResponse; import org.pingle.pingleserver.dto.response.UserInfoResponse; @@ -19,7 +20,7 @@ @RestController @RequestMapping("/v1/users") @RequiredArgsConstructor -public class UserController { +public class UserController implements UserApi { private final MeetingService meetingService; private final UserService userService; diff --git a/src/main/java/org/pingle/pingleserver/controller/swagger/AuthApi.java b/src/main/java/org/pingle/pingleserver/controller/swagger/AuthApi.java new file mode 100644 index 0000000..088244f --- /dev/null +++ b/src/main/java/org/pingle/pingleserver/controller/swagger/AuthApi.java @@ -0,0 +1,30 @@ +package org.pingle.pingleserver.controller.swagger; + +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 org.pingle.pingleserver.annotation.UserId; +import org.pingle.pingleserver.constant.Constants; +import org.pingle.pingleserver.dto.common.ApiResponse; +import org.pingle.pingleserver.dto.request.LoginRequest; +import org.pingle.pingleserver.dto.response.JwtTokenResponse; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +@Tag(name = "Auth", description = "유저 인증 관련 API") +public interface AuthApi { + + @Operation(summary = "로그인", description = "로그인한다.") + ApiResponse login( + @NotNull @RequestHeader(Constants.PROVIDER_TOKEN_HEADER) String providerToken, + @Valid @RequestBody LoginRequest request); + + @Operation(summary = "토큰 재발급", description = "토큰을 재발급한다.") + ApiResponse reissue( + @NotNull @RequestHeader(Constants.AUTHORIZATION_HEADER) String refreshToken); + + @Operation(summary = "로그아웃", description = "로그아웃한다.") + ApiResponse logout(Long userId); + +} diff --git a/src/main/java/org/pingle/pingleserver/controller/swagger/MeetingApi.java b/src/main/java/org/pingle/pingleserver/controller/swagger/MeetingApi.java new file mode 100644 index 0000000..366f6d5 --- /dev/null +++ b/src/main/java/org/pingle/pingleserver/controller/swagger/MeetingApi.java @@ -0,0 +1,30 @@ +package org.pingle.pingleserver.controller.swagger; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.pingle.pingleserver.annotation.GUserId; +import org.pingle.pingleserver.constant.Constants; +import org.pingle.pingleserver.dto.common.ApiResponse; +import org.pingle.pingleserver.dto.request.MeetingRequest; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; + +@Tag(name = "Meeting", description = "번개 API") +public interface MeetingApi { + + @Operation(summary = "번개 생성", description = "번개를 생성한다.") + ApiResponse createMeeting(@Valid @RequestBody MeetingRequest request, @GUserId Long userId, + @RequestHeader(Constants.TEAM_ID) Long groupId); + @Operation(summary = "번개 참여", description = "번개에 참여한다.") + ApiResponse participateMeeting (@GUserId Long userId, Long meetingId); + + @Operation(summary = "번개 취소", description = "번개 참여를 취소한다.") + ApiResponse cancelMeeting (@GUserId Long userId, Long meetingId); + + @Operation(summary = "번개 참여자 조회", description = "번개 참여자를 조회한다.") + ApiResponse getMeetingParticipants (Long meetingId); + + @Operation(summary = "번개 삭제", description = "번개를 삭제한다.") + ApiResponse deleteMeeting(@GUserId Long userId, Long meetingId); +} diff --git a/src/main/java/org/pingle/pingleserver/controller/swagger/OpenApi.java b/src/main/java/org/pingle/pingleserver/controller/swagger/OpenApi.java new file mode 100644 index 0000000..3d276f9 --- /dev/null +++ b/src/main/java/org/pingle/pingleserver/controller/swagger/OpenApi.java @@ -0,0 +1,16 @@ +package org.pingle.pingleserver.controller.swagger; + + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.pingle.pingleserver.dto.common.ApiResponse; +import org.pingle.pingleserver.dto.reponse.LocationResponse; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; + +@Tag(name = "외부 API", description = "외부(네이버) API") +public interface OpenApi { + @Operation(summary = "지역 정보 검색", description = "네이버 API를 이용해 지역 정보를 조회한다.") + ApiResponse> getLocationInfo(@RequestParam(name = "search") String location); +} diff --git a/src/main/java/org/pingle/pingleserver/controller/swagger/PinApi.java b/src/main/java/org/pingle/pingleserver/controller/swagger/PinApi.java new file mode 100644 index 0000000..c12531b --- /dev/null +++ b/src/main/java/org/pingle/pingleserver/controller/swagger/PinApi.java @@ -0,0 +1,27 @@ +package org.pingle.pingleserver.controller.swagger; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Nullable; +import org.pingle.pingleserver.annotation.UserId; +import org.pingle.pingleserver.domain.enums.MCategory; +import org.pingle.pingleserver.dto.common.ApiResponse; +import org.pingle.pingleserver.dto.reponse.MeetingResponse; +import org.pingle.pingleserver.dto.reponse.PinResponse; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; + +@Tag(name = "Pin", description = "핀 API") +public interface PinApi { + + @Operation(summary = "핀 목록 조회", description = "핀 목록을 조회한다.") + ApiResponse> getPins(Long teamId, MCategory category); + + @Operation(summary = "핀에 속한 미팅 목록 조회", description = "핀에 속한 미팅 목록을 조회한다.") + ApiResponse> getMeetings(@UserId Long userId, + @PathVariable String teamId, + @PathVariable Long pinId, + @Nullable @RequestParam MCategory category); +} diff --git a/src/main/java/org/pingle/pingleserver/controller/swagger/TeamApi.java b/src/main/java/org/pingle/pingleserver/controller/swagger/TeamApi.java new file mode 100644 index 0000000..35788c0 --- /dev/null +++ b/src/main/java/org/pingle/pingleserver/controller/swagger/TeamApi.java @@ -0,0 +1,33 @@ +package org.pingle.pingleserver.controller.swagger; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import org.pingle.pingleserver.annotation.UserId; +import org.pingle.pingleserver.dto.common.ApiResponse; +import org.pingle.pingleserver.dto.request.TeamRegisterRequest; +import org.pingle.pingleserver.dto.response.SelectedTeamResponse; +import org.pingle.pingleserver.dto.response.TeamRegisterResponse; +import org.pingle.pingleserver.dto.response.TeamSearchResultResponse; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; + +@Tag(name = "Team", description = "팀 관련 API") +public interface TeamApi { + @Operation(summary = "팀 검색") + ApiResponse> searchTeams(@NotBlank @RequestParam String name); + + @Operation(summary = "팀 조회") + ApiResponse getTeam(@PathVariable Long teamId); + + @Operation(summary = "팀 가입") + ApiResponse registerTeam( + @UserId Long userId, + @PathVariable Long teamId, + @Valid @RequestBody TeamRegisterRequest request); + +} diff --git a/src/main/java/org/pingle/pingleserver/controller/swagger/UserApi.java b/src/main/java/org/pingle/pingleserver/controller/swagger/UserApi.java new file mode 100644 index 0000000..3a1168a --- /dev/null +++ b/src/main/java/org/pingle/pingleserver/controller/swagger/UserApi.java @@ -0,0 +1,30 @@ +package org.pingle.pingleserver.controller.swagger; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.constraints.NotNull; +import org.pingle.pingleserver.annotation.GUserId; +import org.pingle.pingleserver.annotation.UserId; +import org.pingle.pingleserver.constant.Constants; +import org.pingle.pingleserver.dto.common.ApiResponse; +import org.pingle.pingleserver.dto.response.MyPingleResponse; +import org.pingle.pingleserver.dto.response.UserInfoResponse; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; + +@Tag(name = "User", description = "사용자 정보") +public interface UserApi { + + @Operation(summary = "로그인한 사용자 정보 조회") + ApiResponse getLoginUserInfo(@UserId Long userId); + + @Operation(summary = "내가 참여한 미팅 조회") + ApiResponse> getMyPingles ( + @GUserId Long userId, @NotNull @RequestParam boolean participation, + @RequestHeader(Constants.TEAM_ID)Long teamId); + + @Operation(summary = "회원 탈퇴") + ApiResponse leave(@UserId Long userId, @RequestHeader(Constants.APPLE_LOGOUT_HEADER) String code); +}