forked from grumpydevelop/federator
		
	proper support for undoing votes and articles
- added option to remove the like/dislike from an article/comment with creating the correct Undo activity - added option to remove article with creating the correct Undo activity - fixed problem where post might not be accepted/saved when no receiver was set (posterName was previously excluded from receivers)
This commit is contained in:
		
							parent
							
								
									572bb376c1
								
							
						
					
					
						commit
						7a5870de95
					
				
					 3 changed files with 284 additions and 198 deletions
				
			
		| 
						 | 
				
			
			@ -149,11 +149,6 @@ class NewContent implements \Federator\Api\APIInterface
 | 
			
		|||
            }
 | 
			
		||||
 | 
			
		||||
            if (str_ends_with($receiver, '/followers')) {
 | 
			
		||||
                $actor = $newActivity->getAActor();
 | 
			
		||||
                if ($actor === null || !is_string($actor)) {
 | 
			
		||||
                    error_log("NewContent::post no actor found");
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if ($posterName === null) {
 | 
			
		||||
                    error_log("NewContent::post no username found");
 | 
			
		||||
| 
						 | 
				
			
			@ -177,6 +172,10 @@ class NewContent implements \Federator\Api\APIInterface
 | 
			
		|||
                $receiverName = basename((string) (parse_url($receiver, PHP_URL_PATH) ?? ''));
 | 
			
		||||
                $domain = parse_url($receiver, PHP_URL_HOST);
 | 
			
		||||
                if ($receiverName === null || $domain === null) {
 | 
			
		||||
                    if ($receiver === $posterName) {
 | 
			
		||||
                        $users[] = $receiver;
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
                    error_log("NewContent::post no receiverName or domain found for receiver: " . $receiver);
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -327,15 +326,15 @@ class NewContent implements \Federator\Api\APIInterface
 | 
			
		|||
                                error_log("NewContent::postForUser: Failed to remove follower for user $user->id");
 | 
			
		||||
                            }
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 'Vote':
 | 
			
		||||
                            // Undo Vote (remove vote)
 | 
			
		||||
                        case 'Like':
 | 
			
		||||
                        case 'Dislike':
 | 
			
		||||
                            if (method_exists($object, 'getObject')) {
 | 
			
		||||
                                $targetId = $object->getObject();
 | 
			
		||||
                                if (is_string($targetId)) {
 | 
			
		||||
                                    // \Federator\DIO\Votes::removeVote($dbh, $user->id, $targetId);
 | 
			
		||||
                                    \Federator\DIO\Posts::deletePost($dbh, $targetId);
 | 
			
		||||
                                } else {
 | 
			
		||||
                                    error_log("NewContent::postForUser: Error in Undo Vote for user $user->id, targetId is not a string");
 | 
			
		||||
                                    error_log("NewContent::postForUser: Error in Undo Like/Dislike for user $user->id, targetId is not a string");
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                            break;
 | 
			
		||||
| 
						 | 
				
			
			@ -346,6 +345,15 @@ class NewContent implements \Federator\Api\APIInterface
 | 
			
		|||
                                \Federator\DIO\Posts::deletePost($dbh, $noteId);
 | 
			
		||||
                            }
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 'Article':
 | 
			
		||||
                            // Undo Article (remove article)
 | 
			
		||||
                            if (method_exists($object, 'getID')) {
 | 
			
		||||
                                $articleId = $object->getID();
 | 
			
		||||
                                \Federator\DIO\Posts::deletePost($dbh, $articleId);
 | 
			
		||||
                                // also remove latest saved article-update
 | 
			
		||||
                                \Federator\DIO\Posts::deletePost($dbh, $articleId . '#update');
 | 
			
		||||
                            }
 | 
			
		||||
                            break;
 | 
			
		||||
                    }
 | 
			
		||||
                } else if (is_string($object)) {
 | 
			
		||||
                    \Federator\DIO\Posts::deletePost($dbh, $object);
 | 
			
		||||
| 
						 | 
				
			
			@ -355,25 +363,14 @@ class NewContent implements \Federator\Api\APIInterface
 | 
			
		|||
                break;
 | 
			
		||||
 | 
			
		||||
            case 'Like':
 | 
			
		||||
                // Add Like
 | 
			
		||||
            case 'Dislike':
 | 
			
		||||
                // Add Like/Dislike
 | 
			
		||||
                $targetId = $newActivity->getObject();
 | 
			
		||||
                if (is_string($targetId)) {
 | 
			
		||||
                    // \Federator\DIO\Votes::addVote($dbh, $user->id, $targetId, 'like');
 | 
			
		||||
                    \Federator\DIO\Posts::savePost($dbh, $user->id, $newActivity);
 | 
			
		||||
                } else {
 | 
			
		||||
                    error_log("NewContent::postForUser: Error in Add Like for user $user->id, targetId is not a string");
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case 'Dislike':
 | 
			
		||||
                // Add Dislike
 | 
			
		||||
                $targetId = $newActivity->getObject();
 | 
			
		||||
                if (is_string($targetId)) {
 | 
			
		||||
                    // \Federator\DIO\Votes::addVote($dbh, $user->id, $targetId, 'dislike');
 | 
			
		||||
                    \Federator\DIO\Posts::savePost($dbh, $user->id, $newActivity);
 | 
			
		||||
                } else {
 | 
			
		||||
                    error_log("NewContent::postForUser: Error in Add Dislike for user $user->id, targetId is not a string");
 | 
			
		||||
                    error_log("NewContent::postForUser: Error in Add Like/Dislike for user $user->id, targetId is not a string");
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,6 +58,12 @@ class Factory
 | 
			
		|||
            case 'Vote':
 | 
			
		||||
                $return = new Common\Vote();
 | 
			
		||||
                break;
 | 
			
		||||
            case 'Like':
 | 
			
		||||
                $return = new Common\Like();
 | 
			
		||||
                break;
 | 
			
		||||
            case 'Dislike':
 | 
			
		||||
                $return = new Common\Dislike();
 | 
			
		||||
                break;
 | 
			
		||||
            case 'Inbox':
 | 
			
		||||
                $return = new Common\Inbox();
 | 
			
		||||
                break;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -368,7 +368,7 @@ class ContentNation implements Connector
 | 
			
		|||
     * @param array<string, mixed> $jsonData the json data from our platfrom
 | 
			
		||||
     * @return \Federator\Data\ActivityPub\Common\Activity|false
 | 
			
		||||
     */
 | 
			
		||||
    public function jsonToActivity(array $jsonData)
 | 
			
		||||
    public function jsonToActivity($jsonData)
 | 
			
		||||
    {
 | 
			
		||||
        $returnActivity = false;
 | 
			
		||||
        // Common fields for all activity types
 | 
			
		||||
| 
						 | 
				
			
			@ -390,190 +390,273 @@ class ContentNation implements Connector
 | 
			
		|||
 | 
			
		||||
        $ap['actor'] = $ourUrl . '/' . $actorName;
 | 
			
		||||
 | 
			
		||||
        // Handle specific fields based on the type
 | 
			
		||||
        switch ($jsonData['type']) {
 | 
			
		||||
            case 'article':
 | 
			
		||||
                $articleName = $jsonData['object']['name'] ?? null;
 | 
			
		||||
                $articleOwnerName = $jsonData['object']['ownerName'] ?? null;
 | 
			
		||||
                // Set Create-level fields
 | 
			
		||||
                $updatedOn = $jsonData['object']['modified'] ?? null;
 | 
			
		||||
                $originalPublished = $jsonData['object']['published'] ?? null;
 | 
			
		||||
                $update = $updatedOn !== $originalPublished;
 | 
			
		||||
                $ap['published'] = $updatedOn ?? $originalPublished;
 | 
			
		||||
                $ap['id'] = $ourUrl . "/" . $articleOwnerName . "/" . $articleName;
 | 
			
		||||
                $ap['url'] = $ourUrl . "/" . $articleOwnerName . "/" . $articleName;
 | 
			
		||||
                $ap['type'] = $update ? 'Update' : 'Create';
 | 
			
		||||
                $ap['actor'] = $ourUrl . '/' . $actorName;
 | 
			
		||||
                // Set Article-level fields
 | 
			
		||||
                $ap['object'] = [
 | 
			
		||||
                    'type' => 'Article',
 | 
			
		||||
                    'id' => $ourUrl . "/" . $articleOwnerName . "/" . $articleName,
 | 
			
		||||
                    'name' => $jsonData['object']['title'] ?? null,
 | 
			
		||||
                    'published' => $originalPublished,
 | 
			
		||||
                    'summary' => $jsonData['object']['summary'] ?? null,
 | 
			
		||||
                    'content' => $jsonData['object']['content'] ?? null,
 | 
			
		||||
                    'attributedTo' => $ap['actor'],
 | 
			
		||||
                    'url' => $ap['url'],
 | 
			
		||||
                    'cc' => ['https://www.w3.org/ns/activitystreams#Public'],
 | 
			
		||||
                ];
 | 
			
		||||
                if ($update) {
 | 
			
		||||
                    $ap['id'] .= '#update';
 | 
			
		||||
                    $ap['url'] .= '#update';
 | 
			
		||||
                    $ap['object']['updated'] = $updatedOn;
 | 
			
		||||
                }
 | 
			
		||||
                $ap['cc'] = ['https://www.w3.org/ns/activitystreams#Public'];
 | 
			
		||||
                if (isset($jsonData['object']['tags'])) {
 | 
			
		||||
                    if (is_array($jsonData['object']['tags'])) {
 | 
			
		||||
                        foreach ($jsonData['object']['tags'] as $tag) {
 | 
			
		||||
                            $ap['object']['tags'][] = $tag;
 | 
			
		||||
                        }
 | 
			
		||||
                    } elseif (is_string($jsonData['object']['tags']) && $jsonData['object']['tags'] !== '') {
 | 
			
		||||
                        // If it's a single tag as a string, add it as a one-element array
 | 
			
		||||
                        $ap['object']['tags'][] = $jsonData['object']['tags'];
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (isset($jsonData['options'])) {
 | 
			
		||||
                    if (isset($jsonData['options']['informFollowers'])) {
 | 
			
		||||
                        if ($jsonData['options']['informFollowers'] === true) {
 | 
			
		||||
                            $ap['to'][] = $ourUrl . '/' . $actorName . '/followers';
 | 
			
		||||
                            $ap['object']['to'][] = $ourUrl . '/' . $actorName . '/followers';
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                $returnActivity = \Federator\Data\ActivityPub\Factory::newActivityFromJson($ap);
 | 
			
		||||
                if ($returnActivity === false) {
 | 
			
		||||
                    error_log("ContentNation::jsonToActivity couldn't create article");
 | 
			
		||||
                    $returnActivity = new \Federator\Data\ActivityPub\Common\Activity('Create');
 | 
			
		||||
                } else {
 | 
			
		||||
                    $returnActivity->setID($ap['id']);
 | 
			
		||||
                    $returnActivity->setURL($ap['url']);
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case 'comment':
 | 
			
		||||
                $commentId = $jsonData['object']['id'] ?? null;
 | 
			
		||||
                $articleName = $jsonData['object']['articleName'] ?? null;
 | 
			
		||||
                $articleOwnerName = $jsonData['object']['articleOwnerName'] ?? null;
 | 
			
		||||
                // Set Create-level fields
 | 
			
		||||
                $ap['published'] = $jsonData['object']['published'] ?? null;
 | 
			
		||||
                $ap['id'] = $ourUrl . "/" . $articleOwnerName . "/" . $articleName . "#" . $commentId;
 | 
			
		||||
                $ap['url'] = $ourUrl . "/" . $articleOwnerName . "/" . $articleName . "#" . $commentId;
 | 
			
		||||
                $ap['type'] = 'Create';
 | 
			
		||||
                $ap['object'] = [
 | 
			
		||||
                    'type' => 'Note',
 | 
			
		||||
                    'id' => $ourUrl . "/" . $articleOwnerName . "/" . $articleName . "#" . $commentId,
 | 
			
		||||
                    'content' => $jsonData['object']['content'] ?? null,
 | 
			
		||||
                    'summary' => $jsonData['object']['summary'] ?? null,
 | 
			
		||||
                ];
 | 
			
		||||
                $ap['cc'] = ['https://www.w3.org/ns/activitystreams#Public'];
 | 
			
		||||
                if (isset($jsonData['options'])) {
 | 
			
		||||
                    if (isset($jsonData['options']['informFollowers'])) {
 | 
			
		||||
                        if ($jsonData['options']['informFollowers'] === true) {
 | 
			
		||||
                            if ($actorName !== $articleOwnerName) {
 | 
			
		||||
                                $ap['to'][] = $ourUrl . '/' . $articleOwnerName;
 | 
			
		||||
                            }
 | 
			
		||||
                            $ap['to'][] = $ourUrl . '/' . $actorName . '/followers';
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                $replyType = $jsonData['object']['inReplyTo']['type'] ?? null;
 | 
			
		||||
                if ($replyType === "article") {
 | 
			
		||||
                    $ap['object']['inReplyTo'] = $ourUrl . "/" . $articleOwnerName . "/" . $articleName;
 | 
			
		||||
                } elseif ($replyType === "comment") {
 | 
			
		||||
                    $ap['object']['inReplyTo'] = $ourUrl . "/" . $articleOwnerName . "/" . $articleName . "#" . $jsonData['object']['inReplyTo']['id'];
 | 
			
		||||
                } else {
 | 
			
		||||
                    error_log("ContentNation::jsonToActivity unknown inReplyTo type: {$replyType}");
 | 
			
		||||
                }
 | 
			
		||||
                $returnActivity = \Federator\Data\ActivityPub\Factory::newActivityFromJson($ap);
 | 
			
		||||
                if ($returnActivity === false) {
 | 
			
		||||
                    error_log("ContentNation::jsonToActivity couldn't create comment");
 | 
			
		||||
                    $returnActivity = new \Federator\Data\ActivityPub\Common\Activity('Create');
 | 
			
		||||
                } else {
 | 
			
		||||
                    $returnActivity->setID($ap['id']);
 | 
			
		||||
                    $returnActivity->setURL($ap['url']);
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case 'vote':
 | 
			
		||||
                $votedOn = $jsonData['object']['type'] ?? null;
 | 
			
		||||
                $articleName = $jsonData['object']['articleName'] ?? null;
 | 
			
		||||
                $articleOwnerName = $jsonData['object']['articleOwnerName'] ?? null;
 | 
			
		||||
                $voteId = $jsonData['object']['id'] ?? null;
 | 
			
		||||
                $ap['id'] = $ourUrl . '/' . $articleOwnerName . '/' . $articleName . '#' . $voteId;
 | 
			
		||||
                $ap['url'] = $ourUrl . '/' . $articleOwnerName . '/' . $articleName . '#' . $voteId;
 | 
			
		||||
                if (
 | 
			
		||||
                    isset($jsonData['vote']['type']) &&
 | 
			
		||||
                    strtolower($jsonData['vote']['type']) === 'undo'
 | 
			
		||||
                ) {
 | 
			
		||||
        if (isset($jsonData['type'])) {
 | 
			
		||||
            switch ($jsonData['type']) {
 | 
			
		||||
                case 'undo':
 | 
			
		||||
                    $ap['type'] = 'Undo';
 | 
			
		||||
                } elseif ($jsonData['vote']['value'] == 1) {
 | 
			
		||||
                    $ap['type'] = 'Like';
 | 
			
		||||
                } elseif ($jsonData['vote']['value'] == 0) {
 | 
			
		||||
                    $ap['type'] = 'Dislike';
 | 
			
		||||
                } else {
 | 
			
		||||
                    error_log("ContentNation::jsonToActivity unknown vote type: {$jsonData['vote']['type']} and value: {$jsonData['vote']['value']}");
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                $objectId = $ourUrl . '/' . $articleOwnerName . '/' . $articleName;
 | 
			
		||||
                if ($votedOn === "comment") {
 | 
			
		||||
                    $objectId .= '#' . $jsonData['object']['commentId'];
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                $ap['object'] = $objectId;
 | 
			
		||||
 | 
			
		||||
                if ($ap['type'] === "Undo") {
 | 
			
		||||
                    $ap['object'] = $ap['id'];
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                /* if ($ap['type'] === 'Undo') {
 | 
			
		||||
                    $ap['object'] = [
 | 
			
		||||
                        'id' => $objectId,
 | 
			
		||||
                        'type' => 'Vote',
 | 
			
		||||
                    ];
 | 
			
		||||
                } else if (
 | 
			
		||||
                    isset($jsonData['object']['type']) &&
 | 
			
		||||
                    $jsonData['object']['type'] === 'Article'
 | 
			
		||||
                ) {
 | 
			
		||||
                    $ap['object'] = [
 | 
			
		||||
                        'id' => $objectId,
 | 
			
		||||
                        'type' => $jsonData['object']['type'],
 | 
			
		||||
                        'name' => $jsonData['object']['name'] ?? null,
 | 
			
		||||
                        'author' => $jsonData['object']['author'] ?? null,
 | 
			
		||||
                    ];
 | 
			
		||||
                } else if ($jsonData['object']['type'] === 'Comment') {
 | 
			
		||||
                    $ap['object'] = [
 | 
			
		||||
                        'id' => $objectId,
 | 
			
		||||
                        'type' => 'Note',
 | 
			
		||||
                        'author' => $jsonData['object']['author'] ?? null,
 | 
			
		||||
                    ];
 | 
			
		||||
                } */
 | 
			
		||||
 | 
			
		||||
                $returnActivity = \Federator\Data\ActivityPub\Factory::newActivityFromJson($ap);
 | 
			
		||||
                if ($returnActivity === false) {
 | 
			
		||||
                    error_log("ContentNation::jsonToActivity couldn't create vote");
 | 
			
		||||
                    if ($ap['type'] === "Like") {
 | 
			
		||||
                        $returnActivity = new \Federator\Data\ActivityPub\Common\Like();
 | 
			
		||||
                    } elseif ($ap['type'] === "Dislike") {
 | 
			
		||||
                        $returnActivity = new \Federator\Data\ActivityPub\Common\Dislike();
 | 
			
		||||
                    $ap['actor'] = $ourUrl . '/' . $actorName;
 | 
			
		||||
                    $objectType = $jsonData['object']['type'] ?? null;
 | 
			
		||||
                    if ($objectType === "article") {
 | 
			
		||||
                        $articleName = $jsonData['object']['name'] ?? null;
 | 
			
		||||
                        $ownerName = $jsonData['object']['ownerName'] ?? null;
 | 
			
		||||
                        $ap['id'] = $ourUrl . '/' . $ownerName . '/' . $articleName . '/undo';
 | 
			
		||||
                        $ap['object'] = self::generateObjectJson($ourUrl, $jsonData);
 | 
			
		||||
                    } elseif ($objectType === "comment") {
 | 
			
		||||
                        $articleName = $jsonData['object']['articleName'] ?? null;
 | 
			
		||||
                        $ownerName = $jsonData['object']['articleOwnerName'] ?? null;
 | 
			
		||||
                        $commentId = $jsonData['object']['id'] ?? null;
 | 
			
		||||
                        $ap['id'] = $ourUrl . '/' . $ownerName . '/' . $articleName . '#' . $commentId . '/undo';
 | 
			
		||||
                        $ap['object'] = self::generateObjectJson($ourUrl, $jsonData);
 | 
			
		||||
                    } elseif ($objectType === "vote") {
 | 
			
		||||
                        $id = $jsonData['object']['id'] ?? null;
 | 
			
		||||
                        $articleName = $jsonData['object']['articleName'] ?? null;
 | 
			
		||||
                        $articleOwnerName = $jsonData['object']['articleOwnerName'] ?? null;
 | 
			
		||||
                        $ap['id'] = $ourUrl . '/' . $articleOwnerName . '/' . $articleName . '#' . $id . '/undo';
 | 
			
		||||
                        $ap['published'] = $jsonData['object']['published'] ?? null;
 | 
			
		||||
                        $ap['actor'] = $ourUrl . '/' . $actorName;
 | 
			
		||||
                        $ap['object']['id'] = $ourUrl . '/' . $articleOwnerName . '/' . $articleName . '#' . $id;
 | 
			
		||||
                        $ap['object']['url'] = $ourUrl . '/' . $articleOwnerName . '/' . $articleName . '#' . $id;
 | 
			
		||||
                        $ap['object']['actor'] = $ourUrl . '/' . $actorName;
 | 
			
		||||
                        if ($jsonData['object']['vote']['value'] == 1) {
 | 
			
		||||
                            $ap['object']['type'] = 'Like';
 | 
			
		||||
                        } elseif ($jsonData['object']['vote']['value'] == 0) {
 | 
			
		||||
                            $ap['object']['type'] = 'Dislike';
 | 
			
		||||
                        } else {
 | 
			
		||||
                            error_log("ContentNation::jsonToActivity unknown vote value: {$jsonData['object']['vote']['value']}");
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                        $ap['object']['object'] = self::generateObjectJson($ourUrl, $jsonData);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        $returnActivity = new \Federator\Data\ActivityPub\Common\Undo();
 | 
			
		||||
                        error_log("ContentNation::jsonToActivity unknown undo type: {$objectType}");
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    $returnActivity->setID($ap['id']);
 | 
			
		||||
                    $returnActivity->setURL($ap['url']);
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
                    $returnActivity = \Federator\Data\ActivityPub\Factory::newActivityFromJson($ap);
 | 
			
		||||
                    if ($returnActivity === false) {
 | 
			
		||||
                        error_log("ContentNation::jsonToActivity couldn't create undo");
 | 
			
		||||
                        $returnActivity = new \Federator\Data\ActivityPub\Common\Undo();
 | 
			
		||||
                    } else {
 | 
			
		||||
                        $returnActivity->setID($ap['id']);
 | 
			
		||||
                        $returnActivity->setURL($ap['id']);
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                default:
 | 
			
		||||
                    // Handle unsupported types or fallback to default behavior
 | 
			
		||||
                    throw new \InvalidArgumentException("ContentNation::jsonToActivity Unsupported type: {$jsonData['type']}");
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            // Handle specific fields based on the type
 | 
			
		||||
            switch ($jsonData['object']['type']) {
 | 
			
		||||
                case 'article':
 | 
			
		||||
                    $articleName = $jsonData['object']['name'] ?? null;
 | 
			
		||||
                    $articleOwnerName = $jsonData['object']['ownerName'] ?? null;
 | 
			
		||||
                    // Set Create-level fields
 | 
			
		||||
                    $updatedOn = $jsonData['object']['modified'] ?? null;
 | 
			
		||||
                    $originalPublished = $jsonData['object']['published'] ?? null;
 | 
			
		||||
                    $update = $updatedOn !== $originalPublished;
 | 
			
		||||
                    $ap['published'] = $updatedOn ?? $originalPublished;
 | 
			
		||||
                    $ap['id'] = $ourUrl . "/" . $articleOwnerName . "/" . $articleName;
 | 
			
		||||
                    $ap['url'] = $ourUrl . "/" . $articleOwnerName . "/" . $articleName;
 | 
			
		||||
                    $ap['type'] = $update ? 'Update' : 'Create';
 | 
			
		||||
                    $ap['actor'] = $ourUrl . '/' . $actorName;
 | 
			
		||||
                    if ($update) {
 | 
			
		||||
                        $ap['id'] .= '#update';
 | 
			
		||||
                        $ap['url'] .= '#update';
 | 
			
		||||
                    }
 | 
			
		||||
                    $ap['cc'] = ['https://www.w3.org/ns/activitystreams#Public'];
 | 
			
		||||
 | 
			
		||||
            default:
 | 
			
		||||
                // Handle unsupported types or fallback to default behavior
 | 
			
		||||
                throw new \InvalidArgumentException("ContentNation::jsonToActivity Unsupported activity type: {$jsonData['type']}");
 | 
			
		||||
                    if (isset($jsonData['options'])) {
 | 
			
		||||
                        if (isset($jsonData['options']['informFollowers'])) {
 | 
			
		||||
                            if ($jsonData['options']['informFollowers'] === true) {
 | 
			
		||||
                                $ap['to'][] = $ourUrl . '/' . $actorName . '/followers';
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    $ap['object'] = self::generateObjectJson($ourUrl, $jsonData);
 | 
			
		||||
                    $returnActivity = \Federator\Data\ActivityPub\Factory::newActivityFromJson($ap);
 | 
			
		||||
                    if ($returnActivity === false) {
 | 
			
		||||
                        error_log("ContentNation::jsonToActivity couldn't create article");
 | 
			
		||||
                        $returnActivity = new \Federator\Data\ActivityPub\Common\Activity('Create');
 | 
			
		||||
                    } else {
 | 
			
		||||
                        $returnActivity->setID($ap['id']);
 | 
			
		||||
                        $returnActivity->setURL($ap['url']);
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case 'comment':
 | 
			
		||||
                    $commentId = $jsonData['object']['id'] ?? null;
 | 
			
		||||
                    $articleName = $jsonData['object']['articleName'] ?? null;
 | 
			
		||||
                    $articleOwnerName = $jsonData['object']['articleOwnerName'] ?? null;
 | 
			
		||||
                    // Set Create-level fields
 | 
			
		||||
                    $ap['published'] = $jsonData['object']['published'] ?? null;
 | 
			
		||||
                    $ap['actor'] = $ourUrl . '/' . $actorName;
 | 
			
		||||
                    $ap['id'] = $ourUrl . "/" . $articleOwnerName . "/" . $articleName . "#" . $commentId;
 | 
			
		||||
                    $ap['url'] = $ourUrl . "/" . $articleOwnerName . "/" . $articleName . "#" . $commentId;
 | 
			
		||||
                    $ap['type'] = 'Create';
 | 
			
		||||
                    $ap['cc'] = ['https://www.w3.org/ns/activitystreams#Public'];
 | 
			
		||||
                    if (isset($jsonData['options'])) {
 | 
			
		||||
                        if (isset($jsonData['options']['informFollowers'])) {
 | 
			
		||||
                            if ($jsonData['options']['informFollowers'] === true) {
 | 
			
		||||
                                if ($actorName !== $articleOwnerName) {
 | 
			
		||||
                                    $ap['to'][] = $ourUrl . '/' . $articleOwnerName;
 | 
			
		||||
                                }
 | 
			
		||||
                                $ap['to'][] = $ourUrl . '/' . $actorName . '/followers';
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    $ap['object'] = self::generateObjectJson($ourUrl, $jsonData);
 | 
			
		||||
                    $returnActivity = \Federator\Data\ActivityPub\Factory::newActivityFromJson($ap);
 | 
			
		||||
                    if ($returnActivity === false) {
 | 
			
		||||
                        error_log("ContentNation::jsonToActivity couldn't create comment");
 | 
			
		||||
                        $returnActivity = new \Federator\Data\ActivityPub\Common\Activity('Create');
 | 
			
		||||
                    } else {
 | 
			
		||||
                        $returnActivity->setID($ap['id']);
 | 
			
		||||
                        $returnActivity->setURL($ap['url']);
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case 'vote':
 | 
			
		||||
                    $articleName = $jsonData['object']['articleName'] ?? null;
 | 
			
		||||
                    $articleOwnerName = $jsonData['object']['articleOwnerName'] ?? null;
 | 
			
		||||
                    $voteId = $jsonData['object']['id'] ?? null;
 | 
			
		||||
                    $ap['published'] = $jsonData['object']['published'] ?? null;
 | 
			
		||||
                    $ap['actor'] = $ourUrl . '/' . $actorName;
 | 
			
		||||
                    $ap['id'] = $ourUrl . '/' . $articleOwnerName . '/' . $articleName . '#' . $voteId;
 | 
			
		||||
                    $ap['url'] = $ourUrl . '/' . $articleOwnerName . '/' . $articleName . '#' . $voteId;
 | 
			
		||||
                    if ($jsonData['object']['vote']['value'] == 1) {
 | 
			
		||||
                        $ap['type'] = 'Like';
 | 
			
		||||
                    } elseif ($jsonData['object']['vote']['value'] == 0) {
 | 
			
		||||
                        $ap['type'] = 'Dislike';
 | 
			
		||||
                    } else {
 | 
			
		||||
                        error_log("ContentNation::jsonToActivity unknown vote value: {$jsonData['object']['vote']['value']}");
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    $ap['object'] = self::generateObjectJson($ourUrl, $jsonData);
 | 
			
		||||
                    $returnActivity = \Federator\Data\ActivityPub\Factory::newActivityFromJson($ap);
 | 
			
		||||
                    if ($returnActivity === false) {
 | 
			
		||||
                        error_log("ContentNation::jsonToActivity couldn't create vote");
 | 
			
		||||
                        if ($ap['type'] === "Like") {
 | 
			
		||||
                            $returnActivity = new \Federator\Data\ActivityPub\Common\Like();
 | 
			
		||||
                        } elseif ($ap['type'] === "Dislike") {
 | 
			
		||||
                            $returnActivity = new \Federator\Data\ActivityPub\Common\Dislike();
 | 
			
		||||
                        } else {
 | 
			
		||||
                            $returnActivity = new \Federator\Data\ActivityPub\Common\Undo();
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        $returnActivity->setID($ap['id']);
 | 
			
		||||
                        $returnActivity->setURL($ap['url']);
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                default:
 | 
			
		||||
                    // Handle unsupported types or fallback to default behavior
 | 
			
		||||
                    throw new \InvalidArgumentException("ContentNation::jsonToActivity Unsupported object type: {$jsonData['type']}");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $returnActivity;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert jsonData to Activity format
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $ourUrl the url of our instance
 | 
			
		||||
     * @param array<string, mixed> $jsonData the json data from our platfrom
 | 
			
		||||
     * @return array|string|false the json object data or false
 | 
			
		||||
     */
 | 
			
		||||
    private static function generateObjectJson($ourUrl, $jsonData)
 | 
			
		||||
    {
 | 
			
		||||
        $objectType = $jsonData['object']['type'] ?? null;
 | 
			
		||||
        $actorData = $jsonData['actor'] ?? null;
 | 
			
		||||
        $actorName = $actorData['name'] ?? null;
 | 
			
		||||
 | 
			
		||||
        $actorUrl = $ourUrl . '/' . $actorName;
 | 
			
		||||
 | 
			
		||||
        if ($objectType === "article") {
 | 
			
		||||
            $articleName = $jsonData['object']['name'] ?? null;
 | 
			
		||||
            $articleOwnerName = $jsonData['object']['ownerName'] ?? null;
 | 
			
		||||
            $updatedOn = $jsonData['object']['modified'] ?? null;
 | 
			
		||||
            $originalPublished = $jsonData['object']['published'] ?? null;
 | 
			
		||||
            $update = $updatedOn !== $originalPublished;
 | 
			
		||||
            $returnJson = [
 | 
			
		||||
                'type' => 'Article',
 | 
			
		||||
                'id' => $ourUrl . "/" . $articleOwnerName . "/" . $articleName,
 | 
			
		||||
                'name' => $jsonData['object']['title'] ?? null,
 | 
			
		||||
                'published' => $originalPublished,
 | 
			
		||||
                'summary' => $jsonData['object']['summary'] ?? null,
 | 
			
		||||
                'content' => $jsonData['object']['content'] ?? null,
 | 
			
		||||
                'attributedTo' => $actorUrl,
 | 
			
		||||
                'url' => $ourUrl . "/" . $articleOwnerName . "/" . $articleName,
 | 
			
		||||
                'cc' => ['https://www.w3.org/ns/activitystreams#Public'],
 | 
			
		||||
            ];
 | 
			
		||||
            if ($update) {
 | 
			
		||||
                $returnJson['updated'] = $updatedOn;
 | 
			
		||||
            }
 | 
			
		||||
            if (isset($jsonData['object']['tags'])) {
 | 
			
		||||
                if (is_array($jsonData['object']['tags'])) {
 | 
			
		||||
                    foreach ($jsonData['object']['tags'] as $tag) {
 | 
			
		||||
                        $returnJson['tags'][] = $tag;
 | 
			
		||||
                    }
 | 
			
		||||
                } elseif (is_string($jsonData['object']['tags']) && $jsonData['object']['tags'] !== '') {
 | 
			
		||||
                    // If it's a single tag as a string, add it as a one-element array
 | 
			
		||||
                    $returnJson['tags'][] = $jsonData['object']['tags'];
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (isset($jsonData['options'])) {
 | 
			
		||||
                if (isset($jsonData['options']['informFollowers'])) {
 | 
			
		||||
                    if ($jsonData['options']['informFollowers'] === true) {
 | 
			
		||||
                        $returnJson['to'][] = $ourUrl . '/' . $actorName . '/followers';
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } elseif ($objectType === "comment") {
 | 
			
		||||
            $commentId = $jsonData['object']['id'] ?? null;
 | 
			
		||||
            $articleName = $jsonData['object']['articleName'] ?? null;
 | 
			
		||||
            $articleOwnerName = $jsonData['object']['articleOwnerName'] ?? null;
 | 
			
		||||
            $returnJson = [
 | 
			
		||||
                'type' => 'Note',
 | 
			
		||||
                'id' => $ourUrl . "/" . $articleOwnerName . "/" . $articleName . "#" . $commentId,
 | 
			
		||||
                'url' => $ourUrl . "/" . $articleOwnerName . "/" . $articleName . "#" . $commentId,
 | 
			
		||||
                'attributedTo' => $actorUrl,
 | 
			
		||||
                'content' => $jsonData['object']['content'] ?? null,
 | 
			
		||||
                'summary' => $jsonData['object']['summary'] ?? null,
 | 
			
		||||
                'published' => $jsonData['object']['published'] ?? null,
 | 
			
		||||
                'cc' => ['https://www.w3.org/ns/activitystreams#Public'],
 | 
			
		||||
            ];
 | 
			
		||||
            if (isset($jsonData['options'])) {
 | 
			
		||||
                if (isset($jsonData['options']['informFollowers'])) {
 | 
			
		||||
                    if ($jsonData['options']['informFollowers'] === true) {
 | 
			
		||||
                        $returnJson['to'][] = $ourUrl . '/' . $actorName . '/followers';
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            $replyType = $jsonData['object']['inReplyTo']['type'] ?? null;
 | 
			
		||||
            if ($replyType === "article") {
 | 
			
		||||
                $returnJson['object']['inReplyTo'] = $ourUrl . "/" . $articleOwnerName . "/" . $articleName;
 | 
			
		||||
            } elseif ($replyType === "comment") {
 | 
			
		||||
                $returnJson['object']['inReplyTo'] = $ourUrl . "/" . $articleOwnerName . "/" . $articleName . "#" . $jsonData['object']['inReplyTo']['id'];
 | 
			
		||||
            } else {
 | 
			
		||||
                error_log("ContentNation::generateObjectJson for comment - unknown inReplyTo type: {$replyType}");
 | 
			
		||||
            }
 | 
			
		||||
        } elseif ($objectType === "vote") {
 | 
			
		||||
            $votedOn = $jsonData['object']['type'] ?? null;
 | 
			
		||||
            $articleName = $jsonData['object']['articleName'] ?? null;
 | 
			
		||||
            $articleOwnerName = $jsonData['object']['articleOwnerName'] ?? null;
 | 
			
		||||
            $objectId = $ourUrl . '/' . $articleOwnerName . '/' . $articleName;
 | 
			
		||||
            if ($votedOn === "comment") {
 | 
			
		||||
                $objectId .= '#' . $jsonData['object']['commentId'];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $returnJson = $objectId;
 | 
			
		||||
        } else {
 | 
			
		||||
            error_log("ContentNation::generateObjectJson unknown object type: {$objectType}");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $returnJson;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * check if the headers include a valid signature
 | 
			
		||||
     *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue