chore(*.php): use pint for php formatting
This commit is contained in:
parent
029caaaa9e
commit
cf1ee4c97f
40 changed files with 2261 additions and 1900 deletions
289
api/mastodon.php
289
api/mastodon.php
|
@ -1,174 +1,187 @@
|
|||
<?php
|
||||
|
||||
require_once __DIR__ . '/../bootstrap.php';
|
||||
require_once __DIR__.'/../bootstrap.php';
|
||||
|
||||
use App\Classes\ApiHandler;
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
class MastodonPostHandler extends ApiHandler
|
||||
{
|
||||
private string $mastodonAccessToken;
|
||||
private string $rssFeedUrl = "https://www.coryd.dev/feeds/syndication.xml";
|
||||
private string $baseUrl = "https://www.coryd.dev";
|
||||
private const MASTODON_API_STATUS = "https://follow.coryd.dev/api/v1/statuses";
|
||||
private Client $httpClient;
|
||||
private string $mastodonAccessToken;
|
||||
|
||||
public function __construct(?Client $httpClient = null)
|
||||
{
|
||||
parent::__construct();
|
||||
private string $rssFeedUrl = 'https://www.coryd.dev/feeds/syndication.xml';
|
||||
|
||||
$this->ensureCliAccess();
|
||||
$this->mastodonAccessToken = getenv("MASTODON_ACCESS_TOKEN") ?: $_ENV["MASTODON_ACCESS_TOKEN"] ?? "";
|
||||
$this->httpClient = $httpClient ?: new Client();
|
||||
$this->validateAuthorization();
|
||||
}
|
||||
private string $baseUrl = 'https://www.coryd.dev';
|
||||
|
||||
private function validateAuthorization(): void
|
||||
{
|
||||
$authHeader = $_SERVER["HTTP_AUTHORIZATION"] ?? "";
|
||||
$expectedToken = "Bearer " . getenv("MASTODON_SYNDICATION_TOKEN");
|
||||
private const MASTODON_API_STATUS = 'https://follow.coryd.dev/api/v1/statuses';
|
||||
|
||||
if ($authHeader !== $expectedToken) {
|
||||
http_response_code(401);
|
||||
echo json_encode(["error" => "Unauthorized"]);
|
||||
exit();
|
||||
}
|
||||
}
|
||||
private Client $httpClient;
|
||||
|
||||
public function handlePost(): void
|
||||
{
|
||||
if (!$this->isDatabaseAvailable()) {
|
||||
echo "Database is unavailable. Exiting.\n";
|
||||
return;
|
||||
public function __construct(?Client $httpClient = null)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->ensureCliAccess();
|
||||
$this->mastodonAccessToken = getenv('MASTODON_ACCESS_TOKEN') ?: $_ENV['MASTODON_ACCESS_TOKEN'] ?? '';
|
||||
$this->httpClient = $httpClient ?: new Client();
|
||||
$this->validateAuthorization();
|
||||
}
|
||||
|
||||
$latestItems = $this->fetchRSSFeed($this->rssFeedUrl);
|
||||
private function validateAuthorization(): void
|
||||
{
|
||||
$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
|
||||
$expectedToken = 'Bearer '.getenv('MASTODON_SYNDICATION_TOKEN');
|
||||
|
||||
foreach (array_reverse($latestItems) as $item) {
|
||||
$existing = $this->fetchFromApi("mastodon_posts", "link=eq." . urlencode($item["link"]));
|
||||
|
||||
if (!empty($existing)) continue;
|
||||
|
||||
$content = $this->truncateContent(
|
||||
$item["title"],
|
||||
strip_tags($item["description"]),
|
||||
$item["link"],
|
||||
500
|
||||
);
|
||||
$timestamp = date("Y-m-d H:i:s");
|
||||
|
||||
if (!$this->storeInDatabase($item["link"], $timestamp)) {
|
||||
echo "Skipping post: database write failed for {$item["link"]}\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
$postedUrl = $this->postToMastodon($content, $item["image"] ?? null);
|
||||
|
||||
if ($postedUrl) {
|
||||
echo "Posted: {$postedUrl}\n";
|
||||
} else {
|
||||
echo "Failed to post to Mastodon for: {$item["link"]}\n";
|
||||
}
|
||||
if ($authHeader !== $expectedToken) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['error' => 'Unauthorized']);
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
echo "RSS processed successfully.\n";
|
||||
}
|
||||
public function handlePost(): void
|
||||
{
|
||||
if (! $this->isDatabaseAvailable()) {
|
||||
echo "Database is unavailable. Exiting.\n";
|
||||
|
||||
private function fetchRSSFeed(string $rssFeedUrl): array
|
||||
{
|
||||
$rssText = file_get_contents($rssFeedUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$rssText) throw new \Exception("Failed to fetch RSS feed.");
|
||||
$latestItems = $this->fetchRSSFeed($this->rssFeedUrl);
|
||||
|
||||
$rss = new \SimpleXMLElement($rssText);
|
||||
$items = [];
|
||||
foreach (array_reverse($latestItems) as $item) {
|
||||
$existing = $this->fetchFromApi('mastodon_posts', 'link=eq.'.urlencode($item['link']));
|
||||
|
||||
foreach ($rss->channel->item as $item) {
|
||||
$items[] = [
|
||||
"title" => $this->cleanText((string) $item->title),
|
||||
"link" => (string) $item->link,
|
||||
"description" => $this->cleanText((string) $item->description),
|
||||
];
|
||||
if (! empty($existing)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$content = $this->truncateContent(
|
||||
$item['title'],
|
||||
strip_tags($item['description']),
|
||||
$item['link'],
|
||||
500
|
||||
);
|
||||
$timestamp = date('Y-m-d H:i:s');
|
||||
|
||||
if (! $this->storeInDatabase($item['link'], $timestamp)) {
|
||||
echo "Skipping post: database write failed for {$item['link']}\n";
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$postedUrl = $this->postToMastodon($content, $item['image'] ?? null);
|
||||
|
||||
if ($postedUrl) {
|
||||
echo "Posted: {$postedUrl}\n";
|
||||
} else {
|
||||
echo "Failed to post to Mastodon for: {$item['link']}\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo "RSS processed successfully.\n";
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
private function fetchRSSFeed(string $rssFeedUrl): array
|
||||
{
|
||||
$rssText = file_get_contents($rssFeedUrl);
|
||||
|
||||
private function cleanText(string $text): string
|
||||
{
|
||||
$decoded = html_entity_decode($text, ENT_QUOTES | ENT_XML1, 'UTF-8');
|
||||
return mb_convert_encoding($decoded, 'UTF-8', 'UTF-8');
|
||||
}
|
||||
if (! $rssText) {
|
||||
throw new \Exception('Failed to fetch RSS feed.');
|
||||
}
|
||||
|
||||
private function postToMastodon(string $content): ?string
|
||||
{
|
||||
$headers = [
|
||||
"Authorization" => "Bearer {$this->mastodonAccessToken}",
|
||||
"Content-Type" => "application/json",
|
||||
];
|
||||
$postData = ["status" => $content];
|
||||
$response = $this->httpClient->request("POST", self::MASTODON_API_STATUS, [
|
||||
"headers" => $headers,
|
||||
"json" => $postData
|
||||
]);
|
||||
$rss = new \SimpleXMLElement($rssText);
|
||||
$items = [];
|
||||
|
||||
if ($response->getStatusCode() >= 400) throw new \Exception("Mastodon post failed: {$response->getBody()}");
|
||||
foreach ($rss->channel->item as $item) {
|
||||
$items[] = [
|
||||
'title' => $this->cleanText((string) $item->title),
|
||||
'link' => (string) $item->link,
|
||||
'description' => $this->cleanText((string) $item->description),
|
||||
];
|
||||
}
|
||||
|
||||
$body = json_decode($response->getBody()->getContents(), true);
|
||||
|
||||
return $body["url"] ?? null;
|
||||
}
|
||||
|
||||
private function storeInDatabase(string $link, string $timestamp): bool
|
||||
{
|
||||
try {
|
||||
$this->makeRequest("POST", "mastodon_posts", [
|
||||
"json" => [
|
||||
"link" => $link,
|
||||
"created_at" => $timestamp
|
||||
]
|
||||
]);
|
||||
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
echo "Error storing post in DB: " . $e->getMessage() . "\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function isDatabaseAvailable(): bool
|
||||
{
|
||||
try {
|
||||
$response = $this->fetchFromApi("mastodon_posts", "limit=1");
|
||||
|
||||
return is_array($response);
|
||||
} catch (\Exception $e) {
|
||||
echo "Database check failed: " . $e->getMessage() . "\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function truncateContent(string $title, string $description, string $link, int $maxLength): string
|
||||
{
|
||||
$baseLength = strlen("$title\n\n$link");
|
||||
$available = $maxLength - $baseLength - 4;
|
||||
|
||||
if (strlen($description) > $available) {
|
||||
$description = substr($description, 0, $available);
|
||||
$description = preg_replace('/\s+\S*$/', "", $description) . "...";
|
||||
return $items;
|
||||
}
|
||||
|
||||
return "$title\n\n$description\n\n$link";
|
||||
}
|
||||
private function cleanText(string $text): string
|
||||
{
|
||||
$decoded = html_entity_decode($text, ENT_QUOTES | ENT_XML1, 'UTF-8');
|
||||
|
||||
return mb_convert_encoding($decoded, 'UTF-8', 'UTF-8');
|
||||
}
|
||||
|
||||
private function postToMastodon(string $content): ?string
|
||||
{
|
||||
$headers = [
|
||||
'Authorization' => "Bearer {$this->mastodonAccessToken}",
|
||||
'Content-Type' => 'application/json',
|
||||
];
|
||||
$postData = ['status' => $content];
|
||||
$response = $this->httpClient->request('POST', self::MASTODON_API_STATUS, [
|
||||
'headers' => $headers,
|
||||
'json' => $postData,
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() >= 400) {
|
||||
throw new \Exception("Mastodon post failed: {$response->getBody()}");
|
||||
}
|
||||
|
||||
$body = json_decode($response->getBody()->getContents(), true);
|
||||
|
||||
return $body['url'] ?? null;
|
||||
}
|
||||
|
||||
private function storeInDatabase(string $link, string $timestamp): bool
|
||||
{
|
||||
try {
|
||||
$this->makeRequest('POST', 'mastodon_posts', [
|
||||
'json' => [
|
||||
'link' => $link,
|
||||
'created_at' => $timestamp,
|
||||
],
|
||||
]);
|
||||
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
echo 'Error storing post in DB: '.$e->getMessage()."\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function isDatabaseAvailable(): bool
|
||||
{
|
||||
try {
|
||||
$response = $this->fetchFromApi('mastodon_posts', 'limit=1');
|
||||
|
||||
return is_array($response);
|
||||
} catch (\Exception $e) {
|
||||
echo 'Database check failed: '.$e->getMessage()."\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function truncateContent(string $title, string $description, string $link, int $maxLength): string
|
||||
{
|
||||
$baseLength = strlen("$title\n\n$link");
|
||||
$available = $maxLength - $baseLength - 4;
|
||||
|
||||
if (strlen($description) > $available) {
|
||||
$description = substr($description, 0, $available);
|
||||
$description = preg_replace('/\s+\S*$/', '', $description).'...';
|
||||
}
|
||||
|
||||
return "$title\n\n$description\n\n$link";
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$handler = new MastodonPostHandler();
|
||||
$handler->handlePost();
|
||||
$handler = new MastodonPostHandler();
|
||||
$handler->handlePost();
|
||||
} catch (\Exception $e) {
|
||||
http_response_code(500);
|
||||
http_response_code(500);
|
||||
|
||||
echo json_encode(["error" => $e->getMessage()]);
|
||||
echo json_encode(['error' => $e->getMessage()]);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue