From ab5c4bbf776ffc1ec46d468266174fa9acbe6dc0 Mon Sep 17 00:00:00 2001 From: mirageoasis Date: Tue, 2 Jan 2024 21:00:12 +0900 Subject: [PATCH 1/7] refactor: remove unused application helper function --- .../application/enums/SortPartType.java | 9 -- .../application/enums/SortPassType.java | 7 -- .../application/helper/ApplicationHelper.java | 83 ------------------- .../application/mapper/ApplicationMapper.java | 31 +++++-- 4 files changed, 26 insertions(+), 104 deletions(-) delete mode 100644 src/main/java/ceos/backend/domain/application/enums/SortPartType.java delete mode 100644 src/main/java/ceos/backend/domain/application/enums/SortPassType.java diff --git a/src/main/java/ceos/backend/domain/application/enums/SortPartType.java b/src/main/java/ceos/backend/domain/application/enums/SortPartType.java deleted file mode 100644 index a3c2c8c4..00000000 --- a/src/main/java/ceos/backend/domain/application/enums/SortPartType.java +++ /dev/null @@ -1,9 +0,0 @@ -package ceos.backend.domain.application.enums; - -public enum SortPartType { - ALL, - FRONTEND, - BACKEND, - PRODUCT, - DESIGN -} diff --git a/src/main/java/ceos/backend/domain/application/enums/SortPassType.java b/src/main/java/ceos/backend/domain/application/enums/SortPassType.java deleted file mode 100644 index 28f2b68f..00000000 --- a/src/main/java/ceos/backend/domain/application/enums/SortPassType.java +++ /dev/null @@ -1,7 +0,0 @@ -package ceos.backend.domain.application.enums; - -public enum SortPassType { - ALL, - PASS, - FAIL -} diff --git a/src/main/java/ceos/backend/domain/application/helper/ApplicationHelper.java b/src/main/java/ceos/backend/domain/application/helper/ApplicationHelper.java index 355e9816..34ed8047 100644 --- a/src/main/java/ceos/backend/domain/application/helper/ApplicationHelper.java +++ b/src/main/java/ceos/backend/domain/application/helper/ApplicationHelper.java @@ -3,84 +3,27 @@ import ceos.backend.domain.application.domain.Application; import ceos.backend.domain.application.domain.ApplicationQuestion; -import ceos.backend.domain.application.domain.Pass; import ceos.backend.domain.application.dto.request.CreateApplicationRequest; import ceos.backend.domain.application.dto.request.UpdateAttendanceRequest; -import ceos.backend.domain.application.enums.SortPartType; -import ceos.backend.domain.application.enums.SortPassType; import ceos.backend.domain.application.exception.exceptions.ApplicantNotFound; -import ceos.backend.domain.application.mapper.ApplicationMapper; import ceos.backend.domain.application.repository.ApplicationQuestionRepository; import ceos.backend.domain.application.repository.ApplicationRepository; import ceos.backend.global.common.dto.AwsSESMail; import ceos.backend.global.common.dto.SlackUnavailableReason; -import ceos.backend.global.common.entity.Part; import ceos.backend.global.common.event.Event; import java.util.List; import java.util.UUID; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Component; @Slf4j @Component @RequiredArgsConstructor public class ApplicationHelper { - private final ApplicationMapper applicationMapper; private final ApplicationRepository applicationRepository; private final ApplicationQuestionRepository applicationQuestionRepository; - public Page getApplications( - SortPassType docPass, - SortPassType finalPass, - SortPartType sortType, - PageRequest pageRequest) { - Page pageManagements = null; - Part part = toPart(sortType); - if (docPass == SortPassType.ALL && finalPass == SortPassType.ALL) { - switch (sortType) { - case ALL -> pageManagements = applicationRepository.findAll(pageRequest); - default -> pageManagements = - applicationRepository.findAllByPart(toPart(sortType), pageRequest); - } - } else if (docPass != SortPassType.ALL && finalPass == SortPassType.ALL) { - Pass pass = toPass(docPass); - switch (sortType) { - case ALL -> pageManagements = - applicationRepository.findAllByDocumentPass(pass, pageRequest); - default -> pageManagements = - applicationRepository.findAllByPartAndDocumentPass( - toPart(sortType), pass, pageRequest); - } - } else if (docPass == SortPassType.ALL && finalPass != SortPassType.ALL) { - Pass pass = toPass(finalPass); - switch (sortType) { - case ALL -> pageManagements = - applicationRepository.findAllByFinalPass(pass, pageRequest); - default -> pageManagements = - applicationRepository.findAllByPartAndFinalPass( - toPart(sortType), pass, pageRequest); - } - } else { - Pass convertedDocPass = toPass(docPass); - Pass convertedFinalPass = toPass(finalPass); - switch (sortType) { - case ALL -> pageManagements = - applicationRepository.findAllByDocumentPassAndFinalPass( - convertedDocPass, convertedFinalPass, pageRequest); - default -> pageManagements = - applicationRepository.findAllByPartAndDocumentPassAndFinalPass( - toPart(sortType), - convertedDocPass, - convertedFinalPass, - pageRequest); - } - } - return pageManagements; - } - public String generateUUID() { String newUUID; while (true) { @@ -122,30 +65,4 @@ public Application getApplicationByUuidAndEmail(String uuid, String email) { throw ApplicantNotFound.EXCEPTION; }); } - - private Pass toPass(SortPassType passType) { - Pass pass = Pass.FAIL; - if (passType == SortPassType.PASS) { - pass = Pass.PASS; - } - return pass; - } - - private Part toPart(SortPartType sortType) { - switch (sortType) { - case DESIGN -> { - return Part.DESIGN; - } - case BACKEND -> { - return Part.BACKEND; - } - case PRODUCT -> { - return Part.PRODUCT; - } - case FRONTEND -> { - return Part.FRONTEND; - } - } - return null; - } } diff --git a/src/main/java/ceos/backend/domain/application/mapper/ApplicationMapper.java b/src/main/java/ceos/backend/domain/application/mapper/ApplicationMapper.java index 00f83c0c..89d3fbe2 100644 --- a/src/main/java/ceos/backend/domain/application/mapper/ApplicationMapper.java +++ b/src/main/java/ceos/backend/domain/application/mapper/ApplicationMapper.java @@ -1,14 +1,31 @@ package ceos.backend.domain.application.mapper; -import static java.util.Map.*; -import ceos.backend.domain.application.domain.*; +import ceos.backend.domain.application.domain.Application; +import ceos.backend.domain.application.domain.ApplicationAnswer; +import ceos.backend.domain.application.domain.ApplicationInterview; +import ceos.backend.domain.application.domain.ApplicationQuestion; +import ceos.backend.domain.application.domain.ApplicationQuestionDetail; +import ceos.backend.domain.application.domain.Interview; +import ceos.backend.domain.application.domain.QuestionCategory; import ceos.backend.domain.application.dto.request.CreateApplicationRequest; import ceos.backend.domain.application.dto.request.UpdateApplicationQuestion; -import ceos.backend.domain.application.dto.response.*; +import ceos.backend.domain.application.dto.response.GetApplication; +import ceos.backend.domain.application.dto.response.GetApplicationQuestion; +import ceos.backend.domain.application.dto.response.GetApplications; +import ceos.backend.domain.application.dto.response.GetInterviewTime; +import ceos.backend.domain.application.dto.response.GetResultResponse; import ceos.backend.domain.application.exception.exceptions.InterviewNotFound; import ceos.backend.domain.application.exception.exceptions.QuestionNotFound; -import ceos.backend.domain.application.vo.*; +import ceos.backend.domain.application.vo.AnswerVo; +import ceos.backend.domain.application.vo.ApplicationBriefInfoVo; +import ceos.backend.domain.application.vo.InterviewDateTimesVo; +import ceos.backend.domain.application.vo.InterviewTimeVo; +import ceos.backend.domain.application.vo.QnAVo; +import ceos.backend.domain.application.vo.QuestionDetailVo; +import ceos.backend.domain.application.vo.QuestionListVo; +import ceos.backend.domain.application.vo.QuestionVo; +import ceos.backend.domain.application.vo.QuestionWithIdVo; import ceos.backend.domain.recruitment.domain.Recruitment; import ceos.backend.global.common.dto.PageInfo; import ceos.backend.global.common.dto.ParsedDuration; @@ -17,7 +34,11 @@ import ceos.backend.global.util.ParsedDurationConvertor; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -import java.util.*; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; +import java.util.Set; import java.util.stream.Collectors; import org.springframework.data.domain.Page; import org.springframework.stereotype.Component; From 5e48c5b471f5edd4bf1acd5f9dbef80cdd210a7d Mon Sep 17 00:00:00 2001 From: mirageoasis Date: Tue, 2 Jan 2024 23:09:13 +0900 Subject: [PATCH 2/7] feature: add restrospect service and repository --- .../retrospect/RetrospectController.java | 15 ++++ .../domain/retrospect/domain/Retrospect.java | 59 ++++++++++++++++ .../dto/request/CreateRetrospectRequest.java | 44 ++++++++++++ .../dto/request/UpdateRetrospectRequest.java | 41 +++++++++++ .../dto/response/GetRetrospectResponse.java | 24 +++++++ .../dto/response/GetRetrospectsElement.java | 23 ++++++ .../dto/response/GetRetrospectsResponse.java | 26 +++++++ .../exception/RetrospectErrorCode.java | 24 +++++++ .../exception/RetrospectNotFound.java | 13 ++++ .../repository/RetrospectRepository.java | 12 ++++ .../retrospect/service/RetrospectService.java | 70 +++++++++++++++++++ 11 files changed, 351 insertions(+) create mode 100644 src/main/java/ceos/backend/domain/retrospect/RetrospectController.java create mode 100644 src/main/java/ceos/backend/domain/retrospect/domain/Retrospect.java create mode 100644 src/main/java/ceos/backend/domain/retrospect/dto/request/CreateRetrospectRequest.java create mode 100644 src/main/java/ceos/backend/domain/retrospect/dto/request/UpdateRetrospectRequest.java create mode 100644 src/main/java/ceos/backend/domain/retrospect/dto/response/GetRetrospectResponse.java create mode 100644 src/main/java/ceos/backend/domain/retrospect/dto/response/GetRetrospectsElement.java create mode 100644 src/main/java/ceos/backend/domain/retrospect/dto/response/GetRetrospectsResponse.java create mode 100644 src/main/java/ceos/backend/domain/retrospect/exception/RetrospectErrorCode.java create mode 100644 src/main/java/ceos/backend/domain/retrospect/exception/RetrospectNotFound.java create mode 100644 src/main/java/ceos/backend/domain/retrospect/repository/RetrospectRepository.java create mode 100644 src/main/java/ceos/backend/domain/retrospect/service/RetrospectService.java diff --git a/src/main/java/ceos/backend/domain/retrospect/RetrospectController.java b/src/main/java/ceos/backend/domain/retrospect/RetrospectController.java new file mode 100644 index 00000000..a66e8329 --- /dev/null +++ b/src/main/java/ceos/backend/domain/retrospect/RetrospectController.java @@ -0,0 +1,15 @@ +package ceos.backend.domain.retrospect; + + +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping(value = "/retrospect") +@Tag(name = "Retrospect") +public class RetrospectController {} diff --git a/src/main/java/ceos/backend/domain/retrospect/domain/Retrospect.java b/src/main/java/ceos/backend/domain/retrospect/domain/Retrospect.java new file mode 100644 index 00000000..979f0b1b --- /dev/null +++ b/src/main/java/ceos/backend/domain/retrospect/domain/Retrospect.java @@ -0,0 +1,59 @@ +package ceos.backend.domain.retrospect.domain; + + +import ceos.backend.domain.retrospect.dto.request.CreateRetrospectRequest; +import ceos.backend.global.common.entity.BaseEntity; +import ceos.backend.global.common.entity.Part; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class Retrospect extends BaseEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "retrospect_id") + private Long id; + + @NotBlank private String title; + + @NotBlank private String content; + + @NotBlank private String writer; + + @NotNull @Positive private Integer generation; + + @NotNull + @Enumerated(EnumType.STRING) + private Part part; + + @Builder + public Retrospect(String title, String content, String writer, Integer generation, Part part) { + this.title = title; + this.content = content; + this.writer = writer; + this.generation = generation; + this.part = part; + } + + public void update(CreateRetrospectRequest createRetrospectRequest) { + title = createRetrospectRequest.getTitle(); + content = createRetrospectRequest.getContent(); + writer = createRetrospectRequest.getWriter(); + generation = createRetrospectRequest.getGeneration(); + part = createRetrospectRequest.getPart(); + } +} diff --git a/src/main/java/ceos/backend/domain/retrospect/dto/request/CreateRetrospectRequest.java b/src/main/java/ceos/backend/domain/retrospect/dto/request/CreateRetrospectRequest.java new file mode 100644 index 00000000..7188a91e --- /dev/null +++ b/src/main/java/ceos/backend/domain/retrospect/dto/request/CreateRetrospectRequest.java @@ -0,0 +1,44 @@ +package ceos.backend.domain.retrospect.dto.request; + + +import ceos.backend.domain.retrospect.domain.Retrospect; +import ceos.backend.global.common.entity.Part; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; +import lombok.Data; + +@Data +public class CreateRetrospectRequest { + @NotBlank(message = "회고 제목을 입력해주세요") + @Schema(type = "string", description = "회고 제목") + private String title; + + @NotBlank(message = "회고 내용을 입력해주세요") + @Schema(type = "string", description = "회고 내용") + private String content; + + @NotBlank(message = "작성자를 입력해주세요") + @Schema(type = "string", description = "회고 제목") + private String writer; + + @NotNull(message = "기수를 입력해주세요") + @Positive + @Schema(type = "integer", description = "기수") + private Integer generation; + + @NotNull(message = "파트를 입력해주세요") + @Schema(type = "Part", description = "파트") + private Part part; + + public Retrospect toEntity() { + return Retrospect.builder() + .title(title) + .content(content) + .writer(writer) + .generation(generation) + .part(part) + .build(); + } +} diff --git a/src/main/java/ceos/backend/domain/retrospect/dto/request/UpdateRetrospectRequest.java b/src/main/java/ceos/backend/domain/retrospect/dto/request/UpdateRetrospectRequest.java new file mode 100644 index 00000000..cc8d6062 --- /dev/null +++ b/src/main/java/ceos/backend/domain/retrospect/dto/request/UpdateRetrospectRequest.java @@ -0,0 +1,41 @@ +package ceos.backend.domain.retrospect.dto.request; + +import ceos.backend.domain.retrospect.domain.Retrospect; +import ceos.backend.global.common.entity.Part; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; + +public class UpdateRetrospectRequest { + @NotBlank(message = "회고 제목을 입력해주세요") + @Schema(type = "string", description = "회고 제목") + private String title; + + @NotBlank(message = "회고 내용을 입력해주세요") + @Schema(type = "string", description = "회고 내용") + private String content; + + @NotBlank(message = "작성자를 입력해주세요") + @Schema(type = "string", description = "회고 제목") + private String writer; + + @NotNull(message = "기수를 입력해주세요") + @Positive + @Schema(type = "integer", description = "기수") + private Integer generation; + + @NotNull(message = "파트를 입력해주세요") + @Schema(type = "Part", description = "파트") + private Part part; + + public Retrospect toEntity() { + return Retrospect.builder() + .title(title) + .content(content) + .writer(writer) + .generation(generation) + .part(part) + .build(); + } +} diff --git a/src/main/java/ceos/backend/domain/retrospect/dto/response/GetRetrospectResponse.java b/src/main/java/ceos/backend/domain/retrospect/dto/response/GetRetrospectResponse.java new file mode 100644 index 00000000..73570f7f --- /dev/null +++ b/src/main/java/ceos/backend/domain/retrospect/dto/response/GetRetrospectResponse.java @@ -0,0 +1,24 @@ +package ceos.backend.domain.retrospect.dto.response; + + +import ceos.backend.domain.retrospect.domain.Retrospect; +import lombok.Data; + +@Data +public class GetRetrospectResponse { + private Long id; + private String title; + private String content; + private String writer; + + public static GetRetrospectResponse fromEntity(Retrospect retrospect) { + GetRetrospectResponse getRetrospectResponse = new GetRetrospectResponse(); + + getRetrospectResponse.setId(retrospect.getId()); + getRetrospectResponse.setTitle(retrospect.getTitle()); + getRetrospectResponse.setContent(retrospect.getContent()); + getRetrospectResponse.setWriter(retrospect.getWriter()); + + return getRetrospectResponse; + } +} diff --git a/src/main/java/ceos/backend/domain/retrospect/dto/response/GetRetrospectsElement.java b/src/main/java/ceos/backend/domain/retrospect/dto/response/GetRetrospectsElement.java new file mode 100644 index 00000000..35bea674 --- /dev/null +++ b/src/main/java/ceos/backend/domain/retrospect/dto/response/GetRetrospectsElement.java @@ -0,0 +1,23 @@ +package ceos.backend.domain.retrospect.dto.response; + + +import ceos.backend.domain.retrospect.domain.Retrospect; +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class GetRetrospectsElement { + private Long id; + private String title; + private String writer; + private Integer generation; + + public static GetRetrospectsElement fromEntity(Retrospect retrospect) { + return new GetRetrospectsElement( + retrospect.getId(), + retrospect.getTitle(), + retrospect.getWriter(), + retrospect.getGeneration()); + } +} diff --git a/src/main/java/ceos/backend/domain/retrospect/dto/response/GetRetrospectsResponse.java b/src/main/java/ceos/backend/domain/retrospect/dto/response/GetRetrospectsResponse.java new file mode 100644 index 00000000..f92df6a2 --- /dev/null +++ b/src/main/java/ceos/backend/domain/retrospect/dto/response/GetRetrospectsResponse.java @@ -0,0 +1,26 @@ +package ceos.backend.domain.retrospect.dto.response; + + +import ceos.backend.domain.retrospect.domain.Retrospect; +import ceos.backend.global.common.dto.PageInfo; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Data; +import org.springframework.data.domain.Page; + +@Data +@AllArgsConstructor +public class GetRetrospectsResponse { + public List retrospects; + public PageInfo pageInfo; + + public static GetRetrospectsResponse fromPageable(Page retrospects) { + return new GetRetrospectsResponse( + retrospects.map(GetRetrospectsElement::fromEntity).toList(), + PageInfo.of( + retrospects.getNumber(), + retrospects.getSize(), + retrospects.getTotalPages(), + retrospects.getTotalElements())); + } +} diff --git a/src/main/java/ceos/backend/domain/retrospect/exception/RetrospectErrorCode.java b/src/main/java/ceos/backend/domain/retrospect/exception/RetrospectErrorCode.java new file mode 100644 index 00000000..a4625ac6 --- /dev/null +++ b/src/main/java/ceos/backend/domain/retrospect/exception/RetrospectErrorCode.java @@ -0,0 +1,24 @@ +package ceos.backend.domain.retrospect.exception; + +import static org.springframework.http.HttpStatus.BAD_REQUEST; + +import ceos.backend.global.common.dto.ErrorReason; +import ceos.backend.global.error.BaseErrorCode; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum RetrospectErrorCode implements BaseErrorCode { + RETROSPECT_NOT_FOUND(BAD_REQUEST, "QUESTION_404_1", "존재하지 않는 질문입니다."); + + private HttpStatus status; + private String code; + private String reason; + + @Override + public ErrorReason getErrorReason() { + return ErrorReason.of(status.value(), code, reason); + } +} diff --git a/src/main/java/ceos/backend/domain/retrospect/exception/RetrospectNotFound.java b/src/main/java/ceos/backend/domain/retrospect/exception/RetrospectNotFound.java new file mode 100644 index 00000000..fe2055bd --- /dev/null +++ b/src/main/java/ceos/backend/domain/retrospect/exception/RetrospectNotFound.java @@ -0,0 +1,13 @@ +package ceos.backend.domain.retrospect.exception; + + +import ceos.backend.global.error.BaseErrorException; + +public class RetrospectNotFound extends BaseErrorException { + + public static final RetrospectNotFound EXCEPTION = new RetrospectNotFound(); + + public RetrospectNotFound() { + super(RetrospectErrorCode.RETROSPECT_NOT_FOUND); + } +} diff --git a/src/main/java/ceos/backend/domain/retrospect/repository/RetrospectRepository.java b/src/main/java/ceos/backend/domain/retrospect/repository/RetrospectRepository.java new file mode 100644 index 00000000..11623b56 --- /dev/null +++ b/src/main/java/ceos/backend/domain/retrospect/repository/RetrospectRepository.java @@ -0,0 +1,12 @@ +package ceos.backend.domain.retrospect.repository; + + +import ceos.backend.domain.retrospect.domain.Retrospect; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface RetrospectRepository extends JpaRepository { + Page findAll(PageRequest pageRequest, Sort sort); +} diff --git a/src/main/java/ceos/backend/domain/retrospect/service/RetrospectService.java b/src/main/java/ceos/backend/domain/retrospect/service/RetrospectService.java new file mode 100644 index 00000000..101e4858 --- /dev/null +++ b/src/main/java/ceos/backend/domain/retrospect/service/RetrospectService.java @@ -0,0 +1,70 @@ +package ceos.backend.domain.retrospect.service; + + +import ceos.backend.domain.retrospect.domain.Retrospect; +import ceos.backend.domain.retrospect.dto.request.CreateRetrospectRequest; +import ceos.backend.domain.retrospect.dto.response.GetRetrospectResponse; +import ceos.backend.domain.retrospect.dto.response.GetRetrospectsResponse; +import ceos.backend.domain.retrospect.exception.RetrospectNotFound; +import ceos.backend.domain.retrospect.repository.RetrospectRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.data.domain.Sort.Direction; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class RetrospectService { + + private final RetrospectRepository retrospectRepository; + + // 1. 회고 작성 메서드 + + @Transactional + public void createRetrospect(CreateRetrospectRequest createRetrospectRequest) { + retrospectRepository.save(createRetrospectRequest.toEntity()); + } + + // 2. 회고 리스트 메서드(페이징) + @Transactional(readOnly = true) + public GetRetrospectsResponse getRetrospects(Integer pageNum, Integer limit) { + PageRequest pageRequest = PageRequest.of(pageNum, limit); + Sort sort = Sort.by(Direction.DESC, "id"); + + Page data = retrospectRepository.findAll(pageRequest, sort); + + return GetRetrospectsResponse.fromPageable(data); + } + + // 3. 회고 수정 메서드 + @Transactional + public GetRetrospectResponse updateRetrospect(Long id, CreateRetrospectRequest createRetrospectRequest) { + Retrospect retrospect = + retrospectRepository.findById(id).orElseThrow(() -> new RetrospectNotFound()); + + retrospect.update(createRetrospectRequest); + + return GetRetrospectResponse.fromEntity(retrospect); + } + + + // 4. 회고 삭제 메서드 + @Transactional + public void deleteRetrospect(Long id) { + Retrospect retrospect = + retrospectRepository.findById(id).orElseThrow(() -> new RetrospectNotFound()); + + retrospectRepository.delete(retrospect); + } + + // 5. 회고 상세 조회 메서드 + @Transactional(readOnly = true) + public GetRetrospectResponse getRetrospect(Long id) { + Retrospect retrospect = retrospectRepository.findById(id).orElseThrow(() -> new RetrospectNotFound()); + + return GetRetrospectResponse.fromEntity(retrospect); + } +} From 4372a26885d57b6d8a01108c82b78b88c306830b Mon Sep 17 00:00:00 2001 From: mirageoasis Date: Wed, 3 Jan 2024 00:23:32 +0900 Subject: [PATCH 3/7] feature: add restrospect controller --- .../retrospect/RetrospectController.java | 63 ++++++++++++++++++- .../dto/request/UpdateRetrospectRequest.java | 1 + .../repository/RetrospectRepository.java | 5 +- .../retrospect/service/RetrospectService.java | 16 +++-- 4 files changed, 72 insertions(+), 13 deletions(-) diff --git a/src/main/java/ceos/backend/domain/retrospect/RetrospectController.java b/src/main/java/ceos/backend/domain/retrospect/RetrospectController.java index a66e8329..05896a59 100644 --- a/src/main/java/ceos/backend/domain/retrospect/RetrospectController.java +++ b/src/main/java/ceos/backend/domain/retrospect/RetrospectController.java @@ -1,15 +1,76 @@ package ceos.backend.domain.retrospect; +import ceos.backend.domain.retrospect.dto.request.CreateRetrospectRequest; +import ceos.backend.domain.retrospect.dto.response.GetRetrospectResponse; +import ceos.backend.domain.retrospect.dto.response.GetRetrospectsResponse; +import ceos.backend.domain.retrospect.service.RetrospectService; +import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @Slf4j @RestController @RequiredArgsConstructor +@Validated @RequestMapping(value = "/retrospect") @Tag(name = "Retrospect") -public class RetrospectController {} +public class RetrospectController { + private final RetrospectService retrospectService; + + @Operation(summary = "회고록 목록 보기") + @GetMapping + public GetRetrospectsResponse getRetrospects( + @RequestParam("pageNum") int pageNum, @RequestParam("limit") int limit) { + log.info("회고록 목록 보기"); + + return retrospectService.getRetrospects(pageNum, limit); + } + + @Operation(summary = "회고록 상세 보기") + @GetMapping("/{id}") + public GetRetrospectResponse getRetrospect(@PathVariable("id") Long id) { + log.info("회고록 상세 보기"); + + return retrospectService.getRetrospect(id); + } + + @Operation(summary = "회고록 작성") + @PostMapping + public void createRetrospect( + @RequestBody @Valid CreateRetrospectRequest createRetrospectRequest) { + log.info("회고록 작성"); + + retrospectService.createRetrospect(createRetrospectRequest); + } + + @Operation(summary = "회고록 수정") + @PutMapping("/{id}") + public GetRetrospectResponse updateRetrospect( + @PathVariable("id") Long id, + @RequestBody @Valid CreateRetrospectRequest createRetrospectRequest) { + log.info("회고록 수정"); + + return retrospectService.updateRetrospect(id, createRetrospectRequest); + } + + @Operation(summary = "회고록 삭제") + @DeleteMapping("/{id}") + public void deleteRetrospect(@PathVariable("id") Long id) { + log.info("회고록 삭제"); + + retrospectService.deleteRetrospect(id); + } +} diff --git a/src/main/java/ceos/backend/domain/retrospect/dto/request/UpdateRetrospectRequest.java b/src/main/java/ceos/backend/domain/retrospect/dto/request/UpdateRetrospectRequest.java index cc8d6062..9f40ece6 100644 --- a/src/main/java/ceos/backend/domain/retrospect/dto/request/UpdateRetrospectRequest.java +++ b/src/main/java/ceos/backend/domain/retrospect/dto/request/UpdateRetrospectRequest.java @@ -1,5 +1,6 @@ package ceos.backend.domain.retrospect.dto.request; + import ceos.backend.domain.retrospect.domain.Retrospect; import ceos.backend.global.common.entity.Part; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/src/main/java/ceos/backend/domain/retrospect/repository/RetrospectRepository.java b/src/main/java/ceos/backend/domain/retrospect/repository/RetrospectRepository.java index 11623b56..b1c2ac03 100644 --- a/src/main/java/ceos/backend/domain/retrospect/repository/RetrospectRepository.java +++ b/src/main/java/ceos/backend/domain/retrospect/repository/RetrospectRepository.java @@ -3,10 +3,9 @@ import ceos.backend.domain.retrospect.domain.Retrospect; import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Sort; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; public interface RetrospectRepository extends JpaRepository { - Page findAll(PageRequest pageRequest, Sort sort); + Page findAll(Pageable pageable); } diff --git a/src/main/java/ceos/backend/domain/retrospect/service/RetrospectService.java b/src/main/java/ceos/backend/domain/retrospect/service/RetrospectService.java index 101e4858..2bcbe621 100644 --- a/src/main/java/ceos/backend/domain/retrospect/service/RetrospectService.java +++ b/src/main/java/ceos/backend/domain/retrospect/service/RetrospectService.java @@ -11,18 +11,15 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; -import org.springframework.data.domain.Sort.Direction; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor public class RetrospectService { - private final RetrospectRepository retrospectRepository; // 1. 회고 작성 메서드 - @Transactional public void createRetrospect(CreateRetrospectRequest createRetrospectRequest) { retrospectRepository.save(createRetrospectRequest.toEntity()); @@ -31,17 +28,18 @@ public void createRetrospect(CreateRetrospectRequest createRetrospectRequest) { // 2. 회고 리스트 메서드(페이징) @Transactional(readOnly = true) public GetRetrospectsResponse getRetrospects(Integer pageNum, Integer limit) { - PageRequest pageRequest = PageRequest.of(pageNum, limit); - Sort sort = Sort.by(Direction.DESC, "id"); + Sort sort = Sort.by(Sort.Direction.DESC, "id"); + PageRequest pageRequest = PageRequest.of(pageNum, limit, sort); - Page data = retrospectRepository.findAll(pageRequest, sort); + Page data = retrospectRepository.findAll(pageRequest); return GetRetrospectsResponse.fromPageable(data); } // 3. 회고 수정 메서드 @Transactional - public GetRetrospectResponse updateRetrospect(Long id, CreateRetrospectRequest createRetrospectRequest) { + public GetRetrospectResponse updateRetrospect( + Long id, CreateRetrospectRequest createRetrospectRequest) { Retrospect retrospect = retrospectRepository.findById(id).orElseThrow(() -> new RetrospectNotFound()); @@ -50,7 +48,6 @@ public GetRetrospectResponse updateRetrospect(Long id, CreateRetrospectRequest c return GetRetrospectResponse.fromEntity(retrospect); } - // 4. 회고 삭제 메서드 @Transactional public void deleteRetrospect(Long id) { @@ -63,7 +60,8 @@ public void deleteRetrospect(Long id) { // 5. 회고 상세 조회 메서드 @Transactional(readOnly = true) public GetRetrospectResponse getRetrospect(Long id) { - Retrospect retrospect = retrospectRepository.findById(id).orElseThrow(() -> new RetrospectNotFound()); + Retrospect retrospect = + retrospectRepository.findById(id).orElseThrow(() -> new RetrospectNotFound()); return GetRetrospectResponse.fromEntity(retrospect); } From e06df75713c8981a504311d4b499e143260985c0 Mon Sep 17 00:00:00 2001 From: mirageoasis Date: Fri, 5 Jan 2024 20:24:02 +0900 Subject: [PATCH 4/7] fixed: turned content into url and follwing fixes --- .../ceos/backend/domain/retrospect/domain/Retrospect.java | 8 ++++---- .../retrospect/dto/request/CreateRetrospectRequest.java | 6 +++--- .../retrospect/dto/request/UpdateRetrospectRequest.java | 6 +++--- .../retrospect/dto/response/GetRetrospectResponse.java | 4 ++-- .../retrospect/dto/response/GetRetrospectsElement.java | 2 ++ .../domain/retrospect/service/RetrospectService.java | 6 +++--- 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/main/java/ceos/backend/domain/retrospect/domain/Retrospect.java b/src/main/java/ceos/backend/domain/retrospect/domain/Retrospect.java index 979f0b1b..8d7f6691 100644 --- a/src/main/java/ceos/backend/domain/retrospect/domain/Retrospect.java +++ b/src/main/java/ceos/backend/domain/retrospect/domain/Retrospect.java @@ -30,7 +30,7 @@ public class Retrospect extends BaseEntity { @NotBlank private String title; - @NotBlank private String content; + @NotBlank private String url; @NotBlank private String writer; @@ -41,9 +41,9 @@ public class Retrospect extends BaseEntity { private Part part; @Builder - public Retrospect(String title, String content, String writer, Integer generation, Part part) { + public Retrospect(String title, String url, String writer, Integer generation, Part part) { this.title = title; - this.content = content; + this.url = url; this.writer = writer; this.generation = generation; this.part = part; @@ -51,7 +51,7 @@ public Retrospect(String title, String content, String writer, Integer generatio public void update(CreateRetrospectRequest createRetrospectRequest) { title = createRetrospectRequest.getTitle(); - content = createRetrospectRequest.getContent(); + url = createRetrospectRequest.getUrl(); writer = createRetrospectRequest.getWriter(); generation = createRetrospectRequest.getGeneration(); part = createRetrospectRequest.getPart(); diff --git a/src/main/java/ceos/backend/domain/retrospect/dto/request/CreateRetrospectRequest.java b/src/main/java/ceos/backend/domain/retrospect/dto/request/CreateRetrospectRequest.java index 7188a91e..99478a5f 100644 --- a/src/main/java/ceos/backend/domain/retrospect/dto/request/CreateRetrospectRequest.java +++ b/src/main/java/ceos/backend/domain/retrospect/dto/request/CreateRetrospectRequest.java @@ -15,9 +15,9 @@ public class CreateRetrospectRequest { @Schema(type = "string", description = "회고 제목") private String title; - @NotBlank(message = "회고 내용을 입력해주세요") + @NotBlank(message = "회고 내용이 담긴 url을 입력해주세요") @Schema(type = "string", description = "회고 내용") - private String content; + private String url; @NotBlank(message = "작성자를 입력해주세요") @Schema(type = "string", description = "회고 제목") @@ -35,7 +35,7 @@ public class CreateRetrospectRequest { public Retrospect toEntity() { return Retrospect.builder() .title(title) - .content(content) + .url(url) .writer(writer) .generation(generation) .part(part) diff --git a/src/main/java/ceos/backend/domain/retrospect/dto/request/UpdateRetrospectRequest.java b/src/main/java/ceos/backend/domain/retrospect/dto/request/UpdateRetrospectRequest.java index 9f40ece6..a00c4593 100644 --- a/src/main/java/ceos/backend/domain/retrospect/dto/request/UpdateRetrospectRequest.java +++ b/src/main/java/ceos/backend/domain/retrospect/dto/request/UpdateRetrospectRequest.java @@ -13,9 +13,9 @@ public class UpdateRetrospectRequest { @Schema(type = "string", description = "회고 제목") private String title; - @NotBlank(message = "회고 내용을 입력해주세요") + @NotBlank(message = "회고 내용이 담긴 url을 입력해주세요") @Schema(type = "string", description = "회고 내용") - private String content; + private String url; @NotBlank(message = "작성자를 입력해주세요") @Schema(type = "string", description = "회고 제목") @@ -33,7 +33,7 @@ public class UpdateRetrospectRequest { public Retrospect toEntity() { return Retrospect.builder() .title(title) - .content(content) + .url(url) .writer(writer) .generation(generation) .part(part) diff --git a/src/main/java/ceos/backend/domain/retrospect/dto/response/GetRetrospectResponse.java b/src/main/java/ceos/backend/domain/retrospect/dto/response/GetRetrospectResponse.java index 73570f7f..9fcb7ae8 100644 --- a/src/main/java/ceos/backend/domain/retrospect/dto/response/GetRetrospectResponse.java +++ b/src/main/java/ceos/backend/domain/retrospect/dto/response/GetRetrospectResponse.java @@ -8,7 +8,7 @@ public class GetRetrospectResponse { private Long id; private String title; - private String content; + private String url; private String writer; public static GetRetrospectResponse fromEntity(Retrospect retrospect) { @@ -16,7 +16,7 @@ public static GetRetrospectResponse fromEntity(Retrospect retrospect) { getRetrospectResponse.setId(retrospect.getId()); getRetrospectResponse.setTitle(retrospect.getTitle()); - getRetrospectResponse.setContent(retrospect.getContent()); + getRetrospectResponse.setUrl(retrospect.getUrl()); getRetrospectResponse.setWriter(retrospect.getWriter()); return getRetrospectResponse; diff --git a/src/main/java/ceos/backend/domain/retrospect/dto/response/GetRetrospectsElement.java b/src/main/java/ceos/backend/domain/retrospect/dto/response/GetRetrospectsElement.java index 35bea674..356cf4b2 100644 --- a/src/main/java/ceos/backend/domain/retrospect/dto/response/GetRetrospectsElement.java +++ b/src/main/java/ceos/backend/domain/retrospect/dto/response/GetRetrospectsElement.java @@ -10,6 +10,7 @@ public class GetRetrospectsElement { private Long id; private String title; + private String url; private String writer; private Integer generation; @@ -17,6 +18,7 @@ public static GetRetrospectsElement fromEntity(Retrospect retrospect) { return new GetRetrospectsElement( retrospect.getId(), retrospect.getTitle(), + retrospect.getUrl(), retrospect.getWriter(), retrospect.getGeneration()); } diff --git a/src/main/java/ceos/backend/domain/retrospect/service/RetrospectService.java b/src/main/java/ceos/backend/domain/retrospect/service/RetrospectService.java index 2bcbe621..905205fc 100644 --- a/src/main/java/ceos/backend/domain/retrospect/service/RetrospectService.java +++ b/src/main/java/ceos/backend/domain/retrospect/service/RetrospectService.java @@ -41,7 +41,7 @@ public GetRetrospectsResponse getRetrospects(Integer pageNum, Integer limit) { public GetRetrospectResponse updateRetrospect( Long id, CreateRetrospectRequest createRetrospectRequest) { Retrospect retrospect = - retrospectRepository.findById(id).orElseThrow(() -> new RetrospectNotFound()); + retrospectRepository.findById(id).orElseThrow(RetrospectNotFound::new); retrospect.update(createRetrospectRequest); @@ -52,7 +52,7 @@ public GetRetrospectResponse updateRetrospect( @Transactional public void deleteRetrospect(Long id) { Retrospect retrospect = - retrospectRepository.findById(id).orElseThrow(() -> new RetrospectNotFound()); + retrospectRepository.findById(id).orElseThrow(RetrospectNotFound::new); retrospectRepository.delete(retrospect); } @@ -61,7 +61,7 @@ public void deleteRetrospect(Long id) { @Transactional(readOnly = true) public GetRetrospectResponse getRetrospect(Long id) { Retrospect retrospect = - retrospectRepository.findById(id).orElseThrow(() -> new RetrospectNotFound()); + retrospectRepository.findById(id).orElseThrow(RetrospectNotFound::new); return GetRetrospectResponse.fromEntity(retrospect); } From 084f952c63247b96d59ae9371475fda2b9bf8bd0 Mon Sep 17 00:00:00 2001 From: suhhyun <97878992+suhhyun524@users.noreply.github.com> Date: Fri, 19 Jan 2024 19:25:15 +0900 Subject: [PATCH 5/7] =?UTF-8?q?[feat]=20=EB=A9=94=EC=9D=BC=EB=A7=81=20?= =?UTF-8?q?=EC=84=9C=EB=B9=84=EC=8A=A4=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(#168)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [feat] 메일 템플릿 및 기능 구현 * [feat] 도메인 및 ENUM 작성 * [feat] 메일링 서비스 구현 * [feat] 에러 처리 * [refact] url 및 메서드 명 변경 * [add] 루트 권한 설정 * [chore] enum 필드 삭제 --- .../subscriber/SubscriberController.java | 35 +++++++++++++ .../domain/subscriber/domain/Subscriber.java | 37 ++++++++++++++ .../dto/request/SubscribeRequest.java | 14 ++++++ .../subscriber/exception/DuplicateData.java | 13 +++++ .../subscriber/exception/InvalidAction.java | 13 +++++ .../exception/SubscriberErrorCode.java | 27 ++++++++++ .../subscriber/helper/SubscriberHelper.java | 35 +++++++++++++ .../repository/SubscriberRepository.java | 11 ++++ .../subscriber/service/SubscriberService.java | 50 +++++++++++++++++++ .../global/common/dto/AwsSESRecruitMail.java | 21 ++++++++ .../global/common/dto/mail/EmailInfo.java | 22 ++++++++ .../global/config/WebSecurityConfig.java | 2 +- .../infra/ses/AwsSESMailGenerator.java | 13 +++++ .../infra/ses/AwsSESSendMailHandler.java | 9 ++++ .../templates/component/copyright.html | 2 +- .../templates/component/recruit.html | 30 +++++++++++ .../templates/component/recruitButton.html | 35 +++++++++++++ .../resources/templates/sendRecruitMail.html | 43 ++++++++++++++++ 18 files changed, 410 insertions(+), 2 deletions(-) create mode 100644 src/main/java/ceos/backend/domain/subscriber/SubscriberController.java create mode 100644 src/main/java/ceos/backend/domain/subscriber/domain/Subscriber.java create mode 100644 src/main/java/ceos/backend/domain/subscriber/dto/request/SubscribeRequest.java create mode 100644 src/main/java/ceos/backend/domain/subscriber/exception/DuplicateData.java create mode 100644 src/main/java/ceos/backend/domain/subscriber/exception/InvalidAction.java create mode 100644 src/main/java/ceos/backend/domain/subscriber/exception/SubscriberErrorCode.java create mode 100644 src/main/java/ceos/backend/domain/subscriber/helper/SubscriberHelper.java create mode 100644 src/main/java/ceos/backend/domain/subscriber/repository/SubscriberRepository.java create mode 100644 src/main/java/ceos/backend/domain/subscriber/service/SubscriberService.java create mode 100644 src/main/java/ceos/backend/global/common/dto/AwsSESRecruitMail.java create mode 100644 src/main/java/ceos/backend/global/common/dto/mail/EmailInfo.java create mode 100644 src/main/resources/templates/component/recruit.html create mode 100644 src/main/resources/templates/component/recruitButton.html create mode 100644 src/main/resources/templates/sendRecruitMail.html diff --git a/src/main/java/ceos/backend/domain/subscriber/SubscriberController.java b/src/main/java/ceos/backend/domain/subscriber/SubscriberController.java new file mode 100644 index 00000000..1f77fe78 --- /dev/null +++ b/src/main/java/ceos/backend/domain/subscriber/SubscriberController.java @@ -0,0 +1,35 @@ +package ceos.backend.domain.subscriber; + + +import ceos.backend.domain.subscriber.dto.request.SubscribeRequest; +import ceos.backend.domain.subscriber.service.SubscriberService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping(value = "/subscribe") +@Tag(name = "Subscriber") +public class SubscriberController { + + private final SubscriberService subscriberService; + + @Operation(summary = "메일링 서비스 구독") + @PostMapping + public void subscribeMail(@RequestBody @Valid SubscribeRequest subscribeRequest) { + log.info("메일링 서비스 구독"); + subscriberService.subscribeMail(subscribeRequest); + } + + @Operation(summary = "슈퍼유저 - 메일링 서비스") + @GetMapping("/mail") + public void setRecruitingMail() { + log.info("슈퍼유저 - 메일링 서비스"); + subscriberService.sendRecruitingMail(); + } +} diff --git a/src/main/java/ceos/backend/domain/subscriber/domain/Subscriber.java b/src/main/java/ceos/backend/domain/subscriber/domain/Subscriber.java new file mode 100644 index 00000000..6b466de5 --- /dev/null +++ b/src/main/java/ceos/backend/domain/subscriber/domain/Subscriber.java @@ -0,0 +1,37 @@ +package ceos.backend.domain.subscriber.domain; + + +import ceos.backend.global.common.entity.BaseEntity; +import jakarta.persistence.*; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class Subscriber extends BaseEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "subscriber_id") + private Long id; + + @NotNull + @Size(max = 255) + private String email; + + // 생성자 + @Builder + private Subscriber(String email) { + this.email = email; + } + + public static Subscriber from(String email) { + return Subscriber.builder() + .email(email) + .build(); + } +} diff --git a/src/main/java/ceos/backend/domain/subscriber/dto/request/SubscribeRequest.java b/src/main/java/ceos/backend/domain/subscriber/dto/request/SubscribeRequest.java new file mode 100644 index 00000000..0c9fb0e9 --- /dev/null +++ b/src/main/java/ceos/backend/domain/subscriber/dto/request/SubscribeRequest.java @@ -0,0 +1,14 @@ +package ceos.backend.domain.subscriber.dto.request; + + +import ceos.backend.global.common.annotation.ValidEmail; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; + +@Getter +public class SubscribeRequest { + + @Schema(defaultValue = "ceos@ceos-sinchon.com", description = "이메일") + @ValidEmail + private String email; +} diff --git a/src/main/java/ceos/backend/domain/subscriber/exception/DuplicateData.java b/src/main/java/ceos/backend/domain/subscriber/exception/DuplicateData.java new file mode 100644 index 00000000..633f9c19 --- /dev/null +++ b/src/main/java/ceos/backend/domain/subscriber/exception/DuplicateData.java @@ -0,0 +1,13 @@ +package ceos.backend.domain.subscriber.exception; + + +import ceos.backend.global.error.BaseErrorException; + +public class DuplicateData extends BaseErrorException { + + public static final DuplicateData EXCEPTION = new DuplicateData(); + + private DuplicateData() { + super(SubscriberErrorCode.DUPLICATE_DATA); + } +} diff --git a/src/main/java/ceos/backend/domain/subscriber/exception/InvalidAction.java b/src/main/java/ceos/backend/domain/subscriber/exception/InvalidAction.java new file mode 100644 index 00000000..6fbbf4b6 --- /dev/null +++ b/src/main/java/ceos/backend/domain/subscriber/exception/InvalidAction.java @@ -0,0 +1,13 @@ +package ceos.backend.domain.subscriber.exception; + + +import ceos.backend.global.error.BaseErrorException; + +public class InvalidAction extends BaseErrorException { + + public static final InvalidAction EXCEPTION = new InvalidAction(); + + private InvalidAction() { + super(SubscriberErrorCode.INVALID_ACTION); + } +} diff --git a/src/main/java/ceos/backend/domain/subscriber/exception/SubscriberErrorCode.java b/src/main/java/ceos/backend/domain/subscriber/exception/SubscriberErrorCode.java new file mode 100644 index 00000000..06ada2e6 --- /dev/null +++ b/src/main/java/ceos/backend/domain/subscriber/exception/SubscriberErrorCode.java @@ -0,0 +1,27 @@ +package ceos.backend.domain.subscriber.exception; + +import ceos.backend.global.common.dto.ErrorReason; +import ceos.backend.global.error.BaseErrorCode; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +import static org.springframework.http.HttpStatus.*; + +@Getter +@AllArgsConstructor +public enum SubscriberErrorCode implements BaseErrorCode { + + /* Data */ + INVALID_ACTION(BAD_REQUEST, "SUBSCRIBER_400_1", "리쿠르팅 시작 전입니다."), + DUPLICATE_DATA(CONFLICT, "SUBSCRIBER_409_1", "이미 존재하는 데이터입니다"); + + private HttpStatus status; + private String code; + private String reason; + + @Override + public ErrorReason getErrorReason() { + return ErrorReason.of(status.value(), code, reason); + } +} diff --git a/src/main/java/ceos/backend/domain/subscriber/helper/SubscriberHelper.java b/src/main/java/ceos/backend/domain/subscriber/helper/SubscriberHelper.java new file mode 100644 index 00000000..fbfa706b --- /dev/null +++ b/src/main/java/ceos/backend/domain/subscriber/helper/SubscriberHelper.java @@ -0,0 +1,35 @@ +package ceos.backend.domain.subscriber.helper; + +import ceos.backend.domain.subscriber.exception.DuplicateData; +import ceos.backend.domain.subscriber.exception.InvalidAction; +import ceos.backend.domain.subscriber.repository.SubscriberRepository; +import ceos.backend.global.common.dto.AwsSESRecruitMail; +import ceos.backend.global.common.event.Event; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.time.LocalDate; + +@Component +@RequiredArgsConstructor +public class SubscriberHelper { + + private final SubscriberRepository subscriberRepository; + + public void validateEmail(String email) { + if (subscriberRepository.findByEmail(email).isPresent()) { + throw DuplicateData.EXCEPTION; + } + } + + public void validateDate(LocalDate date, LocalDate now) { + if (!date.equals(now)) { + throw InvalidAction.EXCEPTION; + } + } + + public void sendRecruitEmail(String email) { + Event.raise(AwsSESRecruitMail.from(email)); + } + +} diff --git a/src/main/java/ceos/backend/domain/subscriber/repository/SubscriberRepository.java b/src/main/java/ceos/backend/domain/subscriber/repository/SubscriberRepository.java new file mode 100644 index 00000000..9c6c1cd0 --- /dev/null +++ b/src/main/java/ceos/backend/domain/subscriber/repository/SubscriberRepository.java @@ -0,0 +1,11 @@ +package ceos.backend.domain.subscriber.repository; + + +import ceos.backend.domain.subscriber.domain.Subscriber; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface SubscriberRepository extends JpaRepository { + Optional findByEmail(String email); +} diff --git a/src/main/java/ceos/backend/domain/subscriber/service/SubscriberService.java b/src/main/java/ceos/backend/domain/subscriber/service/SubscriberService.java new file mode 100644 index 00000000..9e03fbcc --- /dev/null +++ b/src/main/java/ceos/backend/domain/subscriber/service/SubscriberService.java @@ -0,0 +1,50 @@ +package ceos.backend.domain.subscriber.service; + + +import ceos.backend.domain.recruitment.repository.RecruitmentRepository; +import ceos.backend.domain.subscriber.domain.Subscriber; +import ceos.backend.domain.subscriber.dto.request.SubscribeRequest; +import ceos.backend.domain.subscriber.helper.SubscriberHelper; +import ceos.backend.domain.subscriber.repository.SubscriberRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDate; +import java.util.List; + +@Slf4j +@Service +@RequiredArgsConstructor +public class SubscriberService { + + private final SubscriberHelper subscriberHelper; + private final RecruitmentRepository recruitmentRepository; + private final SubscriberRepository subscriberRepository; + + @Transactional + public void subscribeMail(SubscribeRequest subscribeRequest) { + + //이메일 중복 검증 + subscriberHelper.validateEmail(subscribeRequest.getEmail()); + + Subscriber subscriber = Subscriber.from(subscribeRequest.getEmail()); + subscriberRepository.save(subscriber); + } + + @Transactional(readOnly = true) + public void sendRecruitingMail() { + LocalDate date = recruitmentRepository.findAll().get(0).getStartDateDoc().toLocalDate(); + LocalDate now = LocalDate.now(); + List subscribers = subscriberRepository.findAll(); + + //리쿠르팅 시작 날짜 검증 + subscriberHelper.validateDate(date, now); + + // 메일 보내기 + for (Subscriber subscriber : subscribers) { + subscriberHelper.sendRecruitEmail(subscriber.getEmail()); + } + } +} diff --git a/src/main/java/ceos/backend/global/common/dto/AwsSESRecruitMail.java b/src/main/java/ceos/backend/global/common/dto/AwsSESRecruitMail.java new file mode 100644 index 00000000..406a32da --- /dev/null +++ b/src/main/java/ceos/backend/global/common/dto/AwsSESRecruitMail.java @@ -0,0 +1,21 @@ +package ceos.backend.global.common.dto; + + +import lombok.Builder; +import lombok.Getter; + +@Getter +public class AwsSESRecruitMail { + //수정 예정 -> 이름을 받을 것인가 말 것인가... + private String email; + + @Builder + private AwsSESRecruitMail(String email) { + this.email = email; + } + + public static AwsSESRecruitMail from(String email) { + return AwsSESRecruitMail.builder().email(email) + .build(); + } +} diff --git a/src/main/java/ceos/backend/global/common/dto/mail/EmailInfo.java b/src/main/java/ceos/backend/global/common/dto/mail/EmailInfo.java new file mode 100644 index 00000000..66b5b8ab --- /dev/null +++ b/src/main/java/ceos/backend/global/common/dto/mail/EmailInfo.java @@ -0,0 +1,22 @@ +package ceos.backend.global.common.dto.mail; + + +import ceos.backend.global.common.dto.AwsSESRecruitMail; +import lombok.Builder; +import lombok.Getter; + +@Getter +public class EmailInfo { + private String email; + + @Builder + private EmailInfo(String email) { + this.email = email; + } + + public static EmailInfo from(AwsSESRecruitMail awsSESRecruitMail) { + return EmailInfo.builder() + .email(awsSESRecruitMail.getEmail()) + .build(); + } +} diff --git a/src/main/java/ceos/backend/global/config/WebSecurityConfig.java b/src/main/java/ceos/backend/global/config/WebSecurityConfig.java index 725e7df7..f9948be1 100644 --- a/src/main/java/ceos/backend/global/config/WebSecurityConfig.java +++ b/src/main/java/ceos/backend/global/config/WebSecurityConfig.java @@ -103,7 +103,7 @@ public class WebSecurityConfig { "/applications/interview", "/applications/pass" }; - private final String[] RootPatterns = {"/admin/super"}; + private final String[] RootPatterns = {"/admin/super", "/subscribe/mail"}; @Bean public UserDetailsService userDetailsService() { diff --git a/src/main/java/ceos/backend/infra/ses/AwsSESMailGenerator.java b/src/main/java/ceos/backend/infra/ses/AwsSESMailGenerator.java index 904157f7..35e873f9 100644 --- a/src/main/java/ceos/backend/infra/ses/AwsSESMailGenerator.java +++ b/src/main/java/ceos/backend/infra/ses/AwsSESMailGenerator.java @@ -8,6 +8,7 @@ import ceos.backend.domain.application.vo.AnswerVo; import ceos.backend.global.common.dto.AwsSESMail; import ceos.backend.global.common.dto.AwsSESPasswordMail; +import ceos.backend.global.common.dto.AwsSESRecruitMail; import ceos.backend.global.common.dto.ParsedDuration; import ceos.backend.global.common.dto.mail.*; import ceos.backend.global.common.entity.Part; @@ -128,4 +129,16 @@ public Context generatePasswordMailContext(AwsSESPasswordMail awsSESPasswordMail public String generatePasswordMailSubject() { return "세오스 관리자 페이지 임시 비밀번호 발급"; } + + public Context generateRecruitMailContext(AwsSESRecruitMail awsSESRecruitMail) { + Context context = new Context(); + context.setVariable("email", EmailInfo.from(awsSESRecruitMail)); + + return context; + } + + // 수정 예정 + public String generateRecruitMailSubject() { + return "세오스 리쿠르팅 메일 발송"; + } } diff --git a/src/main/java/ceos/backend/infra/ses/AwsSESSendMailHandler.java b/src/main/java/ceos/backend/infra/ses/AwsSESSendMailHandler.java index f9fbb472..d6d56b02 100644 --- a/src/main/java/ceos/backend/infra/ses/AwsSESSendMailHandler.java +++ b/src/main/java/ceos/backend/infra/ses/AwsSESSendMailHandler.java @@ -4,6 +4,7 @@ import ceos.backend.domain.application.dto.request.CreateApplicationRequest; import ceos.backend.global.common.dto.AwsSESMail; import ceos.backend.global.common.dto.AwsSESPasswordMail; +import ceos.backend.global.common.dto.AwsSESRecruitMail; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.context.event.EventListener; @@ -35,4 +36,12 @@ public void handle(AwsSESPasswordMail awsSESPasswordMail) { final Context CONTEXT = awsSESMailGenerator.generatePasswordMailContext(awsSESPasswordMail); awsSesUtils.singleEmailRequest(TO, SUBJECT, "sendPasswordMail", CONTEXT); } + + @EventListener(AwsSESRecruitMail.class) + public void handle(AwsSESRecruitMail awsSESRecruitMail) { + final String TO = awsSESRecruitMail.getEmail(); + final String SUBJECT = awsSESMailGenerator.generateRecruitMailSubject(); + final Context CONTEXT = awsSESMailGenerator.generateRecruitMailContext(awsSESRecruitMail); + awsSesUtils.singleEmailRequest(TO, SUBJECT, "sendRecruitMail", CONTEXT); + } } diff --git a/src/main/resources/templates/component/copyright.html b/src/main/resources/templates/component/copyright.html index f96c442f..b29553ce 100644 --- a/src/main/resources/templates/component/copyright.html +++ b/src/main/resources/templates/component/copyright.html @@ -21,7 +21,7 @@ font-size: 20px; line-height: 150%; color: #D6DADF;"> - © 2016-2023 Ceos ALL RIGHTS RESERVED. + © 2016-2024 Ceos ALL RIGHTS RESERVED. diff --git a/src/main/resources/templates/component/recruit.html b/src/main/resources/templates/component/recruit.html new file mode 100644 index 00000000..c818a4af --- /dev/null +++ b/src/main/resources/templates/component/recruit.html @@ -0,0 +1,30 @@ + + + + + +
+
+ + 세오스 리루르팅 시작 알림 + 텍스트추가텍스트추가 + + +
+
+
+ \ No newline at end of file diff --git a/src/main/resources/templates/component/recruitButton.html b/src/main/resources/templates/component/recruitButton.html new file mode 100644 index 00000000..7ad90b89 --- /dev/null +++ b/src/main/resources/templates/component/recruitButton.html @@ -0,0 +1,35 @@ + + + + + + + diff --git a/src/main/resources/templates/sendRecruitMail.html b/src/main/resources/templates/sendRecruitMail.html new file mode 100644 index 00000000..f2cc9498 --- /dev/null +++ b/src/main/resources/templates/sendRecruitMail.html @@ -0,0 +1,43 @@ + + + + + + + + + + +
+
title
+
divider
+
+
recruit
+
divider
+
+
+ button +
+
+
copyright
+
+ + From ff56df8a3fc4f64d0a0af3a326fe2928f6f60a53 Mon Sep 17 00:00:00 2001 From: Seo Chanhyeok Date: Tue, 23 Jan 2024 12:04:53 +0900 Subject: [PATCH 6/7] =?UTF-8?q?[fix]=20github=20actions=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/deploy_dev.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy_dev.yml b/.github/workflows/deploy_dev.yml index a9808cc1..b8d83337 100644 --- a/.github/workflows/deploy_dev.yml +++ b/.github/workflows/deploy_dev.yml @@ -16,8 +16,9 @@ jobs: - name: Checkout uses: actions/checkout@v3 - - name: Make application-secret.yml without env + - name: Recreate application-secret.yml run: | + rm -f ./src/main/resources/application-secret.yml touch ./src/main/resources/application-secret.yml echo "${{ secrets.APPLICATION_SECRET_DEV }}" > ./src/main/resources/application-secret.yml From a48ad600be3ff35a676677768939c83e5559b525 Mon Sep 17 00:00:00 2001 From: wjdtkdgns Date: Thu, 29 Feb 2024 10:01:02 +0900 Subject: [PATCH 7/7] =?UTF-8?q?[fix]=20=EC=84=9C=EB=A5=98=20=ED=86=B5?= =?UTF-8?q?=EA=B3=BC=20=EC=A1=B0=ED=9A=8C=20response=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +++ .../application/dto/response/GetResultResponse.java | 9 +++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 3ad6676a..d6a8d1f6 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,6 @@ out/ ### application ### application-secret.yml + +### +.env** \ No newline at end of file diff --git a/src/main/java/ceos/backend/domain/application/dto/response/GetResultResponse.java b/src/main/java/ceos/backend/domain/application/dto/response/GetResultResponse.java index d9f4d091..20f53b1d 100644 --- a/src/main/java/ceos/backend/domain/application/dto/response/GetResultResponse.java +++ b/src/main/java/ceos/backend/domain/application/dto/response/GetResultResponse.java @@ -47,12 +47,17 @@ private GetResultResponse( public static GetResultResponse toDocumentResult( Application application, Recruitment recruitment) { + ParsedDuration duration = null; + + if (application.getInterviewDatetime() != null) { + duration = ParsedDurationConvertor.parsingDuration(application.getInterviewDatetime()); + } + return GetResultResponse.builder() .pass(application.getDocumentPass()) .generation(recruitment.getGeneration()) .name(application.getApplicantInfo().getName()) - .parsedDuration( - ParsedDurationConvertor.parsingDuration(application.getInterviewDatetime())) + .parsedDuration(duration) .otDate(recruitment.getOtDate()) .attendanceStatus(application.isInterviewCheck()) .openChatUrl(recruitment.getOpenChatUrl())