MDL-61574 mod_lti: removed usage of PHP7 reserved word in namespace
[moodle.git] / mod / lti / service / toolproxy / classes / local / resources / toolproxy.php
CommitLineData
e3f69b58 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 Tool Proxy resource
19 *
20 * @package ltiservice_toolproxy
21 * @copyright 2014 Vital Source Technologies http://vitalsource.com
22 * @author Stephen Vickers
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
25
26
6fb64a4e 27namespace ltiservice_toolproxy\local\resources;
e3f69b58 28
29defined('MOODLE_INTERNAL') || die();
30
31require_once($CFG->dirroot . '/mod/lti/OAuth.php');
32require_once($CFG->dirroot . '/mod/lti/TrivialStore.php');
33
34// TODO: Switch to core oauthlib once implemented - MDL-30149.
35use moodle\mod\lti as lti;
36
37/**
38 * A resource implementing the Tool Proxy.
39 *
40 * @package ltiservice_toolproxy
41 * @since Moodle 2.8
42 * @copyright 2014 Vital Source Technologies http://vitalsource.com
43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
44 */
45class toolproxy extends \mod_lti\local\ltiservice\resource_base {
46
47 /**
48 * Class constructor.
49 *
6fb64a4e 50 * @param ltiservice_toolproxy\local\resources\toolproxy $service Service instance
e3f69b58 51 */
52 public function __construct($service) {
53
54 parent::__construct($service);
55 $this->id = 'ToolProxy.collection';
56 $this->template = '/toolproxy';
57 $this->formats[] = 'application/vnd.ims.lti.v2.toolproxy+json';
58 $this->methods[] = 'POST';
59
60 }
61
62 /**
63 * Execute the request for this resource.
64 *
65 * @param mod_lti\local\ltiservice\response $response Response object for this request.
66 */
67 public function execute($response) {
68
69 $ok = $this->check_tool_proxy(null, $response->get_request_data());
70 if ($ok) {
71 $toolproxy = $this->get_service()->get_tool_proxy();
72 } else {
73 $toolproxy = null;
74 $response->set_code(401);
75 }
76 $tools = array();
77
78 // Ensure all required elements are present in the Tool Proxy.
79 if ($ok) {
80 $toolproxyjson = json_decode($response->get_request_data());
81 $ok = !empty($toolproxyjson);
82 if (!$ok) {
83 debugging('Tool proxy is not properly formed JSON');
84 } else {
85 $ok = isset($toolproxyjson->tool_profile->product_instance->product_info->product_family->vendor->code);
86 $ok = $ok && isset($toolproxyjson->security_contract->shared_secret);
87 $ok = $ok && isset($toolproxyjson->tool_profile->resource_handler);
88 if (!$ok) {
89 debugging('One or more missing elements from tool proxy: vendor code, shared secret or resource handlers');
90 }
91 }
92 }
93
94 // Check all capabilities requested were offered.
95 if ($ok) {
96 $offeredcapabilities = explode("\n", $toolproxy->capabilityoffered);
97 $resources = $toolproxyjson->tool_profile->resource_handler;
98 $errors = array();
99 foreach ($resources as $resource) {
100 if (isset($resource->message)) {
101 foreach ($resource->message as $message) {
102 if (!in_array($message->message_type, $offeredcapabilities)) {
103 $errors[] = $message->message_type;
104 } else if (isset($resource->parameter)) {
105 foreach ($message->parameter as $parameter) {
106 if (isset($parameter->variable) && !in_array($parameter->variable, $offeredcapabilities)) {
107 $errors[] = $parameter->variable;
108 }
109 }
110 }
111 }
112 }
113 }
114 if (count($errors) > 0) {
115 $ok = false;
116 debugging('Tool proxy contains capabilities which were not offered: ' . implode(', ', $errors));
117 }
118 }
119
120 // Check all services requested were offered (only tool services currently supported).
121 if ($ok && isset($toolproxyjson->security_contract->tool_service)) {
122 $contexts = lti_get_contexts($toolproxyjson);
123 $profileservice = lti_get_service_by_name('profile');
124 $profileservice->set_tool_proxy($toolproxy);
125 $context = $profileservice->get_service_path() . $profileservice->get_resources()[0]->get_path() . '#';
126 $offeredservices = explode("\n", $toolproxy->serviceoffered);
127 $services = lti_get_services();
128 $tpservices = $toolproxyjson->security_contract->tool_service;
129 $errors = array();
130 foreach ($tpservices as $service) {
131 $fqid = lti_get_fqid($contexts, $service->service);
132 if (substr($fqid, 0, strlen($context)) !== $context) {
133 $errors[] = $service->service;
134 } else {
135 $id = explode('#', $fqid, 2);
136 $aservice = lti_get_service_by_resource_id($services, $id[1]);
137 $classname = explode('\\', get_class($aservice));
138 if (empty($aservice) || !in_array($classname[count($classname) - 1], $offeredservices)) {
139 $errors[] = $service->service;
140 }
141 }
142 }
143 if (count($errors) > 0) {
144 $ok = false;
145 debugging('Tool proxy contains services which were not offered: ' . implode(', ', $errors));
146 }
147 }
148
149 // Extract all launchable tools from the resource handlers.
150 if ($ok) {
151 $resources = $toolproxyjson->tool_profile->resource_handler;
c1fae2b9
JP
152 $messagetypes = [
153 'basic-lti-launch-request',
154 'ContentItemSelectionRequest',
155 ];
e3f69b58 156 foreach ($resources as $resource) {
d8f9109a 157 $launchable = false;
158 $messages = array();
e3f69b58 159 $tool = new \stdClass();
d51757a7
JO
160
161 $iconinfo = null;
162 if (is_array($resource->icon_info)) {
163 $iconinfo = $resource->icon_info[0];
164 } else {
165 $iconinfo = $resource->icon_info;
166 }
167 if (isset($iconinfo) && isset($iconinfo->default_location) && isset($iconinfo->default_location->path)) {
168 $tool->iconpath = $iconinfo->default_location->path;
169 }
170
e3f69b58 171 foreach ($resource->message as $message) {
c1fae2b9 172 if (in_array($message->message_type, $messagetypes)) {
d8f9109a 173 $launchable = $launchable || ($message->message_type === 'basic-lti-launch-request');
174 $messages[$message->message_type] = $message;
e3f69b58 175 }
176 }
d8f9109a 177 if (!$launchable) {
e3f69b58 178 continue;
179 }
e3f69b58 180 $tool->name = $resource->resource_name->default_value;
d8f9109a 181 $tool->messages = $messages;
e3f69b58 182 $tools[] = $tool;
183 }
184 $ok = count($tools) > 0;
185 if (!$ok) {
186 debugging('No launchable messages found in tool proxy');
187 }
188 }
189
190 // Add tools and custom parameters.
191 if ($ok) {
192 $baseurl = '';
193 if (isset($toolproxyjson->tool_profile->base_url_choice[0]->default_base_url)) {
194 $baseurl = $toolproxyjson->tool_profile->base_url_choice[0]->default_base_url;
195 }
196 $securebaseurl = '';
197 if (isset($toolproxyjson->tool_profile->base_url_choice[0]->secure_base_url)) {
198 $securebaseurl = $toolproxyjson->tool_profile->base_url_choice[0]->secure_base_url;
199 }
200 foreach ($tools as $tool) {
d8f9109a 201 $messages = $tool->messages;
c1fae2b9 202 $launchrequest = $messages['basic-lti-launch-request'];
e3f69b58 203 $config = new \stdClass();
c1fae2b9 204 $config->lti_toolurl = "{$baseurl}{$launchrequest->path}";
e3f69b58 205 $config->lti_typename = $tool->name;
206 $config->lti_coursevisible = 1;
207 $config->lti_forcessl = 0;
d8f9109a 208 if (isset($messages['ContentItemSelectionRequest'])) {
c1fae2b9 209 $contentitemrequest = $messages['ContentItemSelectionRequest'];
d8f9109a 210 $config->lti_contentitem = 1;
c1fae2b9
JP
211 if ($launchrequest->path !== $contentitemrequest->path) {
212 $config->lti_toolurl_ContentItemSelectionRequest = $baseurl . $contentitemrequest->path;
d8f9109a 213 }
c1fae2b9
JP
214 $contentitemcapabilities = implode("\n", $contentitemrequest->enabled_capability);
215 $config->lti_enabledcapability_ContentItemSelectionRequest = $contentitemcapabilities;
216 $contentitemparams = self::lti_extract_parameters($contentitemrequest->parameter);
217 $config->lti_parameter_ContentItemSelectionRequest = $contentitemparams;
d8f9109a 218 }
e3f69b58 219
220 $type = new \stdClass();
221 $type->state = LTI_TOOL_STATE_PENDING;
222 $type->toolproxyid = $toolproxy->id;
c1fae2b9
JP
223 $type->enabledcapability = implode("\n", $launchrequest->enabled_capability);
224 $type->parameter = self::lti_extract_parameters($launchrequest->parameter);
e3f69b58 225
d51757a7
JO
226 if (!empty($tool->iconpath)) {
227 $type->icon = "{$baseurl}{$tool->iconpath}";
e3f69b58 228 if (!empty($securebaseurl)) {
d51757a7 229 $type->secureicon = "{$securebaseurl}{$tool->iconpath}";
e3f69b58 230 }
231 }
d51757a7 232
e3f69b58 233 $ok = $ok && (lti_add_type($type, $config) !== false);
234 }
235 if (isset($toolproxyjson->custom)) {
236 lti_set_tool_settings($toolproxyjson->custom, $toolproxy->id);
237 }
238 }
239
240 if (!empty($toolproxy)) {
241 if ($ok) {
242 // If all went OK accept the tool proxy.
243 $toolproxy->state = LTI_TOOL_PROXY_STATE_ACCEPTED;
244 $toolproxy->toolproxy = $response->get_request_data();
245 $toolproxy->secret = $toolproxyjson->security_contract->shared_secret;
246 $toolproxy->vendorcode = $toolproxyjson->tool_profile->product_instance->product_info->product_family->vendor->code;
247
248 $url = $this->get_endpoint();
249 $body = <<< EOD
250{
251 "@context" : "http://purl.imsglobal.org/ctx/lti/v2/ToolProxyId",
252 "@type" : "ToolProxy",
253 "@id" : "{$url}",
254 "tool_proxy_guid" : "{$toolproxy->guid}"
255}
256EOD;
257 $response->set_code(201);
258 $response->set_content_type('application/vnd.ims.lti.v2.toolproxy.id+json');
259 $response->set_body($body);
260 } else {
261 // Otherwise reject the tool proxy.
262 $toolproxy->state = LTI_TOOL_PROXY_STATE_REJECTED;
263 $response->set_code(400);
264 }
265 lti_update_tool_proxy($toolproxy);
266 } else {
267 $response->set_code(400);
268 }
269 }
270
271 /**
272 * Extracts the message parameters from the tool proxy entry
273 *
274 * @param array $parameters Parameter section of a message
275 *
276 * @return String containing parameters
277 */
278 private static function lti_extract_parameters($parameters) {
279
280 $params = array();
281 foreach ($parameters as $parameter) {
282 if (isset($parameter->variable)) {
283 $value = '$' . $parameter->variable;
284 } else {
285 $value = $parameter->fixed;
286 if (strlen($value) > 0) {
287 $first = substr($value, 0, 1);
288 if (($first == '$') || ($first == '\\')) {
289 $value = '\\' . $value;
290 }
291 }
292 }
293 $params[] = "{$parameter->name}={$value}";
294 }
295
296 return implode("\n", $params);
297
298 }
299
300}