forked from grumpydevelop/federator
		
	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
 | 
			
		||||
 | 
			
		||||
        // 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
 | 
			
		||||
        } else {
 | 
			
		||||
            $host = 'dummy';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,6 +40,7 @@ class Outbox implements \Federator\Api\FedUsers\FedUsersInterface
 | 
			
		|||
    {
 | 
			
		||||
        $dbh = $this->main->getDatabase();
 | 
			
		||||
        $cache = $this->main->getCache();
 | 
			
		||||
        
 | 
			
		||||
        // get user
 | 
			
		||||
        $user = \Federator\DIO\User::getUserByName(
 | 
			
		||||
            $dbh,
 | 
			
		||||
| 
						 | 
				
			
			@ -69,10 +70,6 @@ class Outbox implements \Federator\Api\FedUsers\FedUsersInterface
 | 
			
		|||
        if ($page !== '') {
 | 
			
		||||
            $id .= '?page=' . urlencode($page);
 | 
			
		||||
        }
 | 
			
		||||
        if ($page === '' || $outbox->count() == 0) {
 | 
			
		||||
            $outbox->setFirst($id);
 | 
			
		||||
            $outbox->setLast($id . '&min=0');
 | 
			
		||||
        }
 | 
			
		||||
        if (sizeof($items)>0) {
 | 
			
		||||
            $newestId = $items[0]->getPublished();
 | 
			
		||||
            $oldestId = $items[sizeof($items)-1]->getPublished();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -244,7 +244,7 @@ class ContentNation implements Connector
 | 
			
		|||
     */
 | 
			
		||||
    public function getRemoteUserByName(string $_name)
 | 
			
		||||
    {
 | 
			
		||||
        if (preg_match("#^([^@]+)@([^/]+)$#", $_name, $matches) === 1) {
 | 
			
		||||
        if (preg_match("#^([^@]+)@([^/]+)#", $_name, $matches) === 1) {
 | 
			
		||||
            $_name = $matches[1];
 | 
			
		||||
        }
 | 
			
		||||
        // validate name
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,13 +48,14 @@ class Mastodon implements Connector
 | 
			
		|||
        $this->service = $config['mastodon']['service-uri'];
 | 
			
		||||
        $this->main = $main;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * get the host this connector is dedicated to
 | 
			
		||||
     *
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function getHost() {
 | 
			
		||||
    public function getHost()
 | 
			
		||||
    {
 | 
			
		||||
        return "mastodon.social";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -68,22 +69,35 @@ class Mastodon implements Connector
 | 
			
		|||
     */
 | 
			
		||||
    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 = [];
 | 
			
		||||
 | 
			
		||||
        do {
 | 
			
		||||
            if ($min !== '') {
 | 
			
		||||
                $remoteURL .= '&minTS=' . urlencode($min);
 | 
			
		||||
            }
 | 
			
		||||
            if ($max !== '') {
 | 
			
		||||
                $remoteURL .= '&maxTS=' . urlencode($max);
 | 
			
		||||
            }
 | 
			
		||||
        [$outboxResponse, $outboxInfo] = \Federator\Main::getFromRemote($remoteURL, ['Accept: application/activity+json']);
 | 
			
		||||
 | 
			
		||||
        if ($outboxInfo['http_code'] !== 200) {
 | 
			
		||||
            echo "MastodonConnector::getRemotePostsByUser HTTP call failed for remoteURL $remoteURL\n";
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $outbox = json_decode($outboxResponse, true);
 | 
			
		||||
 | 
			
		||||
        // retrieve ALL outbox items - disabled for now
 | 
			
		||||
        /* do {
 | 
			
		||||
            // Fetch the current page of items (first or subsequent pages)
 | 
			
		||||
            [$outboxResponse, $outboxInfo] = \Federator\Main::getFromRemote($remoteURL, ['Accept: application/activity+json']);
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            if ($outboxInfo['http_code'] !== 200) {
 | 
			
		||||
                echo "aborting";
 | 
			
		||||
                echo "MastodonConnector::getRemotePostsByUser HTTP call failed for remoteURL $remoteURL\n";
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -94,18 +108,25 @@ class Mastodon implements Connector
 | 
			
		|||
                $items = array_merge($items, $outbox['orderedItems']);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Step 4: Use 'last' URL to determine pagination
 | 
			
		||||
            if (isset($outbox['last'])) {
 | 
			
		||||
                // The 'last' URL will usually have a query string that includes min_id for the next set of results
 | 
			
		||||
                $remoteURL = $outbox['last']; // Update to the last URL for the next page of items
 | 
			
		||||
            // Use 'next' or 'last' URL to determine pagination
 | 
			
		||||
            if (isset($outbox['next'])) {
 | 
			
		||||
                $remoteURL = $outbox['next']; // Update target 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 {
 | 
			
		||||
                $remoteURL = "";
 | 
			
		||||
                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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        $items = [];
 | 
			
		||||
        } while ($remoteURL !== ""); // Continue fetching until no 'last' URL */
 | 
			
		||||
 | 
			
		||||
        // Follow `first` page (or get orderedItems directly)
 | 
			
		||||
        if (isset($outbox['orderedItems'])) {
 | 
			
		||||
| 
						 | 
				
			
			@ -122,42 +143,86 @@ class Mastodon implements Connector
 | 
			
		|||
 | 
			
		||||
        // Convert to internal representation
 | 
			
		||||
        $posts = [];
 | 
			
		||||
        $host = $_SERVER['SERVER_NAME'];
 | 
			
		||||
        foreach ($items as $activity) {
 | 
			
		||||
            if (!isset($activity['type']) || $activity['type'] !== 'Create' || !isset($activity['object'])) {
 | 
			
		||||
                continue; // Skip non-Create activities
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $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);
 | 
			
		||||
            switch ($activity['type']) {
 | 
			
		||||
                case 'Create':
 | 
			
		||||
                    if (!isset($activity['object'])) {
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                $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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue