- 목록 API status 파라미터(NEW|EXCLUDED|REGISTERED), POST /{id}/restore(→NEW)
- recommend.html: 헤더 '제외 목록' 토글로 EXCLUDED 채널 보기, 카드에 '복원' 버튼
(제외 보기에선 등록/제외 대신 복원+채널이동만), 지역 탭은 그대로 적용
검증: 제외→EXCLUDED 목록 노출→복원→NEW 복귀 end-to-end 확인.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
69 lines
3.0 KiB
Java
69 lines
3.0 KiB
Java
package com.hlab.yanalyst.domain.channel;
|
|
|
|
import com.hlab.yanalyst.global.common.ApiResponse;
|
|
import io.swagger.v3.oas.annotations.Operation;
|
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
import lombok.RequiredArgsConstructor;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
@RestController
|
|
@RequestMapping("/api/recommended-channels")
|
|
@RequiredArgsConstructor
|
|
@Tag(name = "Recommended Channel API", description = "자동 발굴된 추천 채널(떡상 Shorts)")
|
|
public class RecommendedChannelController {
|
|
|
|
private final RecommendedChannelRepository repository;
|
|
private final ChannelDiscoveryService discoveryService;
|
|
private final ChannelService channelService;
|
|
|
|
@GetMapping
|
|
@Operation(summary = "추천 채널 목록", description = "status(NEW|EXCLUDED|REGISTERED, 기본 NEW)를 배율 내림차순으로 반환")
|
|
public ApiResponse<List<RecommendedChannel>> list(@RequestParam(defaultValue = "NEW") String status) {
|
|
return ApiResponse.ok(repository.findByStatusOrderByRatioDesc(status));
|
|
}
|
|
|
|
@PostMapping("/{id}/register")
|
|
@Operation(summary = "내 채널 등록", description = "추천 채널을 내 채널로 등록하고 REGISTERED 처리")
|
|
@Transactional
|
|
public ApiResponse<Void> register(@PathVariable Long id) {
|
|
RecommendedChannel rc = repository.findById(id)
|
|
.orElseThrow(() -> new IllegalArgumentException("추천 채널을 찾을 수 없습니다: " + id));
|
|
channelService.saveChannelFromUrl("https://www.youtube.com/channel/" + rc.getChannelId());
|
|
rc.setStatus("REGISTERED");
|
|
repository.save(rc);
|
|
return ApiResponse.ok(null);
|
|
}
|
|
|
|
@PostMapping("/{id}/exclude")
|
|
@Operation(summary = "추천 제외", description = "다음 발굴에서 다시 뜨지 않게 EXCLUDED 처리")
|
|
@Transactional
|
|
public ApiResponse<Void> exclude(@PathVariable Long id) {
|
|
RecommendedChannel rc = repository.findById(id)
|
|
.orElseThrow(() -> new IllegalArgumentException("추천 채널을 찾을 수 없습니다: " + id));
|
|
rc.setStatus("EXCLUDED");
|
|
repository.save(rc);
|
|
return ApiResponse.ok(null);
|
|
}
|
|
|
|
@PostMapping("/{id}/restore")
|
|
@Operation(summary = "제외 복원", description = "EXCLUDED 를 다시 NEW(추천 목록)로 되돌린다")
|
|
@Transactional
|
|
public ApiResponse<Void> restore(@PathVariable Long id) {
|
|
RecommendedChannel rc = repository.findById(id)
|
|
.orElseThrow(() -> new IllegalArgumentException("추천 채널을 찾을 수 없습니다: " + id));
|
|
rc.setStatus("NEW");
|
|
repository.save(rc);
|
|
return ApiResponse.ok(null);
|
|
}
|
|
|
|
@PostMapping("/run")
|
|
@Operation(summary = "수동 발굴 실행", description = "스케줄과 동일한 발굴을 즉시 1회 실행")
|
|
public ApiResponse<Map<String, Object>> run() {
|
|
return ApiResponse.ok(discoveryService.runDiscovery());
|
|
}
|
|
}
|