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
Expand Up @@ -24,12 +24,12 @@ public Mentor findMentorByMember(Member member) {
}

public Mentor findMentorByMemberId(Long memberId) {
return mentorRepository.findByMemberId(memberId)
return mentorRepository.findByMemberIdWithMember(memberId)
.orElseThrow(() -> new ServiceException(MemberErrorCode.NOT_FOUND_MENTOR));
}

public Mentee findMenteeByMember(Member member) {
return menteeRepository.findByMemberId(member.getId())
return menteeRepository.findByMemberIdWithMember(member.getId())
.orElseThrow(() -> new ServiceException(MemberErrorCode.NOT_FOUND_MENTEE));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
public record MenteeDto(
@Schema(description = "멘티 ID")
Long menteeId,
@Schema(description = "멘티명")
String name
@Schema(description = "멘티 닉네임")
String nickname
) {
public static MenteeDto from(Mentee mentee) {
return new MenteeDto(
mentee.getId(),
mentee.getMember().getName()
mentee.getMember().getNickname()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ public interface MenteeRepository extends JpaRepository<Mentee, Long> {
@Query("SELECT m FROM Mentee m WHERE m.member.id = :memberId AND m.isDeleted = false")
Optional<Mentee> findByMemberId(@Param("memberId") Long memberId);

@Query("SELECT m FROM Mentee m JOIN FETCH m.member WHERE m.member.id = :memberId AND m.isDeleted = false")
Optional<Mentee> findByMemberIdWithMember(@Param("memberId") Long memberId);

@Query("SELECT m FROM Mentee m WHERE m.id = :id AND m.isDeleted = false")
Optional<Mentee> findById(@Param("id") Long id);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
public record MentorDetailDto(
@Schema(description = "멘토 ID")
Long mentorId,
@Schema(description = "멘토명")
String name,
@Schema(description = "멘토 닉네임")
String nickname,
@Schema(description = "평점")
Double rate,
// TODO: Job id, name
Expand All @@ -17,7 +17,7 @@ public record MentorDetailDto(
public static MentorDetailDto from(Mentor mentor) {
return new MentorDetailDto(
mentor.getId(),
mentor.getMember().getName(),
mentor.getMember().getNickname(),
mentor.getRate(),
mentor.getCareerYears()
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
public record MentorDto(
@Schema(description = "멘토 ID")
Long mentorId,
@Schema(description = "멘토명")
String name
@Schema(description = "멘토 닉네임")
String nickname
) {
public static MentorDto from(Mentor mentor) {
return new MentorDto(
mentor.getId(),
mentor.getMember().getName()
mentor.getMember().getNickname()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ public interface MentorRepository extends JpaRepository<Mentor, Long> {
@Query("SELECT m FROM Mentor m WHERE m.member.id = :memberId AND m.isDeleted = false")
Optional<Mentor> findByMemberId(@Param("memberId") Long memberId);

@Query("SELECT m FROM Mentor m JOIN FETCH m.member WHERE m.member.id = :memberId AND m.isDeleted = false")
Optional<Mentor> findByMemberIdWithMember(@Param("memberId") Long memberId);

@Query("SELECT m FROM Mentor m WHERE m.id = :id AND m.isDeleted = false")
Optional<Mentor> findById(@Param("id") Long id);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ public Page<Mentoring> searchMentorings(String keyword, Pageable pageable) {

BooleanBuilder builder = new BooleanBuilder();

// 제목, 멘토 이름 검색 조건
// 제목, 멘토 닉네임 검색 조건
if (keyword != null && !keyword.isBlank()) {
builder.and(
mentoring.title.containsIgnoreCase(keyword)
.or(mentor.member.name.containsIgnoreCase(keyword))
.or(mentor.member.nickname.containsIgnoreCase(keyword))
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.back.domain.mentoring.slot.dto;

import com.back.domain.mentoring.slot.constant.MentorSlotStatus;
import com.back.domain.mentoring.slot.entity.MentorSlot;
import io.swagger.v3.oas.annotations.media.Schema;

import java.time.LocalDateTime;

public record MentorSlotDetailDto(
@Schema(description = "멘토 슬롯 ID")
Long mentorSlotId,
@Schema(description = "시작 일시")
LocalDateTime startDateTime,
@Schema(description = "종료 일시")
LocalDateTime endDateTime,
@Schema(description = "멘토 슬롯 상태")
MentorSlotStatus mentorSlotStatus,
@Schema(description = "생성일")
LocalDateTime createDate,
@Schema(description = "수정일")
LocalDateTime modifyDate
) {
public static MentorSlotDetailDto from(MentorSlot mentorSlot) {
return new MentorSlotDetailDto(
mentorSlot.getId(),
mentorSlot.getStartDateTime(),
mentorSlot.getEndDateTime(),
mentorSlot.getStatus(),
mentorSlot.getCreateDate(),
mentorSlot.getModifyDate()
);
}
}
Original file line number Diff line number Diff line change
@@ -1,51 +1,21 @@
package com.back.domain.mentoring.slot.dto.response;

import com.back.domain.member.mentor.dto.MentorDto;
import com.back.domain.mentoring.mentoring.dto.MentoringDto;
import com.back.domain.mentoring.mentoring.entity.Mentoring;
import com.back.domain.mentoring.slot.constant.MentorSlotStatus;
import com.back.domain.mentoring.slot.dto.MentorSlotDetailDto;
import com.back.domain.mentoring.slot.entity.MentorSlot;
import io.swagger.v3.oas.annotations.media.Schema;

import java.time.LocalDateTime;

public record MentorSlotResponse(
@Schema(description = "멘토 슬롯 ID")
Long mentorSlotId,

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

@Schema(description = "멘토링 ID")
Long mentoringId,

@Schema(description = "멘토링 제목")
String mentoringTitle,

@Schema(description = "시작 일시")
LocalDateTime startDateTime,

@Schema(description = "종료 일시")
LocalDateTime endDateTime,

@Schema(description = "멘토 슬롯 상태")
MentorSlotStatus mentorSlotStatus,

@Schema(description = "생성일")
LocalDateTime createDate,

@Schema(description = "수정일")
LocalDateTime modifyDate
MentorSlotDetailDto mentorSlot,
MentorDto mentor,
MentoringDto mentoring
) {
public static MentorSlotResponse from(MentorSlot mentorSlot, Mentoring mentoring) {
return new MentorSlotResponse(
mentorSlot.getId(),
mentorSlot.getMentor().getId(),
mentoring.getId(),
mentoring.getTitle(),
mentorSlot.getStartDateTime(),
mentorSlot.getEndDateTime(),
mentorSlot.getStatus(),
mentorSlot.getCreateDate(),
mentorSlot.getModifyDate()
MentorSlotDetailDto.from(mentorSlot),
MentorDto.from(mentorSlot.getMentor()),
MentoringDto.from(mentoring)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import com.back.global.exception.ServiceException;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

public class DateTimeValidator {

Expand Down Expand Up @@ -50,4 +52,16 @@ public static void validateTimeSlot(LocalDateTime start, LocalDateTime end) {
validateStartTimeNotInPast(start);
validateMinimumDuration(start, end);
}

public static void validateRepetitionSlot(LocalDate startDate, LocalTime startTime,
LocalDate endDate, LocalTime endTime) {
if (endDate.isBefore(startDate)) {
throw new ServiceException(MentorSlotErrorCode.END_TIME_BEFORE_START);
}

LocalDateTime startDateTime = LocalDateTime.of(startDate, startTime);
LocalDateTime endDateTime = LocalDateTime.of(startDate, endTime);

validateTimeSlot(startDateTime, endDateTime);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ public MentorSlotResponse createMentorSlot(MentorSlotRequest reqDto, Mentor ment
public void createMentorSlotRepetition(MentorSlotRepetitionRequest reqDto, Mentor mentor) {
List<MentorSlot> mentorSlots = new ArrayList<>();

DateTimeValidator.validateRepetitionSlot(reqDto.repeatStartDate(), reqDto.startTime(),
reqDto.repeatEndDate(), reqDto.endTime());

// 지정한 요일별로 슬롯 목록 생성
for(DayOfWeek targetDayOfWeek : reqDto.daysOfWeek()) {
mentorSlots.addAll(generateSlotsForDayOfWeek(reqDto, targetDayOfWeek, mentor));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,52 @@
package com.back.global.converter;

import com.back.standard.util.Ut;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import org.springframework.stereotype.Component;

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

@Converter
@Component
public class StringListConverter implements AttributeConverter<List<String>, String> {

private static final ObjectMapper objectMapper = new ObjectMapper();

@Override
public String convertToDatabaseColumn(List<String> attribute) {
return attribute == null ? null : Ut.json.toString(attribute);
if (attribute == null || attribute.isEmpty()) {
return null;
}
try {
return objectMapper.writeValueAsString(attribute);
} catch (JsonProcessingException e) {
throw new IllegalArgumentException("JSON 변환 실패", e);
}
}

@Override
public List<String> convertToEntityAttribute(String dbData) {
return Ut.json.toList(dbData, String.class);
if (dbData == null || dbData.trim().isEmpty()) {
return new ArrayList<>();
}
try {
// 이중 인코딩된 경우 처리
String data = dbData;
if (data.startsWith("\"") && data.endsWith("\"")) {
data = objectMapper.readValue(data, String.class);
}

return objectMapper.readValue(
data,
objectMapper.getTypeFactory().constructCollectionType(List.class, String.class)
);
} catch (JsonProcessingException e) {
System.err.println("JSON 파싱 실패. 원본 데이터: " + dbData);
e.printStackTrace();
return new ArrayList<>();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -33,6 +34,7 @@
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@ActiveProfiles("test")
@SpringBootTest
@AutoConfigureMockMvc
@Transactional
Expand Down Expand Up @@ -75,14 +77,15 @@ void setUp() {
void getMentoringsSuccess() throws Exception {
mentoringFixture.createMentorings(mentor, 15);

// TODO: 일반 조회, 목록 조회는 쿠키 없어도 가능하게 설정 필요
performGetMentorings(null, "0")
.andExpect(jsonPath("$.data.mentorings").isArray())
.andExpect(jsonPath("$.data.mentorings.length()").value(10))
.andExpect(jsonPath("$.data.currentPage").value(0))
.andExpect(jsonPath("$.data.totalPage").value(2))
.andExpect(jsonPath("$.data.totalElements").value(15))
.andExpect(jsonPath("$.data.hasNext").value(true));
.andExpect(jsonPath("$.data.hasNext").value(true))
.andExpect(jsonPath("$.data.mentorings[0].tags[0]").value("Spring"))
.andExpect(jsonPath("$.data.mentorings[0].tags[1]").value("Java"));
}

@Test
Expand Down Expand Up @@ -118,7 +121,7 @@ void getMentoringsSuccessSearchMentor() throws Exception {
mentoringFixture.createMentorings(mentor, 8);
mentoringFixture.createMentorings(mentor2, 3);

performGetMentorings(mentorMember.getName(), "0")
performGetMentorings(mentorMember.getNickname(), "0")
.andExpect(jsonPath("$.data.mentorings").isArray())
.andExpect(jsonPath("$.data.mentorings.length()").value(3))
.andExpect(jsonPath("$.data.currentPage").value(0))
Expand Down Expand Up @@ -162,7 +165,9 @@ void getMentoringSuccess() throws Exception {
.andExpect(handler().methodName("getMentoring"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.resultCode").value("200"))
.andExpect(jsonPath("$.msg").value("멘토링을 조회하였습니다."));
.andExpect(jsonPath("$.msg").value("멘토링을 조회하였습니다."))
.andExpect(jsonPath("$.data.mentoring.tags[0]").value("Spring"))
.andExpect(jsonPath("$.data.mentoring.tags[1]").value("Java"));
}


Expand Down Expand Up @@ -193,7 +198,7 @@ void createMentoringSuccess() throws Exception {

// Mentor 정보 검증
.andExpect(jsonPath("$.data.mentor.mentorId").value(mentorOfMentoring.getId()))
.andExpect(jsonPath("$.data.mentor.name").value(mentorOfMentoring.getMember().getName()))
.andExpect(jsonPath("$.data.mentor.nickname").value(mentorOfMentoring.getMember().getNickname()))
.andExpect(jsonPath("$.data.mentor.rate").value(mentorOfMentoring.getRate()))
.andExpect(jsonPath("$.data.mentor.careerYears").value(mentorOfMentoring.getCareerYears()));
}
Expand Down
Loading