forked from grumpydevelop/federator
initial support for actually sending NewContent
- integrated functionality to actually send new content to federated recipients and followers (IT WORKS!!) - changed the way we remove a follow to return the removed followId (used in order to build the undo follow activity)
This commit is contained in:
parent
7a5870de95
commit
5c90b4cfc9
5 changed files with 229 additions and 41 deletions
|
@ -140,9 +140,6 @@ class NewContent implements \Federator\Api\APIInterface
|
||||||
&& (filter_var($receiver, FILTER_VALIDATE_URL) !== false);
|
&& (filter_var($receiver, FILTER_VALIDATE_URL) !== false);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!in_array($posterName, $receivers, true)) {
|
|
||||||
$receivers[] = $posterName;
|
|
||||||
}
|
|
||||||
foreach ($receivers as $receiver) {
|
foreach ($receivers as $receiver) {
|
||||||
if ($receiver === '' || !is_string($receiver)) {
|
if ($receiver === '' || !is_string($receiver)) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -173,7 +170,6 @@ class NewContent implements \Federator\Api\APIInterface
|
||||||
$domain = parse_url($receiver, PHP_URL_HOST);
|
$domain = parse_url($receiver, PHP_URL_HOST);
|
||||||
if ($receiverName === null || $domain === null) {
|
if ($receiverName === null || $domain === null) {
|
||||||
if ($receiver === $posterName) {
|
if ($receiver === $posterName) {
|
||||||
$users[] = $receiver;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
error_log("NewContent::post no receiverName or domain found for receiver: " . $receiver);
|
error_log("NewContent::post no receiverName or domain found for receiver: " . $receiver);
|
||||||
|
@ -232,12 +228,13 @@ class NewContent implements \Federator\Api\APIInterface
|
||||||
* connector to fetch use with
|
* connector to fetch use with
|
||||||
* @param \Federator\Cache\Cache|null $cache
|
* @param \Federator\Cache\Cache|null $cache
|
||||||
* optional caching service
|
* optional caching service
|
||||||
|
* @param string $host host url of our server (e.g. https://federator.com)
|
||||||
* @param string $_user user that triggered the post
|
* @param string $_user user that triggered the post
|
||||||
* @param string $_recipientId recipient of the post
|
* @param string $_recipientId recipient of the post
|
||||||
* @param \Federator\Data\ActivityPub\Common\Activity $newActivity the activity that we received
|
* @param \Federator\Data\ActivityPub\Common\Activity $newActivity the activity that we received
|
||||||
* @return boolean response
|
* @return boolean response
|
||||||
*/
|
*/
|
||||||
public static function postForUser($dbh, $connector, $cache, $_user, $_recipientId, $newActivity)
|
public static function postForUser($dbh, $connector, $cache, $host, $_user, $_recipientId, $newActivity)
|
||||||
{
|
{
|
||||||
if (!isset($_user)) {
|
if (!isset($_user)) {
|
||||||
error_log("NewContent::postForUser no user given");
|
error_log("NewContent::postForUser no user given");
|
||||||
|
@ -284,13 +281,15 @@ class NewContent implements \Federator\Api\APIInterface
|
||||||
if ($actor !== '') {
|
if ($actor !== '') {
|
||||||
$followerUsername = basename((string) (parse_url($actor, PHP_URL_PATH) ?? ''));
|
$followerUsername = basename((string) (parse_url($actor, PHP_URL_PATH) ?? ''));
|
||||||
$followerDomain = parse_url($actor, PHP_URL_HOST);
|
$followerDomain = parse_url($actor, PHP_URL_HOST);
|
||||||
|
$newIdUrl = \Federator\DIO\Followers::generateNewFollowId($dbh, $host);
|
||||||
|
$newActivity->setID($newIdUrl);
|
||||||
if (is_string($followerDomain)) {
|
if (is_string($followerDomain)) {
|
||||||
$followerId = "{$followerUsername}@{$followerDomain}";
|
$followerId = "{$followerUsername}@{$followerDomain}";
|
||||||
$success = \Federator\DIO\Followers::addFollow($dbh, $followerId, $user->id, $followerDomain);
|
// $success = \Federator\DIO\Followers::sendFollowRequest($dbh, $connector, $cache, $user->id, $followerId, $followerDomain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($success === false) {
|
if ($success === false) {
|
||||||
error_log("NewContent::postForUser: Failed to add follower for user $user->id");
|
error_log("NewContent::postForUser Failed to add follower for user $user->id");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -318,12 +317,19 @@ class NewContent implements \Federator\Api\APIInterface
|
||||||
$followerDomain = parse_url($actor, PHP_URL_HOST);
|
$followerDomain = parse_url($actor, PHP_URL_HOST);
|
||||||
if (is_string($followerDomain)) {
|
if (is_string($followerDomain)) {
|
||||||
$followerId = "{$followerUsername}@{$followerDomain}";
|
$followerId = "{$followerUsername}@{$followerDomain}";
|
||||||
$success = \Federator\DIO\Followers::removeFollow($dbh, $followerId, $user->id);
|
$removedId = \Federator\DIO\Followers::removeFollow($dbh, $followerId, $user->id);
|
||||||
|
if ($removedId !== false) {
|
||||||
|
$object->setID($removedId);
|
||||||
|
$newActivity->setObject($object);
|
||||||
|
$success = true;
|
||||||
|
} else {
|
||||||
|
error_log("NewContent::postForUser Failed to remove follow for user $user->id");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($success === false) {
|
if ($success === false) {
|
||||||
error_log("NewContent::postForUser: Failed to remove follower for user $user->id");
|
error_log("NewContent::postForUser Failed to remove follower for user $user->id");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'Like':
|
case 'Like':
|
||||||
|
@ -334,7 +340,7 @@ class NewContent implements \Federator\Api\APIInterface
|
||||||
// \Federator\DIO\Votes::removeVote($dbh, $user->id, $targetId);
|
// \Federator\DIO\Votes::removeVote($dbh, $user->id, $targetId);
|
||||||
\Federator\DIO\Posts::deletePost($dbh, $targetId);
|
\Federator\DIO\Posts::deletePost($dbh, $targetId);
|
||||||
} else {
|
} else {
|
||||||
error_log("NewContent::postForUser: Error in Undo Like/Dislike 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;
|
break;
|
||||||
|
@ -358,7 +364,7 @@ class NewContent implements \Federator\Api\APIInterface
|
||||||
} else if (is_string($object)) {
|
} else if (is_string($object)) {
|
||||||
\Federator\DIO\Posts::deletePost($dbh, $object);
|
\Federator\DIO\Posts::deletePost($dbh, $object);
|
||||||
} else {
|
} else {
|
||||||
error_log("NewContent::postForUser: Error in Undo for user $user->id, object is not a string or object");
|
error_log("NewContent::postForUser Error in Undo for user $user->id, object is not a string or object");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -370,7 +376,7 @@ class NewContent implements \Federator\Api\APIInterface
|
||||||
// \Federator\DIO\Votes::addVote($dbh, $user->id, $targetId, 'like');
|
// \Federator\DIO\Votes::addVote($dbh, $user->id, $targetId, 'like');
|
||||||
\Federator\DIO\Posts::savePost($dbh, $user->id, $newActivity);
|
\Federator\DIO\Posts::savePost($dbh, $user->id, $newActivity);
|
||||||
} else {
|
} else {
|
||||||
error_log("NewContent::postForUser: Error in Add Like/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;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -391,13 +397,118 @@ class NewContent implements \Federator\Api\APIInterface
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
error_log("NewContent::postForUser: Unhandled activity type $type for user $user->id");
|
error_log("NewContent::postForUser Unhandled activity type $type for user $user->id");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$response = self::sendActivity($dbh, $host, $user, $recipient, $newActivity);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
error_log("NewContent::postForUser Failed to send activity: " . $e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (empty($response)) {
|
||||||
|
error_log("NewContent::postForUser Sent activity to $recipient->id");
|
||||||
|
} else {
|
||||||
|
error_log("NewContent::postForUser Sent activity to $recipient->id with response: " . json_encode($response, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send activity to federated server
|
||||||
|
*
|
||||||
|
* @param \mysqli $dbh database handle
|
||||||
|
* @param string $host host url of our server (e.g. federator)
|
||||||
|
* @param \Federator\Data\User $sender source user
|
||||||
|
* @param \Federator\Data\FedUser $target federated target user
|
||||||
|
* @param \Federator\Data\ActivityPub\Common\Activity $activity activity to send
|
||||||
|
* @return string|true the generated follow ID on success, false on failure
|
||||||
|
*/
|
||||||
|
public static function sendActivity($dbh, $host, $sender, $target, $activity)
|
||||||
|
{
|
||||||
|
if ($dbh === false) {
|
||||||
|
throw new \Federator\Exceptions\ServerError("NewContent::sendActivity Failed to get database handle");
|
||||||
|
}
|
||||||
|
|
||||||
|
$inboxUrl = $target->inboxURL;
|
||||||
|
|
||||||
|
$json = json_encode($activity, JSON_UNESCAPED_SLASHES);
|
||||||
|
|
||||||
|
if ($json === false) {
|
||||||
|
throw new \Exception('Failed to encode JSON: ' . json_last_error_msg());
|
||||||
|
}
|
||||||
|
$digest = 'SHA-256=' . base64_encode(hash('sha256', $json, true));
|
||||||
|
$date = gmdate('D, d M Y H:i:s') . ' GMT';
|
||||||
|
$parsed = parse_url($inboxUrl);
|
||||||
|
if ($parsed === false) {
|
||||||
|
throw new \Exception('Failed to parse URL: ' . $inboxUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($parsed['host']) || !isset($parsed['path'])) {
|
||||||
|
throw new \Exception('Invalid inbox URL: missing host or path');
|
||||||
|
}
|
||||||
|
$extHost = $parsed['host'];
|
||||||
|
$path = $parsed['path'];
|
||||||
|
|
||||||
|
// Build the signature string
|
||||||
|
$signatureString = "(request-target): post {$path}\n" .
|
||||||
|
"host: {$extHost}\n" .
|
||||||
|
"date: {$date}\n" .
|
||||||
|
"digest: {$digest}";
|
||||||
|
|
||||||
|
// Get rsa private key
|
||||||
|
$privateKey = \Federator\DIO\User::getrsaprivate($dbh, $sender->id); // OR from DB
|
||||||
|
if ($privateKey === false) {
|
||||||
|
throw new \Exception('Failed to get private key');
|
||||||
|
}
|
||||||
|
$pkeyId = openssl_pkey_get_private($privateKey);
|
||||||
|
|
||||||
|
if ($pkeyId === false) {
|
||||||
|
throw new \Exception('Invalid private key');
|
||||||
|
}
|
||||||
|
|
||||||
|
openssl_sign($signatureString, $signature, $pkeyId, OPENSSL_ALGO_SHA256);
|
||||||
|
$signature_b64 = base64_encode($signature);
|
||||||
|
|
||||||
|
// Build keyId (public key ID from your actor object)
|
||||||
|
$keyId = $host . '/' . $sender->id . '#main-key';
|
||||||
|
|
||||||
|
$signatureHeader = 'keyId="' . $keyId . '",algorithm="rsa-sha256",headers="(request-target) host date digest",signature="' . $signature_b64 . '"';
|
||||||
|
|
||||||
|
$ch = curl_init($inboxUrl);
|
||||||
|
if ($ch === false) {
|
||||||
|
throw new \Exception('Failed to initialize cURL');
|
||||||
|
}
|
||||||
|
$headers = [
|
||||||
|
'Host: ' . $extHost,
|
||||||
|
'Date: ' . $date,
|
||||||
|
'Digest: ' . $digest,
|
||||||
|
'Content-Type: application/activity+json',
|
||||||
|
'Signature: ' . $signatureHeader,
|
||||||
|
'Accept: application/activity+json',
|
||||||
|
];
|
||||||
|
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||||
|
$response = curl_exec($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
// Log the response for debugging if needed
|
||||||
|
if ($response === false) {
|
||||||
|
throw new \Exception("Failed to send activity: " . curl_error($ch));
|
||||||
|
} else {
|
||||||
|
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
if ($httpcode != 200 && $httpcode != 202) {
|
||||||
|
throw new \Exception("Unexpected HTTP code $httpcode: $response");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get internal represenation as json string
|
* get internal represenation as json string
|
||||||
* @return string json string or html
|
* @return string json string or html
|
||||||
|
|
|
@ -388,25 +388,97 @@ class Followers
|
||||||
return $idurl; // Return the generated follow ID
|
return $idurl; // Return the generated follow ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generate new follow id
|
||||||
|
*
|
||||||
|
* @param \mysqli $dbh database handle
|
||||||
|
* @param string $hostUrl the host URL (e.g. federator URL)
|
||||||
|
* @return string the new follow id
|
||||||
|
*/
|
||||||
|
public static function generateNewFollowId($dbh, $hostUrl)
|
||||||
|
{
|
||||||
|
// Generate a new unique follow ID
|
||||||
|
do {
|
||||||
|
$newId = bin2hex(openssl_random_pseudo_bytes(16));
|
||||||
|
$newIdUrl = $hostUrl . '/' . $newId;
|
||||||
|
|
||||||
|
// Check if the generated ID is unique
|
||||||
|
$sql = 'select id from follows where id = ?';
|
||||||
|
$stmt = $dbh->prepare($sql);
|
||||||
|
if ($stmt === false) {
|
||||||
|
throw new \Federator\Exceptions\ServerError("Followers::generateNewFollowId Failed to prepare id-check statement");
|
||||||
|
}
|
||||||
|
$stmt->bind_param("s", $newIdUrl);
|
||||||
|
$foundId = 0;
|
||||||
|
$ret = $stmt->bind_result($foundId);
|
||||||
|
$stmt->execute();
|
||||||
|
if ($ret) {
|
||||||
|
$stmt->fetch();
|
||||||
|
}
|
||||||
|
$stmt->close();
|
||||||
|
} while ($foundId > 0);
|
||||||
|
|
||||||
|
return $newIdUrl;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* remove follow
|
* remove follow
|
||||||
*
|
*
|
||||||
* @param \mysqli $dbh database handle
|
* @param \mysqli $dbh database handle
|
||||||
* @param string $sourceUser source user id
|
* @param string $sourceUser source user id
|
||||||
* @param string $targetUserId target user id
|
* @param string $targetUserId target user id
|
||||||
* @return bool true on success
|
* @return string|false removed followId on success, false on failure
|
||||||
*/
|
*/
|
||||||
public static function removeFollow($dbh, $sourceUser, $targetUserId)
|
public static function removeFollow($dbh, $sourceUser, $targetUserId)
|
||||||
{
|
{
|
||||||
|
// Combine retrieval and removal in one query using MySQL's RETURNING (if supported)
|
||||||
|
$sql = 'delete from follows where source_user = ? and target_user = ? RETURNING id';
|
||||||
|
$stmt = $dbh->prepare($sql);
|
||||||
|
if ($stmt !== false) {
|
||||||
|
$stmt->bind_param("ss", $sourceUser, $targetUserId);
|
||||||
|
if ($stmt->execute()) {
|
||||||
|
$stmt->bind_result($followId);
|
||||||
|
if ($stmt->fetch() === true) {
|
||||||
|
$stmt->close();
|
||||||
|
if (!empty($followId)) {
|
||||||
|
return $followId;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$stmt->close();
|
||||||
|
} else {
|
||||||
|
// Fallback for MySQL versions that do not support RETURNING
|
||||||
|
// First, fetch the id of the follow to be removed
|
||||||
|
$sql = 'select id from follows where source_user = ? and target_user = ?';
|
||||||
|
$stmt = $dbh->prepare($sql);
|
||||||
|
if ($stmt === false) {
|
||||||
|
throw new \Federator\Exceptions\ServerError("Followers::removeFollow Failed to prepare select statement");
|
||||||
|
}
|
||||||
|
$stmt->bind_param("ss", $sourceUser, $targetUserId);
|
||||||
|
$stmt->execute();
|
||||||
|
$stmt->bind_result($followId);
|
||||||
|
$found = $stmt->fetch();
|
||||||
|
$stmt->close();
|
||||||
|
|
||||||
|
if ($found === false || empty($followId)) {
|
||||||
|
return false; // No such follow found
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, delete the row
|
||||||
$sql = 'delete from follows where source_user = ? and target_user = ?';
|
$sql = 'delete from follows where source_user = ? and target_user = ?';
|
||||||
$stmt = $dbh->prepare($sql);
|
$stmt = $dbh->prepare($sql);
|
||||||
if ($stmt === false) {
|
if ($stmt === false) {
|
||||||
throw new \Federator\Exceptions\ServerError("Followers::removeFollow Failed to prepare statement");
|
throw new \Federator\Exceptions\ServerError("Followers::removeFollow Failed to prepare delete statement");
|
||||||
}
|
}
|
||||||
$stmt->bind_param("ss", $sourceUser, $targetUserId);
|
$stmt->bind_param("ss", $sourceUser, $targetUserId);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
$affectedRows = $stmt->affected_rows;
|
$affectedRows = $stmt->affected_rows;
|
||||||
$stmt->close();
|
$stmt->close();
|
||||||
return $affectedRows > 0;
|
|
||||||
|
return $affectedRows > 0 ? $followId : false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ class InboxJob extends \Federator\Api
|
||||||
*/
|
*/
|
||||||
public function perform(): bool
|
public function perform(): bool
|
||||||
{
|
{
|
||||||
error_log("InboxJob: Starting inbox job");
|
error_log("InboxJob: Starting job");
|
||||||
$user = $this->args['user'];
|
$user = $this->args['user'];
|
||||||
$recipientId = $this->args['recipientId'];
|
$recipientId = $this->args['recipientId'];
|
||||||
$activity = $this->args['activity'];
|
$activity = $this->args['activity'];
|
||||||
|
|
|
@ -52,7 +52,7 @@ class NewContentJob extends \Federator\Api
|
||||||
*/
|
*/
|
||||||
public function perform(): bool
|
public function perform(): bool
|
||||||
{
|
{
|
||||||
error_log("NewContentJob: Starting inbox job");
|
error_log("NewContentJob: Starting job");
|
||||||
$user = $this->args['user'];
|
$user = $this->args['user'];
|
||||||
$recipientId = $this->args['recipientId'];
|
$recipientId = $this->args['recipientId'];
|
||||||
$activity = $this->args['activity'];
|
$activity = $this->args['activity'];
|
||||||
|
@ -63,8 +63,11 @@ class NewContentJob extends \Federator\Api
|
||||||
error_log("NewContentJob: Failed to create activity from JSON");
|
error_log("NewContentJob: Failed to create activity from JSON");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
$domain = $this->config['generic']['externaldomain'];
|
||||||
|
|
||||||
\Federator\Api\V1\NewContent::postForUser($this->dbh, $this->connector, $this->cache, $user, $recipientId, $activity);
|
$ourUrl = 'https://' . $domain;
|
||||||
|
|
||||||
|
\Federator\Api\V1\NewContent::postForUser($this->dbh, $this->connector, $this->cache, $ourUrl, $user, $recipientId, $activity);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -139,23 +139,25 @@ class ContentNation implements Connector
|
||||||
$activities = $r['activities'];
|
$activities = $r['activities'];
|
||||||
$config = $this->main->getConfig();
|
$config = $this->main->getConfig();
|
||||||
$domain = $config['generic']['externaldomain'];
|
$domain = $config['generic']['externaldomain'];
|
||||||
|
$ourUrl = 'https://' . $domain;
|
||||||
|
|
||||||
$imgpath = $this->config['userdata']['path'];
|
$imgpath = $this->config['userdata']['path'];
|
||||||
$userdata = $this->config['userdata']['url'];
|
$userdata = $this->config['userdata']['url'];
|
||||||
foreach ($activities as $activity) {
|
foreach ($activities as $activity) {
|
||||||
switch ($activity['type']) {
|
switch ($activity['type']) {
|
||||||
case 'Article':
|
case 'Article':
|
||||||
$create = new \Federator\Data\ActivityPub\Common\Create();
|
$create = new \Federator\Data\ActivityPub\Common\Create();
|
||||||
$create->setAActor('https://' . $domain . '/' . $userId);
|
$create->setAActor($ourUrl . '/' . $userId);
|
||||||
$create->setID($activity['id'])
|
$create->setID($activity['id'])
|
||||||
->setPublished($activity['published'] ?? $activity['timestamp'])
|
->setPublished($activity['published'] ?? $activity['timestamp'])
|
||||||
->addTo('https://' . $domain . '/' . $userId . '/followers')
|
->addTo($ourUrl . '/' . $userId . '/followers')
|
||||||
->addCC("https://www.w3.org/ns/activitystreams#Public");
|
->addCC("https://www.w3.org/ns/activitystreams#Public");
|
||||||
$create->setURL('https://' . $domain . '/' . $activity['profilename'] . '/' . $activity['name']);
|
$create->setURL($ourUrl . '/' . $activity['profilename'] . '/' . $activity['name']);
|
||||||
$create->setID('https://' . $domain . '/' . $activity['profilename'] . '/' . $activity['id']);
|
$create->setID($ourUrl . '/' . $activity['profilename'] . '/' . $activity['id']);
|
||||||
$apArticle = new \Federator\Data\ActivityPub\Common\Article();
|
$apArticle = new \Federator\Data\ActivityPub\Common\Article();
|
||||||
if (array_key_exists('tags', $activity)) {
|
if (array_key_exists('tags', $activity)) {
|
||||||
foreach ($activity['tags'] as $tag) {
|
foreach ($activity['tags'] as $tag) {
|
||||||
$href = 'https://' . $domain . '/search.htm?tagsearch=' . urlencode($tag);
|
$href = $ourUrl . '/search.htm?tagsearch=' . urlencode($tag);
|
||||||
$tagObj = new \Federator\Data\ActivityPub\Common\Tag();
|
$tagObj = new \Federator\Data\ActivityPub\Common\Tag();
|
||||||
$tagObj->setHref($href)
|
$tagObj->setHref($href)
|
||||||
->setName('#' . urlencode(str_replace(' ', '', $tag)))
|
->setName('#' . urlencode(str_replace(' ', '', $tag)))
|
||||||
|
@ -165,7 +167,7 @@ class ContentNation implements Connector
|
||||||
}
|
}
|
||||||
$apArticle->setPublished($activity['published'])
|
$apArticle->setPublished($activity['published'])
|
||||||
->setName($activity['title'])
|
->setName($activity['title'])
|
||||||
->setAttributedTo('https://' . $domain . '/' . $activity['profilename'])
|
->setAttributedTo($ourUrl . '/' . $activity['profilename'])
|
||||||
->setContent(
|
->setContent(
|
||||||
$activity['teaser'] ??
|
$activity['teaser'] ??
|
||||||
$this->main->translate(
|
$this->main->translate(
|
||||||
|
@ -175,10 +177,10 @@ class ContentNation implements Connector
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
->addTo("https://www.w3.org/ns/activitystreams#Public")
|
->addTo("https://www.w3.org/ns/activitystreams#Public")
|
||||||
->addCC('https://' . $domain . '/' . $userId . '/followers.json');
|
->addCC($ourUrl . '/' . $userId . '/followers.json');
|
||||||
$articleimage = $activity['imagealt'] ??
|
$articleimage = $activity['imagealt'] ??
|
||||||
$this->main->translate($activity['language'], 'article', 'image');
|
$this->main->translate($activity['language'], 'article', 'image');
|
||||||
$idurl = 'https://' . $domain . '/' . $userId . '/' . $activity['name'];
|
$idurl = $ourUrl . '/' . $userId . '/' . $activity['name'];
|
||||||
$apArticle->setID($idurl)
|
$apArticle->setID($idurl)
|
||||||
->setURL($idurl);
|
->setURL($idurl);
|
||||||
$image = $activity['image'] ?? $activity['profileimg'];
|
$image = $activity['image'] ?? $activity['profileimg'];
|
||||||
|
@ -200,15 +202,15 @@ class ContentNation implements Connector
|
||||||
|
|
||||||
case 'Comment':
|
case 'Comment':
|
||||||
$create = new \Federator\Data\ActivityPub\Common\Create();
|
$create = new \Federator\Data\ActivityPub\Common\Create();
|
||||||
$create->setAActor('https://' . $domain . '/' . $userId);
|
$create->setAActor($ourUrl . '/' . $userId);
|
||||||
$create->setID($activity['id'])
|
$create->setID($activity['id'])
|
||||||
->setPublished($activity['published'] ?? $activity['timestamp'])
|
->setPublished($activity['published'] ?? $activity['timestamp'])
|
||||||
->addTo('https://' . $domain . '/' . $userId . '/followers')
|
->addTo($ourUrl . '/' . $userId . '/followers')
|
||||||
->addCC("https://www.w3.org/ns/activitystreams#Public");
|
->addCC("https://www.w3.org/ns/activitystreams#Public");
|
||||||
$commentJson = $activity;
|
$commentJson = $activity;
|
||||||
$commentJson['type'] = 'Note';
|
$commentJson['type'] = 'Note';
|
||||||
$commentJson['summary'] = $activity['subject'];
|
$commentJson['summary'] = $activity['subject'];
|
||||||
$commentJson['id'] = 'https://' . $domain . '/' . $activity['articleOwnerName'] . '/' . $activity['articleName'] . '#' . $activity['id'];
|
$commentJson['id'] = $ourUrl . '/' . $activity['articleOwnerName'] . '/' . $activity['articleName'] . '#' . $activity['id'];
|
||||||
$note = \Federator\Data\ActivityPub\Factory::newFromJson($commentJson, "");
|
$note = \Federator\Data\ActivityPub\Factory::newFromJson($commentJson, "");
|
||||||
if ($note === null) {
|
if ($note === null) {
|
||||||
error_log("ContentNation::getRemotePostsByUser couldn't create comment");
|
error_log("ContentNation::getRemotePostsByUser couldn't create comment");
|
||||||
|
@ -218,11 +220,11 @@ class ContentNation implements Connector
|
||||||
}
|
}
|
||||||
$note->setID($commentJson['id']);
|
$note->setID($commentJson['id']);
|
||||||
if (!isset($commentJson['parent']) || $commentJson['parent'] === null) {
|
if (!isset($commentJson['parent']) || $commentJson['parent'] === null) {
|
||||||
$note->setInReplyTo('https://' . $domain . '/' . $activity['articleOwnerName'] . '/' . $activity['articleName']);
|
$note->setInReplyTo($ourUrl . '/' . $activity['articleOwnerName'] . '/' . $activity['articleName']);
|
||||||
} else {
|
} else {
|
||||||
$note->setInReplyTo('https://' . $domain . '/' . $activity['articleOwnerName'] . '/' . $activity['articleName'] . "#" . $commentJson['parent']);
|
$note->setInReplyTo($ourUrl . '/' . $activity['articleOwnerName'] . '/' . $activity['articleName'] . "#" . $commentJson['parent']);
|
||||||
}
|
}
|
||||||
$url = 'https://' . $domain . '/' . $activity['articleOwnerName'] . '/' . $activity['articleName'] . '#' . $activity['id'];
|
$url = $ourUrl . '/' . $activity['articleOwnerName'] . '/' . $activity['articleName'] . '#' . $activity['id'];
|
||||||
$create->setURL($url);
|
$create->setURL($url);
|
||||||
$create->setID($url);
|
$create->setID($url);
|
||||||
$create->setObject($note);
|
$create->setObject($note);
|
||||||
|
@ -233,7 +235,7 @@ class ContentNation implements Connector
|
||||||
// Build Like/Dislike as top-level activity
|
// Build Like/Dislike as top-level activity
|
||||||
$likeType = $activity['upvote'] === true ? 'Like' : 'Dislike';
|
$likeType = $activity['upvote'] === true ? 'Like' : 'Dislike';
|
||||||
$like = new \Federator\Data\ActivityPub\Common\Activity($likeType);
|
$like = new \Federator\Data\ActivityPub\Common\Activity($likeType);
|
||||||
$like->setAActor('https://' . $domain . '/' . $userId);
|
$like->setAActor($ourUrl . '/' . $userId);
|
||||||
$like->setID($activity['id'])
|
$like->setID($activity['id'])
|
||||||
->setPublished($activity['published'] ?? $activity['timestamp']);
|
->setPublished($activity['published'] ?? $activity['timestamp']);
|
||||||
// $like->addTo("https://www.w3.org/ns/activitystreams#Public")
|
// $like->addTo("https://www.w3.org/ns/activitystreams#Public")
|
||||||
|
@ -246,7 +248,7 @@ class ContentNation implements Connector
|
||||||
[$activity['username']]
|
[$activity['username']]
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$objectUrl = 'https://' . $domain . '/' . $userId . '/' . $activity['articlename'];
|
$objectUrl = $ourUrl . '/' . $userId . '/' . $activity['articlename'];
|
||||||
$like->setURL($objectUrl . '#' . $activity['id']);
|
$like->setURL($objectUrl . '#' . $activity['id']);
|
||||||
$like->setID($objectUrl . '#' . $activity['id']);
|
$like->setID($objectUrl . '#' . $activity['id']);
|
||||||
$like->setObject($objectUrl);
|
$like->setObject($objectUrl);
|
||||||
|
|
Loading…
Add table
Reference in a new issue