You are here

opigno_messaging.module in Opigno messaging 8

Same filename and directory in other branches
  1. 3.x opigno_messaging.module

File

opigno_messaging.module
View source
<?php

/**
 * @file
 * Contains opigno_messaging.module.
 */
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\group\Entity\Group;
use Drupal\opigno_class\Form\SocialSettingsForm;
use Drupal\opigno_messaging\OpignoMessageThread;
use Drupal\private_message\Entity\PrivateMessageThread;
use Drupal\private_message\Mapper\PrivateMessageMapper;
use Drupal\user\Entity\User;
use Drupal\views\Plugin\views\query\QueryPluginBase;
use Drupal\views\ViewExecutable;

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

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

/**
 * Implements hook_theme().
 */
function opigno_messaging_theme() {
  return [
    'opigno_messaging' => [
      'render element' => 'children',
    ],
  ];
}

/**
 * Implements hook_form_alter().
 */
function opigno_messaging_form_private_message_add_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $thread_members = $form_state
    ->get('thread_members');

  // Only add the select if we are in the context
  // of a new message (not in a tread context).
  if (!isset($thread_members)) {
    $current_user = \Drupal::currentUser();
    $uid = $current_user
      ->id();
    $current_user = User::load($uid);

    // Add the subject.
    $form['subject'] = [
      '#type' => 'textfield',
      '#title' => t('Subject'),
      '#placeholder' => t('Enter a subject'),
      '#default_value' => "",
      '#size' => 60,
      '#maxlength' => 128,
      '#required' => FALSE,
      '#weight' => -3,
    ];

    // Hide the default messaging to field.
    $form['members']['#type'] = 'hidden';
    $plugin_service = \Drupal::service('opigno_learning_path.members.manager');
    $plugin_instance = $plugin_service
      ->createInstance('recipients_plugin');
    $plugin_instance
      ->getMembersForm($form, $form_state, $current_user);
    unset($form['message']['widget']['#title']);
    unset($form['message']['widget'][0]['#title']);
    $form['message']['widget']['#placeholder'] = t('your message');
    $form['actions']['submit']['#value'] = t('Send');

    // Validation function so we can move the values of the users_to_send
    // to the default messaging module field.
    $form['#validate'][] = 'opigno_messaging_private_message_add_form_validate_replace_to';
  }

  // Remove default & set custom submit handler.
  $form['#submit'] = [
    'opigno_messaging_private_message_add_form_submit',
  ];
  $form['actions']['submit']['#submit'] = [
    'opigno_messaging_private_message_add_form_submit',
  ];
  $form['actions']['submit']['#value'] = t('Send');
  $route_name = \Drupal::routeMatch()
    ->getRouteName();
  if ($route_name == 'private_message.private_message_page') {

    // Save current thread id in form storage.
    // For "private_messages" page (not PM thread page).
    $user = \Drupal::currentUser();
    $db_connection = \Drupal::service('database');
    $pm_mapper = new PrivateMessageMapper($db_connection, $user);
    $user = User::load($user
      ->id());
    $thread_id = $pm_mapper
      ->getFirstThreadIdForUser($user);
    $form_state
      ->set('thread_id', $thread_id);
  }
}

/**
 * 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();
  $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',
      //      'learning_path-content_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);
}

/**
 * For validation.
 *
 * Sets the values of the default messaging "to" field with the
 * values of our multiselect.
 */
function opigno_messaging_private_message_add_form_validate_replace_to(&$form, FormStateInterface $form_state) {
  $selected_users = $form_state
    ->getValue('users_to_send');
  $selected_members = $form_state
    ->getValue('members');

  // The select member should be empty at this point,
  // fill it with the users to send.
  $i = 0;
  foreach ($selected_users as $selected_user) {
    $selected_members[$i]['target_id'] = $selected_user;
    $selected_members[$i]['_weight'] = $i;
    $i++;
  }

  // Update the form state with the values we want.
  $form_state
    ->setValue('members', $selected_members);

  // Send error message if fields are empty.
  $message = $form_state
    ->getValue('message');
  if (empty($selected_members['0']['target_id'])) {
    $form_state
      ->setErrorByName('members', t("Please select user for sending message!"));
  }
  if (empty($message[0]['value'])) {
    $form_state
      ->setErrorByName('message', t("Please enter a message!"));
  }
}

/**
 * Add private message form custom submit handler.
 */
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();
  $current_user = \Drupal::currentUser();

  /** @var \Drupal\user\UserDataInterface $user_data */
  $user_data = \Drupal::service('user.data');
  $pm_config = \Drupal::config('private_message.settings');

  /** @var \Drupal\private_message\Service\PrivateMessageServiceInterface $pm_service */
  $pm_service = \Drupal::service('private_message.service');
  $form_state
    ->cleanValues();

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

  /** @var \Drupal\user\UserInterface[] $members */
  $members = $form_state
    ->get('thread_members');
  if (!$members) {

    // Generate an array containing the members of the thread.
    $members = [
      $current_user,
    ];
    foreach ($form_state
      ->getValue('members') as $info) {
      $user = User::load($info['target_id']);
      if ($user) {
        $members[] = $user;
      }
    }
  }
  $subject = $form_state
    ->getValue('subject');

  // If subject is set, create new thread.
  if ($subject) {
    $private_message_thread = PrivateMessageThread::create();
    foreach ($members as $member) {
      $private_message_thread
        ->addMember($member);
    }
    $private_message_thread
      ->set('field_pm_subject', $subject);
    $private_message_thread
      ->save();
  }
  else {

    // Try get thread from path.
    $parameters = \Drupal::routeMatch()
      ->getParameters();
    $private_message_thread = $parameters
      ->get('private_message_thread');
    if ($private_message_thread === NULL) {
      $storage = $form_state
        ->getStorage();
      if (isset($storage['thread_id'])) {

        // Get current thread for "private_messages" page (not PM thread page).
        $private_message_thread = PrivateMessageThread::load($storage['thread_id']);
      }
      else {
        $private_message_thread = $pm_service
          ->getThreadForMembers($members);
      }
    }
  }

  // Add the new message to the thread and save.

  /** @var \Drupal\private_message\Entity\PrivateMessageThreadInterface $private_message_thread */
  $private_message_thread
    ->addMessage($entity);
  $private_message_thread
    ->save();
  $mailManager = \Drupal::service('plugin.manager.mail');
  $params = [
    'private_message' => $entity,
    'private_message_thread' => $private_message_thread,
  ];
  $config_factory = \Drupal::configFactory();
  $message_notification_mail_map = $config_factory
    ->getEditable('private_message.mail')
    ->get('message_notification');
  $site_name = \Drupal::config('system.site')
    ->get('name');
  $params['subject'] = str_replace('[site:name]', $site_name, $message_notification_mail_map['subject']);
  if ($members) {
    $db_connection = \Drupal::service('database');
    $thread_url = $private_message_thread
      ->toUrl();
    $thread_url
      ->setOption('absolute', TRUE);
    $thread_url = Link::fromTextAndUrl($thread_url
      ->toString(), $thread_url)
      ->toString();
    $delta = 0;

    // Send email notifications for members.
    foreach ($members as $member) {
      if ($member
        ->id() != $current_user
        ->id()) {
        $params['member'] = $member;
        $send = $user_data
          ->get('private_message', $member
          ->id(), 'email_notification');
        $send = is_numeric($send) ? (bool) $send : $pm_config
          ->get('enable_email_notifications') && $pm_config
          ->get('send_by_default');
        if ($send) {
          $user_name = $member
            ->getDisplayName();
          $author_name = $entity
            ->getOwner()
            ->getDisplayName();
          $message = $entity
            ->getMessage();
          $params['message'] = str_replace([
            '[site:name]',
            '[user:display-name]',
            '[private_message:author-name]',
            '[private_message:message]',
            '[private_message_thread:url]',
          ], [
            '<strong>' . $site_name . '</strong>',
            '<strong>' . $user_name . '</strong>',
            '<strong>' . $author_name . '</strong>',
            '<strong>' . $message . '</strong>',
            '<strong>' . $thread_url . '</strong>',
          ], $message_notification_mail_map['body']);
          $mailManager
            ->mail('opigno_messaging', 'message_notification', $member
            ->getEmail(), $member
            ->getPreferredLangcode(), $params);
        }
      }
      $query = $db_connection
        ->select('pm_thread_delete_time', 'pmtdt');
      $query
        ->join('private_message_thread__last_delete_time', 'pmtldt', 'pmtldt.last_delete_time_target_id = pmtdt.id');
      $query
        ->fields('pmtdt', [
        'id',
      ]);
      $query
        ->condition('pmtldt.entity_id', $private_message_thread
        ->id());
      $query
        ->condition('pmtdt.owner', $member
        ->id());
      $member_last_delete_time = $query
        ->execute()
        ->fetchField();

      // Restore delete time for users who have deleted thread.
      if (!$member_last_delete_time) {
        try {
          $db_connection
            ->insert('pm_thread_delete_time')
            ->fields([
            'uuid' => \Drupal::service('uuid')
              ->generate(),
            'owner' => $member
              ->id(),
            'delete_time' => 0,
          ])
            ->execute();
        } catch (Exception $e) {
          \Drupal::logger('opigno_messaging')
            ->error($e
            ->getMessage());
        }
        if (empty($e)) {
          $query = $db_connection
            ->select('pm_thread_delete_time', 'pmtdt');
          $query
            ->fields('pmtdt', [
            'id',
          ]);
          $query
            ->condition('pmtdt.owner', $member
            ->id());
          $query
            ->orderBy('id', 'DESC');
          $query
            ->range(0, 1);
          $member_last_delete_time = $query
            ->execute()
            ->fetchField();
          if ($member_last_delete_time) {
            try {
              $db_connection
                ->insert('private_message_thread__last_delete_time')
                ->fields([
                'bundle' => 'private_message_thread',
                'deleted' => 0,
                'entity_id' => $private_message_thread
                  ->id(),
                'revision_id' => $private_message_thread
                  ->id(),
                'langcode' => 'und',
                'delta' => $delta,
                'last_delete_time_target_id' => $member_last_delete_time,
              ])
                ->execute();
            } catch (Exception $e) {
              \Drupal::logger('opigno_messaging')
                ->error($e
                ->getMessage());
            }
            if (empty($e)) {
              $delta++;
            }
          }
        }
      }
    }

    // Update delete time thread with a new message for members (set to 0).
    $delete_times = $private_message_thread
      ->getLastDeleteTimes();
    if ($delete_times) {
      $delete_times = array_map(function ($delete_time) {
        return $delete_time
          ->id();
      }, $delete_times);
      try {
        $db_connection
          ->update('pm_thread_delete_time')
          ->fields([
          'delete_time' => 0,
        ])
          ->condition('id', $delete_times, 'IN')
          ->execute();
      } catch (Exception $e) {
        \Drupal::logger('opigno_messaging')
          ->error($e
          ->getMessage());
      }
    }
  }

  // Send the user to the private message page. As this thread is the newest,
  // it wll be at the top of the list.
  $form_state
    ->setRedirect('entity.private_message_thread.canonical', [
    'private_message_thread' => $private_message_thread
      ->id(),
  ]);
}

/**
 * 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_messaging/view_private_message';
    $vars['#attached']['drupalSettings']['multiLingual'] = \Drupal::languageManager()
      ->isMultilingual();
  }
}

/**
 * Implements hook_preprocess_views_view_field().
 *
 * Sets class for unread message thread.
 */
function opigno_messaging_preprocess_views_view_field(&$variables) {
  if ($variables['view']
    ->id() == 'private_message') {
    $ids =& drupal_static(__FUNCTION__);
    $variables['unread_class'] = '';
    if (!isset($ids)) {
      $ids = OpignoMessageThread::getUnreadThreadCount('entity_id');
    }
    if ($ids && in_array($variables['row']->id, $ids)) {

      // Set class for unread message thread.
      $variables['unread_class'] = 'new';
    }
  }
}

/**
 * Implements hook_views_query_alter().
 */
function opigno_messaging_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
  if ($view
    ->id() == 'private_message') {
    static $threads;
    if (!isset($threads)) {

      // Get all message treads of current user.
      $uid = \Drupal::currentUser()
        ->id();
      $threads = OpignoMessageThread::getUserThreads($uid);
      if ($threads) {

        // Get threads delete/access time
        // for whenever deleted threads of current user.
        $db_connection = \Drupal::service('database');
        $query_thread = $db_connection
          ->select('pm_thread_delete_time', 'tdt');
        $query_thread
          ->join('private_message_thread__last_delete_time', 'ldt', 'ldt.last_delete_time_target_id = tdt.id');
        $query_thread
          ->join('private_message_thread__last_access_time', 'tlat', 'tlat.entity_id = ldt.entity_id');
        $query_thread
          ->join('pm_thread_access_time', 'tat', 'tat.id = tlat.last_access_time_target_id AND tat.owner = :uid', [
          ':uid' => $uid,
        ]);
        $query_thread
          ->fields('ldt', [
          'entity_id',
        ])
          ->condition('tdt.owner', $uid)
          ->condition('tdt.delete_time', 0, '>')
          ->condition('tdt.delete_time', 'tat.access_time', '>');
        $deleted_threads = $query_thread
          ->execute()
          ->fetchCol();
        if ($deleted_threads) {

          // Remove deleted threads from threads array.
          $threads = array_diff($threads, $deleted_threads);
        }
      }
    }
    if ($threads) {

      // Add allowed threads to query.
      $query
        ->addWhere('', 'private_message_threads.id', $threads, 'IN');
    }
    else {
      $query
        ->addWhere('', 'private_message_threads.id', [
        0,
      ], 'IN');
    }
  }
}

/**
 * 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']);
}

Functions

Namesort descending Description
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_views_view Implements hook_preprocess_views_view().
opigno_messaging_preprocess_views_view_field Implements hook_preprocess_views_view_field().
opigno_messaging_private_message_add_form_submit Add private message form custom submit handler.
opigno_messaging_private_message_add_form_validate_replace_to For validation.
opigno_messaging_private_message_thread_view_alter Implements hook_ENTITY_TYPE_view_alter().
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_query_alter Implements hook_views_query_alter().