diff --git a/src/Plugin/Block/SamlLoginBlock.php b/src/Plugin/Block/SamlLoginBlock.php index 0bcb9a7..d024c2d 100644 --- a/src/Plugin/Block/SamlLoginBlock.php +++ b/src/Plugin/Block/SamlLoginBlock.php @@ -17,7 +17,7 @@ * * @Block( * id = "stanford_samlauth_login_block", - * admin_label = @Translation("SAML SUNetID Block") + * admin_label = @Translation("SAML SUNetID Login Block") * ) */ class SamlLoginBlock extends BlockBase implements ContainerFactoryPluginInterface { diff --git a/src/Plugin/Block/SamlLogoutBlock.php b/src/Plugin/Block/SamlLogoutBlock.php new file mode 100644 index 0000000..530b404 --- /dev/null +++ b/src/Plugin/Block/SamlLogoutBlock.php @@ -0,0 +1,129 @@ +get('request_stack') + ); + } + + /** + * Block constructor. + * + * @param array $configuration + * Configuration settings. + * @param string $plugin_id + * Block machine name. + * @param array $plugin_definition + * Plugin definition. + * @param \Symfony\Component\HttpFoundation\RequestStack $requestStack + * Current request stack object. + */ + public function __construct(array $configuration, string $plugin_id, array $plugin_definition, RequestStack $requestStack) { + parent::__construct($configuration, $plugin_id, $plugin_definition); + $this->currentUri = $requestStack->getCurrentRequest() ?->getPathInfo(); + } + + /** + * {@inheritdoc} + */ + public function defaultConfiguration() { + return ['link_text' => 'SUNetID Logout'] + parent::defaultConfiguration(); + } + + /** + * {@inheritdoc} + */ + public function blockForm($form, FormStateInterface $form_state) { + $form['link_text'] = [ + '#type' => 'textfield', + '#title' => $this->t('SUNetID log-out link text'), + '#description' => $this->t('Add text to show a link for authenticated users.'), + '#default_value' => $this->configuration['link_text'], + '#required' => TRUE, + ]; + return $form; + } + + /** + * {@inheritdoc} + */ + public function getCacheContexts() { + $context = parent::getCacheContexts(); + // Make the block cache different for each page since the login link has a + // destination parameter. + return Cache::mergeContexts($context, ['url.path']); + } + + /** + * {@inheritdoc} + */ + public function access(AccountInterface $account, $return_as_object = FALSE) { + $access = AccessResult::allowedIf($account->isAuthenticated()); + return $return_as_object ? $access : $access->isAllowed(); + } + + /** + * {@inheritdoc} + */ + public function blockSubmit($form, FormStateInterface $form_state) { + $this->configuration['link_text'] = $form_state->getValue('link_text'); + } + + /** + * {@inheritdoc} + */ + public function build() { + $url = Url::fromRoute('user.logout', ['destination' => $this->currentUri]); + $build = []; + $build['logout'] = [ + '#type' => 'html_tag', + '#tag' => 'a', + '#value' => $this->configuration['link_text'], + '#attributes' => [ + 'rel' => 'nofollow', + 'href' => $url->toString(), + 'class' => [ + 'su-button', + 'decanter-button', + ], + ], + ]; + return $build; + } + +} diff --git a/tests/src/Unit/Plugin/Block/SamlLogoutBlockTest.php b/tests/src/Unit/Plugin/Block/SamlLogoutBlockTest.php new file mode 100644 index 0000000..bb37871 --- /dev/null +++ b/tests/src/Unit/Plugin/Block/SamlLogoutBlockTest.php @@ -0,0 +1,96 @@ +createMock(UrlGeneratorInterface::class); + $url_generator->method('generateFromRoute')->willReturn('/foo-bar'); + + $request_stack = new RequestStack(); + + $context_manager = $this->createMock(CacheContextsManager::class); + $context_manager->method('assertValidTokens')->willReturn(TRUE); + + $container = new ContainerBuilder(); + $container->set('string_translation', $this->getStringTranslationStub()); + $container->set('url_generator', $url_generator); + $container->set('request_stack', $request_stack); + $container->set('cache_contexts_manager', $context_manager); + \Drupal::setContainer($container); + + $this->block = SamlLogoutBlock::create($container, [], 'saml_logout', ['provider' => 'stanford_samlauth']); + } + + /** + * Test configuration and form methods. + */ + public function testBlock() { + $this->assertEquals(['link_text' => 'SUNetID Logout'], $this->block->defaultConfiguration()); + $form_state = new FormState(); + $form = $this->block->blockForm([], $form_state); + $this->assertCount(1, $form); + $this->assertArrayHasKey('link_text', $form); + + $link_text = $this->getRandomGenerator()->string(); + $form_state->setValue('link_text', $link_text); + $this->block->blockSubmit($form, $form_state); + $new_config = $this->block->getConfiguration(); + $this->assertEquals($link_text, $new_config['link_text']); + } + + /** + * Test anonymous users would access the block, authenticated would not. + */ + public function testAccess() { + $this->assertContains('url.path', $this->block->getCacheContexts()); + + $account = $this->createMock(AccountInterface::class); + $account->method('isAuthenticated')->willReturn(TRUE); + $this->assertTrue($this->block->access($account)); + + $account = $this->createMock(AccountInterface::class); + $account->method('isAuthenticated')->willReturn(FALSE); + $this->assertFALSE($this->block->access($account)); + } + + /** + * Test build render array is structured correctly. + */ + public function testBuild() { + $build = $this->block->build(); + $this->assertCount(1, $build); + $this->assertArrayHasKey('logout', $build); + $this->assertEquals('html_tag', $build['logout']['#type']); + $this->assertEquals('/foo-bar', $build['logout']['#attributes']['href']); + } + +}