Skip to content

Commit 9276910

Browse files
authored
Feat/8 (#161)
* Feat : 권한 체크 * Feat : 멘토링 세션관련 엔티티 작성 * Feat : 필드 수정 * Feat : 필드 수정 * Feat : 필드 수정 * Feat : 소켓 통신을 위한 UUID를 저장할 필드 추가 * Feat : 소켓 통신 의존성 추가 * Feat : 채팅기능 동작확인 * Feat : MemberEntity와 연관관계 매핑 * Feat : SenderRole이 MentoringSession에 의해 초기화되도록 수정 * Feat : 서비스. 레포지토리 추가 * Feat : 유효성 검증 추가 * Test : ReservationFixture 추가 * Test : MentoringSessionTest 작성 * Feat : 서비스, 레포지토리 작성 * Test : 테스트 항목 작성 * Feat : 메서드 추가 * Feat : 제거 * Test : 테스트 수정 * Feat: 메서드 추가 * Feat: 메서드 추가 * Test: 테스트 수정 * Fix : 키값 수정 * Feat : 픽스쳐 작성 * Feat : 픽스쳐 작성 * Feat : 예약이 승인/취소 되면 세션이 생성/삭제 된다. * Feat/Test : 권한검증 * Feat : 세션 여닫기, 정보 확인, 참여를 위한 URL발급 엔드포인트 작성 * Fix : 엔드포인트 프리픽스 수정, @PathVariable 어노테이션 누락 추가 * Feat : 채팅 송수진 기능 * Feat : 채팅 송수진 기능 * Feat : init데이터 생성 * Feat : init데이터 생성 * Feat : 채팅 기능 수정 * chore : 패키지 이동 * Feat : ChatManager 1안 * Feat : 채팅 기능 완료 * Feat : 메시지 저장 시점에서 멘토 멘티 구별 방식 변경 * Feat : Transactional 추가 * Feat : Transactional 추가 * Feat : 예약 조회시 관련된 세션 id도 함께 반환 * Feat : OPTIONS 요청 허용 * Test : 테스트 수정 * Test : 테스트 수정
1 parent 8c50d73 commit 9276910

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1040
-36
lines changed

back/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ dependencies {
6565
implementation ("software.amazon.awssdk:s3:2.25.0")
6666

6767
implementation ("org.springframework.kafka:spring-kafka")
68+
implementation("org.springframework.boot:spring-boot-starter-websocket")
6869

6970
runtimeOnly("com.mysql:mysql-connector-j")
7071

back/src/main/java/com/back/domain/file/video/controller/VideoController.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.back.global.rsData.RsData;
77
import io.swagger.v3.oas.annotations.Operation;
88
import lombok.RequiredArgsConstructor;
9+
import org.springframework.security.access.prepost.PreAuthorize;
910
import org.springframework.web.bind.annotation.GetMapping;
1011
import org.springframework.web.bind.annotation.RequestParam;
1112
import org.springframework.web.bind.annotation.RestController;
@@ -16,15 +17,16 @@ public class VideoController {
1617
private final FileManager fileManager;
1718

1819
@GetMapping("/videos/upload")
19-
@Operation(summary="업로드용 URL 요청", description="파일 업로드를 위한 Presigned URL을 발급받습니다.")
20+
@PreAuthorize("hasRole('ADMIN')")
21+
@Operation(summary = "업로드용 URL 요청", description = "파일 업로드를 위한 Presigned URL을 발급받습니다.")
2022
public RsData<UploadUrlGetResponse> getUploadUrl() {
2123
PresignedUrlResponse uploadUrl = fileManager.getUploadUrl();
2224
UploadUrlGetResponse response = new UploadUrlGetResponse(uploadUrl.url().toString(), uploadUrl.expiresAt());
2325
return new RsData<>("200", "업로드용 URL 요청완료", response);
2426
}
2527

2628
@GetMapping("/videos/download")
27-
@Operation(summary="다운로드용 URL 요청", description="파일 다운로드를 위한 Presigned URL을 발급받습니다.")
29+
@Operation(summary = "다운로드용 URL 요청", description = "파일 다운로드를 위한 Presigned URL을 발급받습니다.")
2830
public RsData<UploadUrlGetResponse> getDownloadUrls(@RequestParam String objectKey) {
2931
PresignedUrlResponse downloadUrl = fileManager.getDownloadUrl(objectKey);
3032
UploadUrlGetResponse response = new UploadUrlGetResponse(downloadUrl.url().toString(), downloadUrl.expiresAt());

back/src/main/java/com/back/domain/member/member/service/MemberStorage.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.back.domain.member.member.entity.Member;
44
import com.back.domain.member.member.error.MemberErrorCode;
5+
import com.back.domain.member.member.repository.MemberRepository;
56
import com.back.domain.member.mentee.entity.Mentee;
67
import com.back.domain.member.mentee.repository.MenteeRepository;
78
import com.back.domain.member.mentor.entity.Mentor;
@@ -13,7 +14,7 @@
1314
@Component
1415
@RequiredArgsConstructor
1516
public class MemberStorage {
16-
17+
private final MemberRepository memberRepository;
1718
private final MentorRepository mentorRepository;
1819
private final MenteeRepository menteeRepository;
1920

@@ -39,4 +40,9 @@ public Mentee findMenteeByMember(Member member) {
3940
public boolean existsMentorById(Long mentorId) {
4041
return mentorRepository.existsById(mentorId);
4142
}
43+
44+
public Member findMemberByEmail(String email) {
45+
return memberRepository.findByEmail(email)
46+
.orElseThrow(() -> new ServiceException(MemberErrorCode.NOT_FOUND_MEMBER));
47+
}
4248
}

back/src/main/java/com/back/domain/mentoring/mentoring/service/MentoringStorage.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import com.back.domain.mentoring.reservation.entity.Reservation;
77
import com.back.domain.mentoring.reservation.error.ReservationErrorCode;
88
import com.back.domain.mentoring.reservation.repository.ReservationRepository;
9+
import com.back.domain.mentoring.session.entity.MentoringSession;
10+
import com.back.domain.mentoring.session.repository.MentoringSessionRepository;
911
import com.back.domain.mentoring.slot.entity.MentorSlot;
1012
import com.back.domain.mentoring.slot.error.MentorSlotErrorCode;
1113
import com.back.domain.mentoring.slot.repository.MentorSlotRepository;
@@ -27,6 +29,7 @@ public class MentoringStorage {
2729
private final MentoringRepository mentoringRepository;
2830
private final MentorSlotRepository mentorSlotRepository;
2931
private final ReservationRepository reservationRepository;
32+
private final MentoringSessionRepository mentoringSessionRepository;
3033

3134
// ===== find 메서드 =====
3235

@@ -67,4 +70,16 @@ public boolean hasMentorSlotsForMentor(Long mentorId) {
6770
public boolean hasReservationForMentorSlot(Long slotId) {
6871
return reservationRepository.existsByMentorSlotId(slotId);
6972
}
73+
74+
75+
// ===== 데이터 조작 메서드 =====
76+
77+
public void deleteMentorSlotsData(Long mentorId) {
78+
mentorSlotRepository.deleteAllByMentorId(mentorId);
79+
}
80+
81+
public MentoringSession getMentoringSessionBySessionUuid(String mentoringSessionId) {
82+
return mentoringSessionRepository.findBySessionUrl(mentoringSessionId)
83+
.orElseThrow(() -> new ServiceException("404", "세션을 찾을 수 없습니다."));
84+
}
7085
}

back/src/main/java/com/back/domain/mentoring/reservation/dto/ReservationDetailDto.java

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,58 @@
22

33
import com.back.domain.mentoring.reservation.constant.ReservationStatus;
44
import com.back.domain.mentoring.reservation.entity.Reservation;
5+
import com.back.domain.mentoring.session.entity.MentoringSession;
56
import io.swagger.v3.oas.annotations.media.Schema;
67

78
import java.time.LocalDateTime;
89

910
public record ReservationDetailDto(
10-
@Schema(description = "예약 ID")
11-
Long reservationId,
12-
@Schema(description = "예약 상태")
13-
ReservationStatus status,
14-
@Schema(description = "사전 질문")
15-
String preQuestion,
11+
@Schema(description = "예약 ID")
12+
Long reservationId,
13+
@Schema(description = "예약 상태")
14+
ReservationStatus status,
15+
@Schema(description = "사전 질문")
16+
String preQuestion,
1617

17-
@Schema(description = "멘토 슬롯 ID")
18-
Long mentorSlotId,
19-
@Schema(description = "시작 일시")
20-
LocalDateTime startDateTime,
21-
@Schema(description = "종료 일시")
22-
LocalDateTime endDateTime,
18+
@Schema(description = "멘토 슬롯 ID")
19+
Long mentorSlotId,
20+
@Schema(description = "시작 일시")
21+
LocalDateTime startDateTime,
22+
@Schema(description = "종료 일시")
23+
LocalDateTime endDateTime,
2324

24-
@Schema(description = "생성일")
25-
LocalDateTime createDate,
26-
@Schema(description = "수정일")
27-
LocalDateTime modifyDate
25+
@Schema(description = "생성일")
26+
LocalDateTime createDate,
27+
@Schema(description = "수정일")
28+
LocalDateTime modifyDate,
29+
@Schema(description = "멘토링 세션 ID")
30+
Long mentoringSessionId
2831
) {
2932
public static ReservationDetailDto from(Reservation reservation) {
3033
return new ReservationDetailDto(
31-
reservation.getId(),
32-
reservation.getStatus(),
33-
reservation.getPreQuestion(),
34-
reservation.getMentorSlot().getId(),
35-
reservation.getMentorSlot().getStartDateTime(),
36-
reservation.getMentorSlot().getEndDateTime(),
37-
reservation.getCreateDate(),
38-
reservation.getModifyDate()
34+
reservation.getId(),
35+
reservation.getStatus(),
36+
reservation.getPreQuestion(),
37+
reservation.getMentorSlot().getId(),
38+
reservation.getMentorSlot().getStartDateTime(),
39+
reservation.getMentorSlot().getEndDateTime(),
40+
reservation.getCreateDate(),
41+
reservation.getModifyDate(),
42+
null
43+
);
44+
}
45+
46+
public static ReservationDetailDto from(Reservation reservation, MentoringSession mentoringSession) {
47+
return new ReservationDetailDto(
48+
reservation.getId(),
49+
reservation.getStatus(),
50+
reservation.getPreQuestion(),
51+
reservation.getMentorSlot().getId(),
52+
reservation.getMentorSlot().getStartDateTime(),
53+
reservation.getMentorSlot().getEndDateTime(),
54+
reservation.getCreateDate(),
55+
reservation.getModifyDate(),
56+
mentoringSession.getId()
3957
);
4058
}
4159
}

back/src/main/java/com/back/domain/mentoring/reservation/dto/ReservationDto.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.back.domain.mentoring.reservation.constant.ReservationStatus;
44
import com.back.domain.mentoring.reservation.entity.Reservation;
5+
import com.back.domain.mentoring.session.entity.MentoringSession;
56
import io.swagger.v3.oas.annotations.media.Schema;
67

78
import java.time.LocalDateTime;
@@ -22,17 +23,20 @@ public record ReservationDto(
2223
@Schema(description = "시작 일시")
2324
LocalDateTime startDateTime,
2425
@Schema(description = "종료 일시")
25-
LocalDateTime endDateTime
26+
LocalDateTime endDateTime,
27+
@Schema(description = "멘토링 세션 ID")
28+
Long mentoringSessionId
2629
) {
27-
public static ReservationDto from(Reservation reservation) {
30+
public static ReservationDto from(Reservation reservation, MentoringSession mentoringSession) {
2831
return new ReservationDto(
2932
reservation.getId(),
3033
reservation.getStatus(),
3134
reservation.getMentoring().getId(),
3235
reservation.getMentoring().getTitle(),
3336
reservation.getMentorSlot().getId(),
3437
reservation.getMentorSlot().getStartDateTime(),
35-
reservation.getMentorSlot().getEndDateTime()
38+
reservation.getMentorSlot().getEndDateTime(),
39+
mentoringSession != null ? mentoringSession.getId() : null
3640
);
3741
}
3842
}

back/src/main/java/com/back/domain/mentoring/reservation/dto/response/ReservationResponse.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.back.domain.mentoring.mentoring.dto.MentoringDto;
66
import com.back.domain.mentoring.reservation.dto.ReservationDetailDto;
77
import com.back.domain.mentoring.reservation.entity.Reservation;
8+
import com.back.domain.mentoring.session.entity.MentoringSession;
89

910
public record ReservationResponse(
1011
ReservationDetailDto reservation,
@@ -20,4 +21,12 @@ public static ReservationResponse from(Reservation reservation) {
2021
MenteeDto.from(reservation.getMentee())
2122
);
2223
}
24+
public static ReservationResponse from(Reservation reservation, MentoringSession mentoringSession) {
25+
return new ReservationResponse(
26+
ReservationDetailDto.from(reservation, mentoringSession),
27+
MentoringDto.from(reservation.getMentoring()),
28+
MentorDto.from(reservation.getMentor()),
29+
MenteeDto.from(reservation.getMentee())
30+
);
31+
}
2332
}

back/src/main/java/com/back/domain/mentoring/reservation/service/ReservationService.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import com.back.domain.mentoring.reservation.entity.Reservation;
1313
import com.back.domain.mentoring.reservation.error.ReservationErrorCode;
1414
import com.back.domain.mentoring.reservation.repository.ReservationRepository;
15+
import com.back.domain.mentoring.session.entity.MentoringSession;
16+
import com.back.domain.mentoring.session.service.MentoringSessionService;
1517
import com.back.domain.mentoring.slot.constant.MentorSlotStatus;
1618
import com.back.domain.mentoring.slot.entity.MentorSlot;
1719
import com.back.domain.mentoring.slot.service.DateTimeValidator;
@@ -33,6 +35,7 @@ public class ReservationService {
3335

3436
private final ReservationRepository reservationRepository;
3537
private final MentoringStorage mentoringStorage;
38+
private final MentoringSessionService mentoringSessionService;
3639

3740
@Transactional(readOnly = true)
3841
public Page<ReservationDto> getReservations(Member member, int page, int size) {
@@ -45,15 +48,20 @@ public Page<ReservationDto> getReservations(Member member, int page, int size) {
4548
} else {
4649
reservations = reservationRepository.findAllByMenteeMember(member, pageable);
4750
}
48-
return reservations.map(ReservationDto::from);
51+
return reservations.map(r -> {
52+
MentoringSession mentoringSession = mentoringSessionService.getMentoringSessionByReservation(r);
53+
return ReservationDto.from(r, mentoringSession);
54+
});
4955
}
5056

5157
@Transactional(readOnly = true)
5258
public ReservationResponse getReservation(Member member, Long reservationId) {
5359
Reservation reservation = reservationRepository.findByIdAndMember(reservationId, member.getId())
5460
.orElseThrow(() -> new ServiceException(ReservationErrorCode.RESERVATION_NOT_ACCESSIBLE));
5561

56-
return ReservationResponse.from(reservation);
62+
MentoringSession mentoringSession = mentoringSessionService.getMentoringSessionByReservation(reservation);
63+
64+
return ReservationResponse.from(reservation, mentoringSession);
5765
}
5866

5967
@Transactional
@@ -90,7 +98,8 @@ public ReservationResponse approveReservation(Mentor mentor, Long reservationId)
9098
reservation.approve(mentor);
9199
reservation.getMentorSlot().updateStatus(MentorSlotStatus.APPROVED);
92100

93-
// 세션
101+
// 예약이 승인되면 세션을 생성한다.
102+
MentoringSession mentoringSession = mentoringSessionService.create(reservation);
94103

95104
return ReservationResponse.from(reservation);
96105
} catch (OptimisticLockException e) {
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.back.domain.mentoring.session.controller;
2+
3+
import com.back.domain.mentoring.session.dto.ChatMessageRequest;
4+
import com.back.domain.mentoring.session.service.ChatManager;
5+
import lombok.RequiredArgsConstructor;
6+
import lombok.extern.slf4j.Slf4j;
7+
import org.springframework.messaging.handler.annotation.DestinationVariable;
8+
import org.springframework.messaging.handler.annotation.MessageMapping;
9+
import org.springframework.stereotype.Controller;
10+
11+
import java.security.Principal;
12+
13+
@Slf4j
14+
@Controller
15+
@RequiredArgsConstructor
16+
public class ChatController {
17+
private final ChatManager chatManager;
18+
19+
@MessageMapping({"/chat/message/{mentoringSessionUuid}"})
20+
public void message(@DestinationVariable String mentoringSessionUuid, Principal principal, ChatMessageRequest chatMessageRequest) {
21+
chatManager.chat(mentoringSessionUuid, principal, chatMessageRequest);
22+
}
23+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.back.domain.mentoring.session.controller;
2+
3+
import com.back.domain.member.member.entity.Member;
4+
import com.back.domain.mentoring.session.dto.*;
5+
import com.back.domain.mentoring.session.service.MentoringSessionManager;
6+
import com.back.global.rq.Rq;
7+
import com.back.global.rsData.RsData;
8+
import lombok.RequiredArgsConstructor;
9+
import org.springframework.security.access.prepost.PreAuthorize;
10+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
11+
import org.springframework.web.bind.annotation.*;
12+
13+
@RestController
14+
@RequiredArgsConstructor
15+
@RequestMapping("/sessions")
16+
public class MentoringSessionController {
17+
private final MentoringSessionManager mentoringSessionManager;
18+
private final Rq rq;
19+
20+
//세션참여 URL발급
21+
@GetMapping("/{sessionId}/url")
22+
public RsData<GetSessionUrlResponse> getSessionUrl(@PathVariable Long sessionId) {
23+
GetSessionUrlResponse response = mentoringSessionManager.getSessionUrl(sessionId);
24+
return new RsData<>("200", "요청완료", response);
25+
}
26+
27+
//세션 상세 정보(참여 현황?, 제목 등등?)
28+
@GetMapping("/{sessionId}")
29+
public RsData<GetSessionInfoResponse> getSessionDetail(@PathVariable Long sessionId) {
30+
GetSessionInfoResponse response = mentoringSessionManager.getSessionDetail(sessionId);
31+
return new RsData<>("200", "요청완료", response);
32+
}
33+
34+
//세션 열기
35+
@PutMapping("/{sessionId}")
36+
@PreAuthorize("hasRole('MENTOR')")
37+
public RsData<OpenSessionResponse> openSession(@PathVariable Long sessionId) {
38+
Member member = rq.getActor();
39+
OpenSessionRequest openSessionRequest = new OpenSessionRequest(sessionId);
40+
OpenSessionResponse response = mentoringSessionManager.openSession(member, openSessionRequest);
41+
return new RsData<>("200", "세션 오픈 완료", response);
42+
}
43+
44+
//세션종료
45+
@DeleteMapping("/{sessionId}")
46+
@PreAuthorize("hasRole('MENTOR')")
47+
public RsData<CloseSessionResponse> closeSession(@PathVariable Long sessionId) {
48+
Member member = rq.getActor();
49+
DeleteSessionRequest deleteSessionRequest = new DeleteSessionRequest(sessionId);
50+
CloseSessionResponse response = mentoringSessionManager.closeSession(member, deleteSessionRequest);
51+
return new RsData<>("200", "세션 종료 완료", response);
52+
}
53+
}

0 commit comments

Comments
 (0)