diff --git a/src/main/java/kz/konturai/parser/controller/MarketingAnalysisV3Controller.java b/src/main/java/kz/konturai/parser/controller/MarketingAnalysisV3Controller.java index ec57b2a..4e92ae8 100644 --- a/src/main/java/kz/konturai/parser/controller/MarketingAnalysisV3Controller.java +++ b/src/main/java/kz/konturai/parser/controller/MarketingAnalysisV3Controller.java @@ -38,6 +38,7 @@ public class MarketingAnalysisV3Controller { private final MinIOService minIOService; private final JwtService jwtService; + // ЕДИНЫЙ МЕТОД ДЛЯ ИЗВЛЕЧЕНИЯ USER ID ИЗ JWT (КАК В СТАРОМ КОНТРОЛЛЕРЕ) private String extractUserIdFromHeader(String authHeader) { if (authHeader == null || authHeader.isEmpty()) { return null; @@ -45,7 +46,7 @@ public class MarketingAnalysisV3Controller { try { return jwtService.extractUserIdFromHeader(authHeader); } catch (Exception e) { - log.error("Error extracting userId: {}", e.getMessage()); + log.error("Error extracting userId from JWT: {}", e.getMessage()); return null; } } @@ -153,31 +154,50 @@ public class MarketingAnalysisV3Controller { /** * ГЕНЕРАЦИЯ СТРАТЕГИИ: Принимает настройки и файл логотипа (опционально) + * ИСПОЛЬЗУЕТ JWT ДЛЯ АВТОРИЗАЦИИ (БЕЗ РУЧНОГО USER-ID) */ @PostMapping(value = "/{analysisId}/strategy/generate", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public ResponseEntity generateStrategy( + public ResponseEntity generateStrategy( + @RequestHeader(value = "Authorization", required = false) String authHeader, @PathVariable String analysisId, - // Данные стратегии принимаем как отдельную часть формы (в Postman это будет текст/JSON) - @RequestPart("request") MarketingStrategyRequest request, - // Файл принимаем как MultipartFile - @RequestPart(value = "logo", required = false) MultipartFile logoFile, - @RequestHeader("User-Id") String userId) { + @RequestPart("request") @Valid MarketingStrategyRequest request, + @RequestPart(value = "logo", required = false) MultipartFile logoFile + ) { + // Достаем ID пользователя из JWT токена + String userId = extractUserIdFromHeader(authHeader); + if (userId == null) return unauthorizedResponse(); - String uploadedLogoFilename = null; + try { + // Проверяем доступ к анализу + Optional analysisOpt = analysisService.getAnalysisById(analysisId); + if (analysisOpt.isEmpty()) return notFoundResponse("Анализ не найден"); + if (!analysisOpt.get().getUserId().equals(userId)) return forbiddenResponse(); - // Если файл прислали, сохраняем его в MinIO - if (logoFile != null && !logoFile.isEmpty()) { - try { - uploadedLogoFilename = "logo_" + System.currentTimeMillis() + "_" + logoFile.getOriginalFilename(); - minIOService.uploadFile(uploadedLogoFilename, logoFile.getBytes(), logoFile.getContentType()); - } catch (Exception e) { - return ResponseEntity.internalServerError().build(); + String logoFilename = null; + + // Если юзер прикрепил логотип, сохраняем его в MinIO + if (logoFile != null && !logoFile.isEmpty()) { + String originalExt = logoFile.getOriginalFilename() != null && logoFile.getOriginalFilename().contains(".") ? + logoFile.getOriginalFilename().substring(logoFile.getOriginalFilename().lastIndexOf(".")) : ".png"; + logoFilename = "logo_" + UUID.randomUUID() + originalExt; + minIOService.uploadFile(logoFilename, logoFile.getBytes(), logoFile.getContentType()); + log.info("Логотип клиента успешно загружен в MinIO: {}", logoFilename); } - } - // Передаем имя файла дальше в твой сервис - MarketingStrategy strategy = strategyService.generateStrategy(analysisId, request, userId, uploadedLogoFilename); - return ResponseEntity.ok(strategy); + // Запускаем полную генерацию, передавая userId из токена + MarketingStrategy strategy = strategyService.generateStrategy(analysisId, request, userId, logoFilename); + + Map responseData = Map.of( + "strategyId", strategy.getId(), + "status", strategy.getStatus(), + "message", "Генерация стратегии и медиафайлов успешно запущена" + ); + return ResponseEntity.accepted().body(ApiResponse.success("Запущено", responseData)); + + } catch (Exception e) { + log.error("Failed to generate strategy for analysis: {}", analysisId, e); + return internalErrorResponse(e); + } } /** @@ -192,7 +212,6 @@ public class MarketingAnalysisV3Controller { if (userId == null) return unauthorizedResponse(); try { - // Предполагается, что в MarketingStrategyV3Service есть метод getStrategyById Optional strategyOpt = strategyService.getStrategyById(strategyId); if (strategyOpt.isEmpty()) return notFoundResponse("Стратегия не найдена"); @@ -207,7 +226,7 @@ public class MarketingAnalysisV3Controller { } // ========================================== - // БЛОК 3: ОБРАБОТКА ОШИБОК + // БЛОК 3: ОБРАБОТКА ОШИБОК И ОТВЕТЫ // ========================================== @ExceptionHandler(MethodArgumentNotValidException.class) @@ -222,12 +241,12 @@ public class MarketingAnalysisV3Controller { private ResponseEntity> unauthorizedResponse() { return ResponseEntity.status(HttpStatus.UNAUTHORIZED) - .body(ApiResponse.error("Не авторизован", new ErrorResponse("UNAUTHORIZED", "Требуется авторизация"))); + .body(ApiResponse.error("Не авторизован", new ErrorResponse("UNAUTHORIZED", "Требуется авторизация. Предоставьте валидный JWT токен."))); } private ResponseEntity> forbiddenResponse() { return ResponseEntity.status(HttpStatus.FORBIDDEN) - .body(ApiResponse.error("Доступ запрещен", new ErrorResponse("FORBIDDEN", "Нет доступа"))); + .body(ApiResponse.error("Доступ запрещен", new ErrorResponse("FORBIDDEN", "У вас нет прав для доступа к этому ресурсу."))); } private ResponseEntity> notFoundResponse(String message) {