ILIAS  release_10 Revision v10.1-43-ga1241a92c2f
class.ilObjLTIConsumer.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
21 use ceLTIc\LTI\Util;
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 
49  protected ?ilLTIConsumeProvider $provider = null;
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 
61  protected string $launchMethod = self::LAUNCH_METHOD_NEW_WIN;
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 
149  public function setActivationVisibility(bool $activationVisibility): void
150  {
151  $this->activationVisibility = $activationVisibility;
152  }
153 
154  public function getMasteryScore(): float
155  {
156  return $this->mastery_score;
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 
189  public function getProvider(): ?\ilLTIConsumeProvider
190  {
191  return $this->provider;
192  }
193 
194  public function setProvider(ilLTIConsumeProvider $provider): void
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  {
221  return $this->customLaunchKey;
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 
301  public function setStatementsReportEnabled(bool $statementsReportEnabled): void
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 
332  public static function getProviderCustomParamsArray(ilLTIConsumeProvider $provider): array
333  {
334  $paramsAsArray = [];
335 
336  $params = $provider->getCustomParams();
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) {
613  $retval = $this->_highscore_top_num;
614  }
615 
616  return $retval;
617  }
618 
619  public function getHighscoreMode(): int
620  {
621  switch (true) {
622  case $this->getHighscoreOwnTable() && $this->getHighscoreTopTable():
623  return self::HIGHSCORE_SHOW_ALL_TABLES;
624 
625  case $this->getHighscoreTopTable():
626  return self::HIGHSCORE_SHOW_TOP_TABLE;
627 
628  case $this->getHighscoreOwnTable():
629  default:
630  return self::HIGHSCORE_SHOW_OWN_TABLE;
631  }
632  }
633 
637  public function setHighscoreMode(int $mode): void
638  {
639  switch ($mode) {
640  case self::HIGHSCORE_SHOW_ALL_TABLES:
641  $this->setHighscoreTopTable(true);
642  $this->setHighscoreOwnTable(true);
643  break;
644 
645  case self::HIGHSCORE_SHOW_TOP_TABLE:
646  $this->setHighscoreTopTable(true);
647  $this->setHighscoreOwnTable(false);
648  break;
649 
650  case self::HIGHSCORE_SHOW_OWN_TABLE:
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 
797  public function buildLaunchParametersLTI13(
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(
942  ilLTIConsumeProvider $provider,
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;
1322  $provider = new ilLTIConsumeProvider();
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 }
static getIdentAsId(int $userIdentMode, ilObjUser $user)
setUseXapi(bool $use_xapi)
$res
Definition: ltiservices.php:69
setInitiateLogin(string $initiate_login)
$context
Definition: webdav.php:31
setPublicKeyset(string $public_keyset)
getHighscoreWTime()
Gets if the column with the workingtime should be shown.
setActivationEndingTime(?int $activationEndingTime=null)
static getLogger(string $a_component_id)
Get component logger.
setCustomActivityId(string $custom_activity_id)
__construct(int $a_id=0, bool $a_reference=true)
ilObjLTIConsumer constructor.
setCustomParams(string $customParams)
setActivationLimited(bool $activationLimited)
const ROOT_FOLDER_ID
Definition: constants.php:32
setHighscoreEnabled(bool $a_enabled)
HIGHSCORE.
static sendResponseError(int $code, string $message, $log=true)
if(! $DIC->user() ->getId()||!ilLTIConsumerAccess::hasCustomProviderCreationAccess()) $params
Definition: ltiregstart.php:31
getHighscorePercentage()
Gets if the percentage column should be shown.
determineLTIRole(int $a_user_id, int $a_ref_id, ilRbacReview $rbac_review_instance)
getHighscoreEnabled()
Gets the setting which determines if the highscore feature is enabled.
setStatementsReportEnabled(bool $statementsReportEnabled)
const SYSTEM_ROLE_ID
Definition: constants.php:29
$clientId
Definition: ltiregend.php:26
setMasteryScorePercent(float $mastery_score_percent)
bool $activationLimited
repository object activation settings (handled by ilObject)
setHighscoreWTime(bool $a_wtime)
Sets if the workingtime of the scores should be shown.
setHighscoreAchievedTS(bool $a_achieved_ts)
Sets if the date and time of the scores achievement should be displayed.
setHighscoreTopTable(bool $a_top_table)
Sets if the top-rankings table should be shown.
setContentItemUrl(string $content_item_url)
setCustomLaunchSecret(string $customLaunchSecret)
$refId
Definition: xapitoken.php:56
static buildContentSelectionParameters(ilLTIConsumeProvider $provider, int $refId, string $returnUrl, string $nonce)
static modifyHttpPath(string $httpPath)
static registerClient(array $data, object $tokenObj)
const PRIVACY_IDENT_IL_UUID_RANDOM
static getIdent(int $userIdentMode, ilObjUser $user)
sort()
description: > Example for rendering a Sort Glyph.
Definition: sort.php:25
$path
Definition: ltiservices.php:30
const ILIAS_VERSION
static getInstance(int $a_id=0, bool $a_reference=true)
getHighscoreTopNum(int $a_retval=10)
Gets the number of entries which are to be shown in the top-rankings table.
setRedirectionUris(string $redirection_uris)
static _lookupTitle(int $obj_id)
setLaunchMethod(string $launchMethod)
$token
Definition: xapitoken.php:67
setHighscoreOwnTable(bool $a_own_table)
Sets if the table with the own ranking should be shown.
$_SERVER['HTTP_HOST']
Definition: raiseError.php:10
static getTokenObject(string $token)
$param
Definition: xapitoken.php:44
const CLIENT_ID
Definition: constants.php:41
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...
static LTISignJWT(array $parms, string $endpoint, string $oAuthConsumerKey, $typeId=0, string $nonce='')
global $DIC
Definition: shib_login.php:25
ilLTIConsumeProvider $provider
setLtiVersion(string $lti_version)
$privateKey
Definition: ltiregstart.php:66
static getByKeys(int $a_obj_id, int $a_usr_id, ?bool $a_create=false)
Get a result by object and user key.
setHighscorePercentage(bool $a_percentage)
Sets if the percentages of the scores pass should be shown.
setActivationVisibility(bool $activationVisibility)
buildLaunchParametersLTI13(ilCmiXapiUser $cmixUser, string $token, string $endpoint, string $clientId, int $deploymentId, string $nonce, string $contextType, string $contextId, string $contextTitle, ?string $returnUrl='')
static getItem(int $ref_id)
static getProviderCustomParamsArray(ilLTIConsumeProvider $provider)
setActivationStartingTime(?int $activationStartingTime=null)
buildLaunchParameters(ilCmiXapiUser $cmixUser, string $token, string $contextType, string $contextId, string $contextTitle, ?string $returnUrl='')
global $ilSetting
Definition: privfeed.php:32
__construct(Container $dic, ilPlugin $plugin)
setCustomLaunchKey(string $customLaunchKey)
getHighscoreTopTable()
Gets, if the top-rankings table should be shown.
assignedGlobalRoles(int $a_usr_id)
Get assigned global roles for an user.
getHighscoreAchievedTS()
Returns if date and time of the scores achievement should be displayed.
ilLogger $log
doCloneObject(ilObject2 $new_obj, int $a_target_id, ?int $a_copy_id=null)
static _lookupType(int $id, bool $reference=false)
setHighscoreTopNum(int $a_top_num)
Sets the number of entries which are to be shown in the top-rankings table.
static sendResponseJson(array $obj)
header()
expected output: > ILIAS shows the rendered Component.
Definition: header.php:13
static signOAuth(array $a_params)
sign request data with OAuth
setProviderUrl(string $provider_url)
Class ilObjectActivation.
assignedRoles(int $a_usr_id)
get all assigned roles to a given user
getHighscoreOwnTable()
Gets if the own rankings table should be shown.
setMasteryScore(float $mastery_score)
setProviderId(int $providerId)
$typeId
Definition: ltiregstart.php:34
setProvider(ilLTIConsumeProvider $provider)