fix
This commit is contained in:
@@ -28,7 +28,15 @@ import java.util.stream.Collectors;
|
||||
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"; // Updated to v19.0
|
||||
private static final String FACEBOOK_GRAPH_API_BASE = "https://graph.facebook.com/v19.0";
|
||||
|
||||
|
||||
private static final String HARDCODED_PAGE_TOKEN = "EAAaocqgT3JoBQgZAlTa20336ZBM9ao5l8Cm6G4l4A495lzjgg5dFeVr722WkkKPa1KPs4ZAeeIq9bAGWHGbXmJnnIxMxLZCAbVcZBSnvKbFz24qFFEa9uyeIMuwV8RhbQPj5z2WmwuMifBZALxixzoxNCLDJGKuLhEPvZBnMJJlZC8dpZCH2haoVjjxKMgjm46jSDjfo7M0WVhvyIcs0Ki8Mu0XbitHEYBTnfd5AIqARg7ZAZChxlQ3oAng6fFCeHWvgIThk5spR4oJxrgh5qHudskZBEAZDZD";
|
||||
|
||||
// 2. Вставь сюда ID страницы (цифры)
|
||||
private static final String HARDCODED_PAGE_ID = "EAAaocqgT3JoBQjjUQwZB0jsJ5ZCLjZCgLbTY4sqL0BBvR3II5AeYrrYaZBrAXLoEYOJEYL0tj9kkeZCZA5q3ZAiq7GxdoECSTfQKzQlSlzZBN5wfzOQOyoWXNpPIobbcWZAkcEeIDSZAiqdQxjZAvpCm0RJtvMaIruzmnSZCCbQvD3q4L3w8xjBXGTraKZCZApKPvtPjo2yEpWXuxVkXZBxFAN2AHz7rZAxHGG42qFuZCwrY0GKpxJadDl8kyOSDYiFvOi0gUhkPAW7jO4Gx9o3KoZCiLWtVxU";
|
||||
|
||||
// =================================================================================
|
||||
|
||||
private final WebClient webClient;
|
||||
private final ObjectMapper objectMapper;
|
||||
@@ -48,9 +56,22 @@ public class FacebookPostingService {
|
||||
this.objectMapper = new ObjectMapper();
|
||||
}
|
||||
|
||||
// === NEW METHOD FOR MESSAGING ===
|
||||
public void sendPrivateMessage(String pageAccessToken, String recipientId, String messageText) {
|
||||
/**
|
||||
* Этот метод теперь просто возвращает хардкодные данные.
|
||||
* Мы НЕ делаем запрос к /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);
|
||||
|
||||
@@ -65,7 +86,7 @@ public class FacebookPostingService {
|
||||
String response = webClient.post()
|
||||
.uri(uriBuilder -> uriBuilder
|
||||
.path("/me/messages")
|
||||
.queryParam("access_token", pageAccessToken)
|
||||
.queryParam("access_token", tokenToUse)
|
||||
.build())
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.bodyValue(body)
|
||||
@@ -73,46 +94,54 @@ public class FacebookPostingService {
|
||||
.bodyToMono(String.class)
|
||||
.block(Duration.ofMillis(timeoutMs));
|
||||
|
||||
logger.info("Message sent successfully to user {}. Response: {}", recipientId, response);
|
||||
logger.info("✅ SUCCESS: Сообщение отправлено! Response: {}", response);
|
||||
|
||||
} catch (WebClientResponseException e) {
|
||||
logger.error("Failed to send message: {}", e.getResponseBodyAsString());
|
||||
// Don't throw exception here to avoid failing the whole task if message fails
|
||||
logger.error("❌ MSG ERROR: Code={}, Body={}", e.getStatusCode(), e.getResponseBodyAsString());
|
||||
} catch (Exception e) {
|
||||
logger.error("❌ MSG ERROR: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
public String postToPage(String userAccessToken, String postText, List<String> hashtags) throws JsonProcessingException {
|
||||
// === ПУБЛИКАЦИЯ ТЕКСТА ===
|
||||
public String postToPage(String ignoredToken, String postText, List<String> hashtags) throws JsonProcessingException {
|
||||
String tokenToUse = HARDCODED_PAGE_TOKEN;
|
||||
String pageIdToUse = HARDCODED_PAGE_ID;
|
||||
|
||||
try {
|
||||
String fullPostText = buildPostText(postText, hashtags);
|
||||
PageCredentials creds = getPageCredentials(userAccessToken);
|
||||
logger.info(">>> POSTING TEXT: Используем PageID={} Token={}...", pageIdToUse, tokenToUse.substring(0, 10));
|
||||
|
||||
String response = webClient.post()
|
||||
.uri(uriBuilder -> uriBuilder
|
||||
.path("/{pageId}/feed")
|
||||
.queryParam("access_token", creds.pageToken)
|
||||
.queryParam("access_token", tokenToUse)
|
||||
.queryParam("message", fullPostText)
|
||||
.build(creds.pageId))
|
||||
.build(pageIdToUse))
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.block(Duration.ofMillis(timeoutMs));
|
||||
|
||||
JsonNode jsonNode = objectMapper.readTree(response);
|
||||
String postId = jsonNode.get("id").asText();
|
||||
logger.info("Posted to Page {}. ID: {}", creds.pageId, postId);
|
||||
logger.info("✅ SUCCESS: Текстовый пост опубликован. ID: {}", postId);
|
||||
return postId;
|
||||
|
||||
} catch (WebClientResponseException e) {
|
||||
if (isTokenExpiredError(e)) throw parseFacebookError(e);
|
||||
logger.error("Page API error: {}", e.getResponseBodyAsString());
|
||||
throw new RuntimeException("Failed to post to Page: " + e.getMessage(), e);
|
||||
handleFacebookError(e, "postToPage");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String postToPageWithImage(String userAccessToken, String postText, List<String> hashtags,
|
||||
byte[] imageData) {
|
||||
// === ПУБЛИКАЦИЯ КАРТИНКИ ===
|
||||
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);
|
||||
PageCredentials creds = getPageCredentials(userAccessToken);
|
||||
|
||||
ByteArrayResource imageResource = new ByteArrayResource(imageData) {
|
||||
@Override public String getFilename() { return "image.jpg"; }
|
||||
@@ -121,10 +150,10 @@ public class FacebookPostingService {
|
||||
MultiValueMap<String, Object> formData = new LinkedMultiValueMap<>();
|
||||
formData.add("message", fullPostText);
|
||||
formData.add("source", imageResource);
|
||||
formData.add("access_token", creds.pageToken);
|
||||
formData.add("access_token", tokenToUse);
|
||||
|
||||
String response = webClient.post()
|
||||
.uri(uriBuilder -> uriBuilder.path("/{pageId}/photos").build(creds.pageId))
|
||||
.uri(uriBuilder -> uriBuilder.path("/{pageId}/photos").build(pageIdToUse))
|
||||
.contentType(MediaType.MULTIPART_FORM_DATA)
|
||||
.body(BodyInserters.fromMultipartData(formData))
|
||||
.retrieve()
|
||||
@@ -133,15 +162,14 @@ public class FacebookPostingService {
|
||||
|
||||
JsonNode jsonNode = objectMapper.readTree(response);
|
||||
String postId = jsonNode.get("id").asText();
|
||||
logger.info("Posted image to Page {}. ID: {}", creds.pageId, postId);
|
||||
logger.info("✅ SUCCESS: Фото опубликовано. ID: {}", postId);
|
||||
return postId;
|
||||
|
||||
} catch (WebClientResponseException e) {
|
||||
if (isTokenExpiredError(e)) throw parseFacebookError(e);
|
||||
logger.error("Page image API error: {}", e.getResponseBodyAsString());
|
||||
throw new RuntimeException("Failed to post image to Page: " + e.getMessage(), e);
|
||||
handleFacebookError(e, "postToPageWithImage");
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to post image to Page", e);
|
||||
throw new RuntimeException("Failed to post image to Page: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,75 +185,23 @@ public class FacebookPostingService {
|
||||
return fullText.toString();
|
||||
}
|
||||
|
||||
private static class PageCredentials {
|
||||
String pageId;
|
||||
String pageToken;
|
||||
// Класс сделали публичным, чтобы он был доступен в других пакетах если что,
|
||||
// но в данном случае он используется как DTO
|
||||
public static class PageCredentials {
|
||||
public String pageId;
|
||||
public String pageToken;
|
||||
public PageCredentials(String pageId, String pageToken) {
|
||||
this.pageId = pageId;
|
||||
this.pageToken = pageToken;
|
||||
}
|
||||
}
|
||||
|
||||
private PageCredentials getPageCredentials(String accessToken) {
|
||||
try {
|
||||
// 1. Try to fetch accounts (This fails if token is already a Page Token)
|
||||
String response = webClient.get()
|
||||
.uri(uriBuilder -> uriBuilder
|
||||
.path("/me/accounts")
|
||||
.queryParam("access_token", accessToken)
|
||||
.build())
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.block(Duration.ofMillis(timeoutMs));
|
||||
private void handleFacebookError(WebClientResponseException e, String context) {
|
||||
String errorBody = e.getResponseBodyAsString();
|
||||
logger.error("❌ FB API ERROR [{}]: Status={}, Body={}", context, e.getStatusCode(), errorBody);
|
||||
|
||||
JsonNode data = objectMapper.readTree(response).get("data");
|
||||
|
||||
if (data.isEmpty()) {
|
||||
// If no pages found, try treating it as a Page Token directly
|
||||
return getPageDetailsDirectly(accessToken);
|
||||
}
|
||||
|
||||
JsonNode firstPage = data.get(0);
|
||||
return new PageCredentials(
|
||||
firstPage.get("id").asText(),
|
||||
firstPage.get("access_token").asText());
|
||||
|
||||
} catch (WebClientResponseException e) {
|
||||
// === FIX IS HERE ===
|
||||
// If we get a 400 Bad Request, it means we cannot list accounts.
|
||||
// This happens when the token is ALREADY a Page Access Token.
|
||||
if (e.getStatusCode().value() == 400) {
|
||||
logger.info("Got 400 on /me/accounts. Assuming token is a Page Token. Trying direct access.");
|
||||
return getPageDetailsDirectly(accessToken);
|
||||
}
|
||||
|
||||
if (isTokenExpiredError(e)) throw parseFacebookError(e);
|
||||
throw new RuntimeException("Failed to get page credentials", e);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to get page credentials", e);
|
||||
}
|
||||
}
|
||||
|
||||
private PageCredentials getPageDetailsDirectly(String pageAccessToken) {
|
||||
try {
|
||||
// Verify the token works for /me and get the Page ID
|
||||
String response = webClient.get()
|
||||
.uri(uriBuilder -> uriBuilder
|
||||
.path("/me")
|
||||
.queryParam("access_token", pageAccessToken)
|
||||
.queryParam("fields", "id,name")
|
||||
.build())
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.block(Duration.ofMillis(timeoutMs));
|
||||
|
||||
String pageId = objectMapper.readTree(response).get("id").asText();
|
||||
logger.info("Successfully resolved Page Token for Page ID: {}", pageId);
|
||||
return new PageCredentials(pageId, pageAccessToken);
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to verify Page Token: {}", e.getMessage());
|
||||
throw new RuntimeException("Invalid token provided. Could not fetch Page ID.", e);
|
||||
}
|
||||
if (isTokenExpiredError(e)) throw parseFacebookError(e);
|
||||
throw new RuntimeException("Facebook API Error (" + context + "): " + errorBody, e);
|
||||
}
|
||||
|
||||
private boolean isTokenExpiredError(WebClientResponseException e) {
|
||||
|
||||
Reference in New Issue
Block a user