forked from grumpydevelop/federator
		
	initial rough support for sending follow to CN
we now send follows to CN to the api/profile/profileName/fedfollow endpoint, either with a post, or a delete. - commit also contains files where line-endings suddenly changed to crlf (now it's back to lf). - targetRequestType (post/delete) now depends on the activity - we now also set the id to username when fetching a user from CN
This commit is contained in:
		
							parent
							
								
									097f871ed6
								
							
						
					
					
						commit
						2ae81a3748
					
				
					 3 changed files with 118 additions and 14 deletions
				
			
		| 
						 | 
					@ -194,6 +194,8 @@ class Inbox implements \Federator\Api\FedUsers\FedUsersInterface
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $users = array_unique($users); // remove duplicates
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (empty($users)) { // todo remove after proper implementation, debugging for now
 | 
					        if (empty($users)) { // todo remove after proper implementation, debugging for now
 | 
				
			||||||
            $rootDir = PROJECT_ROOT . '/';
 | 
					            $rootDir = PROJECT_ROOT . '/';
 | 
				
			||||||
            // Save the raw input and parsed JSON to a file for inspection
 | 
					            // Save the raw input and parsed JSON to a file for inspection
 | 
				
			||||||
| 
						 | 
					@ -229,15 +231,7 @@ class Inbox implements \Federator\Api\FedUsers\FedUsersInterface
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try {
 | 
					 | 
				
			||||||
            $articleId = \Federator\DIO\Posts::getOriginalArticleId($dbh, $inboxActivity);
 | 
					 | 
				
			||||||
            if ($articleId !== null) {
 | 
					 | 
				
			||||||
        $connector->sendActivity($user, $inboxActivity);
 | 
					        $connector->sendActivity($user, $inboxActivity);
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        } catch (\Throwable $e) {
 | 
					 | 
				
			||||||
            error_log("Inbox::postForUser Error sending activity to connector. Exception: " . $e->getMessage());
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return "success";
 | 
					        return "success";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -334,7 +328,7 @@ class Inbox implements \Federator\Api\FedUsers\FedUsersInterface
 | 
				
			||||||
            $cache
 | 
					            $cache
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        if ($recipient === null || $recipient->id === null) {
 | 
					        if ($recipient === null || $recipient->id === null) {
 | 
				
			||||||
            error_log("Inbox::postForUser couldn't find user: $_recipientId");
 | 
					            error_log("Inbox::postForUser couldn't find recipient: $_recipientId");
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -194,6 +194,9 @@ class NewContent implements \Federator\Api\APIInterface
 | 
				
			||||||
                $users[] = $user->id;
 | 
					                $users[] = $user->id;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $users = array_unique($users); // remove duplicates
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (empty($users)) { // todo remove after proper implementation, debugging for now
 | 
					        if (empty($users)) { // todo remove after proper implementation, debugging for now
 | 
				
			||||||
            $rootDir = PROJECT_ROOT . '/';
 | 
					            $rootDir = PROJECT_ROOT . '/';
 | 
				
			||||||
            // Save the raw input and parsed JSON to a file for inspection
 | 
					            // Save the raw input and parsed JSON to a file for inspection
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -314,6 +314,7 @@ class ContentNation implements Connector
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        $user = new \Federator\Data\User();
 | 
					        $user = new \Federator\Data\User();
 | 
				
			||||||
        $user->externalid = $_name;
 | 
					        $user->externalid = $_name;
 | 
				
			||||||
 | 
					        $user->id = $_name;
 | 
				
			||||||
        $user->iconMediaType = $r['iconMediaType'];
 | 
					        $user->iconMediaType = $r['iconMediaType'];
 | 
				
			||||||
        $user->iconURL = $r['iconURL'];
 | 
					        $user->iconURL = $r['iconURL'];
 | 
				
			||||||
        $user->imageMediaType = $r['imageMediaType'];
 | 
					        $user->imageMediaType = $r['imageMediaType'];
 | 
				
			||||||
| 
						 | 
					@ -675,8 +676,9 @@ class ContentNation implements Connector
 | 
				
			||||||
    public function sendActivity($sender, $activity)
 | 
					    public function sendActivity($sender, $activity)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $targetUrl = $this->service;
 | 
					        $targetUrl = $this->service;
 | 
				
			||||||
 | 
					        $targetRequestType = 'post'; // Default request type
 | 
				
			||||||
        // Convert ActivityPub activity to ContentNation JSON format and retrieve target url
 | 
					        // Convert ActivityPub activity to ContentNation JSON format and retrieve target url
 | 
				
			||||||
        $jsonData = self::activityToJson($this->main->getDatabase(), $this->service, $activity, $targetUrl);
 | 
					        $jsonData = self::activityToJson($this->main->getDatabase(), $this->service, $activity, $targetUrl, $targetRequestType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ($jsonData === false) {
 | 
					        if ($jsonData === false) {
 | 
				
			||||||
            error_log("ContentNation::sendActivity failed to convert activity to JSON");
 | 
					            error_log("ContentNation::sendActivity failed to convert activity to JSON");
 | 
				
			||||||
| 
						 | 
					@ -702,7 +704,7 @@ class ContentNation implements Connector
 | 
				
			||||||
        $path = $parsed['path'];
 | 
					        $path = $parsed['path'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Build the signature string
 | 
					        // Build the signature string
 | 
				
			||||||
        $signatureString = "(request-target): post {$path}\n" .
 | 
					        $signatureString = "(request-target): $targetRequestType {$path}\n" .
 | 
				
			||||||
            "host: {$extHost}\n" .
 | 
					            "host: {$extHost}\n" .
 | 
				
			||||||
            "date: {$date}\n" .
 | 
					            "date: {$date}\n" .
 | 
				
			||||||
            "digest: {$digest}";
 | 
					            "digest: {$digest}";
 | 
				
			||||||
| 
						 | 
					@ -740,7 +742,16 @@ class ContentNation implements Connector
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 | 
					        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 | 
				
			||||||
 | 
					        switch ($targetRequestType) {
 | 
				
			||||||
 | 
					            case 'post':
 | 
				
			||||||
                curl_setopt($ch, CURLOPT_POST, true);
 | 
					                curl_setopt($ch, CURLOPT_POST, true);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case 'delete':
 | 
				
			||||||
 | 
					                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                throw new \Exception("ContentNation::sendActivity Unsupported target request type: $targetRequestType");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
 | 
					        curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
 | 
				
			||||||
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
 | 
					        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
 | 
				
			||||||
        $response = curl_exec($ch);
 | 
					        $response = curl_exec($ch);
 | 
				
			||||||
| 
						 | 
					@ -765,11 +776,13 @@ class ContentNation implements Connector
 | 
				
			||||||
     * @param string $serviceUrl the service URL
 | 
					     * @param string $serviceUrl the service URL
 | 
				
			||||||
     * @param \Federator\Data\ActivityPub\Common\Activity $activity the activity
 | 
					     * @param \Federator\Data\ActivityPub\Common\Activity $activity the activity
 | 
				
			||||||
     * @param string $targetUrl the target URL for the activity
 | 
					     * @param string $targetUrl the target URL for the activity
 | 
				
			||||||
 | 
					     * @param string $targetRequestType the target request type (e.g., 'post', 'delete', etc.)
 | 
				
			||||||
     * @return array<string, mixed>|false the json data or false on failure
 | 
					     * @return array<string, mixed>|false the json data or false on failure
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private static function activityToJson($dbh, $serviceUrl, \Federator\Data\ActivityPub\Common\Activity $activity, string &$targetUrl)
 | 
					    private function activityToJson($dbh, $serviceUrl, \Federator\Data\ActivityPub\Common\Activity $activity, string &$targetUrl, string &$targetRequestType)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $type = strtolower($activity->getType());
 | 
					        $type = strtolower($activity->getType());
 | 
				
			||||||
 | 
					        $targetRequestType = 'post'; // Default request type
 | 
				
			||||||
        switch ($type) {
 | 
					        switch ($type) {
 | 
				
			||||||
            case 'create':
 | 
					            case 'create':
 | 
				
			||||||
            case 'update':
 | 
					            case 'update':
 | 
				
			||||||
| 
						 | 
					@ -820,6 +833,50 @@ class ContentNation implements Connector
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case 'follow':
 | 
				
			||||||
 | 
					                $profileUrl = $activity->getObject();
 | 
				
			||||||
 | 
					                if (!is_string($profileUrl)) {
 | 
				
			||||||
 | 
					                    error_log("ContentNation::activityToJson Invalid profile URL: " . json_encode($profileUrl));
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                $receiverName = basename((string) (parse_url($profileUrl, PHP_URL_PATH) ?? ''));
 | 
				
			||||||
 | 
					                $ourDomain = parse_url($profileUrl, PHP_URL_HOST);
 | 
				
			||||||
 | 
					                if ($receiverName === "" || $ourDomain === "") {
 | 
				
			||||||
 | 
					                    error_log("ContentNation::activityToJson no profileName or domain found for object url: " . $profileUrl);
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                $receiver = $receiverName;
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    $localUser = \Federator\DIO\User::getUserByName(
 | 
				
			||||||
 | 
					                        $dbh,
 | 
				
			||||||
 | 
					                        $receiver,
 | 
				
			||||||
 | 
					                        $this,
 | 
				
			||||||
 | 
					                        null
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					                } catch (\Throwable $e) {
 | 
				
			||||||
 | 
					                    error_log("ContentNation::activityToJson get user by name: " . $receiver . ". Exception: " . $e->getMessage());
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if ($localUser === null || $localUser->id === null) {
 | 
				
			||||||
 | 
					                    error_log("ContentNation::activityToJson couldn't find user: $receiver");
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                $targetUrl = $serviceUrl . '/api/profile/' . $localUser->id . '/fedfollow';
 | 
				
			||||||
 | 
					                $type = 'follow';
 | 
				
			||||||
 | 
					                $actor = $activity->getAActor();
 | 
				
			||||||
 | 
					                $fedUser = \Federator\DIO\FedUser::getUserByName(
 | 
				
			||||||
 | 
					                    $dbh,
 | 
				
			||||||
 | 
					                    $actor,
 | 
				
			||||||
 | 
					                    null
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                $from = $fedUser->id;
 | 
				
			||||||
 | 
					                return [
 | 
				
			||||||
 | 
					                    'type' => $type,
 | 
				
			||||||
 | 
					                    'id' => $activity->getID(),
 | 
				
			||||||
 | 
					                    'from' => $from,
 | 
				
			||||||
 | 
					                    'to' => $localUser->id,
 | 
				
			||||||
 | 
					                ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            case 'like':
 | 
					            case 'like':
 | 
				
			||||||
            case 'dislike':
 | 
					            case 'dislike':
 | 
				
			||||||
                $articleId = \Federator\DIO\Posts::getOriginalArticleId($dbh, $activity);
 | 
					                $articleId = \Federator\DIO\Posts::getOriginalArticleId($dbh, $activity);
 | 
				
			||||||
| 
						 | 
					@ -859,6 +916,56 @@ class ContentNation implements Connector
 | 
				
			||||||
                if (is_object($object)) {
 | 
					                if (is_object($object)) {
 | 
				
			||||||
                    $objType = strtolower($object->getType());
 | 
					                    $objType = strtolower($object->getType());
 | 
				
			||||||
                    switch ($objType) {
 | 
					                    switch ($objType) {
 | 
				
			||||||
 | 
					                        case 'follow':
 | 
				
			||||||
 | 
					                            $profileUrl = $object->getObject();
 | 
				
			||||||
 | 
					                            if (!is_string($profileUrl)) {
 | 
				
			||||||
 | 
					                                error_log("ContentNation::activityToJson Invalid profile URL: " . json_encode($profileUrl));
 | 
				
			||||||
 | 
					                                return false;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            $receiverName = basename((string) (parse_url($profileUrl, PHP_URL_PATH) ?? ''));
 | 
				
			||||||
 | 
					                            $ourDomain = parse_url($profileUrl, PHP_URL_HOST);
 | 
				
			||||||
 | 
					                            if ($receiverName === "" || $ourDomain === "") {
 | 
				
			||||||
 | 
					                                error_log("ContentNation::activityToJson no profileName or domain found for object url: " . $profileUrl);
 | 
				
			||||||
 | 
					                                return false;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            $receiver = $receiverName;
 | 
				
			||||||
 | 
					                            try {
 | 
				
			||||||
 | 
					                                $localUser = \Federator\DIO\User::getUserByName(
 | 
				
			||||||
 | 
					                                    $dbh,
 | 
				
			||||||
 | 
					                                    $receiver,
 | 
				
			||||||
 | 
					                                    $this,
 | 
				
			||||||
 | 
					                                    null
 | 
				
			||||||
 | 
					                                );
 | 
				
			||||||
 | 
					                            } catch (\Throwable $e) {
 | 
				
			||||||
 | 
					                                error_log("ContentNation::activityToJson get user by name: " . $receiver . ". Exception: " . $e->getMessage());
 | 
				
			||||||
 | 
					                                return false;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            if ($localUser === null || $localUser->id === null) {
 | 
				
			||||||
 | 
					                                error_log("ContentNation::activityToJson couldn't find user: $receiver");
 | 
				
			||||||
 | 
					                                return false;
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            $targetUrl = $serviceUrl . '/api/profile/' . $localUser->id . '/fedfollow';
 | 
				
			||||||
 | 
					                            $type = 'follow';
 | 
				
			||||||
 | 
					                            if ($object instanceof \Federator\Data\ActivityPub\Common\Activity) {
 | 
				
			||||||
 | 
					                                $actor = $object->getAActor();
 | 
				
			||||||
 | 
					                                if ($actor !== '') {
 | 
				
			||||||
 | 
					                                    $fedUser = \Federator\DIO\FedUser::getUserByName(
 | 
				
			||||||
 | 
					                                        $dbh,
 | 
				
			||||||
 | 
					                                        $actor,
 | 
				
			||||||
 | 
					                                        null
 | 
				
			||||||
 | 
					                                    );
 | 
				
			||||||
 | 
					                                    $from = $fedUser->id;
 | 
				
			||||||
 | 
					                                    $targetRequestType = 'delete';
 | 
				
			||||||
 | 
					                                    return [
 | 
				
			||||||
 | 
					                                        'type' => $type,
 | 
				
			||||||
 | 
					                                        'id' => $object->getID(),
 | 
				
			||||||
 | 
					                                        'from' => $from,
 | 
				
			||||||
 | 
					                                        'to' => $localUser->id,
 | 
				
			||||||
 | 
					                                    ];
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        case 'like':
 | 
					                        case 'like':
 | 
				
			||||||
                        case 'dislike':
 | 
					                        case 'dislike':
 | 
				
			||||||
                            $articleId = \Federator\DIO\Posts::getOriginalArticleId($dbh, $activity);
 | 
					                            $articleId = \Federator\DIO\Posts::getOriginalArticleId($dbh, $activity);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue