Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.
   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  namespace mod_bigbluebuttonbn\local\bigbluebutton\recordings;
  18  
  19  use mod_bigbluebuttonbn\instance;
  20  use mod_bigbluebuttonbn\local\config;
  21  use mod_bigbluebuttonbn\local\helpers\roles;
  22  use mod_bigbluebuttonbn\local\proxy\bigbluebutton_proxy;
  23  use mod_bigbluebuttonbn\output\recording_description_editable;
  24  use mod_bigbluebuttonbn\output\recording_name_editable;
  25  use mod_bigbluebuttonbn\output\recording_row_actionbar;
  26  use mod_bigbluebuttonbn\output\recording_row_playback;
  27  use mod_bigbluebuttonbn\output\recording_row_preview;
  28  use mod_bigbluebuttonbn\recording;
  29  use stdClass;
  30  
  31  /**
  32   * The recordings_data.
  33   *
  34   * @package   mod_bigbluebuttonbn
  35   * @copyright 2021 onwards, Blindside Networks Inc
  36   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  37   * @author    Laurent David  (laurent.david [at] call-learning [dt] fr)
  38   * @author    Jesus Federico  (jesus [at] blindsidenetworks [dt] com)
  39   */
  40  class recording_data {
  41  
  42      /**
  43       * Get the full recording table
  44       *
  45       * @param array $recordings
  46       * @param array $tools
  47       * @param instance|null $instance
  48       * @param int $courseid
  49       * @return array
  50       */
  51      public static function get_recording_table(array $recordings, array $tools, instance $instance = null,
  52          int $courseid = 0): array {
  53          $typeprofiles = bigbluebutton_proxy::get_instance_type_profiles();
  54          $typeprofile = empty($instance) ? $typeprofiles[0] : $typeprofiles[$instance->get_type()];
  55          $lang = get_string('locale', 'core_langconfig');
  56          $locale = substr($lang, 0, strpos($lang, '.'));
  57          $tabledata = [
  58              'activity' => empty($instance) ? '' : bigbluebutton_proxy::view_get_activity_status($instance),
  59              'ping_interval' => (int) config::get('waitformoderator_ping_interval') * 1000,
  60              'locale' => substr($locale, 0, strpos($locale, '_')),
  61              'profile_features' => $typeprofile['features'],
  62              'columns' => [],
  63              'data' => '',
  64          ];
  65          $hascapabilityincourse = empty($instance) && roles::has_capability_in_course($courseid,
  66                  'mod/bigbluebuttonbn:managerecordings');
  67  
  68          $data = [];
  69  
  70          // Build table content.
  71          foreach ($recordings as $recording) {
  72              $rowtools = $tools;
  73              // Protected recordings may be enabled or disabled from UI through configuration.
  74              if (!(boolean) config::get('recording_protect_editable')) {
  75                  $rowtools = array_diff($rowtools, ['protect', 'unprotect']);
  76              }
  77              // Protected recordings is not a standard feature, remove actions when protected flag is not present.
  78              if (in_array('protect', $rowtools) && $recording->get('protected') === null) {
  79                  $rowtools = array_diff($rowtools, ['protect', 'unprotect']);
  80              }
  81              $rowdata = self::row($instance, $recording, $rowtools);
  82              if (!empty($rowdata)) {
  83                  $data[] = $rowdata;
  84              }
  85          }
  86  
  87          $columns = [
  88              [
  89                  'key' => 'playback',
  90                  'label' => get_string('view_recording_playback', 'bigbluebuttonbn'),
  91                  'width' => '125px',
  92                  'type' => 'html',
  93                  'allowHTML' => true,
  94              ],
  95              [
  96                  'key' => 'recording',
  97                  'label' => get_string('view_recording_name', 'bigbluebuttonbn'),
  98                  'width' => '125px',
  99                  'type' => 'html',
 100                  'allowHTML' => true,
 101              ],
 102              [
 103                  'key' => 'description',
 104                  'label' => get_string('view_recording_description', 'bigbluebuttonbn'),
 105                  'sortable' => true,
 106                  'width' => '250px',
 107                  'type' => 'html',
 108                  'allowHTML' => true,
 109              ],
 110          ];
 111  
 112          // Initialize table headers.
 113          $ispreviewenabled = !empty($instance) && self::preview_enabled($instance);
 114          $ispreviewenabled = $ispreviewenabled || $hascapabilityincourse;
 115          if ($ispreviewenabled) {
 116              $columns[] = [
 117                  'key' => 'preview',
 118                  'label' => get_string('view_recording_preview', 'bigbluebuttonbn'),
 119                  'width' => '250px',
 120                  'type' => 'html',
 121                  'allowHTML' => true,
 122              ];
 123          }
 124  
 125          $columns[] = [
 126              'key' => 'date',
 127              'label' => get_string('view_recording_date', 'bigbluebuttonbn'),
 128              'sortable' => true,
 129              'width' => '225px',
 130              'type' => 'html',
 131              'formatter' => 'customDate',
 132          ];
 133          $columns[] = [
 134              'key' => 'duration',
 135              'label' => get_string('view_recording_duration', 'bigbluebuttonbn'),
 136              'width' => '50px',
 137              'allowHTML' => false,
 138              'sortable' => true,
 139          ];
 140          // Either instance is empty and we must show the toolbar (with restricted content) or we check
 141          // specific rights related to the instance.
 142          $canmanagerecordings = !empty($instance) && $instance->can_manage_recordings();
 143          $canmanagerecordings = $canmanagerecordings || $hascapabilityincourse;
 144          if ($canmanagerecordings) {
 145              $columns[] = [
 146                  'key' => 'actionbar',
 147                  'label' => get_string('view_recording_actionbar', 'bigbluebuttonbn'),
 148                  'width' => '120px',
 149                  'type' => 'html',
 150                  'allowHTML' => true,
 151              ];
 152          }
 153  
 154          $tabledata['columns'] = $columns;
 155          $tabledata['data'] = json_encode($data);
 156  
 157          return $tabledata;
 158      }
 159  
 160      /**
 161       * Helper function builds a row for the data used by the recording table.
 162       *
 163       * TODO: replace this with templates whenever possible so we just
 164       * return the data via the API.
 165       *
 166       * @param instance|null $instance $instance
 167       * @param recording $rec a recording row
 168       * @param array|null $tools
 169       * @param int|null $courseid
 170       * @return stdClass|null
 171       */
 172      public static function row(?instance $instance, recording $rec, ?array $tools = null, ?int $courseid = 0): ?stdClass {
 173          global $PAGE;
 174  
 175          $hascapabilityincourse = empty($instance) && roles::has_capability_in_course($courseid,
 176                  'mod/bigbluebuttonbn:managerecordings');
 177          $renderer = $PAGE->get_renderer('mod_bigbluebuttonbn');
 178          foreach ($tools as $key => $tool) {
 179              if ((!empty($instance) && !$instance->can_perform_on_recordings($tool))
 180                  || (empty($instance) && !$hascapabilityincourse)) {
 181                  unset($tools[$key]);
 182              }
 183          }
 184          if (!self::include_recording_table_row($instance, $rec)) {
 185              return null;
 186          }
 187          $rowdata = new stdClass();
 188  
 189          // Set recording_playback.
 190          $recordingplayback = new recording_row_playback($rec, $instance);
 191          $rowdata->playback = $renderer->render($recordingplayback);
 192  
 193          if (empty($instance)) {
 194              // Set activity name.
 195              $rowdata->recording = $rec->get('name');
 196  
 197              // Set activity description.
 198              $rowdata->description = $rec->get('description');
 199          } else {
 200              // Set activity name.
 201              $recordingname = new recording_name_editable($rec, $instance);
 202              $rowdata->recording = $renderer->render_inplace_editable($recordingname);
 203              // Set activity description.
 204              $recordingdescription = new recording_description_editable($rec, $instance);
 205              $rowdata->description = $renderer->render_inplace_editable($recordingdescription);
 206          }
 207  
 208          if ((!empty($instance) && self::preview_enabled($instance)) || $hascapabilityincourse) {
 209              // Set recording_preview.
 210              $rowdata->preview = '';
 211              if ($rec->get('playbacks')) {
 212                  $rowpreview = new recording_row_preview($rec);
 213                  $rowdata->preview = $renderer->render($rowpreview);
 214              }
 215          }
 216          // Set date.
 217          $starttime = $rec->get('starttime');
 218          $rowdata->date = !is_null($starttime) ? floatval($starttime) : 0;
 219          // Set duration.
 220          $rowdata->duration = self::row_duration($rec);
 221          // Set actionbar, if user is allowed to manage recordings.
 222          if ((!empty($instance) && $instance->can_manage_recordings()) || $hascapabilityincourse) {
 223              $actionbar = new recording_row_actionbar($rec, $tools);
 224              $rowdata->actionbar = $renderer->render($actionbar);
 225          }
 226          return $rowdata;
 227      }
 228  
 229      /**
 230       * Helper function evaluates if recording preview should be included.
 231       *
 232       * @param instance $instance
 233       * @return bool
 234       */
 235      public static function preview_enabled(instance $instance): bool {
 236          return $instance->get_instance_var('recordings_preview') == '1';
 237      }
 238  
 239      /**
 240       * Helper function converts recording duration used in row for the data used by the recording table.
 241       *
 242       * @param recording $recording
 243       * @return int
 244       */
 245      protected static function row_duration(recording $recording): int {
 246          $playbacks = $recording->get('playbacks');
 247          if (empty($playbacks)) {
 248              return 0;
 249          }
 250          foreach ($playbacks as $playback) {
 251              // Ignore restricted playbacks.
 252              if (array_key_exists('restricted', $playback) && strtolower($playback['restricted']) == 'true') {
 253                  continue;
 254              }
 255  
 256              // Take the length form the fist playback with an actual value.
 257              if (!empty($playback['length'])) {
 258                  return intval($playback['length']);
 259              }
 260          }
 261          return 0;
 262      }
 263  
 264      /**
 265       * Helper function to handle yet unknown recording types
 266       *
 267       * @param string $playbacktype : for now presentation, video, statistics, capture, notes, podcast
 268       * @return string the matching language string or a capitalised version of the provided string
 269       */
 270      public static function type_text(string $playbacktype): string {
 271          // Check first if string exists, and if it does not, just default to the capitalised version of the string.
 272          $text = ucwords($playbacktype);
 273          $typestringid = 'view_recording_format_' . $playbacktype;
 274          if (get_string_manager()->string_exists($typestringid, 'bigbluebuttonbn')) {
 275              $text = get_string($typestringid, 'bigbluebuttonbn');
 276          }
 277          return $text;
 278      }
 279  
 280      /**
 281       * Helper function evaluates if recording row should be included in the table.
 282       *
 283       * @param instance|null $instance
 284       * @param recording $rec a bigbluebuttonbn_recordings row
 285       * @return bool
 286       */
 287      protected static function include_recording_table_row(?instance $instance, recording $rec): bool {
 288          if (empty($instance)) {
 289              return roles::has_capability_in_course($rec->get('courseid'), 'mod/bigbluebuttonbn:managerecordings');
 290          }
 291          // Exclude unpublished recordings, only if user has no rights to manage them.
 292          if (!$rec->get('published') && !$instance->can_manage_recordings()) {
 293              return false;
 294          }
 295          // Imported recordings are always shown as long as they are published.
 296          if ($rec->get('imported')) {
 297              return true;
 298          }
 299          // When show imported recordings only is enabled, exclude all other recordings.
 300          if ($instance->get_recordings_imported() && !$rec->get('imported')) {
 301              return false;
 302          }
 303          // Administrators and moderators are always allowed.
 304          if ($instance->is_admin() || $instance->is_moderator()) {
 305              return true;
 306          }
 307          // When groups are enabled, exclude those to which the user doesn't have access to.
 308          if ($instance->uses_groups() && !$instance->can_manage_recordings()) {
 309              if (groups_get_activity_groupmode($instance->get_cm()) == VISIBLEGROUPS) {
 310                  // In case we are in visible group mode, we show all recordings.
 311                  return true;
 312              }
 313              // Else we check if the Recording group is the same as the instance. Instance group
 314              // being the group chosen for this instance.
 315              return intval($rec->get('groupid')) === $instance->get_group_id();
 316          }
 317          return true;
 318      }
 319  }