target fix

This commit is contained in:
arys
2026-04-14 09:27:02 +05:00
parent 3abdc34e60
commit 6f3421205a
@@ -7,6 +7,7 @@ import kz.konturai.parser.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.util.StringUtils;
@@ -35,11 +36,13 @@ public class TargetingCampaignController {
if (StringUtils.hasText(userIdHeader)) {
return userIdHeader;
}
try {
String userId = jwtService.extractUserIdFromHeader(authHeader);
if (userId == null) {
throw new IllegalArgumentException("Cannot resolve user identity: X-User-Id header or valid Authorization token required");
return userId; // Может быть null если токен истёк
} catch (Exception e) {
log.warn("[Targeting] Failed to extract userId from token: {}", e.getMessage());
return null;
}
return userId;
}
@PostMapping("/campaigns")
@@ -48,6 +51,8 @@ public class TargetingCampaignController {
@RequestHeader(value = "Authorization", required = false) String authHeader,
@RequestBody TargetingCampaignRequest request) {
String userId = resolveUserId(userIdHeader, authHeader);
if (userId == null)
return unauthorizedResponse();
log.info("[Targeting] Create campaign requested by {}", userId);
return ResponseEntity.ok(campaignService.createCampaign(request, userId));
}
@@ -59,6 +64,8 @@ public class TargetingCampaignController {
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
String userId = resolveUserId(userIdHeader, authHeader);
if (userId == null)
return unauthorizedResponse();
log.info("[Targeting] Get campaigns for {}", userId);
return ResponseEntity.ok(campaignService.getUserCampaigns(userId, page, size));
}
@@ -69,6 +76,8 @@ public class TargetingCampaignController {
@RequestHeader(value = "Authorization", required = false) String authHeader,
@PathVariable String id) {
String userId = resolveUserId(userIdHeader, authHeader);
if (userId == null)
return unauthorizedResponse();
log.info("[Targeting] Get campaign {} for {}", id, userId);
return ResponseEntity.ok(campaignService.getCampaignById(id, userId));
}
@@ -79,6 +88,8 @@ public class TargetingCampaignController {
@RequestHeader(value = "Authorization", required = false) String authHeader,
@PathVariable String id) {
String userId = resolveUserId(userIdHeader, authHeader);
if (userId == null)
return unauthorizedResponse();
log.info("[Targeting] Pause campaign {}", id);
return ResponseEntity.ok(campaignService.pauseCampaign(id, userId));
}
@@ -89,6 +100,8 @@ public class TargetingCampaignController {
@RequestHeader(value = "Authorization", required = false) String authHeader,
@PathVariable String id) {
String userId = resolveUserId(userIdHeader, authHeader);
if (userId == null)
return unauthorizedResponse();
log.info("[Targeting] Resume campaign {}", id);
return ResponseEntity.ok(campaignService.resumeCampaign(id, userId));
}
@@ -100,6 +113,8 @@ public class TargetingCampaignController {
@PathVariable String id,
@RequestParam(defaultValue = "last_7d") String datePreset) {
String userId = resolveUserId(userIdHeader, authHeader);
if (userId == null)
return unauthorizedResponse();
log.info("[Targeting] Get insights for campaign {}", id);
return ResponseEntity.ok(campaignService.getCampaignInsights(id, userId, datePreset));
}
@@ -110,6 +125,8 @@ public class TargetingCampaignController {
@RequestHeader(value = "Authorization", required = false) String authHeader,
@PathVariable String id) {
String userId = resolveUserId(userIdHeader, authHeader);
if (userId == null)
return unauthorizedResponse();
log.info("[Targeting] Force sync insights for campaign {}", id);
campaignService.getCampaignById(id, userId);
campaignService.syncInsights(id);
@@ -122,6 +139,8 @@ public class TargetingCampaignController {
@RequestHeader(value = "Authorization", required = false) String authHeader,
@PathVariable String id) {
String userId = resolveUserId(userIdHeader, authHeader);
if (userId == null)
return unauthorizedResponse();
log.info("[Targeting] Evaluate AB Test for {}", id);
TargetingCampaign campaign = campaignService.getCampaignById(id, userId);
return ResponseEntity.ok(abTestingService.evaluateABTest(campaign));
@@ -158,6 +177,8 @@ public class TargetingCampaignController {
@RequestHeader(value = "Authorization", required = false) String authHeader,
@RequestBody Map<String, String> body) {
String userId = resolveUserId(userIdHeader, authHeader);
if (userId == null)
return unauthorizedResponse();
String campaignId = body.get("campaignId");
log.info("[Targeting] Optimize budget for campaign {}", campaignId);
TargetingCampaign campaign = campaignService.getCampaignById(campaignId, userId);
@@ -173,6 +194,8 @@ public class TargetingCampaignController {
@RequestHeader(value = "Authorization", required = false) String authHeader,
@RequestBody Map<String, String> body) {
String userId = resolveUserId(userIdHeader, authHeader);
if (userId == null)
return unauthorizedResponse();
String platform = body.get("platform");
String adAccountId = body.get("adAccountId");
@@ -190,6 +213,8 @@ public class TargetingCampaignController {
@RequestHeader(value = "Authorization", required = false) String authHeader,
@PathVariable String id) {
String userId = resolveUserId(userIdHeader, authHeader);
if (userId == null)
return unauthorizedResponse();
TargetingCampaign campaign = campaignService.getCampaignById(id, userId);
String status = campaign.getStatus();
boolean isTerminal = "active".equals(status) || "failed".equals(status) || "paused".equals(status);
@@ -210,6 +235,8 @@ public class TargetingCampaignController {
@RequestHeader(value = "Authorization", required = false) String authHeader,
@PathVariable String id) {
String userId = resolveUserId(userIdHeader, authHeader);
if (userId == null)
return unauthorizedResponse();
// Проверяем существование кампании и права доступа
TargetingCampaign campaign = campaignService.getCampaignById(id, userId);
@@ -224,8 +251,7 @@ public class TargetingCampaignController {
return ResponseEntity.accepted().body(Map.of(
"status", "PROCESSING",
"message", "Предсказание еще не готово и было запущено автоматически. Попробуйте через 5-10 секунд."
));
"message", "Предсказание еще не готово и было запущено автоматически. Попробуйте через 5-10 секунд."));
}
@PostMapping("/campaigns/{id}/predict")
@@ -234,6 +260,8 @@ public class TargetingCampaignController {
@RequestHeader(value = "Authorization", required = false) String authHeader,
@PathVariable String id) {
String userId = resolveUserId(userIdHeader, authHeader);
if (userId == null)
return unauthorizedResponse();
TargetingCampaign campaign = campaignService.getCampaignById(id, userId);
log.info("[Targeting] Manual predict trigger for campaign {}", id);
predictionService.generateAsync(campaign);
@@ -248,6 +276,8 @@ public class TargetingCampaignController {
@RequestHeader(value = "Authorization", required = false) String authHeader,
@PathVariable String id) {
String userId = resolveUserId(userIdHeader, authHeader);
if (userId == null)
return unauthorizedResponse();
TargetingCampaign campaign = campaignService.getCampaignById(id, userId);
return ResponseEntity.ok(campaign.getInsights() != null ? campaign.getInsights() : List.of());
}
@@ -260,6 +290,8 @@ public class TargetingCampaignController {
@RequestHeader(value = "Authorization", required = false) String authHeader,
@PathVariable String id) {
String userId = resolveUserId(userIdHeader, authHeader);
if (userId == null)
return unauthorizedResponse();
log.info("[Targeting] Retry campaign {}", id);
return ResponseEntity.ok(campaignService.retryCampaign(id, userId));
}
@@ -273,6 +305,8 @@ public class TargetingCampaignController {
@PathVariable String id,
@RequestBody Map<String, Double> body) {
String userId = resolveUserId(userIdHeader, authHeader);
if (userId == null)
return unauthorizedResponse();
log.info("[Targeting] Update budget for campaign {}", id);
return ResponseEntity.ok(campaignService.updateBudget(id, userId,
body.get("totalBudget"), body.get("dailyBudget")));
@@ -285,6 +319,8 @@ public class TargetingCampaignController {
@PathVariable String id,
@RequestBody TargetingAudienceProfile audience) {
String userId = resolveUserId(userIdHeader, authHeader);
if (userId == null)
return unauthorizedResponse();
log.info("[Targeting] Update audience for campaign {}", id);
return ResponseEntity.ok(campaignService.updateAudience(id, userId, audience));
}
@@ -297,6 +333,8 @@ public class TargetingCampaignController {
@RequestHeader(value = "Authorization", required = false) String authHeader,
@PathVariable String strategyId) {
String userId = resolveUserId(userIdHeader, authHeader);
if (userId == null)
return unauthorizedResponse();
log.info("[Targeting] Direct Facebook publish for strategy {} requested by {}", strategyId, userId);
try {
@@ -304,26 +342,30 @@ public class TargetingCampaignController {
return ResponseEntity.ok(Map.of(
"success", true,
"message", "Пост успешно опубликован в Facebook",
"postId", postId
));
"postId", postId));
} catch (IllegalArgumentException | IllegalStateException e) {
return ResponseEntity.badRequest().body(Map.of("success", false, "error", e.getMessage()));
} catch (kz.konturai.parser.exception.FacebookTokenExpiredException e) {
log.error("Facebook token expired: {}", e.getMessage());
return ResponseEntity.badRequest().body(Map.of("success", false, "error", "Токен Facebook истёк. Пожалуйста, обновите токен (facebook.page.token) в файле application.properties."));
return ResponseEntity.badRequest().body(Map.of("success", false, "error",
"Токен Facebook истёк. Пожалуйста, обновите токен (facebook.page.token) в файле application.properties."));
} catch (RuntimeException e) {
if (e.getMessage() != null && e.getMessage().contains("[Facebook] API Error")) {
log.error("Facebook API Error: {}", e.getMessage());
if (e.getMessage().contains("publish_actions")) {
return ResponseEntity.badRequest().body(Map.of("success", false, "error", "Указан токен Пользователя, а не Страницы (User Token). Facebook запрещает публикацию через личные токены. Сгенерируйте именно Page Access Token."));
return ResponseEntity.badRequest().body(Map.of("success", false, "error",
"Указан токен Пользователя, а не Страницы (User Token). Facebook запрещает публикацию через личные токены. Сгенерируйте именно Page Access Token."));
}
return ResponseEntity.badRequest().body(Map.of("success", false, "error", "Ошибка со стороны Facebook API: " + e.getMessage()));
return ResponseEntity.badRequest()
.body(Map.of("success", false, "error", "Ошибка со стороны Facebook API: " + e.getMessage()));
}
log.error("Failed to publish post: ", e);
return ResponseEntity.internalServerError().body(Map.of("success", false, "error", "Не удалось опубликовать пост"));
return ResponseEntity.internalServerError()
.body(Map.of("success", false, "error", "Не удалось опубликовать пост"));
} catch (Exception e) {
log.error("Failed to publish post: ", e);
return ResponseEntity.internalServerError().body(Map.of("success", false, "error", "Не удалось опубликовать пост"));
return ResponseEntity.internalServerError()
.body(Map.of("success", false, "error", "Не удалось опубликовать пост"));
}
}
@@ -335,6 +377,8 @@ public class TargetingCampaignController {
@RequestHeader(value = "Authorization", required = false) String authHeader,
@PathVariable String id) {
String userId = resolveUserId(userIdHeader, authHeader);
if (userId == null)
return unauthorizedResponse();
return ResponseEntity.ok(campaignService.getAdSets(id, userId));
}
@@ -346,7 +390,27 @@ public class TargetingCampaignController {
@PathVariable String adSetId,
@RequestBody TargetingAdSet adSet) {
String userId = resolveUserId(userIdHeader, authHeader);
if (userId == null)
return unauthorizedResponse();
log.info("[Targeting] Update adSet {} for campaign {}", adSetId, id);
return ResponseEntity.ok(campaignService.updateAdSet(id, adSetId, userId, adSet));
}
// ── Helper methods ───────────────────────────────────────────────────────
@SuppressWarnings("unchecked")
private <T> ResponseEntity<T> unauthorizedResponse() {
return (ResponseEntity<T>) ResponseEntity.status(HttpStatus.UNAUTHORIZED)
.body(ApiResponse.error(
"Не авторизован",
new ErrorResponse("UNAUTHORIZED", "Требуется авторизация. Предоставьте валидный JWT токен.")));
}
@SuppressWarnings("unchecked")
private <T> ResponseEntity<T> forbiddenResponse() {
return (ResponseEntity<T>) ResponseEntity.status(HttpStatus.FORBIDDEN)
.body(ApiResponse.error(
"Доступ запрещён",
new ErrorResponse("FORBIDDEN", "У вас нет прав для доступа к этому ресурсу.")));
}
}