See Release Notes
Long Term Support Release
Differences Between: [Versions 401 and 402] [Versions 401 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 * This is the external API for generic xAPI handling. 19 * 20 * @package core_xapi 21 * @since Moodle 3.9 22 * @copyright 2020 Ferran Recio 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 namespace core_xapi\external; 27 28 use core_xapi\local\statement; 29 use core_xapi\handler; 30 use core_xapi\xapi_exception; 31 use external_api; 32 use external_function_parameters; 33 use external_value; 34 use external_single_structure; 35 use external_multiple_structure; 36 use external_warnings; 37 use core_component; 38 39 defined('MOODLE_INTERNAL') || die(); 40 41 require_once($CFG->libdir .'/externallib.php'); 42 43 /** 44 * This is the external API for generic xAPI handling. 45 * 46 * @copyright 2020 Ferran Recio 47 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 48 */ 49 class post_statement extends external_api { 50 51 /** 52 * Parameters for execute 53 * 54 * @return external_function_parameters 55 */ 56 public static function execute_parameters() { 57 return new external_function_parameters( 58 [ 59 'component' => new external_value(PARAM_COMPONENT, 'Component name', VALUE_REQUIRED), 60 'requestjson' => new external_value(PARAM_RAW, 'json object with all the statements to post', VALUE_REQUIRED) 61 ] 62 ); 63 } 64 65 /** 66 * Process a statement post request. 67 * 68 * @param string $component component name (frankenstyle) 69 * @param string $requestjson json object with all the statements to post 70 * @return bool[] storing acceptance of every statement 71 */ 72 public static function execute(string $component, string $requestjson): array { 73 74 $params = self::validate_parameters(self::execute_parameters(), array( 75 'component' => $component, 76 'requestjson' => $requestjson, 77 )); 78 $component = $params['component']; 79 $requestjson = $params['requestjson']; 80 81 static::validate_component($component); 82 83 $handler = handler::create($component); 84 85 $statements = self::get_statements_from_json($requestjson); 86 87 if (!self::check_statements_users($statements, $handler)) { 88 throw new xapi_exception('Statements actor is not the current user'); 89 } 90 91 $result = $handler->process_statements($statements); 92 93 // In case no statement is processed, an error must be returned. 94 if (count(array_filter($result)) == 0) { 95 throw new xapi_exception('No statement can be processed.'); 96 } 97 return $result; 98 } 99 100 /** 101 * Return for execute. 102 */ 103 public static function execute_returns() { 104 return new external_multiple_structure( 105 new external_value(PARAM_BOOL, 'If the statement is accepted'), 106 'List of statements storing acceptance results' 107 ); 108 } 109 110 /** 111 * Check component name. 112 * 113 * Note: this function is separated mainly for testing purposes to 114 * be overridden to fake components. 115 * 116 * @throws xapi_exception if component is not available 117 * @param string $component component name 118 */ 119 protected static function validate_component(string $component): void { 120 // Check that $component is a real component name. 121 $dir = core_component::get_component_directory($component); 122 if (!$dir) { 123 throw new xapi_exception("Component $component not available."); 124 } 125 } 126 127 /** 128 * Convert mulitple types of statement request into an array of statements. 129 * 130 * @throws xapi_exception if JSON cannot be parsed 131 * @param string $requestjson json encoded statements structure 132 * @return statement[] array of statements 133 */ 134 private static function get_statements_from_json(string $requestjson): array { 135 $request = json_decode($requestjson); 136 if ($request === null) { 137 throw new xapi_exception('JSON error: '.json_last_error_msg()); 138 } 139 $result = []; 140 if (is_array($request)) { 141 foreach ($request as $data) { 142 $result[] = statement::create_from_data($data); 143 } 144 } else { 145 $result[] = statement::create_from_data($request); 146 } 147 if (empty($result)) { 148 throw new xapi_exception('No statements detected'); 149 } 150 return $result; 151 } 152 153 /** 154 * Check that $USER is actor in all statements. 155 * 156 * @param statement[] $statements array of statements 157 * @param handler $handler specific xAPI handler 158 * @return bool if $USER is actor in all statements 159 */ 160 private static function check_statements_users(array $statements, handler $handler): bool { 161 global $USER; 162 163 foreach ($statements as $statement) { 164 if ($handler->supports_group_actors()) { 165 $users = $statement->get_all_users(); 166 if (!isset($users[$USER->id])) { 167 return false; 168 } 169 } else { 170 $user = $statement->get_user(); 171 if ($user->id != $USER->id) { 172 return false; 173 } 174 } 175 } 176 return true; 177 } 178 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body