Skip to content
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
@@ -0,0 +1,99 @@
package com.kusitms.website.domain.mentoring;

import com.kusitms.website.domain.mentoring.dto.request.MentoringApplyRequest;
import com.kusitms.website.domain.mentoring.dto.response.MentorDetailResponse;
import com.kusitms.website.domain.mentoring.dto.response.MentorListResponse;
import com.kusitms.website.domain.mentoring.dto.response.MentorMainResponse;
import com.kusitms.website.domain.mentoring.dto.response.MentoringReviewListResponse;
import com.kusitms.website.domain.mentoring.entity.MentoringCategory;
import com.kusitms.website.domain.mentoring.service.MentoringService;
import com.kusitms.website.global.auth.UserPrincipal;
import com.kusitms.website.global.common.BaseResponse;
import javax.validation.Valid;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/mentoring")
@RequiredArgsConstructor
@Tag(name = "Mentoring", description = "멘토링 API")
public class MentoringController {

private final MentoringService mentoringService;

@GetMapping
@Operation(summary = "멘토링 메인", description = "활동 중인 멘토 카드 최대 4개를 랜덤으로 조회합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "조회 성공"),
})
public ResponseEntity<BaseResponse<MentorMainResponse>> getMainMentors() {
return ResponseEntity.ok(new BaseResponse<>(mentoringService.getMainMentors()));
}

@GetMapping("/list")
@Operation(summary = "멘토 리스트", description = "멘토 목록을 카테고리별로 페이지네이션하여 조회합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "조회 성공"),
})
public ResponseEntity<BaseResponse<MentorListResponse>> getMentorList(
@RequestParam(required = false) MentoringCategory category,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "12") int size) {
return ResponseEntity.ok(new BaseResponse<>(mentoringService.getMentorList(category, page, size)));
}

@GetMapping("/{mentorId}")
@Operation(summary = "멘토 세부정보", description = "멘토의 상세 정보를 조회합니다. 로그인 필수.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "401", description = "인증 필요"),
})
public ResponseEntity<BaseResponse<MentorDetailResponse>> getMentorDetail(
@PathVariable Long mentorId) {
Long userId = getAuthenticatedUserId();
return ResponseEntity.ok(new BaseResponse<>(mentoringService.getMentorDetail(mentorId, userId)));
}

@GetMapping("/{mentorId}/reviews")
@Operation(summary = "멘토링 후기 페이지네이션", description = "멘토의 후기를 페이지네이션하여 조회합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "조회 성공"),
})
public ResponseEntity<BaseResponse<MentoringReviewListResponse>> getMentorReviews(
@PathVariable Long mentorId,
@RequestParam(defaultValue = "0") int page) {
return ResponseEntity.ok(new BaseResponse<>(mentoringService.getMentorReviews(mentorId, page)));
}

@PostMapping("/{mentorId}/apply")
@Operation(summary = "멘토링 신청", description = "멘토링 슬롯을 선택하여 신청합니다. 로그인 필수.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "신청 성공"),
@ApiResponse(responseCode = "400", description = "신청 실패"),
@ApiResponse(responseCode = "401", description = "인증 필요"),
})
public ResponseEntity<BaseResponse> applyMentoring(
@PathVariable Long mentorId,
@Valid @RequestBody MentoringApplyRequest request) {
Long userId = getAuthenticatedUserId();
mentoringService.applyMentoring(mentorId, userId, request);
return ResponseEntity.ok(new BaseResponse());
}

private Long getAuthenticatedUserId() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()
|| authentication.getPrincipal().equals("anonymousUser")) {
throw new IllegalArgumentException("로그인이 필요합니다.");
}
UserPrincipal principal = (UserPrincipal) authentication.getPrincipal();
return principal.getPk();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.kusitms.website.domain.mentoring.dto.request;

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

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@Getter
@NoArgsConstructor
public class MentoringApplyRequest {

@NotNull
@Schema(description = "슬롯 ID", required = true)
private Long slotId;

@Size(max = 500)
@Schema(description = "멘토에게 공유할 메시지", maxLength = 500)
private String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.kusitms.website.domain.mentoring.dto.response;

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

@Getter
@AllArgsConstructor
public class KeywordChipResponse {

@Schema(description = "키워드 ID")
private Long keywordId;

@Schema(description = "키워드 이름")
private String name;

@Schema(description = "선택 횟수")
private Long count;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.kusitms.website.domain.mentoring.dto.response;

import com.kusitms.website.domain.mentoring.entity.Mentor;
import com.kusitms.website.domain.mentoring.entity.MentoringCategory;
import com.kusitms.website.domain.mentoring.entity.MentoringMethod;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class MentorCardResponse {

@Schema(description = "멘토 ID")
private Long mentorId;

@Schema(description = "멘토링 타이틀")
private String title;

@Schema(description = "프로필 이미지 URL")
private String profileImageUrl;

@Schema(description = "이름")
private String name;

@Schema(description = "기수")
private Integer cardinal;

@Schema(description = "직무 카테고리")
private MentoringCategory category;

@Schema(description = "경력")
private String experience;

@Schema(description = "멘토링 방식")
private MentoringMethod method;

@Schema(description = "시간당 가격")
private Integer pricePerHour;

@Schema(description = "뱃지 키워드 (조건부)")
private String badgeKeyword;

public static MentorCardResponse from(Mentor mentor, String badgeKeyword) {
return MentorCardResponse.builder()
.mentorId(mentor.getMentorId())
.title(mentor.getTitle())
.profileImageUrl(mentor.getProfileImageUrl())
.name(mentor.getMember().getName())
.cardinal(mentor.getMember().getCardinal())
.category(mentor.getCategory())
.experience(mentor.getExperience())
.method(mentor.getMethod())
.pricePerHour(mentor.getPricePerHour())
.badgeKeyword(badgeKeyword)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.kusitms.website.domain.mentoring.dto.response;

import com.kusitms.website.domain.mentoring.entity.Mentor;
import com.kusitms.website.domain.mentoring.entity.MentoringCategory;
import com.kusitms.website.domain.mentoring.entity.MentoringMethod;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Getter;

import java.util.List;

@Getter
@Builder
public class MentorDetailResponse {

@Schema(description = "멘토 ID")
private Long mentorId;

@Schema(description = "멘토링 타이틀")
private String title;

@Schema(description = "프로필 이미지 URL")
private String profileImageUrl;

@Schema(description = "이름")
private String name;

@Schema(description = "기수")
private Integer cardinal;

@Schema(description = "직무 카테고리")
private MentoringCategory category;

@Schema(description = "경력")
private String experience;

@Schema(description = "멘토링 방식")
private MentoringMethod method;

@Schema(description = "시간당 가격")
private Integer pricePerHour;

@Schema(description = "멘토링 소개글")
private String introduction;

@Schema(description = "가용 슬롯 목록")
private List<MentoringSlotResponse> slots;

@Schema(description = "키워드 칩 목록 (3회 이상)")
private List<KeywordChipResponse> keywordChips;

@Schema(description = "후기 목록")
private MentoringReviewListResponse reviews;

@Schema(description = "본인 멘토링 여부")
private boolean isOwnMentoring;

@Schema(description = "기존 PENDING/ACTIVE 신청 존재 여부")
private boolean hasExistingApplication;

public static MentorDetailResponse from(Mentor mentor,
List<MentoringSlotResponse> slots,
List<KeywordChipResponse> keywordChips,
MentoringReviewListResponse reviews,
boolean isOwnMentoring,
boolean hasExistingApplication) {
return MentorDetailResponse.builder()
.mentorId(mentor.getMentorId())
.title(mentor.getTitle())
.profileImageUrl(mentor.getProfileImageUrl())
.name(mentor.getMember().getName())
.cardinal(mentor.getMember().getCardinal())
.category(mentor.getCategory())
.experience(mentor.getExperience())
.method(mentor.getMethod())
.pricePerHour(mentor.getPricePerHour())
.introduction(mentor.getIntroduction())
.slots(slots)
.keywordChips(keywordChips)
.reviews(reviews)
.isOwnMentoring(isOwnMentoring)
.hasExistingApplication(hasExistingApplication)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.kusitms.website.domain.mentoring.dto.response;

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

import java.util.List;

@Getter
@Builder
public class MentorListResponse {

@Schema(description = "전체 멘토 수")
private long totalCount;

@Schema(description = "전체 페이지 수")
private int totalPages;

@Schema(description = "현재 페이지")
private int currentPage;

@Schema(description = "멘토 카드 목록")
private List<MentorCardResponse> mentors;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.kusitms.website.domain.mentoring.dto.response;

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

import java.util.List;

@Getter
@AllArgsConstructor
public class MentorMainResponse {

@Schema(description = "활동 중인 멘토 카드 (최대 4개, 랜덤)")
private List<MentorCardResponse> mentors;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.kusitms.website.domain.mentoring.dto.response;

import com.kusitms.website.domain.mentoring.entity.MentoringReview;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Getter;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Getter
@Builder
public class MentoringReviewDetailResponse {

@Schema(description = "후기 ID")
private Long reviewId;

@Schema(description = "작성자 이름")
private String reviewerName;

@Schema(description = "작성자 기수")
private Integer reviewerCardinal;

@Schema(description = "후기 내용")
private String content;

@Schema(description = "선택된 키워드 목록")
private List<String> keywords;

@Schema(description = "작성일")
private LocalDateTime createdAt;

public static MentoringReviewDetailResponse from(MentoringReview review) {
List<String> keywordNames = review.getKeywords().stream()
.map(rk -> rk.getKeyword().getName())
.collect(Collectors.toList());

return MentoringReviewDetailResponse.builder()
.reviewId(review.getReviewId())
.reviewerName(review.getReviewer().getName())
.reviewerCardinal(review.getReviewer().getCardinal())
.content(review.getContent())
.keywords(keywordNames)
.createdAt(review.getCreatedAt())
.build();
}
}
Loading
Loading