ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilSoapUtils.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
26{
27 public function ignoreUserAbort(): int
28 {
29 return ignore_user_abort(true);
30 }
31
32 public function disableSOAPCheck(): void
33 {
34 $this->soap_check = false;
35 }
36
40 public function saveTempFileAsMediaObject(string $sid, string $name, string $tmp_name)
41 {
42 $this->initAuth($sid);
43 $this->initIlias();
44
45 if (!$this->checkSession($sid)) {
46 return $this->raiseError($this->getMessage(), $this->getMessageCode());
47 }
48
49 return ilObjMediaObject::_saveTempFileAsMediaObject($name, $tmp_name);
50 }
51
55 public function getMobsOfObject(string $sid, string $a_type, int $a_id)
56 {
57 $this->initAuth($sid);
58 $this->initIlias();
59
60 if (!$this->checkSession($sid)) {
61 return $this->raiseError($this->getMessage(), $this->getMessageCode());
62 }
63
64 return ilObjMediaObject::_getMobsOfObject($a_type, $a_id);
65 }
66
70 public function ilCloneDependencies(string $sid, int $copy_identifier, bool $is_initialized = false)
71 {
72 if (!$is_initialized) {
73 $this->initAuth($sid);
74 $this->initIlias();
75
76 if (!$this->checkSession($sid)) {
77 return $this->raiseError($this->getMessage(), $this->getMessageCode());
78 }
79 }
80
81 global $DIC;
82
83 $ilLog = $DIC['ilLog'];
84 $ilUser = $DIC['ilUser'];
85
86 $cp_options = ilCopyWizardOptions::_getInstance($copy_identifier);
87
88 // Check owner of copy procedure
89 if (!$cp_options->checkOwner($ilUser->getId())) {
90 ilLoggerFactory::getLogger('obj')->error('Permission check failed for user id: ' . $ilUser->getId() . ', copy id: ' . $copy_identifier);
91 return false;
92 }
93
94 // Fetch first node
95 if (($node = $cp_options->fetchFirstDependenciesNode()) === null) {
96 $cp_options->deleteAll();
97 ilLoggerFactory::getLogger('obj')->info('Finished copy step 2. Copy completed');
98 return true;
99 }
100
101 // Check options of this node
102 $options = $cp_options->getOptions((int) $node['child']);
103 $new_ref_id = 0;
104 switch ($options['type']) {
106 ilLoggerFactory::getLogger('obj')->debug(': Omitting node: ' . $node['obj_id'] . ', ' . $node['title'] . ', ' . $node['type']);
107 $this->callNextDependency($sid, $cp_options);
108 break;
109
111 ilLoggerFactory::getLogger('obj')->debug(': Start cloning dependencies for node: ' . $node['obj_id'] . ', ' . $node['title'] . ', ' . $node['type']);
112 $this->cloneDependencies($node, $cp_options);
113 $this->callNextDependency($sid, $cp_options);
114 break;
115
117 ilLoggerFactory::getLogger('obj')->debug(': Start cloning dependencies: ' . $node['obj_id'] . ', ' . $node['title'] . ', ' . $node['type']);
118 $this->cloneDependencies($node, $cp_options);
119 $this->callNextDependency($sid, $cp_options);
120 break;
121
122 default:
123 ilLoggerFactory::getLogger('obj')->warning('No valid action type given for node: ' . $node['obj_id'] . ', ' . $node['title'] . ', ' . $node['type']);
124 $this->callNextDependency($sid, $cp_options);
125 break;
126 }
127 return true;
128 }
129
133 public function ilClone(string $sid, int $copy_identifier)
134 {
135 $this->initAuth($sid);
136 $this->initIlias();
137
138 if (!$this->checkSession($sid)) {
139 ilLoggerFactory::getLogger('obj')->error('Object cloning failed. Invalid session given: ' . $this->getMessage());
140 }
141
142 global $DIC;
143
144 $ilUser = $DIC->user();
145
146 $cp_options = ilCopyWizardOptions::_getInstance($copy_identifier);
147
148 // Check owner of copy procedure
149 if (!$cp_options->checkOwner($ilUser->getId())) {
150 ilLoggerFactory::getLogger('obj')->error('Permission check failed for user id: ' . $ilUser->getId() . ', copy id: ' . $copy_identifier);
151 return false;
152 }
153
154 // Fetch first node
155 if (($node = $cp_options->fetchFirstNode()) === null) {
156 ilLoggerFactory::getLogger('obj')->info('Finished copy step 1. Starting copying of object dependencies...');
157 return $this->ilCloneDependencies($sid, $copy_identifier, true);
158 }
159 // Check options of this node
160 $options = $cp_options->getOptions((int) $node['child']);
161
162 $action = $this->rewriteActionForNode($cp_options, $node, $options);
163
164 $new_ref_id = 0;
165 switch ($action) {
167 ilLoggerFactory::getLogger('obj')->debug(': Omitting node: ' . $node['obj_id'] . ', ' . $node['title'] . ', ' . $node['type']);
168 // set mapping to zero
169 $cp_options->appendMapping($node['child'], 0);
170 $this->callNextNode($sid, $cp_options);
171 break;
172
174
175 ilLoggerFactory::getLogger('obj')->debug('Start cloning node: ' . $node['obj_id'] . ', ' . $node['title'] . ', ' . $node['type']);
176 $new_ref_id = $this->cloneNode($node, $cp_options);
177 $this->callNextNode($sid, $cp_options);
178 break;
179
181 ilLoggerFactory::getLogger('obj')->debug('Start linking node: ' . $node['obj_id'] . ', ' . $node['title'] . ', ' . $node['type']);
182 $new_ref_id = $this->linkNode($node, $cp_options);
183 $this->callNextNode($sid, $cp_options);
184 break;
185
186 case \ilCopyWizardOptions::COPY_WIZARD_LINK_TO_TARGET:
187 ilLoggerFactory::getLogger('obj')->debug('Start creating internal link for: ' . $node['obj_id'] . ', ' . $node['title'] . ', ' . $node['type']);
188 $new_ref_id = $this->internalLinkNode($node, $cp_options);
189 $this->callNextNode($sid, $cp_options);
190 break;
191
192 default:
193 ilLoggerFactory::getLogger('obj')->warning('No valid action type given for: ' . $node['obj_id'] . ', ' . $node['title'] . ', ' . $node['type']);
194 $this->callNextNode($sid, $cp_options);
195 break;
196 }
197 return $new_ref_id;
198 }
199
200 protected function rewriteActionForNode(ilCopyWizardOptions $cpo, array $node, array $options): int
201 {
203 if (array_key_exists('type', $options)) {
204 $default_mode = (int) $options['type'];
205 }
206 if (
207 array_key_exists('child', $node) &&
208 $cpo->isRootNode((int) $node['child'])
209 ) {
210 return $default_mode;
211 }
212
213 if ($this->findMappedReferenceForNode($cpo, $node) && $default_mode == \ilCopyWizardOptions::COPY_WIZARD_COPY) {
214 return \ilCopyWizardOptions::COPY_WIZARD_LINK_TO_TARGET;
215 }
216 return $default_mode;
217 }
218
219 protected function findMappedReferenceForNode(\ilCopyWizardOptions $cpo, array $node): ?int
220 {
221 global $DIC;
222
223 $logger = $DIC->logger()->obj();
224 $tree = $DIC->repositoryTree();
225 $root = $cpo->getRootNode();
226 $obj_id = (int) $node['obj_id'];
227
228 $mappings = $cpo->getMappings();
229 foreach (\ilObject::_getAllReferences($obj_id) as $ref_id => $also_ref_id) {
230 $logger->debug('Validating node: ' . $ref_id . ' and root ' . $root);
231 $logger->dump($DIC->repositoryTree()->getRelation($ref_id, $root));
232
233 if ($DIC->repositoryTree()->getRelation($ref_id, $root) !== \ilTree::RELATION_CHILD) {
234 $logger->debug('Ignoring non child relation');
235 continue;
236 }
237 // check if mapping is already available
238 $logger->dump($mappings);
239 if (array_key_exists($ref_id, $mappings)) {
240 $logger->debug('Found existing mapping for linked node.');
241 return $mappings[$ref_id];
242 }
243 }
244 $logger->info('Nothing found');
245 return null;
246 }
247
248 private function callNextNode(string $sid, ilCopyWizardOptions $cp_options): void
249 {
250 global $DIC;
251
252 $ilLog = $DIC->logger()->obj();
253
254 $cp_options->dropFirstNode();
255 if ($cp_options->isSOAPEnabled()) {
256 // Start next soap call
257 $soap_client = new ilSoapClient();
258 $soap_client->setResponseTimeout(1);
259 $soap_client->enableWSDL(true);
260 $soap_client->init();
261 $soap_client->call('ilClone', array($sid, $cp_options->getCopyId()));
262 } else {
263 ilLoggerFactory::getLogger('obj')->warning('SOAP clone call failed. Calling clone method manually');
264 $cp_options->read();
265 $res = ilSoapFunctions::ilClone($sid, $cp_options->getCopyId());
266 }
267 }
268
269 private function callNextDependency(string $sid, ilCopyWizardOptions $cp_options): void
270 {
271 $cp_options->dropFirstDependenciesNode();
272
273 if ($cp_options->isSOAPEnabled()) {
274 // Start next soap call
275 $soap_client = new ilSoapClient();
276 $soap_client->setResponseTimeout(1);
277 $soap_client->enableWSDL(true);
278 $soap_client->init();
279 $soap_client->call('ilCloneDependencies', array($sid, $cp_options->getCopyId()));
280 } else {
281 ilLoggerFactory::getLogger('obj')->warning('SOAP clone call failed. Calling clone method manually');
282 $cp_options->read();
284 }
285 }
286
287 private function cloneNode(array $node, ilCopyWizardOptions $cp_options): int
288 {
289 global $DIC;
290
291 $ilLog = $DIC['ilLog'];
292 $tree = $DIC['tree'];
293 $ilAccess = $DIC['ilAccess'];
294 $rbacreview = $DIC['rbacreview'];
295 $source_id = (int) $node['child'];
296 $parent_id = (int) $node['parent'];
297 $options = $cp_options->getOptions((int) $node['child']);
298 $mappings = $cp_options->getMappings();
299
300 if (!$ilAccess->checkAccess('copy', '', (int) $node['child'])) {
301 ilLoggerFactory::getLogger('obj')->error('No copy permission granted: ' . $source_id . ', ' . $node['title'] . ', ' . $node['type']);
302 return 0;
303 }
304 if (!isset($mappings[$parent_id])) {
305 ilLoggerFactory::getLogger('obj')->info('Omitting node ' . $source_id . ', ' . $node['title'] . ', ' . $node['type'] . '. No target found.');
306 return 0;
307 }
308 $target_id = $mappings[$parent_id];
309
310 if (!$tree->isInTree($target_id)) {
311 ilLoggerFactory::getLogger('obj')->notice('Omitting node ' . $source_id . ', ' . $node['title'] . ', ' . $node['type'] . '. Object has been deleted.');
312 return 0;
313 }
314
315 $orig = ilObjectFactory::getInstanceByRefId($source_id);
316 $new_obj = $orig->cloneObject((int) $target_id, $cp_options->getCopyId());
317
318 if (!is_object($new_obj)) {
319 ilLoggerFactory::getLogger('obj')->error('Error copying ' . $source_id . ', ' . $node['title'] . ', ' . $node['type'] . '. No target found.');
320 return 0;
321 }
322
323 // rbac log
324 $rbac_log_roles = $rbacreview->getParentRoleIds($new_obj->getRefId(), false);
325 $rbac_log = ilRbacLog::gatherFaPa($new_obj->getRefId(), array_keys($rbac_log_roles), true);
326 ilRbacLog::add(ilRbacLog::COPY_OBJECT, $new_obj->getRefId(), $rbac_log, true);
327
328 // Finally add new mapping entry
329 $cp_options->appendMapping($source_id, $new_obj->getRefId());
330 return $new_obj->getRefId();
331 }
332
333 private function cloneDependencies(array $node, ilCopyWizardOptions $cp_options): void
334 {
335 global $DIC;
336
337 $ilLog = $DIC['ilLog'];
338
339 $source_id = (int) $node['child'];
340 $mappings = $cp_options->getMappings();
341
342 if (!isset($mappings[$source_id])) {
343 ilLoggerFactory::getLogger('obj')->debug('Omitting node ' . $source_id . ', ' . $node['title'] . ', ' . $node['type'] . '. No mapping found.');
344 return;
345 }
346 $target_id = $mappings[$source_id];
347
348 $orig = ilObjectFactory::getInstanceByRefId($source_id);
349 $orig->cloneDependencies($target_id, $cp_options->getCopyId());
350 }
351
352 private function internalLinkNode(array $node, ilCopyWizardOptions $cp_options): int
353 {
354 global $DIC;
355
356 $ilAccess = $DIC->access();
357 $logger = $DIC->logger()->obj();
358 $rbacreview = $DIC->rbac()->review();
359 $tree = $DIC->repositoryTree();
360 $mappings = $cp_options->getMappings();
361
362 $source_id = $this->findMappedReferenceForNode($cp_options, $node);
363 try {
364 $orig = ilObjectFactory::getInstanceByRefId((int) $source_id);
365 if (!$orig instanceof \ilObject) {
366 $logger->error('Cannot create object instance.');
367 return 0;
368 }
369 } catch (\ilObjectNotFoundException $e) {
370 $logger->error('Cannot create object instance for ref_id: ' . $source_id);
371 $logger->error($e->getMessage());
372 return 0;
373 }
374
375 // target (parent id) is the mapped parent id of the current node
376 $node_parent = $node['parent'];
377 if (!array_key_exists($node_parent, $mappings)) {
378 $logger->error('Cannot new parent id for node: ' . $node['parent']);
379 return 0;
380 }
381 $parent_id = $mappings[$node_parent];
382
383 $new_ref_id = $orig->createReference();
384 $orig->putInTree($parent_id);
385 $orig->setPermissions($parent_id);
386
387 if (!($new_ref_id)) {
388 $logger->warning('Creating internal link failed.');
389 return 0;
390 }
391
392 // rbac log
393 $rbac_log_roles = $rbacreview->getParentRoleIds($new_ref_id, false);
394 $rbac_log = ilRbacLog::gatherFaPa($new_ref_id, array_keys($rbac_log_roles), true);
395 ilRbacLog::add(ilRbacLog::LINK_OBJECT, $new_ref_id, $rbac_log, true);
396
397 // Finally add new mapping entry
398 $cp_options->appendMapping($node['child'], $new_ref_id);
399
400 $logger->notice('Added mapping for ' . $node['child'] . ' ' . $new_ref_id);
401 return $new_ref_id;
402 }
403
404 private function linkNode(array $node, ilCopyWizardOptions $cp_options): int
405 {
406 global $DIC;
407
408 $ilLog = $DIC['ilLog'];
409 $ilAccess = $DIC['ilAccess'];
410 $rbacreview = $DIC['rbacreview'];
411
412 $source_id = (int) $node['child'];
413 $parent_id = (int) $node['parent'];
414 $options = $cp_options->getOptions((int) $node['child']);
415 $mappings = $cp_options->getMappings();
416
417 if (!$ilAccess->checkAccess('delete', '', (int) $node['child'])) {
418 ilLoggerFactory::getLogger('obj')->warning('No delete permission granted: ' . $source_id . ', ' . $node['title'] . ', ' . $node['type']);
419 return 0;
420 }
421 if (!isset($mappings[$parent_id])) {
422 ilLoggerFactory::getLogger('obj')->warning('Omitting node ' . $source_id . ', ' . $node['title'] . ', ' . $node['type'] . '. No target found.');
423 return 0;
424 }
425 $target_id = $mappings[$parent_id];
426
427 $orig = ilObjectFactory::getInstanceByRefId($source_id);
428 $new_ref_id = $orig->createReference();
429 $orig->putInTree($target_id);
430 $orig->setPermissions($target_id);
431
432 if (!($new_ref_id)) {
433 ilLoggerFactory::getLogger('obj')->error('Error linking ' . $source_id . ', ' . $node['title'] . ', ' . $node['type'] . '. No target found.');
434 return 0;
435 }
436
437 // rbac log
438 $rbac_log_roles = $rbacreview->getParentRoleIds($new_ref_id, false);
439 $rbac_log = ilRbacLog::gatherFaPa($new_ref_id, array_keys($rbac_log_roles), true);
440 ilRbacLog::add(ilRbacLog::LINK_OBJECT, $new_ref_id, $rbac_log, true);
441
442 // Finally add new mapping entry
443 $cp_options->appendMapping($source_id, $new_ref_id);
444 return $new_ref_id;
445 }
446
451 public function deleteExpiredDualOptInUserObjects(string $sid, int $usr_id): bool
452 {
453 $this->initAuth($sid);
454 $this->initIlias();
455
456 // Session check not possible -> anonymous user is the trigger
457
458 global $DIC;
459
460 $db = $DIC->database();
461 $logger = $DIC->logger()->user();
462
463 $logger->debug(
464 'Started deletion of inactive user objects with expired confirmation hash values (dual opt in) ...'
465 );
466 $lifetime = (new ilRegistrationSettings())->getRegistrationHashLifetime();
467
468 if ($lifetime <= 0) {
469 $logger->debug('Registration hash lifetime is <= 0, kipping deletion.');
470 return true;
471 }
472
473 $utc_clock = (new \ILIAS\Data\Factory())->clock()->utc();
474 $now = $utc_clock->now();
475 $cutoff = $now->sub(new DateInterval('PT' . $lifetime . 'S'));
476 $formatted_cutoff = $cutoff->format(ilObjUser::DATABASE_DATE_FORMAT);
477
478 // Fetch only candidates that must be deleted, prioritize the triggering user
479 $query = '
480 SELECT usr_id, create_date
481 FROM usr_data
482 WHERE active = 0
483 AND reg_hash IS NOT NULL
484 AND reg_hash != \'\'
485 AND ' . $db->in('usr_id', [ANONYMOUS_USER_ID, SYSTEM_USER_ID], true, ilDBConstants::T_INTEGER) . '
486 AND create_date < %s
487 ORDER BY (CASE WHEN usr_id = %s THEN 0 ELSE 1 END), create_date';
488
489 $res = $db->queryF(
490 $query,
492 [$formatted_cutoff, $usr_id]
493 );
494
495 $logger->info(sprintf(
496 '%d inactive user objects eligible for deletion found (cutoff: %s, lifetime: %d s).',
497 $db->numRows($res),
498 $cutoff->format(DateTimeInterface::ATOM),
499 $lifetime
500 ));
501
502 $num_deleted_users = 0;
503 while ($row = $db->fetchAssoc($res)) {
504 $uid = (int) $row['usr_id'];
505
506 $user = ilObjectFactory::getInstanceByObjId($uid, false);
507 if (!($user instanceof ilObjUser)) {
508 continue;
509 }
510
511 $created = DateTimeImmutable::createFromFormat(
513 (string) $row['create_date'],
514 new DateTimeZone('UTC')
515 );
516
517 $logger->info(sprintf(
518 'Deleting user (login: %s | id: %d) – expired dual opt-in (created: %s, cutoff: %s, lifetime: %d s)',
519 $user->getLogin(),
520 $uid,
521 $created ? $created->format(DateTimeInterface::ATOM) : '-',
522 $cutoff->format(DateTimeInterface::ATOM),
523 $lifetime
524 ));
525
526 $user->delete();
527 ++$num_deleted_users;
528 }
529
530 $logger->info(sprintf(
531 '%d inactive user objects with expired confirmation hash values (dual opt-in) deleted.',
532 $num_deleted_users
533 ));
534
535 return true;
536 }
537}
isRootNode(int $a_root)
Is root node @access public.
dropFirstNode()
Drop first node (for cloneObject())
appendMapping($a_source_id, $a_target_id)
Add mapping of source -> target.
dropFirstDependenciesNode()
Drop first node (for cloneDependencies())
static _getInstance(int $a_copy_id)
isSOAPEnabled()
Check if SOAP calls are disabled.
getOptions(int $a_source_id)
Get entry by source @access public.
static getLogger(string $a_component_id)
Get component logger.
static _getMobsOfObject(string $a_type, int $a_id, int $a_usage_hist_nr=0, string $a_lang="-")
static _saveTempFileAsMediaObject(string $name, string $tmp_name, bool $upload=true)
User class.
const DATABASE_DATE_FORMAT
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
Class ilObject Basic functions for all objects.
static _getAllReferences(int $id)
get all reference ids for object ID
const COPY_OBJECT
static add(int $action, int $ref_id, array $diff, bool $source_ref_id=false)
static gatherFaPa(int $ref_id, array $role_ids, bool $add_action=false)
const LINK_OBJECT
Class ilObjAuthSettingsGUI.
raiseError(string $a_message, $a_code)
static ilCloneDependencies(string $sid, int $copy_identifier)
static ilClone(string $sid, int $copy_identifier)
Soap utitliy functions.
cloneDependencies(array $node, ilCopyWizardOptions $cp_options)
deleteExpiredDualOptInUserObjects(string $sid, int $usr_id)
Method for soap webservice: deleteExpiredDualOptInUserObjects This service will run in background.
callNextDependency(string $sid, ilCopyWizardOptions $cp_options)
internalLinkNode(array $node, ilCopyWizardOptions $cp_options)
getMobsOfObject(string $sid, string $a_type, int $a_id)
rewriteActionForNode(ilCopyWizardOptions $cpo, array $node, array $options)
saveTempFileAsMediaObject(string $sid, string $name, string $tmp_name)
findMappedReferenceForNode(\ilCopyWizardOptions $cpo, array $node)
ilClone(string $sid, int $copy_identifier)
linkNode(array $node, ilCopyWizardOptions $cp_options)
ilCloneDependencies(string $sid, int $copy_identifier, bool $is_initialized=false)
cloneNode(array $node, ilCopyWizardOptions $cp_options)
callNextNode(string $sid, ilCopyWizardOptions $cp_options)
const RELATION_CHILD
const SYSTEM_USER_ID
This file contains constants for PHPStan analyis, see: https://phpstan.org/config-reference#constants...
Definition: constants.php:26
const ANONYMOUS_USER_ID
Definition: constants.php:27
$ref_id
Definition: ltiauth.php:66
$res
Definition: ltiservices.php:69
global $DIC
Definition: shib_login.php:26