fix following from mastodon -> CN

This commit is contained in:
Yannis Vogel 2025-05-25 20:22:34 +02:00
parent 5c90b4cfc9
commit 30c577c82f
No known key found for this signature in database
4 changed files with 94 additions and 31 deletions

View file

@ -77,6 +77,16 @@ class Inbox implements \Federator\Api\FedUsers\FedUsersInterface
$user = $inboxActivity->getAActor(); // url of the sender https://contentnation.net/username $user = $inboxActivity->getAActor(); // url of the sender https://contentnation.net/username
$username = basename((string) (parse_url($user, PHP_URL_PATH) ?? '')); $username = basename((string) (parse_url($user, PHP_URL_PATH) ?? ''));
$domain = parse_url($user, PHP_URL_HOST); $domain = parse_url($user, PHP_URL_HOST);
$userId = $username . '@' . $domain;
$user = \Federator\DIO\FedUser::getUserByName(
$dbh,
$userId,
$cache
);
if ($user === null || $user->id === null) {
error_log("Inbox::post couldn't find user: $userId");
throw new \Federator\Exceptions\ServerError("Inbox::post couldn't find user: $userId");
}
$users = []; $users = [];
@ -97,9 +107,26 @@ class Inbox implements \Federator\Api\FedUsers\FedUsersInterface
&& (filter_var($receiver, FILTER_VALIDATE_URL) !== false); && (filter_var($receiver, FILTER_VALIDATE_URL) !== false);
}); });
if (!in_array($username, $receivers, true)) { // Special handling for Follow and Undo follow activities
$receivers[] = $username; if (strtolower($inboxActivity->getType()) === 'follow') {
// For Follow, the object should hold the target
$object = $inboxActivity->getObject();
if ($object !== null && is_string($object)) {
$receivers[] = $object;
} }
} elseif (strtolower($inboxActivity->getType()) === 'undo') {
$object = $inboxActivity->getObject();
if ($object !== null && is_object($object)) {
// For Undo, the objects object should hold the target
if (strtolower($object->getType()) === 'follow') {
$objObject = $object->getObject();
if ($objObject !== null && is_string($objObject)) {
$receivers[] = $objObject;
}
}
}
}
foreach ($receivers as $receiver) { foreach ($receivers as $receiver) {
if ($receiver === '' || !is_string($receiver)) { if ($receiver === '' || !is_string($receiver)) {
continue; continue;
@ -136,14 +163,14 @@ class Inbox implements \Federator\Api\FedUsers\FedUsersInterface
continue; continue;
} }
$receiverName = basename((string) (parse_url($receiver, PHP_URL_PATH) ?? '')); $receiverName = basename((string) (parse_url($receiver, PHP_URL_PATH) ?? ''));
$domain = parse_url($receiver, PHP_URL_HOST); $ourDomain = parse_url($receiver, PHP_URL_HOST);
if ($receiverName === null || $domain === null) { if ($receiverName === null || $ourDomain === null) {
error_log("Inbox::post no receiverName or domain found for receiver: " . $receiver); error_log("Inbox::post no receiverName or domain found for receiver: " . $receiver);
continue; continue;
} }
$receiver = $receiverName . '@' . $domain; $receiver = $receiverName . '@' . $ourDomain;
try { try {
$user = \Federator\DIO\User::getUserByName( $localUser = \Federator\DIO\User::getUserByName(
$dbh, $dbh,
$receiver, $receiver,
$connector, $connector,
@ -153,11 +180,11 @@ class Inbox implements \Federator\Api\FedUsers\FedUsersInterface
error_log("Inbox::post get user by name: " . $receiver . ". Exception: " . $e->getMessage()); error_log("Inbox::post get user by name: " . $receiver . ". Exception: " . $e->getMessage());
continue; continue;
} }
if ($user === null || $user->id === null) { if ($localUser === null || $localUser->id === null) {
error_log("Inbox::post couldn't find user: $receiver"); error_log("Inbox::post couldn't find user: $receiver");
continue; continue;
} }
$users[] = $user->id; $users[] = $localUser->id;
} }
} }
@ -172,15 +199,15 @@ class Inbox implements \Federator\Api\FedUsers\FedUsersInterface
} }
foreach ($users as $receiver) { foreach ($users as $receiver) {
if (!isset($user)) { if (!isset($receiver)) {
continue; continue;
} }
$token = \Resque::enqueue('inbox', 'Federator\\Jobs\\InboxJob', [ $token = \Resque::enqueue('inbox', 'Federator\\Jobs\\InboxJob', [
'user' => $username . '@' . $domain, 'user' => $user->id,
'recipientId' => $receiver, 'recipientId' => $receiver,
'activity' => $inboxActivity->toObject(), 'activity' => $inboxActivity->toObject(),
]); ]);
error_log("Inbox::post enqueued job for user: $user with token: $token"); error_log("Inbox::post enqueued job for user: $user->id with token: $token");
} }
return "success"; return "success";
} }
@ -241,12 +268,7 @@ class Inbox implements \Federator\Api\FedUsers\FedUsersInterface
$success = false; $success = false;
$actor = $inboxActivity->getAActor(); $actor = $inboxActivity->getAActor();
if ($actor !== '') { if ($actor !== '') {
$followerUsername = basename((string) (parse_url($actor, PHP_URL_PATH) ?? '')); $success = \Federator\DIO\Followers::addExternalFollow($dbh, $inboxActivity->getID(), $user->id, $recipient->id);
$followerDomain = parse_url($actor, PHP_URL_HOST);
if (is_string($followerDomain)) {
$followerId = "{$followerUsername}@{$followerDomain}";
$success = \Federator\DIO\Followers::addFollow($dbh, $followerId, $user->id, $followerDomain);
}
} }
if ($success === false) { if ($success === false) {
error_log("Inbox::postForUser: Failed to add follower for user $user->id"); error_log("Inbox::postForUser: Failed to add follower for user $user->id");
@ -273,12 +295,7 @@ class Inbox implements \Federator\Api\FedUsers\FedUsersInterface
if ($object instanceof \Federator\Data\ActivityPub\Common\Activity) { if ($object instanceof \Federator\Data\ActivityPub\Common\Activity) {
$actor = $object->getAActor(); $actor = $object->getAActor();
if ($actor !== '') { if ($actor !== '') {
$followerUsername = basename((string) (parse_url($actor, PHP_URL_PATH) ?? '')); $success = \Federator\DIO\Followers::removeFollow($dbh, $user->id, $recipient->id);
$followerDomain = parse_url($actor, PHP_URL_HOST);
if (is_string($followerDomain)) {
$followerId = "{$followerUsername}@{$followerDomain}";
$success = \Federator\DIO\Followers::removeFollow($dbh, $followerId, $user->id);
}
} }
} }
if ($success === false) { if ($success === false) {

View file

@ -276,21 +276,21 @@ class NewContent implements \Federator\Api\APIInterface
switch ($type) { switch ($type) {
case 'Follow': case 'Follow':
$success = false; // $success = false;
$actor = $newActivity->getAActor(); $actor = $newActivity->getAActor();
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); $newIdUrl = \Federator\DIO\Followers::generateNewFollowId($dbh, $host);
$newActivity->setID($newIdUrl); $newActivity->setID($newIdUrl);
if (is_string($followerDomain)) { /* if (is_string($followerDomain)) {
$followerId = "{$followerUsername}@{$followerDomain}"; $followerId = "{$followerUsername}@{$followerDomain}";
// $success = \Federator\DIO\Followers::sendFollowRequest($dbh, $connector, $cache, $user->id, $followerId, $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;
case 'Delete': case 'Delete':

View file

@ -21,6 +21,11 @@ class Follow extends Activity
$this->object = $object; $this->object = $object;
} }
public function getObject(): string
{
return $this->object;
}
public function __construct() public function __construct()
{ {
parent::__construct("Follow"); parent::__construct("Follow");

View file

@ -388,6 +388,47 @@ class Followers
return $idurl; // Return the generated follow ID return $idurl; // Return the generated follow ID
} }
/**
* add follow
*
* @param \mysqli $dbh database handle
* @param string $followId the follow ID to use (should be an external url)
* @param string $sourceUser source user id
* @param string $targetUserId target user id
* @return boolean true on success, false on failure
*/
public static function addExternalFollow($dbh, $followId, $sourceUser, $targetUserId)
{
// Check if we already follow this user
$sql = 'select id from follows where source_user = ? and target_user = ?';
$stmt = $dbh->prepare($sql);
if ($stmt === false) {
throw new \Federator\Exceptions\ServerError("Followers::addExternalFollow Failed to prepare statement");
}
$stmt->bind_param("ss", $sourceUser, $targetUserId);
$foundId = 0;
$ret = $stmt->bind_result($foundId);
$stmt->execute();
if ($ret) {
$stmt->fetch();
}
$stmt->close();
if ($foundId != 0) {
return false; // Already following this user
}
// Add follow with created_at timestamp
$sql = 'insert into follows (id, source_user, target_user, created_at) values (?, ?, ?, NOW())';
$stmt = $dbh->prepare($sql);
if ($stmt === false) {
throw new \Federator\Exceptions\ServerError("Followers::addExternalFollow Failed to prepare insert statement");
}
$stmt->bind_param("sss", $followId, $sourceUser, $targetUserId);
$stmt->execute();
$stmt->close();
return true;
}
/** /**
* generate new follow id * generate new follow id
* *