ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
class.ilLTIToolProvider.php
Go to the documentation of this file.
1<?php
2
3/* Copyright (c) 1998-2010 ILIAS open source, Extended GPL, see docs/LICENSE */
4
12
13
18
27{
31 protected $logger = null;
32
33
34 public $debugMode = true; //ACHTUNG weg bei Produktiv-Umgebung
38 private static $LTI_VERSIONS = array(self::LTI_VERSION1, self::LTI_VERSION2);
42 private static $MESSAGE_TYPES = array('basic-lti-launch-request' => 'onLaunch',
43 'ContentItemSelectionRequest' => 'onContentItem',
44 'ToolProxyRegistrationRequest' => 'register');
50 private static $METHOD_NAMES = array('basic-lti-launch-request' => 'onLaunch',
51 'ContentItemSelectionRequest' => 'onContentItem',
52 'ToolProxyRegistrationRequest' => 'onRegister');
58 private static $LTI_CONSUMER_SETTING_NAMES = array('custom_tc_profile_url', 'custom_system_setting_url');
64 private static $LTI_CONTEXT_SETTING_NAMES = array('custom_context_setting_url',
65 'custom_lineitems_url', 'custom_results_url',
66 'custom_context_memberships_url');
72 private static $LTI_RESOURCE_LINK_SETTING_NAMES = array('lis_result_sourcedid', 'lis_outcome_service_url',
73 'ext_ims_lis_basic_outcome_url', 'ext_ims_lis_resultvalue_sourcedids',
74 'ext_ims_lis_memberships_id', 'ext_ims_lis_memberships_url',
75 'ext_ims_lti_tool_setting', 'ext_ims_lti_tool_setting_id', 'ext_ims_lti_tool_setting_url',
76 'custom_link_setting_url',
77 'custom_lineitem_url', 'custom_result_url');
83 private static $CUSTOM_SUBSTITUTION_VARIABLES = array('User.id' => 'user_id',
84 'User.image' => 'user_image',
85 'User.username' => 'username',
86 'User.scope.mentor' => 'role_scope_mentor',
87 'Membership.role' => 'roles',
88 'Person.sourcedId' => 'lis_person_sourcedid',
89 'Person.name.full' => 'lis_person_name_full',
90 'Person.name.family' => 'lis_person_name_family',
91 'Person.name.given' => 'lis_person_name_given',
92 'Person.email.primary' => 'lis_person_contact_email_primary',
93 'Context.id' => 'context_id',
94 'Context.type' => 'context_type',
95 'Context.title' => 'context_title',
96 'Context.label' => 'context_label',
97 'CourseOffering.sourcedId' => 'lis_course_offering_sourcedid',
98 'CourseSection.sourcedId' => 'lis_course_section_sourcedid',
99 'CourseSection.label' => 'context_label',
100 'CourseSection.title' => 'context_title',
101 'ResourceLink.id' => 'resource_link_id',
102 'ResourceLink.title' => 'resource_link_title',
103 'ResourceLink.description' => 'resource_link_description',
104 'Result.sourcedId' => 'lis_result_sourcedid',
105 'BasicOutcome.url' => 'lis_outcome_service_url',
106 'ToolConsumerProfile.url' => 'custom_tc_profile_url',
107 'ToolProxy.url' => 'tool_proxy_url',
108 'ToolProxy.custom.url' => 'custom_system_setting_url',
109 'ToolProxyBinding.custom.url' => 'custom_context_setting_url',
110 'LtiLink.custom.url' => 'custom_link_setting_url',
111 'LineItems.url' => 'custom_lineitems_url',
112 'LineItem.url' => 'custom_lineitem_url',
113 'Results.url' => 'custom_results_url',
114 'Result.url' => 'custom_result_url',
115 'ToolProxyBinding.memberships.url' => 'custom_context_memberships_url');
116
117
122 public function __construct(DataConnector $dataConnector)
123 {
124 global $DIC;
125
126 $this->logger = $DIC->logger()->lti();
127 parent::__construct($dataConnector);
128 }
129
130
134 public function handleRequest()
135 {
136 if ($this->ok) {
137 if ($this->authenticate()) {
138 $this->doCallback();
139 }
140 }
141 // if return url is given, this redirects in case of errors
142 $this->result();
143 return $this->ok;
144 }
145
146 ###
147 ### PROTECTED METHODS
148 ###
149
155 protected function onLaunch()
156 {
157 // save/update current user
158 if ($this->user instanceof User) {
159 $this->user->save();
160 }
161
162 if ($this->context instanceof Context) {
163 $this->context->save();
164 }
165
166 if ($this->resourceLink instanceof ResourceLink) {
167 $this->resourceLink->save();
168 }
169 }
170
176 protected function onContentItem()
177 {
178 $this->onError();
179 }
180
186 protected function onRegister()
187 {
188 $this->onError();
189 }
190
196 protected function onError()
197 {
198 // only return error status
199 return $this->ok;
200
201 //$this->doCallback('onError');
202 // return parent::onError(); //Stefan M.
203 }
204
205 ###
206 ### PRIVATE METHODS
207 ###
208
216 private function doCallback($method = null)
217 {
218 $callback = $method;
219 if (is_null($callback)) {
220 $callback = self::$METHOD_NAMES[$_POST['lti_message_type']];
221 }
222 if (method_exists($this, $callback)) {
223 $result = $this->$callback(); // ACHTUNG HIER PROBLEM UK
224 } elseif (is_null($method) && $this->ok) {
225 $this->ok = false;
226 $this->reason = "Message type not supported: {$_POST['lti_message_type']}";
227 }
228 if ($this->ok && ($_POST['lti_message_type'] == 'ToolProxyRegistrationRequest')) {
229 $this->consumer->save();
230 }
231 }
232
240 private function result()
241 {
242 $ok = false;
243 if (!$this->ok) {
244 $ok = $this->onError();
245 }
246 if (!$ok) {
247 if (!$this->ok) {
248 // If not valid, return an error message to the tool consumer if a return URL is provided
249 if (!empty($this->returnUrl)) {
250 $errorUrl = $this->returnUrl;
251 if (strpos($errorUrl, '?') === false) {
252 $errorUrl .= '?';
253 } else {
254 $errorUrl .= '&';
255 }
256 if ($this->debugMode && !is_null($this->reason)) {
257 $errorUrl .= 'lti_errormsg=' . urlencode("Debug error: $this->reason");
258 } else {
259 $errorUrl .= 'lti_errormsg=' . urlencode($this->message);
260 if (!is_null($this->reason)) {
261 $errorUrl .= '&lti_errorlog=' . urlencode("Debug error: $this->reason");
262 }
263 }
264 if (!is_null($this->consumer) && isset($_POST['lti_message_type']) && ($_POST['lti_message_type'] === 'ContentItemSelectionRequest')) {
265 $formParams = array();
266 if (isset($_POST['data'])) {
267 $formParams['data'] = $_POST['data'];
268 }
269 $version = (isset($_POST['lti_version'])) ? $_POST['lti_version'] : self::LTI_VERSION1;
270 $formParams = $this->consumer->signParameters($errorUrl, 'ContentItemSelection', $version, $formParams);
271 $page = self::sendForm($errorUrl, $formParams);
272 echo $page;
273 } else {
274 header("Location: {$errorUrl}");
275 }
276 exit; //ACHTUNG HIER PROBLEM UK
277 } else {
278 if (!is_null($this->errorOutput)) {
279 echo $this->errorOutput;
280 } elseif ($this->debugMode && !empty($this->reason)) {
281 echo "Debug error: {$this->reason}";
282 } else {
283 echo "Error: {$this->message}";
284 }
285 }
286 } elseif (!is_null($this->redirectUrl)) {
287 header("Location: {$this->redirectUrl}");
288 exit;
289 } elseif (!is_null($this->output)) {
290 echo $this->output;
291 }
292 }
293 }
294
302 private function authenticate()
303 {
304
305// Get the consumer
306 $doSaveConsumer = false;
307 // Check all required launch parameters
308 $this->ok = isset($_POST['lti_message_type']) && array_key_exists($_POST['lti_message_type'], self::$MESSAGE_TYPES);
309 if (!$this->ok) {
310 $this->reason = 'Invalid or missing lti_message_type parameter.';
311 }
312 if ($this->ok) {
313 $this->ok = isset($_POST['lti_version']) && in_array($_POST['lti_version'], self::$LTI_VERSIONS);
314 if (!$this->ok) {
315 $this->reason = 'Invalid or missing lti_version parameter.';
316 }
317 }
318 if ($this->ok) {
319 if ($_POST['lti_message_type'] === 'basic-lti-launch-request') {
320 $this->ok = isset($_POST['resource_link_id']) && (strlen(trim($_POST['resource_link_id'])) > 0);
321 if (!$this->ok) {
322 $this->reason = 'Missing resource link ID.';
323 }
324 } elseif ($_POST['lti_message_type'] === 'ContentItemSelectionRequest') {
325 if (isset($_POST['accept_media_types']) && (strlen(trim($_POST['accept_media_types'])) > 0)) {
326 $mediaTypes = array_filter(explode(',', str_replace(' ', '', $_POST['accept_media_types'])), 'strlen');
327 $mediaTypes = array_unique($mediaTypes);
328 $this->ok = count($mediaTypes) > 0;
329 if (!$this->ok) {
330 $this->reason = 'No accept_media_types found.';
331 } else {
332 $this->mediaTypes = $mediaTypes;
333 }
334 } else {
335 $this->ok = false;
336 }
337 if ($this->ok && isset($_POST['accept_presentation_document_targets']) && (strlen(trim($_POST['accept_presentation_document_targets'])) > 0)) {
338 $documentTargets = array_filter(explode(',', str_replace(' ', '', $_POST['accept_presentation_document_targets'])), 'strlen');
339 $documentTargets = array_unique($documentTargets);
340 $this->ok = count($documentTargets) > 0;
341 if (!$this->ok) {
342 $this->reason = 'Missing or empty accept_presentation_document_targets parameter.';
343 } else {
344 foreach ($documentTargets as $documentTarget) {
345 $this->ok = $this->checkValue(
346 $documentTarget,
347 array('embed', 'frame', 'iframe', 'window', 'popup', 'overlay', 'none'),
348 'Invalid value in accept_presentation_document_targets parameter: %s.'
349 );
350 if (!$this->ok) {
351 break;
352 }
353 }
354 if ($this->ok) {
355 $this->documentTargets = $documentTargets;
356 }
357 }
358 } else {
359 $this->ok = false;
360 }
361 if ($this->ok) {
362 $this->ok = isset($_POST['content_item_return_url']) && (strlen(trim($_POST['content_item_return_url'])) > 0);
363 if (!$this->ok) {
364 $this->reason = 'Missing content_item_return_url parameter.';
365 }
366 }
367 } elseif ($_POST['lti_message_type'] == 'ToolProxyRegistrationRequest') {
368 $this->ok = ((isset($_POST['reg_key']) && (strlen(trim($_POST['reg_key'])) > 0)) &&
369 (isset($_POST['reg_password']) && (strlen(trim($_POST['reg_password'])) > 0)) &&
370 (isset($_POST['tc_profile_url']) && (strlen(trim($_POST['tc_profile_url'])) > 0)) &&
371 (isset($_POST['launch_presentation_return_url']) && (strlen(trim($_POST['launch_presentation_return_url'])) > 0)));
372 if ($this->debugMode && !$this->ok) {
373 $this->reason = 'Missing message parameters.';
374 }
375 }
376 }
377 $now = time();
378
379 $this->logger->debug('Checking consumer key...');
380
381 // Check consumer key
382 if ($this->ok && ($_POST['lti_message_type'] != 'ToolProxyRegistrationRequest')) {
383 $this->ok = isset($_POST['oauth_consumer_key']);
384 if (!$this->ok) {
385 $this->reason = 'Missing consumer key.';
386 }
387 if ($this->ok) {
388 // $this->consumer = new ToolConsumer($_POST['oauth_consumer_key'], $this->dataConnector);
389 $this->consumer = new ilLTIToolConsumer($_POST['oauth_consumer_key'], $this->dataConnector);
390 $this->ok = !is_null($this->consumer->created);
391 if (!$this->ok) {
392 $this->reason = 'Invalid consumer key.';
393 }
394 }
395 if ($this->ok) {
396 $today = date('Y-m-d', $now);
397 if (is_null($this->consumer->lastAccess)) {
398 $doSaveConsumer = true;
399 } else {
400 $last = date('Y-m-d', $this->consumer->lastAccess);
401 $doSaveConsumer = $doSaveConsumer || ($last !== $today);
402 }
403 $this->consumer->last_access = $now;
404 try {
405 $store = new OAuthDataStore($this);
408 $server->add_signature_method($method);
409 $request = OAuth\OAuthRequest::from_request();
410 $res = $server->verify_request($request);
411 } catch (\Exception $e) {
412 $this->ok = false;
413 if (empty($this->reason)) {
414 if ($this->debugMode) {
415 $consumer = new OAuth\OAuthConsumer($this->consumer->getKey(), $this->consumer->secret);
416 $signature = $request->build_signature($method, $consumer, false);
417 $this->reason = $e->getMessage();
418 if (empty($this->reason)) {
419 $this->reason = 'OAuth exception';
420 }
421 $this->details[] = 'Timestamp: ' . time();
422 $this->details[] = "Signature: {$signature}";
423 $this->details[] = "Base string: {$request->base_string}]";
424 } else {
425 $this->reason = 'OAuth signature check failed - perhaps an incorrect secret or timestamp.';
426 }
427 }
428 }
429 }
430 // $this->ok = true; //ACHTUNG Problem Signature bei M.
431 if ($this->ok) {
432 $today = date('Y-m-d', $now);
433 if (is_null($this->consumer->lastAccess)) {
434 $doSaveConsumer = true;
435 } else {
436 $last = date('Y-m-d', $this->consumer->lastAccess);
437 $doSaveConsumer = $doSaveConsumer || ($last !== $today);
438 }
439 $this->consumer->last_access = $now;
440 if ($this->consumer->protected) {
441 if (!is_null($this->consumer->consumerGuid)) {
442 $this->ok = empty($_POST['tool_consumer_instance_guid']) ||
443 ($this->consumer->consumerGuid === $_POST['tool_consumer_instance_guid']);
444 if (!$this->ok) {
445 $this->reason = 'Request is from an invalid tool consumer.';
446 }
447 } else {
448 $this->ok = isset($_POST['tool_consumer_instance_guid']);
449 if (!$this->ok) {
450 $this->reason = 'A tool consumer GUID must be included in the launch request.';
451 }
452 }
453 }
454 if ($this->ok) {
455 $this->ok = $this->consumer->enabled;
456 if (!$this->ok) {
457 $this->reason = 'Tool consumer has not been enabled by the tool provider.';
458 }
459 }
460 if ($this->ok) {
461 $this->ok = is_null($this->consumer->enableFrom) || ($this->consumer->enableFrom <= $now);
462 if ($this->ok) {
463 $this->ok = is_null($this->consumer->enableUntil) || ($this->consumer->enableUntil > $now);
464 if (!$this->ok) {
465 $this->reason = 'Tool consumer access has expired.';
466 }
467 } else {
468 $this->reason = 'Tool consumer access is not yet available.';
469 }
470 }
471 }
472 // Validate other message parameter values
473 if ($this->ok) {
474 if ($_POST['lti_message_type'] === 'ContentItemSelectionRequest') {
475 if (isset($_POST['accept_unsigned'])) {
476 $this->ok = $this->checkValue($_POST['accept_unsigned'], array('true', 'false'), 'Invalid value for accept_unsigned parameter: %s.');
477 }
478 if ($this->ok && isset($_POST['accept_multiple'])) {
479 $this->ok = $this->checkValue($_POST['accept_multiple'], array('true', 'false'), 'Invalid value for accept_multiple parameter: %s.');
480 }
481 if ($this->ok && isset($_POST['accept_copy_advice'])) {
482 $this->ok = $this->checkValue($_POST['accept_copy_advice'], array('true', 'false'), 'Invalid value for accept_copy_advice parameter: %s.');
483 }
484 if ($this->ok && isset($_POST['auto_create'])) {
485 $this->ok = $this->checkValue($_POST['auto_create'], array('true', 'false'), 'Invalid value for auto_create parameter: %s.');
486 }
487 if ($this->ok && isset($_POST['can_confirm'])) {
488 $this->ok = $this->checkValue($_POST['can_confirm'], array('true', 'false'), 'Invalid value for can_confirm parameter: %s.');
489 }
490 } elseif (isset($_POST['launch_presentation_document_target'])) {
491 $this->ok = $this->checkValue(
492 $_POST['launch_presentation_document_target'],
493 array('embed', 'frame', 'iframe', 'window', 'popup', 'overlay'),
494 'Invalid value for launch_presentation_document_target parameter: %s.'
495 );
496 }
497 }
498 }
499
500 if ($this->ok && ($_POST['lti_message_type'] === 'ToolProxyRegistrationRequest')) {
501 $this->ok = $_POST['lti_version'] == self::LTI_VERSION2;
502 if (!$this->ok) {
503 $this->reason = 'Invalid lti_version parameter';
504 }
505 if ($this->ok) {
506 $http = new HTTPMessage($_POST['tc_profile_url'], 'GET', null, 'Accept: application/vnd.ims.lti.v2.toolconsumerprofile+json');
507 $this->ok = $http->send();
508 if (!$this->ok) {
509 $this->reason = 'Tool consumer profile not accessible.';
510 } else {
511 $tcProfile = json_decode($http->response);
512 $this->ok = !is_null($tcProfile);
513 if (!$this->ok) {
514 $this->reason = 'Invalid JSON in tool consumer profile.';
515 }
516 }
517 }
518 // Check for required capabilities
519 if ($this->ok) {
520 // $this->consumer = new ToolConsumer($_POST['reg_key'], $this->dataConnector);
521 $this->consumer = new ilLTIToolConsumer($_POST['oauth_consumer_key'], $this->dataConnector);
522 $this->consumer->profile = $tcProfile;
523 $capabilities = $this->consumer->profile->capability_offered;
524 $missing = array();
525 foreach ($this->resourceHandlers as $resourceHandler) {
526 foreach ($resourceHandler->requiredMessages as $message) {
527 if (!in_array($message->type, $capabilities)) {
528 $missing[$message->type] = true;
529 }
530 }
531 }
532 foreach ($this->constraints as $name => $constraint) {
533 if ($constraint['required']) {
534 if (!in_array($name, $capabilities) && !in_array($name, array_flip($capabilities))) {
535 $missing[$name] = true;
536 }
537 }
538 }
539 if (!empty($missing)) {
540 ksort($missing);
541 $this->reason = 'Required capability not offered - \'' . implode('\', \'', array_keys($missing)) . '\'';
542 $this->ok = false;
543 }
544 }
545 // Check for required services
546 if ($this->ok) {
547 foreach ($this->requiredServices as $service) {
548 foreach ($service->formats as $format) {
549 if (!$this->findService($format, $service->actions)) {
550 if ($this->ok) {
551 $this->reason = 'Required service(s) not offered - ';
552 $this->ok = false;
553 } else {
554 $this->reason .= ', ';
555 }
556 $this->reason .= "'{$format}' [" . implode(', ', $service->actions) . ']';
557 }
558 }
559 }
560 }
561 if ($this->ok) {
562 if ($_POST['lti_message_type'] === 'ToolProxyRegistrationRequest') {
563 $this->consumer->profile = $tcProfile;
564 $this->consumer->secret = $_POST['reg_password'];
565 $this->consumer->ltiVersion = $_POST['lti_version'];
566 $this->consumer->name = $tcProfile->product_instance->service_owner->service_owner_name->default_value;
567 $this->consumer->consumerName = $this->consumer->name;
568 $this->consumer->consumerVersion = "{$tcProfile->product_instance->product_info->product_family->code}-{$tcProfile->product_instance->product_info->product_version}";
569 $this->consumer->consumerGuid = $tcProfile->product_instance->guid;
570 $this->consumer->enabled = true;
571 $this->consumer->protected = true;
572 $doSaveConsumer = true;
573 }
574 }
575 } elseif ($this->ok && !empty($_POST['custom_tc_profile_url']) && empty($this->consumer->profile)) {
576 $http = new HTTPMessage($_POST['custom_tc_profile_url'], 'GET', null, 'Accept: application/vnd.ims.lti.v2.toolconsumerprofile+json');
577 if ($http->send()) {
578 $tcProfile = json_decode($http->response);
579 if (!is_null($tcProfile)) {
580 $this->consumer->profile = $tcProfile;
581 $doSaveConsumer = true;
582 }
583 }
584 }
585 //ACHTUNG HIER TODO UWE
586 // Validate message parameter constraints
587 // if ($this->ok) {
588 // $invalidParameters = array();
589 // foreach ($this->constraints as $name => $constraint) {
590 // // if (empty($constraint['messages']) || in_array($_POST['lti_message_type'], $constraint['messages'])) {
591 // // $ok = true;
592 // // if ($constraint['required']) {
593 // // if (!isset($_POST[$name]) || (strlen(trim($_POST[$name])) <= 0)) {
594 // // $invalidParameters[] = "{$name} (missing)";
595 // // $ok = false;
596 // // }
597 // // }
598 // // if ($ok && !is_null($constraint['max_length']) && isset($_POST[$name])) {
599 // // if (strlen(trim($_POST[$name])) > $constraint['max_length']) {
600 // // $invalidParameters[] = "{$name} (too long)";
601 // // }
602 // // }
603 // // }
604 // }
605 // if (count($invalidParameters) > 0) {
606 // $this->ok = false;
607 // if (empty($this->reason)) {
608 // $this->reason = 'Invalid parameter(s): ' . implode(', ', $invalidParameters) . '.';
609 // }
610 // }
611 // }
612
613 $this->logger->debug('Still ok: ' . ($this->ok ? '1' : '0'));
614 if (!$this->ok) {
615 $this->logger->debug('Reason: ' . $this->reason);
616 }
617
618 if ($this->ok) {
619
620// Set the request context
621 if (isset($_POST['context_id'])) {
622 $this->context = Context::fromConsumer($this->consumer, trim($_POST['context_id']));
623 $title = '';
624 if (isset($_POST['context_title'])) {
625 $title = trim($_POST['context_title']);
626 }
627 if (empty($title)) {
628 $title = "Course {$this->context->getId()}";
629 }
630 $this->context->title = $title;
631 }
632
633 // Set the request resource link
634 if (isset($_POST['resource_link_id'])) {
635 $contentItemId = '';
636 if (isset($_POST['custom_content_item_id'])) {
637 $contentItemId = $_POST['custom_content_item_id'];
638 }
639 $this->resourceLink = ResourceLink::fromConsumer($this->consumer, trim($_POST['resource_link_id']), $contentItemId);
640 if (!empty($this->context)) {
641 $this->resourceLink->setContextId($this->context->getRecordId());
642 }
643 $title = '';
644 if (isset($_POST['resource_link_title'])) {
645 $title = trim($_POST['resource_link_title']);
646 }
647 if (empty($title)) {
648 $title = "Resource {$this->resourceLink->getId()}";
649 }
650 $this->resourceLink->title = $title;
651 // Delete any existing custom parameters
652 foreach ($this->consumer->getSettings() as $name => $value) {
653 if (strpos($name, 'custom_') === 0) {
654 $this->consumer->setSetting($name);
655 $doSaveConsumer = true;
656 }
657 }
658 if (!empty($this->context)) {
659 foreach ($this->context->getSettings() as $name => $value) {
660 if (strpos($name, 'custom_') === 0) {
661 $this->context->setSetting($name);
662 }
663 }
664 }
665 foreach ($this->resourceLink->getSettings() as $name => $value) {
666 if (strpos($name, 'custom_') === 0) {
667 $this->resourceLink->setSetting($name);
668 }
669 }
670 // Save LTI parameters
671 foreach (self::$LTI_CONSUMER_SETTING_NAMES as $name) {
672 if (isset($_POST[$name])) {
673 $this->consumer->setSetting($name, $_POST[$name]);
674 } else {
675 $this->consumer->setSetting($name);
676 }
677 }
678 if (!empty($this->context)) {
679 foreach (self::$LTI_CONTEXT_SETTING_NAMES as $name) {
680 if (isset($_POST[$name])) {
681 $this->context->setSetting($name, $_POST[$name]);
682 } else {
683 $this->context->setSetting($name);
684 }
685 }
686 }
687 foreach (self::$LTI_RESOURCE_LINK_SETTING_NAMES as $name) {
688 if (isset($_POST[$name])) {
689 $this->resourceLink->setSetting($name, $_POST[$name]);
690 } else {
691 $this->resourceLink->setSetting($name);
692 }
693 }
694 // Save other custom parameters
695 foreach ($_POST as $name => $value) {
696 if ((strpos($name, 'custom_') === 0) &&
697 !in_array($name, array_merge(self::$LTI_CONSUMER_SETTING_NAMES, self::$LTI_CONTEXT_SETTING_NAMES, self::$LTI_RESOURCE_LINK_SETTING_NAMES))) {
698 $this->resourceLink->setSetting($name, $value);
699 }
700 }
701 }
702
703 // Set the user instance
704 $userId = '';
705 if (isset($_POST['user_id'])) {
706 $userId = trim($_POST['user_id']);
707 }
708
709 $this->user = User::fromResourceLink($this->resourceLink, $userId);
710
711 // Set the user name
712 $firstname = (isset($_POST['lis_person_name_given'])) ? $_POST['lis_person_name_given'] : '';
713 $lastname = (isset($_POST['lis_person_name_family'])) ? $_POST['lis_person_name_family'] : '';
714 $fullname = (isset($_POST['lis_person_name_full'])) ? $_POST['lis_person_name_full'] : '';
715 $this->user->setNames($firstname, $lastname, $fullname);
716
717 // Set the user email
718 $email = (isset($_POST['lis_person_contact_email_primary'])) ? $_POST['lis_person_contact_email_primary'] : '';
719 $this->user->setEmail($email, $this->defaultEmail);
720
721 // Set the user image URI
722 if (isset($_POST['user_image'])) {
723 $this->user->image = $_POST['user_image'];
724 }
725
726 // Set the user roles
727 if (isset($_POST['roles'])) {
728 $this->user->roles = self::parseRoles($_POST['roles']);
729 }
730
731 // Initialise the consumer and check for changes
732 $this->consumer->defaultEmail = $this->defaultEmail;
733 if ($this->consumer->ltiVersion !== $_POST['lti_version']) {
734 $this->consumer->ltiVersion = $_POST['lti_version'];
735 $doSaveConsumer = true;
736 }
737 if (isset($_POST['tool_consumer_instance_name'])) {
738 if ($this->consumer->consumerName !== $_POST['tool_consumer_instance_name']) {
739 $this->consumer->consumerName = $_POST['tool_consumer_instance_name'];
740 $doSaveConsumer = true;
741 }
742 }
743 if (isset($_POST['tool_consumer_info_product_family_code'])) {
744 $version = $_POST['tool_consumer_info_product_family_code'];
745 if (isset($_POST['tool_consumer_info_version'])) {
746 $version .= "-{$_POST['tool_consumer_info_version']}";
747 }
748 // do not delete any existing consumer version if none is passed
749 if ($this->consumer->consumerVersion !== $version) {
750 $this->consumer->consumerVersion = $version;
751 $doSaveConsumer = true;
752 }
753 } elseif (isset($_POST['ext_lms']) && ($this->consumer->consumerName !== $_POST['ext_lms'])) {
754 $this->consumer->consumerVersion = $_POST['ext_lms'];
755 $doSaveConsumer = true;
756 }
757 if (isset($_POST['tool_consumer_instance_guid'])) {
758 if (is_null($this->consumer->consumerGuid)) {
759 $this->consumer->consumerGuid = $_POST['tool_consumer_instance_guid'];
760 $doSaveConsumer = true;
761 } elseif (!$this->consumer->protected) {
762 $doSaveConsumer = ($this->consumer->consumerGuid !== $_POST['tool_consumer_instance_guid']);
763 if ($doSaveConsumer) {
764 $this->consumer->consumerGuid = $_POST['tool_consumer_instance_guid'];
765 }
766 }
767 }
768 if (isset($_POST['launch_presentation_css_url'])) {
769 if ($this->consumer->cssPath !== $_POST['launch_presentation_css_url']) {
770 $this->consumer->cssPath = $_POST['launch_presentation_css_url'];
771 $doSaveConsumer = true;
772 }
773 } elseif (isset($_POST['ext_launch_presentation_css_url']) &&
774 ($this->consumer->cssPath !== $_POST['ext_launch_presentation_css_url'])) {
775 $this->consumer->cssPath = $_POST['ext_launch_presentation_css_url'];
776 $doSaveConsumer = true;
777 } elseif (!empty($this->consumer->cssPath)) {
778 $this->consumer->cssPath = null;
779 $doSaveConsumer = true;
780 }
781 }
782
783 // Persist changes to consumer
784 if ($doSaveConsumer) {
785 $this->consumer->save();
786 }
787 if ($this->ok && isset($this->context)) {
788 $this->context->save();//ACHTUNG TODO UWE
789 }
790
791 // $this->logger->dump(get_class($this->context));
792
793
794 if ($this->ok && isset($this->resourceLink)) {
795
796// Check if a share arrangement is in place for this resource link
797 // $this->ok = $this->checkForShare();//ACHTUNG TODO UWE
798 // Persist changes to resource link
799 $this->resourceLink->save();
800
801 // Save the user instance
802 if (isset($_POST['lis_result_sourcedid'])) {
803 if ($this->user->ltiResultSourcedId !== $_POST['lis_result_sourcedid']) {
804 $this->user->ltiResultSourcedId = $_POST['lis_result_sourcedid'];
805 $this->user->save();
806 }
807 } elseif (!empty($this->user->ltiResultSourcedId)) {
808 $this->user->ltiResultSourcedId = '';
809 $this->user->save();
810 }
811 }
812 // die ($this->reason.'---'.$this->ok);//ACHTUNG WEG!
813 return $this->ok;
814 }
815
821 private function checkForShare()
822 {
823 $ok = true;
824 $doSaveResourceLink = true;
825
826 $id = $this->resourceLink->primaryResourceLinkId;
827
828 $shareRequest = isset($_POST['custom_share_key']) && !empty($_POST['custom_share_key']);
829 if ($shareRequest) {
830 if (!$this->allowSharing) {
831 $ok = false;
832 $this->reason = 'Your sharing request has been refused because sharing is not being permitted.';
833 } else {
834 // Check if this is a new share key
835 $shareKey = new ResourceLinkShareKey($this->resourceLink, $_POST['custom_share_key']);
836 if (!is_null($shareKey->primaryConsumerKey) && !is_null($shareKey->primaryResourceLinkId)) {
837 // Update resource link with sharing primary resource link details
838 $key = $shareKey->primaryConsumerKey;
839 $id = $shareKey->primaryResourceLinkId;
840 $ok = ($key !== $this->consumer->getKey()) || ($id != $this->resourceLink->getId());
841 if ($ok) {
842 $this->resourceLink->primaryConsumerKey = $key;
843 $this->resourceLink->primaryResourceLinkId = $id;
844 $this->resourceLink->shareApproved = $shareKey->autoApprove;
845 $ok = $this->resourceLink->save();
846 if ($ok) {
847 $doSaveResourceLink = false;
848 $this->user->getResourceLink()->primaryConsumerKey = $key;
849 $this->user->getResourceLink()->primaryResourceLinkId = $id;
850 $this->user->getResourceLink()->shareApproved = $shareKey->autoApprove;
851 $this->user->getResourceLink()->updated = time();
852 // Remove share key
853 $shareKey->delete();
854 } else {
855 $this->reason = 'An error occurred initialising your share arrangement.';
856 }
857 } else {
858 $this->reason = 'It is not possible to share your resource link with yourself.';
859 }
860 }
861 if ($ok) {
862 $ok = !is_null($key);
863 if (!$ok) {
864 $this->reason = 'You have requested to share a resource link but none is available.';
865 } else {
866 $ok = (!is_null($this->user->getResourceLink()->shareApproved) && $this->user->getResourceLink()->shareApproved);
867 if (!$ok) {
868 $this->reason = 'Your share request is waiting to be approved.';
869 }
870 }
871 }
872 }
873 } else {
874 // Check no share is in place
875 $ok = is_null($id);
876 if (!$ok) {
877 $this->reason = 'You have not requested to share a resource link but an arrangement is currently in place.';
878 }
879 }
880 // Look up primary resource link
881 if ($ok && !is_null($id)) {
882 // $consumer = new ToolConsumer($key, $this->dataConnector);
883 $consumer = new ilLTIToolConsumer($_POST['oauth_consumer_key'], $this->dataConnector);
884 $ok = !is_null($consumer->created);
885 if ($ok) {
886 $resourceLink = ResourceLink::fromConsumer($consumer, $id);
887 $ok = !is_null($resourceLink->created);
888 }
889 if ($ok) {
890 if ($doSaveResourceLink) {
891 $this->resourceLink->save();
892 }
893 $this->resourceLink = $resourceLink;
894 } else {
895 $this->reason = 'Unable to load resource link being shared.';
896 }
897 }
898
899 return $ok;
900 }
906 private function checkValue($value, $values, $reason)
907 {
908 $ok = in_array($value, $values);
909 if (!$ok && !empty($reason)) {
910 $this->reason = sprintf($reason, $value);
911 }
912
913 return $ok;
914 }
915}
$result
user()
Definition: user.php:4
foreach($paths as $path) $request
Definition: asyncclient.php:32
exit
Definition: backend.php:16
$version
Definition: build.php:27
$_POST["username"]
An exception for terminatinating execution or to throw for unit testing.
Class to represent an HTTP message.
Definition: HTTPMessage.php:15
Class to represent an OAuth Consumer.
Class to represent an OAuth Data Store.
Class to represent an OAuth Server.
Definition: OAuthServer.php:12
Class to represent an OAuth HMAC_SHA1 signature method.
Class to represent a generic item object.
Definition: Item.php:15
Class to represent a tool consumer context.
Definition: Context.php:18
Class to provide a connection to a persistent store for LTI objects.
Class to represent a tool consumer resource link share key.
Class to represent an LTI Tool Provider.
Class to represent a tool consumer user.
Definition: User.php:16
LTI provider for LTI launch.
LTI provider for LTI launch.
onContentItem()
Process a valid content-item request.
onError()
Process a response to an invalid request.
static $LTI_CONTEXT_SETTING_NAMES
Names of LTI parameters to be retained in the context settings property.
authenticate()
Check the authenticity of the LTI launch request.
static $MESSAGE_TYPES
List of supported message types and associated class methods.
onRegister()
Process a valid tool proxy registration request.
__construct(DataConnector $dataConnector)
ilLTIToolProvider constructor.
doCallback($method=null)
Call any callback function for the requested action.
onLaunch()
Process a valid launch request.
checkForShare()
Check if a share arrangement is in place.
static $LTI_RESOURCE_LINK_SETTING_NAMES
Names of LTI parameters to be retained in the resource link settings property.
handleRequest()
Process an incoming request.
static $METHOD_NAMES
List of supported message types and associated class methods.
static $CUSTOM_SUBSTITUTION_VARIABLES
Names of LTI custom parameter substitution variables (or capabilities) and their associated default m...
checkValue($value, $values, $reason)
Validate a parameter value from an array of permitted values.
result()
Perform the result of an action.
static $LTI_VERSIONS
Permitted LTI versions for messages.
static $LTI_CONSUMER_SETTING_NAMES
Names of LTI parameters to be retained in the consumer settings property.
$key
Definition: croninfo.php:18
if(!array_key_exists('StateId', $_REQUEST)) $id
if(! $oauthconfig->getBoolean('getUserInfo.enable', FALSE)) $store
Definition: getUserInfo.php:11
$format
Definition: metadata.php:141
if( $orgName !==null) if($spconfig->hasValue('contacts')) $email
Definition: metadata.php:201
catch(Exception $e) $message
$http
Definition: raiseError.php:7
$server
Definition: sabredav.php:48
global $DIC
Definition: saml.php:7
foreach($_POST as $key=> $value) $res
$values