Skip to content

Commit 0beddbd

Browse files
committed
refactor/OPS-346 : 개인 / 공유 파일 관리 분리
1 parent 95c057d commit 0beddbd

20 files changed

+2503
-2665
lines changed
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
package org.tuna.zoopzoop.backend.domain.datasource.controller;
2+
3+
import io.swagger.v3.oas.annotations.Operation;
4+
import io.swagger.v3.oas.annotations.tags.Tag;
5+
import jakarta.validation.Valid;
6+
import lombok.RequiredArgsConstructor;
7+
import org.springframework.data.domain.Page;
8+
import org.springframework.data.domain.Pageable;
9+
import org.springframework.data.domain.Sort;
10+
import org.springframework.data.web.PageableDefault;
11+
import org.springframework.http.ResponseEntity;
12+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
13+
import org.springframework.web.bind.annotation.*;
14+
import org.tuna.zoopzoop.backend.domain.datasource.dto.*;
15+
import org.tuna.zoopzoop.backend.domain.datasource.service.DataSourceService;
16+
import org.tuna.zoopzoop.backend.domain.datasource.service.PersonalDataSourceService;
17+
import org.tuna.zoopzoop.backend.domain.member.entity.Member;
18+
import org.tuna.zoopzoop.backend.global.security.jwt.CustomUserDetails;
19+
20+
import java.util.LinkedHashMap;
21+
import java.util.Map;
22+
23+
@RestController
24+
@RequestMapping("/api/v1/archive")
25+
@RequiredArgsConstructor
26+
@Tag(name = "ApiV1DataSource(Personal)", description = "개인 아카이브 자료 API")
27+
public class DataSourceController {
28+
29+
private final PersonalDataSourceService personalApp;
30+
31+
// ===== 등록 (개인만) =====
32+
@Operation(summary = "자료 등록", description = "내 PersonalArchive 안에 자료를 등록합니다.")
33+
@PostMapping("")
34+
public ResponseEntity<?> createDataSource(
35+
@Valid @RequestBody reqBodyForCreateDataSource rq,
36+
@AuthenticationPrincipal CustomUserDetails user
37+
) {
38+
Member me = user.getMember();
39+
int id = personalApp.create(me.getId(), rq.sourceUrl(), rq.folderId(),
40+
DataSourceService.CreateCmd.builder().build());
41+
return ResponseEntity.ok(new ApiResponse<>(200, "새로운 자료가 등록됐습니다.", id));
42+
}
43+
44+
// ===== 단건 삭제 =====
45+
@Operation(summary = "자료 단건 삭제", description = "내 PersonalArchive 안에 자료를 단건 삭제합니다.")
46+
@DeleteMapping("/{dataSourceId}")
47+
public ResponseEntity<?> delete(
48+
@PathVariable Integer dataSourceId,
49+
@AuthenticationPrincipal CustomUserDetails user
50+
) {
51+
int deletedId = personalApp.deleteOne(user.getMember().getId(), dataSourceId);
52+
return ResponseEntity.ok(Map.of(
53+
"status", 200,
54+
"msg", deletedId + "번 자료가 삭제됐습니다.",
55+
"data", Map.of("dataSourceId", deletedId)
56+
));
57+
}
58+
59+
// ===== 다건 삭제 =====
60+
@Operation(summary = "자료 다건 삭제", description = "내 PersonalArchive 안에 자료를 다건 삭제합니다.")
61+
@PostMapping("/delete")
62+
public ResponseEntity<?> deleteMany(
63+
@Valid @RequestBody reqBodyForDeleteMany rq,
64+
@AuthenticationPrincipal CustomUserDetails user
65+
) {
66+
personalApp.deleteMany(user.getMember().getId(), rq.dataSourceId());
67+
return ResponseEntity.ok(Map.of("status", 200, "msg", "복수개의 자료가 삭제됐습니다.", "data", null));
68+
}
69+
70+
// ===== 소프트 삭제/복원 =====
71+
@Operation(summary = "자료 다건 임시 삭제", description = "내 PersonalArchive 안에 자료들을 임시 삭제합니다.")
72+
@PatchMapping("/soft-delete")
73+
public ResponseEntity<?> softDelete(@RequestBody @Valid IdsRequest rq,
74+
@AuthenticationPrincipal CustomUserDetails user) {
75+
personalApp.softDelete(user.getMember().getId(), rq.ids());
76+
return ResponseEntity.ok(Map.of("status", 200, "msg", "자료들이 임시 삭제됐습니다.", "data", null));
77+
}
78+
79+
@Operation(summary = "자료 다건 복원", description = "내 PersonalArchive 안에 자료들을 복원합니다.")
80+
@PatchMapping("/restore")
81+
public ResponseEntity<?> restore(@RequestBody @Valid IdsRequest rq,
82+
@AuthenticationPrincipal CustomUserDetails user) {
83+
personalApp.restore(user.getMember().getId(), rq.ids());
84+
return ResponseEntity.ok(Map.of("status", 200, "msg", "자료들이 복구됐습니다.", "data", null));
85+
}
86+
87+
// ===== 이동 =====
88+
@Operation(summary = "자료 단건 이동", description = "내 PersonalArchive 안에 자료를 단건 이동합니다.")
89+
@PatchMapping("/{dataSourceId}/move")
90+
public ResponseEntity<?> moveDataSource(
91+
@PathVariable Integer dataSourceId,
92+
@Valid @RequestBody reqBodyForMoveDataSource rq,
93+
@AuthenticationPrincipal CustomUserDetails user
94+
) {
95+
var result = personalApp.moveOne(user.getMember().getId(), dataSourceId, rq.folderId());
96+
String msg = result.dataSourceId() + "번 자료가 " + result.folderId() + "번 폴더로 이동했습니다.";
97+
return ResponseEntity.ok(Map.of(
98+
"status", 200,
99+
"msg", msg,
100+
"data", Map.of("folderId", result.folderId(), "dataSourceId", result.dataSourceId())
101+
));
102+
}
103+
104+
@Operation(summary = "자료 다건 이동", description = "내 PersonalArchive 안에 자료들을 다건 이동합니다.")
105+
@PatchMapping("/move")
106+
public ResponseEntity<?> moveMany(
107+
@Valid @RequestBody reqBodyForMoveMany rq,
108+
@AuthenticationPrincipal CustomUserDetails user
109+
) {
110+
personalApp.moveMany(user.getMember().getId(), rq.folderId(), rq.dataSourceId());
111+
return ResponseEntity.ok(Map.of("status", 200, "msg", "복수 개의 자료를 이동했습니다.", "data", null));
112+
}
113+
114+
// ===== 수정 =====
115+
@Operation(summary = "자료 수정", description = "내 PersonalArchive 안에 자료를 수정합니다.")
116+
@PatchMapping("/{dataSourceId}")
117+
public ResponseEntity<?> updateDataSource(
118+
@PathVariable Integer dataSourceId,
119+
@RequestBody reqBodyForUpdateDataSource body,
120+
@AuthenticationPrincipal CustomUserDetails user
121+
) {
122+
boolean anyPresent =
123+
body.title().isPresent() || body.summary().isPresent() || body.sourceUrl().isPresent() ||
124+
body.imageUrl().isPresent() || body.source().isPresent() || body.tags().isPresent() || body.category().isPresent();
125+
if (!anyPresent) throw new IllegalArgumentException("변경할 값이 없습니다.");
126+
127+
int updatedId = personalApp.update(user.getMember().getId(), dataSourceId,
128+
DataSourceService.UpdateCmd.builder()
129+
.title(body.title()).summary(body.summary()).sourceUrl(body.sourceUrl())
130+
.imageUrl(body.imageUrl()).source(body.source())
131+
.tags(body.tags()).category(body.category())
132+
.build());
133+
134+
return ResponseEntity.ok(new ApiResponse<>(200, updatedId + "번 자료가 수정됐습니다.",
135+
new resBodyForUpdateDataSource(updatedId)));
136+
}
137+
138+
// ===== 검색 =====
139+
@Operation(summary = "자료 검색", description = "내 PersonalArchive 안에 자료들을 검색합니다.")
140+
@GetMapping("")
141+
public ResponseEntity<?> search(
142+
@RequestParam(required = false) String title,
143+
@RequestParam(required = false) String summary,
144+
@RequestParam(required = false) String category,
145+
@RequestParam(required = false) Integer folderId,
146+
@RequestParam(required = false) String folderName,
147+
@RequestParam(required = false, defaultValue = "true") Boolean isActive,
148+
@PageableDefault(size = 8, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable,
149+
@AuthenticationPrincipal CustomUserDetails user
150+
) {
151+
var cond = DataSourceSearchCondition.builder()
152+
.title(title).summary(summary).category(category)
153+
.folderId(folderId).folderName(folderName).isActive(isActive).build();
154+
155+
Page<DataSourceSearchItem> page = personalApp.search(user.getMember().getId(), cond, pageable);
156+
String sorted = pageable.getSort().toString().replace(": ", ",");
157+
158+
Map<String, Object> res = new LinkedHashMap<>();
159+
res.put("status", 200);
160+
res.put("msg", "복수개의 자료가 조회됐습니다.");
161+
res.put("data", page.getContent());
162+
res.put("pageInfo", Map.of(
163+
"page", page.getNumber(), "size", page.getSize(),
164+
"totalElements", page.getTotalElements(), "totalPages", page.getTotalPages(),
165+
"first", page.isFirst(), "last", page.isLast(), "sorted", sorted
166+
));
167+
return ResponseEntity.ok(res);
168+
}
169+
170+
record ApiResponse<T>(int status, String msg, T data) {}
171+
}

0 commit comments

Comments
 (0)