Skip to content

Commit 256ad29

Browse files
authored
[refactor/OPS-360] folder&datasource 리펙토링 (#101)
* refactor/OPS-360 : OpenAPI 애너테이션 추가 * refactor/OPS-360 : NoResultException 예외 분리 * refactor/OPS-360 : param 추가 * refactor/OPS-360 : param 추가 * refactor/OPS-360 : default 폴더 CRUD 로직 수정 * refactor/OPS-360 : 폴더 리스트는 호출 로직 수정
1 parent 51648bd commit 256ad29

File tree

11 files changed

+161
-87
lines changed

11 files changed

+161
-87
lines changed

src/main/java/org/tuna/zoopzoop/backend/domain/archive/archive/entity/Archive.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public class Archive extends BaseEntity {
2222
private ArchiveType archiveType;
2323

2424
//아카이브 삭제(아마도 계정 탈퇴) 시 폴더 일괄 삭제
25-
@OneToMany(mappedBy = "archive", cascade = CascadeType.REMOVE, orphanRemoval = true)
25+
@OneToMany(mappedBy = "archive", cascade = CascadeType.ALL, orphanRemoval = true)
2626
private List<Folder> folders = new ArrayList<>();
2727

2828
public Archive(ArchiveType archiveType) {

src/main/java/org/tuna/zoopzoop/backend/domain/archive/archive/repository/PersonalArchiveRepository.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import org.springframework.data.jpa.repository.JpaRepository;
44
import org.springframework.data.jpa.repository.Query;
5+
import org.springframework.data.repository.query.Param;
56
import org.tuna.zoopzoop.backend.domain.archive.archive.entity.PersonalArchive;
67

78
import java.util.Optional;
@@ -14,10 +15,10 @@ public interface PersonalArchiveRepository extends JpaRepository<PersonalArchive
1415
* @return PersonalArchive 엔티티
1516
*/
1617
@Query("""
17-
select pa
18-
from PersonalArchive pa
19-
join fetch pa.archive a
20-
where pa.member.id = :memberId
21-
""")
22-
Optional<PersonalArchive> findByMemberId(Integer memberId);
18+
select pa
19+
from PersonalArchive pa
20+
join fetch pa.archive a
21+
where pa.member.id = :memberId
22+
""")
23+
Optional<PersonalArchive> findByMemberId(@Param("memberId") Integer memberId);
2324
}

src/main/java/org/tuna/zoopzoop/backend/domain/archive/folder/controller/FolderController.java

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.tuna.zoopzoop.backend.domain.archive.folder.controller;
22

3+
import io.swagger.v3.oas.annotations.Operation;
4+
import io.swagger.v3.oas.annotations.tags.Tag;
35
import jakarta.validation.Valid;
46
import lombok.RequiredArgsConstructor;
57
import org.springframework.http.ResponseEntity;
@@ -14,13 +16,13 @@
1416
import org.tuna.zoopzoop.backend.global.rsData.RsData;
1517
import org.tuna.zoopzoop.backend.global.security.jwt.CustomUserDetails;
1618

17-
import java.util.HashMap;
1819
import java.util.List;
1920
import java.util.Map;
2021

2122
@RestController
2223
@RequestMapping("/api/v1/archive/folder")
2324
@RequiredArgsConstructor
25+
@Tag(name = "ApiV1Folder", description = "개인 아카이브의 폴더 CRUD")
2426
public class FolderController {
2527

2628
private final FolderService folderService;
@@ -30,6 +32,7 @@ public class FolderController {
3032
* @param rq reqBodyForCreateFolder
3133
* @return resBodyForCreateFolder
3234
*/
35+
@Operation(summary = "폴더 생성", description = "내 PersonalArchive 안에 새 폴더를 생성합니다.")
3336
@PostMapping
3437
public RsData<resBodyForCreateFolder> createFolder(
3538
@Valid @RequestBody reqBodyForCreateFolder rq,
@@ -55,14 +58,21 @@ public ResponseEntity<Map<String, Object>> deleteFolder(
5558
@PathVariable Integer folderId,
5659
@AuthenticationPrincipal CustomUserDetails userDetails
5760
) {
61+
if (folderId == 0) {
62+
var body = new java.util.HashMap<String, Object>();
63+
body.put("status", 400);
64+
body.put("msg", "default 폴더는 삭제할 수 없습니다.");
65+
body.put("data", null); // HashMap은 null 허용
66+
return ResponseEntity.badRequest().body(body);
67+
}
68+
5869
Member member = userDetails.getMember();
5970
String deletedFolderName = folderService.deleteFolder(member.getId(), folderId);
6071

61-
Map<String, Object> body = new HashMap<>();
72+
var body = new java.util.HashMap<String, Object>();
6273
body.put("status", 200);
6374
body.put("msg", deletedFolderName + " 폴더가 삭제됐습니다.");
64-
body.put("data", null);
65-
75+
body.put("data", null); // <- 여기도 Map.of 쓰면 NPE 납니다
6676
return ResponseEntity.ok(body);
6777
}
6878

@@ -77,22 +87,30 @@ public ResponseEntity<Map<String, Object>> updateFolderName(
7787
@RequestBody Map<String, String> body,
7888
@AuthenticationPrincipal CustomUserDetails userDetails
7989
) {
90+
if (folderId == 0) {
91+
var res = new java.util.HashMap<String, Object>();
92+
res.put("status", 400);
93+
res.put("msg", "default 폴더는 이름을 변경할 수 없습니다.");
94+
res.put("data", null);
95+
return ResponseEntity.badRequest().body(res);
96+
}
97+
8098
Member member = userDetails.getMember();
8199
String newName = body.get("folderName");
82100
String updatedName = folderService.updateFolderName(member.getId(), folderId, newName);
83101

84-
Map<String, Object> response = new HashMap<>();
85-
response.put("status", 200);
86-
response.put("msg", "폴더 이름이 " + updatedName + " 으로 변경됐습니다.");
87-
response.put("data", Map.of("folderName", updatedName));
88-
89-
return ResponseEntity.ok(response);
102+
return ResponseEntity.ok(java.util.Map.of(
103+
"status", 200,
104+
"msg", "폴더 이름이 " + updatedName + " 으로 변경됐습니다.",
105+
"data", java.util.Map.of("folderName", updatedName)
106+
));
90107
}
91108

92109
/**
93110
* 개인 아카이브의 폴더 이름 전부 조회
94111
* "default", "폴더1", "폴더2"
95112
*/
113+
@Operation(summary = "폴더 이름 조회", description = "내 PersonalArchive 안에 이름을 전부 조회합니다.")
96114
@GetMapping
97115
public ResponseEntity<?> getFolders(
98116
@AuthenticationPrincipal CustomUserDetails userDetails
@@ -110,29 +128,32 @@ public ResponseEntity<?> getFolders(
110128
}
111129

112130
/**
113-
* 폴더(내 PersonalArchive 소속) 안의 파일 목록 조회
131+
* 폴더 안의 파일 목록 조회
114132
*/
115133
@GetMapping("/{folderId}/files")
116134
public ResponseEntity<?> getFilesInFolder(
117135
@PathVariable Integer folderId,
118136
@AuthenticationPrincipal CustomUserDetails userDetails
119137
) {
120-
Member member = userDetails.getMember();
121-
FolderFilesDto rs = folderService.getFilesInFolderForPersonal(member.getId(), folderId);
122-
123-
return ResponseEntity.ok(
124-
Map.of(
125-
"status", 200,
126-
"msg", "해당 폴더의 파일 목록을 불러왔습니다.",
127-
"data", Map.of(
128-
"folder", Map.of(
129-
"folderId", rs.folderId(),
130-
"folderName", rs.folderName()
131-
),
132-
"files", rs.files()
133-
)
138+
int memberId = userDetails.getMember().getId();
139+
140+
Integer targetFolderId = (folderId == 0)
141+
? folderService.getDefaultFolderId(memberId)
142+
: folderId;
143+
144+
FolderFilesDto rs = folderService.getFilesInFolderForPersonal(memberId, targetFolderId);
145+
146+
return ResponseEntity.ok(Map.of(
147+
"status", 200,
148+
"msg", folderId == 0 ? "기본 폴더의 파일 목록을 불러왔습니다." : "해당 폴더의 파일 목록을 불러왔습니다.",
149+
"data", Map.of(
150+
"folder", Map.of(
151+
"folderId", rs.folderId(),
152+
"folderName", rs.folderName()
153+
),
154+
"files", rs.files()
134155
)
135-
);
156+
));
136157
}
137158

138159
}

src/main/java/org/tuna/zoopzoop/backend/domain/archive/folder/repository/FolderRepository.java

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ public interface FolderRepository extends JpaRepository<Folder, Integer>{
1717
* @param filenameEnd "파일명 + \ufffff"
1818
*/
1919
@Query("""
20-
select f.name
21-
from Folder f
22-
where f.archive.id = :archiveId
23-
and f.name >= :filename
24-
and f.name < :filenameEnd
25-
""")
26-
List<String> findNamesForConflictCheck(Integer archiveId, String filename, String filenameEnd);
20+
select f.name
21+
from Folder f
22+
where f.archive.id = :archiveId
23+
and f.name >= :filename
24+
and f.name < :filenameEnd
25+
""")
26+
List<String> findNamesForConflictCheck(@Param("archiveId") Integer archiveId,
27+
@Param("filename") String filename,
28+
@Param("filenameEnd") String filenameEnd);
2729
// 개인 아카이브의 폴더 조회
2830
List<Folder> findByArchive(Archive archive);
2931

@@ -38,24 +40,24 @@ public interface FolderRepository extends JpaRepository<Folder, Integer>{
3840
* @param memberId 조회할 회원 Id
3941
*/
4042
@Query("""
41-
select f
42-
from Folder f
43-
join f.archive a
44-
join PersonalArchive pa on pa.archive = a
45-
where pa.member.id = :memberId
46-
and f.isDefault = true
47-
""")
48-
Optional<Folder> findDefaultFolderByMemberId(Integer memberId);
43+
select f
44+
from Folder f
45+
join f.archive a
46+
join PersonalArchive pa on pa.archive = a
47+
where pa.member.id = :memberId
48+
and f.isDefault = true
49+
""")
50+
Optional<Folder> findDefaultFolderByMemberId(@Param("memberId") Integer memberId);
4951

5052
// 한 번의 조인으로 존재 + 소유권(memberId) 검증
5153
@Query("""
52-
select f
53-
from Folder f
54-
join f.archive a
55-
join PersonalArchive pa on pa.archive = a
56-
where f.id = :folderId
57-
and pa.member.id = :memberId
58-
""")
54+
select f
55+
from Folder f
56+
join f.archive a
57+
join PersonalArchive pa on pa.archive = a
58+
where f.id = :folderId
59+
and pa.member.id = :memberId
60+
""")
5961
Optional<Folder> findByIdAndMemberId(@Param("folderId") Integer folderId,
6062
@Param("memberId") Integer memberId);
6163

src/main/java/org/tuna/zoopzoop/backend/domain/archive/folder/service/FolderService.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@ public FolderResponse createFolderForPersonal(Integer currentMemberId, String fo
4242
throw new IllegalArgumentException("폴더 이름은 비어 있을 수 없습니다.");
4343

4444
Member member = memberRepository.findById(currentMemberId)
45-
.orElseThrow(() -> new IllegalArgumentException("멤버를 찾을 수 없습니다."));
45+
.orElseThrow(() -> new NoResultException("멤버를 찾을 수 없습니다."));
4646

4747
Archive archive = personalArchiveRepository.findByMemberId(member.getId())
4848
.map(PersonalArchive::getArchive)
49-
.orElseThrow(() -> new IllegalStateException("개인 아카이브가 없습니다."));
49+
.orElseThrow(() -> new NoResultException("개인 아카이브가 없습니다."));
5050

5151
final String requested = folderName.trim();
5252

@@ -192,6 +192,14 @@ public FolderFilesDto getFilesInFolderForPersonal(Integer memberId, Integer fold
192192
return new FolderFilesDto(folder.getId(), folder.getName(), files);
193193
}
194194

195+
196+
public Integer getDefaultFolderId(int memberId) {
197+
Folder folder = folderRepository.findDefaultFolderByMemberId(memberId)
198+
.orElseThrow(() -> new NoResultException("default 폴더를 찾을 수 없습니다."));
199+
return folder.getId();
200+
201+
}
202+
195203
/**
196204
* 입력된 폴더명을 (폴더명, 숫자)로 분리하는 유틸 클래스
197205
* “폴더명” → (”폴더명”, null)

src/main/java/org/tuna/zoopzoop/backend/domain/auth/dev/controller/DevController.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ public class DevController {
2323

2424
@GetMapping("/token")
2525
public Map<String, String> issueToken(
26-
@RequestParam Provider provider,
27-
@RequestParam String key
26+
@RequestParam(name = "provider") Provider provider,
27+
@RequestParam(name = "key") String key
2828
) {
2929
Member m = memberRepository.findByProviderAndProviderKey(provider, key)
3030
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "member not found"));

src/main/java/org/tuna/zoopzoop/backend/domain/dashboard/service/DashboardService.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
import com.fasterxml.jackson.databind.ObjectMapper;
44
import jakarta.persistence.NoResultException;
55
import lombok.RequiredArgsConstructor;
6-
import org.apache.commons.codec.binary.Hex;
7-
import org.springframework.beans.factory.annotation.Value;
86
import org.springframework.stereotype.Service;
97
import org.springframework.transaction.annotation.Transactional;
108
import org.tuna.zoopzoop.backend.domain.dashboard.dto.BodyForReactFlow;
@@ -16,11 +14,7 @@
1614
import org.tuna.zoopzoop.backend.domain.member.entity.Member;
1715
import org.tuna.zoopzoop.backend.domain.space.membership.service.MembershipService;
1816

19-
import javax.crypto.Mac;
20-
import javax.crypto.spec.SecretKeySpec;
21-
import java.nio.charset.StandardCharsets;
2217
import java.nio.file.AccessDeniedException;
23-
import java.security.MessageDigest;
2418
import java.util.List;
2519

2620
@Service

src/main/java/org/tuna/zoopzoop/backend/domain/datasource/controller/DatasourceController.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.tuna.zoopzoop.backend.domain.datasource.controller;
22

3+
import io.swagger.v3.oas.annotations.Operation;
4+
import io.swagger.v3.oas.annotations.tags.Tag;
35
import jakarta.validation.Valid;
46
import lombok.RequiredArgsConstructor;
57
import org.springframework.data.domain.Page;
@@ -21,6 +23,7 @@
2123
@RestController
2224
@RequestMapping("/api/v1/archive")
2325
@RequiredArgsConstructor
26+
@Tag(name = "ApiV1DataSource", description = "개인 아카이브의 파일 CRUD")
2427
public class DatasourceController {
2528

2629
private final DataSourceService dataSourceService;
@@ -30,6 +33,7 @@ public class DatasourceController {
3033
* sourceUrl 등록할 자료 url
3134
* folderId 등록될 폴더 위치(null 이면 default)
3235
*/
36+
@Operation(summary = "자료 등록", description = "내 PersonalArchive 안에 자료를 등록합니다.")
3337
@PostMapping("")
3438
public ResponseEntity<?> createDataSource(
3539
@Valid @RequestBody reqBodyForCreateDataSource rq,
@@ -49,6 +53,7 @@ public ResponseEntity<?> createDataSource(
4953
/**
5054
* 자료 단건 삭제
5155
*/
56+
@Operation(summary = "자료 단건 삭제", description = "내 PersonalArchive 안에 자료를 단건 삭제합니다.")
5257
@DeleteMapping("/{dataSourceId}")
5358
public ResponseEntity<Map<String, Object>> delete(
5459
@PathVariable Integer dataSourceId,
@@ -68,6 +73,7 @@ public ResponseEntity<Map<String, Object>> delete(
6873
/**
6974
* 자료 다건 삭제
7075
*/
76+
@Operation(summary = "자료 다건 삭제", description = "내 PersonalArchive 안에 자료를 다건 삭제합니다.")
7177
@PostMapping("/delete")
7278
public ResponseEntity<Map<String, Object>> deleteMany(
7379
@Valid @RequestBody reqBodyForDeleteMany body,
@@ -88,6 +94,7 @@ public ResponseEntity<Map<String, Object>> deleteMany(
8894
* 자료 단건 이동
8995
* folderId=null 이면 default 폴더
9096
*/
97+
@Operation(summary = "자료 단건 이동", description = "내 PersonalArchive 안에 자료를 단건 이동합니다.")
9198
@PatchMapping("/{dataSourceId}/move")
9299
public ResponseEntity<?> moveDataSource(
93100
@PathVariable Integer dataSourceId,
@@ -118,6 +125,7 @@ public ResponseEntity<?> moveDataSource(
118125
/**
119126
* 자료 다건 이동
120127
*/
128+
@Operation(summary = "자료 다건 이동", description = "내 PersonalArchive 안에 자료들를 다건 이동합니다..")
121129
@PatchMapping("/move")
122130
public ResponseEntity<?> moveMany(
123131
@Valid @RequestBody reqBodyForMoveMany rq,
@@ -141,6 +149,7 @@ public ResponseEntity<?> moveMany(
141149
* @param dataSourceId 수정할 파일 Id
142150
* @param body 수정할 내용
143151
*/
152+
@Operation(summary = "자료 수정", description = "내 PersonalArchive 안에 자료를 수정합니다.")
144153
@PatchMapping("/{dataSourceId}")
145154
public ResponseEntity<?> updateDataSource(
146155
@PathVariable Integer dataSourceId,
@@ -162,6 +171,10 @@ public ResponseEntity<?> updateDataSource(
162171
);
163172
}
164173

174+
/**
175+
* 자료 검색
176+
*/
177+
@Operation(summary = "자료 검색", description = "내 PersonalArchive 안에 자료들을 검색합니다.")
165178
@GetMapping("")
166179
public ResponseEntity<?> search(
167180
@RequestParam(required = false) String title,

0 commit comments

Comments
 (0)