Skip to content

Commit fc72e10

Browse files
committed
hotfix: 운동 기록 수정 시 사진 개수 검증 로직 추가, dto id값 이름 명확하게 수정, 테이블 이름 수정
1 parent 9c20233 commit fc72e10

File tree

14 files changed

+99
-31
lines changed

14 files changed

+99
-31
lines changed

src/main/java/com/tnt/trainee/domain/PtGoalListConverter.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,11 @@ public String convertToDatabaseColumn(List<PtGoal> attribute) {
2323
return "[]";
2424
}
2525

26+
// enum name만 추출해서 저장
27+
List<String> names = attribute.stream().map(Enum::name).toList();
28+
2629
try {
27-
return objectMapper.writeValueAsString(attribute);
30+
return objectMapper.writeValueAsString(names);
2831
} catch (JsonProcessingException e) {
2932
throw new TnTException(FAILED_TO_CONVERT_JSON, e);
3033
}
@@ -37,8 +40,10 @@ public List<PtGoal> convertToEntityAttribute(String dbData) {
3740
}
3841

3942
try {
40-
return objectMapper.readValue(dbData,
41-
objectMapper.getTypeFactory().constructCollectionType(List.class, PtGoal.class));
43+
List<String> names = objectMapper.readValue(dbData,
44+
objectMapper.getTypeFactory().constructCollectionType(List.class, String.class));
45+
46+
return names.stream().map(PtGoal::valueOf).toList();
4247
} catch (JsonProcessingException e) {
4348
throw new TnTException(FAILED_TO_CONVERT_JSON, e);
4449
}

src/main/java/com/tnt/trainer/presentation/TrainerController.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.tnt.trainer.presentation;
22

33
import static org.springframework.http.HttpStatus.CREATED;
4-
import static org.springframework.http.HttpStatus.NO_CONTENT;
54
import static org.springframework.http.HttpStatus.OK;
65

76
import java.time.LocalDate;
@@ -124,15 +123,15 @@ public void cancelPtLesson(@AuthMember Long memberId,
124123

125124
@Operation(summary = "PT 수업 수정 API")
126125
@PutMapping("/lessons/{ptLessonId}/edit")
127-
@ResponseStatus(NO_CONTENT)
126+
@ResponseStatus(OK)
128127
public void updatePtLesson(@AuthMember Long memberId, @PathVariable("ptLessonId") Long ptLessonId,
129128
@RequestBody @Valid UpdatePtLessonRequest request) {
130129
ptService.updatePtLesson(memberId, ptLessonId, request);
131130
}
132131

133132
@Operation(summary = "PT 수업 삭제 API")
134133
@DeleteMapping("/lessons/{ptLessonId}/delete")
135-
@ResponseStatus(NO_CONTENT)
134+
@ResponseStatus(OK)
136135
public void deletePtLesson(@AuthMember Long memberId, @PathVariable("ptLessonId") Long ptLessonId) {
137136
ptService.deletePtLesson(memberId, ptLessonId);
138137
}

src/main/java/com/tnt/workout/dto/response/SearchWorkoutResponse.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public static SearchWorkoutResponse from(List<Workout> workouts, boolean hasNext
2828
@Schema(description = "운동 정보")
2929
public record WorkoutInfo(
3030
@Schema(description = "운동 ID", example = "1")
31-
Long id,
31+
Long workoutId,
3232

3333
@Schema(description = "운동 이름", example = "벤치프레스")
3434
String name,
@@ -45,6 +45,7 @@ public record WorkoutInfo(
4545
@Schema(description = "운동 타입", example = "ANAEROBIC")
4646
WorkoutType workoutType
4747
) {
48+
4849
public static WorkoutInfo from(Workout workout) {
4950
return new WorkoutInfo(
5051
workout.getId(),

src/main/java/com/tnt/workout/infrastructure/WorkoutJpaEntity.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.tnt.workout.domain.Workout;
88
import com.tnt.workout.domain.WorkoutType;
99

10+
import jakarta.persistence.CollectionTable;
1011
import jakarta.persistence.Column;
1112
import jakarta.persistence.ElementCollection;
1213
import jakarta.persistence.Entity;
@@ -16,6 +17,7 @@
1617
import jakarta.persistence.GeneratedValue;
1718
import jakarta.persistence.GenerationType;
1819
import jakarta.persistence.Id;
20+
import jakarta.persistence.JoinColumn;
1921
import jakarta.persistence.Table;
2022
import lombok.AccessLevel;
2123
import lombok.Builder;
@@ -40,11 +42,15 @@ public class WorkoutJpaEntity {
4042
private String imageUrl;
4143

4244
@ElementCollection(fetch = FetchType.LAZY)
45+
@CollectionTable(name = "workout_body_parts", joinColumns = @JoinColumn(name = "workout_id"))
4346
@Enumerated(EnumType.STRING)
47+
@Column(name = "body_part")
4448
private List<BodyPart> bodyParts;
4549

4650
@ElementCollection(fetch = FetchType.LAZY)
51+
@CollectionTable(name = "workout_machines", joinColumns = @JoinColumn(name = "workout_id"))
4752
@Enumerated(EnumType.STRING)
53+
@Column(name = "machine")
4854
private List<Machine> machines;
4955

5056
@Enumerated(EnumType.STRING)

src/main/java/com/tnt/workoutrecord/application/WorkoutRecordService.java

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,26 @@ public void createWorkoutRecord(Long memberId, CreateWorkoutRecordRequest reques
6969
}
7070
}
7171

72+
@Transactional(readOnly = true)
73+
public void validateImageCount(Long workoutRecordId, int toDeleteCount, int newImageCount) {
74+
WorkoutRecord workoutRecord = workoutRecordRepository.findById(workoutRecordId);
75+
76+
int existingImageCount = 0;
77+
78+
if (workoutRecord.getWorkoutNote() != null && workoutRecord.getWorkoutNote().getImageUrl() != null) {
79+
existingImageCount = workoutRecord.getWorkoutNote().getImageUrl().size();
80+
}
81+
82+
int finalImageCount = existingImageCount - toDeleteCount + newImageCount;
83+
84+
if (finalImageCount > 6) {
85+
throw new IllegalArgumentException(
86+
String.format("이미지는 최대 6장까지 등록 가능합니다. (현재: %d장, 삭제: %d장, 추가: %d장 = 최종: %d장)",
87+
existingImageCount, toDeleteCount, newImageCount, finalImageCount)
88+
);
89+
}
90+
}
91+
7292
@Transactional(readOnly = true)
7393
public GetWorkoutRecordResponse getWorkoutRecord(Long workoutRecordId) {
7494
WorkoutRecord workoutRecord = workoutRecordRepository.findById(workoutRecordId);
@@ -85,22 +105,24 @@ public GetWorkoutRecordResponse getWorkoutRecord(Long workoutRecordId) {
85105

86106
List<GetWorkoutRecordResponse.SetResponse> setResponses = routineSets.stream()
87107
.map(set -> new GetWorkoutRecordResponse.SetResponse(
88-
set.getId(),
108+
set.getId(), // setId
89109
set.getDurationMinutes(),
90110
set.getRepetition(),
91111
set.getWeight()
92112
))
93113
.toList();
94114

95-
return new GetWorkoutRecordResponse.RoutineResponse(routine.getId(), routine.getWorkoutId(),
115+
return new GetWorkoutRecordResponse.RoutineResponse(
116+
routine.getId(), // routineId
117+
routine.getWorkoutId(),
96118
setResponses);
97119
})
98120
.toList();
99121

100122
WorkoutNote workoutNote = workoutRecord.getWorkoutNote();
101123

102124
return new GetWorkoutRecordResponse(
103-
workoutRecord.getId(),
125+
workoutRecord.getId(), // workoutRecordId
104126
workoutRecord.getMemberId(),
105127
workoutRecord.getPtLessonId(),
106128
workoutRecord.getDate(),
@@ -133,10 +155,6 @@ public void updateWorkoutRecord(Long memberId, Long workoutRecordId, UpdateWorko
133155
existingImageUrls.addAll(newImageUrls);
134156
}
135157

136-
if (existingImageUrls.size() > 6) {
137-
throw new IllegalArgumentException("이미지는 최대 6장까지 등록 가능합니다.");
138-
}
139-
140158
WorkoutNote updatedWorkoutNote = WorkoutNote.builder()
141159
.feedback(request.feedback())
142160
.imageUrls(existingImageUrls)

src/main/java/com/tnt/workoutrecord/dto/request/CreateWorkoutRecordRequest.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77

88
import io.swagger.v3.oas.annotations.media.Schema;
99
import jakarta.validation.Valid;
10-
import jakarta.validation.constraints.NotEmpty;
1110
import jakarta.validation.constraints.NotNull;
11+
import jakarta.validation.constraints.Size;
1212

1313
@Schema(description = "운동 기록 등록 요청")
1414
public record CreateWorkoutRecordRequest(
@@ -24,8 +24,9 @@ public record CreateWorkoutRecordRequest(
2424
RecordType recordType,
2525

2626
@Schema(description = "운동 루틴 목록", nullable = false)
27-
@NotEmpty
2827
@Valid
28+
@Size(min = 1, message = "최소 1개 이상의 루틴이 필요합니다.")
29+
@NotNull(message = "루틴 정보는 필수입니다.")
2930
List<RoutineInfo> routines,
3031

3132
@Schema(description = "피드백 내용", example = "오늘 운동 강도가 적절했습니다.", nullable = true)
@@ -39,8 +40,9 @@ public record RoutineInfo(
3940
Long workoutId,
4041

4142
@Schema(description = "세트 목록", nullable = false)
42-
@NotEmpty
4343
@Valid
44+
@Size(min = 1, message = "최소 1개 이상의 세트가 필요합니다.")
45+
@NotNull(message = "세트 정보는 필수입니다.")
4446
List<SetInfo> sets
4547
) {
4648

src/main/java/com/tnt/workoutrecord/dto/response/GetWorkoutRecordResponse.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
@Schema(description = "운동 기록 조회 응답")
1111
public record GetWorkoutRecordResponse(
1212
@Schema(description = "운동 기록 ID", example = "1")
13-
Long id,
13+
Long workoutRecordId,
1414

1515
@Schema(description = "회원 ID", example = "1")
1616
Long memberId,
@@ -36,7 +36,7 @@ public record GetWorkoutRecordResponse(
3636
@Schema(description = "루틴 정보")
3737
public record RoutineResponse(
3838
@Schema(description = "루틴 ID", example = "1")
39-
Long id,
39+
Long routineId,
4040

4141
@Schema(description = "운동 ID", example = "10")
4242
Long workoutId,
@@ -49,7 +49,7 @@ public record RoutineResponse(
4949
@Schema(description = "세트 정보")
5050
public record SetResponse(
5151
@Schema(description = "세트 ID", example = "1")
52-
Long id,
52+
Long setId,
5353

5454
@Schema(description = "지속 시간 (분, 유산소 운동용)", example = "30", nullable = true)
5555
Integer durationMinutes,

src/main/java/com/tnt/workoutrecord/infrastructure/RoutineJpaEntity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
@Entity
1717
@Getter
18-
@Table(name = "routine")
18+
@Table(name = "workout_record_routine")
1919
@NoArgsConstructor(access = AccessLevel.PROTECTED)
2020
public class RoutineJpaEntity {
2121

src/main/java/com/tnt/workoutrecord/infrastructure/SetJpaEntity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
@Entity
1717
@Getter
18-
@Table(name = "workout_set")
18+
@Table(name = "workout_record_set")
1919
@NoArgsConstructor(access = AccessLevel.PROTECTED)
2020
public class SetJpaEntity {
2121

src/main/java/com/tnt/workoutrecord/presentation/WorkoutRecordController.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.tnt.workoutrecord.presentation;
22

33
import static org.springframework.http.HttpStatus.CREATED;
4-
import static org.springframework.http.HttpStatus.NO_CONTENT;
54
import static org.springframework.http.HttpStatus.OK;
65
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
76

@@ -68,7 +67,7 @@ public GetWorkoutRecordResponse getWorkoutRecord(@PathVariable Long recordId) {
6867
@Operation(summary = "운동 기록 수정 API",
6968
description = "운동 기록을 수정합니다. 새 이미지 추가와 기존 이미지 삭제를 동시에 처리하며, 루틴 정보는 전체 교체됩니다.")
7069
@PutMapping(value = "/{recordId}", consumes = MULTIPART_FORM_DATA_VALUE)
71-
@ResponseStatus(NO_CONTENT)
70+
@ResponseStatus(OK)
7271
public void updateWorkoutRecord(@AuthMember Long memberId,
7372
@PathVariable Long recordId,
7473

@@ -78,6 +77,12 @@ public void updateWorkoutRecord(@AuthMember Long memberId,
7877
@Parameter(description = "추가할 운동 사진 (기존 사진과 합쳐 최대 6장)", schema = @Schema(type = "array", format = "binary"))
7978
@RequestPart(value = "newImages", required = false) List<MultipartFile> newImages
8079
) {
80+
// 이미지 개수 검증
81+
int toDeleteCount = request.imageUrlsToDelete() != null ? request.imageUrlsToDelete().size() : 0;
82+
int newImageCount = newImages != null ? newImages.size() : 0;
83+
84+
workoutRecordService.validateImageCount(recordId, toDeleteCount, newImageCount);
85+
8186
// 새 이미지 업로드
8287
List<String> newImageUrls = s3Service.uploadWorkoutRecordImages(newImages);
8388

@@ -92,7 +97,7 @@ public void updateWorkoutRecord(@AuthMember Long memberId,
9297

9398
@Operation(summary = "운동 기록 삭제 API", description = "운동 기록과 관련된 루틴, 세트를 모두 삭제합니다.")
9499
@DeleteMapping("/{recordId}")
95-
@ResponseStatus(NO_CONTENT)
100+
@ResponseStatus(OK)
96101
public void deleteWorkoutRecord(@PathVariable Long recordId) {
97102
// 이미지 URL 조회 후 S3에서 삭제
98103
GetWorkoutRecordResponse workoutRecord = workoutRecordService.getWorkoutRecord(recordId);

0 commit comments

Comments
 (0)