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

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

namespace Drupal\Tests\activitypub\Functional;

use Drupal\Core\Site\Settings;
use Drupal\Core\Url;
use Drupal\Tests\WebAssert;

/**
 * Tests Actor functionality.
 *
 * @group activitypub
 */
class ActorTest extends ActivityPubTestBase {

  /**
   * Tests opt in/out.
   *
   * @throws \Behat\Mink\Exception\ExpectationException
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  public function testOptInAndOptOut() {
    $assert_session = $this->assertSession();
    $page = $this->getSession()->getPage();

    $this->enableActivityPub($assert_session);
    $assert_session->responseContains('ActivityPub is enabled.');

    $edit = [
      'activitypub_enable' => TRUE,
      'activitypub_name' => 'fediverse accountname',
    ];
    $this->drupalLogin($this->authenticatedUserTwo);
    $this->drupalGet('user/' . $this->authenticatedUserTwo->id() . '/activitypub/settings');
    $this->submitForm($edit, 'Save');
    $assert_session->responseContains('The username can only contain letters and numbers.');

    $edit['activitypub_name'] = 'fediverseaccountname_';
    $this->drupalGet('user/' . $this->authenticatedUserTwo->id() . '/activitypub/settings');
    $this->submitForm($edit, 'Save');
    $assert_session->responseContains('The username can only contain letters and numbers.');

    $edit['activitypub_name'] = $this->accountNameOne;
    $this->drupalGet('user/' . $this->authenticatedUserTwo->id() . '/activitypub/settings');
    $this->submitForm($edit, 'Save');
    $assert_session->responseContains('This username is already taken.');
    $edit['activitypub_name'] = $this->accountNameTwo;
    $this->drupalGet('user/' . $this->authenticatedUserTwo->id() . '/activitypub/settings');
    $this->submitForm($edit, 'Save');
    $this->drupalLogout();

    $this->drupalGet(Url::fromRoute('activitypub.inbox', [
      'user' => $this->authenticatedUserOne->id(),
      'activitypub_actor' => $this->accountNameOne,
    ])->toString());
    // By default we'll get back a 400, that's ok as an assertion :)
    $assert_session->statusCodeEquals(400);

    $this->drupalGet(Url::fromRoute('activitypub.user.self', [
      'user' => $this->authenticatedUserOne->id(),
      'activitypub_actor' => $this->accountNameOne,
    ]
    )->toString());
    $assert_session->statusCodeEquals(200);
    $content = json_decode($page->getContent());
    self::assertTrue(strpos($content->icon->url, 'assets/avatar.png') !== FALSE);
    self::assertTrue(!isset($content->summary));

    $this->drupalLogin($this->authenticatedUserOne);
    $this->drupalGet('user/' . $this->authenticatedUserOne->id() . '/activitypub/delete/unknown');
    $assert_session->statusCodeEquals(404);
    $this->drupalGet('user/' . $this->authenticatedUserOne->id() . '/activitypub/delete/' . $this->accountNameTwo);
    $assert_session->statusCodeEquals(403);
    $this->drupalGet('user/' . $this->authenticatedUserOne->id() . '/activitypub/delete/' . $this->accountNameOne);
    $this->submitForm(array(), 'Confirm');

    self::assertTrue(!file_exists('private://activitypub/keys/' . $this->accountNameOne . '/public.pem'));
    $this->drupalGet('user/' . $this->authenticatedUserOne->id() . '/activitypub');
    $assert_session->responseNotContains('ActivityPub is enabled.');
    $this->drupalLogout();

    $this->drupalGet(Url::fromRoute('activitypub.inbox', [
      'user' => $this->authenticatedUserOne->id(),
      'activitypub_actor' => $this->accountNameOne,
    ])->toString());
    $assert_session->statusCodeEquals(404);
    $this->drupalGet(Url::fromRoute('activitypub.user.self', [
      'user' => $this->authenticatedUserOne->id(),
      'activitypub_actor' => $this->accountNameOne,
    ])->toString());
    $assert_session->statusCodeEquals(404);

    $this->enableActivityPub($assert_session);
    $this->drupalLogout();
    $this->flushBins();
    /** @var \Drupal\activitypub\Entity\ActivityPubActorInterface $actor */
    $actor = \Drupal::entityTypeManager()->getStorage('activitypub_actor')->loadActorByEntityIdAndType($this->authenticatedUserOne->id(), 'person');
    self::assertEquals($actor->getOwnerId(), $this->authenticatedUserOne->id());
    $this->drupalGet(Url::fromRoute('activitypub.user.self', [
      'user' => $this->authenticatedUserOne->id(),
      'activitypub_actor' => $this->accountNameOne,
    ])->toString());
    $assert_session->statusCodeEquals(200);
    $this->createActivity($this->authenticatedUserOne->id());
    $this->createActivity($this->authenticatedUserTwo->id());
    $activities = \Drupal::entityTypeManager()->getStorage('activitypub_activity')->loadByProperties([
      'uid' => $this->authenticatedUserOne->id(),
    ]);
    self::assertEquals(1, count($activities));

    $this->drupalLogin($this->authenticatedUserOne);
    $edit = [
      'activitypub_summary' => 'Hi, I am just testing the Drupal integration',
    ];
    $this->drupalGet('user/' . $this->authenticatedUserOne->id() . '/activitypub/settings');
    $this->submitForm($edit, 'Save');
    $this->drupalLogout();
    $this->drupalGet(Url::fromRoute('activitypub.user.self', [
      'user' => $this->authenticatedUserOne->id(),
      'activitypub_actor' => $this->accountNameOne,
    ])->toString());
    $assert_session->statusCodeEquals(200);
    $content = json_decode($page->getContent());
    self::assertEquals('<p>' . $edit['activitypub_summary'] . '</p>', $content->summary);

    // Block user.
    $this->checkRouteAccess($assert_session);
    $this->authenticatedUserOne->block()->save();
    $this->checkRouteAccess($assert_session, TRUE);

    // Delete user.
    \Drupal::entityTypeManager()->getStorage('user')->load($this->authenticatedUserOne->id())->delete();
    $actor = \Drupal::entityTypeManager()->getStorage('activitypub_actor')->loadActorByEntityIdAndType($this->authenticatedUserOne->id(), 'person');
    self::assertNull($actor);
    self::assertTrue(!file_exists('private://activitypub/keys/' . $this->accountNameOne . '/public.pem'));
    $activities = \Drupal::entityTypeManager()->getStorage('activitypub_activity')->loadByProperties(['uid' => $this->authenticatedUserOne->id()]);
    self::assertEquals(0, count($activities));
    $activities = \Drupal::entityTypeManager()->getStorage('activitypub_activity')->loadByProperties(['uid' => $this->authenticatedUserTwo->id()]);
    self::assertEquals(1, count($activities));
  }

  /**
   * Check route access on several AP paths.
   *
   * @param \Drupal\Tests\WebAssert $assert_session
   *   WebAssert object for asserting the presence of elements with.
   * @param bool $blocked
   *   If route is whether blocked or not.
   *
   * @throws \Behat\Mink\Exception\ExpectationException
   */
  protected function checkRouteAccess(WebAssert $assert_session, bool $blocked = FALSE) {
    $actor_stream_href = Url::fromRoute('activitypub.user.self', [
      'user' => $this->authenticatedUserOne->id(),
      'activitypub_actor' => $this->accountNameOne,
    ])->toString();
    $this->drupalGet($actor_stream_href);
    $assert_session->statusCodeEquals($blocked ? 403 : 200);
    foreach ([
      'activitypub.outbox',
      'activitypub.inbox',
      'activitypub.followers',
      'activitypub.following',
    ] as $route_name) {
      $href = Url::fromRoute($route_name, [
        'user' => $this->authenticatedUserOne->id(),
        'activitypub_actor' => $this->accountNameOne,
      ])->toString();
      $this->drupalGet($href);
      $status = $blocked ? 403 : 200;
      // 400 is fine as an assert for 'ok' for inbox.
      if ($route_name == 'activitypub.inbox' && !$blocked) {
        $status = 400;
      }

      $assert_session->statusCodeEquals($status);
    }
  }

  /**
   * Tests the follow me block with mastodon.social.
   */
  public function testFollowBlock() {
    $assert_session = $this->assertSession();

    $block_settings = [
      'label' => 'activitypub follow block',
      //'settings[label_display]' => TRUE,
      'region' => 'header',
      //'visibility' => ['[request_path][pages]' => '/user/*'],
      'visibility' => ['request_path' => ['pages' => '/user/*']],
    ];
    $this->drupalPlaceBlock('activitypub_follow', $block_settings);

    $this->enableActivityPub($assert_session);
    $assert_session->responseContains('ActivityPub is enabled.');

    // Confirm that the user has the activity pub follow block.
    $this->drupalGet('user/' . $this->authenticatedUserOne->id());
    $assert_session->responseContains('<h2>activitypub follow block</h2>');

    // The rest of this test needs internet connection and goes out to call
    // mastodon.social, which at times has connectivity problems, so ignore the
    // rest by default on the bot.
    if (Settings::get('activitypub_stop_follow_block_test', TRUE)) {
      return;
    }

    // Do not let the third party service redirect to login as we want the
    // templated url by RFC6570.
    $this
      ->getSession()
      ->getDriver()
      ->getClient()
      ->followRedirects(FALSE);

    $this->submitForm(['handle' => 'test@mastodon.social'], t('Proceed to follow'));

    // The first url which redirects the follow form.
    $current_url = urldecode($this->getUrl());

    // User one activitypub address excluding
    // subdirectories or trailing slashes.
    $account_one_address = explode("/", $this->getResourceUrl($this->accountNameOne, FALSE))[0];

    $url_pattern = "/" . preg_quote('https://mastodon.social', '/') . ".*" . preg_quote($account_one_address) . "/";

    $message = sprintf('Current page "%s" does not match the regex "%s".', $current_url, $url_pattern);
    $this->assertTrue((bool) preg_match($url_pattern, $current_url), $message);
  }

}

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

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