simplenews-3.0.0-alpha1/tests/src/Functional/SimplenewsSubscribeTest.php

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

namespace Drupal\Tests\simplenews\Functional;

use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\simplenews\Entity\Newsletter;
use Drupal\simplenews\Entity\Subscriber;
use Drupal\user\UserInterface;

/**
 * Un/subscription of anonymous and authenticated users.
 *
 * Subscription via block, subscription page and account page.
 *
 * @group simplenews
 */
class SimplenewsSubscribeTest extends SimplenewsTestBase {

  /**
   * Subscribe to multiple newsletters at the same time.
   */
  public function testSubscribeMultiple() {
    $admin_user = $this->drupalCreateUser([
      'administer blocks',
      'administer content types',
      'administer nodes',
      'access administration pages',
      'administer permissions',
      'administer newsletters',
      'administer simplenews subscriptions',
    ]);
    $this->drupalLogin($admin_user);

    $this->drupalGet('admin/config/services/simplenews');
    for ($i = 0; $i < 5; $i++) {
      $this->clickLink(t('Add newsletter'));
      $name = $this->randomMachineName();
      $edit = [
        'name' => $name,
        'id' => strtolower($name),
        'description' => $this->randomString(20),
        'access' => 'default',
      ];
      $this->submitForm($edit, 'Save');
    }

    $newsletters = simplenews_newsletter_get_all();

    $this->drupalLogout();

    // Track hook results.
    $this->trackHookResults();

    $enable = array_rand($newsletters, 3);
    $mail = $this->randomEmail(8);
    $this->subscribe($enable, $mail);
    $this->assertSession()->pageTextContains('You will receive a confirmation e-mail shortly containing further instructions on how to complete your subscription.');
    $this->assertMailText(t('We have received a request to subscribe @user', ['@user' => $mail]));

    $mails = $this->getMails();
    $this->assertEquals('simpletest@example.com', $mails[0]['from']);
    $this->assertEquals('Drupal <simpletest@example.com>', $mails[0]['headers']['From']);

    $confirm_url = $this->extractConfirmationLink($this->getMail(0));

    $this->drupalGet($confirm_url);
    $this->assertSession()->responseContains('Are you sure you want to confirm your subscription for <em class="placeholder">' . simplenews_mask_mail($mail) . '</em>?');
    $this->assertNoHookResult();

    $this->submitForm([], 'Confirm');
    $this->assertSession()->responseContains('Subscription changes confirmed for <em class="placeholder">' . $mail . '</em>.');

    /** @var \Drupal\simplenews\Subscription\SubscriptionManagerInterface $subscription_manager */
    $subscription_manager = \Drupal::service('simplenews.subscription_manager');
    $subscriber_storage = \Drupal::entityTypeManager()->getStorage('simplenews_subscriber');
    $subscriber_storage->resetCache();

    // Verify subscription changes.
    foreach ($newsletters as $newsletter_id => $newsletter) {
      $is_subscribed = $subscription_manager->isSubscribed($mail, $newsletter_id);
      $subscription_newsletter = $subscriber_storage->getSubscriptionsByNewsletter($newsletter_id);

      if (in_array($newsletter_id, $enable)) {
        $this->assertTrue($is_subscribed);
        $this->assertCount(1, $subscription_newsletter);
        $this->assertHookResult('add', $mail, $newsletter_id);
      }
      else {
        $this->assertFalse($is_subscribed);
        $this->assertCount(0, $subscription_newsletter);
      }
    }
    $this->assertNoHookResult();

    // Go to the manage page and submit without changes.
    $subscriber = Subscriber::loadByMail($mail);
    $hash = simplenews_generate_hash($subscriber->getMail(), 'manage');
    $this->drupalGet('simplenews/manage/' . $subscriber->id() . '/' . \Drupal::time()->getRequestTime() . '/' . $hash);
    $this->submitForm([], 'Update');
    $this->assertSession()->pageTextContains('Your newsletter subscriptions have been updated.');
    $this->assertCount(1, $this->getMails(), 'No confirmation mails have been sent.');
    $this->assertNoHookResult();

    // Unsubscribe from two of the three enabled newsletters.
    $disable = array_rand(array_flip($enable), 2);

    $edit = [
      'mail[0][value]' => $mail,
    ];
    foreach ($disable as $newsletter_id) {
      $edit['subscriptions[' . $newsletter_id . ']'] = FALSE;
    }
    $this->drupalGet('simplenews/manage/' . $subscriber->id() . '/' . \Drupal::time()->getRequestTime() . '/' . $hash);
    $this->submitForm($edit, 'Update');

    // Verify subscription changes.
    $subscriber_storage->resetCache();
    $still_enabled = array_diff($enable, $disable);
    foreach ($newsletters as $newsletter_id => $newsletter) {
      $is_subscribed = $subscription_manager->isSubscribed($mail, $newsletter_id);
      if (in_array($newsletter_id, $still_enabled)) {
        $this->assertTrue($is_subscribed);
      }
      else {
        $this->assertFalse($is_subscribed);
      }
    }

    foreach ($disable as $newsletter_id) {
      $this->assertHookResult('remove', $mail, $newsletter_id);
    }
    $this->assertNoHookResult();

    // Test expired confirmation links.
    $enable = array_rand($newsletters, 3);

    $mail = $this->randomEmail(8);
    foreach ($enable as $newsletter_id) {
      $edit['subscriptions[' . $newsletter_id . ']'] = TRUE;
    }
    $this->subscribe($enable, $mail);

    $subscriber = $this->getLatestSubscriber();
    $this->assertEquals($mail, $subscriber->getMail());
    $expired_timestamp = \Drupal::time()->getRequestTime() - 86401;
    $hash = simplenews_generate_hash($subscriber->getMail(), 'confirm', $expired_timestamp);
    $url = 'simplenews/confirm/' . $subscriber->id() . '/' . $expired_timestamp . '/' . $hash;
    $this->drupalGet($url);
    $this->assertSession()->pageTextContains('This link has expired.');
    $this->submitForm([], 'Request new confirmation mail');

    $confirm_url = $this->extractConfirmationLink($this->getMail());

    $this->assertMailText(t('We have received a request to subscribe @user', ['@user' => $mail]));
    $this->drupalGet($confirm_url);
    $this->assertSession()->responseContains('Are you sure you want to confirm your subscription for <em class="placeholder">' . simplenews_mask_mail($mail) . '</em>?');
    $this->submitForm([], 'Confirm');
    $this->assertSession()->responseContains('Subscription changes confirmed for <em class="placeholder">' . $mail . '</em>.');
  }

  /**
   * Test immediate confirmation.
   */
  public function testConfirmImmediate() {
    $this->trackHookResults();
    $email = $this->randomEmail(8);
    $this->subscribe('default', $email);
    $confirm_url = $this->extractConfirmationLink($this->getMail());
    $this->drupalGet("$confirm_url/ok");
    $this->assertSession()->responseContains('Subscription changes confirmed for <em class="placeholder">' . $email . '</em>.');
    $this->assertHookResult('add', $email, 'default');
    $this->assertNoHookResult();
  }

  /**
   * TestSubscribeAnonymous.
   *
   * Steps performed:
   *   0. Preparation
   *   1. Subscribe anonymous via block
   *   3. Subscribe anonymous via multi block.
   */
  public function testSubscribeAnonymous() {
    // 0. Preparation
    // Login admin
    // Set permission for anonymous to subscribe
    // Enable newsletter block
    // Logout admin.
    $admin_user = $this->drupalCreateUser([
      'administer blocks',
      'administer content types',
      'administer nodes',
      'access administration pages',
      'administer newsletters',
      'administer permissions',
    ]
    );
    $this->drupalLogin($admin_user);

    // Create some newsletters for multi-sign up block.
    $this->drupalGet('admin/config/services/simplenews');
    for ($i = 0; $i < 5; $i++) {
      $this->clickLink(t('Add newsletter'));
      $name = $this->randomMachineName();
      $edit = [
        'name' => $name,
        'id' => strtolower($name),
        'description' => $this->randomString(20),
        'access' => 'default',
      ];
      $this->submitForm($edit, 'Save');
    }

    $newsletter_id = $this->getRandomNewsletter();

    $this->drupalLogout();

    // 1. Subscribe anonymous via block
    // Subscribe + submit
    // Assert confirmation message
    // Assert outgoing email
    //
    // Confirm using mail link
    // Confirm using mail link
    // Assert confirmation message
    // Setup subscription block with subscription form.
    $block_settings = [
      'default_newsletters' => [$newsletter_id],
      'message' => $this->randomMachineName(4),
    ];
    $single_block = $this->setupSubscriptionBlock($block_settings);

    // Testing invalid email error message.
    $mail = '@example.com';
    $edit = [
      'mail[0][value]' => $mail,
    ];
    $this->drupalGet('');
    $this->submitForm($edit, 'Subscribe');
    $this->assertSession()->pageTextContains('The email address ' . $mail . ' is not valid');

    // Now with valid email.
    $mail = $this->randomEmail(8);
    $edit = [
      'mail[0][value]' => $mail,
    ];
    $this->drupalGet('');
    $this->submitForm($edit, 'Subscribe');
    $this->assertSession()->pageTextContains('You will receive a confirmation e-mail shortly containing further instructions on how to complete your subscription.');

    $subscriber = $this->getLatestSubscriber();
    $this->assertNotFalse($subscriber, 'New subscriber entity successfully loaded.');
    $this->assertEquals($mail, $subscriber->getMail());
    $this->assertFalse($subscriber->isConfirmed());
    $confirm_url = $this->extractConfirmationLink($this->getMail(0));

    $this->drupalGet($confirm_url);
    $newsletter = Newsletter::load($newsletter_id);
    $this->assertSession()->responseContains('Are you sure you want to confirm your subscription for <em class="placeholder">' . simplenews_mask_mail($mail) . '</em>?');

    $this->submitForm([], 'Confirm');
    $this->assertSession()->responseContains('Subscription changes confirmed for <em class="placeholder">' . $mail . '</em>.');
    $this->assertSession()->addressEquals(new Url('<front>'));

    // Test that it is possible to register with a mail address that is already
    // a subscriber.
    $site_config = $this->config('user.settings');
    $site_config->set('register', 'visitors');
    $site_config->set('verify_mail', FALSE);
    $site_config->save();

    $pass = $this->randomMachineName();
    $edit = [
      'name' => $this->randomMachineName(),
      'mail' => $mail,
      'pass[pass1]' => $pass,
      'pass[pass2]' => $pass,
    ];
    $this->drupalGet('user/register');
    $this->submitForm($edit, 'Create new account');

    // Verify confirmation messages.
    $this->assertSession()->pageTextContains('Registration successful. You are now logged in.');

    // Verify that the subscriber has been updated and references to the correct
    // user.
    \Drupal::entityTypeManager()->getStorage('simplenews_subscriber')->resetCache();
    $subscriber = Subscriber::loadByMail($mail);
    $account = user_load_by_mail($mail);
    $this->assertEquals($subscriber->getUserId(), $account->id());
    $this->assertEquals($edit['name'], $account->getDisplayName());

    $this->drupalLogout();

    // Disable the newsletter block.
    $single_block->delete();

    // 3. Subscribe anonymous via multi block.
    // Try to submit multi-signup form without selecting a newsletter.
    $mail = $this->randomEmail(8);
    $this->subscribe([], $mail);
    $this->assertSession()->pageTextContains('Manage your newsletter subscriptions field is required.');

    // Now fill out the form and try again.
    $this->subscribe($newsletter_id, $mail);
    $this->assertSession()->pageTextContains('You will receive a confirmation e-mail shortly containing further instructions on how to complete your subscription.');

    $confirm_url = $this->extractConfirmationLink($this->getMail());

    $this->drupalGet($confirm_url);
    $newsletter = Newsletter::load($newsletter_id);
    $this->assertSession()->responseContains('Are you sure you want to confirm your subscription for <em class="placeholder">' . simplenews_mask_mail($mail) . '</em>?');

    $this->submitForm([], 'Confirm');
    $this->assertSession()->responseContains('Subscription changes confirmed for <em class="placeholder">' . $mail . '</em>.');

    // Try to subscribe again, this should not re-set the status to unconfirmed.
    $this->subscribe($newsletter_id, $mail);
    $this->assertSession()->pageTextContains('You will receive a confirmation e-mail shortly containing further instructions on how to complete your subscription.');

    $subscriber = Subscriber::loadByMail($mail);
    $this->assertNotFalse($subscriber, 'New subscriber entity successfully loaded.');
    $this->assertTrue($subscriber->isSubscribed($newsletter_id));

    // Visit the newsletter/subscriptions page with the hash.
    $subscriber = Subscriber::loadByMail($mail);

    $hash = simplenews_generate_hash($subscriber->getMail(), 'manage');
    $this->drupalGet('simplenews/manage/' . $subscriber->id() . '/' . \Drupal::time()->getRequestTime() . '/' . $hash);
    $this->assertSession()->pageTextContains('Subscriptions for ' . $mail);

    $edit = [
      'subscriptions[' . $newsletter_id . ']' => TRUE,
    ];
    $this->submitForm($edit, 'Update');

    $this->assertSession()->pageTextContains('Your newsletter subscriptions have been updated.');

    // Make sure the subscription is confirmed.
    \Drupal::entityTypeManager()->getStorage('simplenews_subscriber')->resetCache();
    $subscriber = Subscriber::loadByMail($mail);

    $this->assertTrue($subscriber->isSubscribed($newsletter_id));

    // Attempt to fetch the page using a wrong hash but correct format.
    $hash = simplenews_generate_hash($subscriber->getMail() . 'a', 'manage');
    $this->drupalGet('simplenews/manage/' . $subscriber->id() . '/' . \Drupal::time()->getRequestTime() . '/' . $hash);
    $this->assertSession()->statusCodeEquals(404);

    // Test expired confirmation links.
    $mail = $this->randomEmail();
    $this->subscribe($newsletter_id, $mail);

    $subscriber = $this->getLatestSubscriber();
    $this->assertEquals($mail, $subscriber->getMail());
    $expired_timestamp = \Drupal::time()->getRequestTime() - 86401;
    $hash = simplenews_generate_hash($subscriber->getMail(), 'confirm', $expired_timestamp);
    $url = 'simplenews/confirm/' . $subscriber->id() . '/' . $expired_timestamp . '/' . $hash;
    $this->drupalGet($url);
    $this->assertSession()->pageTextContains('This link has expired.');
    $this->submitForm([], 'Request new confirmation mail');

    $confirm_url = $this->extractConfirmationLink($this->getMail());

    $this->drupalGet($confirm_url);
    $newsletter = Newsletter::load($newsletter_id);
    $this->assertSession()->responseContains('Are you sure you want to confirm your subscription for <em class="placeholder">' . simplenews_mask_mail($mail) . '</em>?');

    $this->submitForm([], 'Confirm');
    $this->assertSession()->responseContains('Subscription changes confirmed for <em class="placeholder">' . $mail . '</em>.');

    // Make sure the subscription is confirmed now.
    \Drupal::entityTypeManager()->getStorage('simplenews_subscriber')->resetCache();
    $subscriber = Subscriber::loadByMail($mail);

    $this->assertTrue($subscriber->isSubscribed($newsletter_id));
  }

  /**
   * Test anonymous subscription without verification.
   *
   * Steps performed:
   *   0. Preparation
   *   1. Subscribe anonymous via block.
   */
  public function testSubscribeAnonymousSingle() {
    // 0. Preparation
    // Set global skip_verification to TRUE
    // Login admin
    // Create single opt in newsletter.
    // Set permission for anonymous to subscribe
    // Enable newsletter block
    // Logout admin.
    $config = $this->config('simplenews.settings');
    $config->set('subscription.skip_verification', TRUE);
    $config->save();

    $admin_user = $this->drupalCreateUser([
      'administer blocks',
      'administer content types',
      'administer nodes',
      'access administration pages',
      'administer permissions',
      'administer newsletters',
    ]
    );
    $this->drupalLogin($admin_user);

    $this->drupalGet('admin/config/services/simplenews');
    $this->clickLink(t('Add newsletter'));
    $name = $this->randomMachineName();
    $edit = [
      'name' => $name,
      'id' => strtolower($name),
      'description' => $this->randomString(20),
      'access' => 'default',
    ];
    $this->submitForm($edit, 'Save');

    $this->drupalLogout();

    $newsletter_id = $edit['id'];

    // Setup subscription block with subscription form.
    $block_settings = [
      'default_newsletters' => [$newsletter_id],
      'message' => $this->randomMachineName(4),
    ];
    $this->setupSubscriptionBlock($block_settings);

    // 1. Subscribe anonymous via block
    // Subscribe + submit
    // Assert confirmation message
    // Verify subscription state.
    $mail = $this->randomEmail(8);
    $edit = [
      'mail[0][value]' => $mail,
    ];
    $this->drupalGet('');
    $this->submitForm($edit, 'Subscribe');
    $this->assertSession()->pageTextContains('You have been subscribed.');

    $subscriber = $this->getLatestSubscriber();
    $this->assertEquals($mail, $subscriber->getMail());
    $this->assertTrue($subscriber->isSubscribed($newsletter_id));
  }

  /**
   * Test anonymous subscription with redirect page after verification.
   *
   * Steps performed:
   * 0. Preparation
   * 1. Subscribe anonymous via block.
   * 2. Follow redirect link.
   */
  public function testSubscribeAnonymousRedirect() {
    // 0. Preparation
    // Login admin
    // Set permission for anonymous to subscribe
    // Enable newsletter block
    // Logout admin.
    $admin_user = $this->drupalCreateUser([
      'administer blocks',
      'access administration pages',
      'administer newsletters',
      'administer permissions',
      'administer simplenews settings',
    ]
    );
    $this->drupalLogin($admin_user);

    // Create a newsletter.
    $this->drupalGet('admin/config/services/simplenews');
    $this->clickLink('Add newsletter');
    $name = $this->randomMachineName();
    $edit = [
      'name' => $name,
      'id' => strtolower($name),
      'description' => $this->randomString(20),
      'access' => 'default',
    ];
    $this->submitForm($edit, 'Save');

    $newsletter_id = $edit['id'];

    // Access and change the redirect path on configuration.
    $redirectPath = '/simplenews/validate';

    $this->drupalGet('admin/config/services/simplenews/settings/subscription');
    $this->assertSession()->statusCodeEquals(200);
    $this->submitForm(['simplenews_confirm_subscribe_page' => $redirectPath], 'Save configuration');
    $this->assertSession()->responseContains('The configuration options have been saved.');

    $this->drupalLogout();

    // Build the block.
    $block_settings = [
      'default_newsletters' => [$newsletter_id],
      'message' => $this->randomMachineName(4),
    ];
    $this->setupSubscriptionBlock($block_settings);

    // 1. Subscribe anonymous via block
    // Subscribe + submit
    // Assert confirmation message
    // Assert outgoing email
    // Confirm using mail link
    $mail = $this->randomEmail(8);
    $edit = [
      'mail[0][value]' => $mail,
    ];
    $this->drupalGet('');
    $this->submitForm($edit, 'Subscribe');
    $this->assertSession()->pageTextContains('You will receive a confirmation e-mail shortly containing further instructions on how to complete your subscription.');

    // Receive and access link on email.
    $subscriber = $this->getLatestSubscriber();
    $this->assertEquals($mail, $subscriber->getMail());
    $this->assertFalse($subscriber->isConfirmed());
    $confirm_url = $this->extractConfirmationLink($this->getMail(0));
    $this->drupalGet($confirm_url);

    Newsletter::load($newsletter_id);
    $this->assertSession()->responseContains('Are you sure you want to confirm your subscription for <em class="placeholder">' . simplenews_mask_mail($mail) . '</em>?');

    $this->submitForm([], 'Confirm');

    // 2. Follow redirect link.
    $this->assertSession()->addressEquals(Url::fromUri('internal:' . $redirectPath));

  }

  /**
   * TestSubscribeAuthenticated.
   *
   * Steps performed:
   *   0. Preparation
   *   1. Subscribe authenticated via block
   *   2. Unsubscribe authenticated via subscription page
   *   3. Subscribe authenticated via subscription page
   *   4. Unsubscribe authenticated via account page
   *   5. Subscribe authenticated via account page
   *   6. Subscribe authenticated via multi block.
   */
  public function testSubscribeAuthenticated() {
    // 0. Preparation
    // Login admin
    // Set permission for anonymous to subscribe
    // Enable newsletter block
    // Logout admin
    // Login Subscriber.
    $admin_user = $this->drupalCreateUser([
      'administer blocks',
      'administer content types',
      'administer nodes',
      'access administration pages',
      'administer permissions',
      'administer newsletters',
    ]
    );
    $this->drupalLogin($admin_user);

    // Create some newsletters for multi-sign up block.
    $this->drupalGet('admin/config/services/simplenews');
    for ($i = 0; $i < 5; $i++) {
      $this->clickLink(t('Add newsletter'));
      $name = $this->randomMachineName();
      $edit = [
        'name' => $name,
        'id' => strtolower($name),
        'description' => $this->randomString(20),
        'access' => 'default',
      ];
      $this->submitForm($edit, 'Save');
    }

    $newsletter_id = $this->getRandomNewsletter();
    $this->drupalLogout();

    // Setup subscription block with subscription form.
    $block_settings = [
      'default_newsletters' => [$newsletter_id],
      'message' => $this->randomMachineName(4),
    ];
    $single_block = $this->setupSubscriptionBlock($block_settings);
    $subscriber_user = $this->drupalCreateUser(['subscribe to newsletters']);
    $this->drupalLogin($subscriber_user);
    $this->assertEquals(0, $this->countSubscribers());

    // 1. Subscribe authenticated via block
    // Subscribe + submit
    // Assert confirmation message.
    $this->submitForm([], 'Subscribe');
    $this->assertSession()->pageTextContains('You have been subscribed.');
    $this->assertEquals(1, $this->countSubscribers());

    // Disable the newsletter block.
    $single_block->delete();

    // 3. Subscribe authenticated via account page.
    // Subscribe + submit
    // Assert confirmation message.
    $this->resetSubscribers();
    $edit = [
      "subscriptions[$newsletter_id]" => '1',
    ];
    $url = 'user/' . $subscriber_user->id() . '/simplenews';
    $this->drupalGet($url);
    $this->submitForm($edit, 'Save');
    $this->assertSession()->responseContains('Your newsletter subscriptions have been updated.');
    $this->assertEquals(1, $this->countSubscribers());

    // 4. Unsubscribe authenticated via account page
    // Unsubscribe + submit
    // Assert confirmation message.
    $edit = [
      "subscriptions[$newsletter_id]" => FALSE,
    ];
    $this->drupalGet($url);
    $this->submitForm($edit, 'Save');
    $this->assertSession()->responseContains('Your newsletter subscriptions have been updated.');

    $subscriber = Subscriber::loadByMail($subscriber_user->getEmail());
    $this->assertTrue($subscriber->isUnsubscribed($newsletter_id), t('Subscriber is unsubscribed'));

    // 5. Subscribe authenticated via account page
    // Subscribe + submit
    // Assert confirmation message.
    $this->resetSubscribers();
    $edit = [
      "subscriptions[$newsletter_id]" => '1',
    ];
    $this->drupalGet($url);
    $this->submitForm($edit, 'Save');
    $this->assertSession()->responseContains('Your newsletter subscriptions have been updated.');
    $count = 1;
    $this->assertEquals($count, $this->countSubscribers());

    // Try to submit multi-signup form without selecting a newsletter.
    $subscriber_user2 = $this->drupalCreateUser(['subscribe to newsletters']);
    $this->drupalLogin($subscriber_user2);

    // Check that the user has only access to their own subscriptions page.
    $this->drupalGet('user/' . $subscriber_user->id() . '/simplenews');
    $this->assertSession()->statusCodeEquals(403);

    $this->drupalGet('user/' . $subscriber_user2->id() . '/simplenews');
    $this->assertSession()->statusCodeEquals(200);

    $this->assertSession()->fieldNotExists('mail[0][value]');
    $this->submitForm([], 'Save');
    $this->assertSession()->pageTextContains('Your newsletter subscriptions have been updated.');

    // Nothing should have happened to subscriptions but this does create a
    // subscriber.
    $this->drupalGet('user/' . $subscriber_user2->id() . '/simplenews');
    $this->assertSession()->checkboxNotChecked('edit-subscriptions-' . $newsletter_id);
    $count++;
    $this->assertEquals($count, $this->countSubscribers());

    // Now fill out the form and try again.
    $edit = [
      'subscriptions[' . $newsletter_id . ']' => TRUE,
    ];
    $this->submitForm($edit, 'Save');
    $this->assertSession()->pageTextContains('Your newsletter subscriptions have been updated.');
    $this->assertEquals($count, $this->countSubscribers());

    $this->drupalGet('user/' . $subscriber_user2->id() . '/simplenews');
    $this->assertSession()->checkboxChecked('edit-subscriptions-' . $newsletter_id);

    // Unsubscribe.
    $edit = [
      'subscriptions[' . $newsletter_id . ']' => FALSE,
    ];
    $this->submitForm($edit, 'Save');
    $this->assertSession()->pageTextContains('Your newsletter subscriptions have been updated.');

    $this->drupalGet('user/' . $subscriber_user2->id() . '/simplenews');
    $this->assertSession()->checkboxNotChecked('edit-subscriptions-' . $newsletter_id);
  }

  /**
   * Tests Creation of Simplenews Subscription block.
   */
  public function testSimplenewsSubscriptionBlock() {
    $admin_user = $this->drupalCreateUser([
      'administer blocks',
    ]);
    $this->drupalLogin($admin_user);
    $this->drupalGet('/admin/structure/block/add/simplenews_subscription_block/stark');
    // Check for Unique ID field.
    $this->assertSession()->pageTextContains('Unique ID');
    $edit = [
      'settings[unique_id]' => 'test_simplenews_123',
      'settings[newsletters][default]' => TRUE,
      'region' => 'header',
    ];
    $this->submitForm($edit, 'Save block');
    $this->drupalGet('');
    // Provided Unique ID is used as form_id.
    $this->assertSession()->elementExists('css', '#simplenews-subscriptions-block-test-simplenews-123');
  }

  /**
   * Tests admin creating a single subscriber.
   */
  public function testAdminCreate() {
    $admin_user = $this->drupalCreateUser(['administer simplenews subscriptions']);
    $this->drupalLogin($admin_user);

    $newsletter_id = $this->getRandomNewsletter();
    $mail = $this->randomEmail();
    $this->drupalGet('admin/people/simplenews/create');
    $this->assertSession()->pageTextContains('Add subscriber');
    $edit = [
      "subscriptions[$newsletter_id]" => TRUE,
      'mail[0][value]' => $mail,
    ];
    $this->submitForm($edit, 'Save');
    $this->assertSession()->pageTextContains('Subscriber ' . $mail . ' has been added.');

    $subscriber = Subscriber::loadByMail($mail);
    $this->assertTrue($subscriber->isSubscribed($newsletter_id));

    // Check that an unsubscribe link works without any permissions.
    $this->drupalLogout();
    user_role_revoke_permissions(AccountInterface::ANONYMOUS_ROLE, ['subscribe to newsletters']);

    $node = $this->drupalCreateNode([
      'type' => 'simplenews_issue',
      'simplenews_issue[target_id]' => ['target_id' => $newsletter_id],
    ]);
    \Drupal::service('simplenews.spool_storage')->addIssue($node);
    \Drupal::service('simplenews.mailer')->sendSpool();

    $unsubscribe_url = $this->extractConfirmationLink($this->getMail(0), 'remove');
    $this->drupalGet($unsubscribe_url);
    $this->assertSession()->pageTextContains('Confirm remove subscription');
    $this->submitForm([], 'Unsubscribe');
    $this->assertSession()->pageTextContains('was unsubscribed from the Default newsletter mailing list.');
  }

  /**
   * Tests access to manage subscriptions with a hash.
   */
  public function testHashAuth() {
    // User subscriber can't use /newsletter/validate.
    $user = $this->drupalCreateUser(['subscribe to newsletters']);
    $mail = $user->getEmail();
    $subscriber = Subscriber::loadByMail($mail, 'create');
    $subscriber->save();
    $this->drupalGet('simplenews/subscriptions');
    $this->assertSession()->addressEquals('/simplenews/validate');

    $this->submitForm(['mail' => $mail], 'Submit');
    $this->assertSession()->pageTextContains("Please log in to manage your subscriptions.");
    $this->assertSession()->addressEquals('user/' . $user->id() . '/simplenews');

    // User subscriber can use a hash token.
    $hash = simplenews_generate_hash($subscriber->getMail(), 'manage');
    $this->drupalGet('simplenews/manage/' . $subscriber->id() . '/' . \Drupal::time()->getRequestTime() . '/' . $hash);
    $this->assertSession()->pageTextContains("Subscriptions for $mail");
    $this->submitForm([], 'Update');
    $this->assertSession()->pageTextContains('Your newsletter subscriptions have been updated.');

    // Anon subscriber can use /newsletter/validate.
    $this->config('simplenews.settings')
      ->set('subscription.skip_verification', TRUE)
      ->save();
    $mail2 = $this->randomEmail();
    $newsletter_id = $this->getRandomNewsletter();
    $this->subscribe($newsletter_id, $mail2);
    $subscriber2 = Subscriber::loadByMail($mail2);
    $this->drupalGet('/simplenews/validate');
    $this->submitForm(['mail' => $mail2], 'Submit');
    $this->assertSession()->pageTextContains("If $mail2 is subscribed, an email will be sent with a link to manage your subscriptions.");
    $validate_url = $this->extractConfirmationLink($this->getMail(0), 'manage');
    $this->drupalGet($validate_url);
    $this->assertSession()->pageTextContains("Subscriptions for $mail2");
  }

  /**
   * Tests formatting and escaping of subscription mails.
   */
  public function testFormatting() {
    $this->config('simplenews.settings')
      ->set('subscription.confirm_subject', 'Please <join> us & enjoy')
      ->set('subscription.confirm_body', "Hello & welcome,\n\nclick to join us <[simplenews-subscriber:confirm-url]>")
      ->save();

    $newsletter_id = $this->getRandomNewsletter();
    $newsletter = Newsletter::load($newsletter_id);
    $newsletter->name = 'Rise & <shine>';
    $newsletter->save();

    $mail = $this->randomEmail(8);
    $this->subscribe('default', $mail);

    $captured_emails = $this->container->get('state')->get('system.test_mail_collector') ?: [];
    $email = end($captured_emails);
    $this->assertEquals('Please <join> us & enjoy', $email['subject']);
    $this->assertStringContainsString("Hello & welcome,\n\nclick to join us  \n<http", $email['body']);
  }

  /**
   * Tests protection against duplicate subscribers.
   */
  public function testDuplicate() {
    foreach (['a', 'b', 'c', 'd', 'e'] as $i) {
      $edit = [
        'name' => "news_$i",
        'id' => $i,
        'access' => 'default',
      ];
      if ($i == 'e') {
        $edit['new_account'] = 'on';
      }

      Newsletter::create($edit)->save();
    }

    $this->config('simplenews.settings')
      ->set('subscription.skip_verification', TRUE)
      ->save();
    $this->config('user.settings')
      ->set('register', UserInterface::REGISTER_VISITORS)
      ->save();

    // - Create 2 anon subscribers with email A and B.
    // - Admin edits subscriber A to email B.
    // - Should fail.
    $mail_a = $this->randomEmail();
    $this->subscribe('a', $mail_a);
    $sub_a = $this->getLatestSubscriber();
    $this->assertEquals($mail_a, $sub_a->getMail());
    $mail_b = $this->randomEmail();
    $this->subscribe('b', $mail_b);
    $sub_b = $this->getLatestSubscriber();
    $this->assertEquals($mail_b, $sub_b->getMail());
    $this->assertEquals(2, $this->countSubscribers());

    $admin_user = $this->drupalCreateUser(['administer simplenews subscriptions', 'administer users']);
    $this->drupalLogin($admin_user);
    $this->drupalGet('admin/people/simplenews/edit/' . $sub_a->id());
    $this->submitForm(['mail[0][value]' => $mail_b], 'Save');
    $this->assertSession()->pageTextContains("A simplenews subscriber with email $mail_b already exists.");
    $this->assertEquals(2, $this->countSubscribers());

    // - Create a registered user C with no subscriptions.
    // - Admin changes email of subscriber A to C.
    // - Should link subscriptions of A to C.
    $user_c = $this->drupalCreateUser(['subscribe to newsletters']);
    $this->submitForm(['mail[0][value]' => $user_c->getEmail()], 'Save');
    $sub_c = Subscriber::loadByUid($user_c->id());
    $this->assertEquals($sub_a->id(), $sub_c->id());
    $this->assertEquals(['a'], $sub_c->getSubscribedNewsletterIds());
    $this->assertEquals(2, $this->countSubscribers());

    // - Create a registered user subscriber D.
    // - Admin changes email to B.
    // - Should delete subscriber B.
    // - User D subscriptions should not change.
    $user_d = $this->drupalCreateUser(['subscribe to newsletters']);
    $this->subscribe('d', NULL, [], $user_d->id());
    $this->assertEquals(3, $this->countSubscribers());

    $this->drupalGet('user/' . $user_d->id() . '/edit');
    $this->submitForm(['mail' => $mail_b], 'Save');
    $this->assertEquals(2, $this->countSubscribers());
    $sub_d = Subscriber::loadByUid($user_d->id());
    $this->assertEquals(['d'], $sub_d->getSubscribedNewsletterIds());

    // - Create anon subscriber with email E.
    // - Register user with email E and subscribe new account.
    // - Subscription for user should be unconfirmed.
    // - Log-in.
    // - Subscription for user should be confirmed and combined with the first.
    $sub_mgr = \Drupal::service('simplenews.subscription_manager');
    $this->drupalLogout();
    $mail_e = $this->randomEmail();
    $this->subscribe('d', $mail_e);
    $sub_e = Subscriber::loadByMail($mail_e);
    $this->assertTrue($sub_e->isConfirmed());
    $this->assertEquals(['d'], $sub_e->getSubscribedNewsletterIds());
    $this->assertEquals(3, $this->countSubscribers());
    $this->assertTrue($sub_mgr->isSubscribed($mail_e, 'd'));

    $this->config('simplenews.settings')
      ->set('subscription.skip_verification', FALSE)
      ->save();
    $this->drupalGet('user/register');
    $this->submitForm(['mail' => $mail_e, 'name' => 'e'], 'Create new account');
    $this->assertSession()->pageTextContains('You have been subscribed to news_e');
    $user_e = user_load_by_mail($mail_e);
    $sub_user_e = Subscriber::loadByUid($user_e->id(), FALSE, FALSE);
    $this->assertFalse($sub_user_e->isConfirmed());
    $this->assertFalse($sub_mgr->isSubscribed($mail_e, 'e'));
    $this->assertEquals(['e'], $sub_user_e->getSubscribedNewsletterIds());
    $this->assertEquals(4, $this->countSubscribers());

    $resetUrl = user_pass_reset_url($user_e);
    $this->drupalGet($resetUrl);
    $this->submitForm([], 'Log in');
    \Drupal::entityTypeManager()->getStorage('simplenews_subscriber')->resetCache();
    $sub_user_e = Subscriber::loadByUid($user_e->id());
    $this->assertTrue($sub_user_e->isConfirmed());
    $this->assertEquals(3, $this->countSubscribers());
    $this->assertTrue($sub_mgr->isSubscribed($mail_e, 'd'));
    $this->assertTrue($sub_mgr->isSubscribed($mail_e, 'e'));
    $this->assertEquals(['d', 'e'], $sub_user_e->getSubscribedNewsletterIds());
  }

  /**
   * Tests subscription block settings.
   */
  public function testBlockSettings() {
    foreach (['a', 'b'] as $i) {
      $edit = [
        'name' => "news_$i",
        'id' => $i,
        'access' => 'default',
      ];
      Newsletter::create($edit)->save();
    }

    // Set up block with 2 newsletters available, no defaults.
    $block = $this->setupSubscriptionBlock(['newsletters' => ['a', 'b']]);
    $user = $this->drupalCreateUser(['subscribe to newsletters']);
    $this->drupalLogin($user);

    // Check both newsletters are available. Get an error if we don't pick any.
    $this->assertSession()->fieldExists('subscriptions[a]');
    $this->assertSession()->fieldExists('subscriptions[b]');
    $this->submitForm([], 'Subscribe');
    $this->assertSession()->pageTextContains("Manage your newsletter subscriptions field is required.");

    // Subscribe to 'a'. Check only 'b' is now available.
    $this->submitForm(['subscriptions[a]' => 'a'], 'Subscribe');
    $this->assertSession()->pageTextContains("You have been subscribed.");
    $this->assertSession()->fieldNotExists('subscriptions[a]');

    // Subscribe to 'b'. Check no newsletters are available.
    $this->submitForm(['subscriptions[b]' => 'b'], 'Subscribe');
    $this->assertSession()->pageTextContains("You have been subscribed.");
    $this->assertSession()->pageTextContains("You are already subscribed");
    $this->assertSession()->fieldNotExists('subscriptions[b]');

    // Click 'Manage existing' and unsubscribe.
    $this->clickLink('Manage existing');
    $this->assertSession()->addressEquals('user/' . $user->id() . '/simplenews');
    $this->submitForm(['subscriptions[a]' => '0', 'subscriptions[b]' => '0'], 'Save');

    // Default one newsletter on, check it is ticked.
    $block->getPlugin()->setConfigurationValue('default_newsletters', ['a']);
    $block->save();
    $this->drupalGet('');
    $this->assertSession()->checkboxChecked('subscriptions[a]');
    $this->assertSession()->checkboxNotChecked('subscriptions[b]');

    // Also make it hidden. Check can subscribe without picking any.
    // Remove the manage link and check it isn't shown.
    $block->getPlugin()->setConfigurationValue('newsletters', ['b']);
    $block->getPlugin()->setConfigurationValue('show_manage', FALSE);
    $block->save();
    $this->drupalGet('');
    $this->assertSession()->linkNotExistsExact('Manage existing');
    $this->assertSession()->fieldNotExists('subscriptions[a]');
    $this->submitForm([], 'Subscribe');
    $this->assertSession()->pageTextContains("You have been subscribed.");
    $this->assertTrue(\Drupal::service('simplenews.subscription_manager')->isSubscribed($user->getEmail(), 'a'));
  }

  /**
   * Gets the number of subscribers entities.
   */
  protected function countSubscribers() {
    return \Drupal::entityQuery('simplenews_subscriber')->accessCheck(FALSE)->count()->execute();
  }

  /**
   * Delete all subscriber entities ready for the next test.
   */
  protected function resetSubscribers() {
    $storage = \Drupal::entityTypeManager()->getStorage('simplenews_subscriber');
    $storage->delete($storage->loadMultiple());
  }

  /**
   * Enables tracking of (un)subscribe hooks.
   */
  protected function trackHookResults() {
    \Drupal::state()->set('simplenews.test_hook_results', []);
  }

  /**
   * Checks that an (un)subscribe hook has been called.
   *
   * @param string $op
   *   The operation: add or remove.
   * @param string $email
   *   The subscriber email address.
   * @param string $newsletter_id
   *   The newsletter ID for this specific subscribe action.
   */
  protected function assertHookResult(string $op, string $email, string $newsletter_id) {
    $results = \Drupal::state()->get('simplenews.test_hook_results');
    $key = array_search([$op, $email, $newsletter_id], $results);
    $this->assertNotFalse($key, "Hook $op called for $email on newsletter $newsletter_id");
    unset($results[$key]);
    \Drupal::state()->set('simplenews.test_hook_results', $results);
  }

  /**
   * Checks that there were no extra calls to (un)subscribe hooks.
   */
  protected function assertNoHookResult() {
    $this->assertEmpty(\Drupal::state()->get('simplenews.test_hook_results'));
  }

}

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

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