activitypub-1.0.x-dev/tests/src/Functional/FollowTest.php

tests/src/Functional/FollowTest.php
<?php

namespace Drupal\Tests\activitypub\Functional;

use Drupal\activitypub\Entity\ActivityPubActivityInterface;
use Drupal\Core\Url;

/**
 * Tests Follow functionality.
 *
 * @group activitypub
 */
class FollowTest extends ActivityPubTestBase {

  /**
   * Test follow functionality.
   */
  public function testFollow() {
    $this->testFollowHelper();
  }

  /**
   * Test follow helper.
   *
   * @throws \Behat\Mink\Exception\ExpectationException
   * @throws \Behat\Mink\Exception\ResponseTextException
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  protected function testFollowHelper() {
    $assert_session = $this->assertSession();
    $page = $this->getSession()->getPage();
    $this->setTypeStatus('follow');
    $this->setTypeStatus('undo');

    // Set outbox handler.
    $this->setOutboxHandler();

    // Setup ActivityPub actors.
    $this->enableActivityPub($assert_session, TRUE);
    $this->drupalLogout();
    $actor_href = Url::fromRoute('activitypub.user.self', ['user' => $this->authenticatedUserOne->id(), 'activitypub_actor' => $this->accountNameOne], ['absolute' => TRUE])->toString();
    $object_href = Url::fromRoute('activitypub.user.self', ['user' => $this->authenticatedUserTwo->id(), 'activitypub_actor' => $this->accountNameTwo], ['absolute' => TRUE])->toString();

    $payload = [
      'type' => 'Follow',
      '@context' => 'https://www.w3.org/ns/activitystreams',
      'id' => $actor_href . '/follow/1',
      'actor' => $actor_href,
      'object' => $object_href,
    ];
    $inbox = Url::fromRoute('activitypub.inbox', ['user' => $this->authenticatedUserTwo->id(), 'activitypub_actor' => $this->accountNameTwo])->toString();
    $response = $this->sendInboxRequest($inbox, $payload);
    self::assertEquals(202, $response->getStatusCode());

    /** @var \Drupal\activitypub\Entity\Storage\ActivityPubActorStorageInterface $storage */
    $storage = \Drupal::entityTypeManager()->getStorage('activitypub_activity');
    /** @var \Drupal\activitypub\Entity\ActivityPubActivityInterface $activity */
    $activity = $storage->load(1);
    self::assertEquals(FALSE, $activity->isPublished());
    self::assertEquals("Follow", $activity->getType());
    self::assertEquals($payload['id'], $activity->getExternalId());
    self::assertEquals($actor_href, $activity->getActor());
    self::assertEquals($object_href, $activity->getObject());
    self::assertEquals($this->authenticatedUserTwo->id(), $activity->getTargetEntityId());
    self::assertEquals($this->authenticatedUserTwo->getEntityTypeId(), $activity->getTargetEntityTypeId());

    $activity = $storage->load(2);
    self::assertEquals(FALSE, $activity->isPublished());
    self::assertEquals("Accept", $activity->getType());
    self::assertEquals($object_href, $activity->getActor());
    self::assertEquals($actor_href, $activity->getObject());
    self::assertEquals($payload['id'], $activity->getExternalId());

    $count = \Drupal::queue(ACTIVITYPUB_OUTBOX_QUEUE)->numberOfItems();
    self::assertEquals(1, $count);

    // 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, 0, 0, '', '', $assert_session, $page);

    $this->runOutboxQueue();
    $count = \Drupal::queue(ACTIVITYPUB_OUTBOX_QUEUE)->numberOfItems();
    self::assertEquals(0, $count);

    $storage->resetCache([1, 2]);
    $activity = $storage->load(1);
    self::assertEquals(TRUE, $activity->isPublished());

    // Account 2 check
    $this->assertFollowersAndFollowing($this->authenticatedUserTwo->id(), $this->accountNameTwo, 1, 0, $actor_href, '', $assert_session, $page);

    // Allow to block incoming domains.
    $this->drupalLogin($this->authenticatedUserTwo);
    $edit = [
      'activitypub_blocked_domains' => 'http://blocked.domain*',
    ];
    $this->drupalGet('user/' . $this->authenticatedUserTwo->id() . '/activitypub/settings');
    $this->submitForm($edit, 'Save');
    $assert_session->responseContains('http://blocked.domain*');
    $this->drupalLogout();

    $payload = [
      'type' => 'Follow',
      '@context' => 'https://www.w3.org/ns/activitystreams',
      'id' => $actor_href . '/follow/2',
      'actor' => 'http://blocked.domain/user/spammer',
      'object' => $object_href,
    ];
    $response = $this->sendInboxRequest($inbox, $payload);
    self::assertEquals(403, $response->getStatusCode());

    $payload['actor'] = 'http://allowed.domain/user/good';
    $payload['id'] = 'http://allowed.domain/user/good/follow/2';
    $payload['object'] = (object) [
      'object' => $object_href,
    ];
    $response = $this->sendInboxRequest($inbox, $payload);
    self::assertEquals(202, $response->getStatusCode());
    $activity = $storage->load(4);
    self::assertEquals("Follow", $activity->getType());
    self::assertEquals($payload['actor'], $activity->getActor());
    self::assertEquals($object_href, $activity->getObject());

    $count = \Drupal::queue(ACTIVITYPUB_OUTBOX_QUEUE)->numberOfItems();
    self::assertEquals(1, $count);

    $activity = $storage->load(5);
    self::assertEquals("outbox", $activity->getCollection());
    self::assertEquals("Accept", $activity->getType());
    self::assertEquals($payload['actor'], $activity->getObject());
    self::assertEquals($object_href, $activity->getActor());
    $this->runOutboxQueue();

    // Account 2 check
    $this->assertFollowersAndFollowing($this->authenticatedUserTwo->id(), $this->accountNameTwo, 2, 0, [$payload['actor'], $actor_href], '', $assert_session, $page);

    // Remove follower (via undo).
    $payload['type'] = 'Undo';
    $payload['id'] = 'http://allowed.domain/user/good/follow/3';
    $payload['actor'] = 'http://allowed.domain/user/good';
    $payload['object'] = (object) [
      'type' => 'Follow',
      'actor' => $payload['actor'],
      'object' => $object_href,
    ];
    $response = $this->sendInboxRequest($inbox, $payload);
    self::assertEquals(202, $response->getStatusCode());

    // Account 2 check
    $this->assertFollowersAndFollowing($this->authenticatedUserTwo->id(), $this->accountNameTwo, 1, 0, $actor_href, '', $assert_session, $page);

    $this->drupalGet('nodeinfo/content');
    $content = json_decode($page->getContent());
    self::assertEquals(2, $content->usage->users->total);
    self::assertEquals(0, $content->usage->localPosts);

    // Send a DELETE where actor and object are equal, this activity will not be
    // saved.
    $payload = [
      'type' => 'Delete',
      'id' => 'https://mastodon.social/user/deleted#delete',
      'actor' => 'https://mastodon.social/user/deleted',
      'object' => 'https://mastodon.social/user/deleted',
    ];
    $response = $this->sendInboxRequest($inbox, $payload);
    self::assertEquals(202, $response->getStatusCode());
    $ids = $storage->getQuery()->accessCheck()->condition('uid', $this->authenticatedUserTwo->id())->execute();
    self::assertEquals(2, count($ids));

    // Make sure there's only one follower.
    $payload = [
      'type' => 'Follow',
      '@context' => 'https://www.w3.org/ns/activitystreams',
      'id' => $actor_href . '/follow/1',
      'actor' => $actor_href,
      'object' => $object_href,
    ];
    $inbox = Url::fromRoute('activitypub.inbox', ['user' => $this->authenticatedUserTwo->id(), 'activitypub_actor' => $this->accountNameTwo])->toString();
    $response = $this->sendInboxRequest($inbox, $payload);
    self::assertEquals(202, $response->getStatusCode());
    $this->drupalGet('user/' . $this->authenticatedUserTwo->id() . '/activitypub/' . $this->accountNameTwo . '/followers', ['query' => ['page' => 0]]);
    $assert_session->statusCodeEquals(200);
    $content = json_decode($page->getContent());
    self::assertEquals(1, count($content->orderedItems));
    $ids = $storage->getQuery()->accessCheck()->condition('uid', $this->authenticatedUserTwo->id())->execute();
    self::assertEquals(2, count($ids));
    $count = \Drupal::queue(ACTIVITYPUB_OUTBOX_QUEUE)->numberOfItems();
    self::assertEquals(0, $count);

    // Test follow started from internal.
    $this->followUser($object_href, $actor_href, 2);

    $count = \Drupal::queue(ACTIVITYPUB_OUTBOX_QUEUE)->numberOfItems();
    self::assertEquals(1, $count);
    $activity = $storage->load(6);
    self::assertEquals("outbox", $activity->getCollection());
    self::assertEquals("Follow", $activity->getType());
    self::assertEquals($object_href, $activity->getActor());
    self::assertEquals($actor_href, $activity->getObject());

    // 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);

    $this->runOutboxQueue();
    $this->runOutboxQueue();
    $count = \Drupal::queue(ACTIVITYPUB_OUTBOX_QUEUE)->numberOfItems();
    self::assertEquals(0, $count);

    $activity = $storage->load(7);
    self::assertEquals("inbox", $activity->getCollection());
    self::assertEquals("Follow", $activity->getType());
    self::assertEquals($object_href, $activity->getActor());
    self::assertEquals($actor_href, $activity->getObject());

    $activity = $storage->load(8);
    self::assertEquals("outbox", $activity->getCollection());
    self::assertEquals("Accept", $activity->getType());
    self::assertEquals($actor_href, $activity->getActor());
    self::assertEquals($object_href, $activity->getObject());

    $activity = $storage->load(9);
    self::assertEquals("inbox", $activity->getCollection());
    self::assertEquals("Accept", $activity->getType());
    self::assertEquals($actor_href, $activity->getActor());
    self::assertEquals($object_href, $activity->getObject());

    // Account 1 check
    $this->assertFollowersAndFollowing($this->authenticatedUserOne->id(), $this->accountNameOne, 1, 0, $object_href, '', $assert_session, $page);

    // Account 2 check
    $this->assertFollowersAndFollowing($this->authenticatedUserTwo->id(), $this->accountNameTwo, 1, 1, $actor_href, $actor_href, $assert_session, $page);

    //$this->viewActivityOverview();

    // Undo follow.
    $this->drupalLogin($this->authenticatedUserTwo);
    $this->drupalGet('user/' . $this->authenticatedUserTwo->id() . '/activitypub');
    $this->drupalGet('activitypub/6/undo');
    $this->drupalLogout();

    $activity = $storage->load(10);
    self::assertEquals("outbox", $activity->getCollection());
    self::assertEquals("Undo", $activity->getType());
    self::assertEquals($object_href, $activity->getActor());
    self::assertEquals($actor_href, $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);

    //$this->viewActivityOverview();

    $storage->resetCache();
    $activity = $storage->load(6);
    self::assertNull($activity);
    $activity = $storage->load(7);
    self::assertNull($activity);
    $activity = $storage->load(8);
    self::assertNull($activity);
    $activity = $storage->load(9);
    self::assertNull($activity);
    $activity = $storage->load(10);
    self::assertNotNull($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_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');
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc