Skip to content
11 changes: 10 additions & 1 deletion src/main/java/org/example/studylog/config/SwaggerConfig.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.example.studylog.config;

import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
Expand All @@ -10,8 +12,15 @@
public class SwaggerConfig {
@Bean
public OpenAPI openAPI(){
SecurityScheme securityScheme = new SecurityScheme()
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT");
SecurityRequirement securityRequirement = new SecurityRequirement().addList("bearerAuth");

return new OpenAPI()
.components(new Components())
.components(new Components().addSecuritySchemes("bearerAuth", securityScheme))
.addSecurityItem(securityRequirement)
.info(apiInfo());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package org.example.studylog.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.example.studylog.dto.ProfileResponseDTO;
import org.example.studylog.dto.friend.FriendNameDTO;
import org.example.studylog.dto.friend.FriendRequestDTO;
import org.example.studylog.dto.friend.FriendResponseDTO;
Expand All @@ -24,8 +29,12 @@ public class FriendController {

private final FriendService friendService;

@Operation(summary = "code로 친구 조회", description = "친구 추가 시, code로 친구 조회 API")
@GetMapping(params = "code")
@Operation(summary = "code로 친구 조회", description = "친구 추가 시, code로 친구 조회하는 API")
@ApiResponse(responseCode = "200", description = "사용자 이름 조회 완료",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = FriendNameDTO.class)))
@GetMapping("by-code")
public ResponseEntity<?> findUserByCode(@RequestParam String code) {
// 로그인한 사용자 oauthId 가져오기
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
Expand All @@ -36,6 +45,10 @@ public ResponseEntity<?> findUserByCode(@RequestParam String code) {
}

@Operation(summary = "친구 목록 조회", description = "로그인한 사용자의 친구 목록 조회 API")
@ApiResponse(responseCode = "200", description = "친구 목록 조회 완료",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = FriendResponseDTO.class))))
@GetMapping
public ResponseEntity<?> getFriendList(){
// 로그인한 사용자 oauthId 가져오기
Expand All @@ -47,6 +60,10 @@ public ResponseEntity<?> getFriendList(){
}

@Operation(summary = "친구 검색", description = "친구 목록에서 이름으로 친구 조회 API")
@ApiResponse(responseCode = "200", description = "{query}에 대한 친구 검색 완료",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = FriendResponseDTO.class))))
@GetMapping("/search")
public ResponseEntity<?> getFriendByQuery(@RequestParam String query){
// 로그인한 사용자 oauthId 가져오기
Expand All @@ -57,7 +74,10 @@ public ResponseEntity<?> getFriendByQuery(@RequestParam String query){
return ResponseUtil.buildResponse(200, String.format("\'%s\'에 대한 친구 검색 완료", query), friends);
}

@Operation(summary = "code로 친구 추가", description = "코드로 친구 추가 API")
@Operation(summary = "code로 친구 추가", description = "code로 친구 추가 API")
@ApiResponse(responseCode = "201", description = "친구 추가 완료",
content = @Content(
mediaType = "application/json"))
@PostMapping
public ResponseEntity<?> addFriend(@RequestBody @Valid FriendRequestDTO request) {
// 로그인한 사용자 oauthId 가져오기
Expand All @@ -69,6 +89,10 @@ public ResponseEntity<?> addFriend(@RequestBody @Valid FriendRequestDTO request)
}

@Operation(summary = "친구 삭제", description = "friendId로 친구 삭제 API")
@ApiResponse(responseCode = "200", description = "친구 삭제 완료",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = FriendResponseDTO.class)))
@DeleteMapping("/{friendId}")
public ResponseEntity<?> deleteFriend(@PathVariable Long friendId){
// 로그인한 사용자 oauthId 가져오기
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package org.example.studylog.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.RequiredArgsConstructor;
import org.example.studylog.dto.ProfileResponseDTO;
import org.example.studylog.dto.notification.NotificationListResponseDTO;
import org.example.studylog.service.NotificationService;
import org.example.studylog.util.ResponseUtil;
Expand All @@ -20,6 +26,8 @@ public class NotificationController {

private final NotificationService notificationService;

@Operation(summary = "SSE 구독")
@ApiResponse(content = @Content(schema = @Schema(implementation = SseEmitter.class)))
@GetMapping(value = "/subscribe", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter subscribe() {
// 로그인한 사용자 oauthId 가져오기
Expand All @@ -29,6 +37,11 @@ public SseEmitter subscribe() {
return notificationService.createEmitter(oauthId);
}

@Operation(summary = "알림 목록 조회")
@ApiResponse(responseCode = "200", description = "알림 목록 조회 완료",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = NotificationListResponseDTO.class))))
@GetMapping("/notifications")
public ResponseEntity<?> getNotificationList() {
// 로그인한 사용자 oauthId 가져오기
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package org.example.studylog.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.example.studylog.dto.BackgroundDTO;
import org.example.studylog.dto.oauth.CustomOAuth2User;
import org.example.studylog.dto.quiz.CreateQuizRequestDTO;
import org.example.studylog.dto.quiz.QuizListResponseDTO;
Expand All @@ -30,6 +35,10 @@ public class QuizController {
private final QuizService quizService;

@Operation(summary = "퀴즈 생성", description = "recordId로 친구 생성 API")
@ApiResponse(responseCode = "200", description = "퀴즈 생성 완료",
content = @Content(
mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = QuizResponseDTO.class))))
@PostMapping("/{recordId}")
public ResponseEntity<?> createQuiz(
@AuthenticationPrincipal CustomOAuth2User currentUser,
Expand All @@ -55,6 +64,10 @@ public ResponseEntity<?> createQuiz(
}

@Operation(summary = "퀴즈 상세 조회", description = "quizId로 퀴즈 상세 조회 API")
@ApiResponse(responseCode = "200", description = "퀴즈 상세 조회 완료",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = QuizResponseDTO.class)))
@GetMapping("/{quizId}")
public ResponseEntity<?> getQuiz(@AuthenticationPrincipal CustomOAuth2User currentUser,
@PathVariable Long quizId){
Expand All @@ -73,7 +86,11 @@ public ResponseEntity<?> getQuiz(@AuthenticationPrincipal CustomOAuth2User curre
}
}

@Operation(summary = "퀴즈 상세 조회", description = "quizId로 퀴즈 상세 조회 API")
@Operation(summary = "퀴즈 목록 조회", description = "query, date, categoryId로 퀴즈 상세 조회 API")
@ApiResponse(responseCode = "200", description = "퀴즈 목록 조회 완료",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = QuizListResponseDTO.class)))
@GetMapping
public ResponseEntity<?> getQuizList(
@AuthenticationPrincipal CustomOAuth2User currentUser,
Expand Down
46 changes: 35 additions & 11 deletions src/main/java/org/example/studylog/controller/UserController.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import lombok.extern.slf4j.Slf4j;
import org.example.studylog.dto.*;
import org.example.studylog.dto.oauth.CustomOAuth2User;
import org.example.studylog.dto.oauth.TokenDTO;
import org.example.studylog.service.UserService;
import org.example.studylog.util.ResponseUtil;
import org.springframework.http.MediaType;
Expand All @@ -28,18 +29,33 @@ public class UserController {

private final UserService userService;

@Operation(summary = "프로필 업데이트 api", description = "프로필 생성을 위한 api")
@PostMapping("/profile")
@Operation(summary = "프로필 생성", description = "프로필 생성을 위한 api")
@ApiResponse(
responseCode = "200",
description = "사용자 프로필 생성 완료",
content = @Content(
mediaType = "application/json",
schema = @Schema(
implementation = ProfileResponseDTO.class
)))
@PostMapping(path = "/profile", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<?> createProfile(@Valid @ModelAttribute ProfileCreateRequestDTO request) {
// 로그인한 사용자 oauthId 가져오기
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String oauthId = auth.getName();
log.info("사용자 프로필 생성 시작: oauthId = {}", oauthId);

ProfileResponseDTO dto = userService.createUserProfile(request, oauthId);
log.info("사용자 프로필 생성 완료: profileImage = {}, nickname = {}, intro = {}",
dto.getProfileImage(), dto.getNickname(), dto.getIntro());
return ResponseUtil.buildResponse(200, "사용자 프로필 생성 완료", dto);
}

@Operation(summary = "프로필 수정 api", description = "프로필 수정을 위한 api")
@Operation(summary = "프로필 수정", description = "프로필 수정을 위한 api")
@ApiResponse(responseCode = "200", description = "사용자 프로필 수정 완료",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ProfileResponseDTO.class)))
@PatchMapping(path = "/profile", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<?> updateProfile(@ModelAttribute ProfileUpdateRequestDTO request) {
// 로그인한 사용자 oauthId 가져오기
Expand All @@ -50,10 +66,12 @@ public ResponseEntity<?> updateProfile(@ModelAttribute ProfileUpdateRequestDTO r
return ResponseUtil.buildResponse(200, "사용자 프로필 수정 완료", dto);
}

@Operation(summary = "프로필 조회 api")
@Operation(summary = "프로필 조회")
@GetMapping("/profile")
@ApiResponse(responseCode = "200", description = "성공 시 data 필드는 다음과 같습니다",
content = @Content(schema = @Schema(implementation = ProfileResponseDTO.class)))
@ApiResponse(responseCode = "200", description = "사용자 프로필 조회 성공",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ProfileResponseDTO.class)))
public ResponseEntity<?> getProfile() {
// 로그인한 사용자 oauthId 가져오기
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
Expand All @@ -63,7 +81,11 @@ public ResponseEntity<?> getProfile() {
return ResponseUtil.buildResponse(200, "사용자 프로필 조회 성공", dto);
}

@Operation(summary = "로그인 유저의 마이페이지 조회 api")
@Operation(summary = "로그인 유저의 마이페이지 조회")
@ApiResponse(responseCode = "200", description = "사용자 정보 조회 성공",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = UserInfoResponseDTO.class)))
@GetMapping
public ResponseEntity<?> getUserInfo() {
// 로그인한 사용자 oauthId 가져오기
Expand All @@ -74,10 +96,12 @@ public ResponseEntity<?> getUserInfo() {
return ResponseUtil.buildResponse(200, "사용자 정보 조회 성공", dto);
}

@Operation(summary = "배경화면 수정 api")
@PatchMapping("/background")
@ApiResponse(responseCode = "200", description = "성공 시 data 필드는 다음과 같습니다",
content = @Content(schema = @Schema(implementation = BackgroundDTO.ResponseDTO.class)))
@Operation(summary = "배경화면 수정")
@PatchMapping(path = "/background", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ApiResponse(responseCode = "200", description = "사용자 배경화면 수정 완료",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = BackgroundDTO.ResponseDTO.class)))
public ResponseEntity<?> updateBackground(
@AuthenticationPrincipal CustomOAuth2User currentUser,
@Valid @ModelAttribute BackgroundDTO.RequestDTO dto) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
package org.example.studylog.controller.jwt;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.example.studylog.dto.ResponseDTO;
import org.example.studylog.dto.oauth.TokenDTO;
import org.example.studylog.entity.user.User;
import org.example.studylog.jwt.JWTUtil;
import org.example.studylog.service.TokenService;
import org.example.studylog.util.CookieUtil;
import org.example.studylog.util.ResponseUtil;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -27,6 +32,25 @@ public AuthController(JWTUtil jwtUtil, TokenService tokenService) {
this.tokenService = tokenService;
}

@Operation(summary = "AccessToken 재발급 API",
parameters = {
@Parameter(
in = ParameterIn.COOKIE,
name = "refresh",
required = true,
description = "리프레시 토큰"
)
})
@ApiResponse(
responseCode = "200",
description = "토큰 재발급 완료",
content = @Content(
mediaType = "application/json",
schema = @Schema(
name = "TokenResponseDTO",
implementation = TokenDTO.ResponseDTO.class
))
)
@PostMapping("/token-reissue")
public ResponseEntity<?> reissue(HttpServletRequest request, HttpServletResponse response){

Expand Down
4 changes: 4 additions & 0 deletions src/main/java/org/example/studylog/dto/oauth/TokenDTO.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package org.example.studylog.dto.oauth;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;


@Getter
@Builder
@Schema(name = "TokenDTO")
public class TokenDTO {

private String refreshToken;
Expand All @@ -15,6 +18,7 @@ public class TokenDTO {

@Getter
@Builder
@Schema(name = "TokenResponseDTO")
public static class ResponseDTO {
private String accessToken;
private String code;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.example.studylog.dto.oauth.CustomOAuth2User;
import org.example.studylog.entity.user.User;
import org.example.studylog.repository.UserRepository;
Expand All @@ -14,6 +15,7 @@

import java.io.IOException;

@Slf4j
public class ProfileCheckFilter extends OncePerRequestFilter {

private final UserRepository userRepository;
Expand All @@ -38,7 +40,8 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse

// /signup, /users/profile의 PUT 요청은 허용, 그 외는 막음
if(!isProfileCompleted && !requestURI.startsWith("/signup")&&
!(requestURI.equals("/users/profile") && method.equalsIgnoreCase("PUT"))) {
!(requestURI.equals("/users/profile") && method.equalsIgnoreCase("POST"))) {
log.info("ProfileCheckFilter로 인해 /signup으로 리다이렉션");
response.sendRedirect("/signup");
return;
}
Expand Down