See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]
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 file contains a class definition for the LineItem resource 19 * 20 * @package ltiservice_gradebookservices 21 * @copyright 2017 Cengage Learning http://www.cengage.com 22 * @author Dirk Singels, Diego del Blanco, Claude Vervoort 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 namespace ltiservice_gradebookservices\local\resources; 27 28 use ltiservice_gradebookservices\local\service\gradebookservices; 29 use mod_lti\local\ltiservice\resource_base; 30 31 defined('MOODLE_INTERNAL') || die(); 32 33 /** 34 * A resource implementing LineItem. 35 * 36 * @package ltiservice_gradebookservices 37 * @copyright 2017 Cengage Learning http://www.cengage.com 38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 39 */ 40 class lineitem extends resource_base { 41 42 /** 43 * Class constructor. 44 * 45 * @param gradebookservices $service Service instance 46 */ 47 public function __construct($service) { 48 49 parent::__construct($service); 50 $this->id = 'LineItem.item'; 51 $this->template = '/{context_id}/lineitems/{item_id}/lineitem'; 52 $this->variables[] = 'LineItem.url'; 53 $this->formats[] = 'application/vnd.ims.lis.v2.lineitem+json'; 54 $this->methods[] = self::HTTP_GET; 55 $this->methods[] = self::HTTP_PUT; 56 $this->methods[] = self::HTTP_DELETE; 57 58 } 59 60 /** 61 * Execute the request for this resource. 62 * 63 * @param \mod_lti\local\ltiservice\response $response Response object for this request. 64 */ 65 public function execute($response) { 66 global $CFG, $DB; 67 68 $params = $this->parse_template(); 69 $contextid = $params['context_id']; 70 $itemid = $params['item_id']; 71 $isget = $response->get_request_method() === self::HTTP_GET; 72 // We will receive typeid when working with LTI 1.x, if not then we are in LTI 2. 73 $typeid = optional_param('type_id', null, PARAM_INT); 74 75 $scopes = array(gradebookservices::SCOPE_GRADEBOOKSERVICES_LINEITEM); 76 if ($response->get_request_method() === self::HTTP_GET) { 77 $scopes[] = gradebookservices::SCOPE_GRADEBOOKSERVICES_LINEITEM_READ; 78 } 79 80 try { 81 if (!$this->check_tool($typeid, $response->get_request_data(), $scopes)) { 82 throw new \Exception(null, 401); 83 } 84 $typeid = $this->get_service()->get_type()->id; 85 if (!($course = $DB->get_record('course', array('id' => $contextid), 'id', IGNORE_MISSING))) { 86 throw new \Exception("Not Found: Course {$contextid} doesn't exist", 404); 87 } 88 if (!$this->get_service()->is_allowed_in_context($typeid, $course->id)) { 89 throw new \Exception('Not allowed in context', 403); 90 } 91 if (!$DB->record_exists('grade_items', array('id' => $itemid))) { 92 throw new \Exception("Not Found: Grade item {$itemid} doesn't exist", 404); 93 } 94 $item = $this->get_service()->get_lineitem($contextid, $itemid, $typeid); 95 if ($item === false) { 96 throw new \Exception('Line item does not exist', 404); 97 } 98 require_once($CFG->libdir.'/gradelib.php'); 99 switch ($response->get_request_method()) { 100 case self::HTTP_GET: 101 $this->get_request($response, $item, $typeid); 102 break; 103 case self::HTTP_PUT: 104 $json = $this->process_put_request($response->get_request_data(), $item, $typeid); 105 $response->set_body($json); 106 $response->set_code(200); 107 break; 108 case self::HTTP_DELETE: 109 $this->process_delete_request($item); 110 $response->set_code(204); 111 break; 112 } 113 } catch (\Exception $e) { 114 $response->set_code($e->getCode()); 115 $response->set_reason($e->getMessage()); 116 } 117 } 118 119 /** 120 * Process a GET request. 121 * 122 * @param \mod_lti\local\ltiservice\response $response Response object for this request. 123 * @param object $item Grade item instance. 124 * @param string $typeid Tool Type Id 125 */ 126 private function get_request($response, $item, $typeid) { 127 128 $response->set_content_type($this->formats[0]); 129 $lineitem = gradebookservices::item_for_json($item, substr(parent::get_endpoint(), 130 0, strrpos(parent::get_endpoint(), "/", -10)), $typeid); 131 $response->set_body(json_encode($lineitem)); 132 133 } 134 135 /** 136 * Process a PUT request. 137 * 138 * @param string $body PUT body 139 * @param \ltiservice_gradebookservices\local\resources\lineitem $olditem Grade item instance 140 * @param string $typeid Tool Type Id 141 * 142 * @return string 143 * @throws \Exception 144 */ 145 private function process_put_request($body, $olditem, $typeid) { 146 global $DB; 147 $json = json_decode($body); 148 if (empty($json) || 149 !isset($json->scoreMaximum) || 150 !isset($json->label)) { 151 throw new \Exception(null, 400); 152 } 153 $item = \grade_item::fetch(array('id' => $olditem->id, 'courseid' => $olditem->courseid)); 154 $gbs = gradebookservices::find_ltiservice_gradebookservice_for_lineitem($olditem->id); 155 $updategradeitem = false; 156 $rescalegrades = false; 157 $oldgrademax = grade_floatval($item->grademax); 158 $upgradegradebookservices = false; 159 if ($item->itemname !== $json->label) { 160 $updategradeitem = true; 161 } 162 $item->itemname = $json->label; 163 if (!is_numeric($json->scoreMaximum)) { 164 throw new \Exception(null, 400); 165 } else { 166 if (grade_floats_different($oldgrademax, 167 grade_floatval($json->scoreMaximum))) { 168 $updategradeitem = true; 169 $rescalegrades = true; 170 } 171 $item->grademax = grade_floatval($json->scoreMaximum); 172 } 173 if ($gbs) { 174 $resourceid = (isset($json->resourceId)) ? $json->resourceId : ''; 175 $tag = (isset($json->tag)) ? $json->tag : ''; 176 if ($gbs->tag !== $tag || $gbs->resourceid !== $resourceid) { 177 $upgradegradebookservices = true; 178 } 179 $gbs->tag = $tag; 180 $gbs->resourceid = $resourceid; 181 $incomingurl = null; 182 $incomingparams = null; 183 if (isset($json->submissionReview)) { 184 $incomingurl = $json->submissionReview->url ?? 'DEFAULT'; 185 if (isset($json->submissionReview->custom)) { 186 $incomingparams = params_to_string($json->submissionReview->custom); 187 } 188 } 189 if ($gbs->subreviewurl ?? null !== $incomingurl || $gbs->subreviewparams ?? null !== $incomingparams) { 190 $upgradegradebookservices = true; 191 $gbs->subreviewurl = $incomingurl; 192 $gbs->subreviewparams = $incomingparams; 193 } 194 } 195 $ltilinkid = null; 196 if (isset($json->resourceLinkId)) { 197 if (is_numeric($json->resourceLinkId)) { 198 $ltilinkid = $json->resourceLinkId; 199 if ($gbs) { 200 if (intval($gbs->ltilinkid) !== intval($json->resourceLinkId)) { 201 $gbs->ltilinkid = $json->resourceLinkId; 202 $upgradegradebookservices = true; 203 } 204 } else { 205 if (intval($item->iteminstance) !== intval($json->resourceLinkId)) { 206 $item->iteminstance = intval($json->resourceLinkId); 207 $updategradeitem = true; 208 } 209 } 210 } else { 211 throw new \Exception(null, 400); 212 } 213 } else if (isset($json->ltiLinkId)) { 214 if (is_numeric($json->ltiLinkId)) { 215 $ltilinkid = $json->ltiLinkId; 216 if ($gbs) { 217 if (intval($gbs->ltilinkid) !== intval($json->ltiLinkId)) { 218 $gbs->ltilinkid = $json->ltiLinkId; 219 $upgradegradebookservices = true; 220 } 221 } else { 222 if (intval($item->iteminstance) !== intval($json->ltiLinkId)) { 223 $item->iteminstance = intval($json->ltiLinkId); 224 $updategradeitem = true; 225 } 226 } 227 } else { 228 throw new \Exception(null, 400); 229 } 230 } 231 if ($ltilinkid != null) { 232 if (is_null($typeid)) { 233 if (!gradebookservices::check_lti_id($ltilinkid, $item->courseid, 234 $this->get_service()->get_tool_proxy()->id)) { 235 throw new \Exception(null, 403); 236 } 237 } else { 238 if (!gradebookservices::check_lti_1x_id($ltilinkid, $item->courseid, 239 $typeid)) { 240 throw new \Exception(null, 403); 241 } 242 } 243 } 244 if ($updategradeitem) { 245 if (!$item->update('mod/ltiservice_gradebookservices')) { 246 throw new \Exception(null, 500); 247 } 248 if ($rescalegrades) { 249 $item->rescale_grades_keep_percentage(0, $oldgrademax, 0, $item->grademax); 250 } 251 } 252 253 $lineitem = new lineitem($this->get_service()); 254 $endpoint = $lineitem->get_endpoint(); 255 256 if ($upgradegradebookservices) { 257 if (is_null($typeid)) { 258 $toolproxyid = $this->get_service()->get_tool_proxy()->id; 259 $baseurl = null; 260 } else { 261 $toolproxyid = null; 262 $baseurl = lti_get_type_type_config($typeid)->lti_toolurl; 263 } 264 $DB->update_record('ltiservice_gradebookservices', (object)array( 265 'id' => $gbs->id, 266 'gradeitemid' => $gbs->gradeitemid, 267 'courseid' => $gbs->courseid, 268 'toolproxyid' => $toolproxyid, 269 'typeid' => $typeid, 270 'baseurl' => $baseurl, 271 'ltilinkid' => $ltilinkid, 272 'resourceid' => $resourceid, 273 'tag' => $gbs->tag, 274 'subreviewurl' => $gbs->subreviewurl, 275 'subreviewparams' => $gbs->subreviewparams 276 )); 277 } 278 279 if (is_null($typeid)) { 280 $id = "{$endpoint}"; 281 $json->id = $id; 282 } else { 283 $id = "{$endpoint}?type_id={$typeid}"; 284 $json->id = $id; 285 } 286 return json_encode($json, JSON_UNESCAPED_SLASHES); 287 288 } 289 290 /** 291 * Process a DELETE request. 292 * 293 * @param \ltiservice_gradebookservices\local\resources\lineitem $item Grade item instance 294 * @throws \Exception 295 */ 296 private function process_delete_request($item) { 297 global $DB; 298 299 $gradeitem = \grade_item::fetch(array('id' => $item->id)); 300 if (($gbs = gradebookservices::find_ltiservice_gradebookservice_for_lineitem($item->id)) == false) { 301 throw new \Exception(null, 403); 302 } 303 if (!$gradeitem->delete('mod/ltiservice_gradebookservices')) { 304 throw new \Exception(null, 500); 305 } else { 306 $sqlparams = array(); 307 $sqlparams['id'] = $gbs->id; 308 if (!$DB->delete_records('ltiservice_gradebookservices', $sqlparams)) { 309 throw new \Exception(null, 500); 310 } 311 } 312 } 313 314 /** 315 * Parse a value for custom parameter substitution variables. 316 * 317 * @param string $value String to be parsed 318 * 319 * @return string 320 */ 321 public function parse_value($value) { 322 global $COURSE, $CFG; 323 if (strpos($value, '$LineItem.url') !== false) { 324 $resolved = ''; 325 require_once($CFG->libdir . '/gradelib.php'); 326 327 $this->params['context_id'] = $COURSE->id; 328 if ($tool = $this->get_service()->get_type()) { 329 $this->params['tool_code'] = $tool->id; 330 } 331 $id = optional_param('id', 0, PARAM_INT); // Course Module ID. 332 if (empty($id)) { 333 $hint = optional_param('lti_message_hint', "", PARAM_TEXT); 334 if ($hint) { 335 $hintdec = json_decode($hint); 336 if (isset($hintdec->cmid)) { 337 $id = $hintdec->cmid; 338 } 339 } 340 } 341 if (!empty($id)) { 342 $cm = get_coursemodule_from_id('lti', $id, 0, false, MUST_EXIST); 343 $id = $cm->instance; 344 $item = grade_get_grades($COURSE->id, 'mod', 'lti', $id); 345 if ($item && $item->items) { 346 $this->params['item_id'] = $item->items[0]->id; 347 $resolved = parent::get_endpoint(); 348 $resolved .= "?type_id={$tool->id}"; 349 } 350 } 351 $value = str_replace('$LineItem.url', $resolved, $value); 352 } 353 return $value; 354 } 355 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body