ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilObjLTIConsumer.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
21use ceLTIc\LTI\Util;
23use Firebase\JWT\JWK;
24use Firebase\JWT\JWT;
25
36{
37 public const DB_TABLE_NAME = 'lti_consumer_settings';
38
42 protected bool $activationLimited = false;
43 protected ?int $activationStartingTime = null;
44 protected ?int $activationEndingTime = null;
45 protected ?bool $activationVisibility = null;
46
47 protected int $providerId = 0;
48
50
51 public const LAUNCH_METHOD_OWN_WIN = 'ownWin';
52 public const LAUNCH_METHOD_NEW_WIN = 'newWin';
53 public const LAUNCH_METHOD_EMBEDDED = 'embedded';
54
55 protected bool $use_xapi = false;
56 protected string $custom_activity_id = '';
57 protected bool $statementsReportEnabled = false;
58
59 protected float $mastery_score = 0.5;
60
62
63 protected string $customLaunchKey = '';
64
65 protected string $customLaunchSecret = '';
66
67 protected string $customParams = '';
68
69 protected ?int $ref_id = 0;
70
71 //Highscore
72 protected bool $_highscore_enabled = false;
73
74 protected int $anonymity = 0;
75
76 protected bool $_highscore_achieved_ts = true;
77
78 protected bool $_highscore_percentage = true;
79
80 protected bool $_highscore_wtime = true;
81
82 protected bool $_highscore_own_table = true;
83
84 protected bool $_highscore_top_table = true;
85
86 protected int $_highscore_top_num = 10;
87
88 public const HIGHSCORE_SHOW_ALL_TABLES = 1;
89 public const HIGHSCORE_SHOW_TOP_TABLE = 2;
90 public const HIGHSCORE_SHOW_OWN_TABLE = 3;
91
92 public const LTI_JWT_CLAIM_PREFIX = 'https://purl.imsglobal.org/spec/lti';
93 public const LTI_1_3_KID = 'lti_1_3_kid';
94 public const LTI_1_3_PRIVATE_KEY = 'lti_1_3_privatekey';
95 public const ERROR_OPEN_SSL_CONF = 'error openssl config invalid';
96 public const OPENSSL_KEYTYPE_RSA = '';
97
98 public const REG_TOKEN_OP_NEW_REG = 'reg';
99 public const REG_TOKEN_OP_UPDATE_REG = 'reg-update';
100
104 public function __construct(int $a_id = 0, bool $a_reference = true)
105 {
106 parent::__construct($a_id, $a_reference);
107 }
108
109 protected function initType(): void
110 {
111 $this->type = "lti";
112 }
113
114 public function isActivationLimited(): bool
115 {
117 }
118
119 public function setActivationLimited(bool $activationLimited): void
120 {
121 $this->activationLimited = $activationLimited;
122 }
123
124 public function getActivationStartingTime(): ?int
125 {
127 }
128
129 public function setActivationStartingTime(?int $activationStartingTime = null): void
130 {
131 $this->activationStartingTime = $activationStartingTime;
132 }
133
134 public function getActivationEndingTime(): ?int
135 {
137 }
138
139 public function setActivationEndingTime(?int $activationEndingTime = null): void
140 {
141 $this->activationEndingTime = $activationEndingTime;
142 }
143
144 public function getActivationVisibility(): ?bool
145 {
147 }
148
150 {
151 $this->activationVisibility = $activationVisibility;
152 }
153
154 public function getMasteryScore(): float
155 {
157 }
158
159 public function setMasteryScore(float $mastery_score): void
160 {
161 $this->mastery_score = $mastery_score;
162 }
163
164 public function getMasteryScorePercent(): float
165 {
166 return $this->mastery_score * 100;
167 }
168
169 public function setMasteryScorePercent(float $mastery_score_percent): void
170 {
171 $this->mastery_score = $mastery_score_percent / 100;
172 }
173
174 public function getProviderId(): int
175 {
176 return $this->providerId;
177 }
178
179 public function setProviderId(int $providerId): void
180 {
181 $this->providerId = $providerId;
182 }
183
184 public function initProvider(): void
185 {
186 $this->provider = new ilLTIConsumeProvider($this->getProviderId());
187 }
188
190 {
191 return $this->provider;
192 }
193
195 {
196 $this->provider = $provider;
197 }
198
199 public function isLaunchMethodOwnWin(): bool
200 {
201 return $this->launchMethod == self::LAUNCH_METHOD_OWN_WIN;
202 }
203
204 public function isLaunchMethodEmbedded(): bool
205 {
206 return $this->launchMethod == self::LAUNCH_METHOD_EMBEDDED;
207 }
208
209 public function getLaunchMethod(): string
210 {
211 return $this->launchMethod;
212 }
213
214 public function setLaunchMethod(string $launchMethod): void
215 {
216 $this->launchMethod = $launchMethod;
217 }
218
219 public function getCustomLaunchKey(): string
220 {
222 }
223
224 public function setCustomLaunchKey(string $customLaunchKey): void
225 {
226 $this->customLaunchKey = $customLaunchKey;
227 }
228
229 public function getCustomLaunchSecret(): string
230 {
232 }
233
234 public function setCustomLaunchSecret(string $customLaunchSecret): void
235 {
236 $this->customLaunchSecret = $customLaunchSecret;
237 }
238
239 public function getCustomParams(): string
240 {
241 return $this->customParams;
242 }
243
244 public function setCustomParams(string $customParams): void
245 {
246 $this->customParams = $customParams;
247 }
248
249 public function getLaunchKey(): string
250 {
251 if ($this->getProvider()->isProviderKeyCustomizable()) {
252 return $this->getCustomLaunchKey();
253 }
254
255 return $this->getProvider()->getProviderKey();
256 }
257
258 public function getLaunchSecret(): string
259 {
260 if ($this->getProvider()->isProviderKeyCustomizable()) {
261 return $this->getCustomLaunchSecret();
262 }
263
264 return $this->getProvider()->getProviderSecret();
265 }
266
267 public function getUseXapi(): bool
268 {
269 return $this->use_xapi;
270 }
271
272 public function setUseXapi(bool $use_xapi): void
273 {
274 $this->use_xapi = $use_xapi;
275 }
276
277 public function getCustomActivityId(): string
278 {
280 }
281
282 public function setCustomActivityId(string $custom_activity_id): void
283 {
284 $this->custom_activity_id = $custom_activity_id;
285 }
286
287 public function getActivityId(): string
288 {
289 if (strlen($this->getProvider()->getXapiActivityId())) {
290 return $this->getProvider()->getXapiActivityId();
291 }
292
294 }
295
296 public function isStatementsReportEnabled(): bool
297 {
299 }
300
302 {
303 $this->statementsReportEnabled = $statementsReportEnabled;
304 }
305
309 public function getCustomParamsArray(): array
310 {
311 $paramsAsArray = [];
312
313 $params = $this->getCustomParams();
314 // allows foo=bar;foo2=baz2; foo3=baz3
315 $params = preg_split('/; ?/', $params);
316
317 foreach ($params as $param) {
318 $param = explode('=', $param);
319 // empty field, duplicate/leading/trailing semicolon?
320 if ($param[0] != '') {
321 $value = isset($param[1]) ? $param[1] : '';
322 $paramsAsArray[$param[0]] = $value;
323 }
324 }
325
326 return $paramsAsArray;
327 }
328
333 {
334 $paramsAsArray = [];
335
337 // allows foo=bar;foo2=baz2; foo3=baz3
338 $params = preg_split('/; ?/', $params);
339
340 foreach ($params as $param) {
341 $param = explode('=', $param);
342 // empty field, duplicate/leading/trailing semicolon?
343 if ($param[0] != '') {
344 $value = isset($param[1]) ? $param[1] : '';
345 $paramsAsArray[$param[0]] = $value;
346 }
347 }
348
349 return $paramsAsArray;
350 }
351
352 protected function doRead(): void
353 {
354 $this->load();
355 }
356
357 public function load(): void
358 {
359 global $DIC;
360 /* @var \ILIAS\DI\Container $DIC */
361
362 $query = "SELECT * FROM {$this->dbTableName()} WHERE obj_id = %s";
363 $res = $DIC->database()->queryF($query, ['integer'], [$this->getId()]);
364
365 while ($row = $DIC->database()->fetchAssoc($res)) {
366 // if ($row['provider_id']) { //always set
367 $this->setProviderId((int) $row['provider_id']);
368 $this->setProvider(new ilLTIConsumeProvider((int) $row['provider_id']));
369 // }
370
371 $this->setLaunchMethod($row['launch_method']);
372
373 $this->setCustomLaunchKey((string) $row['launch_key']);
374 $this->setCustomLaunchSecret((string) $row['launch_secret']);
375 $this->setCustomParams((string) $row['custom_params']);
376
377 $this->setUseXapi((bool) $row['use_xapi']);
378 $this->setCustomActivityId((string) $row['activity_id']);
379 $this->setStatementsReportEnabled((bool) $row['show_statements']);
380 $this->setHighscoreEnabled((bool) $row['highscore_enabled']);
381 $this->setHighscoreAchievedTS((bool) $row['highscore_achieved_ts']);
382 $this->setHighscorePercentage((bool) $row['highscore_percentage']);
383 $this->setHighscoreWTime((bool) $row['highscore_wtime']);
384 $this->setHighscoreOwnTable((bool) $row['highscore_own_table']);
385 $this->setHighscoreTopTable((bool) $row['highscore_top_table']);
386 $this->setHighscoreTopNum((int) $row['highscore_top_num']);
387
388 $this->setMasteryScore((float) $row['mastery_score']);
389 }
390
392 }
393
394 protected function doUpdate(): void
395 {
396 $this->save();
397 }
398
399 public function save(): void
400 {
401 global $DIC;
402 /* @var \ILIAS\DI\Container $DIC */
403
404 $DIC->database()->replace($this->dbTableName(), [
405 'obj_id' => ['integer', $this->getId()]
406 ], [
407 'provider_id' => ['integer', $this->getProviderId()],
408 'launch_method' => ['text', $this->getLaunchMethod()],
409 'launch_key' => ['text', $this->getCustomLaunchKey()],
410 'launch_secret' => ['text', $this->getCustomLaunchSecret()],
411 'custom_params' => ['text', $this->getCustomParams()],
412 'use_xapi' => ['integer', $this->getUseXapi()],
413 'activity_id' => ['text', $this->getCustomActivityId()],
414 'show_statements' => ['integer', $this->isStatementsReportEnabled()],
415 'highscore_enabled' => ['integer', (int) $this->getHighscoreEnabled()],
416 'highscore_achieved_ts' => ['integer', (int) $this->getHighscoreAchievedTS()],
417 'highscore_percentage' => ['integer', (int) $this->getHighscorePercentage()],
418 'highscore_wtime' => ['integer', (int) $this->getHighscoreWTime()],
419 'highscore_own_table' => ['integer', (int) $this->getHighscoreOwnTable()],
420 'highscore_top_table' => ['integer', (int) $this->getHighscoreTopTable()],
421 'highscore_top_num' => ['integer', $this->getHighscoreTopNum()],
422 'mastery_score' => ['float', $this->getMasteryScore()]
423 ]);
424
426 }
427
428 protected function loadRepositoryActivationSettings(): void
429 {
430 if ($this->ref_id > 0) {
431 $activation = ilObjectActivation::getItem($this->ref_id);
432 switch ($activation["timing_type"]) {
434 $this->setActivationLimited(true);
435 if (!is_null($activation["timing_start"])) {
436 $activation["timing_start"] = (int) $activation["timing_start"];
437 }
438 $this->setActivationStartingTime($activation["timing_start"]);
439 if (!is_null($activation["timing_end"])) {
440 $activation["timing_end"] = (int) $activation["timing_end"];
441 }
442 $this->setActivationEndingTime($activation["timing_end"]);
443 $this->setActivationVisibility((bool) $activation["visible"]);
444 break;
445
446 default:
447 $this->setActivationLimited(false);
448 break;
449 }
450 }
451 }
452
453 protected function saveRepositoryActivationSettings(): void
454 {
455 if ($this->ref_id > 0) {
456 ilObjectActivation::getItem($this->ref_id);
457
458 $item = new ilObjectActivation();
459 if (!$this->isActivationLimited()) {
460 $item->setTimingType(ilObjectActivation::TIMINGS_DEACTIVATED);
461 } else {
462 $item->setTimingType(ilObjectActivation::TIMINGS_ACTIVATION);
463 $item->setTimingStart($this->getActivationStartingTime());
464 $item->setTimingEnd($this->getActivationEndingTime());
465 $item->toggleVisible($this->getActivationVisibility());
466 }
467
468 $item->update($this->ref_id);
469 }
470 }
471
472 protected function dbTableName(): string
473 {
474 return self::DB_TABLE_NAME;
475 }
476
479
483 public function setHighscoreEnabled(bool $a_enabled): void
484 {
485 $this->_highscore_enabled = $a_enabled;
486 }
487
493 public function getHighscoreEnabled(): bool
494 {
496 }
497
501 public function setHighscoreAchievedTS(bool $a_achieved_ts): void
502 {
503 $this->_highscore_achieved_ts = $a_achieved_ts;
504 }
505
511 public function getHighscoreAchievedTS(): bool
512 {
514 }
515
519 public function setHighscorePercentage(bool $a_percentage): void
520 {
521 $this->_highscore_percentage = $a_percentage;
522 }
523
529 public function getHighscorePercentage(): bool
530 {
532 }
533
537 public function setHighscoreWTime(bool $a_wtime): void
538 {
539 $this->_highscore_wtime = $a_wtime;
540 }
541
547 public function getHighscoreWTime(): bool
548 {
550 }
551
557 public function setHighscoreOwnTable(bool $a_own_table): void
558 {
559 $this->_highscore_own_table = $a_own_table;
560 }
561
567 public function getHighscoreOwnTable(): bool
568 {
570 }
571
575 public function setHighscoreTopTable(bool $a_top_table): void
576 {
577 $this->_highscore_top_table = $a_top_table;
578 }
579
585 public function getHighscoreTopTable(): bool
586 {
588 }
589
596 public function setHighscoreTopNum(int $a_top_num): void
597 {
598 $this->_highscore_top_num = $a_top_num;
599 }
600
609 public function getHighscoreTopNum(int $a_retval = 10): int
610 {
611 $retval = $a_retval;
612 if ($this->_highscore_top_num != 0) {
614 }
615
616 return $retval;
617 }
618
619 public function getHighscoreMode(): int
620 {
621 switch (true) {
622 case $this->getHighscoreOwnTable() && $this->getHighscoreTopTable():
624
625 case $this->getHighscoreTopTable():
627
628 case $this->getHighscoreOwnTable():
629 default:
631 }
632 }
633
637 public function setHighscoreMode(int $mode): void
638 {
639 switch ($mode) {
641 $this->setHighscoreTopTable(true);
642 $this->setHighscoreOwnTable(true);
643 break;
644
646 $this->setHighscoreTopTable(true);
647 $this->setHighscoreOwnTable(false);
648 break;
649
651 default:
652 $this->setHighscoreTopTable(false);
653 $this->setHighscoreOwnTable(true);
654 break;
655 }
656 }
657 /* End GET/SET for highscore feature*/
661 public function buildLaunchParameters(
662 ilCmiXapiUser $cmixUser,
663 string $token,
664 string $contextType,
665 string $contextId,
666 string $contextTitle,
667 ?string $returnUrl = ''
668 ): array {
669 global $DIC;
670 /* @var \ILIAS\DI\Container $DIC */
671 $DIC->user()->setExternalAccount($cmixUser->getUsrIdent());
672
673 $roles = $DIC->access()->checkAccess('write', '', $this->getRefId()) ? "Instructor" : "Learner";
674 //todo if object is in course or group, roles would have to be taken from there s. Mantis 35435 - if necessary Jour Fixe topic
675 //$roles = "Administrator";
676
677 if ($this->getProvider()->getAlwaysLearner() == true) {
678 $roles = "Learner";
679 }
680
681 $resource_link_id = $this->getRefId();
682 if ($this->getProvider()->getUseProviderId() == true) {
683 $resource_link_id = 'p' . $this->getProvider()->getId();
684 }
685
686 $usrImage = '';
687 if ($this->getProvider()->getIncludeUserPicture()) {
688 $usrImage = self::getIliasHttpPath() . "/" . $DIC->user()->getPersonalPicturePath("small");
689 }
690
691 $documentTarget = "window";
692 if ($this->getLaunchMethod() == self::LAUNCH_METHOD_EMBEDDED) {
693 $documentTarget = "iframe";
694 }
695
696 $nameGiven = '-';
697 $nameFamily = '-';
698 $nameFull = '-';
699 switch ($this->getProvider()->getPrivacyName()) {
701 $nameGiven = $DIC->user()->getFirstname();
702 $nameFull = $DIC->user()->getFirstname();
703 break;
705 $usrName = $DIC->user()->getUTitle() ? $DIC->user()->getUTitle() . ' ' : '';
706 $usrName .= $DIC->user()->getLastname();
707 $nameFamily = $usrName;
708 $nameFull = $usrName;
709 break;
711 $nameGiven = $DIC->user()->getFirstname();
712 $nameFamily = $DIC->user()->getLastname();
713 $nameFull = $DIC->user()->getFullname();
714 break;
715 }
716
717 $userIdLTI = ilCmiXapiUser::getIdentAsId($this->getProvider()->getPrivacyIdent(), $DIC->user());
718
719 $emailPrimary = $cmixUser->getUsrIdent();
720 if ($this->getProvider()->getPrivacyIdent() == ilObjCmiXapi::PRIVACY_IDENT_IL_UUID_RANDOM) {
721 $userIdLTI = strstr($emailPrimary, '@' . ilCmiXapiUser::getIliasUuid(), true);
722 }
723
724 ilLTIConsumerResult::getByKeys($this->getId(), $DIC->user()->getId(), true);
725
726 //ToDo: Check!
727 $provider_custom_params = self::getProviderCustomParamsArray($this->getProvider());
728 $custom_params = $this->getCustomParamsArray();
729 $merged_params = array_merge($provider_custom_params, $custom_params);
730
731 $toolConsumerInstanceGuid = CLIENT_ID . ".";
732 $parseIliasUrl = parse_url(self::getIliasHttpPath());
733 if (array_key_exists("path", $parseIliasUrl)) {
734 $toolConsumerInstanceGuid .= implode(".", array_reverse(explode("/", $parseIliasUrl["path"])));
735 }
736 $toolConsumerInstanceGuid .= $parseIliasUrl["host"];
737
738 $launch_vars = [
739 "lti_message_type" => "basic-lti-launch-request",
740 "lti_version" => "LTI-1p0",
741 "resource_link_id" => $resource_link_id,
742 "resource_link_title" => $this->getTitle(),
743 "resource_link_description" => $this->getDescription(),
744 "user_id" => $userIdLTI,
745 "user_image" => $usrImage,
746 "roles" => $roles,
747 "lis_person_name_given" => $nameGiven,
748 "lis_person_name_family" => $nameFamily,
749 "lis_person_name_full" => $nameFull,
750 "lis_person_contact_email_primary" => $emailPrimary,
751 "context_id" => $contextId,
752 "context_type" => $contextType,
753 "context_title" => $contextTitle,
754 "context_label" => $contextType . " " . $contextId,
755 "launch_presentation_locale" => $this->lng->getLangKey(),
756 "launch_presentation_document_target" => $documentTarget,
757 //"launch_presentation_width" => "",
758 //recommended
759 //"launch_presentation_height" => "",
760 //recommended
761 "launch_presentation_return_url" => $returnUrl,
762 "tool_consumer_instance_guid" => $toolConsumerInstanceGuid,
763 "tool_consumer_instance_name" => $DIC->settings()->get("short_inst_name") ? $DIC->settings()->get(
764 "short_inst_name"
765 ) : CLIENT_ID,
766 "tool_consumer_instance_description" => ilObjSystemFolder::_getHeaderTitle(),
767 "tool_consumer_instance_url" => ilLink::_getLink(ROOT_FOLDER_ID, "root"),
768 //ToDo? "https://vb52p70.example.com/release_5-3/goto.php?target=root_1&client_id=inno",
769 "tool_consumer_instance_contact_email" => $DIC->settings()->get("admin_email"),
770 "launch_presentation_css_url" => "",
771 "tool_consumer_info_product_family_code" => "ilias",
772 "tool_consumer_info_version" => ILIAS_VERSION,
773 "lis_result_sourcedid" => $token,
774 "lis_outcome_service_url" => self::getIliasHttpPath(
775 ) . "/ltiresult.php?client_id=" . CLIENT_ID,
776 "role_scope_mentor" => ""
777 ];
778
779 $OAuthParams = [
780 "url" => $this->getProvider()->getProviderUrl(),
781 "key" => $this->getLaunchKey(),
782 "secret" => $this->getLaunchSecret(),
783 "callback" => "about:blank",
784 "http_method" => "POST",
785 "sign_method" => "HMAC_SHA1",
786 "token" => null,
787 "data" => ($launch_vars + $merged_params)
788 ];
789
790 return ilLTIConsumerLaunch::signOAuth($OAuthParams);
791 }
792
798 ilCmiXapiUser $cmixUser,
799 string $token,
800 string $endpoint,
801 string $clientId,
802 int $deploymentId,
803 string $nonce,
804 string $contextType,
805 string $contextId,
806 string $contextTitle,
807 ?string $returnUrl = ''
808 ): ?array {
809 global $DIC;
810 /* @var \ILIAS\DI\Container $DIC */
811 $roles = $this->determineLTIRole($DIC->user()->getId(), $this->getRefId(), $DIC->rbac()->review());
812
813 if ($this->getProvider()->getAlwaysLearner() == true) {
814 $roles = 'Learner';
815 }
816
817
818
819 $resource_link_id = $this->getRefId();
820 if ($this->getProvider()->getUseProviderId() == true) {
821 $resource_link_id = 'p' . $this->getProvider()->getId();
822 }
823
824 $usrImage = '';
825 if ($this->getProvider()->getIncludeUserPicture()) {
826 $usrImage = self::getIliasHttpPath() . "/" . $DIC->user()->getPersonalPicturePath("small");
827 }
828
829 $documentTarget = "window";
830 if ($this->getLaunchMethod() == self::LAUNCH_METHOD_EMBEDDED) {
831 $documentTarget = "iframe";
832 }
833
834 $nameGiven = '-';
835 $nameFamily = '-';
836 $nameFull = '-';
837 switch ($this->getProvider()->getPrivacyName()) {
839 $nameGiven = $DIC->user()->getFirstname();
840 $nameFull = $DIC->user()->getFirstname();
841 break;
843 $usrName = $DIC->user()->getUTitle() ? $DIC->user()->getUTitle() . ' ' : '';
844 $usrName .= $DIC->user()->getLastname();
845 $nameFamily = $usrName;
846 $nameFull = $usrName;
847 break;
849 $nameGiven = $DIC->user()->getFirstname();
850 $nameFamily = $DIC->user()->getLastname();
851 $nameFull = $DIC->user()->getFullname();
852 break;
853 }
854
855 $userIdLTI = ilCmiXapiUser::getIdentAsId($this->getProvider()->getPrivacyIdent(), $DIC->user());
856
857 $emailPrimary = $cmixUser->getUsrIdent();
858
859 ilLTIConsumerResult::getByKeys($this->getId(), $DIC->user()->getId(), true);
860
861 $toolConsumerInstanceGuid = CLIENT_ID . ".";
862 $parseIliasUrl = parse_url(self::getIliasHttpPath());
863 if (array_key_exists("path", $parseIliasUrl)) {
864 $toolConsumerInstanceGuid .= implode(".", array_reverse(explode("/", $parseIliasUrl["path"])));
865 }
866 $toolConsumerInstanceGuid .= $parseIliasUrl["host"];
867 $launch_vars = [
868 "lti_message_type" => "basic-lti-launch-request",
869 "lti_version" => "1.3.0",
870 "resource_link_id" => (string) $resource_link_id,
871 "resource_link_title" => $this->getTitle(),
872 "resource_link_description" => $this->getDescription(),
873 "user_id" => (string) $userIdLTI,
874 "user_image" => $usrImage,
875 "roles" => $roles,
876 "lis_person_name_given" => $nameGiven,
877 "lis_person_name_family" => $nameFamily,
878 "lis_person_name_full" => $nameFull,
879 "lis_person_contact_email_primary" => $emailPrimary,
880 "context_id" => $contextId,
881 "context_type" => $contextType,
882 "context_title" => $contextTitle,
883 "context_label" => $contextType . " " . $contextId,
884 "launch_presentation_locale" => $this->lng->getLangKey(),
885 "launch_presentation_document_target" => $documentTarget,
886 //"launch_presentation_width" => "",
887 //recommended
888 //"launch_presentation_height" => "",
889 //recommended
890 "launch_presentation_return_url" => $returnUrl,
891 "tool_consumer_instance_guid" => $toolConsumerInstanceGuid,
892 "tool_consumer_instance_name" => $DIC->settings()->get("short_inst_name") ? $DIC->settings()->get(
893 "short_inst_name"
894 ) : CLIENT_ID,
895 "tool_consumer_instance_description" => ilObjSystemFolder::_getHeaderTitle(),
896 "tool_consumer_instance_url" => ilLink::_getLink(ROOT_FOLDER_ID, "root"),
897 //ToDo? "https://vb52p70.example.com/release_5-3/goto.php?target=root_1&client_id=inno",
898 "tool_consumer_instance_contact_email" => $DIC->settings()->get("admin_email"),
899 "launch_presentation_css_url" => "",
900 "tool_consumer_info_product_family_code" => "ilias",
901 "tool_consumer_info_version" => ILIAS_VERSION,
902 "lis_result_sourcedid" => $token,
903 "lis_outcome_service_url" => self::getIliasHttpPath(
904 ) . "/ltiresult.php?client_id=" . CLIENT_ID,
905 "role_scope_mentor" => ""
906 ];
907
908 $provider_custom_params = self::getProviderCustomParamsArray($this->getProvider());
909 $custom_params = $this->getCustomParamsArray();
910 $merged_params = array_merge($provider_custom_params, $custom_params);
911 foreach ($merged_params as $key => $value) {
912 $launch_vars['custom_' . $key] = $value;
913 }
914
915 if ($this->getProvider()->isGradeSynchronization()) {
916 $gradeservice = new ilLTIConsumerGradeService();
917 $launch_vars['custom_lineitem_url'] = self::getIliasHttpPath(
918 ) . "/ltiservices.php/gradeservice/" . $contextId . "/lineitems/" . $this->id . "/lineitem";
919
920 // ! Moodle as tool provider requires a custom_lineitems_url even though this should be optional in launch request, especially if only posting score scope is permitted by platform
921 // http://www.imsglobal.org/spec/lti-ags/v2p0#example-link-has-a-single-line-item-tool-can-only-post-score
922 $launch_vars['custom_lineitems_url'] = self::getIliasHttpPath(
923 ) . "/ltiservices.php/gradeservice/" . $contextId . "/linetitems/";
924
925 $launch_vars['custom_ags_scopes'] = implode(",", $gradeservice->getPermittedScopes());
926 }
927
928 if (!empty(self::verifyPrivateKey())) {
929 $DIC->ui()->mainTemplate()->setOnScreenMessage('failure', 'ERROR_OPEN_SSL_CONF', true);
930 return null;
931 }
932 return self::LTISignJWT($launch_vars, $endpoint, $clientId, $deploymentId, $nonce);
933 }
934
939 // ToDo:
940
941 public static function buildContentSelectionParameters(
943 int $refId,
944 string $returnUrl,
945 string $nonce
946 ): ?array {
947 global $DIC;
948
949 $clientId = $provider->getClientId();
950 $deploymentId = $provider->getId();
951 $ilLTIConsumerLaunch = new ilLTIConsumerLaunch($refId);
952 $context = $ilLTIConsumerLaunch->getContext();
953 $contextType = $ilLTIConsumerLaunch::getLTIContextType($context["type"]);
954 $contextId = $context["id"];
955 $contextTitle = $context["title"];
956
957 $roles = "Instructor";
958 $usrImage = '';
959 if ($provider->getIncludeUserPicture()) {
960 $usrImage = self::getIliasHttpPath() . "/" . $DIC->user()->getPersonalPicturePath("small");
961 }
962 $documentTarget = "window";
963 if ($provider->getLaunchMethod() == self::LAUNCH_METHOD_EMBEDDED) {
964 $documentTarget = "iframe";
965 }
966 $nameGiven = '-';
967 $nameFamily = '-';
968 $nameFull = '-';
969 switch ($provider->getPrivacyName()) {
971 $nameGiven = $DIC->user()->getFirstname();
972 $nameFull = $DIC->user()->getFirstname();
973 break;
975 $usrName = $DIC->user()->getUTitle() ? $DIC->user()->getUTitle() . ' ' : '';
976 $usrName .= $DIC->user()->getLastname();
977 $nameFamily = $usrName;
978 $nameFull = $usrName;
979 break;
981 $nameGiven = $DIC->user()->getFirstname();
982 $nameFamily = $DIC->user()->getLastname();
983 $nameFull = $DIC->user()->getFullname();
984 break;
985 }
986
987 $userIdLTI = ilCmiXapiUser::getIdentAsId($provider->getPrivacyIdent(), $DIC->user());
988 $emailPrimary = ilCmiXapiUser::getIdent($provider->getPrivacyIdent(), $DIC->user());
989 $toolConsumerInstanceGuid = CLIENT_ID . ".";
990 $parseIliasUrl = parse_url(self::getIliasHttpPath());
991 if (array_key_exists("path", $parseIliasUrl)) {
992 $toolConsumerInstanceGuid .= implode(".", array_reverse(explode("/", $parseIliasUrl["path"])));
993 }
994 $toolConsumerInstanceGuid .= $parseIliasUrl["host"];
995
996 $content_select_vars = [
997 "lti_message_type" => "ContentItemSelectionRequest",
998 "lti_version" => "1.3.0",
999 "user_id" => (string) $userIdLTI,
1000 "user_image" => $usrImage,
1001 "roles" => $roles,
1002 "lis_person_name_given" => $nameGiven,
1003 "lis_person_name_family" => $nameFamily,
1004 "lis_person_name_full" => $nameFull,
1005 "lis_person_contact_email_primary" => $emailPrimary,
1006 "context_id" => (string) $contextId,
1007 "context_type" => $contextType,
1008 "context_title" => $contextTitle,
1009 "context_label" => $contextType . " " . $contextId,
1010 "launch_presentation_locale" => $DIC->language()->getLangKey(),
1011 "launch_presentation_document_target" => $documentTarget,
1012 "launch_presentation_width" => "",
1013 //recommended
1014 "launch_presentation_height" => "",
1015 //recommended
1016 "tool_consumer_instance_guid" => $toolConsumerInstanceGuid,
1017 "tool_consumer_instance_name" => $DIC->settings()->get("short_inst_name") ? $DIC->settings()->get(
1018 "short_inst_name"
1019 ) : CLIENT_ID,
1020 "tool_consumer_instance_description" => ilObjSystemFolder::_getHeaderTitle(),
1021 "tool_consumer_instance_url" => ilLink::_getLink(ROOT_FOLDER_ID, "root"),
1022 //ToDo? "https://vb52p70.example.com/release_5-3/goto.php?target=root_1&client_id=inno",
1023 "tool_consumer_instance_contact_email" => $DIC->settings()->get("admin_email"),
1024 "tool_consumer_info_product_family_code" => "ilias",
1025 "tool_consumer_info_version" => ILIAS_VERSION,
1026 "content_item_return_url" => $returnUrl,
1027 "accept_types" => "ltiResourceLink",
1028 "accept_presentation_document_targets" => "iframe,window,embed",
1029 "accept_multiple" => true,
1030 "auto_create" => true,
1031 ];
1032 $provider_custom_params = self::getProviderCustomParamsArray($provider);
1033 foreach ($provider_custom_params as $key => $value) {
1034 $content_select_vars['custom_' . $key] = $value;
1035 }
1036
1037 if (!empty(self::verifyPrivateKey())) {
1038 $DIC->ui()->mainTemplate()->setOnScreenMessage('failure', 'ERROR_OPEN_SSL_CONF', true);
1039 return null;
1040 }
1041 return self::LTISignJWT($content_select_vars, '', $clientId, $deploymentId, $nonce);
1042 }
1043
1044 public static function LTISignJWT(
1045 array $parms,
1046 string $endpoint,
1047 string $oAuthConsumerKey,
1048 $typeId = 0,
1049 string $nonce = ''
1050 ): array {
1051 if (empty($typeId)) {
1052 $typeId = 0;
1053 }
1054 $messageTypeMapping = Util::MESSAGE_TYPE_MAPPING;
1055 if (isset($parms['lti_message_type']) && array_key_exists($parms['lti_message_type'], $messageTypeMapping)) {
1056 $parms['lti_message_type'] = $messageTypeMapping[$parms['lti_message_type']];
1057 }
1058 if (isset($parms['roles'])) {
1059 $roles = explode(',', $parms['roles']);
1060 $newRoles = array();
1061 foreach ($roles as $role) {
1062 if (strpos($role, 'urn:lti:role:ims/lis/') === 0) {
1063 $role = 'http://purl.imsglobal.org/vocab/lis/v2/membership#' . substr($role, 21);
1064 } elseif (strpos($role, 'urn:lti:instrole:ims/lis/') === 0) {
1065 $role = 'http://purl.imsglobal.org/vocab/lis/v2/institution/person#' . substr($role, 25);
1066 } elseif (strpos($role, 'urn:lti:sysrole:ims/lis/') === 0) {
1067 $role = 'http://purl.imsglobal.org/vocab/lis/v2/system/person#' . substr($role, 24);
1068 } elseif ((strpos($role, '://') === false) && (strpos($role, 'urn:') !== 0)) {
1069 $role = "http://purl.imsglobal.org/vocab/lis/v2/membership#{$role}";
1070 }
1071 $newRoles[] = $role;
1072 }
1073 $parms['roles'] = implode(',', $newRoles);
1074 }
1075 $now = time();
1076 if (empty($nonce)) {
1077 $nonce = bin2hex(openssl_random_pseudo_bytes(10));
1078 }
1079 $claimMapping = Util::JWT_CLAIM_MAPPING;
1080 $payLoad = array(
1081 'nonce' => $nonce,
1082 'iat' => $now,
1083 'exp' => $now + 60,
1084 );
1085 $payLoad['iss'] = self::getIliasHttpPath();
1086 $payLoad['aud'] = $oAuthConsumerKey;
1087 $payLoad[self::LTI_JWT_CLAIM_PREFIX . '/claim/deployment_id'] = strval($typeId);
1088 if (!empty($endpoint)) { // only for launch request
1089 $payLoad[self::LTI_JWT_CLAIM_PREFIX . '/claim/target_link_uri'] = $endpoint;
1090 }
1091
1092 foreach ($parms as $key => $value) {
1093 $claim = self::LTI_JWT_CLAIM_PREFIX;
1094 if (array_key_exists($key, $claimMapping)) {
1095 $mapping = $claimMapping[$key];
1096
1097 if (isset($mapping['isArray']) && $mapping['isArray']) {
1098 $value = explode(',', $value);
1099 sort($value);
1100 } elseif (isset($mapping['isBoolean'])) {
1101 $value = $mapping['isBoolean'];
1102 }
1103 if (!empty($mapping['suffix'])) {
1104 $claim .= "-{$mapping['suffix']}";
1105 }
1106 $claim .= '/claim/';
1107 if (is_null($mapping['group'])) {
1108 $payLoad[$mapping['claim']] = $value;
1109 } elseif (empty($mapping['group'])) {
1110 $payLoad["{$claim}{$mapping['claim']}"] = $value;
1111 } else {
1112 $claim .= $mapping['group'];
1113 $payLoad[$claim][$mapping['claim']] = $value;
1114 }
1115 } elseif (strpos($key, 'custom_') === 0) {
1116 $payLoad["{$claim}/claim/custom"][substr($key, 7)] = $value;
1117 } elseif (strpos($key, 'ext_') === 0) {
1118 $payLoad["{$claim}/claim/ext"][substr($key, 4)] = $value;
1119 }
1120 }
1121 //self::getLogger()->debug(json_encode($payLoad,JSON_PRETTY_PRINT));
1122 if (!empty(self::verifyPrivateKey())) {
1123 throw new DomainException(self::ERROR_OPEN_SSL_CONF);
1124 }
1125 $privateKey = self::getPrivateKey();
1126 $jwt = Firebase\JWT\JWT::encode($payLoad, $privateKey['key'], 'RS256', $privateKey['kid']);
1127 $newParms = array();
1128 $newParms['id_token'] = $jwt;
1129 return $newParms;
1130 }
1131
1132 public static function getPrivateKey(): array
1133 {
1134 global $ilSetting;
1135 $err = self::verifyPrivateKey();
1136 if (!empty($err)) {
1137 return [];
1138 }
1139 $privatekey = $ilSetting->get(self::LTI_1_3_PRIVATE_KEY);
1140 $kid = $ilSetting->get(self::LTI_1_3_KID);
1141 return [
1142 "key" => $privatekey,
1143 "kid" => $kid
1144 ];
1145 }
1146
1147 public static function verifyPrivateKey(): string
1148 {
1149 global $ilSetting;
1150 $key = $ilSetting->get(self::LTI_1_3_PRIVATE_KEY);
1151
1152 if (empty($key)) {
1153 $kid = bin2hex(openssl_random_pseudo_bytes(10));
1154 $ilSetting->set(self::LTI_1_3_KID, $kid);
1155 $config = array(
1156 "digest_alg" => "sha256",
1157 "private_key_bits" => 2048,
1158 "private_key_type" => self::OPENSSL_KEYTYPE_RSA
1159 );
1160 $res = openssl_pkey_new($config);
1161 openssl_pkey_export($res, $privatekey);
1162 if (!empty($privatekey)) {
1163 $ilSetting->set(self::LTI_1_3_PRIVATE_KEY, $privatekey);
1164 } else {
1165 return self::ERROR_OPEN_SSL_CONF;
1166 }
1167 }
1168 return '';
1169 }
1170
1171 public static function getPublicKey(): string
1172 {
1173 $publicKey = null;
1174 $privateKey = self::getPrivateKey();
1175 $res = openssl_pkey_get_private($privateKey['key']);
1176 if ($res !== false) {
1177 $details = openssl_pkey_get_details($res);
1178 $publicKey = $details['key'];
1179 }
1180 return $publicKey;
1181 }
1182
1183 public static function getJwks(): array
1184 {
1185 $jwks = ['keys' => []];
1186
1187 $privatekey = self::getPrivateKey();
1188 $res = openssl_pkey_get_private($privatekey['key']);
1189 $details = openssl_pkey_get_details($res);
1190
1191 $jwk = [];
1192 $jwk['kty'] = 'RSA';
1193 $jwk['alg'] = 'RS256';
1194 $jwk['kid'] = $privatekey['kid'];
1195 $jwk['e'] = rtrim(strtr(base64_encode($details['rsa']['e']), '+/', '-_'), '=');
1196 $jwk['n'] = rtrim(strtr(base64_encode($details['rsa']['n']), '+/', '-_'), '=');
1197 $jwk['use'] = 'sig';
1198
1199 $jwks['keys'][] = $jwk;
1200 return $jwks;
1201 }
1202
1203 public static function getIliasHttpPath(): string
1204 {
1205 global $DIC;
1206
1207 $logger = $DIC->logger()->root();
1208
1209 if ($DIC['https']->isDetected()) {
1210 $protocol = 'https://';
1211 } else {
1212 $protocol = 'http://';
1213 }
1214 $host = $_SERVER['HTTP_HOST'];
1215
1216 $rq_uri = strip_tags($_SERVER['REQUEST_URI']);
1217
1218 // security fix: this failed, if the URI contained "?" and following "/"
1219 // -> we remove everything after "?"
1220 if (is_int($pos = strpos($rq_uri, "?"))) {
1221 $rq_uri = substr($rq_uri, 0, $pos);
1222 }
1223
1224 $path = pathinfo($rq_uri);
1225 if (isset($path['extension']) && $path['extension'] !== '') {
1226 $uri = dirname($rq_uri);
1227 } else {
1228 $uri = $rq_uri;
1229 }
1230 $logger->info("URI --- 1: " . $uri);
1231 $uri = str_replace("components/ILIAS/LTIConsumer", "", $uri);
1232 $logger->info("URI --- 2: " . $uri);
1233 $iliasHttpPath = ilContext::modifyHttpPath(implode('', [$protocol, $host, $uri]));
1234 $f = new \ILIAS\Data\Factory();
1235 $uri = $f->uri(rtrim($iliasHttpPath, "/"));
1236 return $uri->getBaseURI();
1237 }
1238
1239 public static function getPlattformId(): string
1240 {
1241 return self::getIliasHttpPath();
1242 }
1243
1244 public static function getAuthenticationRequestUrl(): string
1245 {
1246 return self::getIliasHttpPath() . "/ltiauth.php";
1247 }
1248
1249 public static function getAccessTokenUrl(): string
1250 {
1251 return self::getIliasHttpPath() . "/ltitoken.php";
1252 }
1253
1254 public static function getPublicKeysetUrl(): string
1255 {
1256 return self::getIliasHttpPath() . "/lticerts.php";
1257 }
1258
1259 public static function getRegistrationUrl(): string
1260 {
1261 return self::getIliasHttpPath() . "/ltiregistration.php";
1262 }
1263
1264 public static function getRegistrationStartUrl(): string
1265 {
1266 return self::getIliasHttpPath() . "/ltiregstart.php";
1267 }
1268
1269 public static function getRegistrationEndUrl(): string
1270 {
1271 return self::getIliasHttpPath() . "/ltiregend.php";
1272 }
1273
1274 public static function getOpenidConfigUrl(): string
1275 {
1276 return self::getIliasHttpPath() . "/lticonfig.php";
1277 }
1278
1279 public static function getOpenidConfig(): array
1280 {
1281 $scopesSupported = array('openid');
1282 $gradeservice = new ilLTIConsumerGradeService();
1283 $scopesSupported = array_merge($scopesSupported, $gradeservice->getPermittedScopes());
1284 return [
1285 "issuer" => self::getPlattformId(),
1286 "authorization_endpoint" => self::getAuthenticationRequestUrl(),
1287 "token_endpoint" => self::getAccessTokenUrl(),
1288 "token_endpoint_auth_methods_supported" => ["private_key_jwt"],
1289 "token_endpoint_auth_signing_alg_values_supported" => ["RS256"],
1290 "jwks_uri" => self::getPublicKeysetUrl(),
1291 "registration_endpoint" => self::getRegistrationUrl(),
1292 "scopes_supported" => $scopesSupported,
1293 "response_types_supported" => ["id_token"],
1294 "subject_types_supported" => ["public", "pairwise"],
1295 "id_token_signing_alg_values_supported" => ["RS256"],
1296 "claims_supported" => ["iss", "aud"],
1297 "https://purl.imsglobal.org/spec/lti-platform-configuration" => [
1298 "product_family_code" => "ilias.de",
1299 "version" => ILIAS_VERSION,
1300 "messages_supported" => [
1301 [
1302 "type" => "LtiResourceLinkRequest",
1303 "placements" => [
1304 ]
1305 ],
1306 [
1307 "type" => "LtiDeepLinkingRequest",
1308 "placements" => [
1309 ]
1310 ]
1311 ]
1312 ]
1313 ];
1314 }
1315
1316 public static function registerClient(array $data, object $tokenObj): array
1317 {
1318 // first analyse tool_config and filter only accepted params
1319 // append client_id (required) and deployment_id(=provider_id in ILIAS) (optional) to tool_config response
1320 global $DIC;
1321 $reponseData = $data;
1323 $toolConfig = $data['https://purl.imsglobal.org/spec/lti-tool-configuration'];
1324 $provider->setTitle(strip_tags($data['client_name'], ilObjectGUI::ALLOWED_TAGS_IN_TITLE_AND_DESCRIPTION));
1325 $provider->setProviderUrl($toolConfig['target_link_uri']);
1326 $provider->setInitiateLogin($data['initiate_login_uri']);
1327 $provider->setRedirectionUris(implode(",", $data['redirect_uris']));
1328 if (isset($data['jwks_uri'])) {
1329 $provider->setPublicKeyset($data['jwks_uri']);
1330 }
1331 foreach ($toolConfig['messages'] as $message) {
1332 if (isset($message['type']) && $message['type'] === 'LtiDeepLinkingRequest') {
1333 $provider->setContentItemUrl($message['target_link_uri']);
1334 }
1335 }
1336 /*
1337 if (isset($data['logo_uri'])) { // needs to be uploaded and then assign filepath
1338 $provider->setProviderIconFilename($data['logo_uri']);
1339 }
1340 */
1341 $provider->setKeyType('JWK_KEYSET');
1342 $provider->setLtiVersion('1.3.0');
1343 $provider->setClientId((string) $tokenObj->aud); //client_id
1344 $provider->setCreator((int) $tokenObj->sub); // user_id
1346 $provider->setIsGlobal(false);
1347 $provider->insert();
1348 $reponseData['client_id'] = $tokenObj->aud;
1349 $reponseData['https://purl.imsglobal.org/spec/lti-tool-configuration']['deployment_id'] = $provider->getId();
1350 return $reponseData;
1351 }
1352
1353 public static function getNewClientId(): string
1354 {
1355 return Util::getRandomString(15);
1356 }
1357
1358 public static function sendResponseError(int $code, string $message, $log = true): void
1359 {
1360 global $DIC;
1361 try {
1362 if ($log) {
1363 self::getLogger()->error("$code $message");
1364 }
1365 $DIC->http()->saveResponse(
1366 $DIC->http()->response()
1367 ->withStatus($code)
1368 ->withBody(Streams::ofString($message))
1369 );
1370 $DIC->http()->sendResponse();
1371 $DIC->http()->close();
1372 } catch (Exception $e) {
1373 $DIC->http()->close();
1374 }
1375 }
1376
1377 public static function sendResponseJson(array $obj): void
1378 {
1379 global $DIC;
1380 try {
1381 header('Content-Type: application/json; charset=utf-8');
1382 header('Cache-Control: no-store');
1383 header('Pragma: no-cache');
1384 echo json_encode($obj, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
1385 } catch (Exception $e) {
1386 self::sendResponseError(500, "error in sendResponseJson");
1387 $DIC->http()->close();
1388 }
1389 }
1390
1391 public static function getInstance(int $a_id = 0, bool $a_reference = true): \ilObjLTIConsumer
1392 {
1393 return new self($a_id, $a_reference);
1394 }
1395
1396 public function isMixedContentType(): bool
1397 {
1398 return true;
1399 }
1400
1401 public static function getRawData(): ?string
1402 {
1403 return file_get_contents('php://input');
1404 }
1405
1406 public static function getTokenObject(string $token): ?object
1407 {
1408 try {
1409 $keys = JWK::parseKeySet(self::getJwks());
1410 return JWT::decode($token, $keys);
1411 } catch (Exception $e) {
1412 return null;
1413 }
1414 }
1415
1416 public static function verifyToken(): ?object
1417 {
1418 global $DIC;
1419 $auth = $DIC->http()->request()->getHeader("Authorization");
1420 if (count($auth) < 1) {
1421 self::sendResponseError(405, "missing Authorization header");
1422 }
1423 preg_match('/Bearer\s+(.+)$/i', $auth[0], $matches);
1424 if (count($matches) != 2) {
1425 self::sendResponseError(405, "missing required Authorization Baerer token");
1426 }
1427 $token = $matches[1];
1428 return self::getTokenObject($token);
1429 }
1430
1431 public static function getLogger(): ilLogger
1432 {
1433 return ilLoggerFactory::getLogger('lti');
1434 }
1435
1436 protected function doCloneObject(ilObject2 $new_obj, int $a_target_id, ?int $a_copy_id = null): void
1437 {
1438 // LTI specific properties
1439 $new_obj->setProviderId($this->getProviderId());
1440 $new_obj->setLaunchMethod($this->getLaunchMethod());
1441 $new_obj->setCustomLaunchKey($this->getCustomLaunchKey());
1442 $new_obj->setCustomLaunchSecret($this->getCustomLaunchSecret());
1443 $new_obj->setCustomParams($this->getCustomParams());
1444 $new_obj->setUseXapi($this->getUseXapi());
1445 $new_obj->setCustomActivityId($this->getCustomActivityId());
1446 $new_obj->setStatementsReportEnabled($this->isStatementsReportEnabled());
1447 $new_obj->setMasteryScore($this->getMasteryScore());
1448
1449 // Highscore configuration
1450 $new_obj->setHighscoreEnabled($this->getHighscoreEnabled());
1451 $new_obj->setHighscoreAchievedTS($this->getHighscoreAchievedTS());
1452 $new_obj->setHighscorePercentage($this->getHighscorePercentage());
1453 $new_obj->setHighscoreWTime($this->getHighscoreWTime());
1454 $new_obj->setHighscoreOwnTable($this->getHighscoreOwnTable());
1455 $new_obj->setHighscoreTopTable($this->getHighscoreTopTable());
1456 $new_obj->setHighscoreTopNum($this->getHighscoreTopNum());
1457
1458 // Activation settings
1459 $new_obj->setActivationLimited($this->isActivationLimited());
1460 $new_obj->setActivationStartingTime($this->getActivationStartingTime());
1461 $new_obj->setActivationEndingTime($this->getActivationEndingTime());
1462
1463 if ($this->isActivationLimited() && $this->getActivationVisibility() !== null) {
1464 $new_obj->setActivationVisibility($this->getActivationVisibility());
1465 }
1466
1467 $new_obj->save();
1468 }
1469
1470 private function determineLTIRole(int $a_user_id, int $a_ref_id, ilRbacReview $rbac_review_instance): string
1471 {
1472 global $DIC;
1473
1474 $global_roles = $rbac_review_instance->assignedGlobalRoles($a_user_id);
1475 if (in_array(SYSTEM_ROLE_ID, $global_roles)) {
1476 return 'Administrator';
1477 }
1478
1479 $user_assigned_roles = $rbac_review_instance->assignedRoles($a_user_id);
1480 $parent_roles_data = $rbac_review_instance->getParentRoleIds($a_ref_id, true);
1481 $roles_in_path_ids = array_keys($parent_roles_data);
1482 $effective_roles_in_context = array_intersect($user_assigned_roles, $roles_in_path_ids);
1483
1484 if (!empty($effective_roles_in_context)) {
1485 $parent_ref_id = $DIC->repositoryTree()->getParentId($a_ref_id);
1486 $context_obj_type = ilObject::_lookupType($parent_ref_id, true);
1487
1488 $instructor_base_titles = [
1489 'il_' . $context_obj_type . '_admin',
1490 'il_' . $context_obj_type . '_tutor'
1491 ];
1492
1493 foreach ($effective_roles_in_context as $role_id) {
1494 $role_title = ilObject::_lookupTitle($role_id);
1495
1496 foreach ($instructor_base_titles as $base_title) {
1497 if (str_starts_with((string) $role_title, $base_title)) {
1498 return 'Instructor';
1499 }
1500 }
1501 }
1502 }
1503
1504 return 'Learner';
1505 }
1506}
Stream factory which enables the user to create streams without the knowledge of the concrete class.
Definition: Streams.php:32
static getIdent(int $userIdentMode, ilObjUser $user)
static getIdentAsId(int $userIdentMode, ilObjUser $user)
static modifyHttpPath(string $httpPath)
static signOAuth(array $a_params)
sign request data with OAuth
static getByKeys(int $a_obj_id, int $a_usr_id, ?bool $a_create=false)
Get a result by object and user key.
static getLogger(string $a_component_id)
Get component logger.
Component logger with individual log levels by component id.
const PRIVACY_IDENT_IL_UUID_RANDOM
bool $activationLimited
repository object activation settings (handled by ilObject)
static sendResponseError(int $code, string $message, $log=true)
doCloneObject(ilObject2 $new_obj, int $a_target_id, ?int $a_copy_id=null)
setCustomLaunchSecret(string $customLaunchSecret)
buildLaunchParametersLTI13(ilCmiXapiUser $cmixUser, string $token, string $endpoint, string $clientId, int $deploymentId, string $nonce, string $contextType, string $contextId, string $contextTitle, ?string $returnUrl='')
getHighscoreEnabled()
Gets the setting which determines if the highscore feature is enabled.
getHighscoreTopTable()
Gets, if the top-rankings table should be shown.
setProvider(ilLTIConsumeProvider $provider)
setHighscorePercentage(bool $a_percentage)
Sets if the percentages of the scores pass should be shown.
setCustomParams(string $customParams)
static getTokenObject(string $token)
setHighscoreEnabled(bool $a_enabled)
HIGHSCORE.
setHighscoreAchievedTS(bool $a_achieved_ts)
Sets if the date and time of the scores achievement should be displayed.
setHighscoreOwnTable(bool $a_own_table)
Sets if the table with the own ranking should be shown.
setLaunchMethod(string $launchMethod)
getHighscoreOwnTable()
Gets if the own rankings table should be shown.
static getInstance(int $a_id=0, bool $a_reference=true)
getHighscorePercentage()
Gets if the percentage column should be shown.
setActivationEndingTime(?int $activationEndingTime=null)
buildLaunchParameters(ilCmiXapiUser $cmixUser, string $token, string $contextType, string $contextId, string $contextTitle, ?string $returnUrl='')
setActivationLimited(bool $activationLimited)
setStatementsReportEnabled(bool $statementsReportEnabled)
setMasteryScorePercent(float $mastery_score_percent)
static LTISignJWT(array $parms, string $endpoint, string $oAuthConsumerKey, $typeId=0, string $nonce='')
static buildContentSelectionParameters(ilLTIConsumeProvider $provider, int $refId, string $returnUrl, string $nonce)
setHighscoreTopNum(int $a_top_num)
Sets the number of entries which are to be shown in the top-rankings table.
ilLTIConsumeProvider $provider
static registerClient(array $data, object $tokenObj)
setHighscoreWTime(bool $a_wtime)
Sets if the workingtime of the scores should be shown.
setCustomLaunchKey(string $customLaunchKey)
setProviderId(int $providerId)
static getProviderCustomParamsArray(ilLTIConsumeProvider $provider)
setHighscoreTopTable(bool $a_top_table)
Sets if the top-rankings table should be shown.
getHighscoreAchievedTS()
Returns if date and time of the scores achievement should be displayed.
setActivationVisibility(bool $activationVisibility)
setMasteryScore(float $mastery_score)
getHighscoreWTime()
Gets if the column with the workingtime should be shown.
determineLTIRole(int $a_user_id, int $a_ref_id, ilRbacReview $rbac_review_instance)
__construct(int $a_id=0, bool $a_reference=true)
ilObjLTIConsumer constructor.
getHighscoreTopNum(int $a_retval=10)
Gets the number of entries which are to be shown in the top-rankings table.
setCustomActivityId(string $custom_activity_id)
setActivationStartingTime(?int $activationStartingTime=null)
static sendResponseJson(array $obj)
setUseXapi(bool $use_xapi)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Class ilObjectActivation.
static getItem(int $ref_id)
static _lookupType(int $id, bool $reference=false)
static _lookupTitle(int $obj_id)
class ilRbacReview Contains Review functions of core Rbac.
assignedRoles(int $a_usr_id)
get all assigned roles to a given user
getParentRoleIds(int $a_endnode_id, bool $a_templates=false)
Get an array of parent role ids of all parent roles, if last parameter is set true you get also all p...
assignedGlobalRoles(int $a_usr_id)
Get assigned global roles for an user.
const CLIENT_ID
Definition: constants.php:41
const SYSTEM_ROLE_ID
Definition: constants.php:29
const ROOT_FOLDER_ID
Definition: constants.php:32
const ILIAS_VERSION
$clientId
Definition: ltiregend.php:26
$privateKey
Definition: ltiregstart.php:66
if(! $DIC->user() ->getId()||!ilLTIConsumerAccess::hasCustomProviderCreationAccess()) $params
Definition: ltiregstart.php:31
$typeId
Definition: ltiregstart.php:34
$log
Definition: ltiresult.php:34
$path
Definition: ltiservices.php:30
$res
Definition: ltiservices.php:69
$provider
Definition: ltitoken.php:80
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
global $ilSetting
Definition: privfeed.php:31
$_SERVER['HTTP_HOST']
Definition: raiseError.php:26
if(!file_exists('../ilias.ini.php'))
global $DIC
Definition: shib_login.php:26
$context
Definition: webdav.php:31
$message
Definition: xapiexit.php:31
$token
Definition: xapitoken.php:70
$refId
Definition: xapitoken.php:58
$param
Definition: xapitoken.php:46