View source
<?php
namespace Drupal\opigno_learning_path;
use Drupal\Component\Utility\Html;
use Drupal\Core\Database\Database;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\group\Entity\Group;
use Drupal\group\Entity\GroupInterface;
use Drupal\opigno_group_manager\Entity\OpignoGroupManagedContent;
use Drupal\opigno_group_manager\OpignoGroupContext;
use Drupal\user\Entity\User;
use Drupal\opigno_learning_path\Entity\LPManagedContent;
use Drupal\opigno_module\Entity\OpignoModule;
class LearningPathAccess {
public static function getGroupRoles(Group $group) {
$type = array_shift($group->type
->getValue());
$properties = [
'group_type' => $type['target_id'],
'permissions_ui' => TRUE,
];
return \Drupal::entityTypeManager()
->getStorage('group_role')
->loadByProperties($properties);
}
public static function setVisibilityFields(Group &$group) {
if ($visibility = $group->field_learning_path_visibility->value) {
switch ($visibility) {
case 'public':
$group
->set('field_anonymous_visibility', 0);
$group
->set('field_requires_validation', 0);
break;
case 'private':
$group
->set('field_anonymous_visibility', 1);
$group
->set('field_requires_validation', 1);
break;
}
}
}
public static function getGroupContentAccess(EntityInterface $entity, AccountInterface $account) {
$access = TRUE;
$contentID = OpignoGroupContext::getCurrentGroupContentId();
if (!empty($contentID)) {
$contents = OpignoGroupManagedContent::loadByProperties([
'id' => $contentID,
]);
if ($contents = array_shift($contents)) {
$learningPath = $contents
->getGroup();
if (isset($learningPath) && $learningPath
->getEntityTypeId() === 'learning_path' && !$learningPath
->access('view', $account)) {
$access = FALSE;
}
}
}
return $access;
}
public static function requiredValidation(Group $group, $account = FALSE) {
if (!$account) {
$account = \Drupal::currentUser();
}
$validation = FALSE;
if ($group
->get('field_requires_validation')->value && !$account
->hasPermission('bypass group validation requirement')) {
$validation = TRUE;
}
return $validation;
}
public static function statusGroupValidation(Group $group, AccountInterface $account) {
$access = TRUE;
if ($membership = $group
->getMember($account)) {
$visibility = $group->field_learning_path_visibility->value;
$validation = LearningPathAccess::requiredValidation($group, $account);
$status = LearningPathAccess::getMembershipStatus($membership
->getGroupContent()
->id());
$required_trainings = self::hasUncompletedRequiredTrainings($group, $account);
if ($visibility === 'semiprivate' && $validation) {
if ($status != 1) {
$access = FALSE;
}
}
elseif ($required_trainings) {
$access = FALSE;
}
else {
if ($status == 3) {
$access = FALSE;
}
}
if (!self::triggerHookAccess('status_group_validation_access', $group, $account)) {
$access = FALSE;
}
}
return $access;
}
public static function checkStepValidation($step, $uid) {
$account = User::load($uid);
switch ($step['typology']) {
case 'Course':
$group = Group::load($step['id']);
return self::triggerHookAccess('status_course_validation_access', $group, $account);
break;
case 'Module':
$module = OpignoModule::load($step['id']);
return self::triggerHookAccess('status_module_validation_access', $module, $account);
break;
}
return TRUE;
}
public static function triggerHookAccess($hook_name, $entity, $account) {
$access = TRUE;
$access_results = \Drupal::moduleHandler()
->invokeAll($hook_name, [
$entity,
$account,
]);
if (is_array($access_results)) {
$access_results = array_filter($access_results, function ($var) {
return empty($var);
});
if (!empty($access_results)) {
$access = FALSE;
}
}
return $access;
}
public static function membershipPreSave(EntityInterface &$membership) {
if ($membership
->isNew()) {
$group = $membership
->getGroup();
$group_is_semiprivate = $group
->hasField('field_learning_path_visibility') && $group
->get('field_learning_path_visibility')
->getValue() === 'semiprivate';
$group_requires_validation = $group
->hasField('field_requires_validation') && $group
->get('field_requires_validation')
->getValue();
$user_join = $membership
->getEntity()
->id() == $membership
->getOwnerId();
if (!($group_is_semiprivate && $group_requires_validation) && $user_join) {
$roles = $membership
->get('group_roles')
->getValue();
if (!in_array('learning_path-student', $roles)) {
$roles[] = 'learning_path-student';
$membership
->set('group_roles', $roles);
}
}
}
LearningPathAccess::setLearningPathCourseMember($membership, 'update');
}
public static function setLearningPathCourseMember(EntityInterface $membership, $mode) {
$group = $membership
->getGroup();
$courses = LPManagedContent::loadByProperties([
'learning_path_id' => $group
->id(),
'lp_content_type_id' => 'ContentTypeCourse',
]);
if ($courses) {
foreach ($courses as $course) {
$group = Group::load($course->entity_id->value);
$account = $membership
->getEntity();
if ($group
->getMember($account) && $mode == 'delete') {
LearningPathAccess::deleteUserStatus($group
->getMember($account)
->getGroupContent());
$group
->removeMember($account);
}
if ($mode == 'update') {
if (!$group
->getMember($account)) {
$group
->addMember($account);
}
LearningPathAccess::mergeUserStatus($group
->getMember($account)
->getGroupContent());
}
}
}
}
public static function getMembershipStatusesArray() {
return [
'1' => t('Active'),
'2' => t('Pending'),
'3' => t('Blocked'),
];
}
public static function getMembershipStatus($mid, $as_string = FALSE) {
$query = \Drupal::database()
->select('opigno_learning_path_group_user_status', 'us')
->fields('us', [
'status',
])
->condition('mid', $mid);
$result = $query
->execute()
->fetchField();
if ($as_string && $result != FALSE) {
$statuses = LearningPathAccess::getMembershipStatusesArray();
$result = $statuses[$result];
}
return $result;
}
public static function getUserMemberEvents() {
return [
'1' => 'subscribed',
'2' => 'approval',
'3' => 'blocked',
];
}
public static function mergeUserStatus(EntityInterface $membership) {
$message = \Drupal::request()
->get('user_message');
$message = !empty($message) ? Html::escape($message) : '';
$group = $membership
->getGroup();
$uid = $membership
->getEntity()
->id();
$gid = $group
->id();
$visibility = $group->field_learning_path_visibility->value;
$validation = LearningPathAccess::requiredValidation($group);
$is_new = $membership
->isNew();
$user_join = $membership
->getEntity()
->id() == $membership
->getOwnerId();
if ($is_new && $user_join) {
$status = in_array($visibility, [
'semiprivate',
'private',
]) && $validation ? 2 : 1;
}
elseif (!empty($_SESSION['opigno_learning_path_group_membership_edit']['user_status'])) {
$status = $_SESSION['opigno_learning_path_group_membership_edit']['user_status'];
unset($_SESSION['opigno_learning_path_group_membership_edit']);
}
else {
$status = 1;
}
$query = \Drupal::database()
->merge('opigno_learning_path_group_user_status')
->key('mid', $membership
->id())
->insertFields([
'mid' => $membership
->id(),
'uid' => $uid,
'gid' => $gid,
'status' => $status,
'message' => $message,
])
->updateFields([
'uid' => $uid,
'gid' => $gid,
'status' => $status,
'message' => $message,
]);
$result = $query
->execute();
if ($result) {
if ($group
->bundle() === 'learning_path') {
$token = \Drupal::moduleHandler()
->moduleExists('token') ? TRUE : FALSE;
LearningPathAccess::notifyUsersByMail($group, $uid, $status, $token);
if ($membership
->isNew() && $membership
->getEntity()
->id() == $membership
->getOwnerId()) {
$messenger = \Drupal::messenger();
if ($status == 2) {
$messenger
->addMessage(t('Thanks ! The subscription to that training requires the validation of an administrator or a teacher.
You will receive an email as soon as your subscription has been validated.'));
}
}
}
}
}
public static function deleteUserStatus(EntityInterface $membership) {
$query = \Drupal::database()
->delete('opigno_learning_path_group_user_status')
->condition('mid', $membership
->id());
$result = $query
->execute();
if ($result) {
$entity = $membership
->getEntity();
$group = $membership
->getGroup();
if (isset($entity) && isset($group) && $group
->bundle() == 'learning_path') {
$uid = $entity
->id();
$token = \Drupal::moduleHandler()
->moduleExists('token');
LearningPathAccess::notifyUsersByMail($group, $uid, NULL, $token);
}
}
}
public static function notifyUsersByMail(Group $group, $uid, $status, $token = FALSE) {
$user = \Drupal::currentUser();
$config = \Drupal::config('opigno_learning_path.learning_path_settings');
$send_to_admins = $config
->get('opigno_learning_path_notify_admin');
$send_to_users = $config
->get('opigno_learning_path_notify_users');
if ($send_to_admins || $send_to_users) {
$account = User::load($uid);
$events = LearningPathAccess::getUserMemberEvents();
$subject = \Drupal::config('system.site')
->get('name') . ' ' . t('subscription');
$host = \Drupal::request()
->getSchemeAndHttpHost();
if ($status) {
$membership = $group
->getMember($account);
$statusName = LearningPathAccess::getMembershipStatus($membership
->getGroupContent()
->id(), TRUE);
$roles = $membership
->getRoles();
$roles_array = [];
if (!empty($roles)) {
foreach ($roles as $role) {
$roles_array[] = $role
->label();
}
}
}
else {
$status = 1;
$statusName = t('Unsubscribed');
}
$roles = !empty($roles_array) ? implode(', ', $roles_array) : '';
if ($send_to_admins) {
$mails = $config
->get('opigno_learning_path_notify_admin_mails');
if (!empty($mails)) {
$message = $config
->get('opigno_learning_path_notify_admin_user_' . $events[$status]);
$params = [
'group' => $group,
'account' => $account,
'link' => $host . '/group/' . $group
->id() . '/members',
'roles' => $roles,
'status' => $statusName,
];
LearningPathAccess::replaceGroupUserTokens($message, $params, $token);
$mails = explode("\r\n", $mails);
foreach ($mails as $to) {
if (!empty($to) && !empty($message)) {
LearningPathAccess::sendMail($to, $subject, $message, $params);
}
}
}
}
$send = FALSE;
$send_message = \Drupal::request()
->get('send_message');
if (empty($send_message)) {
$route_name = \DRUPAL::routeMatch()
->getRouteName();
if ($route_name != 'entity.group_content.add_form') {
$send = $send_to_users && $uid !== $user
->id();
}
}
if ($send) {
$to = $account
->getEmail();
$message = $config
->get('opigno_learning_path_notify_user_user_' . $events[$status]);
$params = [
'group' => $group,
'account' => $account,
'link' => $host . '/group/' . $group
->id(),
'roles' => $roles,
'status' => $statusName,
];
LearningPathAccess::replaceGroupUserTokens($message, $params, $token);
if (!empty($to) && !empty($message)) {
LearningPathAccess::sendMail($to, $subject, $message, $params);
}
}
}
}
public static function replaceGroupUserTokens(&$text, $params, $token) {
if ($token) {
$text = \Drupal::token()
->replace($text);
}
$text = str_replace([
'[user]',
'[group]',
'[link]',
'[user-role]',
'[user-status]',
], [
$params['account']
->getAccountName(),
$params['group']
->label(),
$params['link'],
$params['roles'],
$params['status'],
], $text);
}
public static function sendMail($to, $subject, $message, $params = []) {
$langcode = \Drupal::currentUser()
->getPreferredLangcode();
$mailManager = \Drupal::service('plugin.manager.mail');
$module = 'opigno_learning_path';
$key = 'opigno_learning_path_user_subscribe';
$params['subject'] = $subject;
$params['message'] = $message;
$send = TRUE;
$result = $mailManager
->mail($module, $key, $to, $langcode, $params, NULL, $send);
return $result['result'];
}
public static function createUserStatusTable() {
$schema = Database::getConnection()
->schema();
if (!$schema
->tableExists('opigno_learning_path_group_user_status')) {
$spec = [
'description' => 'Learning Path group user statuses',
'fields' => [
'id' => [
'type' => 'serial',
'not null' => TRUE,
],
'mid' => [
'description' => 'Membership ID',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
],
'uid' => [
'description' => 'User ID',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
],
'gid' => [
'description' => 'Group ID',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
],
'status' => [
'description' => 'Member status',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
],
'message' => [
'description' => 'User message',
'type' => 'varchar',
'length' => 200,
'not null' => TRUE,
'default' => '',
],
],
'primary key' => [
'id',
],
'indexes' => [
'mid' => [
'mid',
],
'gid' => [
'gid',
],
'uid' => [
'uid',
],
],
'foreign keys' => [
'group_content' => [
'mid' => 'id',
],
'users' => [
'uid' => 'uid',
],
'groups' => [
'gid' => 'id',
],
],
];
$schema
->createTable('opigno_learning_path_group_user_status', $spec);
}
}
public static function hasUncompletedRequiredTrainings(GroupInterface $group, AccountInterface $account) {
$trainings = $group
->get('field_required_trainings')
->getValue();
if (!$trainings) {
return FALSE;
}
$database = \Drupal::database();
$uncompleted = [];
if (is_array($trainings)) {
for ($i = 0; $i < count($trainings); $i++) {
$gid = $trainings[$i]['target_id'];
$is_completed = $database
->select('opigno_learning_path_achievements', 'a')
->fields('a')
->condition('uid', $account
->id())
->condition('gid', $gid)
->condition('status', 'completed')
->execute()
->fetchObject();
if (!$is_completed) {
array_push($uncompleted, $gid);
}
}
}
return $uncompleted;
}
public static function checkCourseClassAccess(Group $group, AccountInterface $account) {
$access = FALSE;
$type = $group
->getGroupType()
->id();
if ($type == 'opigno_class') {
$is_member = $group
->getMember($account);
$access = $is_member ? TRUE : FALSE;
}
elseif ($type == 'opigno_course') {
$database = Database::getConnection();
$query = $database
->select('opigno_group_content', 'ogc');
$query
->leftJoin('group_content_field_data', 'gc', 'ogc.group_id = gc.gid');
$results = $query
->fields('ogc', [
'group_id',
])
->condition('ogc.entity_id', $group
->id())
->condition('ogc.group_content_type_id', 'ContentTypeCourse')
->condition('gc.type', 'learning_path-group_membership')
->condition('gc.entity_id', $account
->id())
->execute()
->fetchAll();
$access = $results ? TRUE : FALSE;
if (!self::triggerHookAccess('status_course_validation_access', $group, $account)) {
$access = FALSE;
}
}
return $access;
}
public static function memberHasRole($role, AccountInterface $account, $gid = NULL) {
$role = "learning_path-{$role}";
$connection = Database::getConnection();
$query = $connection
->select('group_content_field_data', 'g_c_f_d')
->fields('g_c_f_d', [
'gid',
]);
$query
->leftJoin('group_content__group_roles', 'g_c_g_r', 'g_c_f_d.id = g_c_g_r.entity_id');
$query
->condition('g_c_g_r.group_roles_target_id', $role);
$query
->condition('g_c_f_d.entity_id', $account
->id());
$query
->condition('g_c_f_d.type', 'learning_path-group_membership');
if (!empty($gid)) {
$query
->condition('g_c_f_d.gid', $gid);
}
$lp_counts = $query
->countQuery()
->execute()
->fetchField();
return $lp_counts > 0;
}
}