ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilRemoteObjectBase.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
26abstract class ilRemoteObjectBase extends ilObject2
27{
28 protected ?string $local_information = null;
29 protected ?string $remote_link = null;
30 protected ?string $organization = null;
31 protected ?int $mid = null;
32 protected string $auth_hash = '';
33
34 protected string $realm_plain = '';
35
37
38 public const MAIL_SENDER = 6;
39 public const OBJECT_OWNER = 6;
40
41 public function __construct(int $a_id = 0, bool $a_call_by_reference = true)
42 {
43 global $DIC;
44
45 parent::__construct($a_id, $a_call_by_reference);
46
47 $this->logger = $DIC->logger()->wsrv();
48 }
49
55 public static function getInstanceByEventType(string $a_type)
56 {
57 switch ($a_type) {
59 return new ilObjRemoteCourse();
60
62 return new ilObjRemoteCategory();
63
65 return new ilObjRemoteFile();
66
68 return new ilObjRemoteGlossary();
69
71 return new ilObjRemoteGroup();
72
74 return new ilObjRemoteLearningModule();
75
77 return new ilObjRemoteWiki();
78
80 return new ilObjRemoteTest();
81
82 default:
83 return null;
84 }
85 }
86
87 protected function beforeCreate(): bool
88 {
89 $this->setOwner(self::OBJECT_OWNER);
90 return parent::beforeCreate();
91 }
92
96 abstract protected function getTableName(): string;
97
101 abstract protected function getECSObjectType(): string;
102
103
107 public function getRealmPlain(): string
108 {
109 return $this->realm_plain;
110 }
111
115 public function setOrganization(string $a_organization): void
116 {
117 $this->organization = $a_organization;
118 }
119
123 public function getOrganization(): string
124 {
125 return $this->organization ?? '';
126 }
127
131 public function getLocalInformation(): string
132 {
133 return $this->local_information ?? '';
134 }
135
141 public function setLocalInformation(string $a_info): void
142 {
143 $this->local_information = $a_info;
144 }
145
149 public function getMID(): int
150 {
151 return $this->mid;
152 }
153
159 public function setMID(int $a_mid): void
160 {
161 $this->mid = $a_mid;
162 }
163
169 public function setRemoteLink(string $a_link): void
170 {
171 $this->remote_link = $a_link;
172 }
173
177 public function getRemoteLink(): string
178 {
179 return $this->remote_link;
180 }
181
188 public function getFullRemoteLink(): string
189 {
190 $server_id = ilECSImportManager::getInstance()->lookupServerId($this->getId());
192 $setting = ilECSParticipantSetting::getInstance($server_id, $this->mid);
193 $user = new ilECSUser($this->user);
194 $ecs_user_data = $user->toGET($setting);
195 $this->logger->info(__METHOD__ . ': Using ecs user data ' . $ecs_user_data);
196
197 // check token mechanism enabled
198 $part = new ilECSParticipantSetting($server_id, $this->getMID());
199 if (!$part->isTokenEnabled()) {
200 return $this->getRemoteLink();
201 }
202
203 $auth_hash = $this->createAuthResource($this->getRemoteLink() . $user->toREALM());
204 $ecs_url_hash = 'ecs_hash_url=' . urlencode($server->getServerURI() . '/sys/auths/' . $auth_hash);
205
206 if (strpos($this->getRemoteLink(), '?')) {
207 $link = $this->getRemoteLink() . '&ecs_hash=' . $auth_hash . $ecs_user_data . '&' . $ecs_url_hash;
208 } else {
209 $link = $this->getRemoteLink() . '?ecs_hash=' . $auth_hash . $ecs_user_data . '&' . $ecs_url_hash;
210 }
211 $this->logger->info(__METHOD__ . ': ECS full link: ' . $link);
212 return $link;
213 }
214
218 public function createAuthResource(string $a_plain_realm)
219 {
220 try {
221 $server_id = ilECSImportManager::getInstance()->lookupServerId($this->getId());
222 $import_info = new ilECSImport($server_id, $this->getId());
223
224 $connector = new ilECSConnector(ilECSSetting::getInstanceByServerId($server_id));
225 $auth = new ilECSAuth();
226 $auth->setPid($import_info->getMID());
227 //TODO URL is deprecated
228 $auth->setUrl($this->getRemoteLink());
229 $realm = sha1($a_plain_realm);
230 $this->logger->info(__METHOD__ . ': Using realm ' . $a_plain_realm);
231 $auth->setRealm($realm);
232 $this->logger->info(__METHOD__ . ' Mid is ' . $this->getMID());
233 //TODO remove @
234 $this->auth_hash = $connector->addAuth(json_encode($auth, JSON_THROW_ON_ERROR), $this->getMID());
235 return $this->auth_hash;
236 } catch (ilECSConnectorException $exc) {
237 $this->logger->info(__METHOD__ . ': Caught error from ECS Auth resource: ' . $exc->getMessage());
238 return false;
239 }
240 }
241
242 protected function doCreate(bool $clone_mode = false): void
243 {
244 $fields = array(
245 "obj_id" => array("integer", $this->getId()),
246 "local_information" => array("text", ""),
247 "remote_link" => array("text", ""),
248 "mid" => array("integer", 0),
249 "organization" => array("text", "")
250 );
251
252 $this->doCreateCustomFields($fields);
253
254 $this->db->insert($this->getTableName(), $fields);
255 }
256
260 protected function doCreateCustomFields(array &$a_fields): void
261 {
262 }
263
267 protected function doUpdate(): void
268 {
269 $fields = array(
270 "local_information" => array("text", $this->getLocalInformation()),
271 "remote_link" => array("text", $this->getRemoteLink()),
272 "mid" => array("integer", $this->getMID()),
273 "organization" => array("text", $this->getOrganization())
274 );
275
276 $this->doUpdateCustomFields($fields);
277
278 $where = array("obj_id" => array("integer", $this->getId()));
279
280 $this->db->update($this->getTableName(), $fields, $where);
281 }
282
286 protected function doUpdateCustomFields(array &$a_fields): void
287 {
288 }
289
293 protected function doDelete(): void
294 {
295 //put here your module specific stuff
296 ilECSImportManager::getInstance()->_deleteByObjId($this->getId());
297
298 $query = "DELETE FROM " . $this->getTableName() .
299 " WHERE obj_id = " . $this->db->quote($this->getId(), 'integer') . " ";
300 $this->db->manipulate($query);
301 }
302
303 protected function doRead(): void
304 {
305 $query = "SELECT * FROM " . $this->getTableName() .
306 " WHERE obj_id = " . $this->db->quote($this->getId(), 'integer') . " ";
307 $res = $this->db->query($query);
308 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
309 if (!is_null($row->local_information)) {
310 $this->setLocalInformation($row->local_information);
311 }
312 if (!is_null($row->remote_link)) {
313 $this->setRemoteLink($row->remote_link);
314 }
315 $this->setMID((int) $row->mid);
316 if (!is_null($row->organization)) {
317 $this->setOrganization($row->organization);
318 }
319 $this->doReadCustomFields($row);
320 }
321 }
322
326 protected function doReadCustomFields(object $a_row): void
327 {
328 }
329
337 public function createFromECSEContent(ilECSSetting $a_server, object $a_ecs_content, int $a_owner): void
338 {
339 $this->create();
340 $this->log->info("Done calling create, creating reference");
341 // won't work for personal workspace
342 $this->createReference();
343 $this->log->info("Done creating reference, setting permissions");
344 $this->setPermissions($a_server->getImportId());
345 $this->log->info("Done setting permissions, putting object in tree");
346
347 $matchable_content = ilECSUtils::getMatchableContent(
348 $this->getECSObjectType(),
349 $a_server->getServerId(),
350 $a_ecs_content,
351 $a_owner
352 );
353
355 $a_server->getServerId(),
356 $matchable_content
357 ));
358 $this->log->info("Done putting object in tree, updateing object");
359
360 $this->updateFromECSContent($a_server, $a_ecs_content, $a_owner);
361 }
362
368 public function updateFromECSContent(ilECSSetting $a_server, object $a_ecs_content, int $a_owner): void
369 {
370 $this->logger->info('updateFromECSContent: ' . print_r($a_ecs_content, true));
371
372 // Get organisation for owner (ObjectListGUI performance)
373 $organisation = null;
374 if ($a_owner) {
375 $organisation = ilECSCommunityReader::getInstanceByServerId($a_server->getServerId())
376 ->getParticipantNameByMid($a_owner);
377 $this->logger->info('found organisation: ' . $organisation);
378 }
379
380 $this->setMID($a_owner); // obsolete?
381 $this->setOrganization($organisation);
382 $this->setTitle($a_ecs_content->title);
383 $this->setDescription($a_ecs_content->abstract);
384 $this->setRemoteLink($a_ecs_content->url);
385
386 $this->logger->info('updateCustomFromECSContent');
387 $this->updateCustomFromECSContent($a_server, $a_ecs_content);
388
389 // we are updating late so custom values can be set
390
391 $this->logger->info('ilObject->update()');
392 $this->update();
393
394 $matchable_content = ilECSUtils::getMatchableContent(
395 $this->getECSObjectType(),
396 $a_server->getServerId(),
397 $a_ecs_content,
398 $a_owner
399 );
400
401 // rule-based category mapping
403 $this->getId(),
404 $a_server->getServerId(),
405 $matchable_content
406 );
407 }
408
413 protected function importMetadataFromJson(object $a_json, ilECSSetting $a_server, array $a_definition, int $a_mapping_mode): void
414 {
415 $this->logger->info("importing metadata from json: " . print_r($a_json, true));
416
418 $values_records = ilAdvancedMDValues::getInstancesForObjectId($this->getId(), $this->getType());
419 foreach ($values_records as $values_record) {
420 // this correctly binds group and definitions
421 $values_record->read();
422 }
423
424 $do_save = false;
425
426 foreach ($a_definition as $id => $type) {
427 if (is_array($type)) {
428 [$type, $target] = $type;
429 } else {
430 $target = $id;
431 }
432
433 $timePlace = null;
434 if ($field = $mappings->getMappingByECSName($a_mapping_mode, $id)) {
435 // find element in records
436 $adv_md_def = null;
437 foreach ($values_records as $values_record) {
438 $adv_md_defs = $values_record->getDefinitions();
439 if (isset($adv_md_defs[$field])) {
440 $adv_md_def = $adv_md_defs[$field];
441 break;
442 }
443 }
444 if (!$adv_md_def) {
445 continue;
446 }
447 if (property_exists($a_json, $target)){
448 $raw_value = $a_json->{$target};
449 } else {
450 $raw_value = '';
451 }
452
454 if (!is_object($timePlace)) {
455 $timePlace = new ilECSTimePlace();
456 if (is_object($raw_value)) {
457 $timePlace->loadFromJSON($raw_value);
458 }
459 }
460 $raw_value = $timePlace;
461 }
462 if (is_string($raw_value) && $adv_md_def->importFromECS((string) $type, (string) $raw_value, $id)) {
463 $do_save = true;
464 }
465 }
466 }
467
468 if ($do_save) {
469 foreach ($values_records as $values_record) {
470 $additional = array();
471 foreach ($values_record->getADTGroup()->getElements() as $element_id => $element) {
472 if (!$element->isNull()) {
473 $additional[$element_id] = array("disabled" => array("integer", 1));
474 }
475 }
476 $values_record->write($additional);
477 }
478 }
479 }
480
487 protected function updateCustomFromECSContent(ilECSSetting $a_server, $ecs_content): void
488 {
489 }
490
496 public function isLocalObject(): bool
497 {
498 if (ilECSExportManager::getInstance()->_isRemote(
499 ilECSImportManager::getInstance()->lookupServerId($this->getId()),
500 (int) ilECSImportManager::getInstance()->_lookupEContentId($this->getId())
501 )) {
502 return false;
503 }
504 return true;
505 }
506
512 public function handleCreate(ilECSSetting $a_server, int $a_econtent_id, array $a_mids): bool
513 {
514 return $this->handleUpdate($a_server, $a_econtent_id, $a_mids);
515 }
516
522 public function handleUpdate(ilECSSetting $a_server, int $a_econtent_id, array $a_mids): bool
523 {
524 // get content details
526 $a_server->getServerId(),
527 $a_econtent_id,
528 $this->getECSObjectType()
529 );
530 if (!$details instanceof ilECSEContentDetails) {
531 $this->handleDelete($a_server, $a_econtent_id);
532 $this->logger->info(__METHOD__ . ': Handling delete of deprecated remote object. DONE');
533 return true;
534 }
535
536 $this->logger->info(__METHOD__ . ': Receivers are ' . print_r($details->getReceivers(), true));
537 $this->logger->info(__METHOD__ . ': Senders are ' . print_r($details->getSenders(), true));
538
539 // check owner (sender mid)
540 if (!ilECSParticipantSettings::getInstanceByServerId($a_server->getServerId())->isImportAllowed($details->getSenders())) {
541 $this->logger->info('Ignoring disabled participant. MID: ' . $details->getOwner());
542 return true;
543 }
544
545 // new mids
546 foreach (array_intersect($a_mids, $details->getReceivers()) as $mid) {
547 try {
548 $connector = new ilECSConnector($a_server);
549 $res = $connector->getResource($this->getECSObjectType(), $a_econtent_id);
550 if ($res->getHTTPCode() === ilECSConnector::HTTP_CODE_NOT_FOUND) {
551 continue;
552 }
553 $json = $res->getResult();
554 $this->logger->info(__METHOD__ . ': Received json: ' . print_r($json, true));
555 if (!is_object($json)) {
556 // try as array (workaround for invalid content)
557 $json = $json[0];
558 if (!is_object($json)) {
559 throw new ilECSConnectorException('invalid json');
560 }
561 }
562 } catch (ilECSConnectorException $exc) {
563 $this->logger->error(__METHOD__ . ': Error parsing result. ' . $exc->getMessage());
564 $this->logger->logStack(ilLogLevel::ERROR);
565 return false;
566 }
567
568 // Update existing
569
570 // Check receiver mid
571 if ($obj_id = ilECSImportManager::getInstance()->_isImported($a_server->getServerId(), (string) $a_econtent_id, $mid)) {
572 $this->logger->info(__METHOD__ . ': Handling update for existing object');
573 $remote = ilObjectFactory::getInstanceByObjId($obj_id, false);
574 if (!$remote instanceof self) {
575 $this->logger->info(__METHOD__ . ': Cannot instantiate remote object. Got object type ' . $remote->getType());
576 continue;
577 }
578 $remote->updateFromECSContent($a_server, $json, $details->getMySender());
579 } else {
580 $this->logger->info(__METHOD__ . ': my sender ' . $details->getMySender() . 'vs mid' . $mid);
581
582 $this->logger->info(__METHOD__ . ': Handling create for non existing object');
583 $this->createFromECSEContent($a_server, $json, $details->getMySender());
584
585 // update import status
586 $this->logger->info(__METHOD__ . ': Updating import status');
587 $import = new ilECSImport($a_server->getServerId(), $this->getId());
588 $import->setEContentId((string) $a_econtent_id);
589 // Store receiver mid
590 $import->setMID($mid);
591 $import->save();
592
593 $this->logger->info(__METHOD__ . ': Sending notification');
594 $this->sendNewContentNotification($a_server->getServerId());
595 }
596 }
597
598 $this->logger->info(__METHOD__ . ': done');
599 return true;
600 }
601
605 protected function sendNewContentNotification($a_server_id): void
606 {
607 $settings = ilECSSetting::getInstanceByServerId($a_server_id);
608 if (!count($settings->getEContentRecipients())) {
609 return;
610 }
611
613 $lang->loadLanguageModule('ecs');
614
615 $mail = new ilMail(self::MAIL_SENDER);
616 $message = $lang->txt('ecs_' . $this->getType() . '_created_body_a') . "\n\n";
617 $message .= $lang->txt('title') . ': ' . $this->getTitle() . "\n";
618 if ($desc = ($this->getDescription() !== '')) {
619 $message .= $lang->txt('desc') . ': ' . $desc . "\n";
620 }
621
622 $href = ilLink::_getStaticLink($this->getRefId(), $this->getType(), true);
623 $message .= $lang->txt("perma_link") . ': ' . $href . "\n\n";
625
626 $mail->enqueue(
627 $settings->getEContentRecipientsAsString(),
628 '',
629 '',
630 $lang->txt('ecs_new_econtent_subject'),
631 $message,
632 array()
633 );
634 }
635
641 public function handleDelete(ilECSSetting $a_server, int $a_econtent_id, $a_mid = 0): bool
642 {
643 // there is no information about the original mid anymore.
644 // Therefor delete any remote objects with given econtent id
645 $obj_ids = ilECSImportManager::getInstance()->_lookupObjIds($a_server->getServerId(), $a_econtent_id);
646 $this->logger->info(__METHOD__ . ': Received obj_ids ' . print_r($obj_ids, true));
647
648 foreach ($obj_ids as $obj_id) {
649 $references = ilObject::_getAllReferences($obj_id);
650 foreach ($references as $ref_id) {
651 if ($tmp_obj = ilObjectFactory::getInstanceByRefId($ref_id, false)) {
652 $this->logger->info(__METHOD__ . ': Deleting obsolete remote course: ' . $tmp_obj->getTitle());
653 $this->logger->info(print_r($this->tree->getNodeData($ref_id), true));
654 $this->logger->info(print_r($this->tree->getNodeData($tmp_obj->getId()), true));
655 $this->tree->deleteTree($this->tree->getNodeData($ref_id));
656 $tmp_obj->delete();
657 }
658 unset($tmp_obj);
659 }
660 }
661 return true;
662 }
663
667 public function getAllResourceIds(ilECSSetting $a_server, bool $a_sender_only = false): array
668 {
669 try {
670 $connector = new ilECSConnector($a_server);
671 $connector->addHeader('X-EcsQueryStrings', $a_sender_only ? 'sender=true' : 'all=true'); // #11301
672 $list = $connector->getResourceList($this->getECSObjectType());
673 if ($list instanceof ilECSResult) {
674 return $list->getResult()->getLinkIds();
675 }
676 } catch (ilECSConnectorException $exc) {
677 $this->logger->error(__METHOD__ . ': Error getting resource list for type . ' . $this->getECSObjectType() . ' with message: ' . $exc->getMessage());
678 }
679
680 return [];
681 }
682}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
static getInstancesForObjectId(int $a_obj_id, ?string $a_obj_type=null, string $a_sub_type="-", int $a_sub_id=0)
static handleUpdate(int $a_obj_id, int $a_server_id, array $a_matchable_content)
Handle update of ecs content and create references.
static getMatchingCategory(int $a_server_id, array $a_matchable_content)
get matching category
static getInstanceByServerId(int $a_server_id)
Get instance by server id.
static getInstanceByServerId(int $a_server_id)
Get singleton instance.
Presentation of ecs content details (http://...campusconnect/courselinks/id/details)
static getInstanceFromServer(int $a_server_id, int $a_econtent_id, string $a_resource_type)
Get data from server.
static getInstance()
Get the singelton instance of this ilECSExportManager.
static getInstance()
Get the singleton instance of this ilECSImportManager.
Storage of ECS imported objects.
static getInstance(int $a_server_id, int $mid)
Get instance by server id and mid.
static getInstanceByServerId(int $a_server_id)
Get instance by server id.
getServerId()
Get current server id.
static getInstanceByServerId(int $a_server_id)
Get singleton instance per server.
getImportId()
get import id
Representation of ECS EContent Time Place.
Stores relevant user data.
const TYPE_TIMEPLACE
static getMatchableContent(string $a_resource_id, int $a_server_id, object $a_ecs_content, int $a_owner)
Convert ECS content to rule matchable values.
static _getLanguage(string $a_lang_key='')
Get language object.
Component logger with individual log levels by component id.
static _getAutoGeneratedMessageString(?ilLanguage $lang=null)
Remote category app class.
Remote course app class.
Remote file app class.
Remote glossary app class.
Remote group app class.
Remote learning module app class.
Remote test app class.
Remote wiki app class.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getInstanceByRefId(int $ref_id, bool $stop_on_error=true)
get an instance of an Ilias object by reference id
static getInstanceByObjId(?int $obj_id, bool $stop_on_error=true)
get an instance of an Ilias object by object id
setPermissions(int $parent_ref_id)
createReference()
creates reference for object
putInTree(int $parent_ref_id)
maybe this method should be in tree object!?
static _getAllReferences(int $id)
get all reference ids for object ID
setTitle(string $title)
setOwner(int $usr_id)
create()
note: title, description and type should be set when this function is called
ilObjUser $user
string $type
setDescription(string $description)
Remote object app base class.
updateCustomFromECSContent(ilECSSetting $a_server, $ecs_content)
update remote object settings from ecs content
doUpdateCustomFields(array &$a_fields)
Add custom fields to db update.
static getInstanceByEventType(string $a_type)
Get instance by ilECSEvent(QueueReader) type.
createAuthResource(string $a_plain_realm)
create authentication resource on ecs server
getOrganization()
get organization
handleUpdate(ilECSSetting $a_server, int $a_econtent_id, array $a_mids)
Handle update event.
setRemoteLink(string $a_link)
set remote link
getTableName()
Get db table name.
handleCreate(ilECSSetting $a_server, int $a_econtent_id, array $a_mids)
Handle creation.
getLocalInformation()
get local information
setLocalInformation(string $a_info)
set local information
__construct(int $a_id=0, bool $a_call_by_reference=true)
Constructor.
doCreate(bool $clone_mode=false)
createFromECSEContent(ilECSSetting $a_server, object $a_ecs_content, int $a_owner)
create remote object from ECSContent object
doUpdate()
Update remote object.
isLocalObject()
Is remote object from same installation?
getFullRemoteLink()
get full remote link Including ecs generated hash and auth mode
doDelete()
Delete remote object.
importMetadataFromJson(object $a_json, ilECSSetting $a_server, array $a_definition, int $a_mapping_mode)
Add advanced metadata to json (export)
doReadCustomFields(object $a_row)
Read custom fields from db row.
updateFromECSContent(ilECSSetting $a_server, object $a_ecs_content, int $a_owner)
update remote object settings from ecs content
getRealmPlain()
Get realm plain.
setOrganization(string $a_organization)
set organization
getECSObjectType()
Get ECS resource identifier, e.g.
handleDelete(ilECSSetting $a_server, int $a_econtent_id, $a_mid=0)
Handle delete event.
getAllResourceIds(ilECSSetting $a_server, bool $a_sender_only=false)
Get all available resources.
beforeCreate()
If overwritten this method should return true, there is currently no "abort" handling for cases where...
sendNewContentNotification($a_server_id)
send notifications about new EContent
doCreateCustomFields(array &$a_fields)
Add custom fields to db insert.
$ref_id
Definition: ltiauth.php:66
$res
Definition: ltiservices.php:69
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
global $DIC
Definition: shib_login.php:26
$server
Definition: shib_login.php:28
$lang
Definition: xapiexit.php:25
$message
Definition: xapiexit.php:31