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