You are here

opigno_messaging.module in Opigno messaging 3.x

Same filename and directory in other branches
  1. 8 opigno_messaging.module

File

opigno_messaging.module
View source
<?php

/**
 * @file
 * Contains opigno_messaging.module.
 */
use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Image\ImageInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\group\Entity\Group;
use Drupal\opigno_class\Form\SocialSettingsForm;
use Drupal\opigno_messaging\Form\PrivateMessageForm;
use Drupal\opigno_messaging\Form\PrivateMessageThreadDeleteForm;
use Drupal\opigno_messaging\Services\OpignoMessageThread;
use Drupal\private_message\Entity\PrivateMessageInterface;
use Drupal\private_message\Entity\PrivateMessageThreadInterface;
use Drupal\user\Entity\User;

/**
 * Implements hook_help().
 */
function opigno_messaging_help($route_name, RouteMatchInterface $route_match) {

  // Main module help for the opigno_messaging module.
  if ($route_name === 'help.page.opigno_messaging') {
    $output = '<h3>' . t('About') . '</h3>';
    $output .= '<p>' . t('Opigno app for messaging') . '</p>';
    return $output;
  }
}

/**
 * Implements hook_theme().
 */
function opigno_messaging_theme() {
  return [
    'opigno_messaging' => [
      'render element' => 'children',
    ],
    'opigno_messaging_modal' => [
      'variables' => [
        'title' => NULL,
        'body' => NULL,
      ],
    ],
    'opigno_messaging_confirmation' => [
      'variables' => [
        'body' => NULL,
      ],
    ],
    'opigno_pm_thread_actions' => [
      'variables' => [
        'actions' => NULL,
      ],
    ],
  ];
}

/**
 * Implements hook_form_alter().
 */
function opigno_messaging_form_private_message_add_form_alter(&$form, FormStateInterface $form_state, $form_id) {

  // Remove default & set custom submit handler.
  $form['actions']['submit']['#submit'][] = 'opigno_messaging_private_message_add_form_submit';
}

/**
 * Helper function to get users for group.
 *
 * @param int $group_id
 *   Group.
 *
 * @return \Drupal\user\UserInterface[]
 *   User ID.
 */
function opigno_messaging_get_user_for_group($group_id = NULL, $show_all = FALSE) {
  if ($group_id === NULL || $group_id === 0) {
    return opigno_messaging_get_all_recipients($show_all);
  }
  $users = [];
  $group = Group::load($group_id);
  $members = $group
    ->getMembers();
  $current_user = \Drupal::currentUser();
  if ($show_all) {
    if ($members) {
      $users = array_map(function ($member) {

        /** @var \Drupal\group\GroupMembership $member */
        return $member
          ->getUser();
      }, $members);
      $users = array_filter($users, function ($user) {

        /** @var \Drupal\user\UserInterface $user */
        return $user
          ->id() > 0 && $user
          ->isActive();
      });
    }
    return $users;
  }
  $member = $group
    ->getMember($current_user);
  $member_roles = $member
    ->getRoles();
  if (opigno_messaging_user_is_manager($member_roles)) {
    $users = array_map(function ($member) {

      /** @var \Drupal\group\GroupMembership $member */
      return $member
        ->getUser();
    }, $members);
    $users = array_filter($users, function ($user) {

      /** @var \Drupal\user\UserInterface $user */
      return $user
        ->id() > 0 && $user
        ->isActive();
    });
  }
  else {
    $owner = $group
      ->getOwner();
    foreach ($members as $member) {
      $member_roles = $member
        ->getRoles();
      if (opigno_messaging_social_sharing($group) || opigno_messaging_user_is_manager($member_roles) || $member
        ->getUser()
        ->id() == $owner
        ->id()) {
        if ($member
          ->getUser()
          ->isActive()) {
          $users[] = $member
            ->getUser();
        }
      }
    }
  }
  return $users;
}

/**
 * Check socials sharing settings.
 *
 * @param \Drupal\Core\Entity\EntityInterface $group
 *
 * @return bool
 *   Social sharing is allowed.
 */
function opigno_messaging_social_sharing($group) {
  $social_config = \Drupal::config('opigno_class.socialsettings')
    ->get('social');
  return $social_config & SocialSettingsForm::SAME_CLASS && $group
    ->getGroupType()
    ->id() == 'opigno_class' || $social_config & SocialSettingsForm::SAME_TRAINING && $group
    ->getGroupType()
    ->id() == 'learning_path' || $social_config === SocialSettingsForm::ALL_USERS;
}

/**
 * Checks the member roles is an manager.
 *
 * @param \Drupal\group\GroupMembership[] $member_roles
 *   Group member roles.
 *
 * @return bool
 *   User membership is manager.
 */
function opigno_messaging_user_is_manager($member_roles) {
  return count(array_intersect(array_keys($member_roles), [
    'learning_path-user_manager',
    'opigno_class-class_manager',
  ])) > 0;
}

/**
 * Helper function to get all users that current user can message to.
 */
function opigno_messaging_get_all_users() {
  $current_user = \Drupal::currentUser();
  if ($current_user
    ->hasPermission('message anyone regardless of groups')) {
    return array_filter(User::loadMultiple(), function ($user) {

      /** @var \Drupal\user\UserInterface $user */
      return $user
        ->id() > 0;
    });
  }
  $users = [];
  $groups = opigno_messaging_get_groups('opigno_class') + opigno_messaging_get_groups('learning_path');

  /** @var \Drupal\group\Entity\GroupInterface $group */
  foreach ($groups as $group_info) {
    $group = Group::load($group_info['entity_id']);
    $members = $group
      ->getMembers();
    foreach ($members as $member) {
      $user = $member
        ->getUser();
      if ($user) {
        $users[$user
          ->id()] = $member
          ->getUser();
      }
    }
  }
  unset($users[0]);
  return array_values($users);
}

/**
 * Helper function to get list of all users that current user can message to.
 */
function opigno_messaging_get_all_recipients($show_all) {
  $current_user = \Drupal::currentUser();
  if ($current_user
    ->isAnonymous()) {
    return [];
  }
  $social_config = \Drupal::config('opigno_class.socialsettings')
    ->get('social');
  if ($social_config == SocialSettingsForm::ALL_USERS || $show_all) {
    return array_filter(User::loadMultiple(), function ($user) {

      /** @var \Drupal\user\UserInterface $user */
      return $user
        ->id() > 0 && $user
        ->isActive();
    });
  }
  else {
    $users = [];

    // Get all users with roles 'user manager' or 'content manager' or 'administrator'.
    $global_managers_roles = [
      'user_manager',
      'content_manager',
      'administrator',
    ];
    $global_managers_ids = \Drupal::entityQuery('user')
      ->condition('status', 1)
      ->condition('roles', $global_managers_roles, 'IN')
      ->execute();
    $users = array_merge($users, $global_managers_ids);

    // Get users with group roles 'student manager' or 'content manager' in which the current user is a member.

    /* @var \Drupal\group\GroupMembershipLoaderInterface $membership_service */
    $membership_service = \Drupal::service('group.membership_loader');

    /* @var \Drupal\group\GroupMembership[] $memberships */
    $memberships = $membership_service
      ->loadByUser($current_user);
    foreach ($memberships as $membership) {
      $group = $membership
        ->getGroup();
      $members = $group
        ->getMembers();
      $owner = $group
        ->getOwner();
      foreach ($members as $member) {
        $member_roles = $member
          ->getRoles();
        if (opigno_messaging_social_sharing($group) || opigno_messaging_user_is_manager($member_roles) || $member
          ->getUser()
          ->id() == $owner
          ->id()) {
          $users[] = $member
            ->getUser()
            ->id();
        }
      }
    }

    // Get members from groups and classes where current user is a 'class manager' in a class,
    // 'student manager' or 'content manager' in a group.
    $memberships = $membership_service
      ->loadByUser($current_user, [
      'learning_path-user_manager',
      'opigno_class-class_manager',
    ]);
    foreach ($memberships as $membership) {
      $group = $membership
        ->getGroup();
      $members = $group
        ->getMembers();
      foreach ($members as $member) {
        $users[] = $member
          ->getUser()
          ->id();
      }
    }
  }
  $users = User::loadMultiple($users);
  return array_values($users);
}

/**
 * Helper function to get all groups that current user can message to.
 */
function opigno_messaging_get_groups($group_type) {
  $current_user = \Drupal::currentUser();
  $groups = \Drupal::entityTypeManager()
    ->getStorage('group')
    ->loadByProperties([
    'type' => $group_type,
  ]);
  if (!$current_user
    ->hasPermission('message all groups')) {
    $groups = array_filter($groups, function ($group) use ($current_user) {

      /** @var \Drupal\group\Entity\GroupInterface $group */
      return $group
        ->getMember($current_user) !== FALSE;
    });
  }
  return array_map(function ($group) {

    /** @var \Drupal\group\Entity\Group $group */
    return [
      'entity_id' => $group
        ->id(),
      'title' => $group
        ->label(),
    ];
  }, $groups);
}

/**
 * Add private message form custom submit handler.
 *
 * @param array $form
 *   The PM creation form.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   The form state object.
 */
function opigno_messaging_private_message_add_form_submit(array $form, FormStateInterface $form_state) {

  /** @var \Drupal\Core\Entity\ContentEntityFormInterface $form_obj */
  $form_obj = $form_state
    ->getFormObject();

  /** @var \Drupal\opigno_messaging\Services\OpignoMessageThread $pm_service */
  $pm_service = \Drupal::service('opigno_messaging.manager');
  $form_state
    ->cleanValues();

  /** @var \Drupal\private_message\Entity\PrivateMessageInterface $entity */
  $entity = $form_obj
    ->buildEntity($form, $form_state);

  // Get the thread and send the email to all participants.
  try {
    $private_message_thread = \Drupal::entityTypeManager()
      ->getStorage('private_message_thread')
      ->loadByProperties([
      'private_messages' => $entity
        ->id(),
    ]);
    if ($private_message_thread instanceof PrivateMessageThreadInterface) {
      $pm_service
        ->sendEmailToThreadMembers($private_message_thread, $entity);
    }
  } catch (PluginNotFoundException|InvalidPluginDefinitionException $e) {
    watchdog_exception('opigno_messaging_exception', $e);
  }
}

/**
 * Implements hook_mail().
 */
function opigno_messaging_mail($key, &$message, $params) {
  if ($key == 'message_notification') {
    $message['from'] = \Drupal::config('system.site')
      ->get('name');
    $message['subject'] = $params['subject'];
    $message['body'][] = $params['message'];
  }
}

/**
 * Implements hook_ENTITY_TYPE_view_alter().
 *
 * Changes 'last_message' view mode to 'thread_preview'
 * if 'private_message_thread' view mode is 'preview'.
 *
 * @see private_message_private_message_thread_view()
 */
function opigno_messaging_private_message_thread_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) {
  if (isset($build['last_message']) && $build['#view_mode'] === 'preview') {

    /** @var \Drupal\private_message\Entity\PrivateMessageThreadInterface $entity */
    $messages = $entity
      ->getMessages();
    $last_message = array_pop($messages);
    $view_builder = \Drupal::entityTypeManager()
      ->getViewBuilder('private_message');
    $build['last_message'] = $view_builder
      ->view($last_message, 'thread_preview');
  }
}

/**
 * Implements hook_preprocess_views_view().
 */
function opigno_messaging_preprocess_views_view(&$vars) {

  // Attach js & css to view.
  if (isset($vars['view_array']['#name']) && $vars['view_array']['#name'] === 'private_message') {
    $vars['#attached']['library'][] = 'opigno_learning_path/opigno_autocomplite_multiselect';
    $vars['#attached']['drupalSettings']['multiLingual'] = \Drupal::languageManager()
      ->isMultilingual();
  }
}

/**
 * Implements hook_menu_local_actions_alter().
 */
function opigno_messaging_menu_local_actions_alter(&$local_actions) {

  // Remove default 'Create private message' button.
  unset($local_actions['private_message.private_message_add']);
}

/**
 * Implements hook_entity_extra_field_info().
 */
function opigno_messaging_entity_extra_field_info() {
  $extra = [];

  // Message thread image.
  $extra['private_message_thread']['private_message_thread']['display']['thread_picture'] = [
    'label' => t('Opigno messages thread picture'),
    'description' => t('Provides the PM thread picture.'),
    'weight' => 0,
  ];

  // Message thread title.
  $extra['private_message_thread']['private_message_thread']['display']['thread_title'] = [
    'label' => t('Opigno messages thread title'),
    'description' => t('Provides the PM thread title.'),
    'weight' => 0,
  ];

  // Message thread formatted date.
  $extra['private_message_thread']['private_message_thread']['display']['thread_formatted_date'] = [
    'label' => t('Opigno messages thread formatted date'),
    'description' => t('Provides the PM thread formatted date.'),
    'weight' => 0,
  ];

  // Message thread displayed text.
  $extra['private_message_thread']['private_message_thread']['display']['thread_text'] = [
    'label' => t('Opigno messages thread text'),
    'description' => t('Provides the PM thread text (last message cropped text OR the last message author).'),
    'weight' => 0,
  ];

  // Message thread options.
  $extra['private_message_thread']['private_message_thread']['display']['thread_actions'] = [
    'label' => t('Opigno messages thread actions'),
    'description' => t('Provides the PM thread actions dropdown.'),
    'weight' => 0,
    'visible' => FALSE,
  ];

  // Message thread unread messages count.
  $extra['private_message_thread']['private_message_thread']['display']['thread_unread_count'] = [
    'label' => t('Opigno unread messages count'),
    'description' => t('Provides the amount of unread messages in the PM thread.'),
    'weight' => 0,
    'visible' => FALSE,
  ];

  // Private message formatted date.
  $extra['private_message']['private_message']['display']['opigno_date'] = [
    'label' => t('Opigno message formatted date'),
    'description' => t('Provides the PM formatted date'),
    'weight' => 0,
    'visible' => FALSE,
  ];
  return $extra;
}

/**
 * Implements hook_ENTITY_TYPE_view().
 */
function opigno_messaging_private_message_thread_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
  if (!$entity instanceof PrivateMessageThreadInterface) {
    return;
  }
  $messages_service = \Drupal::service('opigno_messaging.manager');
  if (!$messages_service instanceof OpignoMessageThread) {
    return;
  }
  $data = $messages_service
    ->getThreadDisplayData($entity);
  $build['thread_picture'] = $data['image'] ?? '';
  $build['thread_title'] = [
    '#markup' => $data['title'] ?? '',
  ];
  $build['thread_formatted_date'] = [
    '#markup' => $data['date'] ?? '',
  ];
  $build['thread_text'] = [
    '#markup' => $data['text'] ?? '',
  ];
  $build['thread_unread_count'] = [
    '#markup' => $data['unread_count'] ?? 0,
  ];
  $build['thread_actions'] = $messages_service
    ->getThreadActions($entity);
}

/**
 * Implements hook_ENTITY_TYPE_view().
 */
function opigno_messaging_private_message_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
  if (!$entity instanceof PrivateMessageInterface) {
    return;
  }
  $messages_service = \Drupal::service('opigno_messaging.manager');
  if ($messages_service instanceof OpignoMessageThread) {
    $build['opigno_date'] = [
      '#markup' => $messages_service
        ->getMessageFormattedDate($entity),
    ];
  }
}

/**
 * Implements hook_views_data_alter().
 */
function opigno_messaging_views_data_alter(array &$data) {

  // The filter by the private messages thread name.
  $data['private_message_threads']['opigno_pm_thread_name'] = [
    'filter' => [
      'title' => t('Opigno private message user/group name'),
      'help' => t('Provides a custom filter for the private message threads user/group name.'),
      'real field' => 'id',
      'id' => 'opigno_pm_thread_name',
    ],
  ];

  // The filter by the current user discussions.
  $data['private_message_threads']['opigno_pm_thread_ids'] = [
    'filter' => [
      'title' => t('Opigno available private message threads'),
      'help' => t('Provides a custom filter to limit the query to the available user message threads.'),
      'real field' => 'id',
      'id' => 'opigno_available_thread_ids',
    ],
  ];

  // Custom sort plugin to display the current thread at the top.
  $data['private_message_threads']['current_thread_first'] = [
    'title' => t('Opigno display the current thread at the top'),
    'group' => t('Opigno messaging'),
    'help' => t('Display the current thread at the top, then others.'),
    'sort' => [
      'field' => 'updated',
      'id' => 'current_thread_first',
    ],
  ];
}

/**
 * Implements hook_preprocess_HOOK().
 */
function opigno_messaging_preprocess_image_widget(&$variables) {

  // Display the image preview for image widget.
  $element = $variables['element'];
  $variables['attributes'] = [
    'class' => [
      'image-widget',
      'js-form-managed-file',
      'form-managed-file',
      'clearfix',
    ],
  ];
  if (!empty($element['fids']['#value'])) {
    $file = reset($element['#files']);
    $file_variables = [
      'style_name' => $element['#preview_image_style'],
      'uri' => $file
        ->getFileUri(),
    ];

    // Determine image dimensions.
    if (isset($element['#value']['width']) && isset($element['#value']['height'])) {
      $file_variables['width'] = $element['#value']['width'];
      $file_variables['height'] = $element['#value']['height'];
    }
    else {
      $image = \Drupal::service('image.factory')
        ->get($file
        ->getFileUri());
      if ($image instanceof ImageInterface && $image
        ->isValid()) {
        $file_variables['width'] = $image
          ->getWidth();
        $file_variables['height'] = $image
          ->getHeight();
      }
      else {
        $file_variables['width'] = $file_variables['height'] = NULL;
      }
    }
    $element['preview'] = [
      '#weight' => -10,
      '#theme' => 'image_style',
      '#width' => $file_variables['width'],
      '#height' => $file_variables['height'],
      '#style_name' => $file_variables['style_name'],
      '#uri' => $file_variables['uri'],
    ];

    // Store the dimensions in the form so the file doesn't have to be accessed
    // again. This is important for remote files.
    $element['width'] = [
      '#type' => 'hidden',
      '#value' => $file_variables['width'],
    ];
    $element['height'] = [
      '#type' => 'hidden',
      '#value' => $file_variables['height'],
    ];
  }
  $variables['data'] = [];
  foreach (Element::children($element) as $child) {
    $variables['data'][$child] = $element[$child];
  }
}

/**
 * Implements hook_entity_type_alter().
 */
function opigno_messaging_entity_type_alter(array &$entity_types) {

  // Override the delete form for thread.
  $entity_types['private_message_thread']
    ->setHandlerClass('form', [
    'delete' => PrivateMessageThreadDeleteForm::class,
  ]);

  // Override the default add message form.
  $entity_types['private_message']
    ->setHandlerClass('form', [
    'add' => PrivateMessageForm::class,
  ]);
}

/**
 * Implements hook_preprocess_HOOK().
 */
function opigno_messaging_preprocess_private_message_thread__full(&$variables) {
  $thread = $variables['private_message_thread'] ?? NULL;
  if ($thread instanceof PrivateMessageThreadInterface && $thread
    ->get('private_messages')
    ->isEmpty()) {

    // Add the extra wrapper to display the 1st message without the page reload.
    $variables['content']['private_messages']['#prefix'] .= '<div class="private-message-wrapper"></div>';
  }

  // Update the field suffix to be create an anchor to scroll to.
  $suffix = $variables['content']['private_messages']['#suffix'] ?? '';
  $variables['content']['private_messages']['#suffix'] = '<div class="opigno-messages-scroll-target"></div>' . $suffix;
}

Functions

Namesort descending Description
opigno_messaging_entity_extra_field_info Implements hook_entity_extra_field_info().
opigno_messaging_entity_type_alter Implements hook_entity_type_alter().
opigno_messaging_form_private_message_add_form_alter Implements hook_form_alter().
opigno_messaging_get_all_recipients Helper function to get list of all users that current user can message to.
opigno_messaging_get_all_users Helper function to get all users that current user can message to.
opigno_messaging_get_groups Helper function to get all groups that current user can message to.
opigno_messaging_get_user_for_group Helper function to get users for group.
opigno_messaging_help Implements hook_help().
opigno_messaging_mail Implements hook_mail().
opigno_messaging_menu_local_actions_alter Implements hook_menu_local_actions_alter().
opigno_messaging_preprocess_image_widget Implements hook_preprocess_HOOK().
opigno_messaging_preprocess_private_message_thread__full Implements hook_preprocess_HOOK().
opigno_messaging_preprocess_views_view Implements hook_preprocess_views_view().
opigno_messaging_private_message_add_form_submit Add private message form custom submit handler.
opigno_messaging_private_message_thread_view Implements hook_ENTITY_TYPE_view().
opigno_messaging_private_message_thread_view_alter Implements hook_ENTITY_TYPE_view_alter().
opigno_messaging_private_message_view Implements hook_ENTITY_TYPE_view().
opigno_messaging_social_sharing Check socials sharing settings.
opigno_messaging_theme Implements hook_theme().
opigno_messaging_user_is_manager Checks the member roles is an manager.
opigno_messaging_views_data_alter Implements hook_views_data_alter().