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 @@ -2,6 +2,7 @@

import kr.suhsaechan.mapsy.place.constant.FolderVisibility;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -14,6 +15,7 @@
@Schema(description = "폴더 생성 요청")
public class CreateFolderRequest {
@Schema(description = "폴더 이름", example = "가고 싶은 곳")
@Size(max = 100, message = "폴더 이름은 100자 이하여야 합니다.")
private String name;

@Schema(description = "공개 설정", example = "PRIVATE")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import kr.suhsaechan.mapsy.place.constant.FolderVisibility;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -14,6 +15,7 @@
@Schema(description = "폴더 수정 요청")
public class UpdateFolderRequest {
@Schema(description = "폴더 이름", example = "맛집 모음")
@Size(max = 100, message = "폴더 이름은 100자 이하여야 합니다.")
private String name;

@Schema(description = "공개 설정", example = "SHARED")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ protected void onCreate() {
if (visibility == null) {
visibility = FolderVisibility.PRIVATE;
}
if (isDefault == null) {
isDefault = false;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
import java.util.UUID;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
Expand All @@ -16,6 +18,15 @@
import lombok.NoArgsConstructor;

@Entity
@Table(
name = "folder_place",
uniqueConstraints = {
@UniqueConstraint(
name = "uk_folder_place",
columnNames = {"folder_id", "place_id"}
)
}
)
@Builder
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,22 @@
import java.util.Optional;
import java.util.UUID;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface FolderRepository extends JpaRepository<Folder, UUID> {

List<Folder> findByOwnerAndDeletedAtIsNullOrderByCreatedAtAsc(Member owner);

@Query("SELECT f, COUNT(fp) FROM Folder f " +
"LEFT JOIN FolderPlace fp ON fp.folder = f AND fp.deletedAt IS NULL " +
"WHERE f.owner = :owner AND f.deletedAt IS NULL " +
"GROUP BY f " +
"ORDER BY f.createdAt ASC")
List<Object[]> findByOwnerWithPlaceCount(@Param("owner") Member owner);

Optional<Folder> findByOwnerAndIsDefaultTrueAndDeletedAtIsNull(Member owner);

Optional<Folder> findByIdAndDeletedAtIsNull(UUID id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,12 @@ public class FolderService {
public GetFoldersResponse getFolders(Member member) {
log.info("Getting folders for member: {}", member.getId());

List<Folder> folders = folderRepository.findByOwnerAndDeletedAtIsNullOrderByCreatedAtAsc(member);
List<Object[]> results = folderRepository.findByOwnerWithPlaceCount(member);

List<FolderDto> folderDtos = folders.stream()
.map(folder -> {
int placeCount = folderPlaceRepository.countByFolderAndDeletedAtIsNull(folder);
List<FolderDto> folderDtos = results.stream()
.map(row -> {
Folder folder = (Folder) row[0];
int placeCount = ((Long) row[1]).intValue();
return FolderDto.from(folder, placeCount);
})
.collect(Collectors.toList());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import kr.suhsaechan.mapsy.place.dto.UpdateFolderRequest;
import kr.suhsaechan.mapsy.place.dto.UpdateFolderResponse;
import kr.suhsaechan.mapsy.place.service.FolderService;
import jakarta.validation.Valid;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -23,12 +24,14 @@
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@Slf4j
@RequestMapping("/api/folders")
@Tag(name = "폴더 관리 API", description = "폴더 CRUD 및 폴더-장소 관리 관련 API 제공")
public class FolderController implements FolderControllerDocs {

private final FolderService folderService;
Expand All @@ -47,7 +50,7 @@ public ResponseEntity<GetFoldersResponse> getFolders(
@Override
public ResponseEntity<CreateFolderResponse> createFolder(
@AuthenticationPrincipal CustomUserDetails userDetails,
@RequestBody CreateFolderRequest request
@Valid @RequestBody CreateFolderRequest request
) {
log.info("Create folder request from member: {}", userDetails.getMemberId());
CreateFolderResponse response = folderService.createFolder(userDetails.getMemberId(), request);
Expand All @@ -59,7 +62,7 @@ public ResponseEntity<CreateFolderResponse> createFolder(
public ResponseEntity<UpdateFolderResponse> updateFolder(
@AuthenticationPrincipal CustomUserDetails userDetails,
@PathVariable UUID folderId,
@RequestBody UpdateFolderRequest request
@Valid @RequestBody UpdateFolderRequest request
) {
log.info("Update folder request from member: {}, folderId: {}", userDetails.getMemberId(), folderId);
UpdateFolderResponse response = folderService.updateFolder(userDetails.getMemberId(), folderId, request);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package kr.suhsaechan.mapsy.web.controller;

import kr.suhsaechan.mapsy.auth.dto.CustomUserDetails;
import kr.suhsaechan.mapsy.common.constant.Author;
import kr.suhsaechan.mapsy.place.dto.AddFolderPlaceRequest;
import kr.suhsaechan.mapsy.place.dto.AddFolderPlaceResponse;
import kr.suhsaechan.mapsy.place.dto.CreateFolderRequest;
Expand All @@ -11,10 +12,12 @@
import kr.suhsaechan.mapsy.place.dto.UpdateFolderResponse;
import io.swagger.v3.oas.annotations.Operation;
import java.util.UUID;
import kr.suhsaechan.suhapilog.annotation.ApiLog;
import org.springframework.http.ResponseEntity;

public interface FolderControllerDocs {

@ApiLog(date = "2026.02.23", author = Author.SUHSAECHAN, issueNumber = 26, description = "폴더 목록 조회 API 구현")
@Operation(summary = "내 폴더 목록 조회", description = """
## 인증(JWT): **필요**

Expand Down Expand Up @@ -42,6 +45,7 @@ ResponseEntity<GetFoldersResponse> getFolders(
CustomUserDetails userDetails
);

@ApiLog(date = "2026.02.23", author = Author.SUHSAECHAN, issueNumber = 26, description = "폴더 생성 API 구현")
@Operation(summary = "폴더 생성", description = """
## 인증(JWT): **필요**

Expand All @@ -67,6 +71,7 @@ ResponseEntity<CreateFolderResponse> createFolder(
CreateFolderRequest request
);

@ApiLog(date = "2026.02.23", author = Author.SUHSAECHAN, issueNumber = 26, description = "폴더 수정 API 구현")
@Operation(summary = "폴더 수정", description = """
## 인증(JWT): **필요**

Expand Down Expand Up @@ -95,6 +100,7 @@ ResponseEntity<UpdateFolderResponse> updateFolder(
UpdateFolderRequest request
);

@ApiLog(date = "2026.02.23", author = Author.SUHSAECHAN, issueNumber = 26, description = "폴더 삭제 API 구현")
@Operation(summary = "폴더 삭제", description = """
## 인증(JWT): **필요**

Expand All @@ -119,6 +125,7 @@ ResponseEntity<Void> deleteFolder(
UUID folderId
);

@ApiLog(date = "2026.02.23", author = Author.SUHSAECHAN, issueNumber = 26, description = "폴더 내 장소 목록 조회 API 구현")
@Operation(summary = "폴더 내 장소 목록 조회", description = """
## 인증(JWT): **필요**

Expand Down Expand Up @@ -150,6 +157,7 @@ ResponseEntity<GetFolderPlacesResponse> getFolderPlaces(
UUID folderId
);

@ApiLog(date = "2026.02.23", author = Author.SUHSAECHAN, issueNumber = 26, description = "폴더에 장소 추가 API 구현")
@Operation(summary = "폴더에 장소 추가", description = """
## 인증(JWT): **필요**

Expand Down Expand Up @@ -181,6 +189,7 @@ ResponseEntity<AddFolderPlaceResponse> addPlaceToFolder(
AddFolderPlaceRequest request
);

@ApiLog(date = "2026.02.23", author = Author.SUHSAECHAN, issueNumber = 26, description = "폴더에서 장소 제거 API 구현")
@Operation(summary = "폴더에서 장소 제거", description = """
## 인증(JWT): **필요**

Expand Down