Skip to content
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

GETP-208 refactor: project apply 컴포넌트 포트-어댑터 아키텍쳐 적용 #139

Merged
merged 2 commits into from
Aug 27, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import es.princip.getp.api.controller.project.command.dto.request.ApplyProjectRequest;
import es.princip.getp.api.controller.project.command.dto.response.ApplyProjectResponse;
import es.princip.getp.api.security.details.PrincipalDetails;
import es.princip.getp.application.project.apply.ProjectApplicationService;
import es.princip.getp.application.project.apply.command.ApplyProjectCommand;
import es.princip.getp.application.project.apply.port.in.ApplyProjectUseCase;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
Expand All @@ -20,7 +20,7 @@
@RequiredArgsConstructor
public class ProjectApplicationController {

private final ProjectApplicationService projectApplicationService;
private final ApplyProjectUseCase applyProjectUseCase;
private final ProjectCommandMapper projectCommandMapper;

/**
Expand All @@ -39,7 +39,7 @@ public ResponseEntity<ApiSuccessResult<ApplyProjectResponse>> applyForProject(
) {
final Long memberId = principalDetails.getMember().getMemberId();
final ApplyProjectCommand command = projectCommandMapper.mapToCommand(memberId, projectId, request);
final Long applicationId = projectApplicationService.applyForProject(command);
final Long applicationId = applyProjectUseCase.apply(command);
final ApplyProjectResponse response = new ApplyProjectResponse(applicationId);
return ApiResponse.success(HttpStatus.CREATED, response);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class GetAppliedProjectService implements GetAppliedProjectQuery {
class GetAppliedProjectService implements GetAppliedProjectQuery {

private final FindAppliedProjectPort findAppliedProjectPort;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class GetProjectApplicantService implements GetProjectApplicantQuery {
class GetProjectApplicantService implements GetProjectApplicantQuery {

private final FindProjectApplicantPort findProjectApplicantPort;
private final LoadClientPort loadClientPort;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package es.princip.getp.application.project.apply;

import es.princip.getp.application.project.apply.command.ApplyProjectCommand;
import es.princip.getp.application.project.apply.exception.AlreadyAppliedProjectException;
import es.princip.getp.application.project.apply.port.in.ApplyProjectUseCase;
import es.princip.getp.application.project.apply.port.out.CheckProjectApplicationPort;
import es.princip.getp.application.project.apply.port.out.SaveProjectApplicationPort;
import es.princip.getp.application.project.commission.port.out.LoadProjectPort;
import es.princip.getp.domain.people.command.domain.People;
import es.princip.getp.domain.people.command.domain.PeopleRepository;
Expand All @@ -15,10 +19,13 @@
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class ProjectApplicationService {
class ProjectApplicationService implements ApplyProjectUseCase {

private final LoadProjectPort loadProjectPort;
private final CheckProjectApplicationPort checkProjectApplicationPort;
private final SaveProjectApplicationPort saveProjectApplicationPort;
private final PeopleRepository peopleRepository;

private final ProjectApplier projectApplier;

/**
Expand All @@ -27,18 +34,25 @@ public class ProjectApplicationService {
* @param command 프로젝트 지원 명령
* @return 프로젝트 지원 ID
*/
@Override
@Transactional
public Long applyForProject(final ApplyProjectCommand command) {
final People people = peopleRepository.findByMemberId(command.memberId())
public Long apply(final ApplyProjectCommand command) {
final People applicant = peopleRepository.findByMemberId(command.memberId())
.orElseThrow(NotFoundPeopleException::new);
final Long applicantId = applicant.getPeopleId();
final Long projectId = command.projectId();
final Project project = loadProjectPort.loadBy(command.projectId());
if (checkProjectApplicationPort.existsByApplicantIdAndProjectId(applicantId, projectId)) {
throw new AlreadyAppliedProjectException();
}
final ProjectApplication application = projectApplier.applyForProject(
people,
applicant,
project,
command.expectedDuration(),
command.description(),
command.attachmentFiles()
);
saveProjectApplicationPort.save(application);
return application.getApplicationId();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package es.princip.getp.domain.project.apply.exception;
package es.princip.getp.application.project.apply.exception;

import es.princip.getp.common.exception.BusinessLogicException;
import es.princip.getp.common.exception.ErrorDescription;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package es.princip.getp.application.project.apply.port.in;

import es.princip.getp.application.project.apply.command.ApplyProjectCommand;

public interface ApplyProjectUseCase {

Long apply(final ApplyProjectCommand command);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package es.princip.getp.application.project.apply.port.out;

public interface CheckProjectApplicationPort {


boolean existsByApplicantIdAndProjectId(Long applicantId, Long projectId);
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package es.princip.getp.application.project.apply.port.out;

import es.princip.getp.domain.project.apply.model.ProjectApplication;

public interface SaveProjectApplicationPort {


Long save(ProjectApplication projectApplication);
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package es.princip.getp.application.project.meeting;

import es.princip.getp.application.project.apply.port.out.CheckProjectApplicationPort;
import es.princip.getp.application.project.commission.port.out.LoadProjectPort;
import es.princip.getp.application.project.meeting.command.ScheduleMeetingCommand;
import es.princip.getp.application.project.meeting.exception.NotApplicantException;
Expand All @@ -9,7 +10,6 @@
import es.princip.getp.domain.people.command.domain.People;
import es.princip.getp.domain.people.command.domain.PeopleRepository;
import es.princip.getp.domain.people.exception.NotFoundPeopleException;
import es.princip.getp.domain.project.apply.ProjectApplicationRepository;
import es.princip.getp.domain.project.commission.model.Project;
import es.princip.getp.domain.project.meeting.model.ProjectMeeting;
import lombok.RequiredArgsConstructor;
Expand All @@ -24,8 +24,7 @@ public class ProjectMeetingService {
private final PeopleRepository peopleRepository;
private final LoadProjectPort loadProjectPort;

private final ProjectApplicationRepository applicationRepository;

private final CheckProjectApplicationPort checkProjectApplicationPort;
private final SaveProjectMeetingPort saveProjectMeetingPort;
private final CheckProjectMeetingPort checkProjectMeetingPort;

Expand Down Expand Up @@ -68,7 +67,7 @@ private void checkMemberIsClientOfProject(final Long memberId, final Long projec
}

private void checkPeopleIsApplicant(final Long applicantId, final Long projectId) {
if (!applicationRepository.existsByApplicantIdAndProjectId(applicantId, projectId)) {
if (!checkProjectApplicationPort.existsByApplicantIdAndProjectId(applicantId, projectId)) {
throw new NotApplicantException();
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
package es.princip.getp.domain.common.model;

import jakarta.persistence.Embeddable;
import jakarta.persistence.Embedded;
import lombok.*;
import es.princip.getp.domain.BaseModel;
import jakarta.validation.constraints.NotNull;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;

@Getter
@ToString
@Embeddable
@EqualsAndHashCode
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class AttachmentFile {
@EqualsAndHashCode(callSuper = false)
public class AttachmentFile extends BaseModel {

@Embedded
private URL url;
@NotNull private final URL url;

public AttachmentFile(final URL url) {
this.url = url;

validate();
}

public static AttachmentFile from(final String url) {
Expand Down
28 changes: 14 additions & 14 deletions src/main/java/es/princip/getp/domain/common/model/Duration.java
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
package es.princip.getp.domain.common.model;

import es.princip.getp.domain.BaseModel;
import es.princip.getp.domain.common.exception.StartDateIsAfterEndDateException;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import lombok.*;
import jakarta.validation.constraints.NotNull;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;

import java.time.Clock;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;

@Getter
@ToString
@Embeddable
@EqualsAndHashCode
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Duration {
@EqualsAndHashCode(callSuper = false)
public class Duration extends BaseModel {

@Column(name = "application_start_date")
private LocalDate startDate;

@Column(name = "application_end_date")
private LocalDate endDate;
@NotNull private final LocalDate startDate;
@NotNull private final LocalDate endDate;

public Duration(final LocalDate startDate, final LocalDate endDate) {
validate(startDate, endDate);
this.startDate = startDate;
this.endDate = endDate;

validate();
}

private void validate(final LocalDate startDate, final LocalDate endDate) {
@Override
protected void validate() {
super.validate();
if (startDate.isAfter(endDate)) {
throw new StartDateIsAfterEndDateException();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public static MeetingSchedule of(
}

@Override
public void validate() {
protected void validate() {
super.validate();
if (startTime.isAfter(endTime)) {
throw new StartTimeIsAfterEndTimeException();
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,76 +1,50 @@
package es.princip.getp.domain.project.apply.model;

import es.princip.getp.common.domain.BaseTimeEntity;
import es.princip.getp.domain.BaseEntity;
import es.princip.getp.domain.common.model.AttachmentFile;
import es.princip.getp.domain.common.model.Duration;
import jakarta.persistence.*;
import lombok.AccessLevel;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.ArrayList;
import java.time.LocalDateTime;
import java.util.List;

@Getter
@Entity
@Table(name = "project_application")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ProjectApplication extends BaseTimeEntity {
public class ProjectApplication extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "project_application_id")
@Getter
private Long applicationId;

// 지원자의 피플 ID
@Column(name = "people_id")
private Long applicantId;

// 지원한 프로젝트 ID
@Column(name = "project_id")
private Long projectId;

// 희망 작업 기간
@Embedded
@AttributeOverrides(
{
@AttributeOverride(name = "startDate", column = @Column(name = "expected_start_date")),
@AttributeOverride(name = "endDate", column = @Column(name = "expected_end_date"))
}
)
private Duration expectedDuration;

// 지원 상태
@Enumerated(EnumType.STRING)
@Column(name = "status")
private ProjectApplicationStatus applicationStatus;

// 지원 내용
@Column(name = "description")
private String description;

// 첨부 파일 목록
@ElementCollection
@CollectionTable(name = "project_application_attachment_file", joinColumns = @JoinColumn(name = "project_application_id"))
private List<AttachmentFile> attachmentFiles = new ArrayList<>();
@NotNull private final Long applicantId;
@NotNull private final Long projectId;
@NotNull private Duration expectedDuration;
@NotNull private ProjectApplicationStatus applicationStatus;
@NotBlank private String description;
private final List<@NotNull AttachmentFile> attachmentFiles;

@Builder
public ProjectApplication(
final Long applicationId,
final Long applicantId,
final Long projectId,
final Duration expectedDuration,
final ProjectApplicationStatus applicationStatus,
final String description,
final List<AttachmentFile> attachmentFiles
final List<AttachmentFile> attachmentFiles,
final LocalDateTime createdAt,
final LocalDateTime updatedAt
) {
super(createdAt, updatedAt);

this.applicationId = applicationId;
this.applicantId = applicantId;
this.projectId = projectId;
this.expectedDuration = expectedDuration;
this.applicationStatus = applicationStatus;
this.description = description;
this.attachmentFiles = attachmentFiles;

validate();
}

public void setStatus(final ProjectApplicationStatus applicationStatus) {
Expand Down
Loading