Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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),
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
}