Called when making a remote contact on a non-native network (like Twitter) unfollow you.
Hook data:
-- **contact** (input): the remote contact (uid = local revoking user id) array.
+- **contact** (input): the target public contact (uid = 0) array.
+- **uid** (input): the id of the source local user.
- **result** (output): a boolean value indicating wether the operation was successful or not.
### block
namespace Friendica\Core;
use Friendica\Database\DBA;
-use Friendica\DI;
use Friendica\Model\User;
use Friendica\Network\HTTPException;
use Friendica\Protocol\Activity;
/**
* Revoke an incoming follow from the provided contact
*
- * @param array $contact Private contact (uid != 0) array
+ * @param array $contact Target public contact (uid == 0) array
+ * @param int $uid Source local user id
* @return bool|null true if successful, false if not, null if no action was performed
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
- public static function revokeFollow(array $contact): ?bool
+ public static function revokeFollow(array $contact, int $uid): ?bool
{
if (empty($contact['network'])) {
throw new \InvalidArgumentException('Missing network key in contact array');
}
if ($protocol == Protocol::ACTIVITYPUB) {
- return ActivityPub\Transmitter::sendContactReject($contact['url'], $contact['hub-verify'], $contact['uid']);
+ return ActivityPub\Transmitter::sendContactReject($contact['url'], $contact['hub-verify'], $uid);
}
// Catch-all hook for connector addons
$hook_data = [
'contact' => $contact,
- 'result' => null,
+ 'uid' => $uid,
+ 'result' => null,
];
Hook::callAll('revoke_follow', $hook_data);
/**
* Revoke follow privileges of the remote user contact
*
- * @param array $contact Contact unfriended
- * @return bool|null Whether the remote operation is successful or null if no remote operation was performed
+ * The local relationship is updated immediately, the eventual remote server is messaged in the background.
+ *
+ * @param array $contact User-specific contact array (uid != 0) to revoke the follow from
* @throws HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
- public static function revokeFollow(array $contact): ?bool
+ public static function revokeFollow(array $contact): void
{
if (empty($contact['network'])) {
throw new \InvalidArgumentException('Empty network in contact array');
throw new \InvalidArgumentException('Unexpected public contact record');
}
- $result = Protocol::revokeFollow($contact);
-
- // A null value here means the remote network doesn't support explicit follow revocation, we can still
- // break the locally recorded relationship
- if ($result !== false) {
- if ($contact['rel'] == self::FRIEND) {
- self::update(['rel' => self::SHARING], ['id' => $contact['id']]);
- } else {
- self::remove($contact['id']);
- }
+ if (in_array($contact['rel'], [self::FOLLOWER, self::FRIEND])) {
+ $cdata = Contact::getPublicAndUserContactID($contact['id'], $contact['uid']);
+ Worker::add(PRIORITY_HIGH, 'Contact\RevokeFollow', $cdata['public'], $contact['uid']);
}
- return $result;
+ self::removeFollower($contact);
}
/**
return null;
}
+ /**
+ * Update the local relationship when a local user loses a follower
+ *
+ * @param array $contact User-specific contact (uid != 0) array
+ * @throws HTTPException\InternalServerErrorException
+ * @throws \ImagickException
+ */
public static function removeFollower(array $contact)
{
if (in_array($contact['rel'] ?? [], [self::FRIEND, self::SHARING])) {
class Revoke extends BaseModule
{
- /** @var array */
+ /**
+ * User-specific contact (uid != 0) array
+ * @var array
+ */
protected $contact;
/** @var Database */
self::checkFormSecurityTokenRedirectOnError('contact/' . $this->parameters['id'], 'contact_revoke');
- $result = Model\Contact::revokeFollow($this->contact);
- if ($result === true) {
- notice($this->t('Follow was successfully revoked.'));
- } elseif ($result === null) {
- notice($this->t('Follow was successfully revoked, however the remote contact won\'t be aware of this revokation.'));
- } else {
- notice($this->t('Unable to revoke follow, please try again later or contact the administrator.'));
- }
+ Model\Contact::revokeFollow($this->contact);
+
+ notice($this->t('Follow was successfully revoked.'));
$this->baseUrl->redirect('contact/' . $this->parameters['id']);
}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (C) 2010-2022, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Worker\Contact;
+
+use Friendica\Core\Protocol;
+use Friendica\Core\Worker;
+use Friendica\Model\Contact;
+
+class RevokeFollow
+{
+ /**
+ * Issue asynchronous follow revokation message to remote servers.
+ * The local relationship has already been updated, so we can't use the user-specific contact
+ *
+ * @param int $cid Target public contact id
+ * @param int $uid Source local user id
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+ * @throws \ImagickException
+ */
+ public static function execute(int $cid, int $uid)
+ {
+ $contact = Contact::getById($cid);
+ if (empty($contact)) {
+ return;
+ }
+
+ $result = Protocol::revokeFollow($contact, $uid);
+ if ($result === false) {
+ Worker::defer();
+ }
+ }
+}