coveo-1.0.0-alpha1/modules/coveo_secured_search/src/Entity/CoveoCustomSecurityProvider.php

modules/coveo_secured_search/src/Entity/CoveoCustomSecurityProvider.php
<?php

declare(strict_types=1);

namespace Drupal\coveo_secured_search\Entity;

use Drupal\Component\Plugin\Exception\PluginException;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Logger\LoggerChannelTrait;
use Drupal\Core\Messenger\MessengerTrait;
use Drupal\Core\Session\AccountInterface;
use Drupal\coveo\Entity\CoveoOrganizationInterface;
use Drupal\coveo\Entity\CoveoSearchComponent;
use Drupal\coveo_secured_search\Event\CoveoSecurityProviderAlter;
use Drupal\coveo_secured_search\Plugin\CoveoCustomSecurityProviderManagerInterface;
use Drupal\coveo_secured_search\Plugin\CoveoCustomSecurityProviderPluginInterface;
use NecLimDul\Coveo\SecurityCache\Model\SecurityProviderModel;
use Neclimdul\OpenapiPhp\Helper\Logging\Error as ApiError;
use Psr\Log\LogLevel;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

/**
 * Defines Coveo Search configuration entity.
 *
 * Defines configuration for exposing searches through user key generation.
 *
 * @ConfigEntityType(
 *   id = "coveo_custom_security_provider",
 *   label = @Translation("Coveo Security Provider"),
 *   label_collection = @Translation("Coveo Security Providers"),
 *   label_singular = @Translation("Coveo security provider"),
 *   label_plural = @Translation("Coveo security providers"),
 *   label_count = @PluralTranslation(
 *     singular = "@count Coveo security provider",
 *     plural = "@count Coveo security providers",
 *   ),
 *   handlers = {
 *     "form" = {
 *       "add" = "Drupal\coveo_secured_search\Form\SecurityProviders\CustomSecurityProviderForm",
 *       "edit" = "Drupal\coveo_secured_search\Form\SecurityProviders\CustomSecurityProviderForm",
 *       "delete" = "Drupal\coveo_secured_search\Form\SecurityProviders\CustomSecurityProviderDeleteForm",
 *     },
 *     "list_builder" = "Drupal\coveo_secured_search\CustomSecurityProviderListBuilder",
 *     "storage" = "Drupal\coveo_secured_search\SecurityProviderStorage",
 *   },
 *   admin_permission = "administer coveo search",
 *   config_prefix = "custom_security_provider",
 *   entity_keys = {
 *     "id" = "name",
 *     "label" = "label",
 *     "coveo_name" = "coveo_name",
 *     "description" = "description",
 *     "security_provider" = "security_provider",
 *   },
 *   links = {
 *     "edit-form" = "/admin/config/search/coveo/security_providers/manage/{coveo_custom_security_provider}",
 *     "delete-form" = "/admin/config/search/coveo/security_providers/manage/{coveo_custom_security_provider}/delete",
 *     "collection" = "/admin/config/search/coveo/security_providers",
 *   },
 *   config_export = {
 *     "name",
 *     "label",
 *     "coveo_name",
 *     "description",
 *     "security_provider",
 *     "push_sources",
 *     "organization_name",
 *   }
 * )
 *
 * @phpstan-type SyncOperation callable(string, string, \Drupal\coveo_search_api\Plugin\search_api\backend\SearchApiCoveoBackend[]): void
 */
class CoveoCustomSecurityProvider extends ConfigEntityBase implements CoveoCustomSecurityProviderInterface {

  use LoggerChannelTrait, MessengerTrait;

  /**
   * The name of the provider.
   */
  protected string $name;

  /**
   * The provider label.
   */
  protected string $label;

  /**
   * A description of the provider.
   */
  protected ?string $description;

  /**
   * Coveo security provider plugin type.
   */
  protected ?string $security_provider;

  /**
   * Coveo security provider.
   */
  protected ?string $organization_name;

  /**
   * Coveo push sources.
   */
  protected ?array $push_sources;

  /**
   * Custom Security Provider plugin manager.
   */
  private CoveoCustomSecurityProviderManagerInterface $manager;

  /**
   * Event dispatcher.
   */
  private EventDispatcherInterface $eventDispatcher;

  public function __construct(array $values, $entity_type) {
    parent::__construct($values, $entity_type);
    $this->manager = \Drupal::service('plugin.manager.coveo_custom_security_provider');
    $this->eventDispatcher = \Drupal::service('event_dispatcher');
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  public function id(): string|null {
    return $this->name ?? NULL;
  }

  /**
   * {@inheritDoc}
   */
  #[\Override]
  public function getDescription(): string|null {
    return $this->description ?? NULL;
  }

  /**
   * {@inheritDoc}
   */
  #[\Override]
  public function getSecurityProviderPluginId(): string|null {
    return $this->security_provider ?? NULL;
  }

  /**
   * {@inheritDoc}
   */
  #[\Override]
  public function getPushSourceIds(): array {
    return $this->push_sources ?? [];
  }

  /**
   * {@inheritDoc}
   */
  #[\Override]
  public function getOrganizationName(): string|null {
    return $this->organization_name ?? NULL;
  }

  /**
   * {@inheritDoc}
   */
  #[\Override]
  public function getCoveoName(): string|null {
    return $this->coveo_name ?? NULL;
  }

  /**
   * {@inheritDoc}
   */
  #[\Override]
  public function getSecurityProviderId(): string {
    if ($this->getCoveoName()) {
      return $this->getCoveoName();
    }

    // Should this be conditional?
    $prefix = $this->getOrganization()?->getPrefix();

    return $prefix . '-' . $this->getSecurityProviderBaseName() . '-' . $this->id();
  }

  /**
   * The base name used for identifying this provider in Coveo.
   *
   * @return string
   *   Provider base name.
   */
  protected function getSecurityProviderBaseName(): string {
    return $this->manager->getDefinition($this->getSecurityProviderPluginId())['baseName'];
  }

  /**
   * {@inheritDoc}
   */
  #[\Override]
  public function getSecurityProvider(): CoveoCustomSecurityProviderPluginInterface {
    $instance = $this->manager->createInstance(
      $this->getSecurityProviderPluginId(),
      [
        'provider_id' => $this->getSecurityProviderId(),
      ]
    );
    return $instance;
  }

  /**
   * {@inheritDoc}
   */
  #[\Override]
  public function generateToken(
    CoveoSearchComponent $search,
    AccountInterface $account,
  ): string {
    $token = FALSE;
    // @todo figure out how to avoid unnecessary token generation
    // Sessions are broken and can't time out for refresh broken tokens so
    // disabled until I can find a fix.
    // $session = $request->getSession();
    // $session->get('coveo_token', FALSE);
    // $session->remove('coveo_token');
    /* @phpstan-ignore-next-line */
    if (!$token) {
      try {
        return $this->getSecurityProvider()
          ->generateToken($search, $account);
      }
      catch (PluginException $e) {
        // dpm($e->getMessage());
        // @todo log plugin failure.
        // Call through and return false as a failure.
      }
    }
    return 'failure';
  }

  /**
   * {@inheritDoc}
   */
  #[\Override]
  public function getOrganization(): CoveoOrganizationInterface|null {
    $id = $this->getOrganizationName();
    if ($id) {
      return $this->entityTypeManager()
        ->getStorage('coveo_organization')
        ->load($id);
    }
    return NULL;
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  public function calculateDependencies() {
    parent::calculateDependencies();
    $organization = $this->getOrganization();
    $this->addDependency('config', $organization->getConfigDependencyName());
    return $this;
  }

  /**
   * {@inheritDoc}
   */
  #[\Override]
  public function postSave(EntityStorageInterface $storage, $update = TRUE) {
    \Drupal::service('plugin.manager.coveo_security_provider')->clearCachedDefinitions();
    $organization = $this->getOrganization();
    if ($organization && !$organization->isReadOnly()) {
      $this->writeToCoveo();
    }
  }

  /**
   * {@inheritDoc}
   */
  #[\Override]
  public static function postDelete(EntityStorageInterface $storage, array $entities) {
    \Drupal::service('plugin.manager.coveo_security_provider')->clearCachedDefinitions();
    foreach ($entities as $entity) {
      assert($entity instanceof static);
      $organization = $entity->getOrganization();
      if ($organization !== NULL && !$organization->isReadOnly()) {
        $entity->deleteFromCoveo();
      }
    }
  }

  /**
   * Sync this custom provider to Coveo.
   *
   * @see https://docs.coveo.com/en/85/index-content/create-or-update-a-security-identity-provider-for-a-secured-push-source
   * @see https://platform.cloud.coveo.com/docs?urls.primaryName=SecurityCache#/Security%20Providers/rest_organizations_paramId_securityproviders_paramId_put
   */
  private function writeToCoveo(): void {

    $provider_id = $this->getSecurityProviderId();
    $base_name = $this->getSecurityProviderBaseName();

    // Create SecurityProviderModel based on this entities' config.
    // @todo it probably makes sense for the plugin to generate this so it
    //   can do any quirky customization of the provider in Coveo it needs to.
    // @todo should this cascade to email provider by default?
    // Generate a provider model.
    $params = new SecurityProviderModel();
    $params->setId($provider_id);
    $params->setDisplayName($base_name . ' - ' . $this->label());
    $params->setType(SecurityProviderModel::TYPE_EXPANDED);
    $params->setNodeRequired(FALSE);

    // Trigger alter event.
    $this->eventDispatcher->dispatch(new CoveoSecurityProviderAlter(
      $this,
      $params
    ));

    // Get a SecurityProviderApi instance.
    // Call API.
    $response = $this->getOrganization()?->getSecurityProviderApi()
      ->createOrUpdateSecurityProvider(
        $this->getOrganization()->getOrganizationId(),
        $provider_id,
        $params,
      );
    if ($response === NULL) {
      $this->messenger()
        ->addError('Error creating request to sync Coveo provider.');
    }
    elseif (!$response->isSuccess()) {
      $this->messenger()->addError('Error syncing provider to Coveo. Check logs for more information.');
      ApiError::logError(
        $this->getLogger('coveo'),
        $response,
      );
    }
  }

  /**
   * Sync this custom provider to Coveo.
   *
   * @see https://docs.coveo.com/en/85/index-content/create-or-update-a-security-identity-provider-for-a-secured-push-source
   * @see https://platform.cloud.coveo.com/docs?urls.primaryName=SecurityCache#/Security%20Providers/rest_organizations_paramId_securityproviders_paramId_delete
   */
  private function deleteFromCoveo(): void {
    $provider_id = $this->getSecurityProviderId();
    // @todo this doesn't seem to actually do anything. Coveo is aware and
    //   should be fixing it.
    // Get a SecurityProviderApi instance.
    $response = $this->getOrganization()?->getSecurityProviderApi()
      ->removeSecurityProvider(
        $this->getOrganization()->getOrganizationId(),
        $provider_id,
      );
    if ($response === NULL) {
      $this->messenger()
        ->addError('Error creating request to delete Coveo provider.');
    }
    elseif ($response->getResponse()->getStatusCode() == 412) {
      $this->messenger()->addWarning('Known delete failure. Coveo can\'t actually delete a provider with its delete method so you will have to manually clean up your push source securityProviderReferences.');
      ApiError::logError(
        $this->getLogger('coveo'),
        $response,
        LogLevel::DEBUG,
        'Known delete failure. ' . $response->getResponse()->getBody(),
      );
    }
    elseif (!$response->isSuccess()) {
      $this->messenger()->addError('Error syncing provider to Coveo. Check logs for more information.');
      ApiError::logError(
        $this->getLogger('coveo'),
        $response,
      );
    }
  }

}

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

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