-
Notifications
You must be signed in to change notification settings - Fork 0
version 2.15.3 #304
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
version 2.15.3 #304
Changes from 4 commits
0762d72
ed1721d
054e092
675e8a1
34a700a
656d52b
61244aa
ebae030
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| package com.kustacks.kuring.admin.adapter.in.web.dto; | ||
|
|
||
| import org.springframework.data.domain.Page; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public record AdminAlertListResponse( | ||
| List<AdminAlertResponse> alerts, | ||
| boolean hasNext, | ||
| long totalElements, | ||
| int totalPages | ||
| ) { | ||
|
|
||
| public static AdminAlertListResponse from(Page<AdminAlertResponse> page) { | ||
| return new AdminAlertListResponse( | ||
| page.getContent(), | ||
| page.hasNext(), | ||
| page.getTotalElements(), | ||
| page.getTotalPages() | ||
| ); | ||
| } | ||
| } | ||
|
|
||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| package com.kustacks.kuring.admin.adapter.in.web.dto; | ||
|
|
||
| import com.kustacks.kuring.user.application.port.in.dto.AdminFeedbacksResult; | ||
| import org.springframework.data.domain.Page; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public record AdminFeedbackListResponse( | ||
| List<AdminFeedbacksResult> feedbacks, | ||
| boolean hasNext, | ||
| long totalElements, | ||
| int totalPages | ||
| ) { | ||
|
|
||
| public static AdminFeedbackListResponse from(Page<AdminFeedbacksResult> page) { | ||
| return new AdminFeedbackListResponse( | ||
| page.getContent(), | ||
| page.hasNext(), | ||
| page.getTotalElements(), | ||
| page.getTotalPages() | ||
| ); | ||
| } | ||
| } | ||
|
|
||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| package com.kustacks.kuring.admin.adapter.in.web.dto; | ||
|
|
||
| import com.kustacks.kuring.report.application.port.in.dto.AdminReportsResult; | ||
| import org.springframework.data.domain.Page; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public record AdminReportListResponse( | ||
| List<AdminReportsResult> reports, | ||
| boolean hasNext, | ||
| long totalElements, | ||
| int totalPages | ||
| ) { | ||
|
|
||
| public static AdminReportListResponse from(Page<AdminReportsResult> page) { | ||
| return new AdminReportListResponse( | ||
| page.getContent(), | ||
| page.hasNext(), | ||
| page.getTotalElements(), | ||
| page.getTotalPages() | ||
| ); | ||
| } | ||
| } | ||
|
|
||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,13 @@ | ||
| package com.kustacks.kuring.admin.application.port.out; | ||
|
|
||
| import com.kustacks.kuring.user.application.port.out.dto.FeedbackDto; | ||
| import org.springframework.data.domain.Page; | ||
| import org.springframework.data.domain.Pageable; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public interface AdminUserFeedbackPort { | ||
| List<String> findAllToken(); | ||
| List<FeedbackDto> findAllFeedbackByPageRequest(Pageable pageable); | ||
|
|
||
| Page<FeedbackDto> findAllFeedbackByPageRequest(Pageable pageable); | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -10,14 +10,20 @@ | |||||||
| import com.kustacks.kuring.auth.interceptor.FirebaseTokenAuthenticationFilter; | ||||||||
| import com.kustacks.kuring.auth.interceptor.UserRegisterNonChainingFilter; | ||||||||
| import com.kustacks.kuring.auth.token.JwtTokenProvider; | ||||||||
| import com.kustacks.kuring.message.application.port.in.FirebaseWithUserUseCase; | ||||||||
| import com.kustacks.kuring.common.properties.ServerProperties; | ||||||||
| import com.kustacks.kuring.message.application.port.in.FirebaseWithUserUseCase; | ||||||||
| import com.kustacks.kuring.user.adapter.out.persistence.UserPersistenceAdapter; | ||||||||
| import lombok.RequiredArgsConstructor; | ||||||||
| import org.springframework.boot.web.servlet.FilterRegistrationBean; | ||||||||
| import org.springframework.context.annotation.Bean; | ||||||||
| import org.springframework.context.annotation.Configuration; | ||||||||
| import org.springframework.core.Ordered; | ||||||||
| import org.springframework.security.crypto.factory.PasswordEncoderFactories; | ||||||||
| import org.springframework.security.crypto.password.PasswordEncoder; | ||||||||
| import org.springframework.web.cors.CorsConfiguration; | ||||||||
| import org.springframework.web.cors.UrlBasedCorsConfigurationSource; | ||||||||
| import org.springframework.web.filter.CorsFilter; | ||||||||
| import org.springframework.web.method.support.HandlerMethodArgumentResolver; | ||||||||
| import org.springframework.web.servlet.config.annotation.InterceptorRegistry; | ||||||||
| import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | ||||||||
|
|
||||||||
|
|
@@ -34,6 +40,34 @@ public class AuthConfig implements WebMvcConfigurer { | |||||||
| private final FirebaseWithUserUseCase firebaseService; | ||||||||
| private final UserPersistenceAdapter userPersistenceAdapter; | ||||||||
|
|
||||||||
| @Bean | ||||||||
| public FilterRegistrationBean<CorsFilter> corsFilterRegistration() { | ||||||||
| CorsConfiguration config = new CorsConfiguration(); | ||||||||
|
|
||||||||
| config.setAllowedOriginPatterns(List.of( | ||||||||
| "https://www.ku-ring.com", | ||||||||
| "https://ku-ring.com", | ||||||||
| "http://localhost:[*]", | ||||||||
| "http://127.0.0.1:[*]" | ||||||||
| )); | ||||||||
| config.setAllowedMethods(List.of("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")); | ||||||||
| config.setAllowedHeaders(List.of("*")); // 모든 요청 헤더 허용 | ||||||||
|
|
||||||||
| // [보안 권장] 모든 응답 헤더를 노출하는 대신 필요한 헤더만 명시적으로 노출합니다. | ||||||||
| // 예를 들어, 프론트에서 Authorization 헤더에 담긴 토큰을 읽어야 할 경우 아래와 같이 설정합니다. | ||||||||
| config.setExposedHeaders(List.of("Authorization", "Location")); | ||||||||
|
|
||||||||
| config.setAllowCredentials(true); | ||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. allowCredentials=true 재검토 (쿠키 미사용 시 보안 여지) 쿠키/세션을 사용하지 않고 Authorization 헤더만 사용한다면 다음 변경을 제안합니다: - config.setAllowCredentials(true);
+ // 쿠키 기반 인증이 필요한 경우에만 true
+ config.setAllowCredentials(false);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||
| config.setMaxAge(3600L); | ||||||||
|
|
||||||||
| UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); | ||||||||
| source.registerCorsConfiguration("/**", config); | ||||||||
|
|
||||||||
| FilterRegistrationBean<CorsFilter> registration = new FilterRegistrationBean<>(new CorsFilter(source)); | ||||||||
| registration.setOrder(Ordered.HIGHEST_PRECEDENCE); // [수정] 필터 순서를 가장 높게 설정하여 다른 필터보다 먼저 실행되도록 합니다. | ||||||||
| return registration; | ||||||||
| } | ||||||||
|
|
||||||||
| @Override | ||||||||
| public void addInterceptors(InterceptorRegistry registry) { | ||||||||
| registry.addInterceptor(new SecurityContextPersistenceFilter()); | ||||||||
|
|
@@ -56,7 +90,7 @@ adminDetailsService, passwordEncoder(), objectMapper, | |||||||
| } | ||||||||
|
|
||||||||
| @Override | ||||||||
| public void addArgumentResolvers(List argumentResolvers) { | ||||||||
| public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { | ||||||||
| argumentResolvers.add(new AuthenticationPrincipalArgumentResolver()); | ||||||||
| } | ||||||||
|
|
||||||||
|
|
@@ -84,4 +118,5 @@ AuthenticationSuccessHandler userRegisterSuccessHandler() { | |||||||
| AuthenticationFailureHandler userRegisterFailureHandler() { | ||||||||
| return new UserRegisterFailureHandler(objectMapper); | ||||||||
| } | ||||||||
|
|
||||||||
| } | ||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -49,10 +49,11 @@ public ResponseEntity<BaseResponse<List<NoticeRangeLookupResponse>>> getNotices( | |
| @Parameter(description = "공지 타입") @RequestParam(name = "type") String type, | ||
| @Parameter(description = "학과는 hostPrefix 로 전달") @RequestParam(name = "department", required = false) String department, | ||
| @Parameter(description = "중요도") @RequestParam(name = "important", defaultValue = "false") Boolean important, | ||
| @Parameter(description = "대학원 여부") @RequestParam(name = "graduated", required = false) Boolean graduated, | ||
| @Parameter(description = "페이지") @RequestParam(name = "page") @Min(0) int page, | ||
| @Parameter(description = "단일 페이지의 사이즈, 1 ~ 30까지 허용") @RequestParam(name = "size") @Min(1) @Max(30) int size | ||
| ) { | ||
| NoticeRangeLookupCommand command = new NoticeRangeLookupCommand(type, department, important, page, size); | ||
| NoticeRangeLookupCommand command = new NoticeRangeLookupCommand(type, department, important, graduated, page, size); | ||
| List<NoticeRangeLookupResponse> searchResults = noticeQueryUseCase.getNotices(command) | ||
|
Comment on lines
52
to
64
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chaingraduated 파라미터의 의미와 null 처리 계약을 명확히 해주세요. nullable(Boolean)로 전달되어 하위 계층에서 null 의미(예: 전체, 필터 미적용 등)를 어떻게 해석하는지 명시/검증이 필요합니다. 스웨거 설명에도 기본 동작을 문서화하세요. 필요 시 Optional 또는 enum(ALL/UNDERGRAD/GRAD)로의 전환도 고려해볼 만합니다. 아래 스크립트로 graduated 처리 경로를 점검해 주세요(UseCase/Port/Repository에서 null 안전 여부 확인). 🏁 Script executed: #!/bin/bash
rg -n --type=java -C2 '\bgraduated\b'Length of output: 35847 graduated 파라미터 null 처리 — 긴급 수정 필요 Controller가 @RequestParam(required = false) Boolean graduated로 nullable을 허용하지만, 하위 계층에서 null 검사 없이 departmentNotice.graduated.eq(graduated)를 직접 사용하고 있습니다. graduated == null일 때 의도된 “필터 미적용(전체 조회)”이 아니라 쿼리 조건이 잘못 적용되어 결과가 누락될 위험이 있습니다. 수정(필수)
권장 대안(간단)
🤖 Prompt for AI Agents |
||
| .stream() | ||
| .map(NoticeRangeLookupResponse::from) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Port 시그니처 변경으로 인한 하위 구현/호출부 전파 확인 필요
List→Page로 변경은 어댑터 구현체, 서비스, 컨트롤러, 응답 DTO 래핑(Page DTO)까지 연쇄 영향입니다. 전파 누락 시 런타임 에러 발생합니다.
다음 스크립트로 구현체/호출부의 시그니처 및 사용처를 점검해 주세요:
🏁 Script executed:
Length of output: 17
추가 검증을 위해 다음 스크립트를 실행해 구현체, 호출부, Page 래핑 및 Swagger 스펙 반영 여부를 다시 확인해 주세요.
🏁 Script executed:
Length of output: 9830
확인 완료 — Port 시그니처(Page) 변경이 전파됨
AdminUserFeedbackPort, 구현체 및 호출부에서 Page 반환으로 정상 반영됨 (예: src/main/java/com/kustacks/kuring/admin/application/port/out/AdminUserFeedbackPort.java, src/main/java/com/kustacks/kuring/user/adapter/out/persistence/UserPersistenceAdapter.java, src/main/java/com/kustacks/kuring/user/adapter/out/persistence/UserQueryRepository.java, src/main/java/com/kustacks/kuring/user/adapter/out/persistence/UserQueryRepositoryImpl.java, src/main/java/com/kustacks/kuring/admin/application/service/AdminQueryService.java, src/main/java/com/kustacks/kuring/admin/adapter/in/web/dto/AdminFeedbackListResponse.java).
문제: 테스트 코드에 아직 List로 할당한 사용처가 남아 있음 — src/test/java/com/kustacks/kuring/user/adapter/out/persistence/UserRepositoryTest.java (List feedbackDtos = userPersistenceAdapter.findAllFeedbackByPageRequest(...))를 Page로 변경하거나 .getContent()로 추출하여 수정 필요.
🤖 Prompt for AI Agents