Skip to content

Commit

Permalink
[CHORE] develop 컨플릭트 해결
Browse files Browse the repository at this point in the history
  • Loading branch information
happyjamy committed Feb 20, 2024
2 parents e9ffb00 + 16f69ed commit 1d7ccc8
Show file tree
Hide file tree
Showing 26 changed files with 439 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import io.oeid.mogakgo.common.base.CursorPaginationInfoReq;
import io.oeid.mogakgo.common.base.CursorPaginationResult;
import io.oeid.mogakgo.core.properties.swagger.error.SwaggerProjectErrorExamples;
import io.oeid.mogakgo.core.properties.swagger.error.SwaggerProjectJoinReqErrorExamples;
import io.oeid.mogakgo.core.properties.swagger.error.SwaggerProjectJoinRequestErrorExamples;
import io.oeid.mogakgo.core.properties.swagger.error.SwaggerUserErrorExamples;
import io.oeid.mogakgo.domain.matching.presentation.dto.res.MatchingId;
import io.oeid.mogakgo.domain.project_join_req.application.dto.req.ProjectJoinCreateReq;
import io.oeid.mogakgo.domain.project_join_req.presentation.dto.res.ProjectJoinRequestAPIRes;
import io.oeid.mogakgo.domain.project_join_req.presentation.dto.res.ProjectJoinRequestDetailAPIRes;
Expand All @@ -19,8 +21,41 @@
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;

@Tag(name = "Project Join Request", description = "프로젝트 매칭 요청 관련 API")
public interface ProjectJoinRequestSwagger {
@Tag(name = "Project Join Request", description = "프로젝트 카드 참여 요청 관련 API")
@SuppressWarnings("unused")
public interface ProjectJoinReqSwagger {

@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 = "E050101", value = SwaggerProjectJoinReqErrorExamples.INVALID_PROJECT_STATUS_TO_ACCEPT),
@ExampleObject(name = "E050102", value = SwaggerProjectJoinReqErrorExamples.INVALID_PROJECT_REQ_STATUS_TO_ACCEPT),
@ExampleObject(name = "E050103", value = SwaggerProjectJoinReqErrorExamples.INVALID_MATCHING_USER_TO_ACCEPT),
@ExampleObject(name = "E050104", value = SwaggerProjectJoinReqErrorExamples.INVALID_SENDER_TO_ACCEPT),
})),
@ApiResponse(responseCode = "403", description = "요청을 보낸 사람이 요청 수락할 권한이 안됨 (프로젝트 카드 주인이 아님)",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class),
examples = @ExampleObject(name = "E030201", value = SwaggerProjectErrorExamples.PROJECT_FORBIDDEN_OPERATION))),
@ApiResponse(responseCode = "404", description = "요청한 데이터가 존재하지 않음",
content = @Content(
mediaType = "application/json",
schema = @Schema(implementation = ErrorResponse.class),
examples = {
@ExampleObject(name = "E050301", value = SwaggerProjectJoinReqErrorExamples.PROJECT_JOIN_REQUEST_NOT_FOUND),
@ExampleObject(name = "E020301", value = SwaggerUserErrorExamples.USER_NOT_FOUND)
})),
})
ResponseEntity<MatchingId> accept(
@Parameter(hidden = true) Long userId,
@Parameter(description = "프로젝트 참가 요청 ID", required = true) Long projectRequestId
);

@Operation(summary = "프로젝트 매칭 요청 생성", description = "회원이 프로젝트 매칭 요청을 생성할 때 사용하는 API")
@ApiResponses(value = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectDetailAPIRes;
import io.oeid.mogakgo.domain.project.presentation.dto.req.ProjectCreateReq;
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectIdRes;
import io.oeid.mogakgo.domain.project_join_req.presentation.projectJoinRequestRes;
import io.oeid.mogakgo.domain.project_join_req.presentation.dto.res.projectJoinRequestRes;
import io.oeid.mogakgo.exception.dto.ErrorResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
Expand Down Expand Up @@ -40,6 +40,8 @@ public interface ProjectSwagger {
@ExampleObject(name = "E030103", value = SwaggerProjectErrorExamples.INVALID_PROJECT_TAG_CONTENT_LENGTH),
@ExampleObject(name = "E030104", value = SwaggerProjectErrorExamples.INVALID_PROJECT_NULL_DATA),
@ExampleObject(name = "E030105", value = SwaggerProjectErrorExamples.INVALID_PROJECT_MEET_LOCATION),
@ExampleObject(name = "E030108", value = SwaggerProjectErrorExamples.INVALID_MATCHING_USER_TO_CREATE_PROJECT),
@ExampleObject(name = "E030109", value = SwaggerProjectErrorExamples.ALREADY_EXIST_PROGRESS_PROJECT)
})),
@ApiResponse(responseCode = "403", description = "프로젝트 카드 생성 권한이 없음",
content = @Content(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ public class SwaggerProjectErrorExamples {
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\":\"이미 취소 되었거나 종료된 프로젝트는 취소할 수 없습니다.\"}";
public static final String PROJECT_JOIN_REQUEST_FORBIDDEN_OPERATION = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":403,\"code\":\"E050201\",\"message\":\"해당 프로젝트 요청에 대한 권한이 없습니다.\"}";
public static final String INVALID_MATCHING_USER_TO_CREATE_PROJECT = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E030108\",\"message\":\"매칭이 진행 중인 유저는 프로젝트 생성을 할 수 없습니다.\"}";
public static final String ALREADY_EXIST_PROGRESS_PROJECT = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E030109\",\"message\":\"종료되지 않은 프로젝트 카드가 있으면 프로젝트 생성을 할 수 없습니다.\"}";

private SwaggerProjectErrorExamples() {
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.oeid.mogakgo.core.properties.swagger.error;

public class SwaggerProjectJoinReqErrorExamples {

public static final String INVALID_PROJECT_STATUS_TO_ACCEPT = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E050101\",\"message\":\"프로젝트가 대기중이 아니여서 참여 요청을 수락할 수 없습니다.\"}";
public static final String INVALID_PROJECT_REQ_STATUS_TO_CANCEL = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E050105\",\"message\":\"\"프로젝트 참여 요청이 대기중이 아니여서 참여 요청을 취소할 수 없습니다.\"}";
public static final String INVALID_PROJECT_REQ_STATUS_TO_ACCEPT = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E050102\",\"message\":\"프로젝트 참가 요청이 대기중이 아니여서 수락할 수 없습니다.\"}";
public static final String INVALID_MATCHING_USER_TO_ACCEPT = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E050103\",\"message\":\"매칭이 진행 중인 유저는 프로젝트 참여 요청을 수락할 수 없습니다.\"}";
public static final String INVALID_SENDER_TO_ACCEPT = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E050104\",\"message\":\"요청 보낸 상대가 이미 매칭중이기 때문에 프로젝트 참여 요청을 수락할 수 없습니다.\"}";
public static final String PROJECT_JOIN_REQUEST_NOT_FOUND = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":404,\"code\":\"E050301\",\"message\":\"프로젝트 참가 요청이 존재하지 않습니다.\"}";


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.oeid.mogakgo.domain.matching.application;

import io.oeid.mogakgo.domain.matching.domain.entity.Matching;
import io.oeid.mogakgo.domain.matching.infrastructure.MatchingJpaRepository;
import io.oeid.mogakgo.domain.project_join_req.domain.entity.ProjectJoinRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Transactional(readOnly = true)
@RequiredArgsConstructor
@Service
public class MatchingService {

private final MatchingJpaRepository matchingJpaRepository;

@Transactional
public Long create(ProjectJoinRequest projectJoinRequest) {
Matching matching = Matching.builder()
.project(projectJoinRequest.getProject())
.sender(projectJoinRequest.getSender())
.build();

matchingJpaRepository.save(matching);

return matching.getId();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.oeid.mogakgo.domain.matching.application;

import io.oeid.mogakgo.domain.matching.infrastructure.MatchingJpaRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Transactional(readOnly = true)
@RequiredArgsConstructor
@Service
public class UserMatchingService {

private final MatchingJpaRepository matchingJpaRepository;

public boolean hasProgressMatching(Long userId) {
return !matchingJpaRepository.findProgressOneByUserId(userId, PageRequest.of(0, 1))
.isEmpty();
}

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

import static io.oeid.mogakgo.domain.matching.domain.entity.enums.MatchingStatus.PROGRESS;

import io.oeid.mogakgo.domain.matching.domain.entity.enums.MatchingStatus;
import io.oeid.mogakgo.domain.project.domain.entity.Project;
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.OneToOne;
import jakarta.persistence.Table;
import java.time.LocalDateTime;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

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

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

@OneToOne
@JoinColumn(name = "project_id", updatable = false)
private Project project;

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

@Enumerated(EnumType.STRING)
@Column(name = "matching_status")
private MatchingStatus matchingStatus;

@CreatedDate
@Column(name = "created_at")
private LocalDateTime createdAt;

@Builder
private Matching(
Long id, Project project, User sender
) {
this.id = id;
this.project = project;
this.sender = sender;
this.matchingStatus = PROGRESS;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.oeid.mogakgo.domain.matching.domain.entity.enums;

public enum MatchingStatus {
PROGRESS,
CANCELED,
FINISHED
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package io.oeid.mogakgo.domain.matching.infrastructure;

import io.oeid.mogakgo.domain.matching.domain.entity.Matching;
import java.util.List;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

public interface MatchingJpaRepository extends JpaRepository<Matching, Long> {

@Query("select m from Matching m join Project p on m.project.id = p.id "
+ "where (m.sender.id = :userId or p.creator.id = :userId) and m.matchingStatus = 'PROGRESS'")
List<Matching> findProgressOneByUserId(Long userId, Pageable pageable);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.oeid.mogakgo.domain.matching.presentation.dto.res;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;

@Schema(description = "매칭 ID")
@Getter
public class MatchingId {

@Schema(description = "매칭 ID", example = "1")
private final Long matchingId;

public MatchingId(Long matchingId) {
this.matchingId = matchingId;
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.oeid.mogakgo.domain.project.application;

import static io.oeid.mogakgo.exception.code.ErrorCode400.ALREADY_EXIST_PROGRESS_PROJECT;
import static io.oeid.mogakgo.exception.code.ErrorCode400.INVALID_MATCHING_USER_TO_CREATE_PROJECT;
import static io.oeid.mogakgo.exception.code.ErrorCode400.INVALID_SERVICE_REGION;
import static io.oeid.mogakgo.exception.code.ErrorCode400.NOT_MATCH_MEET_LOCATION;
import static io.oeid.mogakgo.exception.code.ErrorCode403.PROJECT_FORBIDDEN_OPERATION;
Expand All @@ -11,22 +13,23 @@
import io.oeid.mogakgo.common.base.CursorPaginationResult;
import io.oeid.mogakgo.domain.geo.application.GeoService;
import io.oeid.mogakgo.domain.geo.domain.enums.Region;
import io.oeid.mogakgo.domain.matching.application.UserMatchingService;
import io.oeid.mogakgo.domain.geo.exception.GeoException;
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectDetailAPIRes;
import io.oeid.mogakgo.domain.project.domain.entity.Project;
import io.oeid.mogakgo.domain.project.domain.entity.enums.ProjectStatus;
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.domain.entity.ProjectJoinRequest;
import io.oeid.mogakgo.domain.project_join_req.exception.ProjectJoinRequestException;
import io.oeid.mogakgo.domain.project_join_req.infrastructure.ProjectJoinRequestJpaRepository;
import io.oeid.mogakgo.domain.project_join_req.presentation.projectJoinRequestRes;
import io.oeid.mogakgo.domain.project_join_req.presentation.dto.res.projectJoinRequestRes;
import io.oeid.mogakgo.domain.user.domain.User;
import io.oeid.mogakgo.domain.user.exception.UserException;
import io.oeid.mogakgo.domain.user.infrastructure.UserJpaRepository;
import java.util.Collections;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -39,11 +42,23 @@ public class ProjectService {
private final ProjectJpaRepository projectJpaRepository;
private final GeoService geoService;
private final ProjectJoinRequestJpaRepository projectJoinRequestJpaRepository;
private final UserMatchingService userMatchingService;

@Transactional
public Long create(Long userId, ProjectCreateReq request) {
// 유저 존재 여부 체크
User tokenUser = getUser(userId);

// 종료 되지 않은 (PENDING,MATCHED) 프로젝트 카드가 있으면 예외를 발생.
if (isExistsNotEndProjectCard(tokenUser)) {
throw new ProjectException(ALREADY_EXIST_PROGRESS_PROJECT);
}

// 매칭 중인 프로젝트가 있으면 예외를 발생.
if (userMatchingService.hasProgressMatching(tokenUser.getId())) {
throw new ProjectException(INVALID_MATCHING_USER_TO_CREATE_PROJECT);
}

// 프로젝트 카드 생성자와 토큰 유저가 다르면 예외를 발생.
validateProjectCardCreator(tokenUser, request.getCreatorId());

Expand All @@ -58,6 +73,11 @@ public Long create(Long userId, ProjectCreateReq request) {
return project.getId();
}

private boolean isExistsNotEndProjectCard(User tokenUser) {
return !projectJpaRepository.findNotEndProjectOneByCreatorId(tokenUser.getId(),
PageRequest.of(0, 1)).isEmpty();
}

@Transactional
public void delete(Long userId, Long projectId) {
// 유저 존재 여부 체크
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import static io.oeid.mogakgo.exception.code.ErrorCode400.INVALID_PROJECT_TAG_COUNT;
import static io.oeid.mogakgo.exception.code.ErrorCode403.PROJECT_FORBIDDEN_OPERATION;

import io.oeid.mogakgo.common.base.BaseTimeEntity;
import io.oeid.mogakgo.domain.project.domain.entity.enums.ProjectStatus;
import io.oeid.mogakgo.common.base.BaseTimeEntity;
import io.oeid.mogakgo.domain.project.domain.entity.vo.CreatorInfo;
import io.oeid.mogakgo.domain.project.domain.entity.vo.MeetingInfo;
import io.oeid.mogakgo.domain.project.exception.ProjectException;
Expand Down Expand Up @@ -79,6 +79,12 @@ private Project(
addProjectTagsWithValidation(projectTags);
}

public void match(User tokenUser) {
validateCreator(tokenUser);
projectStatus.validateAvailableMatched();
this.projectStatus = ProjectStatus.MATCHED;
}

public void delete(User tokenUser) {
validateAvailableDelete(tokenUser);
super.delete();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

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 static io.oeid.mogakgo.exception.code.ErrorCode400.INVALID_PROJECT_STATUS_TO_ACCEPT;

import io.oeid.mogakgo.domain.project.exception.ProjectException;
import io.oeid.mogakgo.domain.project_join_req.exception.ProjectJoinRequestException;
import lombok.Getter;

@Getter
Expand All @@ -30,4 +32,10 @@ public void validateAvailableCancel() {
throw new ProjectException(PROJECT_CANCEL_NOT_ALLOWED);
}
}

public void validateAvailableMatched() {
if (this != PENDING) {
throw new ProjectJoinRequestException(INVALID_PROJECT_STATUS_TO_ACCEPT);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package io.oeid.mogakgo.domain.project.infrastructure;

import io.oeid.mogakgo.domain.project.domain.entity.Project;
import java.util.List;
import java.util.Optional;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
Expand All @@ -15,4 +17,8 @@ public interface ProjectJpaRepository extends JpaRepository<Project, Long>, Proj

@Query("select p from Project p where p.id = :id")
Optional<Project> findByIdWithDeleted(Long id);

@Query("select p from Project p "
+ "where p.creator.id = :creatorId and p.projectStatus in ('PROGRESS', 'MATCHED')")
List<Project> findNotEndProjectOneByCreatorId(Long creatorId, Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectDetailAPIRes;
import io.oeid.mogakgo.domain.project.presentation.dto.req.ProjectCreateReq;
import io.oeid.mogakgo.domain.project.presentation.dto.res.ProjectIdRes;
import io.oeid.mogakgo.domain.project_join_req.presentation.projectJoinRequestRes;
import io.oeid.mogakgo.domain.project_join_req.presentation.dto.res.projectJoinRequestRes;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
Expand Down
Loading

0 comments on commit 1d7ccc8

Please sign in to comment.