.
This commit is contained in:
@@ -659,6 +659,85 @@ public class MarketingController {
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/tasks/{taskId}/execute")
|
||||
public ResponseEntity<?> executeTaskManually(
|
||||
@RequestHeader(value = "Authorization", required = false) String authHeader,
|
||||
@PathVariable String taskId) {
|
||||
|
||||
String userId = extractUserIdFromHeader(authHeader);
|
||||
if (userId == null) {
|
||||
return unauthorizedResponse();
|
||||
}
|
||||
|
||||
// Проверяем существование задачи и права доступа
|
||||
Optional<PostingTask> optTask = postingTaskService.getTaskById(taskId);
|
||||
if (optTask.isEmpty()) {
|
||||
ErrorResponse error = new ErrorResponse(
|
||||
"NOT_FOUND",
|
||||
"Задача с указанным ID не найдена");
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("Задача не найдена", error));
|
||||
}
|
||||
|
||||
PostingTask task = optTask.get();
|
||||
if (!userId.equals(task.getUserId())) {
|
||||
ErrorResponse error = new ErrorResponse(
|
||||
"FORBIDDEN",
|
||||
"У вас нет доступа к этой задаче");
|
||||
return ResponseEntity.status(HttpStatus.FORBIDDEN)
|
||||
.body(ApiResponse.error("Доступ запрещен", error));
|
||||
}
|
||||
|
||||
try {
|
||||
// Запускаем задачу вручную
|
||||
postingTaskService.executeTaskManually(taskId);
|
||||
|
||||
// Получаем обновленную задачу для ответа
|
||||
Optional<PostingTask> updatedTask = postingTaskService.getTaskById(taskId);
|
||||
if (updatedTask.isPresent()) {
|
||||
PostingTask taskData = updatedTask.get();
|
||||
Map<String, Object> responseData = new HashMap<>();
|
||||
responseData.put("taskId", taskData.getId());
|
||||
responseData.put("status", taskData.getStatus());
|
||||
responseData.put("platform", taskData.getPlatform());
|
||||
responseData.put("publishDate", taskData.getPublishDate());
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
"Задача успешно запущена",
|
||||
responseData));
|
||||
} else {
|
||||
// Если задача не найдена после выполнения (маловероятно)
|
||||
Map<String, Object> responseData = new HashMap<>();
|
||||
responseData.put("taskId", taskId);
|
||||
responseData.put("status", "processing");
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(
|
||||
"Задача успешно запущена",
|
||||
responseData));
|
||||
}
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
ErrorResponse error = new ErrorResponse(
|
||||
"NOT_FOUND",
|
||||
e.getMessage());
|
||||
return ResponseEntity.status(404)
|
||||
.body(ApiResponse.error("Задача не найдена", error));
|
||||
} catch (IllegalStateException e) {
|
||||
ErrorResponse error = new ErrorResponse(
|
||||
"INVALID_STATUS",
|
||||
e.getMessage());
|
||||
return ResponseEntity.status(400)
|
||||
.body(ApiResponse.error("Задача не может быть запущена", error));
|
||||
} catch (Exception e) {
|
||||
logger.error("Error executing task {} manually: {}", taskId, e.getMessage(), e);
|
||||
ErrorResponse error = new ErrorResponse(
|
||||
"INTERNAL_SERVER_ERROR",
|
||||
"Произошла ошибка при запуске задачи");
|
||||
return ResponseEntity.status(500)
|
||||
.body(ApiResponse.error("Внутренняя ошибка сервера", error));
|
||||
}
|
||||
}
|
||||
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public ResponseEntity<ApiResponse<ErrorResponse>> handleValidationException(
|
||||
MethodArgumentNotValidException ex) {
|
||||
|
||||
@@ -16,7 +16,9 @@ public class MarketingStrategyResponse {
|
||||
public MarketingStrategyResponse() {
|
||||
}
|
||||
|
||||
public MarketingStrategyResponse(String strategyId, String analysisId, String status, LocalDateTime createdAt, LocalDateTime completedAt, Integer durationWeeks, List<String> priorityPlatforms, StrategyContent strategy) {
|
||||
public MarketingStrategyResponse(String strategyId, String analysisId, String status, LocalDateTime createdAt,
|
||||
LocalDateTime completedAt, Integer durationWeeks, List<String> priorityPlatforms,
|
||||
StrategyContent strategy) {
|
||||
this.strategyId = strategyId;
|
||||
this.analysisId = analysisId;
|
||||
this.status = status;
|
||||
@@ -129,7 +131,8 @@ public class MarketingStrategyResponse {
|
||||
public WeeklyPlan() {
|
||||
}
|
||||
|
||||
public WeeklyPlan(Integer weekNumber, List<String> mainThemes, String contentRecommendations, List<String> priorityPlatforms) {
|
||||
public WeeklyPlan(Integer weekNumber, List<String> mainThemes, String contentRecommendations,
|
||||
List<String> priorityPlatforms) {
|
||||
this.weekNumber = weekNumber;
|
||||
this.mainThemes = mainThemes;
|
||||
this.contentRecommendations = contentRecommendations;
|
||||
@@ -179,11 +182,13 @@ public class MarketingStrategyResponse {
|
||||
private String publishTime;
|
||||
private String imageUrl;
|
||||
private String imageFilename;
|
||||
private String taskId;
|
||||
|
||||
public PostCalendarItem() {
|
||||
}
|
||||
|
||||
public PostCalendarItem(LocalDateTime publishDate, String platform, String contentType, String theme, String postText, List<String> hashtags, String publishTime) {
|
||||
public PostCalendarItem(LocalDateTime publishDate, String platform, String contentType, String theme,
|
||||
String postText, List<String> hashtags, String publishTime) {
|
||||
this.publishDate = publishDate;
|
||||
this.platform = platform;
|
||||
this.contentType = contentType;
|
||||
@@ -264,6 +269,13 @@ public class MarketingStrategyResponse {
|
||||
public void setImageFilename(String imageFilename) {
|
||||
this.imageFilename = imageFilename;
|
||||
}
|
||||
|
||||
public String getTaskId() {
|
||||
return taskId;
|
||||
}
|
||||
|
||||
public void setTaskId(String taskId) {
|
||||
this.taskId = taskId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import kz.konturai.parser.dto.MarketingStrategyResponse;
|
||||
import kz.konturai.parser.dto.StatusHistoryEntry;
|
||||
import kz.konturai.parser.model.MarketingAnalysis;
|
||||
import kz.konturai.parser.model.MarketingStrategy;
|
||||
import kz.konturai.parser.model.PostingTask;
|
||||
import kz.konturai.parser.repository.MarketingAnalysisRepository;
|
||||
import kz.konturai.parser.repository.MarketingStrategyRepository;
|
||||
import org.slf4j.Logger;
|
||||
@@ -32,6 +33,7 @@ public class MarketingStrategyService {
|
||||
private final OpenAIAnalyticsService openAIAnalyticsService;
|
||||
private final OpenAIImageGenerationService imageGenerationService;
|
||||
private final MinIOService minIOService;
|
||||
private final PostingTaskService postingTaskService;
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
public MarketingStrategyService(
|
||||
@@ -40,13 +42,15 @@ public class MarketingStrategyService {
|
||||
MarketingAnalysisRepository analysisRepository,
|
||||
OpenAIAnalyticsService openAIAnalyticsService,
|
||||
OpenAIImageGenerationService imageGenerationService,
|
||||
MinIOService minIOService) {
|
||||
MinIOService minIOService,
|
||||
PostingTaskService postingTaskService) {
|
||||
this.repository = repository;
|
||||
this.marketingAnalysisService = marketingAnalysisService;
|
||||
this.analysisRepository = analysisRepository;
|
||||
this.openAIAnalyticsService = openAIAnalyticsService;
|
||||
this.imageGenerationService = imageGenerationService;
|
||||
this.minIOService = minIOService;
|
||||
this.postingTaskService = postingTaskService;
|
||||
}
|
||||
|
||||
public MarketingStrategy generateStrategy(String analysisId, MarketingStrategyRequest request, String userId) {
|
||||
@@ -615,8 +619,11 @@ public class MarketingStrategyService {
|
||||
}
|
||||
strategyContent.setWeeklyPlans(weeklyPlans);
|
||||
|
||||
// Convert PostCalendarItems
|
||||
// Convert PostCalendarItems and add taskId if tasks exist
|
||||
List<MarketingStrategyResponse.PostCalendarItem> postCalendar = new ArrayList<>();
|
||||
// Получаем все задачи для этой стратегии
|
||||
List<PostingTask> tasks = postingTaskService.getStrategyTasks(strategyId);
|
||||
|
||||
for (MarketingStrategy.PostCalendarItem item : strategy.getPostCalendar()) {
|
||||
MarketingStrategyResponse.PostCalendarItem dtoItem = new MarketingStrategyResponse.PostCalendarItem();
|
||||
dtoItem.setPublishDate(item.getPublishDate());
|
||||
@@ -628,6 +635,21 @@ public class MarketingStrategyService {
|
||||
dtoItem.setPublishTime(item.getPublishTime());
|
||||
dtoItem.setImageUrl(item.getImageUrl());
|
||||
dtoItem.setImageFilename(item.getImageFilename());
|
||||
|
||||
// Находим соответствующую задачу по дате публикации, платформе и тексту поста
|
||||
Optional<PostingTask> matchingTask = tasks.stream()
|
||||
.filter(task -> task.getPublishDate() != null && item.getPublishDate() != null
|
||||
&& task.getPublishDate().equals(item.getPublishDate())
|
||||
&& task.getPlatform() != null && item.getPlatform() != null
|
||||
&& task.getPlatform().equalsIgnoreCase(item.getPlatform())
|
||||
&& task.getPostText() != null && item.getPostText() != null
|
||||
&& task.getPostText().equals(item.getPostText()))
|
||||
.findFirst();
|
||||
|
||||
if (matchingTask.isPresent()) {
|
||||
dtoItem.setTaskId(matchingTask.get().getId());
|
||||
}
|
||||
|
||||
postCalendar.add(dtoItem);
|
||||
}
|
||||
strategyContent.setPostCalendar(postCalendar);
|
||||
|
||||
@@ -225,6 +225,44 @@ public class PostingTaskService {
|
||||
executeTask(taskId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ручное выполнение задачи публикации (независимо от времени публикации)
|
||||
* Разрешает выполнение только для задач со статусом "pending" или "failed"
|
||||
*
|
||||
* @param taskId ID задачи
|
||||
* @throws IllegalArgumentException если задача не найдена
|
||||
* @throws IllegalStateException если задача уже выполнена или имеет
|
||||
* недопустимый статус
|
||||
*/
|
||||
public void executeTaskManually(String taskId) {
|
||||
Optional<PostingTask> optTask = taskRepository.findById(taskId);
|
||||
if (optTask.isEmpty()) {
|
||||
throw new IllegalArgumentException("Task not found: " + taskId);
|
||||
}
|
||||
|
||||
PostingTask task = optTask.get();
|
||||
|
||||
// Проверяем статус - разрешаем только pending или failed
|
||||
String status = task.getStatus();
|
||||
if (!"pending".equals(status) && !"failed".equals(status)) {
|
||||
throw new IllegalStateException(
|
||||
"Task cannot be executed manually. Current status: " + status +
|
||||
". Only tasks with status 'pending' or 'failed' can be executed manually.");
|
||||
}
|
||||
|
||||
// Если задача в статусе failed, сбрасываем статус на pending для повторной
|
||||
// попытки
|
||||
if ("failed".equals(status)) {
|
||||
task.setStatus("pending");
|
||||
task.setErrorMessage(null);
|
||||
taskRepository.save(task);
|
||||
logger.info("Task {} status reset from 'failed' to 'pending' for manual execution", taskId);
|
||||
}
|
||||
|
||||
// Выполняем задачу (игнорируя время публикации)
|
||||
executeTask(taskId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает задачи пользователя
|
||||
*
|
||||
@@ -244,4 +282,14 @@ public class PostingTaskService {
|
||||
public List<PostingTask> getStrategyTasks(String strategyId) {
|
||||
return taskRepository.findByStrategyId(strategyId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает задачу по ID
|
||||
*
|
||||
* @param taskId ID задачи
|
||||
* @return Optional с задачей, если найдена
|
||||
*/
|
||||
public Optional<PostingTask> getTaskById(String taskId) {
|
||||
return taskRepository.findById(taskId);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user