social_event_invite_flow-1.0.0-beta3/src/Service/EventInviteFlowService.php

src/Service/EventInviteFlowService.php
<?php

namespace Drupal\social_event_invite_flow\Service;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\node\NodeInterface;
use Drupal\user\UserInterface;
use Drupal\Component\Utility\Crypt;
use Drupal\social_event_invite_flow\EventInviteSettingsInterface;
use Drupal\social_event_invite_flow\EventInviteMessageInterface;
use Drupal\social_event\EventEnrollmentInterface;
use Drupal\Core\Mail\MailManagerInterface;
use Drupal\Component\Utility\EmailValidatorInterface;
use Drupal\Core\Utility\Token;
use Drupal\Component\Render\PlainTextOutput;
use Drupal\Core\Render\Markup;
use Drupal\Core\Url;
use Drupal\Core\Link;
use Drupal\webform\WebformInterface;
use Drupal\social_event_invite_flow\EventInviteFlowLogInterface;


/**
 * Service description.
 */
class EventInviteFlowService {

  use StringTranslationTrait;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The config factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * The current route match.
   *
   * @var \Drupal\Core\Routing\RouteMatchInterface
   */
  protected $routeMatch;

  /**
   * The current user.
   *
   * @var \Drupal\Core\Session\AccountInterface
   */
  protected $account;

  /**
   * The language manager.
   *
   * @var \Drupal\Core\Language\LanguageManagerInterface
   */
  protected $languageManager;

  /**
   * The mail manager.
   *
   * @var \Drupal\Core\Mail\MailManagerInterface
   */
  protected $mailManager;  

  /**
   * The Email validator service.
   *
   * @var \Drupal\Component\Utility\EmailValidatorInterface
   */
  protected $emailValidator;  

  /**
   * The Token service.
   *
   * @var \Drupal\Core\Utility\Token
   */
  protected $token;  

  /**
   * Constructs a Common object.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The config factory.
   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
   *   The current route match.
   * @param \Drupal\Core\Session\AccountInterface $account
   *   The current user.
   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
   *   The language manager.
   */
  public function __construct(
    EntityTypeManagerInterface $entity_type_manager, 
    ConfigFactoryInterface $config_factory, 
    RouteMatchInterface $route_match, 
    AccountInterface $account, 
    LanguageManagerInterface $language_manager, 
    MailManagerInterface $mail_manager, 
    EmailValidatorInterface $email_validator,
    Token $token) {
      
    $this->entityTypeManager = $entity_type_manager;
    $this->configFactory = $config_factory;
    $this->routeMatch = $route_match;
    $this->account = $account;
    $this->languageManager = $language_manager;
    $this->mailManager = $mail_manager;
    $this->emailValidator = $email_validator;
    $this->token = $token;
  
  }

  /**
   * Gets the default invite messages
   * 
   * @return array
   *   An array of configuration object names.
   */
  public function getEventInviteMessagesDefault() {
    return $this->configFactory->get('social_event_invite_flow.settings');
  }

  public function getEventInviteDefaultMessages() {

    $defaults = FALSE;
   
    $config = $this->configFactory->get('social_event_invite_flow.settings');

    if ($config) {
      $defaults = [
        'reply_to' => $config->get('reply_to'),
        'guests_invite_subject' => $config->get('guests_invite_subject'),
        'guests_invite_message' => ['value' => $config->get('guests_invite_message')],
        'new_accounts_invite_subject' => $config->get('new_accounts_invite_subject'),
        'new_accounts_invite_message' => ['value' => $config->get('new_accounts_invite_message')],
        'existing_accounts_invite_subject' => $config->get('existing_accounts_invite_subject'),
        'existing_accounts_invite_message' => ['value' => $config->get('existing_accounts_invite_message')],
      ];
    }

    return $defaults;

  }


  public function getEventInviteSettings(int $nid) {

    $entity = FALSE;

    $node = $this->entityTypeManager->getStorage('node')->load($nid);

    $storage = $this->entityTypeManager->getStorage('event_invite_settings');
    $event_invite_settings = $storage->loadByProperties(['node' => $node->id()]);

    if ($event_invite_setting = reset($event_invite_settings)) {
      $entity = $event_invite_setting;
    }

    return $entity;


  } 
  
  public function isInviteFlowSettingsPresent() {

    $present = FALSE;

    $config = $this->configFactory->get('social_event_invite_flow.settings');

    $invite_mode_existing_accounts = $config->get('invite_mode_existing_accounts');
    $invite_mode_new_accounts = $config->get('invite_mode_new_accounts');
    $webforms_existing_accounts = $config->get('webforms_existing_accounts');
    $webforms_new_accounts = $config->get('webforms_new_accounts');

    if (isset($invite_mode_existing_accounts) &&
        isset($invite_mode_new_accounts) &&
        isset($webforms_existing_accounts) &&
        isset($webforms_new_accounts)
    ) {
      $present = TRUE;
    }

    return $present;

  }

  public function getInviteSettingsDefaultData() {

    $data = [];

    $config = $this->configFactory->get('social_event_invite_flow.settings');

    /** @var \Drupal\node\Entity\Node $node */
    $node = $this->routeMatch->getParameter('node');

    if (isset($node) && !$node instanceof NodeInterface) {
      $storage = $this->entityTypeManager->getStorage('node');
      $node = $storage->loadByProperties(['node' => $node]);
    }

    // Per default we need to have our config data available.
    $data = [
      'invite_mode_existing_accounts' => $config->get('invite_mode_existing_accounts'),
      'invite_mode_new_accounts' => $config->get('invite_mode_new_accounts'),
      'selected_webform_existing_accounts' => '',
      'selected_webform_new_accounts' => ''
    ];

    if ($node instanceof NodeInterface) {
      $storage = $this->entityTypeManager->getStorage('event_invite_settings');
      $event_invite_settings = $storage->loadByProperties(['node' => $node->id()]);
      if ($event_invite_setting = reset($event_invite_settings)) {
        $invite_mode_existing_accounts = $event_invite_setting->getInviteModeExistingAccounts();
        $invite_mode_new_accounts = $event_invite_setting->getInviteModeNewAccounts();
        $selected_webform_existing_accounts = $event_invite_setting->getSelectedWebformExistingAccounts();
        $selected_webform_new_accounts = $event_invite_setting->getSelectedWebformNewAccounts();
        $enable_shareable_link = $event_invite_setting->getEnableShareableLink();

     
        if (isset($invite_mode_existing_accounts)) {
          $data['invite_mode_existing_accounts'] = $invite_mode_existing_accounts;
        }

        if (isset($selected_webform_existing_accounts)) {
          $data['selected_webform_existing_accounts'] = $selected_webform_existing_accounts;
        }

        if (isset($invite_mode_new_accounts)) {
          $data['invite_mode_new_accounts'] = $invite_mode_new_accounts;
        }

        if (isset($selected_webform_new_accounts)) {
          $data['selected_webform_new_accounts'] = $selected_webform_new_accounts;
        }

        if (isset($enable_shareable_link)) {
          $data['enable_shareable_link'] = $enable_shareable_link;
        }
      }
    }
    
    return $data;    

  }

  public function saveEventInviteSettings($node, $fields = NULL) {

    if (!$node instanceof NodeInterface) {
      $storage = $this->entityTypeManager->getStorage('node');
      $node = $storage->loadByProperties(['node' => $node]);
    }   

    $storage = $this->entityTypeManager->getStorage('event_invite_settings');
    $event_invite_settings = $storage->loadByProperties(['node' => $node->id()]);
    if ($event_invite_setting = reset($event_invite_settings)) {
      if (isset($fields)) {
        if (isset($fields['invite_mode_existing_accounts'])) {
          $event_invite_setting->setInviteModeExistingAccounts($fields['invite_mode_existing_accounts']);
        }
        if (isset($fields['invite_mode_new_accounts'])) {
          $event_invite_setting->setInviteModeNewAccounts($fields['invite_mode_new_accounts']);
        }
        if (isset($fields['selected_webform_existing_accounts'])) {
          $event_invite_setting->setSelectedWebformExistingAccounts($fields['selected_webform_existing_accounts']);
        }
        if (isset($fields['selected_webform_new_accounts'])) {
          $event_invite_setting->setSelectedWebformNewAccounts($fields['selected_webform_new_accounts']);
        }
        if (isset($fields['enable_shareable_link'])) {
          $event_invite_setting->setEnableShareableLink($fields['enable_shareable_link']);
        }
      }
      $event_invite_setting->save();
    }
    else {
      // When creating new entity, we need to add the
      // id field, access token and node field, which are only needed
      // when creating new entities.
      $fields['id'] = $node->bundle() . '_' . $node->uuid();
      $fields['access_token'] = $this->generateAccessToken();
      $fields['node'] = $node->id();
      $new_entity = $storage->create($fields);
      $new_entity->save();
    }

  }

  protected function getInviteMessagesData() {

    $data = [];

    $config = $this->configFactory->get('social_event_invite_flow.settings');

    /** @var \Drupal\node\Entity\Node $node */
    $node = $this->routeMatch->getParameter('node');

    if (isset($node) && !$node instanceof NodeInterface) {
      $storage = $this->entityTypeManager->getStorage('node');
      $node = $storage->loadByProperties(['node' => $node]);
    }    

    if ($node instanceof NodeInterface) {
      $storage = $this->entityTypeManager->getStorage('event_invite_message');
      $event_invite_messages = $storage->loadByProperties(['node' => $node->id()]);
      if ($event_invite_message = reset($event_invite_messages)) {
        $data = [
          'guests_invite_subject' => $event_invite_message->getGuestsInviteSubject(),
          'guests_invite_message' => $event_invite_message->getGuestsInviteMessage(),
          'new_accounts_invite_subject' => $event_invite_message->getNewAccountsInviteSubject(),
          'new_accounts_invite_message' => $event_invite_message->getNewAccountsInviteMessage(),
          'existing_accounts_invite_subject' => $event_invite_message->getExistingAccountsInviteSubject(),
          'existing_accounts_invite_message' => $event_invite_message->getExistingAccountsInviteMessage(),
        ];
      }
      else {
        $data = [
          'guests_invite_subject' => $config->get('guests_invite_subject'),
          'guests_invite_message' => $config->get('guests_invite_message'),
          'new_accounts_invite_subject' => $config->get('new_accounts_invite_subject'),
          'new_accounts_invite_message' => $config->get('new_accounts_invite_message'),
          'existing_accounts_invite_subject' => $config->get('existing_accounts_invite_subject'),
          'existing_accounts_invite_message' => $config->get('existing_accounts_invite_message'),
        ];
      }
    }    

    return $data;

  }

  public function getEventInviteMessageFormElements() {

    $elements = [
      'guests_invite_subject' => [
        'type' => 'textfield',
        'title' => $this->t('Subject for guests'),
        'required' => TRUE,
        'default_value' => $this->getInviteMessagesData()['guests_invite_subject']
      ],
      'guests_invite_message' => [
        'type' => 'text_format',
        'title' => $this->t('Message for guests'),
        'required' => TRUE,
        'default_value' => $this->getInviteMessagesData()['guests_invite_message']
      ],
      'new_accounts_invite_subject' => [
        'type' => 'textfield',
        'title' => $this->t('Subject for new accounts'),
        'required' => TRUE,
        'default_value' => $this->getInviteMessagesData()['new_accounts_invite_subject']        
      ],
      'new_accounts_invite_message' => [
        'type' => 'text_format',
        'title' => $this->t('Message for new accounts'),
        'required' => TRUE,
        'default_value' => $this->getInviteMessagesData()['new_accounts_invite_message']           
      ],
      'existing_accounts_invite_subject' => [
        'type' => 'textfield',
        'title' => $this->t('Subject for existing accounts'),
        'required' => TRUE,
        'default_value' => $this->getInviteMessagesData()['existing_accounts_invite_subject']            
      ],
      'existing_accounts_invite_message' => [
        'type' => 'text_format',
        'title' => $this->t('Message for existing accounts'),
        'required' => TRUE,
        'default_value' => $this->getInviteMessagesData()['existing_accounts_invite_message']            
      ],            
    ];   
    
    return $elements;

  }

  /**
   * Gets an event invite message based on 
   * the given route.
   */
  public function getEventInviteMessages() {

    $entity = FALSE;

    /** @var \Drupal\node\Entity\Node $node */
    $node = $this->routeMatch->getParameter('node');

    if (isset($node) && !$node instanceof NodeInterface) {
      $node = $this->entityTypeManager->getStorage('node')->load($node);
    } 
    
    if ($node instanceof NodeInterface) {

      $storage = $this->entityTypeManager->getStorage('event_invite_message');
      $event_invite_messages = $storage->loadByProperties(['node' => $node->id()]);

      if ($event_invite_message = reset($event_invite_messages)) {
        $entity = $event_invite_message;
      }

    }

    return $entity;

  }

  public function createEventInviteMessages(array $fields) {

    $entity = FALSE;

    $storage = $this->entityTypeManager->getStorage('event_invite_message');

    $storage->create($fields);
    $entity = $storage->save();

    return $entity;

  }

  public function getAllWebforms() {

    $webforms = [];

    // Get webforms
    $webform_ids = \Drupal::entityQuery('webform')
      ->accessCheck(TRUE)
      ->execute();    

 
    /** @var \Drupal\webform\Entity\Webform $webform */
    foreach ($webform_ids as $webform) {
      $storage = $this->entityTypeManager->getStorage('webform');
      $loaded_webform = $storage->load($webform);
      if ($loaded_webform instanceof WebformInterface) {
        $webform_machine_name = $loaded_webform->id();
        $webform_label = $loaded_webform->label();
        $webforms[$webform_machine_name] = $webform_label;
      }
    }

    return $webforms;

  }

  public function getWebformsExistingAccountsOptions() {

    $webforms = [];

    $social_event_invite_flow = $this->configFactory->get('social_event_invite_flow.settings');
    $webform_ids = $social_event_invite_flow->get('webforms_existing_accounts');


    /** @var \Drupal\webform\Entity\Webform $webform */
    foreach ($webform_ids as $webform) {
      $storage = $this->entityTypeManager->getStorage('webform');
      $loaded_webform = $storage->load($webform);
      if ($loaded_webform instanceof WebformInterface) {
        $webform_machine_name = $loaded_webform->id();
        $webform_label = $loaded_webform->label();
        $webforms[$webform_machine_name] = $webform_label;
      }
    }  

    return $webforms; 

  }

  public function getWebformsNewAccountsOptions() {

    $webforms = [];

    $social_event_invite_flow = $this->configFactory->get('social_event_invite_flow.settings');
    $webform_ids = $social_event_invite_flow->get('webforms_new_accounts');

    /** @var \Drupal\webform\Entity\Webform $webform */
    foreach ($webform_ids as $webform) {
      $storage = $this->entityTypeManager->getStorage('webform');
      $loaded_webform = $storage->load($webform);
      if ($loaded_webform instanceof WebformInterface) {
        $webform_machine_name = $loaded_webform->id();
        $webform_label = $loaded_webform->label();
        $webforms[$webform_machine_name] = $webform_label;
      }
    }  

    return $webforms; 

  } 

  public function getAvailableFields() {

    $node_field_definitions = [];
    $available_fields = []; 
    $node_bundles = [];
    $profile_bundles = []; 
    $user_bundles = ['user'];
    $forbidden_node_fields = [
      'type',
      'field_group_allowed_join_method',
      'field_group_allowed_visibility'
    ]; 
    $forbidden_profile_fields = [
      'type'
    ];
    $forbidden_user_fields = [
      'init',
      'name'
    ];

    $default_tokens = [
      '[node:title]' => '[node:title]',     
      '[current-user:display-name]' => '[current-user:display-name]',
      '[user:display-name]' => '[user:display-name]',
      '[site:name]' => '[site:name]'
    ];
      


    $available_node_fields = $this->getFields('node', ['event'], $forbidden_node_fields);
   

    // Get profile bundles
    $profile_bundles = $this->getBundle('profile');

    // Default Tokens for user profiles
    $default_tokens_user_profile = $this->getUserProfileBundleTokens($profile_bundles);

    if (isset($profile_bundles) && !empty($profile_bundles)) {

      $available_profile_fields = $this->getFields('profile',$profile_bundles,$forbidden_profile_fields);


    }

    $available_user_fields = $this->getFields('user',$user_bundles,$forbidden_user_fields);

    $available_fields = array_merge($default_tokens,
                                    $default_tokens_user_profile,
                                    $available_node_fields, 
                                    $available_profile_fields,
                                    $available_user_fields);


      
    // Get user field definitions
    
    return $available_fields;

  }

  protected function getUserProfileBundleTokens($profile_bundles) {

    $token_fields = [];

    foreach ($profile_bundles as $bundle_key => $bundle) {
      $token_fields['[user:' . $bundle_key .']'] = '[user:' . $bundle_key . ']';
    }

    return $token_fields;

  }

  protected function getFields(string $entity_type, array $bundles, array $forbidden_fields) {

    $field_definitions = [];
    $available_fields = [];  

    foreach ($bundles as $bundle_key => $bundle) {

      $field_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions($entity_type, $bundle_key);

      foreach ($field_definitions as $field_key => $field_value) {

        $field_token_key = strtolower($field_definitions[$field_key]->getName());
        $field_token_key = str_replace(' ','_',$field_token_key);
            
        if ($field_definitions[$field_key]->isRequired() && !in_array($field_key, $forbidden_fields)) {
          if ($entity_type == 'profile') {
            $available_fields['[user:' . $bundle_key . ':' . $field_token_key . ']'] = '[user:' . $bundle_key . ':' . $field_token_key . ']';
          }
          $available_fields['[' . $entity_type . ':' . $field_token_key . ']'] = '[' . $entity_type . ':' . $field_token_key . ']'; 
        }
            
      }

    }

    return $available_fields;

  }

  protected function getBundle($entity_type) {

    $bundles = \Drupal::service('entity_type.bundle.info')->getBundleInfo($entity_type);
    return $bundles;    

  } 

  public function getInviteModeExistingAccountsOptions() {
    return [
      EventInviteSettingsInterface::InviteModeExistingAccountsDefaultEnrollment => $this->t('Default Enrollment'),
      EventInviteSettingsInterface::InviteModeExistingAccountsWebformEnrollment => $this->t('Webform Enrollment')
    ];
  }

  public function getInviteModeNewAccountsOptions() {
    return [
      EventInviteSettingsInterface::InviteModeNewAccountsGuestEnrollment => $this->t('Guest Enrollment'),
      EventInviteSettingsInterface::InviteModeNewAccountsWebformEnrollment => $this->t('Webform Enrollment')
    ];
  }

  public function generateAccessToken() {

    $access_token = Crypt::randomBytesBase64();
    return $access_token;

  }

  protected function enrollmentExists($user, $nid) {

    $enrollment_exists = FALSE;

    $conditions = [
      'field_account' => $user->id(),
      'field_event' => $nid,
    ];

    $storage = $this->entityTypeManager->getStorage('event_enrollment');
    $event_enrollment = $storage->loadByProperties($conditions);
    if (!empty($event_enrollment)) {
      $enrollment_exists = TRUE;
    }

    return $enrollment_exists;

  }

  public function enrollmentExistsBySID($sid, $nid) {
    $enrollment = FALSE;

    $conditions = [
      'field_token' => $sid,
      'field_event' => $nid,
    ];

    $storage = $this->entityTypeManager->getStorage('event_enrollment');
    $event_enrollments = $storage->loadByProperties($conditions);
    if ($event_enrollment = reset($event_enrollments)) {
      $enrollment = $event_enrollment;
    }

    return $enrollment;

  }

  protected function enrollmentExistsByEmail($email, $nid) {

    $enrollment_exists = FALSE;

    $conditions = [
      'field_email' => $email,
      'field_event' => $nid,
    ];

    $storage = $this->entityTypeManager->getStorage('event_enrollment');
    $event_enrollment = $storage->loadByProperties($conditions);
    if (!empty($event_enrollment)) {
      $enrollment_exists = TRUE;
    }

    return $enrollment_exists;

  }

  public function enrollExistingAccount($user, $nid) {

    $invite_flow = FALSE;

    // First we need to know which flow we are using
    $storage = $this->entityTypeManager->getStorage('event_invite_settings');
    $event_invite_settings = $storage->loadByProperties(['node' => $nid]);
    if ($event_invite_setting = reset($event_invite_settings)) {
      $invite_flow = $event_invite_setting->getInviteModeExistingAccounts();
    }

    $event = $this->entityTypeManager->getStorage('node')->load($nid);
      
    if ($invite_flow === EventInviteSettingsInterface::InviteModeExistingAccountsDefaultEnrollment) {
      if (!$this->enrollmentExists($user, $nid)) {
        $fields = [
          //'name' => $user->getDisplayName() . ' @ ' . $event->getTitle(),
          'field_event' => $nid,
          'field_enrollment_status' => '1',
          'user_id' => $user->id(),
          'field_account' => $user->id(),
        ];
        $storage = $this->entityTypeManager->getStorage('event_enrollment');
        $new_enrollment = $storage->create($fields);
        $new_enrollment->save();
        $has_enrolled = $new_enrollment;

        // Send emails for enrolled users only
        if ($has_enrolled instanceof EventEnrollmentInterface) {
          $this->sendInviteEmails(
            EventInviteSettingsInterface::InviteModeExistingAccountsDefaultEnrollment,
            $user,
            $nid,
            $has_enrolled
          );
        }
      }
    }

    if ($invite_flow === EventInviteSettingsInterface::InviteModeExistingAccountsWebformEnrollment) {
      // Here we just send out the emails the rest will be done
      // by the webform.
      $this->sendInviteEmails(
        EventInviteSettingsInterface::InviteModeExistingAccountsWebformEnrollment,
        $user,
        $nid
      );
    }

  }

  public function enrollNewAccount($email, $nid) {

    $invite_flow = FALSE;
    $invite_access_token = FALSE;
    $enable_shareable_link = FALSE;
    
    $storage = $this->entityTypeManager->getStorage('event_invite_settings');
    $event_invite_settings = $storage->loadByProperties(['node' => $nid]);
    if ($event_invite_setting = reset($event_invite_settings)) {
      $invite_flow = $event_invite_setting->getInviteModeNewAccounts();
      $enable_shareable_link = $event_invite_setting->getEnableShareableLink();
      $invite_access_token = $event_invite_setting->getAccessToken();
    }

    $event = $this->entityTypeManager->getStorage('node')->load($nid);
    
    if ($invite_flow === EventInviteSettingsInterface::InviteModeNewAccountsGuestEnrollment) {

      if ($enable_shareable_link) {
        // Here we just send out the emails the rest will be done
        // by the user himself (Auto enrollment).
        $this->sendInviteEmails(
          EventInviteSettingsInterface::InviteModeNewAccountsGuestEnrollment,
          $email,
          $nid
        );
      }
      else {
        // Here we need to enroll the user first
        if(!$this->enrollmentExistsByEmail($email, $nid)) {

          $storage = $this->entityTypeManager->getStorage('event_enrollment');

          $generated_token = Crypt::randomBytesBase64();
          $fields = [
            //'name' => 'anonymous' . ' @ ' . $event->getTitle(),
            'field_request_or_invite_status' => EventEnrollmentInterface::INVITE_PENDING_REPLY,
            'field_event' => $nid,
            'field_enrollment_status' => '0',
            'field_email' => $email,
            'field_token' => $generated_token,
            'field_account' => 0,
            'user_id' => 0
          ];        
          $new_enrollment = $storage->create($fields);
          $new_enrollment->save();
          $has_enrolled = $new_enrollment; 
          if ($has_enrolled instanceof EventEnrollmentInterface) {
            $token = $has_enrolled->field_token->value;
          }
        }
        else {
          $existing_enrollments = $storage->loadByProperties([
            'field_event' => $nid,
            'field_email' => $email
          ]);
          if ($has_enrolled = reset($existing_enrollments)) {
            $token = $has_enrolled->field_token->value;
          }
        }  
        
        if ($token) {

          $this->sendInviteEmails(
            EventInviteSettingsInterface::InviteModeNewAccountsGuestEnrollment,
            $email,
            $nid,
            $has_enrolled,
            $token
          );
        }
      }
    }

    if ($invite_flow === EventInviteSettingsInterface::InviteModeNewAccountsWebformEnrollment) {

      $token = FALSE;
      $storage = $this->entityTypeManager->getStorage('event_enrollment');

      // Create guest enrollment and send emails with token
      if(!$this->enrollmentExistsByEmail($email, $nid)) {
        $generated_token = Crypt::randomBytesBase64();
        $fields = [
          //'name' => 'Anonymous' . ' @ ' . $event->getTitle(),         
          'field_event' => $nid,
          'field_enrollment_status' => '0',
          'field_email' => $email,
          'field_token' => $generated_token,
          'field_account' => 0,
          'user_id' => 0
        ];        
        $new_enrollment = $storage->create($fields);
        $new_enrollment->save();
        $has_enrolled = $new_enrollment; 
        if ($has_enrolled instanceof EventEnrollmentInterface) {
          $token = $has_enrolled->field_token->value;
        }
      }
      else {
        $existing_enrollments = $storage->loadByProperties([
          'field_event' => $nid,
          'field_token' => $token
        ]);
        if ($has_enrolled = reset($existing_enrollments)) {
          $token = $has_enrolled->field_token->value;
        }
      }

      if ($token) {

        $this->sendInviteEmails(
          EventInviteSettingsInterface::InviteModeNewAccountsWebformEnrollment,
          $email,
          $nid,
          $has_enrolled,
          $token
        );
      }
    }

    
  }

  public function convertEnrollRequestFormMessage(UserInterface $user, NodeInterface $node, $to_email, array $message) {

    $email_sent = FALSE;

    // Build token context
    $token_context = [];    

    $token_context['node'] = $node;

    $token_context['user'] = $user;

    $langcode = $user->getPreferredLangcode();

    $subject =  PlainTextOutput::renderFromHtml($this->token->replace($message['subject'], $token_context));
    $message = $this->token->replace($message['message'], $token_context);

    $context = [
      'subject' => $subject,
      'message' => $message,
    ];    

    // Sending Email
    $delivered = $this->mailManager->mail('system', 'action_send_email', $to_email, $langcode, ['context' => $context]);

    if ($delivered) {
      \Drupal::messenger()->addStatus($this->t('Message sent successfully!'));
    }

  }

  public function sendInviteEmails(string $invite_flow, $attendee, int $nid, $event_enrollment = NULL, $token = FALSE ) {

    $email_sent = FALSE;

    // Get event invite message for specific invite flow
    $event_invite_message = $this->getInviteMessageFromNid($nid, $invite_flow);


    // Load the node
    $node = $this->entityTypeManager->getStorage('node')->load($nid);

    // Build token context
    $token_context = [];

    if ($node instanceof NodeInterface) {
      $token_context['node'] = $node;
    }   
   
    if ($attendee instanceof UserInterface) {
      $user_mail = $attendee->getEmail();
      $token_context['user'] = $this->account;
      $langcode = $attendee->getPreferredLangcode();
    }
    else {
      $token_context['user'] = $this->account;
      $user_mail = $attendee;
      $langcode = $this->languageManager->getCurrentLanguage()->getId();
    }


    // Get our event settings
    $event_invite_setting = $this->getEventInviteSettings($nid);

    // Shareable link or not
    $enable_shareable_link = $event_invite_setting->getEnableShareableLink();
    
    $log_data['shareable_link'] = $enable_shareable_link;
    $log_data['invite_flow'] = $invite_flow;
    $log_data['invitee_email'] = $user_mail;
    $log_data['event'] = $node;

    if ($event_enrollment instanceof EventEnrollmentInterface) {
      $log_data['event_enrollment'] = $event_enrollment;
    }



    if (!$event_invite_message) {
      return;      
    }

    $subject =  PlainTextOutput::renderFromHtml($this->token->replace($event_invite_message['subject'], $token_context));
    $message = $this->token->replace($event_invite_message['message'], $token_context);
    // As we have our action buttons pre-defined we attach it here
    $action_links = [
      '#theme' => 'social_event_invite_flow__actions',
      '#links' => $this->getInviteActionsFromNid($nid, $invite_flow, $user_mail, $token),
    ];
    
    $actions = \Drupal::service('renderer')->render($action_links);

    $message  = Markup::create($message);
    // Attach actions to message
    $message .= $message . $actions;

    $reply_to = $event_invite_message['reply_to'];

    $context = [
      'subject' => $subject,
      'message' => $message,
    ];    

    // Sending Email
    $delivered = $this->mailManager->mail('system', 'action_send_email', $user_mail, $langcode, ['context' => $context], $reply_to);

    if ($delivered) {
      $email_sent = TRUE;
      // Log
      $this->createInviteFlowLogEntry('invitation_sent', $log_data);
    }

    return $email_sent;

  }

  protected function getInviteActionsFromNid(int $nid, string $invite_flow, string $email, $token = FALSE) {
    
    $links = [];

    // Get decoded invitee email 
    $invitee_email = $this->getEncodedEmailString($email);

    // Get our event settings
    $event_invite_setting = $this->getEventInviteSettings($nid);

    // Shareable link or not
    $enable_shareable_link = $event_invite_setting->getEnableShareableLink();

    // First we need to get our token      
    $access_token = $event_invite_setting->getAccessToken();    

    // Define link attributes
    $link_options = [
      'absolute' => TRUE,
      'attributes' => [
        'class' => [
          'btn-link', 'btn-link-bg', 'btn-link-one'
        ]
      ]
    ];

    // Get the site name from config
    $config = $this->configFactory->get('system.site');
    $site_name = $config->get('name');

    // Get site url
    $site_url = Url::fromRoute('<front>');
    $site_url->setOptions($link_options);
    $site_link_title = $this->t('About') . ' ' . $site_name; 
    $site_link = Link::fromTextAndUrl($site_link_title, $site_url);

    if ($invite_flow === EventInviteSettingsInterface::InviteModeExistingAccountsDefaultEnrollment) {
      // Add link to event
      if ($enable_shareable_link) {

        // For shareable links we do not want any button styling
        unset($link_options['attributes']['class']);
        
        $link_options['query'] = [
          'access_token' => $access_token,
          //'invitee' => $invitee_email
        ];

      }

      $event_url = Url::fromRoute('social_event_invite_flow.event_guest_access', ['node' => $nid]);
      $event_url->setOptions($link_options);

      if ($enable_shareable_link) {
        $event_link = Link::fromTextAndUrl($event_url->toString(), $event_url);
      }
      else {
        $event_link = Link::fromTextAndUrl($this->t('See event'), $event_url); 
      }

      $links['event'] = $event_link->toRenderable();

    }

    if ($invite_flow === EventInviteSettingsInterface::InviteModeNewAccountsGuestEnrollment) {


      // Add link to event
      $event_url = Url::fromRoute('social_event_invite_flow.event_guest_access', ['node' => $nid]);


      if ($enable_shareable_link) {

        // Attach the access token to the url
        $link_options['query'] = [
          'access_token' => $access_token,
          //'invitee' => $invitee_email
        ];         

      }
      else {
        if (isset($token)) {

          $link_options['query'] = [
            'token' => $token,
            'invitee' => $invitee_email
          ];
          
        }
      }

      $event_url->setOptions($link_options);     
      $event_link = Link::fromTextAndUrl($this->t('See event'), $event_url);
      $links['event'] = $event_link->toRenderable();
    }

    if ($invite_flow === EventInviteSettingsInterface::InviteModeExistingAccountsWebformEnrollment) {
      // First we need to get the webfrom
      $webform_id = $event_invite_setting->getSelectedWebformExistingAccounts();
      // Add link to event
      $event_url = Url::fromRoute('entity.webform.canonical', ['webform' => $webform_id]);
      // Add query parameter event
      $link_options['query'] = [
        'event' => $nid,
        'webform_redirect' => '/node/' . $nid . '/join',
      ];
      $event_url->setOptions($link_options); 
      $event_link = Link::fromTextAndUrl($this->t('See event'), $event_url);
      $links['event'] = $event_link->toRenderable();
    }

    if ($invite_flow === EventInviteSettingsInterface::InviteModeNewAccountsWebformEnrollment) {
      // First we need to get the webfrom
      $webform_id = $event_invite_setting->getSelectedWebformNewAccounts();
      $event_url = Url::fromRoute('entity.webform.canonical', ['webform' => $webform_id]);
      // Add query parameter webform_redirect
      $link_options['query'] = [
        'webform_redirect' => '/node/' . $nid,
        'token' => $token        
      ];
      $event_url->setOptions($link_options);
      $event_link = Link::fromTextAndUrl($this->t('See event'), $event_url);
      $links['event'] = $event_link->toRenderable();
    }

    // Always add the site link 
    //$links['site'] = $site_link->toRenderable();

    return $links;

  }

  public function getDecodedEmailString(string $invitee_email) {
    return base64_decode(str_replace(['-', '_'], ['+', '/'], $invitee_email));
  }

  protected function getEncodedEmailString($email) {

    $invitee_email = base64_encode($email);
    return $invitee_email;

  }
  
  protected function getInviteMessageFromNid(int $nid, string $invite_flow) {

    $config = $this->configFactory->get('social_event_invite_flow.settings');

    $message_data = [];

    $message_data['reply_to'] = NULL;

    $storage = $this->entityTypeManager->getStorage('event_invite_message');
    $event_invite_messages = $storage->loadByProperties(['node' => $nid]);

    if ($entity = reset($event_invite_messages)) {
      $event_invite_message = $entity;
      $data = [
        'reply_to' => $event_invite_message->getReplyTo(),
        'guests_invite_subject' => $event_invite_message->getGuestsInviteSubject(),
        'guests_invite_message' => $event_invite_message->getGuestsInviteMessage()['value'],
        'new_accounts_invite_subject' => $event_invite_message->getNewAccountsInviteSubject(),
        'new_accounts_invite_message' => $event_invite_message->getNewAccountsInviteMessage()['value'],
        'existing_accounts_invite_subject' => $event_invite_message->getExistingAccountsInviteSubject(),
        'existing_accounts_invite_message' => $event_invite_message->getExistingAccountsInviteMessage()['value'],
      ];
    }
    else {
      $data = [
        'reply_to' => $config->get('reply_to'),
        'guests_invite_subject' => $config->get('guests_invite_subject'),
        'guests_invite_message' => $config->get('guests_invite_message'),
        'new_accounts_invite_subject' => $config->get('new_accounts_invite_subject'),
        'new_accounts_invite_message' => $config->get('new_accounts_invite_message'),
        'existing_accounts_invite_subject' => $config->get('existing_accounts_invite_subject'),
        'existing_accounts_invite_message' => $config->get('existing_accounts_invite_message'),
      ];
    }
   
 
    // We need to check the invite_flow to get proper message
    if ($invite_flow === EventInviteSettingsInterface::InviteModeExistingAccountsDefaultEnrollment ||
        $invite_flow === EventInviteSettingsInterface::InviteModeExistingAccountsWebformEnrollment) {
      $message_data['subject'] = $data['existing_accounts_invite_subject'];
      $message_data['message'] = $data['existing_accounts_invite_message'];
    }
    elseif ($invite_flow === EventInviteSettingsInterface::InviteModeNewAccountsGuestEnrollment) {
      $message_data['subject'] = $data['guests_invite_subject'];
      $message_data['message'] = $data['guests_invite_message'];
    }
    elseif ($invite_flow === EventInviteSettingsInterface::InviteModeNewAccountsWebformEnrollment) {
      $message_data['subject'] = $data['new_accounts_invite_subject'];
      $message_data['message'] = $data['new_accounts_invite_message'];
    }

    if (empty($message_data)) {
      return FALSE;
    }

    // Get Reply to email or use site mail
    $reply_to = $data['reply_to'];
    if (!empty($reply_to)) {
      $message_data['reply_to'] = $reply_to;
    }
  
    return $message_data;

  }

  public function addFieldTokens(array &$form) {

    $tokens = [
      'node_title' => '[node:title]',     
      'current_user_display_name' => '[current-user:display-name]',
      'user_display_name' => '[user:display-name]',
      'site_name' => '[site:name]'
    ];    

    $form['tokens'] = [
      '#type' => 'fieldset',
      '#title' => $this->t('Available Tokens'),
      '#collapsed' => TRUE,
      '#collapsible' => TRUE  
    ];

    foreach($tokens as $key => $token) {
      $key_value = "'" . $key . "'";
      $link = '<a class="btn btn-sm btn-default" onclick="myFunction(' . $key_value . ')">Copy</a>';

      $form['tokens'][$key]['container'] = [
        '#type' => 'container',
        '#attributes' => ['class' => ['invite--flow']],
      ];

      $form['tokens'][$key]['container']['text'] = [
        '#attributes' => ['id' => $key],
        '#type' => 'textfield',
        '#value' =>  $token,
      ];
      $form['tokens'][$key]['container']['link'] = [
        '#markup' => Markup::Create($link),
        '#prefix' => '<div>',
        '#suffix' => '</div>'
      ];
    }

  }

  protected function getPseudoEmail() {
    $sid = $this->getSessionIDForUnauthenticatedUsers();
    $host = \Drupal::request()->getHost();
    $email = $sid . '@' . $host;
    return $email;    
  }

  protected function getEventEnrollmentTitleFromEventNode($nid) {
    $node = $this->entityTypeManager->getStorage('node')->load($nid);
    $event_enrollment_name = 'Anonymous' . ' @ ' . $node->getTitle();
    return $event_enrollment_name;
  }

  public function enrollGuestInEvent($nid, $name) {

    $enrolled = FALSE;

    $storage = $this->entityTypeManager->getStorage('event_enrollment');

    // Get Session ID for anon. user
    $sid = $this->getSessionIDForUnauthenticatedUsers();
    // Get our pseudo email for anon. user
    $email = $this->getPseudoEmail();

    // Create enrollment
    if(!$this->enrollmentExistsByEmail($email, $nid)) {
      $fields = [
        //'name' => $this->getEventEnrollmentTitleFromEventNode($nid),
        'field_event' => $nid,
        'field_enrollment_status' => '1',
        'field_request_or_invite_status' => EventEnrollmentInterface::INVITE_ACCEPTED_AND_JOINED,      
        'field_email' => $email,
        'field_first_name' => $name,
        'field_token' => $this->generateAccessToken(),
        'field_account' => 0,
        //'user_id' => 0
      ];        
      $new_enrollment = $storage->create($fields);
      $new_enrollment->save();
      $enrolled = $new_enrollment;     
    }

    return $enrolled;

  }

  public function enrollGuestInEventWithEmail($nid, $name, $email) {

    $enrollment = FALSE;

    $conditions = [
      'field_email' => $email,
      'field_event' => $nid,
    ];

    $storage = $this->entityTypeManager->getStorage('event_enrollment');
    $event_enrollments = $storage->loadByProperties($conditions);
    if ($event_enrollment = reset($event_enrollments)) {
      $enrollment = $event_enrollment;
    }

    // We are already enrolled and need to set the enrolled status
    if ($enrollment) {
      $enrollment->field_first_name->value = $name;
      $enrollment->field_enrollment_status->value = 1;
      $enrollment->field_request_or_invite_status->value = EventEnrollmentInterface::INVITE_ACCEPTED_AND_JOINED;    
      $enrollment->save();
    }
    
    return $enrollment;

  }  

  public function validateEnrollAsGuestInEvent($email, $nid) {


  }

  /**
   * Check if an authenticated user has enrolled
   *
   * @param integer $nid
   *   The node id.
   * 
   * @return bool $enrolled
   *   TRUE | FALSE
   */
  public function checkIfAuthenticatedUserHasEnrolled(int $nid) {

    $enrolled = FALSE;

    $user = $this->account;
    $uid = $user->id();

    $conditions = [
      'field_account' => $uid,
      'field_event' => $nid,
    ];

    $storage = $this->entityTypeManager->getStorage('event_enrollment');
    $event_enrollments = $storage->loadByProperties($conditions);

    if ($event_enrollment = reset($event_enrollments)) {
      $enrolled = TRUE;
    }

    return $enrolled;


  }

  /**
   * Check if an un-authenticated user has enrolled
   *
   * @param integer $nid
   *   The node id.
   * 
   * @return bool $enrolled
   *   TRUE | FALSE
   */
  public function checkIfUnauthenticatedUserHasEnrolled(int $nid, $email) {

    $enrolled = FALSE;

    $conditions = [
      'field_email' => $email,
      'field_event' => $nid,
    ];

    $storage = $this->entityTypeManager->getStorage('event_enrollment');
    $event_enrollments = $storage->loadByProperties($conditions);

    if ($event_enrollment = reset($event_enrollments)) {
      $enrolled = TRUE;
    }

    return $enrolled;


  }

  /**
   * Check if the enetered email belongs to an authenticated user
   *
   * @param integer $nid
   *   The node id.
   * 
   * @return bool $enrolled
   *   TRUE | FALSE
   */
  public function checkIfEmailHasAccount($email) {

    $user = user_load_by_mail($email);
    return $user;

  }  

  public function isEventShareable(int $nid) {

    $enable_shareable_link = FALSE;

    // First we need to know which flow we are using
    $storage = $this->entityTypeManager->getStorage('event_invite_settings');
    $event_invite_settings = $storage->loadByProperties(['node' => $nid]);
    if ($event_invite_setting = reset($event_invite_settings)) {
      $enable_shareable_link = $event_invite_setting->getEnableShareableLink();
    }

    return $enable_shareable_link;

  }

  /**
   * Creates and returns a unique identifier for unauthenticated users.
   *  
   * @return string $session_key
   *   Unique session key.
   */
  public function getSessionIDForUnauthenticatedUsers() {
    // Define session.
    $session = \Drupal::request()->getSession();
    // Check if we have already an unique identifier saved into session
    if (!$session->has('core.tempstore.private.owner')) {
     // This generates a unique identifier for the user
     $session->set('core.tempstore.private.owner', Crypt::randomBytesBase64());
    }
    
    $session_key = $session->get('core.tempstore.private.owner');
  
    return $session_key;
  
  }  

  public function isHideEnrollButtonPossible() {

    $hide = FALSE;
    $current_user = $this->account;

    if ($current_user->isAnonymous()) {
      $hide = TRUE;
    }
    else {

      $user_roles = $current_user->getRoles();

      foreach ($user_roles as $role) {
        if ($role === 'administrator' || 
            $role === 'contentmanager' || 
            $role === 'sitemanager') {
          
          $hide = FALSE;

        }
        else {
          $hide = TRUE;
        }
      }
    }

    return $hide;



  }

  public function enrollmentExistsByToken($token, $nid) {

    $enrollment = FALSE;

    $conditions = [
      'field_token' => $token,
      'field_event' => $nid,
    ];

    $storage = $this->entityTypeManager->getStorage('event_enrollment');
    $event_enrollments = $storage->loadByProperties($conditions);
    if ($event_enrollment = reset($event_enrollments)) {
      if ($event_enrollment instanceof EventEnrollmentInterface) {
        if ($event_enrollment->field_enrollment_status->value == 1) {
          $enrollment = $event_enrollment;
        }
      }
    }

    return $enrollment;

  }

  /**
   * Get an account from uid
   *
   * @param integer $uid
   * @return UserInterface or FALSE
   */
  public function getAccountFromUserId(int $uid) {
    $account = $this->entityTypeManager->getStorage('user')->load($uid);
    return $account;
  }


/**
 * Create Invite Flow Log
 *
 * @param [type] $invite_flow
 * @param [type] $invitee_email
 * @param [type] $event
 * @param boolean $invitee_joined
 * @param boolean $shareable_link
 * @param [type] $event_enrollment
 * @return void
 */
  public function createInviteFlowLogEntry($action, array $data) {

    $current_time = \Drupal::time()->getCurrentTime();
    
    if ($data['event'] instanceof NodeInterface) {
      $event_id = $data['event']->id();
    }
    else {
      $event_id = $data['event'];
    }

    $conditions = [
      'invitee_email' => $data['invitee_email'],
      'event' => $event_id,
    ];

    $storage = $this->entityTypeManager->getStorage('event_invite_flow_log');
    $event_invite_flow_logs = $storage->loadByProperties($conditions);

    if ($event_invite_flow_log = reset($event_invite_flow_logs)) {

      if ($event_invite_flow_log instanceof EventInviteFlowLogInterface) {

        $event_invite_flow_log->setInviteFlow($data['invite_flow']);
        $event_invite_flow_log->setShareableLink($data['shareable_link']);
        $event_invite_flow_log->setInviteeEmail($data['invitee_email']);
        $event_invite_flow_log->setEvent($data['event']);

        // Log when the message has been sent out.
        if ($action === 'invitation_sent') {
          $event_invite_flow_log->setInvitationSent($current_time);
          $event_invite_flow_log->setHasInvitationSent(TRUE);
        }

        // If there is an event enrollment put it into the log
        if ($data['event_enrollment'] instanceof EventEnrollmentInterface) {
          $event_invite_flow_log->setEventEnrollment($data['event_enrollment']); 
          $event_invite_flow_log->setInviteeEnrolled($current_time);  
          $event_invite_flow_log->setHasInviteeEnrolled(TRUE);              
        }

        // If the invitee has joined
        if ($action === 'joined') {
          $event_invite_flow_log->setInviteeJoined($current_time);
          $event_invite_flow_log->setHasInviteeJoined(TRUE);
        }

        $event_invite_flow_log->save();

      }


    }
    else {


      if ($action === 'invitation_sent') {
        $data['invitation_sent'] = $current_time;  
        $data['has_invitation_sent'] = TRUE;  
      }

      // If there is an event enrollment put it into the log
      if ($data['event_enrollment'] instanceof EventEnrollmentInterface) {
        $data['event_enrollment'] = $data['event_enrollment']->id();
        $data['invitee_enrolled'] = $current_time; 
        $data['has_invitee_enrolled'] = TRUE;       
      }

      // If the invitee has joined
      if ($action === 'joined') {
        $data['invitee_joined'] = $current_time;  
        $data['has_invitee_joined'] = TRUE;  
      }

      // Create new log entry
      $new_event_invite_log = $storage->create($data);
      $new_event_invite_log->save();

    }



  }

  public function deleteInviteLogRecord($conditions) {

    $storage = $this->entityTypeManager->getStorage('event_invite_flow_log');
    $event_invite_flow_logs = $storage->loadByProperties($conditions); 

    if ($event_invite_flow_log = reset($event_invite_flow_logs)) {
      if ($event_invite_flow_log instanceof EventInviteFlowLogInterface) {
        \Drupal::logger('debug')->debug('Delete!!!');
        $event_invite_flow_log->delete();
      }
    }
  }

}

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

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