SU-HKKU/cardinal_service_profile

View on GitHub
src/Plugin/InstallTask/SiteSettings.php

Summary

Maintainability
B
4 hrs
Test Coverage
A
100%
<?php

namespace Drupal\cardinal_service_profile\Plugin\InstallTask;

use Drupal\Component\Utility\Html;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Site\Settings;
use Drupal\Core\State\StateInterface;
use Drupal\externalauth\AuthmapInterface;
use Drupal\cardinal_service_profile\InstallTaskBase;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\GuzzleException;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * SNOW site settings installation.
 *
 * @InstallTask(
 *   id="cardinal_service_profile_site_settings"
 * )
 */
class SiteSettings extends InstallTaskBase implements ContainerFactoryPluginInterface {

  /**
   * The fallback site name.
   */
  const DEFAULT_SITE = 'default';

  /**
   * Service now api endpoint.
   */
  const SNOW_API = 'https://stanford.service-now.com/api/stu/su_acsf_site_requester_information/requestor';

  /**
   * Guzzle service.
   *
   * @var \GuzzleHttp\ClientInterface
   */
  protected $client;

  /**
   * Authmap service.
   *
   * @var \Drupal\externalauth\AuthmapInterface
   */
  protected $authmap;

  /**
   * State Service.
   *
   * @var \Drupal\Core\State\StateInterface
   */
  protected $state;

  /**
   * Logger channel service.
   *
   * @var \Drupal\Core\Logger\LoggerChannelInterface
   */
  protected $logger;

  /**
   * {@inheritDoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('entity_type.manager'),
      $container->get('http_client'),
      $container->get('externalauth.authmap'),
      $container->get('state'),
      $container->get('logger.factory')
    );
  }

  /**
   * {@inheritDoc}
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entityTypeManager, ClientInterface $client, AuthmapInterface $authmap, StateInterface $state, LoggerChannelFactoryInterface $logger_factory) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->entityTypeManager = $entityTypeManager;
    $this->client = $client;
    $this->authmap = $authmap;
    $this->state = $state;
    $this->logger = $logger_factory->get('cardinal_service_profile');
  }

  /**
   * {@inheritDoc}
   */
  public function runTask(array &$install_state) {
    $this->state->set('nobots', FALSE);

    $node_pages = [
      '403_page' => '4b8018dc-49a6-4018-9c54-e8c3e462beee',
      '404_page' => '6d51339d-ff67-498d-98e9-d8228d36fd51',
      'front_page' => '72f0069b-f1ec-4122-af73-6aa841faea90',
    ];

    // @codeCoverageIgnoreStart
    foreach ($node_pages as $page => $uuid) {
      if ($node = $this->getNode($uuid)) {
        $this->state->set("stanford_profile.$page", '/node/' . $node->id());
      }
    }

    if (!static::isAhEnv()) {
      return;
    }
    // @codeCoverageIgnoreEnd
    $site_name = $install_state['forms']['install_configure_form']['site_name'] ?? self::DEFAULT_SITE;
    $site_name = Html::escape($site_name);

    $site_data = $this->getSnowData($site_name);
    if (empty($site_data)) {
      return;
    }
    $this->state->set('xmlsitemap_base_url', "https://$site_name.sites.stanford.edu");

    $this->entityTypeManager->getStorage('config_pages')->create([
      'type' => 'stanford_basic_site_settings',
      'su_site_email' => $site_data['email'],
      'su_site_name' => $site_data['webSiteTitle'],
      'context' => 'a:0:{}',
    ])->save();

    $this->addSiteOwner($site_data['sunetId'], $site_data['email']);

    if (isset($site_data['webSiteOwners'])) {
      foreach ($site_data['webSiteOwners'] as $owner) {
        if ($owner['sunetId'] == $site_data['sunetId']) {
          continue;
        }

        $this->addSiteOwner($owner['sunetId'], $owner['email']);
      }
    }
  }

  /**
   * Add a user with the site manager role.
   *
   * @param string $sunet
   *   User SunetId.
   * @param string $email
   *   User email.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  protected function addSiteOwner($sunet, $email) {
    $new_user = $this->entityTypeManager->getStorage('user')->create([
      'name' => $sunet,
      'pass' => user_password(),
      'mail' => $email,
      'roles' => ['site_manager'],
      'status' => 1,
    ]);
    $new_user->save();
    $this->authmap->save($new_user, 'simplesamlphp_auth', $sunet);
  }

  /**
   * Get site information from the SNOW API.
   *
   * @param string $site_name
   *   The requested name of the site.
   *
   * @return array|null
   *   Returned data if any exist.
   */
  protected function getSnowData($site_name) {
    $api_url = Settings::get('cardinal_service_profile_snow_api_url', self::SNOW_API);
    try {
      $response = $this->client->request('GET', $api_url, [
        'query' => ['website_address' => $site_name],
        'auth' => [
          Settings::get('cardinal_service_profile_snow_api_user'),
          Settings::get('cardinal_service_profile_snow_api_pass'),
        ],
      ]);

      $response = json_decode((string) $response->getBody(), TRUE);

      // If the response body was not a json string.
      if (!is_array($response)) {
        throw new \Exception('Could not decode JSON from SNOW API.');
      }

      if (isset($response['result'][0]['message']) && preg_match('/no records found/i', $response['result'][0]['message'])) {
        throw new \Exception($response['result'][0]['message']);
      }

      return reset($response['result'][0]);
    }
    catch (GuzzleException $e) {
      $this->logger->alert($this->t('Unable to fetch SNOW data for %site. Message: %message'), [
        '%site' => $site_name,
        '%message' => $e->getMessage(),
      ]);
    }
    catch (\Exception $e) {
      $this->logger->alert($this->t('Unable to fetch SNOW data for %site. Message: %message'), [
        '%site' => $site_name,
        '%message' => $e->getMessage(),
      ]);
      if ($site_name != 'default') {
        return $this->getSnowData('default');
      }
    }
  }

  /**
   * Load a node by the UUID value.
   *
   * @param string $uuid
   *   Node uuid.
   *
   * @return \Drupal\node\NodeInterface
   *   Node object.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  protected function getNode($uuid) {
    $nodes = $this->entityTypeManager->getStorage('node')->loadByProperties(['uuid' => $uuid]);
    return reset($nodes);
  }

}