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
21 changes: 21 additions & 0 deletions src/main/java/jombi/freemates/controller/BookmarkController.java
Original file line number Diff line number Diff line change
Expand Up @@ -250,4 +250,25 @@ public ResponseEntity<Void> likeBookmark(
return ResponseEntity.ok().build(); // 혹은 204 No Content
}

@PostMapping(value ="/update/{bookmarkId}",
consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Void> updateBookmark(
@AuthenticationPrincipal CustomUserDetails customUserDetails,
@PathVariable("bookmarkId") UUID bookmarkId,
@RequestParam String title,
@RequestParam String description,
@RequestParam PinColor pinColor,
@RequestParam Visibility visibility,
@RequestParam(value = "image", required = false) MultipartFile image
) {
BookmarkRequest req = BookmarkRequest.builder()
.title(title)
.description(description)
.pinColor(pinColor)
.visibility(visibility)
.build();
bookmarkService.updateBookmark(customUserDetails, bookmarkId, req, image);
return ResponseEntity.ok().build();
}

}
26 changes: 26 additions & 0 deletions src/main/java/jombi/freemates/controller/CourseController.java
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,33 @@ public ResponseEntity<Void> likeCourse(
courseService.likeCourse(customUserDetails, courseId);
return ResponseEntity.ok().build();
}
/**
* 코스 수정
*/
@PostMapping(value ="/update/{courseId}",
consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Void> updateCourse(
@AuthenticationPrincipal CustomUserDetails user,
@PathVariable("courseId") UUID courseId,
@RequestParam("title") String title,
@RequestParam("description") String description,
@RequestParam("freeTime") Integer freeTime,
@RequestParam("visibility") Visibility visibility,
// placeIds를 여러 개 RquestParam으로 받을 수도 있고, 한 문자열(콤마 구분)로 받을 수도 있음
@RequestParam("placeIds") List<UUID> placeIds,
@RequestParam(value = "image", required = false) MultipartFile image
) {
CourseRequest req = CourseRequest.builder()
.title(title)
.description(description)
.freeTime(freeTime)
.visibility(visibility)
.placeIds(placeIds)
.build();

courseService.updateCourse(user, courseId, req, image);
return ResponseEntity.ok().build();
}



Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package jombi.freemates.repository;

import jombi.freemates.model.postgres.Course;
import jombi.freemates.model.postgres.CoursePlace;
import jombi.freemates.model.postgres.id.CoursePlaceId;
import org.springframework.data.jpa.repository.JpaRepository;

public interface CoursePlaceRepository extends JpaRepository<CoursePlace, CoursePlaceId> {

void deleteAllByCourse(Course course);

}
40 changes: 40 additions & 0 deletions src/main/java/jombi/freemates/service/BookmarkService.java
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,46 @@ public void addPlaceToBookmark(
bookmarkPlaceRepository.save(bp);

}
@Transactional
public void updateBookmark(
CustomUserDetails customUserDetails,
UUID bookmarkId,
BookmarkRequest req,
MultipartFile image
) {
// 파일이 있으면 저장 후 imageUrl 세팅, 없으면 imageUrl = null
String imageUrl = null;
if (image != null && !image.isEmpty()) {
imageUrl = storage.storeImage(image);
}
Comment on lines +198 to +202
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

이미지 처리 로직을 개선하세요

현재 구현에서는 새 이미지가 제공되지 않으면 imageUrlnull로 설정합니다. 이는 기존 이미지를 덮어쓰게 되어 사용자가 다른 필드만 업데이트하고 싶을 때 의도하지 않게 이미지를 삭제할 수 있습니다.

다음과 같이 수정하여 기존 이미지를 보존하세요:

-    // 파일이 있으면 저장 후 imageUrl 세팅, 없으면 imageUrl = null
-    String imageUrl = null;
-    if (image != null && !image.isEmpty()) {
-      imageUrl = storage.storeImage(image);
-    }
+    // 파일이 있으면 저장 후 imageUrl 세팅, 없으면 기존 imageUrl 유지
+    String imageUrl = bookmark.getImageUrl(); // 기존 이미지 URL 유지
+    if (image != null && !image.isEmpty()) {
+      imageUrl = storage.storeImage(image);
+    }

그리고 imageUrl 설정 부분도 수정:

-    bookmark.setImageUrl(imageUrl);   // 파일이 없으면 null, 있으면 저장된 경로
+    bookmark.setImageUrl(imageUrl);   // 파일이 없으면 기존 유지, 있으면 저장된 경로

Also applies to: 223-223

🤖 Prompt for AI Agents
In src/main/java/jombi/freemates/service/BookmarkService.java around lines 198
to 202 and line 223, the current image handling logic sets imageUrl to null if
no new image is provided, which unintentionally deletes existing images during
updates. Modify the code to preserve the existing imageUrl when no new image is
uploaded by only updating imageUrl if a new image is present; otherwise, retain
the current imageUrl value. Adjust the assignment logic accordingly to prevent
overwriting the existing image with null.


// Member 조회
Member member = customUserDetails.getMember();

// 기존 북마크 조회
Bookmark bookmark = bookmarkRepository.findById(bookmarkId)
.orElseThrow(() -> new CustomException(ErrorCode.BOOKMARK_NOT_FOUND));

// 소유자 검사
UUID ownerId = bookmark.getMember().getMemberId();
UUID currentUserId = member.getMemberId();
if (!ownerId.equals(currentUserId)) {
throw new CustomException(ErrorCode.UNAUTHORIZED);
}

// 업데이트
bookmark.setTitle(req.getTitle());
bookmark.setDescription(req.getDescription());
bookmark.setPinColor(req.getPinColor());
bookmark.setVisibility(req.getVisibility());
bookmark.setImageUrl(imageUrl); // 파일이 없으면 null, 있으면 저장된 경로

// DB 저장
bookmarkRepository.save(bookmark);
}
/**
* Bookmark 엔티티를 BookmarkDto로 변환하는 공통 메서드
*/


public BookmarkDto convertToBookmarkDto(Bookmark bookmark) {
Expand Down
80 changes: 65 additions & 15 deletions src/main/java/jombi/freemates/service/CourseService.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,21 +82,7 @@ public CourseDto createCourse(
.build()
);

List<UUID> placeIds = req.getPlaceIds();
List<CoursePlace> coursePlaceList = IntStream.range(0, placeIds.size())
.mapToObj(idx -> {
UUID placeId = placeIds.get(idx);
Place place = placeRepository.findByPlaceId(placeId)
.orElseThrow(() -> new CustomException(ErrorCode.PLACE_NOT_FOUND));
CoursePlaceId compositeId = new CoursePlaceId(course.getCourseId(), place.getPlaceId());
return CoursePlace.builder()
.coursePlaceId(compositeId)
.course(course)
.place(place)
.sequence(idx + 1)
.build();
})
.collect(Collectors.toList());
List<CoursePlace> coursePlaceList = createCoursePlaceList(course, req.getPlaceIds());

// CoursePlace 한꺼번에 저장
coursePlaceRepository.saveAll(coursePlaceList);
Expand Down Expand Up @@ -173,6 +159,52 @@ public void likeCourse(CustomUserDetails customUser, UUID courseId) {
courseRepository.save(course);
}
}
@Transactional
public void updateCourse(
CustomUserDetails customUser,
UUID courseId,
CourseRequest req,
MultipartFile image

) {
// 회원 확인
Member member = customUser.getMember();
if (member == null) {
throw new CustomException(ErrorCode.MEMBER_NOT_FOUND);
}

// 코스 조회
Course course = courseRepository.findById(courseId)
.orElseThrow(() -> new CustomException(ErrorCode.COURSE_NOT_FOUND));
UUID ownerId = course.getMember().getMemberId();
UUID currentUserId = member.getMemberId();
if (!ownerId.equals(currentUserId)) {
throw new CustomException(ErrorCode.UNAUTHORIZED);
}

// 이미지 저장
String imageUrl = null;
if (image != null && !image.isEmpty()) {
imageUrl = storage.storeImage(image);
course.setImageUrl(imageUrl);
}

// 코스 정보 업데이트
course.setTitle(req.getTitle());
course.setDescription(req.getDescription());
course.setFreeTime(req.getFreeTime());
course.setVisibility(req.getVisibility());

// CoursePlace 업데이트
List<CoursePlace> coursePlaceList = createCoursePlaceList(course, req.getPlaceIds());

// 기존 CoursePlace 삭제 후 새로 저장
coursePlaceRepository.deleteAllByCourse(course);
coursePlaceRepository.saveAll(coursePlaceList);

entityManager.flush();
}




Expand All @@ -196,4 +228,22 @@ public CourseDto converToCourseDto(Course course) {
.likeCount(course.getLikeCount())
.build();
}

private List<CoursePlace> createCoursePlaceList(Course course, List<UUID> placeIds) {
return IntStream.range(0, placeIds.size())
.mapToObj(idx -> {
UUID placeId = placeIds.get(idx);
Place place = placeRepository.findByPlaceId(placeId)
.orElseThrow(() -> new CustomException(ErrorCode.PLACE_NOT_FOUND));
CoursePlaceId compositeId = new CoursePlaceId(course.getCourseId(), place.getPlaceId());

return CoursePlace.builder()
.coursePlaceId(compositeId)
.course(course)
.place(place)
.sequence(idx + 1)
.build();
})
.collect(Collectors.toList());
}
}