-
Notifications
You must be signed in to change notification settings - Fork 2
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
[DDING-108] 동아리 지원 결과 email 전송 API 구현 #256
Changes from 5 commits
86a0747
234c6fb
287c45a
4235a67
ebfa8cd
1d6c986
b657367
9f18504
ccd9593
a613e50
7e4b09c
edc8851
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 |
---|---|---|
|
@@ -7,6 +7,10 @@ | |
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; | ||
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; | ||
import software.amazon.awssdk.regions.Region; | ||
import software.amazon.awssdk.services.ses.SesClient; | ||
|
||
@Configuration | ||
public class AmazonS3Config { | ||
|
@@ -30,4 +34,14 @@ public AmazonS3Client amazonS3Client() { | |
.build(); | ||
} | ||
|
||
@Bean | ||
public SesClient sesClient() { | ||
return SesClient.builder() | ||
.region(Region.AP_NORTHEAST_2) | ||
.credentialsProvider(StaticCredentialsProvider.create( | ||
AwsBasicCredentials.create(accessKey, secretKey) | ||
)) | ||
.build(); | ||
} | ||
Comment on lines
+37
to
+45
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. 🛠️ Refactor suggestion AWS SES 클라이언트 설정 개선이 필요합니다. 다음 사항들을 개선하면 좋을 것 같습니다:
다음과 같이 수정하는 것을 제안드립니다: -@Bean
-public SesClient sesClient() {
- return SesClient.builder()
- .region(Region.AP_NORTHEAST_2)
- .credentialsProvider(StaticCredentialsProvider.create(
- AwsBasicCredentials.create(accessKey, secretKey)
- ))
- .build();
-} 새로운 @Configuration
public class AmazonSesConfig {
@Value("${cloud.aws.region.static}")
private String region;
@Value("${spring.s3.access-key}")
private String accessKey;
@Value("${spring.s3.secret-key}")
private String secretKey;
@Bean
public SesClient sesClient() {
return SesClient.builder()
.region(Region.of(region))
.credentialsProvider(StaticCredentialsProvider.create(
AwsBasicCredentials.create(accessKey, secretKey)
))
.build();
}
} |
||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package ddingdong.ddingdongBE.common.config; | ||
|
||
import java.util.concurrent.Executor; | ||
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; | ||
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.scheduling.annotation.AsyncConfigurer; | ||
import org.springframework.scheduling.annotation.EnableAsync; | ||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | ||
|
||
@Configuration | ||
@EnableAsync | ||
public class AsyncConfig implements AsyncConfigurer { | ||
|
||
@Override | ||
public Executor getAsyncExecutor() { | ||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); | ||
executor.setCorePoolSize(5); | ||
executor.setMaxPoolSize(10); | ||
executor.setQueueCapacity(500); | ||
executor.setThreadNamePrefix("EmailAsync-"); | ||
executor.initialize(); | ||
return executor; | ||
} | ||
|
||
@Override | ||
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { | ||
return new SimpleAsyncUncaughtExceptionHandler(); | ||
} | ||
|
||
|
||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -2,6 +2,7 @@ | |||||||||||||||||
|
||||||||||||||||||
import ddingdong.ddingdongBE.auth.PrincipalDetails; | ||||||||||||||||||
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.UpdateFormRequest; | ||||||||||||||||||
import ddingdong.ddingdongBE.domain.form.controller.dto.response.FormListResponse; | ||||||||||||||||||
import ddingdong.ddingdongBE.domain.form.controller.dto.response.FormResponse; | ||||||||||||||||||
|
@@ -115,4 +116,12 @@ FormStatisticsResponse getFormStatistics( | |||||||||||||||||
@SecurityRequirement(name = "AccessToken") | ||||||||||||||||||
@PostMapping("/my/forms/{formId}/members/register-applicants") | ||||||||||||||||||
void registerMembers(@PathVariable("formId") Long formId); | ||||||||||||||||||
|
||||||||||||||||||
@Operation(summary = "동아리 지원 결과 이메일 전송 API") | ||||||||||||||||||
@ApiResponse(responseCode = "201", description = "동아리 지원 결과 이메일 전송 성공") | ||||||||||||||||||
@ResponseStatus(HttpStatus.OK) | ||||||||||||||||||
@SecurityRequirement(name = "AccessToken") | ||||||||||||||||||
Comment on lines
+120
to
+123
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. HTTP 상태 코드가 일관되지 않습니다. @ApiResponse는 201을 명시하고 있지만, @ResponseStatus는 200을 반환하도록 설정되어 있습니다. 리소스 생성을 의미하는 201로 통일하는 것이 좋습니다. 다음과 같이 수정하는 것을 제안합니다: @Operation(summary = "동아리 지원 결과 이메일 전송 API")
@ApiResponse(responseCode = "201", description = "동아리 지원 결과 이메일 전송 성공")
-@ResponseStatus(HttpStatus.OK)
+@ResponseStatus(HttpStatus.CREATED)
@SecurityRequirement(name = "AccessToken") 📝 Committable suggestion
Suggested change
|
||||||||||||||||||
@PostMapping("/my/forms/{formId}/results/email") | ||||||||||||||||||
void sendApplicationResultEmail(@PathVariable("formId") Long formId, | ||||||||||||||||||
@RequestBody SendApplicationResultEmailRequest request); | ||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,30 @@ | ||||||||||||||||||||||||||||||||||||||||||||
package ddingdong.ddingdongBE.domain.form.controller.dto.request; | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.domain.form.service.dto.command.SendApplicationResultEmailCommand; | ||||||||||||||||||||||||||||||||||||||||||||
import io.swagger.v3.oas.annotations.media.Schema; | ||||||||||||||||||||||||||||||||||||||||||||
import jakarta.validation.constraints.NotNull; | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
public record SendApplicationResultEmailRequest( | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
@Schema(description = "메일 제목", example = "제목") | ||||||||||||||||||||||||||||||||||||||||||||
@NotNull(message = "메일 제목은 필수입니다.") | ||||||||||||||||||||||||||||||||||||||||||||
String title, | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
@Schema(description = "전송 대상", | ||||||||||||||||||||||||||||||||||||||||||||
example = "FIRST_PASS", | ||||||||||||||||||||||||||||||||||||||||||||
allowableValues = {"FIRST_PASS", "FIRST_FAIL", "FINAL_PASS", "FINAL_FAIL"} | ||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||
@NotNull(message = "전송 대상은 필수입니다.") | ||||||||||||||||||||||||||||||||||||||||||||
String target, | ||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+13
to
+18
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. 🛠️ Refactor suggestion 전송 대상을 열거형(enum)으로 변경하는 것이 좋습니다. String 타입 대신 enum을 사용하면 타입 안전성이 향상되고 가능한 값들을 명확하게 제한할 수 있습니다. +public enum EmailTarget {
+ FIRST_PASS, FIRST_FAIL, FINAL_PASS, FINAL_FAIL
+}
public record SendApplicationResultEmailRequest(
@Schema(description = "전송 대상",
example = "FIRST_PASS",
allowableValues = {"FIRST_PASS", "FIRST_FAIL", "FINAL_PASS", "FINAL_FAIL"}
)
@NotNull(message = "전송 대상은 필수입니다.")
- String target,
+ EmailTarget target, 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
@Schema(description = "내용", example = "내용") | ||||||||||||||||||||||||||||||||||||||||||||
@NotNull(message = "메일 내용은 필수입니다.") | ||||||||||||||||||||||||||||||||||||||||||||
String message | ||||||||||||||||||||||||||||||||||||||||||||
) { | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
public SendApplicationResultEmailCommand toCommand(Long formId) { | ||||||||||||||||||||||||||||||||||||||||||||
return new SendApplicationResultEmailCommand(formId, title, target, message); | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -13,6 +13,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.domain.form.entity.FormField; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.domain.form.service.dto.command.CreateFormCommand; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.domain.form.service.dto.command.CreateFormCommand.CreateFormFieldCommand; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.domain.form.service.dto.command.SendApplicationResultEmailCommand; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.domain.form.service.dto.command.UpdateFormCommand; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.domain.form.service.dto.command.UpdateFormCommand.UpdateFormFieldCommand; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.domain.form.service.dto.query.FormListQuery; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -21,30 +22,38 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.domain.form.service.dto.query.FormStatisticsQuery.ApplicantStatisticQuery; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.domain.form.service.dto.query.FormStatisticsQuery.DepartmentStatisticQuery; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.domain.form.service.dto.query.FormStatisticsQuery.FieldStatisticsQuery; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.domain.formapplication.entity.FormApplication; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.domain.formapplication.entity.FormApplicationStatus; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.domain.formapplication.service.FormApplicationService; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.domain.form.service.dto.query.MultipleFieldStatisticsQuery; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.domain.form.service.dto.query.MultipleFieldStatisticsQuery.OptionStatisticQuery; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.domain.form.service.dto.query.TextFieldStatisticsQuery; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.domain.form.service.dto.query.TextFieldStatisticsQuery.TextStatisticsQuery; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.domain.formapplication.entity.FormApplication; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.domain.formapplication.service.FormApplicationService; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.domain.user.entity.User; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.email.SesEmailService; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import ddingdong.ddingdongBE.email.dto.EmailContent; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import java.time.LocalDate; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import java.util.List; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import java.util.Objects; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import java.util.concurrent.CompletableFuture; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import java.util.concurrent.TimeUnit; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import lombok.RequiredArgsConstructor; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import lombok.extern.slf4j.Slf4j; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import org.springframework.stereotype.Service; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
import org.springframework.transaction.annotation.Transactional; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
@Service | ||||||||||||||||||||||||||||||||||||||||||||||||||||
@RequiredArgsConstructor | ||||||||||||||||||||||||||||||||||||||||||||||||||||
@Transactional(readOnly = true) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
@Slf4j | ||||||||||||||||||||||||||||||||||||||||||||||||||||
public class FacadeCentralFormServiceImpl implements FacadeCentralFormService { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
private final FormService formService; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
private final FormFieldService formFieldService; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
private final ClubService clubService; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
private final FormStatisticService formStatisticService; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
private final FormApplicationService formApplicationService; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
private final SesEmailService sesEmailService; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
@Transactional | ||||||||||||||||||||||||||||||||||||||||||||||||||||
@Override | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -132,14 +141,16 @@ public MultipleFieldStatisticsQuery getMultipleFieldStatistics(Long fieldId) { | |||||||||||||||||||||||||||||||||||||||||||||||||||
@Override | ||||||||||||||||||||||||||||||||||||||||||||||||||||
@Transactional | ||||||||||||||||||||||||||||||||||||||||||||||||||||
public void registerApplicantAsMember(Long formId) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
List<FormApplication> finalPassedFormApplications = formApplicationService.getAllFinalPassedByFormId( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
formId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
List<FormApplication> finalPassedFormApplications = formApplicationService.getAllFinalPassedByFormId(formId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
finalPassedFormApplications.forEach(formApplication -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
Club club = formApplication.getForm().getClub(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
ClubMember clubMember = ClubMember.builder().name(formApplication.getName()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
ClubMember clubMember = ClubMember.builder() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
.name(formApplication.getName()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
.studentNumber(formApplication.getStudentNumber()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
.department(formApplication.getDepartment()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
.phoneNumber(formApplication.getPhoneNumber()).position(MEMBER).build(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
.phoneNumber(formApplication.getPhoneNumber()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
.position(MEMBER) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
.build(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
club.addClubMember(clubMember); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -155,6 +166,23 @@ public TextFieldStatisticsQuery getTextFieldStatistics(Long fieldId) { | |||||||||||||||||||||||||||||||||||||||||||||||||||
return new TextFieldStatisticsQuery(type, textStatisticsQueries); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
@Override | ||||||||||||||||||||||||||||||||||||||||||||||||||||
public void sendApplicationResultEmail(SendApplicationResultEmailCommand command) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
List<FormApplication> formApplications = formApplicationService.getAllByFormIdAndFormApplicationStatus( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
command.formId(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||
FormApplicationStatus.findStatus(command.target()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
EmailContent emailContent = EmailContent.of(command.title(), command.message()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
CompletableFuture<Void> future = sesEmailService.sendBulkResultEmails(formApplications, emailContent); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+176
to
+182
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. 🛠️ Refactor suggestion 이메일 전송 로직에 대한 유효성 검사 추가 필요 현재 구현에 다음 사항들을 추가하면 좋을 것 같습니다:
다음과 같이 수정하는 것을 제안드립니다: public void sendApplicationResultEmail(SendApplicationResultEmailCommand command) {
+ if (command.title() == null || command.title().trim().isEmpty()) {
+ throw new IllegalArgumentException("이메일 제목은 필수입니다.");
+ }
+ if (command.message() == null || command.message().trim().isEmpty()) {
+ throw new IllegalArgumentException("이메일 내용은 필수입니다.");
+ }
List<FormApplication> formApplications = formApplicationService.getAllByFormIdAndFormApplicationStatus(
command.formId(),
FormApplicationStatus.findStatus(command.target())
);
+ if (formApplications.isEmpty()) {
+ log.warn("지원자가 없습니다. formId: {}, status: {}", command.formId(), command.target());
+ return;
+ }
EmailContent emailContent = EmailContent.of(command.title(), command.message());
CompletableFuture<Void> future = sesEmailService.sendBulkResultEmails(formApplications, emailContent); 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
future.get(5, TimeUnit.MINUTES); // 최대 5분 대기 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch (Exception e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
log.error("Failed to send bulk emails", e); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
throw new RuntimeException("이메일 전송 중 오류가 발생했습니다.", e); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
private FormListQuery buildFormListQuery(Form form) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
boolean isActive = TimeUtils.isDateInRange(LocalDate.now(), form.getStartDate(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||
form.getEndDate()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -177,13 +205,13 @@ public void validateDuplicationDate(Club club, LocalDate startDate, LocalDate en | |||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
private List<FormField> toUpdateFormFields(Form originform, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
List<UpdateFormFieldCommand> updateFormFieldCommands) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
List<UpdateFormFieldCommand> updateFormFieldCommands) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
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. p4) |
||||||||||||||||||||||||||||||||||||||||||||||||||||
return updateFormFieldCommands.stream() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
.map(formFieldCommand -> formFieldCommand.toEntity(originform)).toList(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
private List<FormField> toCreateFormFields(Form savedForm, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
List<CreateFormFieldCommand> createFormFieldCommands) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
List<CreateFormFieldCommand> createFormFieldCommands) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
return createFormFieldCommands.stream() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
.map(formFieldCommand -> formFieldCommand.toEntity(savedForm)).toList(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package ddingdong.ddingdongBE.domain.form.service.dto.command; | ||
|
||
public record SendApplicationResultEmailCommand( | ||
Long formId, | ||
String title, | ||
String target, | ||
String message | ||
) { | ||
|
||
} |
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.
💡 Verification agent
🧩 Analysis chain
AWS SDK 버전 검증이 필요합니다.
AWS SDK for SES의 의존성이 추가되었습니다. 다음 사항들을 확인해 주시기 바랍니다:
io.awspring.cloud:spring-cloud-starter-aws:2.4.4
)AWS SDK 버전을 확인하기 위해 다음 웹 검색을 실행해 주세요:
🌐 Web query:
💡 Result:
The latest stable version of
software.amazon.awssdk:ses
as of February 2025 is 2.30.16, based on recent AWS SDK updates[7][9]. This version includes enhancements like improved Amazon SES Mail Manager features for traffic policy management[7].For Maven projects, use:
Key details:
Always verify dependencies against official AWS documentation or Maven Central for real-time version tracking[4][8].
Citations:
AWS SDK SES 의존성 버전 업데이트 필요
현재
build.gradle
파일에서는software.amazon.awssdk:ses:2.24.0
버전을 사용 중입니다. 최신 웹 검색 결과에 따르면 February 2025 기준 최신 안정 버전은 2.30.16입니다.따라서, 아래 사항을 검토해 주시기 바랍니다:
io.awspring.cloud:spring-cloud-starter-aws:2.4.4
와의 호환성 재확인