Skip to content

Commit

Permalink
Feat/#69 프로젝트 취소 기능 구현 (#79)
Browse files Browse the repository at this point in the history
* [FEAT] 프로젝트 요청 도메인 구현

* [FEAT] 잔디력 감소를 위한 임시 함수 구현

* [FEAT] 프로젝트 취소 기능 구
  • Loading branch information
happyjamy authored Feb 18, 2024
1 parent 62611de commit 5c07b8a
Show file tree
Hide file tree
Showing 11 changed files with 160 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
@SuppressWarnings("unused")
public interface ProjectSwagger {

@Operation(summary = "프로젝트 카드 생성", description = "회원이 프로젝트 카드를 생성할 때 사용하는 API"
)
@Operation(summary = "프로젝트 카드 생성", description = "회원이 프로젝트 카드를 생성할 때 사용하는 API")
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "프로젝트 카드 생성 성공",
content = @Content(schema = @Schema(implementation = ProjectIdRes.class))),
Expand Down Expand Up @@ -51,8 +50,7 @@ ResponseEntity<ProjectIdRes> create(
ProjectCreateReq request
);

@Operation(summary = "프로젝트 카드 삭제", description = "회원이 프로젝트 카드를 삭제할 때 사용하는 API"
)
@Operation(summary = "프로젝트 카드 삭제", description = "회원이 프로젝트 카드를 삭제할 때 사용하는 API")
@ApiResponses(value = {
@ApiResponse(responseCode = "204", description = "프로젝트 카드 삭제 성공"),
@ApiResponse(responseCode = "400", description = "프로젝트를 삭제 할 수 없습니다.",
Expand Down Expand Up @@ -80,4 +78,33 @@ ResponseEntity<Void> delete(
@Parameter(hidden = true) Long userId,
@Parameter(description = "프로젝트 ID", required = true) Long id
);

@Operation(summary = "프로젝트 카드 취소", description = "회원이 프로젝트 카드를 임의로 취소 할때 사용하는 API")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "프로젝트 카드 취소 성공"),
@ApiResponse(responseCode = "400", description = "프로젝트를 취소 할 수 없습니다.",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class),
examples = {
@ExampleObject(name = "E030107", value = SwaggerProjectErrorExamples.PROJECT_CANCEL_NOT_ALLOWED)
})),
@ApiResponse(responseCode = "404", description = "요청한 데이터가 존재하지 않음",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class),
examples = {
@ExampleObject(name = "E030301", value = SwaggerProjectErrorExamples.PROJECT_NOT_FOUND),
@ExampleObject(name = "E020301", value = SwaggerUserErrorExamples.USER_NOT_FOUND)
})),
@ApiResponse(responseCode = "403", description = "프로젝트 카드 취소 권한이 없음",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class),
examples = @ExampleObject(name = "E030201", value = SwaggerProjectErrorExamples.PROJECT_FORBIDDEN_OPERATION)))
})
ResponseEntity<ProjectIdRes> cancel(
@Parameter(hidden = true) Long userId,
@Parameter(description = "프로젝트 ID", required = true) Long id
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public class SwaggerProjectErrorExamples {
public static final String PROJECT_NOT_FOUND = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":404,\"code\":\"E030301\",\"message\":\"해당 프로젝트가 존재하지 않습니다.\"}";
public static final String PROJECT_FORBIDDEN_OPERATION = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":403,\"code\":\"E030201\",\"message\":\"해당 프로젝트에 대한 권한이 없습니다.\"}";
public static final String PROJECT_DELETION_NOT_ALLOWED = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E030106\",\"message\":\"매칭 중이거나 대기중인 프로젝트는 삭제할 수 없습니다.\"}";
public static final String PROJECT_CANCEL_NOT_ALLOWED = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E030107\",\"message\":\"이미 취소 되었거나 종료된 프로젝트는 취소할 수 없습니다.\"}";
private SwaggerProjectErrorExamples() {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import io.oeid.mogakgo.domain.project.exception.ProjectException;
import io.oeid.mogakgo.domain.project.infrastructure.ProjectJpaRepository;
import io.oeid.mogakgo.domain.project.presentation.dto.req.ProjectCreateReq;
import io.oeid.mogakgo.domain.project_join_req.infrastruture.ProjectJoinRequestJpaRepository;
import io.oeid.mogakgo.domain.user.domain.User;
import io.oeid.mogakgo.domain.user.exception.UserException;
import io.oeid.mogakgo.domain.user.infrastructure.UserJpaRepository;
Expand All @@ -26,6 +27,7 @@ public class ProjectService {
private final UserJpaRepository userJpaRepository;
private final ProjectJpaRepository projectJpaRepository;
private final GeoService geoService;
private final ProjectJoinRequestJpaRepository projectJoinRequestJpaRepository;

@Transactional
public Long create(Long userId, ProjectCreateReq request) {
Expand Down Expand Up @@ -57,6 +59,20 @@ public void delete(Long userId, Long projectId) {
project.delete(user);
}

public void cancel(Long userId, Long projectId) {
// 유저 존재 여부 체크
User user = getUser(userId);

// 프로젝트 존재 여부 체크
Project project = getProject(projectId);

// 매칭이 되었거나, 매칭 준비중이지만 요청이 있을때는 잔디력 감소를 위한 변수
boolean projectHasReq = projectJoinRequestJpaRepository.existsByProjectId(projectId);

// 프로젝트 취소
project.cancel(user, projectHasReq);
}

private User getUser(Long userId) {
return userJpaRepository.findById(userId)
.orElseThrow(() -> new UserException(USER_NOT_FOUND));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,20 @@ public void delete(User tokenUser) {
super.delete();
}

public void cancel(User tokenUser, boolean projectHasReq) {
validateAvailableCancel(tokenUser);
// 매칭이 되었거나, 매칭 준비중이지만 요청이 있을때는 잔디력 감소
if (projectHasReq) {
this.creator.decreaseJandiRate();
}
this.projectStatus = ProjectStatus.CANCELED;
}

private void validateAvailableCancel(User tokenUser) {
validateCreator(tokenUser);
this.projectStatus.validateAvailableCancel();
}

private void validateAvailableDelete(User tokenUser) {
validateCreator(tokenUser);
this.projectStatus.validateAvailableDelete();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.oeid.mogakgo.domain.project.domain.entity.enums;

import static io.oeid.mogakgo.exception.code.ErrorCode400.PROJECT_CANCEL_NOT_ALLOWED;
import static io.oeid.mogakgo.exception.code.ErrorCode400.PROJECT_DELETION_NOT_ALLOWED;

import io.oeid.mogakgo.domain.project.exception.ProjectException;
Expand All @@ -23,4 +24,10 @@ public void validateAvailableDelete() {
throw new ProjectException(PROJECT_DELETION_NOT_ALLOWED);
}
}

public void validateAvailableCancel() {
if (this == CANCELED || this == FINISHED) {
throw new ProjectException(PROJECT_CANCEL_NOT_ALLOWED);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
Expand All @@ -22,7 +23,6 @@ public class ProjectController implements ProjectSwagger {

private final ProjectService projectService;

@Override
@PostMapping
public ResponseEntity<ProjectIdRes> create(
@UserId Long userId, @Valid @RequestBody ProjectCreateReq request
Expand All @@ -39,4 +39,12 @@ public ResponseEntity<Void> delete(
return ResponseEntity.noContent().build();
}

@PatchMapping("/{id}/cancel")
public ResponseEntity<ProjectIdRes> cancel(
@UserId Long userId, @PathVariable Long id
) {
projectService.cancel(userId, id);
return ResponseEntity.status(200).body(ProjectIdRes.from(id));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package io.oeid.mogakgo.domain.project_join_req.domain.entity;

import io.oeid.mogakgo.domain.project.domain.entity.Project;
import io.oeid.mogakgo.domain.project_join_req.domain.entity.enums.RequestStatus;
import io.oeid.mogakgo.domain.user.domain.User;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.time.LocalDateTime;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

@Getter
@Entity
@Table(name = "project_join_request_tb")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@EntityListeners(AuditingEntityListener.class)
public class ProjectJoinRequest {

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

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "sender_id", updatable = false)
private User sender;

@Enumerated(EnumType.STRING)
@Column(name = "join_request_status")
private RequestStatus requestStatus;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "project_id", updatable = false)
private Project project;

@CreatedDate
@Column(name = "created_at")
private LocalDateTime createdAt;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.oeid.mogakgo.domain.project_join_req.domain.entity.enums;

public enum RequestStatus {
PENDING("요청 대기중"),
ACCEPTED("요청 수락됨"),
REJECTED("요청 거절됨");

private final String description;

RequestStatus(String description) {
this.description = description;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.oeid.mogakgo.domain.project_join_req.infrastruture;

import io.oeid.mogakgo.domain.project_join_req.domain.entity.ProjectJoinRequest;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ProjectJoinRequestJpaRepository extends JpaRepository<ProjectJoinRequest, Long> {

boolean existsByProjectId(Long projectId);

}
5 changes: 5 additions & 0 deletions src/main/java/io/oeid/mogakgo/domain/user/domain/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,9 @@ public void updateRegion(Region region) {
this.region = region;
this.regionAuthenticationAt = LocalDateTime.now();
}

//TODO : 추후 구현 필요
public void decreaseJandiRate() {
return;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public enum ErrorCode400 implements ErrorCode {
INVALID_PROJECT_NULL_DATA("E030104", "프로젝트를 생성하기 위해 null 이여서는 안되는 데이터가 null 입니다."),
NOT_MATCH_MEET_LOCATION("E030105", "프로젝트 만남 장소가 유저가 동네인증 한 구역이 아닙니다."),
PROJECT_DELETION_NOT_ALLOWED("E030106", "매칭 중이거나 대기중인 프로젝트는 삭제할 수 없습니다."),
PROJECT_CANCEL_NOT_ALLOWED("E030107", "이미 취소 되었거나 종료된 프로젝트는 취소할 수 없습니다."),

USER_DEVELOP_LANGUAGE_BAD_REQUEST("E020101", "개발 언어는 3개까지만 등록 가능합니다."),
USER_WANTED_JOB_BAD_REQUEST("E020102", "희망 직무는 3개까지만 등록 가능합니다."),
Expand Down

0 comments on commit 5c07b8a

Please sign in to comment.