fixes for outbox
- mastodon now properly sets available type-attributes - database should now save user with his platform (as that's the actual unique identifier, plain username isn't) - properly retrieve items from mastodon and print them on api-call (example call for mastodon: federator/fedusers/gutenberg_org@mastodon.social/outbox?page=0)
This commit is contained in:
parent
530caa7ea6
commit
1a7b8264a1
4 changed files with 120 additions and 58 deletions
|
@ -78,7 +78,7 @@ class Api extends Main
|
||||||
$host = 'dummy'; // fallback
|
$host = 'dummy'; // fallback
|
||||||
|
|
||||||
// Check if path matches something like fedusers/username@domain.tld
|
// Check if path matches something like fedusers/username@domain.tld
|
||||||
if (preg_match("#^fedusers/([^@]+)@([^/]+)$#", $this->path, $matches) === 1) {
|
if (preg_match("#^fedusers/([^@]+)@([^/]+)/.*$#", $this->path, $matches) === 1) {
|
||||||
$host = strtolower($matches[2]); // extract domain
|
$host = strtolower($matches[2]); // extract domain
|
||||||
} else {
|
} else {
|
||||||
$host = 'dummy';
|
$host = 'dummy';
|
||||||
|
|
|
@ -40,6 +40,7 @@ class Outbox implements \Federator\Api\FedUsers\FedUsersInterface
|
||||||
{
|
{
|
||||||
$dbh = $this->main->getDatabase();
|
$dbh = $this->main->getDatabase();
|
||||||
$cache = $this->main->getCache();
|
$cache = $this->main->getCache();
|
||||||
|
|
||||||
// get user
|
// get user
|
||||||
$user = \Federator\DIO\User::getUserByName(
|
$user = \Federator\DIO\User::getUserByName(
|
||||||
$dbh,
|
$dbh,
|
||||||
|
@ -69,10 +70,6 @@ class Outbox implements \Federator\Api\FedUsers\FedUsersInterface
|
||||||
if ($page !== '') {
|
if ($page !== '') {
|
||||||
$id .= '?page=' . urlencode($page);
|
$id .= '?page=' . urlencode($page);
|
||||||
}
|
}
|
||||||
if ($page === '' || $outbox->count() == 0) {
|
|
||||||
$outbox->setFirst($id);
|
|
||||||
$outbox->setLast($id . '&min=0');
|
|
||||||
}
|
|
||||||
if (sizeof($items)>0) {
|
if (sizeof($items)>0) {
|
||||||
$newestId = $items[0]->getPublished();
|
$newestId = $items[0]->getPublished();
|
||||||
$oldestId = $items[sizeof($items)-1]->getPublished();
|
$oldestId = $items[sizeof($items)-1]->getPublished();
|
||||||
|
|
|
@ -244,7 +244,7 @@ class ContentNation implements Connector
|
||||||
*/
|
*/
|
||||||
public function getRemoteUserByName(string $_name)
|
public function getRemoteUserByName(string $_name)
|
||||||
{
|
{
|
||||||
if (preg_match("#^([^@]+)@([^/]+)$#", $_name, $matches) === 1) {
|
if (preg_match("#^([^@]+)@([^/]+)#", $_name, $matches) === 1) {
|
||||||
$_name = $matches[1];
|
$_name = $matches[1];
|
||||||
}
|
}
|
||||||
// validate name
|
// validate name
|
||||||
|
|
|
@ -54,7 +54,8 @@ class Mastodon implements Connector
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getHost() {
|
public function getHost()
|
||||||
|
{
|
||||||
return "mastodon.social";
|
return "mastodon.social";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,22 +69,35 @@ class Mastodon implements Connector
|
||||||
*/
|
*/
|
||||||
public function getRemotePostsByUser($userId, $min = null, $max = null)
|
public function getRemotePostsByUser($userId, $min = null, $max = null)
|
||||||
{
|
{
|
||||||
$remoteURL = $this->service . '/users/' . $userId . '/outbox';
|
if (preg_match("#^([^@]+)@([^/]+)#", $userId, $matches) === 1) {
|
||||||
|
$name = $matches[1];
|
||||||
|
}
|
||||||
|
$remoteURL = $this->service . '/users/' . $name . '/outbox';
|
||||||
|
if ($min !== '') {
|
||||||
|
$remoteURL .= '&minTS=' . urlencode($min);
|
||||||
|
}
|
||||||
|
if ($max !== '') {
|
||||||
|
$remoteURL .= '&maxTS=' . urlencode($max);
|
||||||
|
}
|
||||||
|
|
||||||
$items = [];
|
$items = [];
|
||||||
|
|
||||||
do {
|
[$outboxResponse, $outboxInfo] = \Federator\Main::getFromRemote($remoteURL, ['Accept: application/activity+json']);
|
||||||
if ($min !== '') {
|
|
||||||
$remoteURL .= '&minTS=' . urlencode($min);
|
if ($outboxInfo['http_code'] !== 200) {
|
||||||
}
|
echo "MastodonConnector::getRemotePostsByUser HTTP call failed for remoteURL $remoteURL\n";
|
||||||
if ($max !== '') {
|
return false;
|
||||||
$remoteURL .= '&maxTS=' . urlencode($max);
|
}
|
||||||
}
|
|
||||||
|
$outbox = json_decode($outboxResponse, true);
|
||||||
|
|
||||||
|
// retrieve ALL outbox items - disabled for now
|
||||||
|
/* do {
|
||||||
// Fetch the current page of items (first or subsequent pages)
|
// Fetch the current page of items (first or subsequent pages)
|
||||||
[$outboxResponse, $outboxInfo] = \Federator\Main::getFromRemote($remoteURL, ['Accept: application/activity+json']);
|
[$outboxResponse, $outboxInfo] = \Federator\Main::getFromRemote($remoteURL, ['Accept: application/activity+json']);
|
||||||
|
|
||||||
if ($outboxInfo['http_code'] !== 200) {
|
if ($outboxInfo['http_code'] !== 200) {
|
||||||
echo "aborting";
|
echo "MastodonConnector::getRemotePostsByUser HTTP call failed for remoteURL $remoteURL\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,18 +108,25 @@ class Mastodon implements Connector
|
||||||
$items = array_merge($items, $outbox['orderedItems']);
|
$items = array_merge($items, $outbox['orderedItems']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 4: Use 'last' URL to determine pagination
|
// Use 'next' or 'last' URL to determine pagination
|
||||||
if (isset($outbox['last'])) {
|
if (isset($outbox['next'])) {
|
||||||
// The 'last' URL will usually have a query string that includes min_id for the next set of results
|
$remoteURL = $outbox['next']; // Update target URL for the next page of items
|
||||||
$remoteURL = $outbox['last']; // Update to the last URL for the next page of items
|
} else if (isset($outbox['last'])) {
|
||||||
|
$remoteURL = $outbox['last']; // Update target URL for the next page of items
|
||||||
} else {
|
} else {
|
||||||
|
$remoteURL = "";
|
||||||
break; // No more pages, exit pagination
|
break; // No more pages, exit pagination
|
||||||
}
|
}
|
||||||
|
if ($remoteURL !== "") {
|
||||||
|
if ($min !== '') {
|
||||||
|
$remoteURL .= '&minTS=' . urlencode($min);
|
||||||
|
}
|
||||||
|
if ($max !== '') {
|
||||||
|
$remoteURL .= '&maxTS=' . urlencode($max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} while (!empty($outbox['last'])); // Continue fetching until no 'last' URL
|
} while ($remoteURL !== ""); // Continue fetching until no 'last' URL */
|
||||||
|
|
||||||
|
|
||||||
$items = [];
|
|
||||||
|
|
||||||
// Follow `first` page (or get orderedItems directly)
|
// Follow `first` page (or get orderedItems directly)
|
||||||
if (isset($outbox['orderedItems'])) {
|
if (isset($outbox['orderedItems'])) {
|
||||||
|
@ -122,42 +143,86 @@ class Mastodon implements Connector
|
||||||
|
|
||||||
// Convert to internal representation
|
// Convert to internal representation
|
||||||
$posts = [];
|
$posts = [];
|
||||||
|
$host = $_SERVER['SERVER_NAME'];
|
||||||
foreach ($items as $activity) {
|
foreach ($items as $activity) {
|
||||||
if (!isset($activity['type']) || $activity['type'] !== 'Create' || !isset($activity['object'])) {
|
switch ($activity['type']) {
|
||||||
continue; // Skip non-Create activities
|
case 'Create':
|
||||||
}
|
if (!isset($activity['object'])) {
|
||||||
|
break;
|
||||||
$obj = $activity['object'];
|
|
||||||
$create = new \Federator\Data\ActivityPub\Common\Create();
|
|
||||||
$create->setID($activity['id'])
|
|
||||||
->setPublished(strtotime($activity['published'] ?? $obj['published'] ?? 'now'))
|
|
||||||
->setAActor($activity['actor'])
|
|
||||||
->addTo("https://www.w3.org/ns/activitystreams#Public");
|
|
||||||
|
|
||||||
// Handle main Note content
|
|
||||||
if ($obj['type'] === 'Note') {
|
|
||||||
$apNote = new \Federator\Data\ActivityPub\Common\Note();
|
|
||||||
$apNote->setID($obj['id'])
|
|
||||||
->setPublished(strtotime($obj['published'] ?? 'now'))
|
|
||||||
->setContent($obj['content'] ?? '')
|
|
||||||
->setAttributedTo($obj['attributedTo'] ?? $activity['actor'])
|
|
||||||
->addTo("https://www.w3.org/ns/activitystreams#Public");
|
|
||||||
|
|
||||||
// Handle attachments
|
|
||||||
if (!empty($obj['attachment']) && is_array($obj['attachment'])) {
|
|
||||||
foreach ($obj['attachment'] as $media) {
|
|
||||||
if (!isset($media['type'], $media['url']))
|
|
||||||
continue;
|
|
||||||
$mediaObj = new \Federator\Data\ActivityPub\Common\APObject($media['type']);
|
|
||||||
$mediaObj->setURL($media['url']);
|
|
||||||
$apNote->addAttachment($mediaObj);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$create->setObject($apNote);
|
$obj = $activity['object'];
|
||||||
|
$create = new \Federator\Data\ActivityPub\Common\Create();
|
||||||
|
$create->setID($activity['id'])
|
||||||
|
->setURL($activity['id'])
|
||||||
|
->setPublished(strtotime($activity['published'] ?? $obj['published'] ?? 'now'))
|
||||||
|
->setAActor($activity['actor'])
|
||||||
|
->addCC($activity['cc']);
|
||||||
|
|
||||||
|
if (array_key_exists('to', $activity)) {
|
||||||
|
foreach ($activity['to'] as $to) {
|
||||||
|
$create->addTo($to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($obj['type']) {
|
||||||
|
case 'Note':
|
||||||
|
$apNote = new \Federator\Data\ActivityPub\Common\Note();
|
||||||
|
$apNote->setID($obj['id'])
|
||||||
|
->setPublished(strtotime($obj['published'] ?? 'now'))
|
||||||
|
->setContent($obj['content'] ?? '')
|
||||||
|
->setSummary($obj['summary'])
|
||||||
|
->setURL($obj['url'])
|
||||||
|
->setAttributedTo($obj['attributedTo'] ?? $activity['actor'])
|
||||||
|
->addTo("https://www.w3.org/ns/activitystreams#Public");
|
||||||
|
|
||||||
|
if (!empty($obj['sensitive'])) {
|
||||||
|
$apNote->setSensitive($obj['sensitive']);
|
||||||
|
}
|
||||||
|
if (!empty($obj['conversation'])) {
|
||||||
|
$apNote->setConversation($obj['conversation']);
|
||||||
|
}
|
||||||
|
if (!empty($obj['inReplyTo'])) {
|
||||||
|
$apNote->setInReplyTo($obj['inReplyTo']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle attachments
|
||||||
|
if (!empty($obj['attachment']) && is_array($obj['attachment'])) {
|
||||||
|
foreach ($obj['attachment'] as $media) {
|
||||||
|
if (!isset($media['type'], $media['url']))
|
||||||
|
continue;
|
||||||
|
$mediaObj = new \Federator\Data\ActivityPub\Common\APObject($media['type']);
|
||||||
|
$mediaObj->setURL($media['url']);
|
||||||
|
$apNote->addAttachment($mediaObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('tag', $obj)) {
|
||||||
|
foreach ($obj['tag'] as $tag) {
|
||||||
|
$tagName = is_array($tag) && isset($tag['name']) ? $tag['name'] : (string) $tag;
|
||||||
|
$cleanName = preg_replace('/\s+/', '', ltrim($tagName, '#')); // Remove space and leading #
|
||||||
|
$tagObj = new \Federator\Data\ActivityPub\Common\Tag();
|
||||||
|
$tagObj->setName('#' . $cleanName)
|
||||||
|
->setHref("https://$host/tags/" . urlencode($cleanName))
|
||||||
|
->setType('Hashtag');
|
||||||
|
$apNote->addTag($tagObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$create->setObject($apNote);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
echo "MastodonConnector::getRemotePostsByUser we currently don't support the obj type " . $obj['type'] . "\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$posts[] = $create;
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
echo "MastodonConnector::getRemotePostsByUser we currently don't support the activity type " . $activity['type'] . "\n";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$posts[] = $create;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $posts;
|
return $posts;
|
||||||
|
|
Loading…
Add table
Reference in a new issue