PageRenderTime 35ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/mod/lti/service/gradebookservices/classes/local/resources/lineitem.php

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