Skip to content

Commit ba0ba12

Browse files
committed
refactor/OPS-246 : 머지
2 parents 31d4944 + 7e4f1e8 commit ba0ba12

File tree

1 file changed

+198
-0
lines changed

1 file changed

+198
-0
lines changed
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
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.openapitools.jackson.nullable.JsonNullable;
8+
import org.springframework.data.domain.Page;
9+
import org.springframework.data.domain.Pageable;
10+
import org.springframework.data.domain.Sort;
11+
import org.springframework.data.web.PageableDefault;
12+
import org.springframework.http.ResponseEntity;
13+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
14+
import org.springframework.web.bind.annotation.*;
15+
import org.tuna.zoopzoop.backend.domain.datasource.dto.*;
16+
import org.tuna.zoopzoop.backend.domain.datasource.entity.Category;
17+
import org.tuna.zoopzoop.backend.domain.datasource.service.DataSourceService;
18+
import org.tuna.zoopzoop.backend.domain.datasource.service.PersonalDataSourceService;
19+
import org.tuna.zoopzoop.backend.global.rsData.RsData;
20+
import org.tuna.zoopzoop.backend.global.security.jwt.CustomUserDetails;
21+
22+
import java.io.IOException;
23+
import java.util.Map;
24+
25+
@RestController
26+
@RequestMapping("/api/v1/archive")
27+
@RequiredArgsConstructor
28+
@Tag(name = "ApiV1DataSource(Personal)", description = "개인 아카이브 자료 API")
29+
public class DataSourceController {
30+
31+
private final PersonalDataSourceService personalApp;
32+
33+
// ===== 등록 (개인만) =====
34+
// DataSourceController
35+
36+
@Operation(summary = "자료 등록", description = "내 PersonalArchive 안에 자료를 등록합니다.")
37+
@PostMapping("")
38+
public ResponseEntity<RsData<Map<String, Integer>>> createDataSource(
39+
@Valid @RequestBody reqBodyForCreateDataSource rq,
40+
@AuthenticationPrincipal CustomUserDetails user
41+
) throws IOException {
42+
int id = personalApp.create(
43+
user.getMember().getId(),
44+
rq.sourceUrl(),
45+
rq.folderId(),
46+
DataSourceService.CreateCmd.builder().build()
47+
);
48+
return ResponseEntity.ok(
49+
new RsData<>("200", "새로운 자료가 등록됐습니다.", Map.of("dataSourceId", id))
50+
);
51+
}
52+
53+
54+
// ===== 단건 삭제 =====
55+
@Operation(summary = "자료 단건 삭제", description = "내 PersonalArchive 안에 자료를 단건 삭제합니다.")
56+
@DeleteMapping("/{dataSourceId}")
57+
public ResponseEntity<RsData<Map<String, Integer>>> delete(
58+
@PathVariable Integer dataSourceId,
59+
@AuthenticationPrincipal CustomUserDetails user
60+
) {
61+
int deletedId = personalApp.deleteOne(user.getMember().getId(), dataSourceId);
62+
return ResponseEntity.ok(
63+
new RsData<>("200", deletedId + "번 자료가 삭제됐습니다.", Map.of("dataSourceId", deletedId))
64+
);
65+
}
66+
67+
// ===== 다건 삭제 =====
68+
@Operation(summary = "자료 다건 삭제", description = "내 PersonalArchive 안에 자료를 다건 삭제합니다.")
69+
@PostMapping("/delete")
70+
public ResponseEntity<RsData<Void>> deleteMany(
71+
@Valid @RequestBody reqBodyForDeleteMany rq,
72+
@AuthenticationPrincipal CustomUserDetails user
73+
) {
74+
personalApp.deleteMany(user.getMember().getId(), rq.dataSourceId());
75+
return ResponseEntity.ok(new RsData<>("200", "복수개의 자료가 삭제됐습니다.", null));
76+
}
77+
78+
// ===== 소프트 삭제/복원 =====
79+
@Operation(summary = "자료 다건 임시 삭제", description = "내 PersonalArchive 안에 자료들을 임시 삭제합니다.")
80+
@PatchMapping("/soft-delete")
81+
public ResponseEntity<RsData<Void>> softDelete(@RequestBody @Valid IdsRequest rq,
82+
@AuthenticationPrincipal CustomUserDetails user) {
83+
personalApp.softDelete(user.getMember().getId(), rq.dataSourceId());
84+
return ResponseEntity.ok(new RsData<>("200", "자료들이 임시 삭제됐습니다.", null));
85+
}
86+
87+
@Operation(summary = "자료 다건 복원", description = "내 PersonalArchive 안에 자료들을 복원합니다.")
88+
@PatchMapping("/restore")
89+
public ResponseEntity<RsData<Void>> restore(@RequestBody @Valid IdsRequest rq,
90+
@AuthenticationPrincipal CustomUserDetails user) {
91+
personalApp.restore(user.getMember().getId(), rq.dataSourceId());
92+
return ResponseEntity.ok(new RsData<>("200", "자료들이 복구됐습니다.", null));
93+
}
94+
95+
// ===== 이동 =====
96+
@Operation(summary = "자료 단건 이동", description = "내 PersonalArchive 안에 자료를 단건 이동합니다.")
97+
@PatchMapping("/{dataSourceId}/move")
98+
public ResponseEntity<RsData<Map<String, Integer>>> moveDataSource(
99+
@PathVariable Integer dataSourceId,
100+
@Valid @RequestBody reqBodyForMoveDataSource rq,
101+
@AuthenticationPrincipal CustomUserDetails user
102+
) {
103+
var result = personalApp.moveOne(user.getMember().getId(), dataSourceId, rq.folderId());
104+
String msg = result.dataSourceId() + "번 자료가 " + result.folderId() + "번 폴더로 이동했습니다.";
105+
return ResponseEntity.ok(
106+
new RsData<>("200", msg,
107+
Map.of("folderId", result.folderId(), "dataSourceId", result.dataSourceId()))
108+
);
109+
}
110+
111+
@Operation(summary = "자료 다건 이동", description = "내 PersonalArchive 안에 자료들을 다건 이동합니다.")
112+
@PatchMapping("/move")
113+
public ResponseEntity<RsData<Void>> moveMany(
114+
@Valid @RequestBody reqBodyForMoveMany rq,
115+
@AuthenticationPrincipal CustomUserDetails user
116+
) {
117+
personalApp.moveMany(user.getMember().getId(), rq.folderId(), rq.dataSourceId());
118+
return ResponseEntity.ok(new RsData<>("200", "복수 개의 자료를 이동했습니다.", null));
119+
}
120+
121+
// ===== 수정 =====
122+
@Operation(summary = "자료 수정", description = "내 PersonalArchive 안에 자료를 수정합니다.")
123+
@PatchMapping("/{dataSourceId}")
124+
public ResponseEntity<RsData<Map<String, Integer>>> updateDataSource(
125+
@PathVariable Integer dataSourceId,
126+
@RequestBody reqBodyForUpdateDataSource body,
127+
@AuthenticationPrincipal CustomUserDetails user
128+
) {
129+
boolean anyPresent =
130+
(body.title() != null && body.title().isPresent()) ||
131+
(body.summary() != null && body.summary().isPresent()) ||
132+
(body.sourceUrl() != null && body.sourceUrl().isPresent()) ||
133+
(body.imageUrl() != null && body.imageUrl().isPresent()) ||
134+
(body.source() != null && body.source().isPresent()) ||
135+
(body.tags() != null && body.tags().isPresent()) ||
136+
(body.category() != null && body.category().isPresent());
137+
if (!anyPresent) throw new IllegalArgumentException("변경할 값이 없습니다.");
138+
139+
140+
var catNullable = body.category();
141+
142+
// category enum 변환 시도
143+
JsonNullable<Category> enumCat = null;
144+
if (catNullable != null && catNullable.isPresent()) {
145+
String raw = catNullable.get();
146+
try {
147+
// 필요하면 대소문자 허용 로직 추가
148+
enumCat = JsonNullable.of(Category.valueOf(raw.toUpperCase()));
149+
} catch (IllegalArgumentException ex) {
150+
throw new IllegalArgumentException("유효하지 않은 카테고리입니다: " + raw);
151+
}
152+
}
153+
154+
int updatedId = personalApp.update(
155+
user.getMember().getId(),
156+
dataSourceId,
157+
DataSourceService.UpdateCmd.builder()
158+
.title(body.title()).summary(body.summary()).sourceUrl(body.sourceUrl())
159+
.imageUrl(body.imageUrl()).source(body.source())
160+
.tags(body.tags()).category(enumCat)
161+
.build()
162+
);
163+
164+
return ResponseEntity.ok(
165+
new RsData<>("200", updatedId + "번 자료가 수정됐습니다.", Map.of("dataSourceId", updatedId))
166+
);
167+
}
168+
169+
// ===== 검색 =====
170+
@Operation(summary = "자료 검색", description = "내 PersonalArchive 안에 자료들을 검색합니다.")
171+
@GetMapping("")
172+
public ResponseEntity<RsData<SearchResponse<DataSourceSearchItem>>> search(
173+
@RequestParam(required = false) String title,
174+
@RequestParam(required = false) String summary,
175+
@RequestParam(required = false) String category,
176+
@RequestParam(required = false) String keyword,
177+
@RequestParam(required = false) Integer folderId,
178+
@RequestParam(required = false) String folderName,
179+
@RequestParam(required = false, defaultValue = "true") Boolean isActive,
180+
@PageableDefault(size = 8, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable,
181+
@AuthenticationPrincipal CustomUserDetails user
182+
) {
183+
var cond = DataSourceSearchCondition.builder()
184+
.title(title).summary(summary).category(category).folderId(folderId)
185+
.folderName(folderName).isActive(isActive).keyword(keyword).build();
186+
187+
Page<DataSourceSearchItem> page = personalApp.search(user.getMember().getId(), cond, pageable);
188+
String sorted = pageable.getSort().toString().replace(": ", ",");
189+
190+
var pageInfo = new PageInfo(
191+
page.getNumber(), page.getSize(), page.getTotalElements(), page.getTotalPages(),
192+
page.isFirst(), page.isLast(), sorted
193+
);
194+
var body = new SearchResponse<>(page.getContent(), pageInfo);
195+
196+
return ResponseEntity.ok(new RsData<>("200", "복수개의 자료가 조회됐습니다.", body));
197+
}
198+
}

0 commit comments

Comments
 (0)