ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilSoapLearningProgressAdministration.php
Go to the documentation of this file.
1<?php
2
25{
27 protected static array $DELETE_PROGRESS_FILTER_TYPES = ['sahs', 'tst'];
28
29 public const PROGRESS_FILTER_ALL = 0;
31 public const PROGRESS_FILTER_COMPLETED = 2;
32 public const PROGRESS_FILTER_FAILED = 3;
34
39 public const SOAP_LP_ERROR_NO_PERMISSION = 58;
41
43 protected static array $PROGRESS_INFO_TYPES = [
49 ];
50
51 public const USER_FILTER_ALL = -1;
52
56 public function deleteProgress(string $sid, array $ref_ids, array $usr_ids, array $type_filter, array $progress_filter)
57 {
58 $this->initAuth($sid);
59 $this->initIlias();
60
61 if (!is_array($usr_ids)) {
62 $usr_ids = (array) $usr_ids;
63 }
64 if (!is_array($type_filter)) {
65 $type_filter = (array) $type_filter;
66 }
67
68 if (!$this->checkSession($sid)) {
69 return $this->raiseError($this->getMessage(), $this->getMessageCode());
70 }
71
72 if (array_diff($type_filter, self::$DELETE_PROGRESS_FILTER_TYPES)) {
73 return $this->raiseError('Invalid filter type given', 'Client');
74 }
75
76 if (!in_array(self::USER_FILTER_ALL, $usr_ids) && !ilObjUser::userExists($usr_ids)) {
77 return $this->raiseError('Invalid user ids given', 'Client');
78 }
79
80 $valid_refs = array();
81 $type = '';
82 foreach ($ref_ids as $ref_id) {
84 $type = ilObject::_lookupType($obj_id);
85
86 // All containers
87 if ($GLOBALS['DIC']['objDefinition']->isContainer($type)) {
88 $all_sub_objs = array();
89 foreach (($type_filter) as $type_filter_item) {
90 $sub_objs = $GLOBALS['DIC']['tree']->getSubTree(
91 $GLOBALS['DIC']['tree']->getNodeData($ref_id),
92 false,
93 $type_filter_item
94 );
95 $all_sub_objs = array_merge($all_sub_objs, $sub_objs);
96 }
97
98 foreach ($all_sub_objs as $child_ref) {
99 $child_type = ilObject::_lookupType(ilObject::_lookupObjId($child_ref));
100 if (!$GLOBALS['DIC']['ilAccess']->checkAccess('write', '', $child_ref)) {
101 return $this->raiseError(
102 'Permission denied for : ' . $ref_id . ' -> type ' . $type,
103 'Client'
104 );
105 }
106 $valid_refs[] = $child_ref;
107 }
108 } elseif (in_array($type, $type_filter)) {
109 if (!$GLOBALS['DIC']['ilAccess']->checkAccess('write', '', $ref_id)) {
110 return $this->raiseError('Permission denied for : ' . $ref_id . ' -> type ' . $type, 'Client');
111 }
112 $valid_refs[] = $ref_id;
113 } else {
114 return $this->raiseError(
115 'Invalid object type given for : ' . $ref_id . ' -> type ' . $type,
116 'Client'
117 );
118 }
119 }
120
121 // Delete tracking data
122 foreach ($valid_refs as $ref_id) {
124
125 if (!$obj instanceof ilObject) {
126 return $this->raiseError('Invalid reference id given : ' . $ref_id . ' -> type ' . $type, 'Client');
127 }
128
129 // filter users
130 $valid_users = $this->applyProgressFilter($obj->getId(), $usr_ids, $progress_filter);
131
132 switch ($obj->getType()) {
133 case 'sahs':
134 $subtype = ilObjSAHSLearningModule::_lookupSubType($obj->getId());
135
136 switch ($subtype) {
137 case 'scorm':
138 $this->deleteScormTracking($obj->getId(), $valid_users);
139 break;
140
141 case 'scorm2004':
142 $this->deleteScorm2004Tracking($obj->getId(), $valid_users);
143 break;
144 }
145 break;
146
147 case 'tst':
148
150 $obj->removeTestResultsFromSoapLpAdministration(array_values($valid_users));
151 break;
152 }
153
154 // Refresh status
156 ilLPStatusWrapper::_refreshStatus($obj->getId(), $valid_users);
157 }
158 return true;
159 }
160
165 public function getProgressInfo(string $sid, int $a_ref_id, array $a_progress_filter)
166 {
167 global $DIC;
168
169 $this->initAuth($sid);
170 $this->initIlias();
171
172 $ilAccess = $DIC->access();
173
174 // Check session
175 if (!$this->checkSession($sid)) {
176 return $this->raiseError(
177 'Error ' . self::SOAP_LP_ERROR_AUTHENTICATION . ':' . $this->getMessage(),
178 self::SOAP_LP_ERROR_AUTHENTICATION
179 );
180 }
181
182 // Check filter
183 if (array_diff($a_progress_filter, self::$PROGRESS_INFO_TYPES)) {
184 return $this->raiseError(
185 'Error ' . self::SOAP_LP_ERROR_INVALID_FILTER . ': Invalid filter type given',
186 self::SOAP_LP_ERROR_INVALID_FILTER
187 );
188 }
189 // Check LP enabled
191 return $this->raiseError(
192 'Error ' . self::SOAP_LP_ERROR_LP_NOT_ENABLED . ': Learning progress not enabled in ILIAS',
193 self::SOAP_LP_ERROR_LP_NOT_ENABLED
194 );
195 }
196
197 $obj = ilObjectFactory::getInstanceByRefId($a_ref_id, false);
198 if (!$obj instanceof ilObject) {
199 return $this->raiseError(
200 'Error ' . self::SOAP_LP_ERROR_INVALID_REF_ID . ': Invalid reference id ' . $a_ref_id . ' given',
201 self::SOAP_LP_ERROR_INVALID_REF_ID
202 );
203 }
204
205 // check lp available
206 $mode = ilLPObjSettings::_lookupDBMode($obj->getId());
208 return $this->raiseError(
209 'Error ' . self::SOAP_LP_ERROR_LP_NOT_AVAILABLE . ': Learning progress not available for objects of type ' .
210 $obj->getType(),
211 self::SOAP_LP_ERROR_LP_NOT_AVAILABLE
212 );
213 }
214
215 // check rbac
219 if (!$ilAccess->checkRbacOrPositionPermissionAccess(
220 'read_learning_progress',
221 'read_learning_progress',
222 $a_ref_id
223 )) {
224 return $this->raiseError(
225 'Error ' . self::SOAP_LP_ERROR_NO_PERMISSION . ': No Permission to access learning progress in this object',
226 self::SOAP_LP_ERROR_NO_PERMISSION
227 );
228 }
229
230 $writer = new ilXmlWriter();
231 $writer->xmlStartTag(
232 'LearningProgressInfo',
233 array(
234 'ref_id' => $obj->getRefId(),
235 'type' => $obj->getType()
236 )
237 );
238
239 $writer->xmlStartTag('LearningProgressSummary');
240
241 if (in_array(self::PROGRESS_FILTER_ALL, $a_progress_filter) || in_array(
242 self::PROGRESS_FILTER_COMPLETED,
243 $a_progress_filter
244 )) {
245 $completed = ilLPStatusWrapper::_getCompleted($obj->getId());
246 $completed = $GLOBALS['DIC']->access()->filterUserIdsByRbacOrPositionOfCurrentUser(
247 'read_learning_progress',
249 $a_ref_id,
250 $completed
251 );
252 $completed = count($completed);
253
254 $writer->xmlElement(
255 'Status',
256 array(
257 'type' => self::PROGRESS_FILTER_COMPLETED,
258 'num' => $completed
259 )
260 );
261 }
262 if (in_array(self::PROGRESS_FILTER_ALL, $a_progress_filter) || in_array(
263 self::PROGRESS_FILTER_IN_PROGRESS,
264 $a_progress_filter
265 )) {
266 $completed = ilLPStatusWrapper::_getInProgress($obj->getId());
267 $completed = $GLOBALS['DIC']->access()->filterUserIdsByRbacOrPositionOfCurrentUser(
268 'read_learning_progress',
270 $a_ref_id,
271 $completed
272 );
273 $completed = count($completed);
274
275 $writer->xmlElement(
276 'Status',
277 array(
278 'type' => self::PROGRESS_FILTER_IN_PROGRESS,
279 'num' => $completed
280 )
281 );
282 }
283 if (in_array(self::PROGRESS_FILTER_ALL, $a_progress_filter) || in_array(
284 self::PROGRESS_FILTER_FAILED,
285 $a_progress_filter
286 )) {
287 $completed = ilLPStatusWrapper::_getFailed($obj->getId());
288 $completed = $GLOBALS['DIC']->access()->filterUserIdsByRbacOrPositionOfCurrentUser(
289 'read_learning_progress',
291 $a_ref_id,
292 $completed
293 );
294 $completed = count($completed);
295
296 $writer->xmlElement(
297 'Status',
298 array(
299 'type' => self::PROGRESS_FILTER_FAILED,
300 'num' => $completed
301 )
302 );
303 }
304 if (in_array(self::PROGRESS_FILTER_ALL, $a_progress_filter) || in_array(
305 self::PROGRESS_FILTER_NOT_ATTEMPTED,
306 $a_progress_filter
307 )) {
308 $completed = ilLPStatusWrapper::_getNotAttempted($obj->getId());
309 $completed = $GLOBALS['DIC']->access()->filterUserIdsByRbacOrPositionOfCurrentUser(
310 'read_learning_progress',
312 $a_ref_id,
313 $completed
314 );
315 $completed = count($completed);
316
317 $writer->xmlElement(
318 'Status',
319 array(
320 'type' => self::PROGRESS_FILTER_NOT_ATTEMPTED,
321 'num' => $completed
322 )
323 );
324 }
325 $writer->xmlEndTag('LearningProgressSummary');
326 $writer->xmlStartTag('UserProgress');
327 if (in_array(self::PROGRESS_FILTER_ALL, $a_progress_filter) || in_array(
328 self::PROGRESS_FILTER_COMPLETED,
329 $a_progress_filter
330 )) {
331 $completed = ilLPStatusWrapper::_getCompleted($obj->getId());
332 $completed = $GLOBALS['DIC']->access()->filterUserIdsByRbacOrPositionOfCurrentUser(
333 'read_learning_progress',
335 $a_ref_id,
336 $completed
337 );
338
339 $this->addUserProgress($writer, $completed, self::PROGRESS_FILTER_COMPLETED);
340 }
341 if (in_array(self::PROGRESS_FILTER_ALL, $a_progress_filter) || in_array(
342 self::PROGRESS_FILTER_IN_PROGRESS,
343 $a_progress_filter
344 )) {
345 $completed = ilLPStatusWrapper::_getInProgress($obj->getId());
346 $completed = $GLOBALS['DIC']->access()->filterUserIdsByRbacOrPositionOfCurrentUser(
347 'read_learning_progress',
349 $a_ref_id,
350 $completed
351 );
352 $this->addUserProgress($writer, $completed, self::PROGRESS_FILTER_IN_PROGRESS);
353 }
354 if (in_array(self::PROGRESS_FILTER_ALL, $a_progress_filter) || in_array(
355 self::PROGRESS_FILTER_FAILED,
356 $a_progress_filter
357 )) {
358 $completed = ilLPStatusWrapper::_getFailed($obj->getId());
359 $completed = $GLOBALS['DIC']->access()->filterUserIdsByRbacOrPositionOfCurrentUser(
360 'read_learning_progress',
362 $a_ref_id,
363 $completed
364 );
365 $this->addUserProgress($writer, $completed, self::PROGRESS_FILTER_FAILED);
366 }
367 if (in_array(self::PROGRESS_FILTER_ALL, $a_progress_filter) || in_array(
368 self::PROGRESS_FILTER_NOT_ATTEMPTED,
369 $a_progress_filter
370 )) {
371 $completed = ilLPStatusWrapper::_getNotAttempted($obj->getId());
372 $completed = $GLOBALS['DIC']->access()->filterUserIdsByRbacOrPositionOfCurrentUser(
373 'read_learning_progress',
375 $a_ref_id,
376 $completed
377 );
378
379 $this->addUserProgress($writer, $completed, self::PROGRESS_FILTER_NOT_ATTEMPTED);
380 }
381 $writer->xmlEndTag('UserProgress');
382 $writer->xmlEndTag('LearningProgressInfo');
383
384 return $writer->xmlDumpMem();
385 }
386
387 protected function addUserProgress(ilXmlWriter $writer, array $users, int $a_type): void
388 {
389 foreach ($users as $user_id) {
390 $writer->xmlStartTag(
391 'User',
392 array(
393 'id' => $user_id,
394 'status' => $a_type
395 )
396 );
397
399 $writer->xmlElement('Login', array(), (string) $info['login']);
400 $writer->xmlElement('Firstname', array(), (string) $info['firstname']);
401 $writer->xmlElement('Lastname', array(), (string) $info['lastname']);
402 $writer->xmlEndTag('User');
403 }
404 }
405
413 protected function applyProgressFilter(int $obj_id, array $usr_ids, array $filter): array
414 {
415 $all_users = array();
416 if (in_array(self::USER_FILTER_ALL, $usr_ids)) {
417 $all_users = array_unique(
418 array_merge(
422 )
423 );
424 } else {
425 $all_users = $usr_ids;
426 }
427
428 if (!$filter || in_array(self::PROGRESS_FILTER_ALL, $filter)) {
429 $GLOBALS['DIC']['log']->write(__METHOD__ . ': Deleting all progress data');
430 return $all_users;
431 }
432
433 $filter_users = array();
434 if (in_array(self::PROGRESS_FILTER_IN_PROGRESS, $filter)) {
435 $GLOBALS['DIC']['log']->write(__METHOD__ . ': Filtering in progress.');
436 $filter_users = array_merge($filter, ilLPStatusWrapper::_getInProgress($obj_id));
437 }
438 if (in_array(self::PROGRESS_FILTER_COMPLETED, $filter)) {
439 $GLOBALS['DIC']['log']->write(__METHOD__ . ': Filtering completed.');
440 $filter_users = array_merge($filter, ilLPStatusWrapper::_getCompleted($obj_id));
441 }
442 if (in_array(self::PROGRESS_FILTER_FAILED, $filter)) {
443 $GLOBALS['DIC']['log']->write(__METHOD__ . ': Filtering failed.');
444 $filter_users = array_merge($filter, ilLPStatusWrapper::_getFailed($obj_id));
445 }
446
447 // Build intersection
448 return array_intersect($all_users, $filter_users);
449 }
450
454 protected function deleteScormTracking(int $a_obj_id, array $a_usr_ids): bool
455 {
456 global $DIC;
457
458 $ilDB = $DIC['ilDB'];
459
460 $query = 'DELETE FROM scorm_tracking ' .
461 'WHERE ' . $ilDB->in('user_id', $a_usr_ids, false, 'integer') . ' ' .
462 'AND obj_id = ' . $ilDB->quote($a_obj_id, 'integer') . ' ';
463 $res = $ilDB->manipulate($query);
464 return true;
465 }
466
470 protected function deleteScorm2004Tracking(int $a_obj_id, array $a_usr_ids): void
471 {
472 global $DIC;
473
474 $ilDB = $DIC['ilDB'];
475
476 $query = 'SELECT cp_node_id FROM cp_node ' .
477 'WHERE nodename = ' . $ilDB->quote('item', 'text') . ' ' .
478 'AND cp_node.slm_id = ' . $ilDB->quote($a_obj_id, 'integer');
479 $res = $ilDB->query($query);
480
481 $scos = array();
482 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
483 $scos[] = $row->cp_node_id;
484 }
485
486 $query = 'DELETE FROM cmi_node ' .
487 'WHERE ' . $ilDB->in('user_id', $a_usr_ids, false, 'integer') . ' ' .
488 'AND ' . $ilDB->in('cp_node_id', $scos, false, 'integer');
489 $ilDB->manipulate($query);
490 }
491
496 public function getLearningProgressChanges(string $sid, string $timestamp, bool $include_ref_ids, array $type_filter)
497 {
498 $this->initAuth($sid);
499 $this->initIlias();
500
501 if (!$this->checkSession($sid)) {
502 return $this->raiseError($this->getMessage(), $this->getMessageCode());
503 }
504 global $DIC;
505
506 $rbacsystem = $DIC['rbacsystem'];
507 $tree = $DIC['tree'];
508 $ilLog = $DIC['ilLog'];
509
510 // check administrator
511 $types = "";
512 if (is_array($type_filter)) {
513 $types = implode(",", $type_filter);
514 }
515
516 // output lp changes as xml
517 try {
518 $writer = new ilLPXmlWriter(true);
519 $writer->setTimestamp($timestamp);
520 $writer->setIncludeRefIds($include_ref_ids);
521 $writer->setTypeFilter($type_filter);
522 $writer->write();
523
524 return $writer->xmlDumpMem(true);
525 } catch (UnexpectedValueException $e) {
526 return $this->raiseError($e->getMessage(), 'Client');
527 }
528 }
529}
foreach($mandatory_scripts as $file) $timestamp
Definition: buildRTE.php:70
static _lookupDBMode(int $a_obj_id)
static _refreshStatus(int $a_obj_id, ?array $a_users=null)
static _getInProgress(int $a_obj_id)
Static function to read users who have the status 'in_progress'.
static _getFailed(int $a_obj_id)
Static function to read the users who have the status 'completed'.
static _resetInfoCaches($a_obj_id)
static _getNotAttempted(int $a_obj_id)
Static function to read the number of user who have the status 'not_attempted'.
static _getCompleted(int $a_obj_id)
Static function to read the users who have the status 'completed'.
XML writer learning progress.
static _lookupSubType(int $a_obj_id)
lookup subtype id (scorm, )
static userExists(array $a_usr_ids=[])
static _lookupName(int $a_user_id)
static getInstanceByRefId(int $ref_id, bool $stop_on_error=true)
get an instance of an Ilias object by reference id
Class ilObject Basic functions for all objects.
static _lookupType(int $id, bool $reference=false)
static _lookupObjId(int $ref_id)
raiseError(string $a_message, $a_code)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
addUserProgress(ilXmlWriter $writer, array $users, int $a_type)
applyProgressFilter(int $obj_id, array $usr_ids, array $filter)
Apply progress filter.
getLearningProgressChanges(string $sid, string $timestamp, bool $include_ref_ids, array $type_filter)
deleteScorm2004Tracking(int $a_obj_id, array $a_usr_ids)
Delete scorm 2004 tracking.
deleteScormTracking(int $a_obj_id, array $a_usr_ids)
Delete SCORM Tracking.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
xmlElement(string $tag, $attrs=null, $data=null, $encode=true, $escape=true)
Writes a basic element (no children, just textual content)
xmlEndTag(string $tag)
Writes an endtag.
xmlStartTag(string $tag, ?array $attrs=null, bool $empty=false, bool $encode=true, bool $escape=true)
Writes a starttag.
$info
Definition: entry_point.php:21
$ref_id
Definition: ltiauth.php:66
$res
Definition: ltiservices.php:69
global $DIC
Definition: shib_login.php:26
$GLOBALS["DIC"]
Definition: wac.php:54