ILIAS  trunk Revision v11.0_alpha-1689-g66c127b4ae8
All Data Structures Namespaces Files Functions Variables Enumerations Enumerator Modules Pages
class.ilRemoteObjectBase.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
26 abstract 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 
36  private ilLogger $logger;
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 
463  if ($adv_md_def->importFromECS((string) $type, (string) $raw_value, $id)) {
464  $do_save = true;
465  }
466  }
467  }
468 
469  if ($do_save) {
470  foreach ($values_records as $values_record) {
471  $additional = array();
472  foreach ($values_record->getADTGroup()->getElements() as $element_id => $element) {
473  if (!$element->isNull()) {
474  $additional[$element_id] = array("disabled" => array("integer", 1));
475  }
476  }
477  $values_record->write($additional);
478  }
479  }
480  }
481 
488  protected function updateCustomFromECSContent(ilECSSetting $a_server, $ecs_content): void
489  {
490  }
491 
497  public function isLocalObject(): bool
498  {
499  if (ilECSExportManager::getInstance()->_isRemote(
500  ilECSImportManager::getInstance()->lookupServerId($this->getId()),
501  (int) ilECSImportManager::getInstance()->_lookupEContentId($this->getId())
502  )) {
503  return false;
504  }
505  return true;
506  }
507 
513  public function handleCreate(ilECSSetting $a_server, int $a_econtent_id, array $a_mids): bool
514  {
515  return $this->handleUpdate($a_server, $a_econtent_id, $a_mids);
516  }
517 
523  public function handleUpdate(ilECSSetting $a_server, int $a_econtent_id, array $a_mids): bool
524  {
525  // get content details
527  $a_server->getServerId(),
528  $a_econtent_id,
529  $this->getECSObjectType()
530  );
531  if (!$details instanceof ilECSEContentDetails) {
532  $this->handleDelete($a_server, $a_econtent_id);
533  $this->logger->info(__METHOD__ . ': Handling delete of deprecated remote object. DONE');
534  return true;
535  }
536 
537  $this->logger->info(__METHOD__ . ': Receivers are ' . print_r($details->getReceivers(), true));
538  $this->logger->info(__METHOD__ . ': Senders are ' . print_r($details->getSenders(), true));
539 
540  // check owner (sender mid)
541  if (!ilECSParticipantSettings::getInstanceByServerId($a_server->getServerId())->isImportAllowed($details->getSenders())) {
542  $this->logger->info('Ignoring disabled participant. MID: ' . $details->getOwner());
543  return true;
544  }
545 
546  // new mids
547  foreach (array_intersect($a_mids, $details->getReceivers()) as $mid) {
548  try {
549  $connector = new ilECSConnector($a_server);
550  $res = $connector->getResource($this->getECSObjectType(), $a_econtent_id);
551  if ($res->getHTTPCode() === ilECSConnector::HTTP_CODE_NOT_FOUND) {
552  continue;
553  }
554  $json = $res->getResult();
555  $this->logger->info(__METHOD__ . ': Received json: ' . print_r($json, true));
556  if (!is_object($json)) {
557  // try as array (workaround for invalid content)
558  $json = $json[0];
559  if (!is_object($json)) {
560  throw new ilECSConnectorException('invalid json');
561  }
562  }
563  } catch (ilECSConnectorException $exc) {
564  $this->logger->error(__METHOD__ . ': Error parsing result. ' . $exc->getMessage());
565  $this->logger->logStack(ilLogLevel::ERROR);
566  return false;
567  }
568 
569  // Update existing
570 
571  // Check receiver mid
572  if ($obj_id = ilECSImportManager::getInstance()->_isImported($a_server->getServerId(), (string) $a_econtent_id, $mid)) {
573  $this->logger->info(__METHOD__ . ': Handling update for existing object');
574  $remote = ilObjectFactory::getInstanceByObjId($obj_id, false);
575  if (!$remote instanceof self) {
576  $this->logger->info(__METHOD__ . ': Cannot instantiate remote object. Got object type ' . $remote->getType());
577  continue;
578  }
579  $remote->updateFromECSContent($a_server, $json, $details->getMySender());
580  } else {
581  $this->logger->info(__METHOD__ . ': my sender ' . $details->getMySender() . 'vs mid' . $mid);
582 
583  $this->logger->info(__METHOD__ . ': Handling create for non existing object');
584  $this->createFromECSEContent($a_server, $json, $details->getMySender());
585 
586  // update import status
587  $this->logger->info(__METHOD__ . ': Updating import status');
588  $import = new ilECSImport($a_server->getServerId(), $this->getId());
589  $import->setEContentId((string) $a_econtent_id);
590  // Store receiver mid
591  $import->setMID($mid);
592  $import->save();
593 
594  $this->logger->info(__METHOD__ . ': Sending notification');
595  $this->sendNewContentNotification($a_server->getServerId());
596  }
597  }
598 
599  $this->logger->info(__METHOD__ . ': done');
600  return true;
601  }
602 
606  protected function sendNewContentNotification($a_server_id): void
607  {
608  $settings = ilECSSetting::getInstanceByServerId($a_server_id);
609  if (!count($settings->getEContentRecipients())) {
610  return;
611  }
612 
614  $lang->loadLanguageModule('ecs');
615 
616  $mail = new ilMail(self::MAIL_SENDER);
617  $message = $lang->txt('ecs_' . $this->getType() . '_created_body_a') . "\n\n";
618  $message .= $lang->txt('title') . ': ' . $this->getTitle() . "\n";
619  if ($desc = ($this->getDescription() !== '')) {
620  $message .= $lang->txt('desc') . ': ' . $desc . "\n";
621  }
622 
623  $href = ilLink::_getStaticLink($this->getRefId(), $this->getType(), true);
624  $message .= $lang->txt("perma_link") . ': ' . $href . "\n\n";
626 
627  $mail->enqueue(
628  $settings->getEContentRecipientsAsString(),
629  '',
630  '',
631  $lang->txt('ecs_new_econtent_subject'),
632  $message,
633  array()
634  );
635  }
636 
642  public function handleDelete(ilECSSetting $a_server, int $a_econtent_id, $a_mid = 0): bool
643  {
644  // there is no information about the original mid anymore.
645  // Therefor delete any remote objects with given econtent id
646  $obj_ids = ilECSImportManager::getInstance()->_lookupObjIds($a_server->getServerId(), $a_econtent_id);
647  $this->logger->info(__METHOD__ . ': Received obj_ids ' . print_r($obj_ids, true));
648 
649  foreach ($obj_ids as $obj_id) {
650  $references = ilObject::_getAllReferences($obj_id);
651  foreach ($references as $ref_id) {
652  if ($tmp_obj = ilObjectFactory::getInstanceByRefId($ref_id, false)) {
653  $this->logger->info(__METHOD__ . ': Deleting obsolete remote course: ' . $tmp_obj->getTitle());
654  $this->logger->info(print_r($this->tree->getNodeData($ref_id), true));
655  $this->logger->info(print_r($this->tree->getNodeData($tmp_obj->getId()), true));
656  $this->tree->deleteTree($this->tree->getNodeData($ref_id));
657  $tmp_obj->delete();
658  }
659  unset($tmp_obj);
660  }
661  }
662  return true;
663  }
664 
668  public function getAllResourceIds(ilECSSetting $a_server, bool $a_sender_only = false): array
669  {
670  try {
671  $connector = new ilECSConnector($a_server);
672  $connector->addHeader('X-EcsQueryStrings', $a_sender_only ? 'sender=true' : 'all=true'); // #11301
673  $list = $connector->getResourceList($this->getECSObjectType());
674  if ($list instanceof ilECSResult) {
675  return $list->getResult()->getLinkIds();
676  }
677  } catch (ilECSConnectorException $exc) {
678  $this->logger->error(__METHOD__ . ': Error getting resource list for type . ' . $this->getECSObjectType() . ' with message: ' . $exc->getMessage());
679  }
680 
681  return [];
682  }
683 }
static getInstancesForObjectId(int $a_obj_id, ?string $a_obj_type=null, string $a_sub_type="-", int $a_sub_id=0)
Remote test app class.
static getInstance(int $a_server_id, int $mid)
Get instance by server id and mid.
doDelete()
Delete remote object.
$res
Definition: ltiservices.php:66
sendNewContentNotification($a_server_id)
send notifications about new EContent
string $type
static getInstanceByServerId(int $a_server_id)
Get singleton instance.
getTableName()
Get db table name.
getOrganization()
get organization
doCreateCustomFields(array &$a_fields)
Add custom fields to db insert.
setRemoteLink(string $a_link)
set remote link
getRemoteLink()
get remote link
static getInstanceByServerId(int $a_server_id)
Get instance by server id.
Representation of ECS EContent Time Place.
Remote file app class.
createAuthResource(string $a_plain_realm)
create authentication resource on ecs server
Remote glossary app class.
setOrganization(string $a_organization)
set organization
getServerId()
Get current server id.
string $desc
static getInstance()
Get the singelton instance of this ilECSExportManager.
doUpdateCustomFields(array &$a_fields)
Add custom fields to db update.
static _getAllReferences(int $id)
get all reference ids for object ID
updateFromECSContent(ilECSSetting $a_server, object $a_ecs_content, int $a_owner)
update remote object settings from ecs content
doReadCustomFields(object $a_row)
Read custom fields from db row.
updateCustomFromECSContent(ilECSSetting $a_server, $ecs_content)
update remote object settings from ecs content
static getInstanceByEventType(string $a_type)
Get instance by ilECSEvent(QueueReader) type.
setTitle(string $title)
Presentation of ecs content details (http://...campusconnect/courselinks/id/details) ...
Remote learning module app class.
getImportId()
get import id
getECSObjectType()
Get ECS resource identifier, e.g.
getRealmPlain()
Get realm plain.
setPermissions(int $parent_ref_id)
__construct(int $a_id=0, bool $a_call_by_reference=true)
Remote wiki app class.
importMetadataFromJson(object $a_json, ilECSSetting $a_server, array $a_definition, int $a_mapping_mode)
Add advanced metadata to json (export)
setLocalInformation(string $a_info)
set local information
isLocalObject()
Is remote object from same installation?
static _getAutoGeneratedMessageString(?ilLanguage $lang=null)
const TYPE_TIMEPLACE
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
getAllResourceIds(ilECSSetting $a_server, bool $a_sender_only=false)
Get all available resources.
doCreate(bool $clone_mode=false)
handleUpdate(ilECSSetting $a_server, int $a_econtent_id, array $a_mids)
Handle update event.
createReference()
creates reference for object
static getInstance()
Get the singleton instance of this ilECSImportManager.
create()
note: title, description and type should be set when this function is called
static getInstanceByServerId(int $a_server_id)
Get instance by server id.
static getInstanceByServerId(int $a_server_id)
Get singleton instance per server.
static getInstanceByRefId(int $ref_id, bool $stop_on_error=true)
get an instance of an Ilias object by reference id
getFullRemoteLink()
get full remote link Including ecs generated hash and auth mode
global $DIC
Definition: shib_login.php:22
Storage of ECS imported objects.
handleCreate(ilECSSetting $a_server, int $a_econtent_id, array $a_mids)
Handle creation.
static _getLanguage(string $a_lang_key='')
Get language object.
Remote object app base class.
Remote course app class.
static getMatchingCategory(int $a_server_id, array $a_matchable_content)
get matching category
setMID(int $a_mid)
set mid
Remote group app class.
$lang
Definition: xapiexit.php:25
handleDelete(ilECSSetting $a_server, int $a_econtent_id, $a_mid=0)
Handle delete event.
static getInstanceByObjId(?int $obj_id, bool $stop_on_error=true)
get an instance of an Ilias object by object id
putInTree(int $parent_ref_id)
maybe this method should be in tree object!?
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
__construct(Container $dic, ilPlugin $plugin)
static getInstanceFromServer(int $a_server_id, int $a_econtent_id, string $a_resource_type)
Get data from server.
setEContentId($a_id)
set econtent id
doUpdate()
Update remote object.
$message
Definition: xapiexit.php:31
$server
Definition: shib_login.php:24
createFromECSEContent(ilECSSetting $a_server, object $a_ecs_content, int $a_owner)
create remote object from ECSContent object
Remote category app class.
static handleUpdate(int $a_obj_id, int $a_server_id, array $a_matchable_content)
Handle update of ecs content and create references.
setDescription(string $description)
Stores relevant user data.
setOwner(int $usr_id)
getLocalInformation()
get local information
ilObjUser $user
static getMatchableContent(string $a_resource_id, int $a_server_id, object $a_ecs_content, int $a_owner)
Convert ECS content to rule matchable values.