Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/dev-server-integrator.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ on:
jobs:
build_and_push:
runs-on: ubuntu-latest
env:
TZ: Asia/Seoul
steps:
- name: Check Out Repository
uses: actions/checkout@v4
Expand All @@ -32,7 +34,7 @@ jobs:
run: chmod +x gradlew

- name: CI Test
run: ./gradlew clean test --no-build-cache
run: ./gradlew clean test --no-build-cache -Duser.timezone=Asia/Seoul

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ddingdong.ddingdongBE.domain.form.api;

import ddingdong.ddingdongBE.auth.PrincipalDetails;
import ddingdong.ddingdongBE.domain.form.controller.dto.response.EmailSendStatusResponse;
import ddingdong.ddingdongBE.domain.form.controller.dto.request.CreateFormRequest;
import ddingdong.ddingdongBE.domain.form.controller.dto.request.SendApplicationResultEmailRequest;
import ddingdong.ddingdongBE.domain.form.controller.dto.request.UpdateFormEndDateRequest;
Expand Down Expand Up @@ -129,8 +130,8 @@ void registerMembers(
@SecurityRequirement(name = "AccessToken")
@PostMapping("/my/forms/{formId}/results/email")
void sendApplicationResultEmail(@PathVariable("formId") Long formId,
@AuthenticationPrincipal PrincipalDetails principalDetails,
@RequestBody SendApplicationResultEmailRequest request);
@AuthenticationPrincipal PrincipalDetails principalDetails,
@RequestBody SendApplicationResultEmailRequest request);

@Operation(summary = "동아리 폼지 종료일자 수정 API")
@ApiResponse(responseCode = "204", description = "동아리 폼지 지원기간 마감일자 수정 성공")
Expand All @@ -152,4 +153,14 @@ void updateFormEndDate(
EmailSendCountResponse getEmailSendCount(
@PathVariable("formEmailSendHistoryId") Long formEmailSendHistoryId
);

@Operation(summary = "이메일 전송 현황 조회 API")
@ApiResponse(responseCode = "200", description = "이메일 전송 현황 조회 성공",
content = @Content(schema = @Schema(implementation = EmailSendStatusResponse.class)))
@ResponseStatus(HttpStatus.OK)
@SecurityRequirement(name = "AccessToken")
@GetMapping("/my/forms/{formId}/emails/status")
EmailSendStatusResponse getEmailSendStatus(
@PathVariable("formId") Long formId
);
Comment on lines +157 to +165
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find the CentralFormApi file and check its location
find . -name "CentralFormApi.java" -type f

Repository: COW-dev/ddingdong-be

Length of output: 137


🏁 Script executed:

# Search for getEmailSendStatus implementation and ownership validation
rg -n "getEmailSendStatus" -A 10 -B 2

Repository: COW-dev/ddingdong-be

Length of output: 4047


🏁 Script executed:

# Search for form ownership/authorization validation patterns
rg -n "owner|userId|principalId|authorize|permission" --type java -C 3 | head -100

Repository: COW-dev/ddingdong-be

Length of output: 10990


🏁 Script executed:

# Look for service implementation related to form
rg -n "FormService|FormServiceImpl" --type java | head -20

Repository: COW-dev/ddingdong-be

Length of output: 3363


🏁 Script executed:

# Read the full implementation of getEmailSendStatusByFormId
sed -n '250,265p' src/main/java/ddingdong/ddingdongBE/domain/form/service/FacadeCentralFormServiceImpl.java

Repository: COW-dev/ddingdong-be

Length of output: 912


🏁 Script executed:

# Check the controller implementation to see if it receives userId/principal
cat -n src/main/java/ddingdong/ddingdongBE/domain/form/controller/CentralFormController.java | grep -A 10 "getEmailSendStatus"

Repository: COW-dev/ddingdong-be

Length of output: 325


🏁 Script executed:

# Search for getAllByFormId to understand what it does
rg -n "getAllByFormId" -B 2 -A 8

Repository: COW-dev/ddingdong-be

Length of output: 7661


🏁 Script executed:

# Search for Form ownership validation patterns
rg -n "getByFormIdAndUserId|validateOwnership|checkOwner|verifyOwner" --type java

Repository: COW-dev/ddingdong-be

Length of output: 46


🏁 Script executed:

# Check Form entity to see if it has userId/clubId field
fd "Form.java" --type f | xargs cat -n | head -50

Repository: COW-dev/ddingdong-be

Length of output: 1928


🏁 Script executed:

# Check other /my/ endpoints to see if they validate ownership
rg -n "@GetMapping.*my/forms" -A 5 -B 2 src/main/java/ddingdong/ddingdongBE/domain/form/

Repository: COW-dev/ddingdong-be

Length of output: 6785


🏁 Script executed:

# Check sendApplicationResultEmail which uses validateEqualsClub
sed -n '195,215p' src/main/java/ddingdong/ddingdongBE/domain/form/service/FacadeCentralFormServiceImpl.java

Repository: COW-dev/ddingdong-be

Length of output: 1209


🏁 Script executed:

# Look at Form entity club relationship and see if there's ownership validation elsewhere
rg -n "form.isNotEqualClubId|validateEqualsClub" -B 3 -A 3 src/main/java/ddingdong/ddingdongBE/domain/form/service/

Repository: COW-dev/ddingdong-be

Length of output: 3292


폼 소유자 검증 누락으로 인한 IDOR 취약점 존재

경로가 /my/forms/{formId}인데 메서드 시그니처에 인증 사용자 정보가 없어 소유권 검증이 불가능합니다. 서비스 레이어에서도 ownership check가 없어서 다른 사용자가 formId만으로 임의의 폼의 이메일 전송 현황을 조회할 수 있습니다.

같은 패턴의 getFormStatistics() (라인 95-99)는 @AuthenticationPrincipal PrincipalDetails를 받아 userId를 기반으로 validateEqualsClub()을 통해 소유권을 검증합니다. 이 엔드포인트도 동일한 방식으로 수정해야 합니다.

✅ 수정 방안
     `@GetMapping`("/my/forms/{formId}/emails/status")
     EmailSendStatusResponse getEmailSendStatus(
-            `@PathVariable`("formId") Long formId
+            `@PathVariable`("formId") Long formId,
+            `@AuthenticationPrincipal` PrincipalDetails principalDetails
     );

그 후 서비스 레이어에서:

public EmailSendStatusQuery getEmailSendStatusByFormId(Long formId, Long userId) {
    Club club = clubService.getByUserId(userId);
    Form form = formService.getById(formId);
    validateEqualsClub(club, form);  // 소유권 검증
    // ... 기존 로직
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Operation(summary = "이메일 전송 현황 조회 API")
@ApiResponse(responseCode = "200", description = "이메일 전송 현황 조회 성공",
content = @Content(schema = @Schema(implementation = EmailSendStatusResponse.class)))
@ResponseStatus(HttpStatus.OK)
@SecurityRequirement(name = "AccessToken")
@GetMapping("/my/forms/{formId}/emails/status")
EmailSendStatusResponse getEmailSendStatus(
@PathVariable("formId") Long formId
);
`@Operation`(summary = "이메일 전송 현황 조회 API")
`@ApiResponse`(responseCode = "200", description = "이메일 전송 현황 조회 성공",
content = `@Content`(schema = `@Schema`(implementation = EmailSendStatusResponse.class)))
`@ResponseStatus`(HttpStatus.OK)
`@SecurityRequirement`(name = "AccessToken")
`@GetMapping`("/my/forms/{formId}/emails/status")
EmailSendStatusResponse getEmailSendStatus(
`@PathVariable`("formId") Long formId,
`@AuthenticationPrincipal` PrincipalDetails principalDetails
);
🤖 Prompt for AI Agents
In `@src/main/java/ddingdong/ddingdongBE/domain/form/api/CentralFormApi.java`
around lines 157 - 165, The API getEmailSendStatus currently lacks owner
verification causing an IDOR; update the controller method signature
getEmailSendStatus to accept the authenticated principal (e.g.,
`@AuthenticationPrincipal` PrincipalDetails principal) and pass principal.getId()
(or equivalent) into the service, then implement ownership validation in the
service (create/modify getEmailSendStatusByFormId(Long formId, Long userId)) by
calling clubService.getByUserId(userId), formService.getById(formId) and
validateEqualsClub(club, form) before returning the EmailSendStatusResponse.

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import ddingdong.ddingdongBE.auth.PrincipalDetails;
import ddingdong.ddingdongBE.domain.form.api.CentralFormApi;
import ddingdong.ddingdongBE.domain.form.controller.dto.response.EmailSendStatusResponse;
import ddingdong.ddingdongBE.domain.form.controller.dto.request.CreateFormRequest;
import ddingdong.ddingdongBE.domain.form.controller.dto.request.SendApplicationResultEmailRequest;
import ddingdong.ddingdongBE.domain.form.controller.dto.request.UpdateFormEndDateRequest;
Expand All @@ -14,6 +15,7 @@
import ddingdong.ddingdongBE.domain.form.controller.dto.response.SingleFieldStatisticsResponse;
import ddingdong.ddingdongBE.domain.form.service.FacadeCentralFormService;
import ddingdong.ddingdongBE.domain.form.service.dto.query.EmailSendCountQuery;
import ddingdong.ddingdongBE.domain.form.service.dto.query.EmailSendStatusQuery;
import ddingdong.ddingdongBE.domain.form.service.dto.query.FormListQuery;
import ddingdong.ddingdongBE.domain.form.service.dto.query.FormQuery;
import ddingdong.ddingdongBE.domain.form.service.dto.query.FormStatisticsQuery;
Expand Down Expand Up @@ -106,14 +108,16 @@ public void sendApplicationResultEmail(
SendApplicationResultEmailRequest request
) {
User user = principalDetails.getUser();
facadeCentralFormService.sendApplicationResultEmail(request.toCommand(user.getId(), formId));
facadeCentralFormService.sendApplicationResultEmail(
request.toCommand(user.getId(), formId));
}

@Override
public void updateFormEndDate(UpdateFormEndDateRequest updateFormEndDateRequest, Long formId,
PrincipalDetails principalDetails) {
User user = principalDetails.getUser();
facadeCentralFormService.updateFormEndDate(updateFormEndDateRequest.toCommand(user, formId));
facadeCentralFormService.updateFormEndDate(
updateFormEndDateRequest.toCommand(user, formId));
}

@Override
Expand All @@ -122,4 +126,10 @@ public EmailSendCountResponse getEmailSendCount(Long formEmailSendHistoryId) {
formEmailSendHistoryId);
return EmailSendCountResponse.from(query);
}

@Override
public EmailSendStatusResponse getEmailSendStatus(Long formId) {
EmailSendStatusQuery query = facadeCentralFormService.getEmailSendStatusByFormId(formId);
return EmailSendStatusResponse.from(query);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package ddingdong.ddingdongBE.domain.form.controller.dto.response;

import ddingdong.ddingdongBE.domain.form.service.dto.query.EmailSendStatusQuery;
import ddingdong.ddingdongBE.domain.form.service.dto.query.EmailSendStatusQuery.EmailSendStatusInfoQuery;
import ddingdong.ddingdongBE.domain.formapplication.entity.FormApplicationStatus;
import ddingdong.ddingdongBE.email.entity.EmailSendStatus;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.LocalDateTime;
import java.util.List;

public record EmailSendStatusResponse(
List<EmailSendStatusInfoResponse> emailSendStatusInfoResponses

) {

public static EmailSendStatusResponse from(EmailSendStatusQuery emailSendStatusQuery) {
List<EmailSendStatusInfoResponse> responses = emailSendStatusQuery.emailSendStatusInfoQueries()
.stream()
.map(EmailSendStatusInfoResponse::from)
.toList();
return new EmailSendStatusResponse(responses);
}

record EmailSendStatusInfoResponse(
@Schema(description = "지원자 이름", example = "고건")
String name,
@Schema(description = "학번", example = "60221300")
String studentNumber,
@Schema(description = "이메일 전송 일시", example = "2025.12.13 13:00")
LocalDateTime sendAt, // TODO: 재전송 시 Update 해주기
@Schema(description = "이메일 전송 상태", example = "Sending")
EmailSendStatus emailSendStatus,
@Schema(description = "지원자 서류/면접 합불 상태", example = "FIRST_PASS")
FormApplicationStatus formApplicationStatus
) {

public static EmailSendStatusInfoResponse from(
EmailSendStatusInfoQuery emailSendStatusInfoQuery) {
return new EmailSendStatusInfoResponse(
emailSendStatusInfoQuery.name(),
emailSendStatusInfoQuery.studentNumber(),
emailSendStatusInfoQuery.sendAt(),
emailSendStatusInfoQuery.emailSendStatus(),
emailSendStatusInfoQuery.formApplicationStatus()
);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package ddingdong.ddingdongBE.domain.form.repository;

import ddingdong.ddingdongBE.domain.form.entity.FormEmailSendHistory;
import ddingdong.ddingdongBE.domain.formapplication.entity.FormApplication;
import ddingdong.ddingdongBE.domain.formapplication.entity.FormApplicationStatus;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;

public interface FormEmailSendHistoryRepository extends JpaRepository<FormEmailSendHistory, Long> {

Optional<FormEmailSendHistory> findByFormIdAndFormApplicationStatus(Long formId, FormApplicationStatus formApplicationStatus);
List<FormEmailSendHistory> getAllByFormId(Long formId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import ddingdong.ddingdongBE.domain.form.service.dto.command.UpdateFormCommand;
import ddingdong.ddingdongBE.domain.form.service.dto.command.UpdateFormEndDateCommand;
import ddingdong.ddingdongBE.domain.form.service.dto.query.EmailSendCountQuery;
import ddingdong.ddingdongBE.domain.form.service.dto.query.EmailSendStatusQuery;
import ddingdong.ddingdongBE.domain.form.service.dto.query.FormListQuery;
import ddingdong.ddingdongBE.domain.form.service.dto.query.FormQuery;
import ddingdong.ddingdongBE.domain.form.service.dto.query.FormStatisticsQuery;
Expand Down Expand Up @@ -38,4 +39,6 @@ public interface FacadeCentralFormService {
void updateFormEndDate(UpdateFormEndDateCommand command);

EmailSendCountQuery getEmailSendCountByFormEmailSendHistoryId(Long formEmailSendHistoryId);

EmailSendStatusQuery getEmailSendStatusByFormId(Long formId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import ddingdong.ddingdongBE.domain.form.service.dto.command.UpdateFormCommand.UpdateFormFieldCommand;
import ddingdong.ddingdongBE.domain.form.service.dto.command.UpdateFormEndDateCommand;
import ddingdong.ddingdongBE.domain.form.service.dto.query.EmailSendCountQuery;
import ddingdong.ddingdongBE.domain.form.service.dto.query.EmailSendStatusQuery;
import ddingdong.ddingdongBE.domain.form.service.dto.query.FormListQuery;
import ddingdong.ddingdongBE.domain.form.service.dto.query.FormQuery;
import ddingdong.ddingdongBE.domain.form.service.dto.query.FormStatisticsQuery;
Expand Down Expand Up @@ -91,13 +92,15 @@ public void createForm(CreateFormCommand createFormCommand) {
})
public void updateForm(UpdateFormCommand command) {
Club club = clubService.getByUserId(command.user().getId());
validateDuplicationDateExcludingSelf(club, command.startDate(), command.endDate(), command.formId());
validateDuplicationDateExcludingSelf(club, command.startDate(), command.endDate(),
command.formId());

Form originform = formService.getById(command.formId());
Form updateForm = command.toEntity();
originform.update(updateForm);

List<FormField> updatedFormFields = toUpdateFormFields(originform, command.formFieldCommands());
List<FormField> updatedFormFields = toUpdateFormFields(originform,
command.formFieldCommands());
originform.updateFormFields(updatedFormFields);
}

Expand Down Expand Up @@ -164,7 +167,8 @@ public void registerApplicantAsMember(Long userId, Long formId) {
List<ClubMember> originClubMembers = club.getClubMembers();
clubMemberService.deleteAll(originClubMembers);

List<FormApplication> finalPassedFormApplications = formApplicationService.getAllFinalPassedByFormId(formId);
List<FormApplication> finalPassedFormApplications = formApplicationService.getAllFinalPassedByFormId(
formId);
List<ClubMember> finalPassedClubMembers = finalPassedFormApplications.stream()
.map(ClubMember::createFromFormApplication)
.toList();
Expand All @@ -180,10 +184,12 @@ public SingleFieldStatisticsQuery getTextFieldStatistics(Long fieldId) {
}
String type = formField.getFieldType().name();
if (formField.isFile()) {
List<SingleStatisticsQuery> textStatisticsQueries = formStatisticService.createFileStatistics(formField);
List<SingleStatisticsQuery> textStatisticsQueries = formStatisticService.createFileStatistics(
formField);
return new SingleFieldStatisticsQuery(type, textStatisticsQueries);
}
List<SingleStatisticsQuery> textStatisticsQueries = formStatisticService.createTextStatistics(formField);
List<SingleStatisticsQuery> textStatisticsQueries = formStatisticService.createTextStatistics(
formField);
return new SingleFieldStatisticsQuery(type, textStatisticsQueries);
}

Expand All @@ -197,18 +203,21 @@ public void sendApplicationResultEmail(SendApplicationResultEmailCommand command
);
Form form = formService.getById(command.formId());
EmailContent emailContent = EmailContent.of(command.title(), command.message(), club);
FormEmailSendHistory formEmailSendHistory = formEmailSendHistoryService.create(form, command.target(),
FormEmailSendHistory formEmailSendHistory = formEmailSendHistoryService.create(form,
command.target(),
command.message());

List<FormResultSendingEmailInfo> formResultSendingEmailInfos = formApplications.stream()
.map(application -> {
EmailSendHistory emailSendHistory = emailSendHistoryService.save(
EmailSendHistory.createPending(application, formEmailSendHistory));
return new FormResultSendingEmailInfo(emailSendHistory.getId(), application.getEmail(),
return new FormResultSendingEmailInfo(emailSendHistory.getId(),
application.getEmail(),
application.getName(), emailContent);
})
.toList();
applicationEventPublisher.publishEvent(new SendFormResultEvent(formResultSendingEmailInfos));
applicationEventPublisher.publishEvent(
new SendFormResultEvent(formResultSendingEmailInfos));
}

@Transactional
Expand All @@ -217,13 +226,16 @@ public void updateFormEndDate(UpdateFormEndDateCommand command) {
Club club = clubService.getByUserId(command.user().getId());
Form form = formService.getById(command.formId());
validateEndDate(form.getStartDate(), command.endDate());
validateDuplicationDateExcludingSelf(club, form.getStartDate(), command.endDate(), command.formId());
validateDuplicationDateExcludingSelf(club, form.getStartDate(), command.endDate(),
command.formId());
form.updateEndDate(command.endDate());
}

@Override
public EmailSendCountQuery getEmailSendCountByFormEmailSendHistoryId(Long formEmailSendHistoryId) {
FormEmailSendHistory formEmailSendHistory = formEmailSendHistoryService.getById(formEmailSendHistoryId);
public EmailSendCountQuery getEmailSendCountByFormEmailSendHistoryId(
Long formEmailSendHistoryId) {
FormEmailSendHistory formEmailSendHistory = formEmailSendHistoryService.getById(
formEmailSendHistoryId);
EmailSendHistories emailSendHistories = emailSendHistoryService.getAllByFormEmailSendHistoryId(
formEmailSendHistory.getId());

Expand All @@ -234,6 +246,20 @@ public EmailSendCountQuery getEmailSendCountByFormEmailSendHistoryId(Long formEm
);
}

@Override
public EmailSendStatusQuery getEmailSendStatusByFormId(Long formId) {
List<FormEmailSendHistory> formEmailSendHistories = formEmailSendHistoryService.getAllByFormId(
formId);
List<Long> formEmailSendHistoryIds = formEmailSendHistories.stream()
.map(FormEmailSendHistory::getId)
.toList();
EmailSendHistories emailSendHistories = emailSendHistoryService.getAllByFormEmailSendHistoryIds(
formEmailSendHistoryIds);
EmailSendHistories latestEmailSendHistories = emailSendHistories.getLatestByFormApplication();

return EmailSendStatusQuery.from(latestEmailSendHistories.getAll());
}
Comment on lines +249 to +261
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Form 소유권 검증 누락 확인 필요

다른 메서드들(getStatisticsByForm, deleteForm 등)에서는 validateEqualsClub(club, form)을 통해 현재 사용자가 해당 Form의 소유자인지 검증하고 있습니다. 이 메서드에서는 해당 검증이 누락되어 있어, 다른 동아리의 Form에 대한 이메일 전송 현황을 조회할 수 있는 보안 문제가 발생할 수 있습니다.

🔒 소유권 검증 추가 제안
 `@Override`
-public EmailSendStatusQuery getEmailSendStatusByFormId(Long formId) {
+public EmailSendStatusQuery getEmailSendStatusByFormId(Long formId, User user) {
+    Club club = clubService.getByUserId(user.getId());
+    Form form = formService.getById(formId);
+    validateEqualsClub(club, form);
+    
     List<FormEmailSendHistory> formEmailSendHistories = formEmailSendHistoryService.getAllByFormId(
             formId);

참고: 이 변경을 적용할 경우, FacadeCentralFormService 인터페이스와 Controller의 메서드 시그니처도 함께 수정해야 합니다.

🤖 Prompt for AI Agents
In
`@src/main/java/ddingdong/ddingdongBE/domain/form/service/FacadeCentralFormServiceImpl.java`
around lines 249 - 261, The method getEmailSendStatusByFormId is missing
ownership validation; update it to accept the calling club (or current club) and
perform validateEqualsClub(club, form) before fetching histories: retrieve the
Form entity (e.g., via formService.getById(formId)), call
validateEqualsClub(club, form), then proceed with the existing logic
(formEmailSendHistoryService.getAllByFormId, etc.). Also update the
FacadeCentralFormService interface and the Controller method signature to
include the club parameter (or otherwise provide the caller's Club) so the
ownership check can be enforced.


private void validateEqualsClub(Club club, Form form) {
if (form.isNotEqualClubId(club.getId())) {
throw new NonHaveFormAuthority();
Expand All @@ -259,7 +285,8 @@ private void validateDuplicationDateExcludingSelf(
LocalDate endDate,
Long formId
) {
List<Form> overlappingForms = formService.findOverlappingForms(club.getId(), startDate, endDate)
List<Form> overlappingForms = formService.findOverlappingForms(club.getId(), startDate,
endDate)
.stream()
.filter(form -> !form.isEqualsById(formId))
.toList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import ddingdong.ddingdongBE.domain.form.entity.FormEmailSendHistory;
import ddingdong.ddingdongBE.domain.form.repository.FormEmailSendHistoryRepository;
import ddingdong.ddingdongBE.domain.formapplication.entity.FormApplicationStatus;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -21,8 +22,14 @@ public FormEmailSendHistory getById(Long id) {
.orElseThrow(() -> new ResourceNotFound("이메일 전송 기록을 찾을 수 없습니다. (id: " + id + ")"));
}



@Transactional
public FormEmailSendHistory create(Form form, FormApplicationStatus formApplicationStatus, String emailContent) {
return formEmailSendHistoryRepository.save(new FormEmailSendHistory(formApplicationStatus, emailContent, form));
}

public List<FormEmailSendHistory> getAllByFormId(Long formId) {
return formEmailSendHistoryRepository.getAllByFormId(formId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package ddingdong.ddingdongBE.domain.form.service.dto.query;

import ddingdong.ddingdongBE.domain.formapplication.entity.FormApplicationStatus;
import ddingdong.ddingdongBE.email.entity.EmailSendHistory;
import ddingdong.ddingdongBE.email.entity.EmailSendStatus;
import java.time.LocalDateTime;
import java.util.List;


public record EmailSendStatusQuery(
List<EmailSendStatusInfoQuery> emailSendStatusInfoQueries
) {

public static EmailSendStatusQuery from(List<EmailSendHistory> emailSendHistories) {
List<EmailSendStatusInfoQuery> infos = emailSendHistories.stream()
.map(EmailSendStatusInfoQuery::from)
.toList();

return new EmailSendStatusQuery(infos);
}

public record EmailSendStatusInfoQuery(
String name,
String studentNumber,
LocalDateTime sendAt,
EmailSendStatus emailSendStatus,
FormApplicationStatus formApplicationStatus
) {

public static EmailSendStatusInfoQuery from(EmailSendHistory emailSendHistory) {
return new EmailSendStatusInfoQuery(
emailSendHistory.getFormApplication().getName(),
emailSendHistory.getFormApplication().getStudentNumber(),
emailSendHistory.getSentAt(),
emailSendHistory.getStatus(),
emailSendHistory.getFormEmailSendHistory().getFormApplicationStatus()
);
}
}
}
Loading