fix
This commit is contained in:
@@ -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<String, Object> 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<String> 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<String> 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<String, Object> 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<String> hashtags) throws JsonProcessingException {
|
||||
return internalPost(postText, hashtags, null);
|
||||
}
|
||||
|
||||
public String postToPageWithImage(String ignoredToken, String postText, List<String> hashtags, byte[] imageData) {
|
||||
return internalPost(postText, hashtags, imageData);
|
||||
}
|
||||
|
||||
private String internalPost(String postText, List<String> hashtags, byte[] imageData) {
|
||||
try {
|
||||
String fullPostText = buildPostText(postText, hashtags);
|
||||
|
||||
MultiValueMap<String, Object> 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);
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user