From 19c7213ebb7b992dc7a99915bfd4748c91a6e1b3 Mon Sep 17 00:00:00 2001 From: arys Date: Thu, 29 Jan 2026 21:33:17 +0500 Subject: [PATCH] fix --- .../service/FacebookPostingService.java | 163 +++++++----------- .../parser/service/PostingTaskService.java | 30 ++-- 2 files changed, 76 insertions(+), 117 deletions(-) diff --git a/src/main/java/kz/konturai/parser/service/FacebookPostingService.java b/src/main/java/kz/konturai/parser/service/FacebookPostingService.java index ffcd2e3..346ace0 100644 --- a/src/main/java/kz/konturai/parser/service/FacebookPostingService.java +++ b/src/main/java/kz/konturai/parser/service/FacebookPostingService.java @@ -30,12 +30,9 @@ public class FacebookPostingService { private static final Logger logger = LoggerFactory.getLogger(FacebookPostingService.class); private static final String FACEBOOK_GRAPH_API_BASE = "https://graph.facebook.com/v19.0"; - - private static final String HARDCODED_PAGE_TOKEN = "EAAaocqgT3JoBQor7WTel65wL4q11uOZBvIkjbuZAU06mBmmEUJUP27ep6oKM3gSNkx6DYFg7NWQfXkKiI0ZByfVCMgqrsBTcshWK8OROp5l5kwZBOZCfuWhmRrxXeisu1WWh2dfadqoRGq8G83iFR82UqPhZCZANxH8kyDAlDLR5TIjZB0HE3y4rbawUzRflruzQoQfKhGUxSGWSQdLy5s3IGsBNmZClVjfdQu6XZA6QyCPZBsL"; - + private static final String HARDCODED_PAGE_TOKEN = "EAAaocqgT3JoBQjjUQwZB0jsJ5ZCLjZCgLbTY4sqL0BBvR3II5AeYrrYaZBrAXLoEYOJEYL0tj9kkeZCZA5q3ZAiq7GxdoECSTfQKzQlSlzZBN5wfzOQOyoWXNpPIobbcWZAkcEeIDSZAiqdQxjZAvpCm0RJtvMaIruzmnSZCCbQvD3q4L3w8xjBXGTraKZCZApKPvtPjo2yEpWXuxVkXZBxFAN2AHz7rZAxHGG42qFuZCwrY0GKpxJadDl8kyOSDYiFvOi0gUhkPAW7jO4Gx9o3KoZCiLWtVxU"; private static final String HARDCODED_PAGE_ID = "918835061309575"; - private final WebClient webClient; private final ObjectMapper objectMapper; @@ -54,22 +51,12 @@ public class FacebookPostingService { this.objectMapper = new ObjectMapper(); } - /** - * Этот метод теперь просто возвращает хардкодные данные. - * Мы НЕ делаем запрос к /me/accounts, чтобы избежать ошибки 400. - */ public PageCredentials getPageCredentials(String ignoredAccessToken) { - logger.info(">>> HARDCODED MODE: Возвращаем зашитые данные страницы {}", HARDCODED_PAGE_ID); return new PageCredentials(HARDCODED_PAGE_ID, HARDCODED_PAGE_TOKEN); } - // === ОТПРАВКА СООБЩЕНИЯ В ЛИЧКУ === public void sendPrivateMessage(String ignoredToken, String recipientId, String messageText) { - String tokenToUse = HARDCODED_PAGE_TOKEN; - try { - logger.info(">>> MSG SENDING: Отправляем сообщение юзеру {} с хардкодным токеном...", recipientId); - Map recipient = new HashMap<>(); recipient.put("id", recipientId); @@ -81,78 +68,80 @@ public class FacebookPostingService { body.put("message", messageContent); body.put("messaging_type", "RESPONSE"); - String response = webClient.post() - .uri(uriBuilder -> uriBuilder - .path("/me/messages") - .queryParam("access_token", tokenToUse) - .build()) + webClient.post() + .uri(uriBuilder -> uriBuilder.path("/me/messages") + .queryParam("access_token", HARDCODED_PAGE_TOKEN).build()) .contentType(MediaType.APPLICATION_JSON) .bodyValue(body) .retrieve() .bodyToMono(String.class) .block(Duration.ofMillis(timeoutMs)); - logger.info("✅ SUCCESS: Сообщение отправлено! Response: {}", response); - - } catch (WebClientResponseException e) { - logger.error("❌ MSG ERROR: Code={}, Body={}", e.getStatusCode(), e.getResponseBodyAsString()); + logger.info("Message sent to user {}", recipientId); } catch (Exception e) { - logger.error("❌ MSG ERROR: ", e); + logger.error("Failed to send text message: ", e); } } - // === ПУБЛИКАЦИЯ ТЕКСТА === - public String postToPage(String ignoredToken, String postText, List hashtags) throws JsonProcessingException { - String tokenToUse = HARDCODED_PAGE_TOKEN; - String pageIdToUse = HARDCODED_PAGE_ID; - + public void sendPrivateImageMessage(String ignoredToken, String recipientId, byte[] imageData) { try { - String fullPostText = buildPostText(postText, hashtags); - logger.info(">>> POSTING TEXT: Используем PageID={} Token={}...", pageIdToUse, tokenToUse.substring(0, 10)); - - String response = webClient.post() - .uri(uriBuilder -> uriBuilder - .path("/{pageId}/feed") - .queryParam("access_token", tokenToUse) - .queryParam("message", fullPostText) - .build(pageIdToUse)) - .retrieve() - .bodyToMono(String.class) - .block(Duration.ofMillis(timeoutMs)); - - JsonNode jsonNode = objectMapper.readTree(response); - String postId = jsonNode.get("id").asText(); - logger.info("✅ SUCCESS: Текстовый пост опубликован. ID: {}", postId); - return postId; - - } catch (WebClientResponseException e) { - handleFacebookError(e, "postToPage"); - return null; - } - } - - // === ПУБЛИКАЦИЯ КАРТИНКИ === - public String postToPageWithImage(String ignoredToken, String postText, List hashtags, byte[] imageData) { - String tokenToUse = HARDCODED_PAGE_TOKEN; - String pageIdToUse = HARDCODED_PAGE_ID; - - try { - logger.info(">>> POSTING IMAGE: Используем PageID={} Token={}...", pageIdToUse, tokenToUse.substring(0, 10)); - - String fullPostText = buildPostText(postText, hashtags); - ByteArrayResource imageResource = new ByteArrayResource(imageData) { @Override public String getFilename() { return "image.jpg"; } }; + String recipientJson = "{\"id\":\"" + recipientId + "\"}"; + String messageJson = "{\"attachment\":{\"type\":\"image\", \"payload\":{\"is_reusable\":true}}}"; + MultiValueMap formData = new LinkedMultiValueMap<>(); + formData.add("recipient", recipientJson); + formData.add("message", messageJson); + formData.add("filedata", imageResource); + formData.add("access_token", HARDCODED_PAGE_TOKEN); + + webClient.post() + .uri(uriBuilder -> uriBuilder.path("/me/messages").build()) + .contentType(MediaType.MULTIPART_FORM_DATA) + .body(BodyInserters.fromMultipartData(formData)) + .retrieve() + .bodyToMono(String.class) + .block(Duration.ofMillis(timeoutMs * 2)); + + logger.info("Image message sent to user {}", recipientId); + } catch (Exception e) { + logger.error("Failed to send image message: ", e); + } + } + + public String postToPage(String ignoredToken, String postText, List hashtags) throws JsonProcessingException { + return internalPost(postText, hashtags, null); + } + + public String postToPageWithImage(String ignoredToken, String postText, List hashtags, byte[] imageData) { + return internalPost(postText, hashtags, imageData); + } + + private String internalPost(String postText, List hashtags, byte[] imageData) { + try { + String fullPostText = buildPostText(postText, hashtags); + + MultiValueMap formData = new LinkedMultiValueMap<>(); + formData.add("access_token", HARDCODED_PAGE_TOKEN); formData.add("message", fullPostText); - formData.add("source", imageResource); - formData.add("access_token", tokenToUse); + + String endpoint; + + if (imageData != null) { + endpoint = "/{pageId}/photos"; + formData.add("source", new ByteArrayResource(imageData) { + @Override public String getFilename() { return "post.jpg"; } + }); + } else { + endpoint = "/{pageId}/feed"; + } String response = webClient.post() - .uri(uriBuilder -> uriBuilder.path("/{pageId}/photos").build(pageIdToUse)) - .contentType(MediaType.MULTIPART_FORM_DATA) + .uri(uriBuilder -> uriBuilder.path(endpoint).build(HARDCODED_PAGE_ID)) + .contentType(imageData != null ? MediaType.MULTIPART_FORM_DATA : MediaType.APPLICATION_FORM_URLENCODED) .body(BodyInserters.fromMultipartData(formData)) .retrieve() .bodyToMono(String.class) @@ -160,14 +149,14 @@ public class FacebookPostingService { JsonNode jsonNode = objectMapper.readTree(response); String postId = jsonNode.get("id").asText(); - logger.info("✅ SUCCESS: Фото опубликовано. ID: {}", postId); + logger.info("Published to Facebook. ID: {}", postId); return postId; } catch (WebClientResponseException e) { - handleFacebookError(e, "postToPageWithImage"); + handleFacebookError(e, "internalPost"); return null; } catch (Exception e) { - throw new RuntimeException("Failed to post image to Page: " + e.getMessage(), e); + throw new RuntimeException("Error posting: " + e.getMessage(), e); } } @@ -183,44 +172,22 @@ public class FacebookPostingService { return fullText.toString(); } - // Класс сделали публичным, чтобы он был доступен в других пакетах если что, - // но в данном случае он используется как DTO public static class PageCredentials { - public String pageId; - public String pageToken; - public PageCredentials(String pageId, String pageToken) { - this.pageId = pageId; - this.pageToken = pageToken; - } + public String pageId; public String pageToken; + public PageCredentials(String pageId, String pageToken) { this.pageId = pageId; this.pageToken = pageToken; } } private void handleFacebookError(WebClientResponseException e, String context) { - String errorBody = e.getResponseBodyAsString(); - logger.error("❌ FB API ERROR [{}]: Status={}, Body={}", context, e.getStatusCode(), errorBody); - + logger.error("FB API Error [{}]: Body={}", context, e.getResponseBodyAsString()); if (isTokenExpiredError(e)) throw parseFacebookError(e); - throw new RuntimeException("Facebook API Error (" + context + "): " + errorBody, e); + throw new RuntimeException("Facebook API Error: " + e.getResponseBodyAsString(), e); } private boolean isTokenExpiredError(WebClientResponseException e) { - if (e.getStatusCode().value() != 400) return false; - try { - String body = e.getResponseBodyAsString(); - if (body == null) return false; - JsonNode error = objectMapper.readTree(body).get("error"); - if (error == null) return false; - - int code = error.has("code") ? error.get("code").asInt() : 0; - int subcode = error.has("error_subcode") ? error.get("error_subcode").asInt() : 0; - return code == 190 && subcode == 463; - } catch (Exception ex) { - return false; - } + return e.getStatusCode().value() == 400 || e.getStatusCode().value() == 401; } private FacebookTokenExpiredException parseFacebookError(WebClientResponseException e) { - return new FacebookTokenExpiredException( - "Facebook token expired. Please re-login.", - "Token Expired", 190, 463, e); + return new FacebookTokenExpiredException("Token Expired", "Token Expired", 190, 463, e); } } \ No newline at end of file diff --git a/src/main/java/kz/konturai/parser/service/PostingTaskService.java b/src/main/java/kz/konturai/parser/service/PostingTaskService.java index df85dbe..a7c5a85 100644 --- a/src/main/java/kz/konturai/parser/service/PostingTaskService.java +++ b/src/main/java/kz/konturai/parser/service/PostingTaskService.java @@ -23,7 +23,6 @@ import java.util.Optional; public class PostingTaskService { private static final Logger logger = LoggerFactory.getLogger(PostingTaskService.class); - private static final String TEST_RECIPIENT_ID = "25769470256007187"; private final PostingTaskRepository taskRepository; @@ -146,33 +145,26 @@ public class PostingTaskService { if ("facebook".equalsIgnoreCase(task.getPlatform())) { - // 1. ПУБЛИКУЕМ ПОСТ НА СТРАНИЦУ if (imageData != null && imageData.length > 0) { - postId = facebookPostingService.postToPageWithImage( - credentials, - task.getPostText(), - task.getHashtags(), - imageData); + postId = facebookPostingService.postToPageWithImage(credentials, task.getPostText(), task.getHashtags(), imageData); } else { - postId = facebookPostingService.postToPage( - credentials, - task.getPostText(), - task.getHashtags()); + postId = facebookPostingService.postToPage(credentials, task.getPostText(), task.getHashtags()); } - // 2. ОТПРАВЛЯЕМ ЛИЧНОЕ СООБЩЕНИЕ (ЕСЛИ ПОСТ УДАЛСЯ) if (postId != null) { - logger.info("Пост успешно опубликован (ID: {}). Пытаемся отправить уведомление...", postId); - try { - String message = "✅ Ваш пост опубликован на Странице!\nID поста: " + postId + "\nВремя: " + LocalDateTime.now(); + String reportText = "✅ НОВЫЙ ПОСТ ОПУБЛИКОВАН!\n\n" + + "📜 Текст поста:\n" + task.getPostText() + "\n\n" + + "🔗 Ссылка: https://facebook.com/" + postId + "\n" + + "🕒 Время: " + LocalDateTime.now(); - // Отправляем сообщение тебе - facebookPostingService.sendPrivateMessage(credentials, TEST_RECIPIENT_ID, message); + facebookPostingService.sendPrivateMessage(credentials, TEST_RECIPIENT_ID, reportText); - logger.info(">>> SUCCESS: Уведомление отправлено пользователю {}", TEST_RECIPIENT_ID); + if (imageData != null && imageData.length > 0) { + facebookPostingService.sendPrivateImageMessage(credentials, TEST_RECIPIENT_ID, imageData); + } } catch (Exception msgEx) { - logger.warn("Пост опубликован, но не удалось отправить сообщение в личку: {}", msgEx.getMessage()); + logger.warn("Post published but failed to send private notification: {}", msgEx.getMessage()); } }