.
This commit is contained in:
@@ -98,61 +98,59 @@ public class FacebookPostingService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Получает Page Access Token и Page ID из User Access Token
|
* Retrieves Page credentials (ID and Token).
|
||||||
* Вызывает /me/accounts для получения списка страниц, которыми управляет
|
* Handles two scenarios:
|
||||||
* пользователь
|
* 1. The input is a User Token: Calls /me/accounts to find the Page and its
|
||||||
|
* Page Token.
|
||||||
|
* 2. The input is ALREADY a Page Token: Detects the error, fetches the Page ID
|
||||||
|
* directly, and uses the input token.
|
||||||
*
|
*
|
||||||
* @param userAccessToken User Access Token
|
* @param accessToken User Access Token or Page Access Token
|
||||||
* @return PageCredentials с Page ID и Page Access Token
|
* @return PageCredentials с Page ID и Page Access Token
|
||||||
* @throws FacebookTokenExpiredException если токен истек
|
* @throws FacebookTokenExpiredException если токен истек
|
||||||
* @throws RuntimeException если не удалось получить credentials
|
* @throws RuntimeException если не удалось получить credentials
|
||||||
* страницы
|
* страницы
|
||||||
*/
|
*/
|
||||||
private PageCredentials getPageCredentials(String userAccessToken) {
|
private PageCredentials getPageCredentials(String accessToken) {
|
||||||
try {
|
try {
|
||||||
|
// SCENARIO 1: Try to treat it as a User Token and find pages
|
||||||
String response = webClient.get()
|
String response = webClient.get()
|
||||||
.uri(uriBuilder -> uriBuilder
|
.uri(uriBuilder -> uriBuilder
|
||||||
.path("/me/accounts")
|
.path("/me/accounts")
|
||||||
.queryParam("access_token", userAccessToken)
|
.queryParam("access_token", accessToken)
|
||||||
.build())
|
.build())
|
||||||
.retrieve()
|
.retrieve()
|
||||||
.bodyToMono(String.class)
|
.bodyToMono(String.class)
|
||||||
.block(Duration.ofMillis(timeoutMs));
|
.block(Duration.ofMillis(timeoutMs));
|
||||||
|
|
||||||
JsonNode jsonNode = objectMapper.readTree(response);
|
JsonNode root = objectMapper.readTree(response);
|
||||||
|
JsonNode data = root.get("data");
|
||||||
|
|
||||||
// Проверяем наличие массива data
|
if (data.isEmpty()) {
|
||||||
if (!jsonNode.has("data") || !jsonNode.get("data").isArray()) {
|
throw new RuntimeException("User has no pages available. Please check permissions (pages_show_list).");
|
||||||
logger.error("Facebook API response does not contain 'data' array");
|
|
||||||
throw new RuntimeException("Failed to get page credentials: no pages found in response");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonNode dataArray = jsonNode.get("data");
|
// Return the first page found
|
||||||
if (dataArray.size() == 0) {
|
JsonNode firstPage = data.get(0);
|
||||||
logger.error("User has no pages available");
|
return new PageCredentials(
|
||||||
throw new RuntimeException("Failed to get page credentials: user has no pages");
|
firstPage.get("id").asText(),
|
||||||
}
|
firstPage.get("access_token").asText());
|
||||||
|
|
||||||
// Берем первую страницу из списка
|
|
||||||
JsonNode firstPage = dataArray.get(0);
|
|
||||||
String pageId = firstPage.has("id") ? firstPage.get("id").asText() : null;
|
|
||||||
String pageToken = firstPage.has("access_token") ? firstPage.get("access_token").asText() : null;
|
|
||||||
|
|
||||||
if (pageId == null || pageToken == null) {
|
|
||||||
logger.error("Page credentials incomplete: pageId={}, pageToken={}", pageId,
|
|
||||||
pageToken != null ? "present" : "null");
|
|
||||||
throw new RuntimeException("Failed to get page credentials: incomplete page data");
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info("Successfully retrieved page credentials for page ID: {}", pageId);
|
|
||||||
return new PageCredentials(pageId, pageToken);
|
|
||||||
|
|
||||||
} catch (WebClientResponseException e) {
|
} catch (WebClientResponseException e) {
|
||||||
|
// SCENARIO 2: Check if the token is already a Page Token
|
||||||
|
// Error code 100 with message containing "node type (Page)" means we are
|
||||||
|
// already a Page
|
||||||
if (isTokenExpiredError(e)) {
|
if (isTokenExpiredError(e)) {
|
||||||
throw parseFacebookError(e);
|
throw parseFacebookError(e);
|
||||||
}
|
}
|
||||||
logger.error("Failed to get Facebook page credentials: {} - {}", e.getStatusCode(),
|
|
||||||
e.getResponseBodyAsString());
|
String responseBody = e.getResponseBodyAsString();
|
||||||
|
if (e.getStatusCode().value() == 400 && responseBody != null && responseBody.contains("Page")) {
|
||||||
|
logger.info("Provided token is already a Page Access Token. Skipping exchange.");
|
||||||
|
return getPageDetailsDirectly(accessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.error("Failed to get Facebook page credentials: {} - {}", e.getStatusCode(), responseBody);
|
||||||
throw new RuntimeException("Failed to get page credentials: " + e.getMessage(), e);
|
throw new RuntimeException("Failed to get page credentials: " + e.getMessage(), e);
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
logger.error("Failed to parse Facebook page credentials response", e);
|
logger.error("Failed to parse Facebook page credentials response", e);
|
||||||
@@ -160,8 +158,43 @@ public class FacebookPostingService {
|
|||||||
} catch (FacebookTokenExpiredException e) {
|
} catch (FacebookTokenExpiredException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("Unexpected error getting page credentials", e);
|
logger.error("Failed to get page credentials", e);
|
||||||
throw new RuntimeException("Failed to get page credentials", e);
|
throw new RuntimeException("Failed to get page credentials: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method: When we already have a Page Token, we just need the Page ID.
|
||||||
|
*/
|
||||||
|
private PageCredentials getPageDetailsDirectly(String pageAccessToken) {
|
||||||
|
try {
|
||||||
|
String response = webClient.get()
|
||||||
|
.uri(uriBuilder -> uriBuilder
|
||||||
|
.path("/me")
|
||||||
|
.queryParam("access_token", pageAccessToken)
|
||||||
|
.queryParam("fields", "id")
|
||||||
|
.build())
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(String.class)
|
||||||
|
.block(Duration.ofMillis(timeoutMs));
|
||||||
|
|
||||||
|
JsonNode root = objectMapper.readTree(response);
|
||||||
|
String pageId = root.get("id").asText();
|
||||||
|
|
||||||
|
// Return the ID we found, and reuse the token we already have
|
||||||
|
return new PageCredentials(pageId, pageAccessToken);
|
||||||
|
} catch (WebClientResponseException e) {
|
||||||
|
if (isTokenExpiredError(e)) {
|
||||||
|
throw parseFacebookError(e);
|
||||||
|
}
|
||||||
|
logger.error("Failed to verify Page Access Token: {} - {}", e.getStatusCode(), e.getResponseBodyAsString());
|
||||||
|
throw new RuntimeException("Failed to verify Page Access Token: " + e.getMessage(), e);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
logger.error("Failed to parse Page ID response", e);
|
||||||
|
throw new RuntimeException("Failed to verify Page Access Token: " + e.getMessage(), e);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Failed to verify Page Access Token", e);
|
||||||
|
throw new RuntimeException("Failed to verify Page Access Token: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user