See Release Notes
Long Term Support Release
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body