Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 401 and 402] [Versions 401 and 403]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  /**
  17   * The mod_bigbluebuttonbn roles helper
  18   *
  19   * @package   mod_bigbluebuttonbn
  20   * @copyright 2021 onwards, Blindside Networks Inc
  21   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22   * @author    Laurent David  (laurent [at] call-learning [dt] fr)
  23   */
  24  
  25  namespace mod_bigbluebuttonbn\local\helpers;
  26  
  27  use cache;
  28  use cache_store;
  29  use context;
  30  use context_course;
  31  use mod_bigbluebuttonbn\instance;
  32  use mod_bigbluebuttonbn\local\proxy\bigbluebutton_proxy;
  33  use stdClass;
  34  
  35  /**
  36   * Utility class for all roles routines helper
  37   *
  38   * @package mod_bigbluebuttonbn
  39   * @copyright 2021 onwards, Blindside Networks Inc
  40   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  41   */
  42  class roles {
  43  
  44      /** @var int The bigbluebutton viewer role */
  45      public const ROLE_VIEWER = 'viewer';
  46  
  47      /** @var string The bigbluebutton moderator role */
  48      public const ROLE_MODERATOR = 'moderator';
  49  
  50      /**
  51       * Returns user roles in a context.
  52       *
  53       * @param context $context
  54       * @param int $userid
  55       *
  56       * @return array $userroles
  57       */
  58      public static function get_user_roles(context $context, int $userid) {
  59          global $DB;
  60          $userroles = get_user_roles($context, $userid);
  61          if ($userroles) {
  62              $where = '';
  63              foreach ($userroles as $userrole) {
  64                  $where .= (empty($where) ? ' WHERE' : ' OR') . ' id=' . $userrole->roleid;
  65              }
  66              $userroles = $DB->get_records_sql('SELECT * FROM {role}' . $where);
  67          }
  68          return $userroles;
  69      }
  70  
  71      /**
  72       * Returns guest role wrapped in an array.
  73       *
  74       * @return array
  75       */
  76      protected static function get_guest_role() {
  77          $guestrole = get_guest_role();
  78          return [$guestrole->id => $guestrole];
  79      }
  80  
  81      /**
  82       * Returns an array containing all the users in a context wrapped for html select element.
  83       *
  84       * @param context_course $context
  85       * @param null $bbactivity
  86       * @return array $users
  87       */
  88      public static function get_users_array(context_course $context, $bbactivity = null) {
  89          // CONTRIB-7972, check the group of current user and course group mode.
  90          $groups = null;
  91          $users = (array) get_enrolled_users($context, '', 0, 'u.*', null, 0, 0, true);
  92          $course = get_course($context->instanceid);
  93          $groupmode = groups_get_course_groupmode($course);
  94          if ($bbactivity) {
  95              list($bbcourse, $cm) = get_course_and_cm_from_instance($bbactivity->id, 'bigbluebuttonbn');
  96              $groupmode = groups_get_activity_groupmode($cm);
  97  
  98          }
  99          if ($groupmode == SEPARATEGROUPS && !has_capability('moodle/site:accessallgroups', $context)) {
 100              global $USER;
 101              $groups = groups_get_all_groups($course->id, $USER->id);
 102              $users = [];
 103              foreach ($groups as $g) {
 104                  $users += (array) get_enrolled_users($context, '', $g->id, 'u.*', null, 0, 0, true);
 105              }
 106          }
 107          return array_map(
 108              function($u) {
 109                  return ['id' => $u->id, 'name' => fullname($u)];
 110              },
 111              $users);
 112      }
 113  
 114      /**
 115       * Can do some administration in this course, likely manage recordings
 116       *
 117       * @param int $courseid
 118       * @param string $capability
 119       */
 120      public static function has_capability_in_course(int $courseid, string $capability) {
 121          global $DB;
 122          if (empty($courseid) || $DB->record_exists('course', ['id' => $courseid])) {
 123              return has_capability('moodle/site:config', \context_system::instance());
 124          }
 125  
 126          $coursecontext = context_course::instance($courseid);
 127          return has_capability($capability, $coursecontext);
 128      }
 129  
 130      /**
 131       * Returns an array containing all the roles in a context.
 132       *
 133       * @param context|null $context $context
 134       * @param bool|null $onlyviewableroles
 135       *
 136       * @return array $roles
 137       */
 138      public static function get_roles(?context $context = null, ?bool $onlyviewableroles = true) {
 139          global $CFG;
 140  
 141          if ($onlyviewableroles == true && $CFG->branch >= 35) {
 142              $roles = (array) get_viewable_roles($context);
 143              foreach ($roles as $key => $value) {
 144                  $roles[$key] = $value;
 145              }
 146          } else {
 147              $roles = (array) role_get_names($context);
 148              foreach ($roles as $key => $value) {
 149                  $roles[$key] = $value->localname;
 150              }
 151          }
 152  
 153          return $roles;
 154      }
 155  
 156      /**
 157       * Returns an array containing all the roles in a context wrapped for html select element.
 158       *
 159       * @param context|null $context $context
 160       * @param bool $onlyviewableroles
 161       *
 162       * @return array $users
 163       */
 164      protected static function get_roles_select(context $context = null, bool $onlyviewableroles = true) {
 165          global $CFG;
 166  
 167          if ($onlyviewableroles == true && $CFG->branch >= 35) {
 168              $roles = (array) get_viewable_roles($context);
 169              foreach ($roles as $key => $value) {
 170                  $roles[$key] = ['id' => $key, 'name' => $value];
 171              }
 172          } else {
 173              $roles = (array) role_get_names($context);
 174              foreach ($roles as $key => $value) {
 175                  $roles[$key] = ['id' => $value->id, 'name' => $value->localname];
 176              }
 177          }
 178  
 179          return $roles;
 180      }
 181  
 182      /**
 183       * Returns role that corresponds to an id.
 184       *
 185       * @param string|integer $id
 186       *
 187       * @return stdClass|null $role
 188       */
 189      protected static function get_role($id): ?stdClass {
 190          $roles = (array) role_get_names();
 191          if (is_numeric($id) && isset($roles[$id])) {
 192              return (object) $roles[$id];
 193          }
 194          foreach ($roles as $role) {
 195              if ($role->shortname == $id) {
 196                  return $role;
 197              }
 198          }
 199          return null;
 200      }
 201  
 202      /**
 203       * Returns an array to populate a list of participants used in mod_form.js.
 204       *
 205       * @param context $context
 206       * @param null|stdClass $bbactivity
 207       * @return array $data
 208       */
 209      public static function get_participant_data(context $context, ?stdClass $bbactivity = null) {
 210          $data = [
 211              'all' => [
 212                  'name' => get_string('mod_form_field_participant_list_type_all', 'bigbluebuttonbn'),
 213                  'children' => []
 214              ],
 215          ];
 216          $data['role'] = [
 217              'name' => get_string('mod_form_field_participant_list_type_role', 'bigbluebuttonbn'),
 218              'children' => self::get_roles_select($context, true)
 219          ];
 220          $data['user'] = [
 221              'name' => get_string('mod_form_field_participant_list_type_user', 'bigbluebuttonbn'),
 222              'children' => self::get_users_array($context, $bbactivity),
 223          ];
 224          return $data;
 225      }
 226  
 227      /**
 228       * Returns an array to populate a list of participants used in mod_form.php.
 229       *
 230       * @param stdClass|null $bigbluebuttonbn
 231       * @param context $context
 232       *
 233       * @return array
 234       */
 235      public static function get_participant_list(?stdClass $bigbluebuttonbn, context $context): array {
 236          global $USER;
 237          if ($bigbluebuttonbn == null) {
 238              return self::get_participant_rules_encoded(
 239                  self::get_participant_list_default($context, $USER->id)
 240              );
 241          }
 242          if (empty($bigbluebuttonbn->participants)) {
 243              $bigbluebuttonbn->participants = "[]";
 244          }
 245          $rules = json_decode($bigbluebuttonbn->participants, true);
 246          if (empty($rules)) {
 247              $rules = self::get_participant_list_default($context,
 248                  bigbluebutton_proxy::get_instance_ownerid($bigbluebuttonbn));
 249          }
 250          return self::get_participant_rules_encoded($rules);
 251      }
 252  
 253      /**
 254       * Returns an array to populate a list of participants used in mod_form.php with default values.
 255       *
 256       * @param context $context
 257       * @param int|null $ownerid
 258       *
 259       * @return array
 260       */
 261      protected static function get_participant_list_default(context $context, ?int $ownerid = null) {
 262          $participantlist = [];
 263          $participantlist[] = [
 264              'selectiontype' => 'all',
 265              'selectionid' => 'all',
 266              'role' => self::ROLE_VIEWER,
 267          ];
 268          $defaultrules = explode(',', \mod_bigbluebuttonbn\local\config::get('participant_moderator_default'));
 269          foreach ($defaultrules as $defaultrule) {
 270              if ($defaultrule == '0') {
 271                  if (!empty($ownerid) && is_enrolled($context, $ownerid)) {
 272                      $participantlist[] = [
 273                          'selectiontype' => 'user',
 274                          'selectionid' => (string) $ownerid,
 275                          'role' => self::ROLE_MODERATOR];
 276                  }
 277                  continue;
 278              }
 279              $participantlist[] = [
 280                  'selectiontype' => 'role',
 281                  'selectionid' => $defaultrule,
 282                  'role' => self::ROLE_MODERATOR];
 283          }
 284          return $participantlist;
 285      }
 286  
 287      /**
 288       * Returns an array to populate a list of participants used in mod_form.php with bigbluebuttonbn values.
 289       *
 290       * @param array $rules
 291       *
 292       * @return array
 293       */
 294      protected static function get_participant_rules_encoded(array $rules): array {
 295          foreach ($rules as $key => $rule) {
 296              if ($rule['selectiontype'] !== 'role' || is_numeric($rule['selectionid'])) {
 297                  continue;
 298              }
 299              $role = self::get_role($rule['selectionid']);
 300              if ($role == null) {
 301                  unset($rules[$key]);
 302                  continue;
 303              }
 304              $rule['selectionid'] = $role->id;
 305              $rules[$key] = $rule;
 306          }
 307          return $rules;
 308      }
 309  
 310      /**
 311       * Returns an array to populate a list of participant_selection used in mod_form.php.
 312       *
 313       * @return array
 314       */
 315      public static function get_participant_selection_data(): array {
 316          return [
 317              'type_options' => [
 318                  'all' => get_string('mod_form_field_participant_list_type_all', 'bigbluebuttonbn'),
 319                  'role' => get_string('mod_form_field_participant_list_type_role', 'bigbluebuttonbn'),
 320                  'user' => get_string('mod_form_field_participant_list_type_user', 'bigbluebuttonbn'),
 321              ],
 322              'type_selected' => 'all',
 323              'options' => ['all' => '---------------'],
 324              'selected' => 'all',
 325          ];
 326      }
 327  
 328      /**
 329       * Evaluate if a user in a context is moderator based on roles and participation rules.
 330       *
 331       * @param context $context
 332       * @param array $participantlist
 333       * @param int $userid
 334       *
 335       * @return bool
 336       */
 337      public static function is_moderator(context $context, array $participantlist, ?int $userid = null): bool {
 338          global $USER;
 339          // If an admin, then also a moderator.
 340          if (has_capability('moodle/site:config', $context)) {
 341              return true;
 342          }
 343          if (!is_array($participantlist)) {
 344              return false;
 345          }
 346          if (empty($userid)) {
 347              $userid = $USER->id;
 348          }
 349          $userroles = self::get_guest_role();
 350          if (!isguestuser()) {
 351              $userroles = self::get_user_roles($context, $userid);
 352          }
 353          return self::is_moderator_validator($participantlist, $userid, $userroles);
 354      }
 355  
 356      /**
 357       * Iterates participant list rules to evaluate if a user is moderator.
 358       *
 359       * @param array $participantlist
 360       * @param int $userid
 361       * @param array $userroles
 362       *
 363       * @return bool
 364       */
 365      protected static function is_moderator_validator(array $participantlist, int $userid, array $userroles): bool {
 366          // Iterate participant rules.
 367          foreach ($participantlist as $participant) {
 368              if (self::is_moderator_validate_rule($participant, $userid, $userroles)) {
 369                  return true;
 370              }
 371          }
 372          return false;
 373      }
 374  
 375      /**
 376       * Evaluate if a user is moderator based on roles and a particular participation rule.
 377       *
 378       * @param array $participant
 379       * @param int $userid
 380       * @param array $userroles
 381       *
 382       * @return bool
 383       */
 384      protected static function is_moderator_validate_rule(array $participant, int $userid, array $userroles): bool {
 385          if ($participant['role'] == self::ROLE_VIEWER) {
 386              return false;
 387          }
 388          // Validation for the 'all' rule.
 389          if ($participant['selectiontype'] == 'all') {
 390              return true;
 391          }
 392          // Validation for a 'user' rule.
 393          if ($participant['selectiontype'] == 'user') {
 394              if ($participant['selectionid'] == $userid) {
 395                  return true;
 396              }
 397              return false;
 398          }
 399          // Validation for a 'role' rule.
 400          $role = self::get_role($participant['selectionid']);
 401          if ($role != null && array_key_exists($role->id, $userroles)) {
 402              return true;
 403          }
 404          return false;
 405      }
 406  
 407      /**
 408       * Updates the meeting info cached object when a participant has joined.
 409       *
 410       * @param string $meetingid
 411       * @param bool $ismoderator
 412       *
 413       * @return void
 414       */
 415      public static function participant_joined(string $meetingid, bool $ismoderator): void {
 416          $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'mod_bigbluebuttonbn', 'meetings_cache');
 417          $result = $cache->get($meetingid);
 418          $meetinginfo = json_decode($result['meeting_info']);
 419          $meetinginfo->participantCount += 1;
 420          if ($ismoderator) {
 421              $meetinginfo->moderatorCount += 1;
 422          }
 423          $cache->set($meetingid, ['creation_time' => $result['creation_time'],
 424              'meeting_info' => json_encode($meetinginfo)]);
 425      }
 426  
 427      /**
 428       * Helper function returns a list of courses a user has access to, wrapped in an array that can be used
 429       * by a html select.
 430       *
 431       * @param instance $instance
 432       * @return array
 433       */
 434      public static function import_get_courses_for_select(instance $instance): array {
 435          if ($instance->is_admin()) {
 436              $courses = get_courses('all', 'c.fullname ASC');
 437              // It includes the name of the site as a course (category 0), so remove the first one.
 438              unset($courses['1']);
 439          } else {
 440              $courses = enrol_get_users_courses($instance->get_user_id(), false, 'id,shortname,fullname');
 441          }
 442          $courses = array_filter($courses, function($course) {
 443              $modules = get_fast_modinfo($course->id);
 444              return !empty($modules->instances['bigbluebuttonbn']);
 445          });
 446          $coursesforselect = [];
 447          foreach ($courses as $course) {
 448              $coursesforselect[$course->id] = $course->fullname . " (" . $course->shortname . ")";
 449          }
 450          return $coursesforselect;
 451      }
 452  }