diff --git a/build.gradle b/build.gradle index 30ef1a3..64e1acd 100644 --- a/build.gradle +++ b/build.gradle @@ -22,15 +22,12 @@ repositories { } dependencies { - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-security' - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.4' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'com.mysql:mysql-connector-j' implementation 'io.jsonwebtoken:jjwt:0.9.1' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' - testImplementation 'org.springframework.boot:spring-boot-starter-test' - developmentOnly 'org.springframework.boot:spring-boot-devtools' } diff --git a/src/main/java/com/powersupply/PES/answer/controller/AnswerController.java b/src/main/java/com/powersupply/PES/answer/controller/AnswerController.java index 90c6307..6c122e3 100644 --- a/src/main/java/com/powersupply/PES/answer/controller/AnswerController.java +++ b/src/main/java/com/powersupply/PES/answer/controller/AnswerController.java @@ -3,11 +3,6 @@ import com.powersupply.PES.answer.dto.AnswerDTO; import com.powersupply.PES.answer.service.AnswerService; import com.powersupply.PES.utils.ResponseUtil; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -15,61 +10,33 @@ @RestController @RequiredArgsConstructor -@Tag(name = "Answer", description = "답변 관련 API") public class AnswerController { private final AnswerService answerService; - @Operation(summary = "답변 생성", description = "사용자가 답변을 생성합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "201", description = "답변 생성 성공"), - @ApiResponse(responseCode = "400", description = "잘못된 요청"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // answerEntity 만들기 @PostMapping("/api/answer") - public ResponseEntity createAnswer( - @Parameter(description = "회원 이메일", example = "user@example.com") @RequestParam("memberEmail") String email, - @Parameter(description = "문제 ID", example = "1") @RequestParam("problemId") Long problemId) { + public ResponseEntity createAnswer(@RequestParam("memberEmail") String email, @RequestParam("problemId") Long problemId) { return ResponseEntity.status(HttpStatus.CREATED).body(answerService.createAnswer(email, problemId)); } - @Operation(summary = "질문 및 답변 조회", description = "특정 답변 ID에 대한 질문과 답변을 조회합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "조회 성공(토큰에 문제가 없고 유저를 DB에서 찾을 수 있는 경우)"), - @ApiResponse(responseCode = "404", description = "해당 answerId를 찾을 수 없는 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 질문, 답변 가져오기 @GetMapping("/api/answer/{answerId}") - public ResponseEntity getAnswer( - @Parameter(description = "답변 ID", example = "1") @PathVariable Long answerId) { + public ResponseEntity getAnswer(@PathVariable Long answerId) { return ResponseEntity.ok().body(answerService.getAnswer(answerId)); } - @Operation(summary = "답변하기", description = "사용자가 특정 답변 ID에 대해 답변을 작성합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "답변 작성 성공"), - @ApiResponse(responseCode = "400", description = "answer 내용이 null인 경우 or 이미 댓글이 있어 수정이 불가능 한 경우"), - @ApiResponse(responseCode = "404", description = "answer의 주인과 토큰이 다른 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 답변하기 @PostMapping("/api/answer/{answerId}") - public ResponseEntity postAnswer( - @Parameter(description = "답변 ID", example = "1") @PathVariable Long answerId, - @RequestBody AnswerDTO.AnswerContent dto) { + public ResponseEntity postAnswer(@PathVariable Long answerId, + @RequestBody AnswerDTO.AnswerContent dto) { answerService.postAnswer(answerId, dto); return ResponseUtil.successResponse(""); } - @Operation(summary = "풀이 보기", description = "특정 문제 ID에 대한 풀이 목록을 조회합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "201", description = "토큰에 문제가 없고 유저를 DB에서 찾을 수 있는 경우"), - @ApiResponse(responseCode = "204", description = "아직 푼 사람이 없는 경우"), - @ApiResponse(responseCode = "404", description = "problemId가 잘못된 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 풀이 보기 @GetMapping("/api/answerlist/{problemId}") - public ResponseEntity getAnswerList( - @Parameter(description = "문제 ID", example = "1") @PathVariable Long problemId) { + public ResponseEntity getAnswerList(@PathVariable Long problemId) { return answerService.getAnswerList(problemId); } -} \ No newline at end of file +} diff --git a/src/main/java/com/powersupply/PES/comment/controller/CommentController.java b/src/main/java/com/powersupply/PES/comment/controller/CommentController.java index a6e41bf..d12680d 100644 --- a/src/main/java/com/powersupply/PES/comment/controller/CommentController.java +++ b/src/main/java/com/powersupply/PES/comment/controller/CommentController.java @@ -2,46 +2,26 @@ import com.powersupply.PES.comment.dto.CommentDTO; import com.powersupply.PES.comment.service.CommentService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @RestController @RequiredArgsConstructor -@Tag(name = "Comment", description = "댓글 관련 API") public class CommentController { private final CommentService commentService; - @Operation(summary = "댓글 조회", description = "특정 답변 ID에 대한 댓글을 조회합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "조회 성공"), - @ApiResponse(responseCode = "204", description = "댓글이 없는 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 댓글 가져오기 @GetMapping("/api/comment/{answerId}") - public ResponseEntity getComment( - @Parameter(description = "답변 ID", example = "1") @PathVariable Long answerId) { + public ResponseEntity getComment(@PathVariable Long answerId) { return commentService.getComment(answerId); } - @Operation(summary = "댓글 달기", description = "특정 답변 ID에 대해 댓글을 작성합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "201", description = "토큰에 문제가 없고 유저를 DB에서 찾아 정상적으로 댓글을 생성한 경우"), - @ApiResponse(responseCode = "400", description = "이미 자신의 댓글이 있는 경우"), - @ApiResponse(responseCode = "403", description = "재학생이 아닌 경우 / jwt 문제 / 자신의 답변에 댓글을 단 경우 / 최대 댓글 수 도달"), - @ApiResponse(responseCode = "404", description = "answerId가 잘못된 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 댓글 달기 @PostMapping("/api/comment/{answerId}") - public ResponseEntity createComment( - @Parameter(description = "답변 ID", example = "1") @PathVariable Long answerId, - @RequestBody CommentDTO.CreateComment dto) { + public ResponseEntity createComment(@PathVariable Long answerId, + @RequestBody CommentDTO.CreateComment dto) { return commentService.createComment(answerId, dto); } } diff --git a/src/main/java/com/powersupply/PES/configuration/JwtFilter.java b/src/main/java/com/powersupply/PES/configuration/JwtFilter.java index e19f82b..e86e8aa 100644 --- a/src/main/java/com/powersupply/PES/configuration/JwtFilter.java +++ b/src/main/java/com/powersupply/PES/configuration/JwtFilter.java @@ -26,25 +26,10 @@ public class JwtFilter extends OncePerRequestFilter { private final String secretKey; // 인증이 필요없는 경로 URL 목록 - private final List skipUrls = Arrays.asList( - "/api/signin", - "/api/signup", - "/api/finduser", - "/swagger-ui/**", - "/v3/api-docs/**", - "/swagger-resources/**", - "/webjars/**" - ); + private final List skipUrls = Arrays.asList("/api/signin", "/api/signup", "/api/finduser"); // 인증이 필요 없는 GET 요청의 URL 목록 - private final List skipGetUrls = Arrays.asList( - "/api/problemlist/", - "/api/answer/**", - "/api/comment/**", - "/api/answerlist/**", - "/api/rank/**", - "/api/admin/**" - ); + private final List skipGetUrls = Arrays.asList("/api/problemlist/" , "/api/answer/**", "/api/comment/**", "/api/answerlist/**", "/api/rank/**", "/api/admin/**"); @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { @@ -61,7 +46,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse } // 인증이 필요없는 경로는 바로 통과 - if (skipUrls.stream().anyMatch(uri -> pathMatcher.match(uri, requestURI))) { + if (skipUrls.contains(requestURI)) { log.info("인증 필요 없음 : {}", requestURI); filterChain.doFilter(request, response); return; diff --git a/src/main/java/com/powersupply/PES/configuration/SecurityConfig.java b/src/main/java/com/powersupply/PES/configuration/SecurityConfig.java index 889f187..cdd86a4 100644 --- a/src/main/java/com/powersupply/PES/configuration/SecurityConfig.java +++ b/src/main/java/com/powersupply/PES/configuration/SecurityConfig.java @@ -5,14 +5,14 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; +import org.springframework.security.access.expression.SecurityExpressionHandler; +import org.springframework.security.access.hierarchicalroles.RoleHierarchy; +import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; @@ -28,25 +28,18 @@ public class SecurityConfig { @Value("${jwt.secret}") private String secretKey; - @Value("${admin.username}") - private String adminUsername; - - @Value("${admin.password}") - private String adminPassword; - @Bean - public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception { + public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception{ return httpSecurity - .httpBasic().and() // 기본 인증 활성화 - .csrf().disable() // CSRF 비활성화 - .cors().configurationSource(corsConfigurationSource()).and() // CORS 설정 + .httpBasic().disable() // UI쪽 들어오는거 disable + .csrf().disable() // cross site 기능 + .cors().configurationSource(corsConfigurationSource()).and() // cross site 도메인 다른 경우 허용 .authorizeRequests() - .antMatchers("/api/signin", "/api/signup").permitAll() // 기본 요청 허용 - .antMatchers("/swagger-ui/**", "/v3/api-docs/**", "/swagger-resources/**", "/webjars/**").authenticated() // Swagger 경로에 대한 접근 제한 - .antMatchers(HttpMethod.GET, "/api/problemlist", "/api/answer/**", "/api/comment/**", "/api/answerlist/**", "/api/rank/**", "/api/notice/**", "/api/admin/**").permitAll() - .antMatchers(HttpMethod.POST, "/api/comment/**").hasRole("REGULAR_STUDENT") - .antMatchers(HttpMethod.POST, "/api/notice/**").hasRole("MANAGER") - .antMatchers(HttpMethod.PATCH, "/api/notice/**").hasRole("MANAGER") + .antMatchers("/api/signin","/api/signup").permitAll() // 기본 요청 언제나 접근 가능 + .antMatchers(HttpMethod.GET, "/api/problemlist" , "/api/answer/**", "/api/comment/**", "/api/answerlist/**", "/api/rank/**", "/api/notice/**", "/api/admin/**").permitAll() + .antMatchers(HttpMethod.POST,"/api/comment/**").hasRole("REGULAR_STUDENT") + .antMatchers(HttpMethod.POST,"/api/notice/**").hasRole("MANAGER") + .antMatchers(HttpMethod.PATCH,"/api/notice/**").hasRole("MANAGER") .anyRequest().hasRole("USER") .and() .sessionManagement() @@ -60,38 +53,31 @@ public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOrigins(Arrays.asList("https://www.pes23.com", "https://pes23.com", "http://localhost:8080")); + configuration.setAllowedOrigins(Arrays.asList("https://www.pes23.com", "https://pes23.com")); // 여기에 IP 추가 configuration.setAllowedMethods(Arrays.asList("POST", "GET", "OPTIONS", "PUT", "DELETE", "PATCH")); configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "Content-Type")); - configuration.setAllowCredentials(true); + configuration.setAllowCredentials(true); // 필요한 경우, 쿠키와 함께 요청을 보내는 것을 허용 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); - source.registerCorsConfiguration("/**", configuration); + source.registerCorsConfiguration("/**", configuration); // 모든 URL에 대해 설정 적용 return source; } @Bean - public UserDetailsService userDetailsService() { - InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); - manager.createUser(User.withUsername(adminUsername).password("{noop}" + adminPassword).roles("ADMIN").build()); - return manager; + public SecurityExpressionHandler customWebSecurityExpressionHandler() { + DefaultWebSecurityExpressionHandler defaultWebSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler(); + defaultWebSecurityExpressionHandler.setRoleHierarchy(roleHierarchy()); + return defaultWebSecurityExpressionHandler; } @Bean - public PasswordEncoder passwordEncoder() { - return new NoOpPasswordEncoder(); - } -} - -class NoOpPasswordEncoder implements PasswordEncoder { - @Override - public String encode(CharSequence rawPassword) { - return rawPassword.toString(); - } - - @Override - public boolean matches(CharSequence rawPassword, String encodedPassword) { - return rawPassword.toString().equals(encodedPassword); + public RoleHierarchy roleHierarchy() { + RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl(); + //roleHierarchy.setHierarchy("ROLE_MANAGER > ROLE_REGULAR_STUDENT > ROLE_USER and ROLE_NEW_STUDENT > ROLE_USER"); + String hierarchy = "ROLE_ADMIN > ROLE_MANAGER > ROLE_REGULAR_STUDENT > ROLE_USER\n" + + "ROLE_NEW_STUDENT > ROLE_USER"; + roleHierarchy.setHierarchy(hierarchy); + return roleHierarchy; } -} +} \ No newline at end of file diff --git a/src/main/java/com/powersupply/PES/manage/controller/ManageController.java b/src/main/java/com/powersupply/PES/manage/controller/ManageController.java index b639f9c..12d8d41 100644 --- a/src/main/java/com/powersupply/PES/manage/controller/ManageController.java +++ b/src/main/java/com/powersupply/PES/manage/controller/ManageController.java @@ -3,11 +3,6 @@ import com.powersupply.PES.manage.dto.ManageDTO; import com.powersupply.PES.member.entity.MemberEntity; import com.powersupply.PES.manage.service.ManageService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -18,161 +13,90 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/admin") -@Tag(name = "Manage", description = "관리 기능 API") public class ManageController { private final ManageService manageService; /* ---------- 문제 관리 기능 ---------- */ - @Operation(summary = "전체 문제 리스트 불러오기", description = "전체 문제 리스트를 불러옵니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "조회 성공"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 전체 문제 리스트 불러오기 @GetMapping("/problemlist") public ResponseEntity> problemList() { List problemList = manageService.problemList(); return ResponseEntity.ok().body(problemList); } - @Operation(summary = "특정 문제 detail 불러오기", description = "특정 문제의 상세 정보를 불러옵니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "조회 성공"), - @ApiResponse(responseCode = "404", description = "해당 problemId가 없을 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 특정 문제 detail 불러오기 @GetMapping("/problem/{problemId}") - public ResponseEntity problemDetail( - @Parameter(description = "문제 ID", example = "1") @PathVariable Long problemId) { + public ResponseEntity problemDetail(@PathVariable Long problemId) { return ResponseEntity.ok().body(manageService.problemDetail(problemId)); } - @Operation(summary = "문제 등록하기", description = "새로운 문제를 등록합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "201", description = "등록 성공"), - @ApiResponse(responseCode = "403", description = "관리자 권한이 없는 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 문제 등록하기 @PostMapping("/problem") public ResponseEntity postProblem(@RequestBody ManageDTO.ProblemRequestDto requestDto) throws IOException { return ResponseEntity.ok(manageService.postProblem(requestDto)); } - @Operation(summary = "문제 수정하기", description = "기존 문제를 수정합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "수정 성공"), - @ApiResponse(responseCode = "404", description = "해당 problemId가 없을 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 문제 수정하기 @PatchMapping("/problem/{problemId}") - public ResponseEntity patchProblem( - @Parameter(description = "문제 ID", example = "1") @PathVariable Long problemId, - @RequestBody ManageDTO.ProblemRequestDto requestDto) { + public ResponseEntity patchProblem(@PathVariable Long problemId, @RequestBody ManageDTO.ProblemRequestDto requestDto) { return manageService.patchProblem(problemId, requestDto); } /* ---------- 회원 관리 기능 ---------- */ - @Operation(summary = "전체 멤버 리스트 불러오기", description = "전체 멤버 리스트를 불러옵니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "조회 성공"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 전체 멤버 리스트 불러오기 @GetMapping("/memberlist") public ResponseEntity> list() { List memberList = manageService.list(); + return ResponseEntity.ok().body(memberList); } - @Operation(summary = "특정 멤버 detail 불러오기", description = "특정 멤버의 상세 정보를 불러옵니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "조회 성공"), - @ApiResponse(responseCode = "404", description = "해당 memberId가 없을 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 특정 멤버 detail 불러오기 @GetMapping("/member/{memberId}") - public ResponseEntity readDetail( - @Parameter(description = "멤버 ID", example = "user123") @PathVariable String memberId) { + public ResponseEntity readDetail(@PathVariable String memberId) { return ResponseEntity.ok().body(manageService.readDetail(memberId)); } - @Operation(summary = "멤버 삭제하기", description = "특정 멤버를 삭제합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "삭제 성공"), - @ApiResponse(responseCode = "403", description = "관리자 권한이 없는 경우"), - @ApiResponse(responseCode = "404", description = "해당 memberId가 없을 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 멤버 삭제하기 @DeleteMapping("/member/{memberId}") - public ResponseEntity deleteMember( - @Parameter(description = "멤버 ID", example = "user123") @PathVariable String memberId) { + public ResponseEntity deleteMember(@PathVariable String memberId) { return manageService.deleteMember(memberId); } - @Operation(summary = "멤버 상태 수정하기", description = "특정 멤버의 상태를 수정합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "수정 성공"), - @ApiResponse(responseCode = "403", description = "관리자 권한이 없는 경우"), - @ApiResponse(responseCode = "404", description = "해당 memberId가 없을 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 멤버 상태 수정하기 @PutMapping("/member/{memberId}") - public ResponseEntity updateMemberStatus( - @Parameter(description = "멤버 ID", example = "user123") @PathVariable String memberId, - @RequestBody ManageDTO.MemberUpdateRequestDto requestDto) { + public ResponseEntity updateMemberStatus(@PathVariable String memberId, @RequestBody ManageDTO.MemberUpdateRequestDto requestDto) { return ResponseEntity.ok(manageService.updateMemberStatus(memberId, requestDto)); } /* ---------- 질문 관리 기능 ---------- */ - @Operation(summary = "문제 별 질문 목록 가져오기", description = "특정 문제에 대한 질문 목록을 불러옵니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "조회 성공"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 문제 별 질문 목록 가져오기 @GetMapping("/questionlist/{problemId}") - public ResponseEntity> questionList( - @Parameter(description = "문제 ID", example = "1") @PathVariable Long problemId) { + public ResponseEntity> questionList(@PathVariable Long problemId) { List questionList = manageService.questionList(problemId); + return ResponseEntity.ok().body(questionList); } - @Operation(summary = "질문 등록하기", description = "특정 문제에 대해 질문을 등록합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "201", description = "등록 성공"), - @ApiResponse(responseCode = "400", description = "관리자 권한이 없는 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 질문 등록하기 @PostMapping("/question/{problemId}") - public ResponseEntity postQuestion( - @Parameter(description = "문제 ID", example = "1") @PathVariable Long problemId, - @RequestBody ManageDTO.QuestionRequestDto requestDto) { + public ResponseEntity postQuestion(@PathVariable Long problemId, @RequestBody ManageDTO.QuestionRequestDto requestDto) { return ResponseEntity.ok(manageService.postQuestion(problemId, requestDto)); } - @Operation(summary = "질문 수정하기", description = "기존 질문을 수정합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "수정 성공"), - @ApiResponse(responseCode = "404", description = "해당 questionId가 없을 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 질문 수정하기 @PatchMapping("/question/{questionId}") - public ResponseEntity patchQuestion( - @Parameter(description = "질문 ID", example = "1") @PathVariable Long questionId, - @RequestBody ManageDTO.QuestionRequestDto requestDto) { + public ResponseEntity patchQuestion(@PathVariable Long questionId, @RequestBody ManageDTO.QuestionRequestDto requestDto) { return ResponseEntity.ok(manageService.updateQuestion(questionId, requestDto)); } - @Operation(summary = "질문 삭제하기", description = "특정 질문을 삭제합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "삭제 성공"), - @ApiResponse(responseCode = "404", description = "해당 questionId가 없을 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 질문 삭제하기 @DeleteMapping("/question/{questionId}") - public ResponseEntity deleteQuestion( - @Parameter(description = "질문 ID", example = "1") @PathVariable Long questionId) { + public ResponseEntity deleteQuestion(@PathVariable Long questionId) { return ResponseEntity.ok(manageService.deleteQuestion(questionId)); } } diff --git a/src/main/java/com/powersupply/PES/member/controller/MemberController.java b/src/main/java/com/powersupply/PES/member/controller/MemberController.java index 4f05fe6..f419dc0 100644 --- a/src/main/java/com/powersupply/PES/member/controller/MemberController.java +++ b/src/main/java/com/powersupply/PES/member/controller/MemberController.java @@ -3,10 +3,6 @@ import com.powersupply.PES.member.dto.MemberDTO; import com.powersupply.PES.member.service.MemberService; import com.powersupply.PES.utils.ResponseUtil; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -15,19 +11,14 @@ import javax.servlet.http.HttpServletResponse; import java.time.LocalDate; import java.util.List; + @RestController @RequiredArgsConstructor -@Tag(name = "Member", description = "회원 관련 API") public class MemberController { private final MemberService memberService; - @Operation(summary = "회원가입 정보 저장", description = "회원가입 정보를 저장하는 메서드입니다.") - @ApiResponses({ - @ApiResponse(responseCode = "201", description = "회원가입 성공"), - @ApiResponse(responseCode = "400", description = "서버에 해당 이메일,번호, 아이디가 겹치는 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 회원가입 정보 저장 @PostMapping("/api/signup") public ResponseEntity postSignUp(@RequestBody MemberDTO.MemberSignUpRequest dto) { String name = memberService.signUp(dto); @@ -35,12 +26,7 @@ public ResponseEntity postSignUp(@RequestBody MemberDTO.MemberSignUpRequest d return ResponseUtil.createResponse(name + "님, 가입에 성공했습니다."); } - @Operation(summary = "로그인 진행", description = "로그인 시 jwt 토큰을 반환해 로그인을 승인하는 메서드입니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "로그인 성공"), - @ApiResponse(responseCode = "401", description = "로그인 실패"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 로그인 진행 @PostMapping("/api/signin") public ResponseEntity postSignIn(HttpServletResponse response, @RequestBody MemberDTO.MemberSignInRequest dto) { String token = memberService.signIn(dto); @@ -55,8 +41,7 @@ public ResponseEntity postSignIn(HttpServletResponse response, @RequestBody M return ResponseUtil.successResponse("로그인에 성공했습니다."); } - @Operation(summary = "로그아웃 진행", description = "로그아웃을 진행하는 메서드입니다.") - @ApiResponse(responseCode = "200", description = "로그아웃 성공") + // 로그아웃 진행 @PostMapping("/api/logout") public ResponseEntity postLogout(HttpServletResponse response) { Cookie logoutCookie = new Cookie("Authorization", null); @@ -69,58 +54,37 @@ public ResponseEntity postLogout(HttpServletResponse response) { return ResponseUtil.successResponse("로그아웃 되었습니다."); } - @Operation(summary = "마이페이지 정보 조회", description = "클라이언트가 요청한 마이페이지 정보를 조회하는 메서드입니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "회원 정보가 존재하여 반환에 성공"), - @ApiResponse(responseCode = "401", description = "회원 정보가 존재하지 않는 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 마이페이지(정보) @GetMapping("/api/mypage/information") public ResponseEntity getMyPageInfo() { + return ResponseEntity.ok().body(memberService.getMyPage()); } - @Operation(summary = "마이페이지 내가 푼 문제 조회", description = "클라이언트가 요청한 내가 푼 문제 정보를 조회하는 메서드입니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "조회 성공"), - @ApiResponse(responseCode = "204", description = "리스트가 비어있는 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 마이페이지(내가 푼 문제) @GetMapping("/api/mypage/mysolve") public ResponseEntity getMySolveInfo() { + return memberService.getMySolve(); } - @Operation(summary = "마이페이지 나의 피드백 조회", description = "클라이언트가 요청한 나의 피드백 정보를 조회하는 메서드입니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "조회 성공"), - @ApiResponse(responseCode = "204", description = "리스트가 비어있는 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 마이페이지(나의 피드백) @GetMapping("/api/mypage/myfeedback") public ResponseEntity getMyFeedbackInfo() { + return memberService.getMyFeedback(); } - @Operation(summary = "상단 사용자 정보 조회", description = "상단 사용자 정보를 조회하는 메서드입니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "조회 성공"), - @ApiResponse(responseCode = "204", description = "리스트가 비어있는 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 상단 사용자 정보 @GetMapping("/api/exp") public ResponseEntity myUser() { return ResponseEntity.ok().body(memberService.expVar()); } - @Operation(summary = "주니어 랭킹 조회", description = "주니어 회원의 랭킹을 조회하는 메서드입니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "조회 성공"), - @ApiResponse(responseCode = "204", description = "리스트가 비어있는 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 랭킹 가져오기 @GetMapping("/api/rank/junior") public ResponseEntity> getRank(@RequestParam(value = "memberGen", required = false) Integer memberGen) { + // year이 null이면 현재 현재 기수로 설정 if (memberGen == null) { memberGen = LocalDate.now().getYear() - 1989; } @@ -130,12 +94,7 @@ public ResponseEntity> getRank(@RequestParam(value = "membe return ResponseEntity.ok().body(rank); } - @Operation(summary = "시니어 랭킹 조회", description = "시니어 회원의 랭킹을 조회하는 메서드입니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "조회 성공"), - @ApiResponse(responseCode = "204", description = "리스트가 비어있는 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 재학생 랭킹 가져오기 @GetMapping("/api/rank/senior") public ResponseEntity> getSeniorRank() { List rank = memberService.getSeniorRank(); @@ -143,3 +102,5 @@ public ResponseEntity> getSeniorRank() { return ResponseEntity.ok().body(rank); } } + + diff --git a/src/main/java/com/powersupply/PES/member/dto/MemberDTO.java b/src/main/java/com/powersupply/PES/member/dto/MemberDTO.java index 5e104a7..66c8a2c 100644 --- a/src/main/java/com/powersupply/PES/member/dto/MemberDTO.java +++ b/src/main/java/com/powersupply/PES/member/dto/MemberDTO.java @@ -1,6 +1,5 @@ package com.powersupply.PES.member.dto; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; import lombok.Getter; import lombok.Setter; @@ -8,144 +7,72 @@ public class MemberDTO { @Getter - @Schema(description = "회원 가입 요청 데이터") public static class MemberSignUpRequest { - @Schema(description = "아이디", example = "user123") private String memberId; // 아이디 - - @Schema(description = "비밀번호", example = "password123") private String memberPw; // 멤버 비밀번호 - - @Schema(description = "이름", example = "홍길동") private String memberName; // 이름 - - @Schema(description = "기수", example = "1") private int memberGen; // 기수 - - @Schema(description = "학과", example = "컴퓨터공학과") private String memberMajor; // 학과 - - @Schema(description = "전화번호", example = "010-1234-5678") private String memberPhone; // 전화번호 - - @Schema(description = "이메일", example = "user@example.com") private String memberEmail; // 이메일 } @Getter - @Schema(description = "회원 로그인 요청 데이터") public static class MemberSignInRequest { - @Schema(description = "아이디", example = "user123") private String memberId; // 아이디 - - @Schema(description = "비밀번호", example = "password123") private String memberPw; // 비밀번호 } @Builder @Getter - @Schema(description = "마이페이지 응답 데이터") public static class MemberMyPageResponse { - @Schema(description = "이름", example = "홍길동") private String memberName; // 이름 - - @Schema(description = "기수", example = "1") private int memberGen; // 기수 - - @Schema(description = "학과", example = "컴퓨터공학과") private String memberMajor; // 학과 - - @Schema(description = "전화번호", example = "010-1234-5678") private String memberPhone; // 전화번호 - - @Schema(description = "상태", example = "재학생") private String memberStatus; // 상태 - - @Schema(description = "이메일", example = "user@example.com") private String memberEmail; // 이메일 - - @Schema(description = "점수", example = "100") private int memberScore; // 점수 - - @Schema(description = "아이디", example = "user123") private String memberId; // 아이디 } @Getter @Builder - @Schema(description = "이름과 점수 응답 데이터") public static class NameScoreResponse { - @Schema(description = "이름", example = "홍길동") private String memberName; - - @Schema(description = "상태", example = "재학생") private String memberStatus; - - @Schema(description = "점수", example = "100") private int memberScore; - - @Schema(description = "기수", example = "1") private int memberGen; - - @Schema(description = "새로운 공지 여부", example = "true") private boolean hasNewNotices; } @Getter @Builder - @Schema(description = "내가 푼 문제 응답 데이터") public static class MemberMySolveResponse { - @Schema(description = "문제 ID", example = "1") private Long problemId; - - @Schema(description = "문제 제목", example = "문제 제목 예시") private String problemTitle; - - @Schema(description = "문제 점수", example = "10") private int problemScore; - - @Schema(description = "답변 ID", example = "1") private Long answerId; - - @Schema(description = "답변 상태", example = "완료") private String answerState; - - @Schema(description = "최종 점수", example = "10") private int finalScore; } @Getter @Builder - @Schema(description = "내가 받은 피드백 응답 데이터") public static class MemberMyFeedbackResponse { - @Schema(description = "답변 ID", example = "1") private Long answerId; - - @Schema(description = "기수", example = "1") private int memberGen; - - @Schema(description = "이름", example = "홍길동") private String memberName; - - @Schema(description = "피드백 통과 여부", example = "1") private int commentPassFail; - - @Schema(description = "피드백 내용", example = "잘했습니다.") private String commentContent; } @Getter @Builder @Setter - @Schema(description = "랭킹 데이터") public static class Rank { - @Schema(description = "순위", example = "1") private int rank; - - @Schema(description = "이름", example = "홍길동") private String memberName; - - @Schema(description = "점수", example = "100") private int score; } } diff --git a/src/main/java/com/powersupply/PES/notice/controller/NoticeController.java b/src/main/java/com/powersupply/PES/notice/controller/NoticeController.java index de39a74..3b617ee 100644 --- a/src/main/java/com/powersupply/PES/notice/controller/NoticeController.java +++ b/src/main/java/com/powersupply/PES/notice/controller/NoticeController.java @@ -2,93 +2,53 @@ import com.powersupply.PES.notice.dto.NoticeDTO; import com.powersupply.PES.notice.service.NoticeService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @RestController @RequiredArgsConstructor -@Tag(name = "Notice", description = "공지사항 관련 API") public class NoticeController { private final NoticeService noticeService; - @Operation(summary = "새로운 공지사항 존재 확인", description = "비회원 전용 API로 새로운 공지사항이 있는지 확인합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "정상적으로 통신 완료"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 새로운 공지사항 존재 확인(비회원 전용) @GetMapping("/api/notice/new") public ResponseEntity checkNewNotice() { return noticeService.checkNewNotice(); } - @Operation(summary = "공지사항 등록", description = "새로운 공지사항을 등록합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "공지사항 등록 성공"), - @ApiResponse(responseCode = "403", description = "관리자 권한이 없는 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 공지사항 등록 @PostMapping("/api/notice") public ResponseEntity postNotice(@RequestBody NoticeDTO.BaseNotice dto) { return noticeService.postNotice(dto); } - @Operation(summary = "공지사항 리스트 가져오기", description = "공지사항 리스트를 가져옵니다. state가 true이면 삭제된 공지사항을 포함합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "조회 성공"), - @ApiResponse(responseCode = "204", description = "공지사항이 없는 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 공지사항 리스트 가져오기(state가 true시 삭제된 것 가져오기) @GetMapping("/api/notice") public ResponseEntity getNoticeList(@RequestParam(required = false) boolean state) { return noticeService.getNoticeList(state); } - @Operation(summary = "공지사항 내용 가져오기", description = "특정 공지사항의 내용을 가져옵니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "조회 성공"), - @ApiResponse(responseCode = "404", description = "해당 noticeId가 없을 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 공지사항 내용 가져오기 @GetMapping("/api/notice/{noticeId}") public ResponseEntity getNotice(@PathVariable Long noticeId) { return noticeService.getNotice(noticeId); } - @Operation(summary = "공지사항 수정", description = "특정 공지사항의 내용을 수정합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "수정 성공"), - @ApiResponse(responseCode = "403", description = "관리자 권한이 없는 경우"), - @ApiResponse(responseCode = "404", description = "해당 noticeId가 없을 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 공지사항 수정 @PatchMapping("/api/notice/{noticeId}") public ResponseEntity updateNotice(@PathVariable Long noticeId, @RequestBody NoticeDTO.BaseNotice dto) { return noticeService.updateNotice(noticeId, dto); } - @Operation(summary = "공지사항 복구", description = "삭제된 공지사항을 복구합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "복구 성공"), - @ApiResponse(responseCode = "404", description = "해당 noticeId가 없을 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 공지사항 복구 @PatchMapping("/api/notice/restore/{noticeId}") public ResponseEntity restoreNotice(@PathVariable Long noticeId) { return noticeService.restoreNotice(noticeId); } - @Operation(summary = "공지사항 삭제", description = "특정 공지사항을 삭제합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "삭제 성공"), - @ApiResponse(responseCode = "403", description = "관리자 권한이 없는 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 공지사항 삭제 @DeleteMapping("/api/notice/{noticeId}") public ResponseEntity deleteNotice(@PathVariable Long noticeId) { return noticeService.deleteNotice(noticeId); diff --git a/src/main/java/com/powersupply/PES/problem/controller/ProblemController.java b/src/main/java/com/powersupply/PES/problem/controller/ProblemController.java index 681c15b..f2f91fc 100644 --- a/src/main/java/com/powersupply/PES/problem/controller/ProblemController.java +++ b/src/main/java/com/powersupply/PES/problem/controller/ProblemController.java @@ -1,10 +1,6 @@ package com.powersupply.PES.problem.controller; import com.powersupply.PES.problem.service.ProblemService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -12,20 +8,11 @@ @RestController @RequiredArgsConstructor -@Tag(name = "Problem", description = "문제 관련 API") public class ProblemController { private final ProblemService problemService; - @Operation(summary = "문제 리스트 가져오기", description = "전체 문제 리스트를 가져옵니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "토큰에 문제가 없고 유저를 DB에서 찾을 수 있음\n" + - "- 로그인 되어있고, 해당 문제를 푼 경우 → answerId 및 answerState를 포함하여 전송\n" + - "- 나머지 경우 → answerId 및 answerState는 null로 전송\n" + - "- answerScore가 없은 경우는 null로 전송 → 타입도 Integer임"), - @ApiResponse(responseCode = "204", description = "리스트가 비어있는 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // 문제 리스트 가져오기 @GetMapping("/api/problemlist") public ResponseEntity getProblemList() { return problemService.getProblemList(); diff --git a/src/main/java/com/powersupply/PES/question/controller/QuestionController.java b/src/main/java/com/powersupply/PES/question/controller/QuestionController.java index e2d70a8..0562388 100644 --- a/src/main/java/com/powersupply/PES/question/controller/QuestionController.java +++ b/src/main/java/com/powersupply/PES/question/controller/QuestionController.java @@ -2,10 +2,6 @@ import com.powersupply.PES.question.dto.QuestionDTO; import com.powersupply.PES.question.service.QuestionService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; @@ -16,17 +12,11 @@ @Controller @RequiredArgsConstructor -@Tag(name = "Question", description = "질문 관련 API") public class QuestionController { private final QuestionService questionService; - @Operation(summary = "(재)질문 목록 보기", description = "특정 문제에 대한 (재)질문 목록을 가져옵니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "조회 성공"), - @ApiResponse(responseCode = "404", description = "해당 problemId가 없을 경우"), - @ApiResponse(responseCode = "500", description = "서버 오류") - }) + // (재)질문 목록 보기 @GetMapping("/api/questions/{problemId}") public ResponseEntity> getQuestionList(@PathVariable Long problemId) { return ResponseEntity.ok().body(questionService.getQeustionList(problemId)); diff --git a/src/main/java/com/powersupply/PES/swagger/SwaggerConfig.java b/src/main/java/com/powersupply/PES/swagger/SwaggerConfig.java deleted file mode 100644 index a6f074f..0000000 --- a/src/main/java/com/powersupply/PES/swagger/SwaggerConfig.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.powersupply.PES.swagger; - -import io.swagger.v3.oas.models.info.Info; -import io.swagger.v3.oas.models.Components; -import io.swagger.v3.oas.models.security.SecurityRequirement; -import io.swagger.v3.oas.models.security.SecurityScheme; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import io.swagger.v3.oas.models.OpenAPI; - -@Configuration -public class SwaggerConfig { - @Bean - public OpenAPI openAPI() { - String jwt = "JWT"; - SecurityRequirement securityRequirement = new SecurityRequirement().addList(jwt); - Components components = new Components().addSecuritySchemes(jwt, new SecurityScheme() - .name(jwt) - .type(SecurityScheme.Type.HTTP) - .scheme("bearer") - .bearerFormat("JWT") - ); - return new OpenAPI() - .info(apiInfo()) - .addSecurityItem(securityRequirement) - .components(components); - } - - private Info apiInfo() { - return new Info() - .title("PES") - .description("PES API 명세") - .version("1.0.0"); - } -}