Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b64781d
feat: 멘토 미리보기 목록 조회 dto 생성
nayonsoso Jul 2, 2025
05b2db7
feat: 멘토 미리보기 목록 서비스 함수 생성
nayonsoso Jul 2, 2025
e75413e
feat: 멘토 미리보기 목록 컨트롤러 생성
nayonsoso Jul 2, 2025
d071435
feat: 멘토 마이페이지 응답 dto 생성
nayonsoso Jul 5, 2025
d67a23a
feat: 멘토 마이페이지 응답 서비스 함수 구현
nayonsoso Jul 5, 2025
2d84180
feat: 멘토 마이페이지 컨트롤러 생성
nayonsoso Jul 5, 2025
34ca47c
test: 멘토 마이페이지 조회 테스트 코드 작성
nayonsoso Jul 5, 2025
92a6352
feat: 멘토 마이페이지 수정 요청 dto 생성
nayonsoso Jul 5, 2025
a92fd09
feat: 멘토 마이페이지 수정 서비스 함수 구현
nayonsoso Jul 5, 2025
ddfb315
feat: 멘토 마이페이지 수정 컨트롤러 구현
nayonsoso Jul 5, 2025
31d5c1d
test: 멘토 마이페이지 수정 테스트 코드 작성
nayonsoso Jul 5, 2025
7917b40
style: 불필요한 중괄호 제거
nayonsoso Jul 7, 2025
97af404
chore: 사용되지 않는 변수 제거
nayonsoso Jul 7, 2025
be32db8
refactor: 변수명 단순화
nayonsoso Jul 7, 2025
c19906a
refactor: 최대 채널 등록 갯수 검증 추가, 함수 분리
nayonsoso Jul 7, 2025
7fcca23
style: 개행 추가
nayonsoso Jul 7, 2025
0dcceda
refactor: 멘토 마이 페이지에서 사용자 정보를 수정하지 않도록
nayonsoso Jul 7, 2025
f84b6ab
refactor: 누락한 검증 메세지 추가
nayonsoso Jul 7, 2025
a54bf50
style: 불필요한 중괄호 삭제
nayonsoso Jul 8, 2025
787d636
refactor: 누락한 RequestBody 어노테이션 추가
nayonsoso Jul 8, 2025
83dfae4
refactor: 불필요한 빈 주입 제거
nayonsoso Jul 8, 2025
0551bff
style: 사용되지 않는 import 제거
nayonsoso Jul 9, 2025
9c37b76
refactor: 잘못된 반환 타입 수정
nayonsoso Jul 9, 2025
a440c57
fix: 테스트 깨지는 곳 수정
nayonsoso Jul 9, 2025
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
Expand Up @@ -101,6 +101,9 @@ public enum ErrorCode {
// news
INVALID_NEWS_ACCESS(HttpStatus.BAD_REQUEST.value(), "자신의 소식지만 제어할 수 있습니다."),

// mentor
CHANNEL_SEQUENCE_NOT_UNIQUE(HttpStatus.BAD_REQUEST.value(), "채널의 순서가 중복되었습니다."),
CHANNEL_REGISTRATION_LIMIT_EXCEEDED(HttpStatus.BAD_REQUEST.value(), "등록 가능한 채널 수를 초과하였습니다."),

// database
DATA_INTEGRITY_VIOLATION(HttpStatus.CONFLICT.value(), "데이터베이스 무결성 제약조건 위반이 발생했습니다."),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.example.solidconnection.mentor.controller;

import com.example.solidconnection.common.resolver.AuthorizedUser;
import com.example.solidconnection.mentor.dto.MentorMyPageResponse;
import com.example.solidconnection.mentor.dto.MentorMyPageUpdateRequest;
import com.example.solidconnection.mentor.service.MentorMyPageService;
import com.example.solidconnection.security.annotation.RequireRoleAccess;
import com.example.solidconnection.siteuser.domain.Role;
import com.example.solidconnection.siteuser.domain.SiteUser;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RequestMapping("/mentor/my")
@RestController
public class MentorMyPageController {

private final MentorMyPageService mentorMyPageService;

@RequireRoleAccess(roles = Role.MENTOR)
@GetMapping
public ResponseEntity<MentorMyPageResponse> getMentorMyPage(
@AuthorizedUser SiteUser siteUser
) {
MentorMyPageResponse mentorMyPageResponse = mentorMyPageService.getMentorMyPage(siteUser);
return ResponseEntity.ok(mentorMyPageResponse);
}

@RequireRoleAccess(roles = Role.MENTOR)
@PutMapping
public ResponseEntity<Void> updateMentorMyPage(
@AuthorizedUser SiteUser siteUser,
@Valid @RequestBody MentorMyPageUpdateRequest mentorMyPageUpdateRequest
) {
mentorMyPageService.updateMentorMyPage(siteUser, mentorMyPageUpdateRequest);
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ public class Channel {
@ManyToOne(fetch = FetchType.LAZY)
private Mentor mentor;

public Channel(int sequence, ChannelType type, String url) {
this.sequence = sequence;
this.type = type;
this.url = url;
}

public void updateMentor(Mentor mentor) {
this.mentor = mentor;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,23 @@ public class Mentor {
public void increaseMenteeCount() {
this.menteeCount++;
}

public void updateIntroduction(String introduction) {
this.introduction = introduction;
}

public void updatePassTip(String passTip) {
this.passTip = passTip;
}

public void updateChannels(List<Channel> channels) {
this.channels.clear();
if (channels == null || channels.isEmpty()) {
return;
}
for (Channel channel : channels) {
channel.updateMentor(this);
this.channels.add(channel);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.example.solidconnection.mentor.dto;

import com.example.solidconnection.mentor.domain.ChannelType;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import org.hibernate.validator.constraints.URL;

public record ChannelRequest(
@NotNull(message = "채널 종류를 입력해주세요.")
ChannelType type,

@NotBlank(message = "채널 URL을 입력해주세요.")
@URL
String url
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.example.solidconnection.mentor.dto;

import com.example.solidconnection.mentor.domain.Mentor;
import com.example.solidconnection.siteuser.domain.ExchangeStatus;
import com.example.solidconnection.siteuser.domain.SiteUser;

import java.util.List;

public record MentorMyPageResponse(
long id,
String profileImageUrl,
String nickname,
ExchangeStatus exchangeStatus,
String country,
String universityName,
int menteeCount,
boolean hasBadge,
String introduction,
List<ChannelResponse> channels
) {

public static MentorMyPageResponse of(Mentor mentor, SiteUser siteUser) {
return new MentorMyPageResponse(
mentor.getId(),
siteUser.getProfileImageUrl(),
siteUser.getNickname(),
siteUser.getExchangeStatus(),
"국가", // todo: 교환학생 기록이 인증되면 추가
"대학 이름",
mentor.getMenteeCount(),
mentor.isHasBadge(),
mentor.getIntroduction(),
mentor.getChannels().stream()
.map(ChannelResponse::from)
.toList()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.example.solidconnection.mentor.dto;

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;

import java.util.List;

public record MentorMyPageUpdateRequest(
@NotBlank(message = "자기소개를 입력해주세요.")
String introduction,

@NotBlank(message = "합격 레시피를 입력해주세요.")
String passTip,

@Valid
List<ChannelRequest> channels
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.example.solidconnection.mentor.dto;

import java.util.List;

public record MentorPreviewsResponse(
List<MentorPreviewResponse> content,
int nextPageNumber
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.example.solidconnection.mentor.service;

import com.example.solidconnection.common.exception.CustomException;
import com.example.solidconnection.mentor.domain.Channel;
import com.example.solidconnection.mentor.domain.Mentor;
import com.example.solidconnection.mentor.dto.ChannelRequest;
import com.example.solidconnection.mentor.dto.MentorMyPageResponse;
import com.example.solidconnection.mentor.dto.MentorMyPageUpdateRequest;
import com.example.solidconnection.mentor.repository.MentorRepository;
import com.example.solidconnection.siteuser.domain.SiteUser;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

import static com.example.solidconnection.common.exception.ErrorCode.CHANNEL_REGISTRATION_LIMIT_EXCEEDED;
import static com.example.solidconnection.common.exception.ErrorCode.MENTOR_NOT_FOUND;

@RequiredArgsConstructor
@Service
public class MentorMyPageService {

private static final int CHANNEL_REGISTRATION_LIMIT = 4;
private static final int CHANNEL_SEQUENCE_START_NUMBER = 1;

private final MentorRepository mentorRepository;

@Transactional(readOnly = true)
public MentorMyPageResponse getMentorMyPage(SiteUser siteUser) {
Mentor mentor = mentorRepository.findBySiteUserId(siteUser.getId())
.orElseThrow(() -> new CustomException(MENTOR_NOT_FOUND));
return MentorMyPageResponse.of(mentor, siteUser);
}

@Transactional
public void updateMentorMyPage(SiteUser siteUser, MentorMyPageUpdateRequest request) {
validateChannelRegistrationLimit(request.channels());
Mentor mentor = mentorRepository.findBySiteUserId(siteUser.getId())
.orElseThrow(() -> new CustomException(MENTOR_NOT_FOUND));

mentor.updateIntroduction(request.introduction());
mentor.updatePassTip(request.passTip());
updateChannel(request.channels(), mentor);
}

private void validateChannelRegistrationLimit(List<ChannelRequest> channelRequests) {
if (channelRequests.size() > CHANNEL_REGISTRATION_LIMIT) {
throw new CustomException(CHANNEL_REGISTRATION_LIMIT_EXCEEDED);
}
}

private void updateChannel(List<ChannelRequest> channelRequests, Mentor mentor) {
int sequence = CHANNEL_SEQUENCE_START_NUMBER;
List<Channel> newChannels = new ArrayList<>();
for (ChannelRequest request : channelRequests) {
newChannels.add(new Channel(sequence++, request.type(), request.url()));
}
mentor.updateChannels(newChannels);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.example.solidconnection.mentor.repository;

import com.example.solidconnection.mentor.domain.Channel;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface ChannelRepositoryForTest extends JpaRepository<Channel, Long> {

List<Channel> findAllByMentorId(long mentorId);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.example.solidconnection.mentor.repository;

import com.example.solidconnection.mentor.domain.Mentor;
import com.example.solidconnection.mentor.domain.Mentoring;
import com.example.solidconnection.mentor.fixture.MentorFixture;
import com.example.solidconnection.mentor.fixture.MentoringFixture;
import com.example.solidconnection.siteuser.domain.SiteUser;
Expand Down Expand Up @@ -29,10 +28,10 @@ class MentorBatchQueryRepositoryTest {
private MentorFixture mentorFixture;

@Autowired
private SiteUserFixture siteUserFixture;
private MentoringFixture mentoringFixture;

@Autowired
private MentoringFixture mentoringFixture;
private SiteUserFixture siteUserFixture;

private long universityId = 1L; // todo: 멘토 인증 기능 추가 변경 필요
private Mentor mentor1, mentor2;
Expand Down Expand Up @@ -65,7 +64,7 @@ void setUp() {
@Test
void 멘토_ID_와_현재_사용자의_지원_여부를_매핑한다() {
// given
Mentoring 대기중_멘토링 = mentoringFixture.대기중_멘토링(mentor1.getId(), currentUser.getId());
mentoringFixture.대기중_멘토링(mentor1.getId(), currentUser.getId());
List<Mentor> mentors = List.of(mentor1, mentor2);

// when
Expand Down
Loading
Loading