Differences Between: [Versions 402 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 /** 18 * The mod_bigbluebuttonbn files helper 19 * 20 * @package mod_bigbluebuttonbn 21 * @copyright 2021 onwards, Blindside Networks Inc 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 * @author Laurent David (laurent [at] call-learning [dt] fr) 24 */ 25 26 namespace mod_bigbluebuttonbn\local\helpers; 27 28 use cache; 29 use cache_store; 30 use context; 31 use context_module; 32 use context_system; 33 use mod_bigbluebuttonbn\instance; 34 use moodle_url; 35 use stdClass; 36 37 /** 38 * Utility class for all files routines helper 39 * 40 * @package mod_bigbluebuttonbn 41 * @copyright 2021 onwards, Blindside Networks Inc 42 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 43 */ 44 class files { 45 46 /** 47 * Helper for validating pluginfile. 48 * 49 * @param stdClass $context context object 50 * @param string $filearea file area 51 * 52 * @return bool|null false if file not valid 53 */ 54 public static function pluginfile_valid(stdClass $context, string $filearea): ?bool { 55 56 // Can be in context module or in context_system (if is the presentation by default). 57 if (!in_array($context->contextlevel, [CONTEXT_MODULE, CONTEXT_SYSTEM])) { 58 return false; 59 } 60 61 if (!array_key_exists($filearea, self::get_file_areas())) { 62 return false; 63 } 64 65 return true; 66 } 67 68 /** 69 * Helper for getting pluginfile. 70 * 71 * @param stdClass|null $course course object 72 * @param stdClass|null $cm course module object 73 * @param context $context context object 74 * @param string $filearea file area 75 * @param array $args extra arguments 76 * 77 * @return \stored_file|bool 78 */ 79 public static function pluginfile_file(?stdClass $course, ?stdClass $cm, context $context, string $filearea, array $args) { 80 $filename = self::get_plugin_filename($course, $cm, $context, $args); 81 if (!$filename) { 82 return false; 83 } 84 $fullpath = "/$context->id/mod_bigbluebuttonbn/$filearea/0/" . $filename; 85 $fs = get_file_storage(); 86 $file = $fs->get_file_by_hash(sha1($fullpath)); 87 if (!$file || $file->is_directory()) { 88 return false; 89 } 90 return $file; 91 } 92 93 /** 94 * Get a full path to the file attached as a preuploaded presentation 95 * or if there is none, set the presentation field will be set to blank. 96 * 97 * @param stdClass $bigbluebuttonformdata BigBlueButtonBN form data 98 * Note that $bigbluebuttonformdata->presentation is the id of the filearea whereas the bbb instance table 99 * stores the file name/path 100 * @return string 101 */ 102 public static function save_media_file(stdClass &$bigbluebuttonformdata): string { 103 if (!isset($bigbluebuttonformdata->presentation) || $bigbluebuttonformdata->presentation == '') { 104 return ''; 105 } 106 $context = context_module::instance($bigbluebuttonformdata->coursemodule); 107 // Set the filestorage object. 108 $fs = get_file_storage(); 109 // Save the file if it exists that is currently in the draft area. 110 file_save_draft_area_files($bigbluebuttonformdata->presentation, $context->id, 'mod_bigbluebuttonbn', 'presentation', 0); 111 // Get the file if it exists. 112 $files = $fs->get_area_files( 113 $context->id, 114 'mod_bigbluebuttonbn', 115 'presentation', 116 0, 117 'itemid, filepath, filename', 118 false 119 ); 120 // Check that there is a file to process. 121 $filesrc = ''; 122 if (count($files) == 1) { 123 // Get the first (and only) file. 124 $file = reset($files); 125 $filesrc = '/' . $file->get_filename(); 126 } 127 return $filesrc; 128 } 129 130 /** 131 * Helper return array containing the file descriptor for a preuploaded presentation. 132 * 133 * @param context $context 134 * @param string $presentation matching presentation file name 135 * @param int $id bigbluebutton instance id 136 * @param bool $withnonce add nonce to the url 137 * @return array|null the representation of the presentation as an associative array 138 */ 139 public static function get_presentation(context $context, string $presentation, $id = null, $withnonce = false): ?array { 140 global $CFG; 141 $fs = get_file_storage(); 142 $files = []; 143 $defaultpresentation = $fs->get_area_files( 144 context_system::instance()->id, 145 'mod_bigbluebuttonbn', 146 'presentationdefault', 147 0, 148 "filename", 149 false 150 ); 151 $activitypresentation = $files = $fs->get_area_files( 152 $context->id, 153 'mod_bigbluebuttonbn', 154 'presentation', 155 false, 156 'itemid, filepath, filename', 157 false 158 ); 159 // Presentation upload logic based on config settings. 160 if (empty($defaultpresentation)) { 161 if (empty($activitypresentation) || !\mod_bigbluebuttonbn\local\config::get('preuploadpresentation_editable')) { 162 return null; 163 } 164 $files = $activitypresentation; 165 166 } else { 167 if (empty($activitypresentation) || !\mod_bigbluebuttonbn\local\config::get('preuploadpresentation_editable')) { 168 $files = $defaultpresentation; 169 $id = null; 170 } else { 171 $files = $activitypresentation; 172 } 173 } 174 $pnoncevalue = 0; 175 if ($withnonce) { 176 $nonceid = 0; 177 if (!is_null($id)) { 178 $instance = instance::get_from_instanceid($id); 179 $nonceid = $instance->get_instance_id(); 180 } 181 $pnoncevalue = self::generate_nonce($nonceid); 182 } 183 184 $file = null; 185 foreach ($files as $f) { 186 if (basename($f->get_filename()) == basename($presentation)) { 187 $file = $f; 188 } 189 } 190 if (!$file && !empty($files)) { 191 $file = reset($files); 192 } 193 if (empty($file)) { 194 return null; // File was not found. 195 } 196 197 // Note: $pnoncevalue is an int. 198 $url = moodle_url::make_pluginfile_url( 199 $file->get_contextid(), 200 $file->get_component(), 201 $file->get_filearea(), 202 $withnonce ? $pnoncevalue : null, // Hack: item id as a nonce. 203 $file->get_filepath(), 204 $file->get_filename() 205 ); 206 return [ 207 'icondesc' => get_mimetype_description($file), 208 'iconname' => file_file_icon($file, 24), 209 'name' => $file->get_filename(), 210 'url' => $url->out(false), 211 ]; 212 } 213 214 /** 215 * Helper for getting pluginfile name. 216 * 217 * @param stdClass|null $course course object 218 * @param stdClass|null $cm course module object 219 * @param context $context context object 220 * @param array $args extra arguments 221 * 222 * @return string|null 223 */ 224 public static function get_plugin_filename(?stdClass $course, ?stdClass $cm, context $context, array $args): ?string { 225 global $DB; 226 if ($context->contextlevel != CONTEXT_SYSTEM) { 227 // Plugin has a file to use as default in general setting. 228 // The difference with the standard bigbluebuttonbn_pluginfile_filename() are. 229 // - Context is system, so we don't need to check the cmid in this case. 230 // - The area is "presentationdefault_cache". 231 if (!$DB->get_record('bigbluebuttonbn', ['id' => $cm->instance])) { 232 return null; 233 } 234 } 235 // Plugin has a file to use as default in general setting. 236 // The difference with the standard bigbluebuttonbn_pluginfile_filename() are. 237 // - Context is system, so we don't need to check the cmid in this case. 238 // - The area is "presentationdefault_cache". 239 if (count($args) > 1) { 240 $id = 0; 241 if ($cm) { 242 $instance = instance::get_from_cmid($cm->id); 243 $id = $instance->get_instance_id(); 244 } 245 $actualnonce = self::get_nonce($id); 246 return ($args['0'] == $actualnonce) ? $args['1'] : null; 247 248 } 249 if (!empty($course)) { 250 require_course_login($course, true, $cm, true, true); 251 } else { 252 require_login(null, true, $cm, true, true); 253 } 254 if (!has_capability('mod/bigbluebuttonbn:join', $context)) { 255 return null; 256 } 257 return implode('/', $args); 258 } 259 260 /** 261 * Helper generates a salt used for the preuploaded presentation callback url. 262 * 263 * @param int $id 264 * @return int 265 */ 266 protected static function get_nonce(int $id): int { 267 $cache = static::get_nonce_cache(); 268 $pnoncekey = sha1($id); 269 $existingnoncedata = $cache->get($pnoncekey); 270 if ($existingnoncedata) { 271 if ($existingnoncedata->counter > 0) { 272 $existingnoncedata->counter--; 273 $cache->set($pnoncekey, $existingnoncedata); 274 return $existingnoncedata->nonce; 275 } 276 } 277 // The item id was adapted for granting public access to the presentation once in order to allow BigBlueButton to gather 278 // the file once. 279 return static::generate_nonce($id); 280 } 281 282 /** 283 * Generate a nonce and store it in the cache 284 * 285 * @param int $id 286 * @return int 287 */ 288 protected static function generate_nonce($id): int { 289 $cache = static::get_nonce_cache(); 290 $pnoncekey = sha1($id); 291 // The item id was adapted for granting public access to the presentation once in order to allow BigBlueButton to gather 292 // the file once. 293 $pnoncevalue = ((int) microtime()) + mt_rand(); 294 $cache->set($pnoncekey, (object) ['nonce' => $pnoncevalue, 'counter' => 2]); 295 return $pnoncevalue; 296 } 297 298 /** 299 * Get cache for nonce 300 * 301 * @return \cache_application|\cache_session|cache_store 302 */ 303 private static function get_nonce_cache() { 304 return cache::make_from_params( 305 cache_store::MODE_APPLICATION, 306 'mod_bigbluebuttonbn', 307 'presentation_cache' 308 ); 309 } 310 311 /** 312 * Returns an array of file areas. 313 * 314 * @return array a list of available file areas 315 * 316 */ 317 protected static function get_file_areas(): array { 318 $areas = []; 319 $areas['presentation'] = get_string('mod_form_block_presentation', 'bigbluebuttonbn'); 320 $areas['presentationdefault'] = get_string('mod_form_block_presentation_default', 'bigbluebuttonbn'); 321 return $areas; 322 } 323 324 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body