From f968e475a82d52a29827486af3059204698498c0 Mon Sep 17 00:00:00 2001 From: EunjinWoo Date: Thu, 11 Dec 2025 19:48:15 +0900 Subject: [PATCH 01/11] =?UTF-8?q?fix:=20=EA=B4=80=EB=A6=AC=EC=9E=90?= =?UTF-8?q?=EC=9A=A9=20=EC=A7=80=EC=9B=90=EC=84=9C=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EC=B5=9C=EC=8B=A0=EC=88=9C=20=EC=A0=95=EB=A0=AC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20#159?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/controller/AdminApplicationController.java | 4 ++-- .../application/enumerate/AdminApplicationSortField.java | 1 + .../application/service/ApplicationServiceImpl.java | 3 +++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/KUSITMS/WITHUS/domain/application/application/controller/AdminApplicationController.java b/src/main/java/KUSITMS/WITHUS/domain/application/application/controller/AdminApplicationController.java index e38d6b79..4023fe81 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/application/application/controller/AdminApplicationController.java +++ b/src/main/java/KUSITMS/WITHUS/domain/application/application/controller/AdminApplicationController.java @@ -41,8 +41,8 @@ public class AdminApplicationController { public SuccessResponse> getList( @PathVariable Long recruitmentId, @RequestParam(defaultValue = "DOCUMENT") AdminStageFilter stage, - @RequestParam(defaultValue = "NAME") AdminApplicationSortField sortBy, - @RequestParam(defaultValue = "ASC") Sort.Direction direction, + @RequestParam(defaultValue = "LATEST") AdminApplicationSortField sortBy, + @RequestParam(defaultValue = "DESC") Sort.Direction direction, @PageableDefault(size = 7) Pageable pageable ) { ApplicationResponseDTO.AdminPageWithStageCounts result = applicationService.getByRecruitmentIdForAdmin(recruitmentId, stage, pageable, sortBy, direction); diff --git a/src/main/java/KUSITMS/WITHUS/domain/application/application/enumerate/AdminApplicationSortField.java b/src/main/java/KUSITMS/WITHUS/domain/application/application/enumerate/AdminApplicationSortField.java index 0bbd91c3..07365ea0 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/application/application/enumerate/AdminApplicationSortField.java +++ b/src/main/java/KUSITMS/WITHUS/domain/application/application/enumerate/AdminApplicationSortField.java @@ -1,6 +1,7 @@ package KUSITMS.WITHUS.domain.application.application.enumerate; public enum AdminApplicationSortField { + LATEST, NAME, POSITION_NAME, DOCUMENT_EVALUATION_STATUS, diff --git a/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java b/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java index e089a146..b4b2d59c 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java +++ b/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java @@ -300,6 +300,9 @@ public ApplicationResponseDTO.AdminPageWithStageCounts getByRecruitmentIdForAdmi boolean smsB = Boolean.TRUE.equals(sb.isSmsSent()); cmp = Boolean.compare(smsA, smsB); break; + case LATEST: + cmp = a.getCreatedAt().compareTo(b.getCreatedAt()); + break; case NAME: default: cmp = sa.name().compareToIgnoreCase(sb.name()); From b308ae4d7e6bc229eaa9fe86f8f7957c426be9f5 Mon Sep 17 00:00:00 2001 From: EunjinWoo Date: Thu, 11 Dec 2025 20:15:04 +0900 Subject: [PATCH 02/11] =?UTF-8?q?fix:=20=EA=B4=80=EB=A6=AC=EC=9E=90?= =?UTF-8?q?=EC=9A=A9=20=EC=A7=80=EC=9B=90=EC=84=9C=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EC=A1=B0=EC=A7=81=20=ED=8C=8C=ED=8A=B8,=20=EC=A7=80=EC=9B=90?= =?UTF-8?q?=EC=84=9C=20=EC=83=81=ED=83=9C=20=ED=95=84=ED=84=B0=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20#159?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdminApplicationController.java | 5 +- .../service/ApplicationService.java | 3 +- .../service/ApplicationServiceImpl.java | 84 ++++++++++++------- 3 files changed, 61 insertions(+), 31 deletions(-) diff --git a/src/main/java/KUSITMS/WITHUS/domain/application/application/controller/AdminApplicationController.java b/src/main/java/KUSITMS/WITHUS/domain/application/application/controller/AdminApplicationController.java index 4023fe81..5b3f0080 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/application/application/controller/AdminApplicationController.java +++ b/src/main/java/KUSITMS/WITHUS/domain/application/application/controller/AdminApplicationController.java @@ -10,6 +10,7 @@ import KUSITMS.WITHUS.domain.application.applicationEvaluator.dto.ApplicationEvaluatorRequestDTO; import KUSITMS.WITHUS.domain.application.distributionRequest.dto.DistributionRequestResponseDTO; import KUSITMS.WITHUS.domain.application.distributionRequest.entity.DistributionRequest; +import KUSITMS.WITHUS.domain.application.enumerate.ApplicationStatus; import KUSITMS.WITHUS.global.response.PagedResponse; import KUSITMS.WITHUS.global.response.SuccessResponse; import io.swagger.v3.oas.annotations.Operation; @@ -43,9 +44,11 @@ public SuccessResponse> ge @RequestParam(defaultValue = "DOCUMENT") AdminStageFilter stage, @RequestParam(defaultValue = "LATEST") AdminApplicationSortField sortBy, @RequestParam(defaultValue = "DESC") Sort.Direction direction, + @RequestParam(required = false) List organizationRoleIds, + @RequestParam(required = false) List statuses, @PageableDefault(size = 7) Pageable pageable ) { - ApplicationResponseDTO.AdminPageWithStageCounts result = applicationService.getByRecruitmentIdForAdmin(recruitmentId, stage, pageable, sortBy, direction); + ApplicationResponseDTO.AdminPageWithStageCounts result = applicationService.getByRecruitmentIdForAdmin(recruitmentId, stage, pageable, sortBy, direction, organizationRoleIds, statuses); PagedResponse paged = PagedResponse.from(result.page(), result.counts()); return SuccessResponse.ok(paged); } diff --git a/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationService.java b/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationService.java index 23159fa2..c0c08ee9 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationService.java +++ b/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationService.java @@ -7,6 +7,7 @@ import KUSITMS.WITHUS.domain.application.application.enumerate.EvaluationStatus; import KUSITMS.WITHUS.domain.application.applicationEvaluator.dto.ApplicationEvaluatorRequestDTO; import KUSITMS.WITHUS.domain.application.distributionRequest.dto.DistributionRequestResponseDTO; +import KUSITMS.WITHUS.domain.application.enumerate.ApplicationStatus; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; @@ -19,7 +20,7 @@ public interface ApplicationService { void delete(Long id); ApplicationResponseDTO.Detail getById(Long id, Long currentUserId); Page getByRecruitmentId(Long recruitmentId, Long currentUserId, EvaluationStatus evaluationStatus, String keyword, Pageable pageable); - ApplicationResponseDTO.AdminPageWithStageCounts getByRecruitmentIdForAdmin(Long recruitmentId, AdminStageFilter stage, Pageable pageable, AdminApplicationSortField sortBy, Sort.Direction direction); + ApplicationResponseDTO.AdminPageWithStageCounts getByRecruitmentIdForAdmin(Long recruitmentId, AdminStageFilter stage, Pageable pageable, AdminApplicationSortField sortBy, Sort.Direction direction, List organizationRoleIds, List statuses); List updateStatus(ApplicationRequestDTO.UpdateStatus request); void distributeEvaluators(ApplicationEvaluatorRequestDTO.Distribute request); DistributionRequestResponseDTO.Detail distributeEvaluatorsLatestRequest(Long recruitmentId); diff --git a/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java b/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java index b4b2d59c..c4a7e957 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java +++ b/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java @@ -46,6 +46,7 @@ import KUSITMS.WITHUS.global.infra.upload.dto.FileResponseDTO; import KUSITMS.WITHUS.global.infra.upload.service.FileUploadService; import lombok.RequiredArgsConstructor; +import org.jetbrains.annotations.NotNull; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; @@ -254,11 +255,63 @@ public ApplicationResponseDTO.AdminPageWithStageCounts getByRecruitmentIdForAdmi AdminStageFilter stage, Pageable pageable, AdminApplicationSortField sortBy, - Sort.Direction direction + Sort.Direction direction, + List organizationRoleIds, + List statuses ) { List allApps = applicationRepository .findByRecruitmentIdAndStatusIn(recruitmentId, stage.toStatusList()); + // POSITION_NAME 필터 + if (organizationRoleIds != null && !organizationRoleIds.isEmpty()) { + allApps = allApps.stream() + .filter(app -> + app.getOrganizationRole() != null && + organizationRoleIds.contains(app.getOrganizationRole().getId()) + ) + .collect(Collectors.toList()); + } + + // STATUS 필터 + if (statuses != null && !statuses.isEmpty()) { + allApps = allApps.stream() + .filter(app -> statuses.contains(app.getStatus())) + .collect(Collectors.toList()); + } + + List sortedApps = getSortedApps(sortBy, direction, allApps); + + List allDtos = IntStream.range(0, sortedApps.size()) + .mapToObj(i -> ApplicationResponseDTO.SummaryForAdmin.from(sortedApps.get(i), i + 1L)) + .toList(); + + int start = (int) pageable.getOffset(); + int end = Math.min(start + pageable.getPageSize(), allDtos.size()); + List content = start > end + ? List.of() + : allDtos.subList(start, end); + + Page page = new PageImpl<>(content, pageable, allDtos.size()); + + long documentCnt = applicationRepository.countByRecruitmentIdAndStatusIn( + recruitmentId, AdminStageFilter.DOCUMENT.toStatusList()); + long interviewCnt = applicationRepository.countByRecruitmentIdAndStatusIn( + recruitmentId, AdminStageFilter.INTERVIEW.toStatusList()); + long finalPassCnt = applicationRepository.countByRecruitmentIdAndStatusIn( + recruitmentId, AdminStageFilter.FINAL_PASS.toStatusList()); + long failCnt = applicationRepository.countByRecruitmentIdAndStatusIn( + recruitmentId, AdminStageFilter.FAIL.toStatusList()); + + ApplicationResponseDTO.StageCount counts = ApplicationResponseDTO.StageCount.from( + documentCnt, interviewCnt, finalPassCnt, failCnt + ); + + return ApplicationResponseDTO.AdminPageWithStageCounts.from(page, counts); + } + + @NotNull + private static List getSortedApps(AdminApplicationSortField sortBy, Sort.Direction direction, List allApps) { + allApps.sort((a, b) -> { var sa = ApplicationResponseDTO.SummaryForAdmin.from(a, 0L); var sb = ApplicationResponseDTO.SummaryForAdmin.from(b, 0L); @@ -310,34 +363,7 @@ public ApplicationResponseDTO.AdminPageWithStageCounts getByRecruitmentIdForAdmi } return direction.isDescending() ? -cmp : cmp; }); - - - List allDtos = IntStream.range(0, allApps.size()) - .mapToObj(i -> ApplicationResponseDTO.SummaryForAdmin.from(allApps.get(i), i + 1L)) - .toList(); - - int start = (int) pageable.getOffset(); - int end = Math.min(start + pageable.getPageSize(), allDtos.size()); - List content = start > end - ? List.of() - : allDtos.subList(start, end); - - Page page = new PageImpl<>(content, pageable, allDtos.size()); - - long documentCnt = applicationRepository.countByRecruitmentIdAndStatusIn( - recruitmentId, AdminStageFilter.DOCUMENT.toStatusList()); - long interviewCnt = applicationRepository.countByRecruitmentIdAndStatusIn( - recruitmentId, AdminStageFilter.INTERVIEW.toStatusList()); - long finalPassCnt = applicationRepository.countByRecruitmentIdAndStatusIn( - recruitmentId, AdminStageFilter.FINAL_PASS.toStatusList()); - long failCnt = applicationRepository.countByRecruitmentIdAndStatusIn( - recruitmentId, AdminStageFilter.FAIL.toStatusList()); - - ApplicationResponseDTO.StageCount counts = ApplicationResponseDTO.StageCount.from( - documentCnt, interviewCnt, finalPassCnt, failCnt - ); - - return ApplicationResponseDTO.AdminPageWithStageCounts.from(page, counts); + return allApps; } From 744a7e8dd98bb9dd20de9fee0e2d9241ae1ee21e Mon Sep 17 00:00:00 2001 From: EunjinWoo Date: Thu, 11 Dec 2025 20:28:03 +0900 Subject: [PATCH 03/11] =?UTF-8?q?fix:=20=EA=B4=80=EB=A6=AC=EC=9E=90?= =?UTF-8?q?=EC=9A=A9=20=EC=A7=80=EC=9B=90=EC=84=9C=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EA=B2=80=EC=83=89=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?#159?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AdminApplicationController.java | 3 ++- .../application/service/ApplicationService.java | 2 +- .../service/ApplicationServiceImpl.java | 14 +++++++++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/main/java/KUSITMS/WITHUS/domain/application/application/controller/AdminApplicationController.java b/src/main/java/KUSITMS/WITHUS/domain/application/application/controller/AdminApplicationController.java index 5b3f0080..c5f033fe 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/application/application/controller/AdminApplicationController.java +++ b/src/main/java/KUSITMS/WITHUS/domain/application/application/controller/AdminApplicationController.java @@ -46,9 +46,10 @@ public SuccessResponse> ge @RequestParam(defaultValue = "DESC") Sort.Direction direction, @RequestParam(required = false) List organizationRoleIds, @RequestParam(required = false) List statuses, + @RequestParam(required = false) String keyword, @PageableDefault(size = 7) Pageable pageable ) { - ApplicationResponseDTO.AdminPageWithStageCounts result = applicationService.getByRecruitmentIdForAdmin(recruitmentId, stage, pageable, sortBy, direction, organizationRoleIds, statuses); + ApplicationResponseDTO.AdminPageWithStageCounts result = applicationService.getByRecruitmentIdForAdmin(recruitmentId, stage, pageable, sortBy, direction, organizationRoleIds, statuses, keyword); PagedResponse paged = PagedResponse.from(result.page(), result.counts()); return SuccessResponse.ok(paged); } diff --git a/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationService.java b/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationService.java index c0c08ee9..8530d15a 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationService.java +++ b/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationService.java @@ -20,7 +20,7 @@ public interface ApplicationService { void delete(Long id); ApplicationResponseDTO.Detail getById(Long id, Long currentUserId); Page getByRecruitmentId(Long recruitmentId, Long currentUserId, EvaluationStatus evaluationStatus, String keyword, Pageable pageable); - ApplicationResponseDTO.AdminPageWithStageCounts getByRecruitmentIdForAdmin(Long recruitmentId, AdminStageFilter stage, Pageable pageable, AdminApplicationSortField sortBy, Sort.Direction direction, List organizationRoleIds, List statuses); + ApplicationResponseDTO.AdminPageWithStageCounts getByRecruitmentIdForAdmin(Long recruitmentId, AdminStageFilter stage, Pageable pageable, AdminApplicationSortField sortBy, Sort.Direction direction, List organizationRoleIds, List statuses, String keyword); List updateStatus(ApplicationRequestDTO.UpdateStatus request); void distributeEvaluators(ApplicationEvaluatorRequestDTO.Distribute request); DistributionRequestResponseDTO.Detail distributeEvaluatorsLatestRequest(Long recruitmentId); diff --git a/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java b/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java index c4a7e957..b60fb09a 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java +++ b/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java @@ -257,7 +257,8 @@ public ApplicationResponseDTO.AdminPageWithStageCounts getByRecruitmentIdForAdmi AdminApplicationSortField sortBy, Sort.Direction direction, List organizationRoleIds, - List statuses + List statuses, + String keyword ) { List allApps = applicationRepository .findByRecruitmentIdAndStatusIn(recruitmentId, stage.toStatusList()); @@ -279,6 +280,17 @@ public ApplicationResponseDTO.AdminPageWithStageCounts getByRecruitmentIdForAdmi .collect(Collectors.toList()); } + // NAME KEYWORD 필터 + if (keyword != null && !keyword.trim().isEmpty()) { + String lower = keyword.toLowerCase(); + allApps = allApps.stream() + .filter(app -> + app.getName() != null && + app.getName().toLowerCase().contains(lower) + ) + .collect(Collectors.toList()); + } + List sortedApps = getSortedApps(sortBy, direction, allApps); List allDtos = IntStream.range(0, sortedApps.size()) From dc8bdfdd3205950a954d09630b241e6a70153ad2 Mon Sep 17 00:00:00 2001 From: EunjinWoo Date: Thu, 11 Dec 2025 20:43:38 +0900 Subject: [PATCH 04/11] =?UTF-8?q?feat:=20=EB=A9=94=EC=9D=BC/=EB=AC=B8?= =?UTF-8?q?=EC=9E=90=20=ED=85=9C=ED=94=8C=EB=A6=BF=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20#159?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../template/controller/TemplateController.java | 10 ++++++++++ .../domain/template/dto/TemplateRequestDTO.java | 15 +++++++++++++++ .../WITHUS/domain/template/entity/Template.java | 7 +++++++ .../domain/template/service/TemplateService.java | 3 ++- .../template/service/TemplateServiceImpl.java | 15 +++++++++++++++ 5 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/main/java/KUSITMS/WITHUS/domain/template/controller/TemplateController.java b/src/main/java/KUSITMS/WITHUS/domain/template/controller/TemplateController.java index e98cec0d..bb83ab71 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/template/controller/TemplateController.java +++ b/src/main/java/KUSITMS/WITHUS/domain/template/controller/TemplateController.java @@ -51,5 +51,15 @@ public SuccessResponse create( return SuccessResponse.ok(created); } + @PutMapping("/{templateId}") + @Operation(summary = "문자/메일 템플릿 수정", description = "기존에 등록된 템플릿의 정보를 수정합니다.") + public SuccessResponse update( + @PathVariable Long templateId, + @RequestBody @Valid TemplateRequestDTO.Update dto + ) { + TemplateResponseDTO.Detail updated = templateService.update(templateId, dto); + return SuccessResponse.ok(updated); + } + } diff --git a/src/main/java/KUSITMS/WITHUS/domain/template/dto/TemplateRequestDTO.java b/src/main/java/KUSITMS/WITHUS/domain/template/dto/TemplateRequestDTO.java index baca8a77..97e47a18 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/template/dto/TemplateRequestDTO.java +++ b/src/main/java/KUSITMS/WITHUS/domain/template/dto/TemplateRequestDTO.java @@ -25,4 +25,19 @@ public record Create( @Schema(description = "템플릿 타입", example = "SMS | MAIL") @NotNull Medium medium ) {} + + @Schema(description = "문자/메일 템플릿 수정 요청 DTO") + public record Update( + @Schema(description = "템플릿 이름", example = "면접 일정 안내") + @NotBlank String name, + + @Schema(description = "메일 제목", example = "[WITHUS] 면접 일정 안내") + @NotBlank String subject, + + @Schema(description = "메일 본문", example = "

안녕하세요, {{applicantName}}님!

") + @NotBlank String body, + + @Schema(description = "템플릿 타입", example = "SMS | MAIL") + @NotNull Medium medium + ) {} } diff --git a/src/main/java/KUSITMS/WITHUS/domain/template/entity/Template.java b/src/main/java/KUSITMS/WITHUS/domain/template/entity/Template.java index bf38f9fc..5c4baa8a 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/template/entity/Template.java +++ b/src/main/java/KUSITMS/WITHUS/domain/template/entity/Template.java @@ -45,5 +45,12 @@ public Template(String name, String subject, String body, Medium medium, Organiz this.medium = medium; this.organization = organization; } + + public void update(String name, String subject, String body, Medium medium) { + this.name = name; + this.subject = subject; + this.body = body; + this.medium = medium; + } } diff --git a/src/main/java/KUSITMS/WITHUS/domain/template/service/TemplateService.java b/src/main/java/KUSITMS/WITHUS/domain/template/service/TemplateService.java index a96a8621..3f34c1ff 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/template/service/TemplateService.java +++ b/src/main/java/KUSITMS/WITHUS/domain/template/service/TemplateService.java @@ -11,4 +11,5 @@ public interface TemplateService { TemplateResponseDTO.Detail getById(Long templateId); List listAll(Medium medium, User user); TemplateResponseDTO.Detail create(TemplateRequestDTO.Create dto); -} \ No newline at end of file + TemplateResponseDTO.Detail update(Long templateId, TemplateRequestDTO.Update dto); +} diff --git a/src/main/java/KUSITMS/WITHUS/domain/template/service/TemplateServiceImpl.java b/src/main/java/KUSITMS/WITHUS/domain/template/service/TemplateServiceImpl.java index 5798d719..84bc844b 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/template/service/TemplateServiceImpl.java +++ b/src/main/java/KUSITMS/WITHUS/domain/template/service/TemplateServiceImpl.java @@ -62,4 +62,19 @@ public TemplateResponseDTO.Detail create(TemplateRequestDTO.Create dto) { return TemplateResponseDTO.Detail.from(saved); } + @Override + @Transactional + public TemplateResponseDTO.Detail update(Long templateId, TemplateRequestDTO.Update dto) { + Template template = templateRepository.getById(templateId); + + template.update( + dto.name(), + dto.subject(), + dto.body(), + dto.medium() + ); + + return TemplateResponseDTO.Detail.from(template); + } + } From 3157af126b0be127a09ccae51b3f5a1da6ab306a Mon Sep 17 00:00:00 2001 From: EunjinWoo Date: Thu, 11 Dec 2025 21:50:05 +0900 Subject: [PATCH 05/11] =?UTF-8?q?feat:=20=EC=A7=80=EC=9B=90=EC=84=9C=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EC=97=91=EC=85=80=20=EC=B6=94=EC=B6=9C=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20#159?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 + .../ApplicantAvailabilityRepository.java | 1 + .../AdminApplicationController.java | 43 ++++++++- .../service/ApplicationService.java | 1 + .../service/ApplicationServiceImpl.java | 90 +++++++++++++++++++ .../repository/EvaluationJpaRepository.java | 1 + .../repository/EvaluationRepository.java | 1 + .../repository/EvaluationRepositoryImpl.java | 5 ++ .../global/util/excel/ExcelExporter.java | 51 +++++++++++ 9 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 src/main/java/KUSITMS/WITHUS/global/util/excel/ExcelExporter.java diff --git a/build.gradle b/build.gradle index 14bfbb3f..a7af60bd 100644 --- a/build.gradle +++ b/build.gradle @@ -75,6 +75,9 @@ dependencies { // H2 (테스트 환경) testImplementation 'com.h2database:h2' + + // Excel + implementation 'org.apache.poi:poi-ooxml:5.2.3' } test { diff --git a/src/main/java/KUSITMS/WITHUS/domain/application/applicantAvailability/repository/ApplicantAvailabilityRepository.java b/src/main/java/KUSITMS/WITHUS/domain/application/applicantAvailability/repository/ApplicantAvailabilityRepository.java index bc7f6d0f..06ded9b3 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/application/applicantAvailability/repository/ApplicantAvailabilityRepository.java +++ b/src/main/java/KUSITMS/WITHUS/domain/application/applicantAvailability/repository/ApplicantAvailabilityRepository.java @@ -9,4 +9,5 @@ public interface ApplicantAvailabilityRepository extends JpaRepository { List findByApplicationIn(List applications); List findByApplicationId(Long id); + List findAllByApplicationIdIn(List appIds); } diff --git a/src/main/java/KUSITMS/WITHUS/domain/application/application/controller/AdminApplicationController.java b/src/main/java/KUSITMS/WITHUS/domain/application/application/controller/AdminApplicationController.java index c5f033fe..92f8058c 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/application/application/controller/AdminApplicationController.java +++ b/src/main/java/KUSITMS/WITHUS/domain/application/application/controller/AdminApplicationController.java @@ -9,21 +9,26 @@ import KUSITMS.WITHUS.domain.application.application.service.ApplicationSmsService; import KUSITMS.WITHUS.domain.application.applicationEvaluator.dto.ApplicationEvaluatorRequestDTO; import KUSITMS.WITHUS.domain.application.distributionRequest.dto.DistributionRequestResponseDTO; -import KUSITMS.WITHUS.domain.application.distributionRequest.entity.DistributionRequest; import KUSITMS.WITHUS.domain.application.enumerate.ApplicationStatus; +import KUSITMS.WITHUS.domain.user.user.entity.User; +import KUSITMS.WITHUS.global.common.annotation.CurrentUser; import KUSITMS.WITHUS.global.response.PagedResponse; import KUSITMS.WITHUS.global.response.SuccessResponse; +import KUSITMS.WITHUS.global.util.excel.ExcelExporter; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.mail.MessagingException; +import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.apache.poi.ss.usermodel.Workbook; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.web.PageableDefault; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; +import java.io.IOException; import java.util.List; @RestController @@ -54,6 +59,42 @@ public SuccessResponse> ge return SuccessResponse.ok(paged); } + @GetMapping("/recruitment/{recruitmentId}/excel") + public void downloadExcel( + @PathVariable Long recruitmentId, + @RequestParam(defaultValue = "DOCUMENT") AdminStageFilter stage, + @RequestParam(defaultValue = "LATEST") AdminApplicationSortField sortBy, + @RequestParam(defaultValue = "DESC") Sort.Direction direction, + @RequestParam(required = false) List organizationRoleIds, + @RequestParam(required = false) List statuses, + @RequestParam(required = false) String keyword, + @CurrentUser User user, + HttpServletResponse response + ) throws IOException { + + List list = + applicationService.getAllDetailForExcel( + recruitmentId, + stage, + sortBy, + direction, + organizationRoleIds, + statuses, + keyword, + user.getId() + ); + + Workbook workbook = ExcelExporter.createExcel(list); + + String fileName = "applications-detail.xlsx"; + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setHeader("Content-Disposition", "attachment; filename=" + fileName); + + workbook.write(response.getOutputStream()); + workbook.close(); + } + + @GetMapping("/recruitments/{recruitmentId}/timeslots/{timeslotId}/candidates") @Operation(summary = "타임테이블 후보자 조회") public SuccessResponse> getTimetableCandidates( diff --git a/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationService.java b/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationService.java index 8530d15a..9c63749a 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationService.java +++ b/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationService.java @@ -27,4 +27,5 @@ public interface ApplicationService { void updateEvaluators(ApplicationEvaluatorRequestDTO.Update request); boolean toggleAcquaintance(Long applicationId, Long userId); List findTimeslotCandidates(Long recruitmentId, Long timeslotId, String query, boolean excludeCurrent); + List getAllDetailForExcel(Long recruitmentId, AdminStageFilter stage, AdminApplicationSortField sortBy, Sort.Direction direction, List organizationRoleIds, List statuses, String keyword, Long id); } diff --git a/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java b/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java index b60fb09a..c31eb418 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java +++ b/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java @@ -466,6 +466,96 @@ public List findTimeslotCandidates( return applicationRepository.findEligibleCandidates(recruitmentId, timeslotId, q, excludeCurrent); } + @Override + public List getAllDetailForExcel( + Long recruitmentId, + AdminStageFilter stage, + AdminApplicationSortField sortBy, + Sort.Direction direction, + List organizationRoleIds, + List statuses, + String keyword, + Long currentUserId + ) { + + List apps = applicationRepository.findByRecruitmentIdAndStatusIn( + recruitmentId, stage.toStatusList() + ); + + // POSITION(OrganizationRole) 필터 + if (organizationRoleIds != null && !organizationRoleIds.isEmpty()) { + apps = apps.stream() + .filter(a -> a.getOrganizationRole() != null && + organizationRoleIds.contains(a.getOrganizationRole().getId())) + .toList(); + } + + // STATUS 필터 + if (statuses != null && !statuses.isEmpty()) { + apps = apps.stream() + .filter(a -> statuses.contains(a.getStatus())) + .toList(); + } + + // KEYWORD (name 검색) + if (keyword != null && !keyword.isBlank()) { + String kw = keyword.toLowerCase(); + apps = apps.stream() + .filter(a -> a.getName().toLowerCase().contains(kw)) + .toList(); + } + + // SORT + apps = getSortedApps(sortBy, direction, apps); + + + // 성능 최적화 - bulk 조회 + List appIds = apps.stream() + .map(Application::getId) + .toList(); + + // 면접 가능 시간 전체 조회 + List allAvail = + applicantAvailabilityRepository.findAllByApplicationIdIn(appIds); + + // 평가 전체 조회 + List allEvaluations = + evaluationRepository.findAllByApplicationIdIn(appIds); + + // 평가 기준 (기존 단건 상세 방식과 동일) + // 단건에서는 DOCUMENT 기준만 가져오지만, Detail.from() 내부에서 인터뷰/서류 모두 사용하므로 recruitment.getEvaluationCriteriaList() 그대로 써도 됨. + Recruitment recruitment = apps.isEmpty() ? null : apps.get(0).getRecruitment(); + List criteriaList = + recruitment != null ? recruitment.getEvaluationCriteriaList() : List.of(); + + + // previous, next → 엑셀에서는 불필요하므로 null + Long previous = null; + Long next = null; + + + // Detail DTO 변환 + Map> availMap = + allAvail.stream().collect(Collectors.groupingBy(a -> a.getApplication().getId())); + + Map> evalMap = + allEvaluations.stream().collect(Collectors.groupingBy(e -> e.getApplication().getId())); + + + return apps.stream() + .map(app -> assembler.toDetail( + app, + availMap.getOrDefault(app.getId(), List.of()), + evalMap.getOrDefault(app.getId(), List.of()), + criteriaList, + currentUserId, + previous, + next + )) + .toList(); + } + + /** * PASS/FAIL/HOLD의 간단 상태를 단계와 현재 상태에 맞춰 ApplicationStatus으로 매핑 * @param stage 변경할 단계 (DOCUMENT, INTERVIEW, FINAL_PASS, FAIL) diff --git a/src/main/java/KUSITMS/WITHUS/domain/evaluation/evaluation/repository/EvaluationJpaRepository.java b/src/main/java/KUSITMS/WITHUS/domain/evaluation/evaluation/repository/EvaluationJpaRepository.java index ccdf6266..c6e2b66f 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/evaluation/evaluation/repository/EvaluationJpaRepository.java +++ b/src/main/java/KUSITMS/WITHUS/domain/evaluation/evaluation/repository/EvaluationJpaRepository.java @@ -14,5 +14,6 @@ public interface EvaluationJpaRepository extends JpaRepository List findByApplicationAndUserAndCriteriaIn(Application application, User user, List criterias); long countByApplication_IdAndUser_IdAndCriteria_IdIn(Long applicationId, Long userId, List criteriaIds); long countByApplication_IdAndUser_IdAndCriteria_EvaluationType(Long id, Long userId, EvaluationType evaluationType); + List findAllByApplicationIdIn(List appIds); } diff --git a/src/main/java/KUSITMS/WITHUS/domain/evaluation/evaluation/repository/EvaluationRepository.java b/src/main/java/KUSITMS/WITHUS/domain/evaluation/evaluation/repository/EvaluationRepository.java index b14d94f8..b9d6f360 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/evaluation/evaluation/repository/EvaluationRepository.java +++ b/src/main/java/KUSITMS/WITHUS/domain/evaluation/evaluation/repository/EvaluationRepository.java @@ -18,4 +18,5 @@ public interface EvaluationRepository { long countByApplication_IdAndUser_IdAndCriteria_IdIn(Long applicationId, Long userId, List criteriaIds); long countByApplication_IdAndUser_IdAndCriteria_EvaluationType(Long id, Long userId, EvaluationType evaluationType); void deleteAll(List existingEvaluations); + List findAllByApplicationIdIn(List appIds); } diff --git a/src/main/java/KUSITMS/WITHUS/domain/evaluation/evaluation/repository/EvaluationRepositoryImpl.java b/src/main/java/KUSITMS/WITHUS/domain/evaluation/evaluation/repository/EvaluationRepositoryImpl.java index 45a4f36f..70893322 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/evaluation/evaluation/repository/EvaluationRepositoryImpl.java +++ b/src/main/java/KUSITMS/WITHUS/domain/evaluation/evaluation/repository/EvaluationRepositoryImpl.java @@ -85,4 +85,9 @@ public long countByApplication_IdAndUser_IdAndCriteria_EvaluationType(Long id, L public void deleteAll(List existingEvaluations) { evaluationJpaRepository.deleteAll(existingEvaluations); } + + @Override + public List findAllByApplicationIdIn(List appIds) { + return evaluationJpaRepository.findAllByApplicationIdIn(appIds); + } } diff --git a/src/main/java/KUSITMS/WITHUS/global/util/excel/ExcelExporter.java b/src/main/java/KUSITMS/WITHUS/global/util/excel/ExcelExporter.java new file mode 100644 index 00000000..6ee12416 --- /dev/null +++ b/src/main/java/KUSITMS/WITHUS/global/util/excel/ExcelExporter.java @@ -0,0 +1,51 @@ +package KUSITMS.WITHUS.global.util.excel; + +import KUSITMS.WITHUS.domain.application.application.dto.ApplicationResponseDTO; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +import java.util.List; + +public class ExcelExporter { + + public static Workbook createExcel(List list) { + Workbook workbook = new XSSFWorkbook(); + Sheet sheet = workbook.createSheet("지원서 상세"); + + Row header = sheet.createRow(0); + String[] columns = { + "ID", "이름", "이메일", "전화번호", "성별", "전공", + "지원 분야", "합불 상태", + "서류 평균", "면접 평균", + "주소", "생년월일", "학교", + "지인 수" + }; + + for (int i = 0; i < columns.length; i++) { + header.createCell(i).setCellValue(columns[i]); + } + + int rowIdx = 1; + for (var dto : list) { + Row row = sheet.createRow(rowIdx++); + + row.createCell(0).setCellValue(dto.id()); + row.createCell(1).setCellValue(dto.name()); + row.createCell(2).setCellValue(dto.email()); + row.createCell(3).setCellValue(dto.phoneNumber()); + row.createCell(4).setCellValue(dto.gender() != null ? dto.gender().name() : ""); + row.createCell(5).setCellValue(dto.major()); + row.createCell(6).setCellValue(dto.appliedPosition()); + row.createCell(7).setCellValue(dto.status().name()); + row.createCell(8).setCellValue(dto.documentAverageScore()); + row.createCell(9).setCellValue(dto.interviewAverageScore()); + row.createCell(10).setCellValue(dto.address()); + row.createCell(11).setCellValue(dto.birthDate() != null ? dto.birthDate().toString() : ""); + row.createCell(12).setCellValue(dto.university()); + row.createCell(13).setCellValue(dto.acquaintanceCount()); + } + + return workbook; + } + +} From 39ebf1d5dc3a11b0e01d494ebeb4997b0e6bec66 Mon Sep 17 00:00:00 2001 From: EunjinWoo Date: Sat, 13 Dec 2025 17:26:44 +0900 Subject: [PATCH 06/11] =?UTF-8?q?fix:=20.toList()=EB=A1=9C=20=EB=B6=88?= =?UTF-8?q?=EB=B3=80=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=ED=9B=84=20=EC=A0=95=EB=A0=AC=20=EC=8B=9C=EB=8F=84=ED=95=98?= =?UTF-8?q?=EB=8D=98=20=EA=B2=83=20=EC=88=98=EC=A0=95=20#159?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/service/ApplicationServiceImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java b/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java index c31eb418..bbe66b4a 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java +++ b/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java @@ -487,14 +487,14 @@ public List getAllDetailForExcel( apps = apps.stream() .filter(a -> a.getOrganizationRole() != null && organizationRoleIds.contains(a.getOrganizationRole().getId())) - .toList(); + .collect(Collectors.toList()); } // STATUS 필터 if (statuses != null && !statuses.isEmpty()) { apps = apps.stream() .filter(a -> statuses.contains(a.getStatus())) - .toList(); + .collect(Collectors.toList()); } // KEYWORD (name 검색) @@ -502,7 +502,7 @@ public List getAllDetailForExcel( String kw = keyword.toLowerCase(); apps = apps.stream() .filter(a -> a.getName().toLowerCase().contains(kw)) - .toList(); + .collect(Collectors.toList()); } // SORT From 3f7dda6bf0764f4535c3138ae5c374ef5cd77dfe Mon Sep 17 00:00:00 2001 From: EunjinWoo Date: Sat, 13 Dec 2025 17:28:01 +0900 Subject: [PATCH 07/11] =?UTF-8?q?fix:=20=ED=85=9C=ED=94=8C=EB=A6=BF=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EC=8B=9C=20medium=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=EC=9E=90=EC=99=80=20=EB=8F=99=EC=9D=BC?= =?UTF-8?q?=ED=95=98=EA=B2=8C=20=EC=88=98=EC=A0=95=20#159?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/KUSITMS/WITHUS/domain/template/entity/Template.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/KUSITMS/WITHUS/domain/template/entity/Template.java b/src/main/java/KUSITMS/WITHUS/domain/template/entity/Template.java index 5c4baa8a..3ad57ca5 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/template/entity/Template.java +++ b/src/main/java/KUSITMS/WITHUS/domain/template/entity/Template.java @@ -47,6 +47,9 @@ public Template(String name, String subject, String body, Medium medium, Organiz } public void update(String name, String subject, String body, Medium medium) { + if(medium == Medium.MAIL && (subject == null || subject.isBlank())) { + throw new CustomException(ErrorCode.EMAIL_SUBJECT_REQUIRED); + } this.name = name; this.subject = subject; this.body = body; From 8ac22ddb013b5cea231350d40aba74b8f9c106b1 Mon Sep 17 00:00:00 2001 From: EunjinWoo Date: Sat, 13 Dec 2025 17:28:56 +0900 Subject: [PATCH 08/11] =?UTF-8?q?fix:=20=EB=AC=B8=EC=9E=90=EC=9D=B8=20?= =?UTF-8?q?=EA=B2=BD=EC=9A=B0=20subject=20=EB=B9=88=20=EA=B0=92=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=B4=EB=82=BC=20=EC=88=98=20=EC=9E=88=EA=B2=8C?= =?UTF-8?q?=20=EC=88=98=EC=A0=95=20#159?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../KUSITMS/WITHUS/domain/template/dto/TemplateRequestDTO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/KUSITMS/WITHUS/domain/template/dto/TemplateRequestDTO.java b/src/main/java/KUSITMS/WITHUS/domain/template/dto/TemplateRequestDTO.java index 97e47a18..6d710f73 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/template/dto/TemplateRequestDTO.java +++ b/src/main/java/KUSITMS/WITHUS/domain/template/dto/TemplateRequestDTO.java @@ -32,7 +32,7 @@ public record Update( @NotBlank String name, @Schema(description = "메일 제목", example = "[WITHUS] 면접 일정 안내") - @NotBlank String subject, + String subject, @Schema(description = "메일 본문", example = "

안녕하세요, {{applicantName}}님!

") @NotBlank String body, From dfe294cde7f4232d889db248241f48bf4130e651 Mon Sep 17 00:00:00 2001 From: EunjinWoo Date: Sat, 13 Dec 2025 17:30:34 +0900 Subject: [PATCH 09/11] =?UTF-8?q?fix:=20Workbook=20=EB=A6=AC=EC=86=8C?= =?UTF-8?q?=EC=8A=A4=20=EB=88=84=EC=88=98=20=EA=B0=80=EB=8A=A5=EC=84=B1=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0=20#159?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/controller/AdminApplicationController.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/KUSITMS/WITHUS/domain/application/application/controller/AdminApplicationController.java b/src/main/java/KUSITMS/WITHUS/domain/application/application/controller/AdminApplicationController.java index 92f8058c..351e875b 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/application/application/controller/AdminApplicationController.java +++ b/src/main/java/KUSITMS/WITHUS/domain/application/application/controller/AdminApplicationController.java @@ -84,14 +84,13 @@ public void downloadExcel( user.getId() ); - Workbook workbook = ExcelExporter.createExcel(list); - String fileName = "applications-detail.xlsx"; response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setHeader("Content-Disposition", "attachment; filename=" + fileName); - workbook.write(response.getOutputStream()); - workbook.close(); + try (Workbook workbook = ExcelExporter.createExcel(list)) { + workbook.write(response.getOutputStream()); + } } From cfaf2231b46b468656143c99542f521ef67f3009 Mon Sep 17 00:00:00 2001 From: EunjinWoo Date: Sat, 13 Dec 2025 17:32:13 +0900 Subject: [PATCH 10/11] =?UTF-8?q?chore:=20=EB=88=84=EB=9D=BD=EB=90=9C=20?= =?UTF-8?q?=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=82=AC=20TODO=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20#159?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WITHUS/domain/template/service/TemplateServiceImpl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/KUSITMS/WITHUS/domain/template/service/TemplateServiceImpl.java b/src/main/java/KUSITMS/WITHUS/domain/template/service/TemplateServiceImpl.java index 84bc844b..68c2df41 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/template/service/TemplateServiceImpl.java +++ b/src/main/java/KUSITMS/WITHUS/domain/template/service/TemplateServiceImpl.java @@ -67,6 +67,8 @@ public TemplateResponseDTO.Detail create(TemplateRequestDTO.Create dto) { public TemplateResponseDTO.Detail update(Long templateId, TemplateRequestDTO.Update dto) { Template template = templateRepository.getById(templateId); + // TODO: 사용자가 속한 조직의 템플릿만 수정하도록 검증 추가 필요 + template.update( dto.name(), dto.subject(), From eb009a764ef490692ed6599a31e9f00fd6b64f53 Mon Sep 17 00:00:00 2001 From: EunjinWoo Date: Sat, 13 Dec 2025 17:39:40 +0900 Subject: [PATCH 11/11] =?UTF-8?q?fix:=20=ED=82=A4=EC=9B=8C=EB=93=9C=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20trim=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20?= =?UTF-8?q?=EB=B9=88=20IN-query=20=EB=AC=B8=EC=A0=9C=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=20#159?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/service/ApplicationServiceImpl.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java b/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java index bbe66b4a..cbcfdcbc 100644 --- a/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java +++ b/src/main/java/KUSITMS/WITHUS/domain/application/application/service/ApplicationServiceImpl.java @@ -282,7 +282,7 @@ public ApplicationResponseDTO.AdminPageWithStageCounts getByRecruitmentIdForAdmi // NAME KEYWORD 필터 if (keyword != null && !keyword.trim().isEmpty()) { - String lower = keyword.toLowerCase(); + String lower = keyword.trim().toLowerCase(Locale.ROOT); allApps = allApps.stream() .filter(app -> app.getName() != null && @@ -499,15 +499,18 @@ public List getAllDetailForExcel( // KEYWORD (name 검색) if (keyword != null && !keyword.isBlank()) { - String kw = keyword.toLowerCase(); + String kw = keyword.trim().toLowerCase(Locale.ROOT); apps = apps.stream() - .filter(a -> a.getName().toLowerCase().contains(kw)) + .filter(a -> a.getName() != null && a.getName().toLowerCase().contains(kw)) .collect(Collectors.toList()); } // SORT apps = getSortedApps(sortBy, direction, apps); + if (apps.isEmpty()) { + return List.of(); + } // 성능 최적화 - bulk 조회 List appIds = apps.stream()