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
 * Responsible for handling AJAX requests related to H5P.
18
 *
19
 * @package    mod_hvp
20
 * @copyright  2016 Joubel AS <contact@joubel.com>
21
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22
 */
23
 
24
use mod_hvp\framework;
25
 
26
define('AJAX_SCRIPT', true);
27
require(__DIR__ . '/../../config.php');
28
require_once($CFG->libdir . '/filelib.php');
29
require_once("locallib.php");
30
 
31
require_login();
32
 
33
$action = required_param('action', PARAM_ALPHA);
34
switch($action) {
35
 
36
    /*
37
     * Handle user data reporting
38
     *
39
     * Type: HTTP POST
40
     *
41
     * Parameters:
42
     *  - content_id
43
     *  - data_type
44
     *  - sub_content_id
45
     */
46
    case 'contentsuserdata':
47
        \mod_hvp\content_user_data::handle_ajax();
48
        break;
49
 
50
    /*
51
     * Handle restricting H5P libraries
52
     *
53
     * Type: HTTP GET
54
     *
55
     * Parameters:
56
     *  - library_id
57
     *  - restrict (0 or 1)
58
     *  - token
59
     */
60
    case 'restrictlibrary':
61
 
62
        // Check permissions.
63
        $context = \context_system::instance();
64
        if (!has_capability('mod/hvp:restrictlibraries', $context)) {
65
            \H5PCore::ajaxError(get_string('nopermissiontorestrict', 'hvp'));
66
            http_response_code(403);
67
            break;
68
        }
69
 
70
        $libraryid = required_param('library_id', PARAM_INT);
71
        $restrict = required_param('restrict', PARAM_INT);
72
 
73
        if (!\H5PCore::validToken('library_' . $libraryid, required_param('token', PARAM_RAW))) {
74
            \H5PCore::ajaxError(get_string('invalidtoken', 'hvp'));
75
            exit;
76
        }
77
 
78
        hvp_restrict_library($libraryid, $restrict);
79
        header('Cache-Control: no-cache');
80
        header('Content-Type: application/json');
81
        echo json_encode(array(
82
            'url' => (new moodle_url('/mod/hvp/ajax.php', array(
83
                'action' => 'restrict_library',
84
                'token' => \H5PCore::createToken('library_' . $libraryid),
85
                'restrict' => ($restrict === '1' ? 0 : 1),
86
                'library_id' => $libraryid
87
            )))->out(false)));
88
        break;
89
 
90
    /*
91
     * Collecting data needed by H5P content upgrade
92
     *
93
     * Type: HTTP GET
94
     *
95
     * Parameters:
96
     *  - library (Format: /<machine-name>/<major-version>/<minor-version>)
97
     */
98
    case 'getlibrarydataforupgrade':
99
 
100
        // Check permissions.
101
        $context = \context_system::instance();
102
        if (!has_capability('mod/hvp:updatelibraries', $context)) {
103
            \H5PCore::ajaxError(get_string('nopermissiontoupgrade', 'hvp'));
104
            http_response_code(403);
105
            break;
106
        }
107
 
108
        $library = required_param('library', PARAM_TEXT);
109
        $library = explode('/', substr($library, 1));
110
 
111
        if (count($library) !== 3) {
112
            http_response_code(422);
113
            return;
114
        }
115
 
116
        $library = hvp_get_library_upgrade_info($library[0], $library[1], $library[2]);
117
 
118
        header('Cache-Control: no-cache');
119
        header('Content-Type: application/json');
120
        print json_encode($library);
121
 
122
        break;
123
 
124
    /*
125
     * Saving upgraded content, and returning next batch to process
126
     *
127
     * Type: HTTP POST
128
     *
129
     * Parameters:
130
     *  - library_id
131
     */
132
    case 'libraryupgradeprogress':
133
        // Check upgrade permissions.
134
        $context = \context_system::instance();
135
        if (!has_capability('mod/hvp:updatelibraries', $context)) {
136
            \H5PCore::ajaxError(get_string('nopermissiontoupgrade', 'hvp'));
137
            http_response_code(403);
138
            break;
139
        }
140
 
141
        // Because of a confirmed bug in PHP, filter_input(INPUT_SERVER, ...)
142
        // will return null on some versions of FCGI/PHP (5.4 and probably
143
        // older versions as well), ref. https://bugs.php.net/bug.php?id=49184.
144
        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
145
            $libraryid = required_param('library_id', PARAM_INT);
146
            $out = hvp_content_upgrade_progress($libraryid);
147
            header('Cache-Control: no-cache');
148
            header('Content-Type: application/json');
149
            print json_encode($out);
150
        } else {
151
            // Only allow POST.
152
            http_response_code(405);
153
        }
154
        break;
155
 
156
    /*
157
     * Handle set finished / storing grades
158
     *
159
     * Type: HTTP GET
160
     *
161
     * Parameters:
162
     *  - contentId
163
     *  - score
164
     *  - maxScore
165
     */
166
    case 'setfinished':
167
        \mod_hvp\user_grades::handle_ajax();
168
        break;
169
 
170
    /*
171
     * Saves a dynamically graded grade to the gradebook
172
     *
173
     * Type: HTTP POST
174
     *
175
     * Parameters:
176
     *  - subcontent_id
177
     *  - score
178
     */
179
    case 'updatesubcontentscore':
180
        \mod_hvp\user_grades::handle_dynamic_grading();
181
        break;
182
 
183
    /*
184
     * Returns a grade
185
     *
186
     * Type: HTTP GET
187
     *
188
     * Parameters:
189
     *  - subcontent_id
190
     */
191
    case 'getsubcontentscore':
192
        \mod_hvp\user_grades::return_subcontent_grade();
193
        break;
194
 
195
    /*
196
     * Provide data for results view
197
     *
198
     * Type: HTTP GET
199
     *
200
     * Parameters:
201
     *  int content_id
202
     *  int offset
203
     *  int limit
204
     *  int sortBy
205
     *  int sortDir
206
     *  string[] filters
207
     */
208
    case 'results':
209
        $results = new \mod_hvp\results();
210
        $results->print_results();
211
        break;
212
 
213
    /*
214
     * Load list of libraries or details for library.
215
     *
216
     * Parameters:
217
     *  string machineName
218
     *  int majorVersion
219
     *  int minorVersion
220
     */
221
    case 'libraries':
222
        if (!framework::has_editor_access('nopermissiontoviewcontenttypes')) {
223
            break;
224
        }
225
 
226
        // Get parameters.
227
        $name = optional_param('machineName', '', PARAM_TEXT);
228
        $major = optional_param('majorVersion', 0, PARAM_INT);
229
        $minor = optional_param('minorVersion', 0, PARAM_INT);
230
        $editor = framework::instance('editor');
231
        $language = optional_param('default-language', null, PARAM_RAW);
232
 
233
        if (!empty($name)) {
234
            $editor->ajax->action(H5PEditorEndpoints::SINGLE_LIBRARY, $name,
235
                $major, $minor, framework::get_language(), '', '', $language);
236
 
237
            new \mod_hvp\event(
238
                    'library', null,
239
                    null, null,
240
                    $name, $major . '.' . $minor
241
            );
242
        } else {
243
            $editor->ajax->action(H5PEditorEndpoints::LIBRARIES);
244
        }
245
 
246
        break;
247
 
248
    /*
249
     * Load content type cache list to display available libraries in hub
250
     */
251
    case 'contenttypecache':
252
        if (!framework::has_editor_access('nopermissiontoviewcontenttypes')) {
253
            break;
254
        }
255
 
256
        $editor = framework::instance('editor');
257
        $editor->ajax->action(H5PEditorEndpoints::CONTENT_TYPE_CACHE);
258
        break;
259
 
260
    /*
261
     * Handle file upload through the editor.
262
     *
263
     * Parameters:
264
     *  int contentId
265
     *  int contextId
266
     */
267
    case 'files':
268
        $token = required_param('token', PARAM_RAW);
269
        $contentid = required_param('contentId', PARAM_INT);
270
        if (!framework::has_editor_access('nopermissiontouploadfiles')) {
271
            break;
272
        }
273
 
274
        $editor = framework::instance('editor');
275
        $editor->ajax->action(H5PEditorEndpoints::FILES, $token, $contentid);
276
        break;
277
 
278
    /*
279
     * Handle file upload through the editor.
280
     *
281
     * Parameters:
282
     *  raw token
283
     *  raw contentTypeUrl
284
     */
285
    case 'libraryinstall':
286
        $token = required_param('token', PARAM_RAW);
287
        $machinename = required_param('id', PARAM_TEXT);
288
        $editor = framework::instance('editor');
289
        $editor->ajax->action(H5PEditorEndpoints::LIBRARY_INSTALL, $token, $machinename);
290
        break;
291
 
292
    /*
293
     * Install libraries from h5p and retrieve content json
294
     *
295
     * Parameters:
296
     *  file h5p
297
     */
298
    case 'libraryupload':
299
        $token = required_param('token', PARAM_RAW);
300
        if (!framework::has_editor_access('nopermissiontouploadcontent')) {
301
            break;
302
        }
303
 
304
        $editor = framework::instance('editor');
305
        $uploadpath = $_FILES['h5p']['tmp_name'];
306
        $contentid = optional_param('contentId', 0, PARAM_INT);
307
        $editor->ajax->action(H5PEditorEndpoints::LIBRARY_UPLOAD, $token, $uploadpath, $contentid);
308
        break;
309
 
310
    /*
311
     * Record xAPI result from view
312
     */
313
    case 'xapiresult':
314
        \mod_hvp\xapi_result::handle_ajax();
315
        break;
316
 
317
    case 'translations':
318
        if (!framework::has_editor_access('nopermissiontogettranslations')) {
319
            break;
320
        }
321
        $language = required_param('language', PARAM_RAW);
322
        $editor = framework::instance('editor');
323
        $editor->ajax->action(H5PEditorEndpoints::TRANSLATIONS, $language);
324
        break;
325
 
326
    /*
327
     * Handle filtering of parameters through AJAX.
328
     */
329
    case 'filter':
330
        $token = required_param('token', PARAM_RAW);
331
        $libraryparameters = required_param('libraryParameters', PARAM_RAW);
332
 
333
        if (!framework::has_editor_access('nopermissiontouploadfiles')) {
334
            break;
335
        }
336
 
337
        $editor = framework::instance('editor');
338
        $editor->ajax->action(H5PEditorEndpoints::FILTER, $token, $libraryparameters);
339
        break;
340
 
341
    /*
342
     * Handle filtering of parameters through AJAX.
343
     */
344
    case 'contenthubmetadatacache':
345
        if (!framework::has_editor_access('nopermissiontoviewcontenthubcache')) {
346
            break;
347
        }
348
        $editor = framework::instance('editor');
349
        $editor->ajax->action(H5PEditorEndpoints::CONTENT_HUB_METADATA_CACHE, framework::get_language());
350
        break;
351
 
352
    case 'contenthubregistration':
353
        // Check permission.
354
        $context = \context_system::instance();
355
        if (!has_capability('mod/hvp:contenthubregistration', $context)) {
356
            \H5PCore::ajaxError(get_string('contenthub:nopermissions', 'hvp'), 'NO_PERMISSION', 403);
357
            return;
358
        }
359
 
360
        $token = required_param('_token', PARAM_RAW);
361
 
362
        if (!H5PCore::validToken('contentHubRegistration', $token)) {
363
            H5PCore::ajaxError('Invalid token', 'INVALID_TOKEN', 401);
364
            return;
365
        }
366
        $logo = isset($_FILES['logo']) ? $_FILES['logo'] : null;
367
 
368
        $formdata = [
369
            'name'           => required_param('name', PARAM_TEXT),
370
            'email'          => required_param('email', PARAM_EMAIL),
371
            'description'    => optional_param('description', '', PARAM_TEXT),
372
            'contact_person' => optional_param('contact_person', '', PARAM_TEXT),
373
            'phone'          => optional_param('phone', '', PARAM_TEXT),
374
            'address'        => optional_param('address', '', PARAM_TEXT),
375
            'city'           => optional_param('city', '', PARAM_TEXT),
376
            'zip'            => optional_param('zip', '', PARAM_TEXT),
377
            'country'        => optional_param('country', '', PARAM_TEXT),
378
            'remove_logo'    => optional_param('remove_logo', '', PARAM_BOOL),
379
        ];
380
 
381
        $core = framework::instance();
382
        $result = $core->hubRegisterAccount($formdata, $logo);
383
 
384
        if ($result['success'] === false) {
385
            $core->h5pF->setErrorMessage($result['message']);
386
            H5PCore::ajaxError($result['message'], $result['error_code'], $result['status_code']);
387
            return;
388
        }
389
 
390
        $core->h5pF->setInfoMessage($result['message']);
391
        H5PCore::ajaxSuccess($result['message']);
392
        break;
393
 
394
    /*
395
     * Handle filtering of parameters through AJAX.
396
     */
397
    case 'getcontent':
398
        $token = required_param('token', PARAM_RAW);
399
        $hubid = required_param('hubId', PARAM_INT);
400
 
401
        $editor = \mod_hvp\framework::instance('editor');
402
        $editor->ajax->action(H5PEditorEndpoints::GET_HUB_CONTENT, $token, $hubid, null);
403
        break;
404
 
405
    /*
406
     * Handle publishing of content to the H5P OER Hub.
407
     */
408
    case 'share':
409
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
410
            http_response_code(405);
411
        }
412
        $token = required_param('_token', PARAM_RAW);
413
        $id = required_param('id', PARAM_INT);
414
 
415
        if (!\H5PCore::validToken('share_' . $id, $token)) {
416
            \H5PCore::ajaxError(get_string('invalidtoken', 'hvp'));
417
            break;
418
        }
419
 
420
        $data = array(
421
            'title'                => required_param('title', PARAM_RAW),
422
            'language'             => required_param('language', PARAM_RAW),
423
            'license'              => required_param('license', PARAM_RAW),
424
            'license_version'      => required_param('license_version', PARAM_RAW),
425
            'level'                => optional_param('level', null, PARAM_RAW),
426
            'disciplines'          => optional_param_array('disciplines', null, PARAM_RAW),
427
            'keywords'             => optional_param_array('keywords', null, PARAM_RAW),
428
            'summary'              => optional_param('summary', null, PARAM_RAW),
429
            'description'          => optional_param('description', null, PARAM_RAW),
430
            'screenshot_alt_texts' => optional_param_array('screenshot_alt_texts', null, PARAM_RAW),
431
            'remove_screenshots'   => optional_param_array('remove_screenshots', null, PARAM_RAW),
432
            'remove_icon'          => optional_param('remove_icon', null, PARAM_RAW),
433
            'age'                  => optional_param('age', null, PARAM_RAW),
434
        );
435
 
436
        // Load content.
437
        $core = \mod_hvp\framework::instance();
438
        $cm = get_coursemodule_from_id('hvp', $id);
439
        $content = $core->loadContent($cm->instance);
440
 
441
        // Update Hub status for content before proceeding.
442
        $newstate = hvp_update_hub_status($content);
443
        $synced = $newstate !== false ? $newstate : intval($content['synced']);
444
 
445
        if ($synced === \H5PContentHubSyncStatus::WAITING) {
446
            \H5PCore::ajaxError(get_string('contentissyncing', 'hvp'));
447
            break;
448
        }
449
 
450
        // Create URL.
451
        $data['download_url'] = hvp_create_hub_export_url($cm->id, $content);
452
 
453
        // Get file size.
454
        $slug = $content['slug'] ? $content['slug'] . '-' : '';
455
        $filecontext = context_course::instance($cm->course);
456
        $file = get_file_storage()->get_file($filecontext->id, 'mod_hvp', 'exports', 0, '/', "{$slug}{$content['id']}.h5p");
457
        if (!$file) {
458
            \H5PCore::ajaxError(get_string('noexport', 'hvp'));
459
            break;
460
        }
461
        $size = $file->get_filesize();
462
        $data['size'] = empty($size) ? -1 : $size;
463
 
464
        // Add the icon and any screenshots.
465
        $files = array(
466
            'icon' => !empty($_FILES['icon']) ? $_FILES['icon'] : null,
467
            'screenshots' => !empty($_FILES['screenshots']) ? $_FILES['screenshots'] : null,
468
        );
469
 
470
        try {
471
            $isedit = !empty($content['contentHubId']);
472
            $updatecontent = $synced === \H5PContentHubSyncStatus::NOT_SYNCED && $isedit;
473
            if ($updatecontent) {
474
                // Node has been edited since the last time it was published.
475
                $data['resync'] = 1;
476
            }
477
            $result = $core->hubPublishContent($data, $files, $isedit ? $content['contentHubId'] : null);
478
 
479
            $fields = array(
480
                'shared' => 1, // Content is always shared after sharing or editing.
481
            );
482
            if (!$isedit) {
483
                $fields['hub_id'] = $result->content->id;
484
                // Sync will not happen on 'edit info', only for 'publish' or 'sync'.
485
                $fields['synced'] = \H5PContentHubSyncStatus::WAITING;
486
            } else if ($updatecontent) {
487
                $fields['synced'] = \H5PContentHubSyncStatus::WAITING;
488
            }
489
 
490
            // Store the content hub id.
491
            $core->h5pF->updateContentFields($cm->instance, $fields);
492
 
493
            H5PCore::ajaxSuccess();
494
        } catch (Exception $e) {
495
            H5PCore::ajaxError(!empty($e->errors) ? $e->errors : $e->getMessage());
496
        }
497
 
498
        break;
499
 
500
    /*
501
     * Throw error if AJAX isnt handeled
502
     */
503
    default:
504
        throw new coding_exception('Unhandled AJAX');
505
        break;
506
}