Skip to content
Snippets Groups Projects
Commit 9cac68e5 authored by Kristof De Jaeger's avatar Kristof De Jaeger
Browse files

Issue #3187991 by swentel: Undo of follow does not delete original follow

parent 9b69e689
No related branches found
No related tags found
No related merge requests found
......@@ -12,6 +12,7 @@ use Drupal\Core\Site\Settings;
define('ACTIVITYPUB_OUTBOX_QUEUE', 'activitypub_outbox');
define('ACTIVITYPUB_OUTBOX_SEND_QUEUE', 'activitypub_outbox_send');
define('ACTIVITYPUB_INBOX_QUEUE', 'activitypub_inbox');
define('ACTIVITYPUB_FOLLOW_TEST_USER', 'https://example.com/user/random');
/**
* Implements hook_entity_delete().
......
......@@ -132,11 +132,14 @@ class StaticTypes extends TypePluginBase {
// Undo request.
if ($activity->getType() == 'Undo' && !$update) {
$payload = @json_decode($activity->getPayLoad(), TRUE);
if (isset($payload['object']) && isset($payload['object']['type']) && $payload['object']['type'] == 'Follow') {
$build = $activity->buildActivity();
if (isset($build['object']) && isset($build['object']['type']) && $build['object']['type'] == 'Follow') {
foreach ($this->entityTypeManager->getStorage('activitypub_activity')->loadByProperties(['type' => 'Follow', 'actor' => $activity->getActor(), 'object' => $activity->getObject()]) as $a) {
$a->delete();
}
foreach ($this->entityTypeManager->getStorage('activitypub_activity')->loadByProperties(['type' => 'Accept', 'object' => $activity->getActor(), 'actor' => $activity->getObject()]) as $a) {
$a->delete();
}
}
}
......
......@@ -210,6 +210,14 @@ class ActivityPubProcessClient implements ActivityPubProcessClientInterface {
// Get inboxes.
foreach ($targets as $target) {
// Ignore 'https://example.com/user/random' target which is used in
// the follow test, we don't care about it that the call is going
// out.
if ($target == ACTIVITYPUB_FOLLOW_TEST_USER) {
continue;
}
$target_actor = $server->actor($target);
if ($target_actor) {
$inbox = (string) $target_actor->get('inbox');
......
......@@ -2,6 +2,7 @@
namespace Drupal\Tests\activitypub\Functional;
use Drupal\activitypub\Entity\ActivityPubActivityInterface;
use Drupal\Core\Url;
/**
......@@ -14,13 +15,17 @@ class FollowTest extends ActivityPubTestBase {
/**
* Test follow functionality.
*
* @throws \Behat\Mink\Exception\ExpectationException
* @throws \Behat\Mink\Exception\ResponseTextException
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
* @throws \Behat\Mink\Exception\ExpectationException
* @throws \Drupal\Core\Entity\EntityStorageException
*/
public function testFollow() {
$assert_session = $this->assertSession();
$page = $this->getSession()->getPage();
$this->setTypeStatus('follow');
$this->setTypeStatus('undo');
// Set outbox handler.
$this->setOutboxHandler();
......@@ -76,9 +81,6 @@ class FollowTest extends ActivityPubTestBase {
$activity = $storage->load(1);
self::assertEquals(TRUE, $activity->isPublished());
// Account 1 check
$this->assertFollowersAndFollowing($this->authenticatedUserOne->id(), $this->accountNameOne, 0, 0, '', '', $assert_session, $page);
// Account 2 check
$this->assertFollowersAndFollowing($this->authenticatedUserTwo->id(), $this->accountNameTwo, 1, 0, $actor_href, '', $assert_session, $page);
......@@ -123,9 +125,6 @@ class FollowTest extends ActivityPubTestBase {
self::assertEquals($object_href, $activity->getActor());
$this->runOutboxQueue();
// Account 1 check
$this->assertFollowersAndFollowing($this->authenticatedUserOne->id(), $this->accountNameOne, 0, 0,'' , '', $assert_session, $page);
// Account 2 check
$this->assertFollowersAndFollowing($this->authenticatedUserTwo->id(), $this->accountNameTwo, 2, 0, [$payload['actor'], $actor_href], '', $assert_session, $page);
......@@ -141,9 +140,6 @@ class FollowTest extends ActivityPubTestBase {
$response = $this->sendInboxRequest($inbox, $payload);
self::assertEquals(202, $response->getStatusCode());
// Account 1 check
$this->assertFollowersAndFollowing($this->authenticatedUserOne->id(), $this->accountNameOne, 0, 0, '', '', $assert_session, $page);
// Account 2 check
$this->assertFollowersAndFollowing($this->authenticatedUserTwo->id(), $this->accountNameTwo, 1, 0, $actor_href, '', $assert_session, $page);
......@@ -265,14 +261,87 @@ class FollowTest extends ActivityPubTestBase {
self::assertNull($activity);
$activity = $storage->load(10);
self::assertNotNull($activity);
$activity = $storage->load(11);
self::assertNull($activity);
// Account 1 check
$this->assertFollowersAndFollowing($this->authenticatedUserOne->id(), $this->accountNameOne, 0, 0, '', '', $assert_session, $page);
// Account 2 check
$this->assertFollowersAndFollowing($this->authenticatedUserTwo->id(), $this->accountNameTwo, 1, 0, $actor_href, '', $assert_session, $page);
// Follow an external user as user 1, then undo it. We cheat a little by
// simply saving an activity already, this test is really to figure out
// that the 'undo' call works.
$actor_random = ACTIVITYPUB_FOLLOW_TEST_USER;
$activity_values = [
'collection' => ActivityPubActivityInterface::OUTBOX,
'config_id' => 'follow',
'type' => 'Follow',
'actor' => $actor_href,
'object' => $actor_random,
'queued' => FALSE,
'processed' => TRUE,
'status' => TRUE,
'uid' => $this->authenticatedUserOne->id(),
];
/** @var \Drupal\activitypub\Entity\ActivityPubActivityInterface $follow */
$follow = $storage->create($activity_values);
$follow->save();
$follow->set('queued', FALSE)->save();
$follow_id = $follow->id();
$activity_values['collection'] = ActivityPubActivityInterface::INBOX;
$activity_values['actor'] = $actor_random;
$activity_values['object'] = $actor_href;
$activity_values['config_id'] = '';
$activity_values['type'] = 'Accept';
$activity_values['status'] = FALSE;
$activity_values['processed'] = FALSE;
$accept = $storage->create($activity_values);
$accept->save();
$accept_id = $accept->id();
// Clear queues (the follow will have created one).
$this->clearQueue(ACTIVITYPUB_OUTBOX_QUEUE);
// Account 1 check
$this->assertFollowersAndFollowing($this->authenticatedUserOne->id(), $this->accountNameOne, 0, 1, '', $actor_random, $assert_session, $page);
// Undo follow.
$this->drupalLogin($this->authenticatedUserOne);
$this->drupalGet('user/' . $this->authenticatedUserOne->id() . '/activitypub');
$this->drupalGet('activitypub/11/undo');
$this->drupalLogout();
$undo_activity = $storage->load(13);
self::assertEquals("outbox", $undo_activity->getCollection());
self::assertEquals("Undo", $undo_activity->getType());
self::assertEquals($actor_href, $undo_activity->getActor());
self::assertEquals($actor_random, $undo_activity->getObject());
$count = \Drupal::queue(ACTIVITYPUB_OUTBOX_QUEUE)->numberOfItems();
self::assertEquals(1, $count);
$this->runOutboxQueue();
$count = \Drupal::queue(ACTIVITYPUB_OUTBOX_QUEUE)->numberOfItems();
self::assertEquals(0, $count);
$count = \Drupal::queue(ACTIVITYPUB_OUTBOX_SEND_QUEUE)->numberOfItems();
self::assertEquals(0, $count);
// Account 1 check
$this->assertFollowersAndFollowing($this->authenticatedUserOne->id(), $this->accountNameOne, 0, 0, '', '', $assert_session, $page);
$storage->resetCache();
/** @var \Drupal\activitypub\Entity\ActivityPubActivityInterface $un */
$un = $storage->load($undo_activity->id());
self::assertTrue($un->isProcessed());
self::assertFalse($un->isQueued());
$f = $storage->load($follow_id);
self::assertNull($f);
$a = $storage->load($accept_id);
self::assertNull($a);
$this->drupalLogin($this->authenticatedUserOne);
$this->drupalGet('user/' . $this->authenticatedUserOne->id() . '/activitypub');
$assert_session->pageTextNotContains('Follow');
}
/**
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment