target fix
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
package kz.konturai.parser.controller;
|
||||
|
||||
import kz.konturai.parser.service.MinIOService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Controller for public access to marketing images and videos at the root level.
|
||||
* This handles requests to https://api.konturai.kz/image_*.png or video_*.mp4.
|
||||
*/
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class PublicAssetController {
|
||||
|
||||
private final MinIOService minIOService;
|
||||
|
||||
/**
|
||||
* Serves images that start with "image_" and end with ".png" from the root.
|
||||
* Example: https://api.konturai.kz/image_1772616225367_1567876836.png
|
||||
*/
|
||||
@GetMapping("/{filename:image_.+\\.png}")
|
||||
public ResponseEntity<byte[]> getPublicImage(@PathVariable String filename) {
|
||||
log.info("[PublicAsset] Access request for image: {}", filename);
|
||||
try {
|
||||
if (!minIOService.fileExists(filename)) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
try (InputStream is = minIOService.downloadFile(filename)) {
|
||||
byte[] bytes = is.readAllBytes();
|
||||
return ResponseEntity.ok()
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.IMAGE_PNG_VALUE)
|
||||
.header(HttpHeaders.CACHE_CONTROL, "public, max-age=3600")
|
||||
.body(bytes);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("[PublicAsset] Failed to serve public image {}: {}", filename, e.getMessage());
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serves videos that start with "video_" and end with ".mp4" from the root.
|
||||
* Example: https://api.konturai.kz/video_1772616225367_1567876836.mp4
|
||||
*/
|
||||
@GetMapping("/{filename:video_.+\\.mp4}")
|
||||
public ResponseEntity<Resource> getPublicVideo(@PathVariable String filename) {
|
||||
log.info("[PublicAsset] Access request for video: {}", filename);
|
||||
try {
|
||||
if (!minIOService.fileExists(filename)) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
InputStream is = minIOService.downloadFile(filename);
|
||||
InputStreamResource resource = new InputStreamResource(is);
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.header(HttpHeaders.CONTENT_TYPE, "video/mp4")
|
||||
.header(HttpHeaders.CACHE_CONTROL, "public, max-age=3600")
|
||||
.body(resource);
|
||||
} catch (Exception e) {
|
||||
log.error("[PublicAsset] Failed to serve public video {}: {}", filename, e.getMessage());
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,12 +190,15 @@ public class TargetingCampaignController {
|
||||
@PathVariable String id) {
|
||||
String userId = resolveUserId(userIdHeader, authHeader);
|
||||
TargetingCampaign campaign = campaignService.getCampaignById(id, userId);
|
||||
return ResponseEntity.ok(Map.of(
|
||||
"id", campaign.getId(),
|
||||
"status", campaign.getStatus(),
|
||||
"completedAt", campaign.getCompletedAt() != null ? campaign.getCompletedAt().toString() : "",
|
||||
"statusHistory", campaign.getStatusHistory() != null ? campaign.getStatusHistory() : List.of()
|
||||
));
|
||||
String status = campaign.getStatus();
|
||||
boolean isTerminal = "active".equals(status) || "failed".equals(status) || "paused".equals(status);
|
||||
java.util.Map<String, Object> response = new java.util.LinkedHashMap<>();
|
||||
response.put("id", campaign.getId());
|
||||
response.put("status", status);
|
||||
response.put("isTerminal", isTerminal);
|
||||
response.put("completedAt", campaign.getCompletedAt() != null ? campaign.getCompletedAt().toString() : null);
|
||||
response.put("statusHistory", campaign.getStatusHistory() != null ? campaign.getStatusHistory() : List.of());
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
// ── AI Предсказания ───────────────────────────────────────────────────────
|
||||
|
||||
@@ -18,6 +18,8 @@ import kz.konturai.parser.enums.CampaignObjective;
|
||||
import kz.konturai.parser.util.RangeParser;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
@@ -49,6 +51,10 @@ public class TargetingCampaignService {
|
||||
private final MarketingStrategyRepository strategyRepository;
|
||||
private final CampaignPredictionService predictionService;
|
||||
|
||||
// Self-reference through Spring proxy so @Async works (avoids self-invocation bypass)
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
public TargetingCampaign createCampaign(TargetingCampaignRequest req, String userId) {
|
||||
if (req.getStrategyId() == null || req.getStrategyId().isBlank()) {
|
||||
throw new IllegalArgumentException("strategyId is required");
|
||||
@@ -157,8 +163,8 @@ public class TargetingCampaignService {
|
||||
addStatusHistory(campaign, "CREATED", CampaignStatusMessage.CREATED.getMessage());
|
||||
TargetingCampaign saved = repository.save(campaign);
|
||||
|
||||
// Process Async
|
||||
processAsync(saved.getId(), req, userId);
|
||||
// Process Async — вызываем через Spring proxy чтобы @Async работал корректно
|
||||
applicationContext.getBean(TargetingCampaignService.class).processAsync(saved.getId(), req, userId);
|
||||
|
||||
return saved;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user