Skip to content

Commit 96741cc

Browse files
authored
[TNT-194] feat: 트레이너 홈 - 날짜별 스케쥴 리스트 불러오기 API 구현 (#36)
1 parent d5fc40a commit 96741cc

40 files changed

+668
-213
lines changed

src/main/java/com/tnt/application/member/MemberService.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import com.tnt.dto.member.response.SignUpResponse;
2828
import com.tnt.gateway.service.SessionService;
2929
import com.tnt.infrastructure.mysql.repository.member.MemberRepository;
30-
import com.tnt.infrastructure.mysql.repository.trainee.PtGoalRepository;
30+
import com.tnt.infrastructure.mysql.repository.pt.PtGoalRepository;
3131
import com.tnt.infrastructure.mysql.repository.trainee.TraineeRepository;
3232
import com.tnt.infrastructure.mysql.repository.trainer.TrainerRepository;
3333

src/main/java/com/tnt/application/pt/PtService.java

+38-50
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
import static com.tnt.common.error.model.ErrorMessage.PT_TRAINEE_ALREADY_EXIST;
44
import static com.tnt.common.error.model.ErrorMessage.PT_TRAINER_TRAINEE_ALREADY_EXIST;
5-
import static java.util.Objects.isNull;
65

76
import java.time.LocalDate;
87
import java.util.List;
8+
import java.util.stream.Collectors;
99

1010
import org.springframework.stereotype.Service;
1111
import org.springframework.transaction.annotation.Transactional;
@@ -16,15 +16,19 @@
1616
import com.tnt.common.error.exception.NotFoundException;
1717
import com.tnt.common.error.model.ErrorMessage;
1818
import com.tnt.domain.member.Member;
19+
import com.tnt.domain.pt.PtLesson;
1920
import com.tnt.domain.pt.PtTrainerTrainee;
2021
import com.tnt.domain.trainee.PtGoal;
2122
import com.tnt.domain.trainee.Trainee;
2223
import com.tnt.domain.trainer.Trainer;
2324
import com.tnt.dto.trainer.ConnectWithTrainerDto;
2425
import com.tnt.dto.trainer.request.ConnectWithTrainerRequest;
2526
import com.tnt.dto.trainer.response.ConnectWithTraineeResponse;
27+
import com.tnt.dto.trainer.response.GetPtLessonsOnDateResponse;
28+
import com.tnt.dto.trainer.response.GetPtLessonsOnDateResponse.Lesson;
29+
import com.tnt.infrastructure.mysql.repository.pt.PtGoalRepository;
30+
import com.tnt.infrastructure.mysql.repository.pt.PtLessonSearchRepository;
2631
import com.tnt.infrastructure.mysql.repository.pt.PtTrainerTraineeRepository;
27-
import com.tnt.infrastructure.mysql.repository.trainee.PtGoalRepository;
2832

2933
import lombok.RequiredArgsConstructor;
3034

@@ -37,17 +41,18 @@ public class PtService {
3741
private final TrainerService trainerService;
3842
private final PtTrainerTraineeRepository ptTrainerTraineeRepository;
3943
private final PtGoalRepository ptGoalRepository;
44+
private final PtLessonSearchRepository ptLessonSearchRepository;
4045

4146
@Transactional
42-
public ConnectWithTrainerDto connectWithTrainer(String memberId, ConnectWithTrainerRequest request) {
47+
public ConnectWithTrainerDto connectWithTrainer(Long memberId, ConnectWithTrainerRequest request) {
4348
Trainer trainer = trainerService.getTrainerWithInvitationCode(request.invitationCode());
4449
Trainee trainee = traineeService.getTraineeWithMemberId(memberId);
4550

4651
validateNotAlreadyConnected(trainer.getId(), trainee.getId());
4752

4853
PtTrainerTrainee ptTrainerTrainee = PtTrainerTrainee.builder()
49-
.trainerId(trainer.getId())
50-
.traineeId(trainee.getId())
54+
.trainer(trainer)
55+
.trainee(trainee)
5156
.startedAt(request.startDate())
5257
.finishedPtCount(request.finishedPtCount())
5358
.totalPtCount(request.totalPtCount())
@@ -62,8 +67,8 @@ public ConnectWithTrainerDto connectWithTrainer(String memberId, ConnectWithTrai
6267
trainerMember.getProfileImageUrl(), traineeMember.getProfileImageUrl(), trainer.getId(), trainee.getId());
6368
}
6469

65-
public ConnectWithTraineeResponse getFirstTrainerTraineeConnect(String memberId, String trainerId,
66-
String traineeId) {
70+
public ConnectWithTraineeResponse getFirstTrainerTraineeConnect(Long memberId, Long trainerId,
71+
Long traineeId) {
6772
validateIfNotConnected(trainerId, traineeId);
6873

6974
Trainer trainer = trainerService.getTrainerWithMemberId(memberId);
@@ -72,61 +77,44 @@ public ConnectWithTraineeResponse getFirstTrainerTraineeConnect(String memberId,
7277
Member trainerMember = trainer.getMember(); // fetch join 으로 가져온 member
7378
Member traineeMember = trainee.getMember(); // fetch join 으로 가져온 member
7479

75-
String traineeAge = calculateCurrentAge(traineeMember.getBirthday());
76-
77-
List<PtGoal> ptGoals = ptGoalRepository.findAllByTraineeId(Long.valueOf(traineeId));
78-
String ptGoal = getPtGoals(ptGoals);
80+
List<PtGoal> ptGoals = ptGoalRepository.findAllByTraineeId(traineeId);
81+
String ptGoal = ptGoals.stream().map(PtGoal::getContent).collect(Collectors.joining(", "));
7982

8083
return new ConnectWithTraineeResponse(trainerMember.getName(), traineeMember.getName(),
81-
trainerMember.getProfileImageUrl(), traineeMember.getProfileImageUrl(), traineeAge, trainee.getHeight(),
82-
trainee.getWeight(), ptGoal, trainee.getCautionNote());
84+
trainerMember.getProfileImageUrl(), traineeMember.getProfileImageUrl(), traineeMember.getAge(),
85+
trainee.getHeight(), trainee.getWeight(), ptGoal, trainee.getCautionNote());
8386
}
8487

85-
private void validateNotAlreadyConnected(Long trainerId, Long traineeId) {
86-
ptTrainerTraineeRepository.findByTraineeIdAndDeletedAtIsNull(traineeId)
87-
.ifPresent(pt -> { // 이미 다른 트레이너와 연결 중인지 확인
88-
throw new ConflictException(PT_TRAINEE_ALREADY_EXIST);
89-
});
90-
91-
ptTrainerTraineeRepository.findByTrainerIdAndTraineeIdAndDeletedAtIsNull(trainerId, traineeId)
92-
.ifPresent(pt -> { // 이미 해당 트레이너와 연결 중인지 확인
93-
throw new ConflictException(PT_TRAINER_TRAINEE_ALREADY_EXIST);
94-
});
95-
}
88+
public GetPtLessonsOnDateResponse getPtLessonsOnDate(Long memberId, LocalDate date) {
89+
Trainer trainer = trainerService.getTrainerWithMemberId(memberId);
9690

97-
private void validateIfNotConnected(String trainerId, String traineeId) {
98-
ptTrainerTraineeRepository.findByTrainerIdAndTraineeIdAndDeletedAtIsNull(Long.valueOf(trainerId),
99-
Long.valueOf(traineeId))
100-
.orElseThrow(() -> new NotFoundException(ErrorMessage.PT_TRAINER_TRAINEE_NOT_FOUND));
101-
}
91+
List<PtLesson> ptLessons = ptLessonSearchRepository.findAllByTrainerIdAndDate(trainer.getId(), date);
10292

103-
private String calculateCurrentAge(LocalDate birthDay) {
104-
if (isNull(birthDay)) {
105-
return "비공개";
106-
}
93+
List<Lesson> lessons = ptLessons.stream().map(ptLesson -> {
94+
PtTrainerTrainee ptTrainerTrainee = ptLesson.getPtTrainerTrainee();
95+
Trainee trainee = ptTrainerTrainee.getTrainee();
10796

108-
LocalDate currentDate = LocalDate.now();
109-
int age = currentDate.getYear() - birthDay.getYear();
97+
return new Lesson(String.valueOf(ptLesson.getId()),
98+
String.valueOf(trainee.getId()), trainee.getMember().getName(), ptTrainerTrainee.getCurrentSession(),
99+
ptLesson.getLessonStart(), ptLesson.getLessonEnd(), ptLesson.getIsCompleted());
100+
}).toList();
110101

111-
// 생일이 아직 지나지 않았으면 나이를 1 줄임
112-
if (currentDate.isBefore(birthDay.withYear(currentDate.getYear()))) {
113-
age--;
114-
}
115-
116-
return String.valueOf(age);
102+
return new GetPtLessonsOnDateResponse(ptLessons.size(), date, lessons);
117103
}
118104

119-
private String getPtGoals(List<PtGoal> ptGoals) {
120-
StringBuilder sb = new StringBuilder();
121-
122-
for (int i = 0; i < ptGoals.size(); i++) {
123-
sb.append(ptGoals.get(i).getContent());
105+
private void validateNotAlreadyConnected(Long trainerId, Long traineeId) {
106+
if (ptTrainerTraineeRepository.existsByTraineeIdAndDeletedAtIsNull(traineeId)) {
107+
throw new ConflictException(PT_TRAINEE_ALREADY_EXIST);
108+
}
124109

125-
if (i != ptGoals.size() - 1) {
126-
sb.append(", ");
127-
}
110+
if (ptTrainerTraineeRepository.existsByTrainerIdAndTraineeIdAndDeletedAtIsNull(trainerId, traineeId)) {
111+
throw new ConflictException(PT_TRAINER_TRAINEE_ALREADY_EXIST);
128112
}
113+
}
129114

130-
return sb.toString();
115+
private void validateIfNotConnected(Long trainerId, Long traineeId) {
116+
if (!ptTrainerTraineeRepository.existsByTrainerIdAndTraineeIdAndDeletedAtIsNull(trainerId, traineeId)) {
117+
throw new NotFoundException(ErrorMessage.PT_TRAINER_TRAINEE_NOT_FOUND);
118+
}
131119
}
132120
}

src/main/java/com/tnt/application/trainee/TraineeService.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ public class TraineeService {
1818

1919
private final TraineeSearchRepository traineeSearchRepository;
2020

21-
public Trainee getTraineeWithMemberId(String memberId) {
22-
return traineeSearchRepository.findByMemberIdAndDeletedAtIsNull(Long.valueOf(memberId))
21+
public Trainee getTraineeWithMemberId(Long memberId) {
22+
return traineeSearchRepository.findByMemberId(memberId)
2323
.orElseThrow(() -> new NotFoundException(TRAINEE_NOT_FOUND));
2424
}
2525

26-
public Trainee getTraineeWithId(String traineeId) {
27-
return traineeSearchRepository.findByIdAndDeletedAtIsNull(Long.valueOf(traineeId))
26+
public Trainee getTraineeWithId(Long traineeId) {
27+
return traineeSearchRepository.findById(traineeId)
2828
.orElseThrow(() -> new NotFoundException(TRAINEE_NOT_FOUND));
2929
}
3030
}

src/main/java/com/tnt/application/trainer/TrainerService.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public class TrainerService {
2222
private final TrainerRepository trainerRepository;
2323
private final TrainerSearchRepository trainerSearchRepository;
2424

25-
public InvitationCodeResponse getInvitationCode(String memberId) {
25+
public InvitationCodeResponse getInvitationCode(Long memberId) {
2626
Trainer trainer = getTrainerWithMemberId(memberId);
2727

2828
return new InvitationCodeResponse(trainer.getInvitationCode());
@@ -35,20 +35,20 @@ public InvitationCodeVerifyResponse verifyInvitationCode(String invitationCode)
3535
}
3636

3737
@Transactional
38-
public InvitationCodeResponse reissueInvitationCode(String memberId) {
38+
public InvitationCodeResponse reissueInvitationCode(Long memberId) {
3939
Trainer trainer = getTrainerWithMemberId(memberId);
4040
trainer.setNewInvitationCode();
4141

4242
return new InvitationCodeResponse(trainer.getInvitationCode());
4343
}
4444

45-
public Trainer getTrainerWithMemberId(String memberId) {
46-
return trainerRepository.findByMemberIdAndDeletedAtIsNull(Long.valueOf(memberId))
45+
public Trainer getTrainerWithMemberId(Long memberId) {
46+
return trainerRepository.findByMemberIdAndDeletedAtIsNull(memberId)
4747
.orElseThrow(() -> new NotFoundException(TRAINER_NOT_FOUND));
4848
}
4949

5050
public Trainer getTrainerWithInvitationCode(String invitationCode) {
51-
return trainerSearchRepository.findByInvitationCodeAndDeletedAtIsNull(invitationCode)
51+
return trainerSearchRepository.findByInvitationCode(invitationCode)
5252
.orElseThrow(() -> new NotFoundException(TRAINER_NOT_FOUND));
5353
}
5454
}

src/main/java/com/tnt/common/error/model/ErrorMessage.java

+6-3
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,13 @@ public enum ErrorMessage {
5252
MEMBER_NULL_ADVERTISEMENT_AGREEMENT("회원 광고성 알림 수신 동의 여부가 null 입니다."),
5353
MEMBER_NULL_PUSH_AGREEMENT("회원 푸쉬 알림 수신 동의 여부가 null 입니다."),
5454

55-
TRAINER_NULL_ID("트레이너 id가 null 입니다."),
55+
TRAINER_NULL("트레이너가 null 입니다."),
5656
TRAINER_NULL_MEMBER("트레이너 member 가 null 입니다."),
5757
TRAINER_INVALID_INVITATION_CODE("초대 코드가 올바르지 않습니다."),
5858
TRAINER_NOT_FOUND("존재하지 않는 트레이너입니다."),
5959
TRAINER_INVITATION_CODE_GENERATE_FAILED("트레이너 초대 코드 생성에 실패했습니다."),
6060

61-
TRAINEE_NULL_ID("트레이니 id가 null 입니다."),
61+
TRAINEE_NULL("트레이니가 null 입니다."),
6262
TRAINEE_NULL_MEMBER("트레이니 member 가 null 입니다."),
6363
TRAINEE_NULL_HEIGHT("트레이니 height가 null 입니다."),
6464
TRAINEE_NULL_WEIGHT("트레이니 weight가 null 입니다."),
@@ -70,7 +70,10 @@ public enum ErrorMessage {
7070

7171
PT_TRAINER_TRAINEE_ALREADY_EXIST("이미 연결된 트레이너-트레이니입니다."),
7272
PT_TRAINEE_ALREADY_EXIST("이미 다른 트레이너와 연결되어 있습니다."),
73-
PT_TRAINER_TRAINEE_NOT_FOUND("존재하지 않는 연결 정보입니다.");
73+
PT_TRAINER_TRAINEE_NOT_FOUND("존재하지 않는 연결 정보입니다."),
74+
PT_TRAINER_TRAINEE_NULL("트레이너 - 트레이니 연결 정보가 null 입니다."),
75+
76+
PT_LESSON_INVALID_MEMO("수업 메모의 길이는 공백 포함 30자 이하이어야 합니다.");
7477

7578
private final String message;
7679
}

src/main/java/com/tnt/domain/member/Member.java

+18-2
Original file line numberDiff line numberDiff line change
@@ -107,17 +107,33 @@ public Member(Long id, String socialId, String fcmToken, String email, String na
107107
}
108108

109109
public void updateFcmTokenIfExpired(String fcmToken) {
110-
if (!this.fcmToken.equals(fcmToken)) {
110+
if (!isBlank(fcmToken) && !this.fcmToken.equals(fcmToken)) {
111111
this.fcmToken = fcmToken;
112112
}
113113
}
114114

115115
public void updateProfileImageUrl(String profileImageUrl) {
116-
if (!this.profileImageUrl.equals(profileImageUrl)) {
116+
if (!isBlank(profileImageUrl) && !this.profileImageUrl.equals(profileImageUrl)) {
117117
this.profileImageUrl = profileImageUrl;
118118
}
119119
}
120120

121+
public String getAge() {
122+
if (isNull(this.birthday)) {
123+
return "비공개";
124+
}
125+
126+
LocalDate currentDate = LocalDate.now();
127+
int age = currentDate.getYear() - this.birthday.getYear();
128+
129+
// 생일이 아직 지나지 않았으면 나이를 1 줄임
130+
if (currentDate.isBefore(this.birthday.withYear(currentDate.getYear()))) {
131+
age--;
132+
}
133+
134+
return String.valueOf(age);
135+
}
136+
121137
private String validateSocialId(String socialId) {
122138
if (isBlank(socialId) || socialId.length() > SOCIAL_ID_LENGTH) {
123139
throw new IllegalArgumentException(MEMBER_INVALID_SOCIAL_ID.getMessage());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package com.tnt.domain.pt;
2+
3+
import static com.tnt.common.error.model.ErrorMessage.PT_TRAINER_TRAINEE_NULL;
4+
import static jakarta.persistence.ConstraintMode.NO_CONSTRAINT;
5+
import static java.util.Objects.isNull;
6+
import static java.util.Objects.requireNonNull;
7+
8+
import java.time.LocalDateTime;
9+
10+
import org.springframework.lang.Nullable;
11+
12+
import com.tnt.infrastructure.mysql.BaseTimeEntity;
13+
14+
import io.hypersistence.utils.hibernate.id.Tsid;
15+
import jakarta.persistence.Column;
16+
import jakarta.persistence.Entity;
17+
import jakarta.persistence.FetchType;
18+
import jakarta.persistence.ForeignKey;
19+
import jakarta.persistence.Id;
20+
import jakarta.persistence.JoinColumn;
21+
import jakarta.persistence.ManyToOne;
22+
import jakarta.persistence.Table;
23+
import lombok.AccessLevel;
24+
import lombok.Builder;
25+
import lombok.Getter;
26+
import lombok.NoArgsConstructor;
27+
28+
@Entity
29+
@Getter
30+
@Table(name = "pt_lesson")
31+
@NoArgsConstructor(access = AccessLevel.PROTECTED)
32+
public class PtLesson extends BaseTimeEntity {
33+
34+
private static final int MEMO_LENGTH = 30;
35+
36+
@Id
37+
@Tsid
38+
@Column(name = "id", nullable = false, unique = true)
39+
private Long id;
40+
41+
@ManyToOne(fetch = FetchType.LAZY)
42+
@JoinColumn(name = "pt_trainer_trainee_id", nullable = false, foreignKey = @ForeignKey(NO_CONSTRAINT))
43+
private PtTrainerTrainee ptTrainerTrainee;
44+
45+
@Column(name = "lesson_start", nullable = false)
46+
private LocalDateTime lessonStart;
47+
48+
@Column(name = "lesson_end", nullable = false)
49+
private LocalDateTime lessonEnd;
50+
51+
@Column(name = "is_completed", nullable = false)
52+
private Boolean isCompleted;
53+
54+
@Column(name = "memo", nullable = true, length = MEMO_LENGTH)
55+
private String memo;
56+
57+
@Column(name = "deleted_at", nullable = true)
58+
private LocalDateTime deletedAt;
59+
60+
@Builder
61+
public PtLesson(Long id, PtTrainerTrainee ptTrainerTrainee, LocalDateTime lessonStart, LocalDateTime lessonEnd,
62+
@Nullable String memo) {
63+
this.id = id;
64+
this.ptTrainerTrainee = requireNonNull(ptTrainerTrainee, PT_TRAINER_TRAINEE_NULL.getMessage());
65+
this.lessonStart = requireNonNull(lessonStart);
66+
this.lessonEnd = requireNonNull(lessonEnd);
67+
this.isCompleted = false;
68+
validateAndSetMemo(memo);
69+
}
70+
71+
public void completeLesson() {
72+
this.isCompleted = true;
73+
}
74+
75+
private void validateAndSetMemo(String memo) {
76+
if (isNull(memo)) {
77+
return;
78+
}
79+
80+
if (memo.length() > MEMO_LENGTH) {
81+
throw new IllegalArgumentException("메모는 30자 이하여야 합니다.");
82+
}
83+
84+
this.memo = memo;
85+
}
86+
}

0 commit comments

Comments
 (0)