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