Skip to content

Commit

Permalink
Merge pull request #32 from Leets-Official/feat/#29/매칭-취소,매칭-성공-로직-완성
Browse files Browse the repository at this point in the history
Feat/#29/매칭 취소,매칭 성공 로직 완성
  • Loading branch information
soyesenna authored Jan 20, 2025
2 parents faa69ce + 0ed17f0 commit 27b937f
Show file tree
Hide file tree
Showing 43 changed files with 988 additions and 276 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,5 @@ out/
.vscode/

src/main/resources/.env

docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public Optional<FindRoomResult> findRoom(Long userId, double startLongitude, dou
ACTIVE 상태인 방만 필터링
*/
matchingRooms = matchingRooms.stream()
.filter(MatchingRoom::isActiveMatchingRoom)
.filter(MatchingRoom::isActive)
.toList();
/*
태그 조건이 있는 경우에 태그정보까지 필터링
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.gachtaxi.domain.matching.aop;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SseSubscribeRequired {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.gachtaxi.domain.matching.aop;

import com.gachtaxi.domain.matching.common.controller.ResponseMessage;
import com.gachtaxi.domain.matching.common.exception.ControllerNotHasCurrentMemberIdException;
import com.gachtaxi.domain.matching.common.service.AutoMatchingService;
import com.gachtaxi.global.auth.jwt.annotation.CurrentMemberId;
import com.gachtaxi.global.common.response.ApiResponse;
import java.lang.reflect.Parameter;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

@Aspect
@Component
@RequiredArgsConstructor
public class SseSubscribeRequiredAop {

private final AutoMatchingService autoMatchingService;

@Around("@annotation(com.gachtaxi.domain.matching.aop.SseSubscribeRequired)")
public Object checkSseSubscribe(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
Long memberId = null;
MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
Parameter[] parameters = signature.getMethod().getParameters();

for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
if (parameter.getType().equals(Long.class) && parameter.isAnnotationPresent(
CurrentMemberId.class)) {
memberId = (Long) proceedingJoinPoint.getArgs()[i];
break;
}
}

if (memberId == null) {
throw new ControllerNotHasCurrentMemberIdException();
}

if (!this.autoMatchingService.isSseSubscribed(memberId)) {
return ApiResponse.response(
HttpStatus.BAD_REQUEST,
ResponseMessage.NOT_SUBSCRIBED_SSE.getMessage()
);
}

return proceedingJoinPoint.proceed();
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package com.gachtaxi.domain.matching.common.controller;

import com.gachtaxi.domain.matching.aop.SseSubscribeRequired;
import com.gachtaxi.domain.matching.common.dto.request.AutoMatchingCancelledRequest;
import com.gachtaxi.domain.matching.common.dto.request.AutoMatchingPostRequest;
import com.gachtaxi.domain.matching.common.dto.response.AutoMatchingPostResponse;
import com.gachtaxi.domain.matching.common.service.AutoMatchingService;
import com.gachtaxi.global.auth.jwt.annotation.CurrentMemberId;
import com.gachtaxi.global.common.response.ApiResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
Expand All @@ -15,6 +19,7 @@
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/matching/auto")
Expand All @@ -23,31 +28,33 @@ public class AutoMatchingController {
private final AutoMatchingService autoMatchingService;

@GetMapping(value = "/subscribe", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter subscribeSse(@RequestParam Long memberId) {
// TODO: 인가 로직 완성되면 해당 멤버의 아이디를 가져오도록 변경
// Long memberId = 1L;

public SseEmitter subscribeSse(@CurrentMemberId Long memberId) {
return this.autoMatchingService.handleSubscribe(memberId);
}

@PostMapping("/request")
@SseSubscribeRequired
public ApiResponse<AutoMatchingPostResponse> requestMatching(
@RequestParam Long memberId,
@CurrentMemberId Long memberId,
@RequestBody AutoMatchingPostRequest autoMatchingPostRequest
) {
// TODO: 인가 로직 완성되면 해당 멤버의 아이디를 가져오도록 변경
// Long memberId = 1L;
if (!this.autoMatchingService.isSseSubscribed(memberId)) {
return ApiResponse.response(
HttpStatus.BAD_REQUEST,
ResponseMessage.NOT_SUBSCRIBED_SSE.getMessage()
);
}

return ApiResponse.response(
HttpStatus.OK,
ResponseMessage.AUTO_MATCHING_REQUEST_ACCEPTED.getMessage(),
this.autoMatchingService.handlerAutoRequestMatching(memberId, autoMatchingPostRequest)
);
}

@PostMapping("/cancel")
@SseSubscribeRequired
public ApiResponse<AutoMatchingPostResponse> cancelMatching(
@CurrentMemberId Long memberId,
@RequestBody AutoMatchingCancelledRequest autoMatchingCancelledRequest
) {
return ApiResponse.response(
HttpStatus.OK,
ResponseMessage.AUTO_MATCHING_REQUEST_CANCELLED.getMessage(),
this.autoMatchingService.handlerAutoCancelMatching(memberId, autoMatchingCancelledRequest)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ public enum ResponseMessage {

// auto matching
AUTO_MATCHING_REQUEST_ACCEPTED("자동 매칭 요청 전송에 성공했습니다."),
NOT_SUBSCRIBED_SSE("SSE 구독 후 자동 매칭을 요청할 수 있습니다.");
NOT_SUBSCRIBED_SSE("SSE 구독 후 자동 매칭을 요청할 수 있습니다."),
AUTO_MATCHING_REQUEST_CANCELLED("자동 매칭 취소 요청 전송에 성공했습니다.");

private final String message;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
@AllArgsConstructor
public enum AutoMatchingStatus {
REQUESTED("REQUESTED"),
REJECTED("REJECTED");

REJECTED("REJECTED"),
CANCELLED("CANCELLED");
private final String value;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.gachtaxi.domain.matching.common.dto.request;

public record AutoMatchingCancelledRequest(
Long roomId
) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.gachtaxi.domain.matching.algorithm.dto.FindRoomResult;
import com.gachtaxi.domain.matching.common.entity.enums.MatchingRoomStatus;
import com.gachtaxi.domain.matching.event.dto.kafka_topic.MatchRoomCreatedEvent;
import com.gachtaxi.domain.matching.common.entity.enums.Tags;
import com.gachtaxi.domain.members.entity.Members;
import com.gachtaxi.global.common.entity.BaseEntity;
Expand All @@ -20,10 +21,11 @@
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Entity
@Table(name = "matching_room")
@Builder
@Builder(access = AccessLevel.PRIVATE)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class MatchingRoom extends BaseEntity {
Expand All @@ -40,6 +42,8 @@ public class MatchingRoom extends BaseEntity {
private List<MemberMatchingRoomChargingInfo> memberMatchingRoomChargingInfo;

@ManyToOne(cascade = CascadeType.PERSIST, optional = false)
@Getter
@Setter
private Members roomMaster;

@Column(name = "title", nullable = false)
Expand All @@ -58,9 +62,37 @@ public class MatchingRoom extends BaseEntity {
@Enumerated(EnumType.STRING)
private MatchingRoomStatus matchingRoomStatus;

public boolean isActiveMatchingRoom() {
public boolean isActive() {
return this.matchingRoomStatus == MatchingRoomStatus.ACTIVE;
}

public void changeRoomMaster(Members members) {
this.setRoomMaster(members);
}

public void cancelMatchingRoom() {
this.matchingRoomStatus = MatchingRoomStatus.CANCELLED;
}

public void completeMatchingRoom() {
this.matchingRoomStatus = MatchingRoomStatus.COMPLETE;
}

public boolean isFull(int size) {
return size == totalCharge;
}

public static MatchingRoom activeOf(MatchRoomCreatedEvent matchRoomCreatedEvent, Members members, Route route) {
return MatchingRoom.builder()
.capacity(matchRoomCreatedEvent.maxCapacity())
.roomMaster(members)
.title(matchRoomCreatedEvent.title())
.description(matchRoomCreatedEvent.description())
.route(route)
.totalCharge(matchRoomCreatedEvent.expectedTotalCharge())
.matchingRoomStatus(MatchingRoomStatus.ACTIVE)
.build();
}
public boolean containsTag(Tags tag) {
return this.matchingRoomTagInfo.stream()
.anyMatch(tagInfo -> tagInfo.matchesTag(tag));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
@Table(name = "matching_room_tag_info")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Builder
@Builder(access = AccessLevel.PRIVATE)
public class MatchingRoomTagInfo extends BaseEntity {

@ManyToOne
Expand All @@ -25,6 +25,13 @@ public class MatchingRoomTagInfo extends BaseEntity {
@Enumerated(EnumType.STRING)
private Tags tags;

public static MatchingRoomTagInfo of(MatchingRoom matchingRoom, Tags tag) {
return MatchingRoomTagInfo.builder()
.matchingRoom(matchingRoom)
.tags(tag)
.build();
}

public boolean matchesTag(Tags tag) {
return this.tags == tag;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

Expand All @@ -26,10 +27,11 @@
)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Builder
@Builder(access = AccessLevel.PRIVATE)
public class MemberMatchingRoomChargingInfo extends BaseEntity {

@ManyToOne(fetch = FetchType.LAZY)
@Getter
private Members members;

@ManyToOne(fetch = FetchType.LAZY)
Expand All @@ -40,5 +42,27 @@ public class MemberMatchingRoomChargingInfo extends BaseEntity {
private Integer charge;

@Enumerated(EnumType.STRING)
private PaymentStatus paymentStatus = PaymentStatus.NOT_PAYED;
private PaymentStatus paymentStatus;

public void leftMatchingRoom() {
this.paymentStatus = PaymentStatus.LEFT;
}

public boolean isAlreadyLeft() {
return this.paymentStatus == PaymentStatus.LEFT;
}

public MemberMatchingRoomChargingInfo joinMatchingRoom() {
this.paymentStatus = PaymentStatus.NOT_PAYED;
return this;
}

public static MemberMatchingRoomChargingInfo notPayedOf(MatchingRoom matchingRoom, Members members) {
return MemberMatchingRoomChargingInfo.builder()
.matchingRoom(matchingRoom)
.members(members)
.charge(matchingRoom.getTotalCharge())
.paymentStatus(PaymentStatus.NOT_PAYED)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.gachtaxi.domain.matching.common.entity;

import com.gachtaxi.domain.matching.event.dto.kafka_topic.MatchRoomCreatedEvent;
import com.gachtaxi.global.common.entity.BaseEntity;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.gachtaxi.domain.matching.common.entity.enums;

public enum MatchingRoomStatus {
PROCESS, COMPLETE, CANCELED, ACTIVE
COMPLETE, CANCELLED, ACTIVE
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.gachtaxi.domain.matching.common.entity.enums;

public enum PaymentStatus {
PAYED, NOT_PAYED, FAILED
PAYED, NOT_PAYED, FAILED, LEFT
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.gachtaxi.domain.matching.common.exception;

import static com.gachtaxi.domain.matching.common.exception.ErrorMessage.CONTROLLER_NOT_HAS_CURRENT_MEMBER_ID;
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;

import com.gachtaxi.global.common.exception.BaseException;

public class ControllerNotHasCurrentMemberIdException extends BaseException {

public ControllerNotHasCurrentMemberIdException() {
super(INTERNAL_SERVER_ERROR, CONTROLLER_NOT_HAS_CURRENT_MEMBER_ID.getMessage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ public enum ErrorMessage {

NO_SUCH_MATCHING_ROOM("해당 매칭 방이 존재하지 않습니다."),
NOT_ACTIVE_MATCHING_ROOM("열린 매칭 방이 아닙니다."),
MEMBER_NOT_IN_MATCHING_ROOM("해당 매칭 방에 참가한 멤버가 아닙니다."),
MEMBER_ALREADY_JOINED_MATCHING_ROOM("해당 맴버는 이미 매칭 방에 참가한 멤버입니다"),
MEMBER_ALREADY_LEFT_MATCHING_ROOM("해당 멤버는 이미 매칭 방에서 나간 멤버입니다."),
CONTROLLER_NOT_HAS_CURRENT_MEMBER_ID("해당 컨트롤러는 인가된 멤버 ID가 필요합니다."),
NOT_DEFINED_KAFKA_TEMPLATE("해당 이벤트와 맞는 KafkaTemplate이 정의되지 않았습니다."),
DUPLICATED_MATCHING_ROOM("이미 존재하는 매칭 방입니다."),
NOT_FOUND_PAGE("페이지 번호는 0 이상이어야 합니다.");

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.gachtaxi.domain.matching.common.exception;

import static com.gachtaxi.domain.matching.common.exception.ErrorMessage.MEMBER_ALREADY_JOINED_MATCHING_ROOM;
import static org.springframework.http.HttpStatus.CONFLICT;

import com.gachtaxi.global.common.exception.BaseException;

public class MemberAlreadyJoinedException extends BaseException {

public MemberAlreadyJoinedException() {
super(CONFLICT, MEMBER_ALREADY_JOINED_MATCHING_ROOM.getMessage());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.gachtaxi.domain.matching.common.exception;

import static com.gachtaxi.domain.matching.common.exception.ErrorMessage.MEMBER_ALREADY_LEFT_MATCHING_ROOM;
import static org.springframework.http.HttpStatus.CONFLICT;

import com.gachtaxi.global.common.exception.BaseException;

public class MemberAlreadyLeftMatchingRoomException extends BaseException {

public MemberAlreadyLeftMatchingRoomException() {
super(CONFLICT, MEMBER_ALREADY_LEFT_MATCHING_ROOM.getMessage());
}
}
Loading

0 comments on commit 27b937f

Please sign in to comment.