ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
class.ilECSCmsCourseMemberCommandQueueHandler.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
26 {
27  protected ilLogger $log;
28 
30  private int $mid = 0;
31 
32  private ?ilECSnodeMappingSettings $mapping = null;
33 
37  public function __construct(ilECSSetting $server)
38  {
39  global $DIC;
40  $this->log = $DIC->logger()->wsrv();
41  $this->server = $server;
42  }
43 
47  public function getServer(): \ilECSSetting
48  {
49  return $this->server;
50  }
51 
55  public function getMid(): int
56  {
57  return $this->mid;
58  }
59 
63  public function checkAllocationActivation(ilECSSetting $server, $a_content_id): bool
64  {
65  try {
66  $crsm_reader = new ilECSCourseMemberConnector($server);
67  $details = $crsm_reader->getCourseMember($a_content_id, true);
68  $this->mid = $details->getMySender();
69 
70  // Check if import is enabled
71  $part = ilECSParticipantSetting::getInstance($this->getServer()->getServerId(), $this->getMid());
72  if (!$part->isImportEnabled()) {
73  $this->log->warning('Import disabled for mid ' . $this->getMid());
74  return false;
75  }
76  // Check course allocation setting
78  $this->getServer()->getServerId(),
79  $this->getMid()
80  );
81  return $this->mapping->isCourseAllocationEnabled();
82  } catch (ilECSConnectorException $e) {
83  $this->log->error('Reading course member details failed with message ' . $e->getMessage());
84  return false;
85  }
86  }
87 
88 
92  public function handleCreate(ilECSSetting $server, $a_content_id): bool
93  {
94  if (!$this->checkAllocationActivation($server, $a_content_id)) {
95  return true;
96  }
97  try {
98  //$course = $this->readCourse($server, $a_content_id);
99  $course_member = $this->readCourseMember($server, $a_content_id);
100  $this->doUpdate($a_content_id, $course_member);
101  return true;
102  } catch (ilECSConnectorException $e) {
103  $this->log->error('Course member creation failed with mesage ' . $e->getMessage());
104  return false;
105  }
106  return true;
107  }
108 
112  public function handleDelete(ilECSSetting $server, $a_content_id): bool
113  {
114  // nothing todo
115  return true;
116  }
117 
121  public function handleUpdate(ilECSSetting $server, $a_content_id): bool
122  {
123  if (!$this->checkAllocationActivation($server, $a_content_id)) {
124  return true;
125  }
126 
127  try {
128  $course_member = $this->readCourseMember($server, $a_content_id);
129  $this->doUpdate($a_content_id, $course_member);
130  return true;
131  } catch (ilECSConnectorException $e) {
132  $this->log->error('Course member update failed with mesage ' . $e->getMessage());
133  return false;
134  }
135  return true;
136  }
137 
138 
142  protected function doUpdate($a_content_id, $course_member): bool
143  {
144  $this->log->debug('Starting ecs member update');
145 
146  if (is_array($course_member) && !isset($course_member["lectureID"])) {
147  $this->log->warning('Missing course id in course_member');
148  return false;
149  }
150 
151  $course_id = (int) $course_member->lectureID;
152  if (!$course_id) {
153  $this->log->warning('Missing course id');
154  return false;
155  }
156  $this->log->debug('sid: ' . $this->getServer()->getServerId() . ' course_id: ' . $course_id . ' mid: ' . $this->mid);
157  //$crs_obj_id = ilECSImportManager::getInstance()->_lookupObjId($this->getServer()->getServerId(), $course_id, $this->mid);
158  $crs_obj_id = ilECSImportManager::getInstance()->lookupObjIdByContentId($this->getServer()->getServerId(), $this->mid, $course_id);
159 
160  if (!$crs_obj_id) {
161  $this->log->info('No main course created. Group scenario >= 3 ?');
162  }
163 
164  $course = $this->readCourse($course_member);
165  if (is_null($course)) {
166  $this->log->info('No course found, skip processing' . print_r($course_member, true));
167  return true;
168  }
169  // Lookup already imported users and update their status
170  $assignments = $this->readAssignments($course, $course_member);
171 
172  $this->log->debug('Parallel group assignments');
173  $this->log->dump($assignments, ilLogLevel::DEBUG);
174  $this->log->debug('------------------ End assignemtns');
175 
176  // iterate through all parallel groups
177  foreach ($assignments as $cms_id => $assigned) {
178  $sub_id = ($cms_id === $course_id) ? null : (string) $cms_id;
179 
180  $this->log->debug('sub id is ' . is_null($sub_id) ? "<null>" : $sub_id . ' for ' . $cms_id);
181 
182  $obj_id = ilECSImportManager::getInstance()->lookupObjIdByContentId(
183  $this->getServer()->getServerId(),
184  $this->getMid(),
185  $course_id,
186  $sub_id
187  );
188 
189  $this->refreshAssignmentStatus($course_member, $obj_id, $sub_id, $assigned);
190  }
191  return true;
192  }
193 
197  protected function readAssignments($course, $course_member): array
198  {
199  //TODO check if this switch is still needed
200  if (!property_exists($course, 'groupScenario')) {
201  $course->groupScenario = ilECSMappingUtils::PARALLEL_ONE_COURSE;
202  }
203 
204  switch ((int) $course->groupScenario) {
206  $this->log->debug('Parallel group scenario one course.');
207  break;
208 
210  $this->log->debug('Parallel group scenario groups in courses.');
211  break;
212 
214  $this->log->debug('Parallel group scenario only courses.');
215  break;
216 
217  default:
218  $this->log->debug('Parallel group scenario undefined.');
219  break;
220  }
221 
222  $course_id = $course_member->lectureID;
223  $assigned = array();
224  foreach ((array) $course_member->members as $member) {
225  $assigned[$course_id][$member->personID] = array(
226  'id' => $member->personID,
227  'role' => $member->role
228  );
229  if ((int) $course->groupScenario === ilECSMappingUtils::PARALLEL_ONE_COURSE) {
230  $this->log->debug('Group scenarion "one course". Ignoring group assignments');
231  continue;
232  }
233 
234  if (property_exists($member, 'groups')) {
235  foreach ((array) $member->groups as $pgroup) {
236  // the sequence number in the course ressource
237  $sequence_number = (int) $pgroup->num;
238  // find parallel group with by sequence number
239  if (property_exists($course, 'groups')) {
240  $tmp_pgroup = $course->groups[$sequence_number] ?? null;
241 
242  if (is_object($tmp_pgroup) && $tmp_pgroup->id !== '') {
243  $this->log->debug('Found parallel group with id: ' . $tmp_pgroup->id . ': for sequence number: ' . $sequence_number);
244 
245  // @todo check hierarchy of roles
246  $assigned[$tmp_pgroup->id][$member->personID] = array(
247  'id' => $member->personID,
248  'role' => $pgroup->role
249  );
250  } else {
251  $this->log->warning('Cannot find parallel group with sequence id: ' . $sequence_number);
252  }
253  } else {
254  $this->log->error('Invalid course/group-configuration found, ignoring}');
255  }
256 
257  }
258  }
259  }
260  $this->log->debug('ECS member assignments ' . print_r($assigned, true));
261  return $assigned;
262  }
263 
264 
265 
269  protected function refreshAssignmentStatus(object $course_member, int $obj_id, ?string $sub_id, $assigned): bool
270  {
271  $this->log->debug('Currrent sub_id = ' . $sub_id . ', obj_id = ' . $obj_id);
272 
273  $type = ilObject::_lookupType($obj_id);
274  if ($type === 'crs') {
276  } elseif ($type === 'grp') {
278  } else {
279  $this->log->warning('Invalid object type given for obj_id: ' . $obj_id);
280  return false;
281  }
282 
283  $course_id = (int) $course_member->lectureID;
285  $course_id,
286  is_null($sub_id) ? $sub_id : (int) $sub_id,
287  $obj_id
288  );
289  $this->log->debug('Current coursemember assignments:');
290  $this->log->dump($usr_ids, ilLogLevel::DEBUG);
291 
292  // Delete remote deleted
293  foreach ($usr_ids as $usr_id) {
294  if (!isset($assigned[$usr_id])) {
295  $ass = ilECSCourseMemberAssignment::lookupAssignment($course_id, is_null($sub_id) ? $sub_id : (int) $sub_id, $obj_id, $usr_id);
296  if ($ass instanceof ilECSCourseMemberAssignment) {
298  $this->mapping->getAuthMode(),
299  (string) $usr_id
300  );
301 
302  $this->log->debug('Local user assignment: ' . $usr_id . ' <-> ' . $login);
303 
304  if ($il_usr_id = ilObjUser::_lookupId($login)) {
305  // this removes also admin, tutor roles
306  $part->delete($il_usr_id);
307  $this->log->info('Deassigning user ' . $usr_id . ' ' . 'from course ' . ilObject::_lookupTitle($obj_id));
308  } else {
309  $this->log->notice('Deassigning unknown ILIAS user ' . $usr_id . ' ' . 'from course ' . ilObject::_lookupTitle($obj_id));
310  }
311 
312  $ass->delete();
313  }
314  }
315  }
316 
317  $this->log->debug('Handled assignmnent...');
318 
319  // Assign new participants
320  foreach ((array) $assigned as $person_id => $person) {
321  $role = $this->lookupRole((string) $person['role'], $type);
322  $role_info = ilECSMappingUtils::getRoleMappingInfo($role);
323 
324  $this->log->debug('Using role info...');
326  $this->mapping->getAuthMode(),
327  (string) $person_id
328  );
329  $this->log->info('Handling user ' . $person_id);
330 
331  if (in_array($person_id, $usr_ids, true)) {
332  if ($il_usr_id = ilObjUser::_lookupId($login)) {
333  $this->log->info('Update user assignment for: ' . $person_id);
334  $part->updateRoleAssignments($il_usr_id, array($part->getAutoGeneratedRoleId($role)));
335  } elseif ($role_info['create']) {
336  $this->createMember($person_id);
337  $this->log->info('Added new user ' . $person_id);
339  $this->mapping->getAuthMode(),
340  (string) $person_id
341  );
342  if ($role && $il_usr_id = ilObjUser::_lookupId($login)) {
343  $part->add($il_usr_id, $role);
344  $part->sendNotification(ilCourseMembershipMailNotification::TYPE_ADMISSION_MEMBER, $il_usr_id);
345  }
346  }
347  } else {
348  if ($il_usr_id = ilObjUser::_lookupId($login)) {
349  // user exists => assign to course/group
350  if ($role) {
351  // Assign user
352  $this->log->info('Assigning new user ' . $person_id . ' ' . 'to ' . ilObject::_lookupTitle($obj_id) . ' using role: ' . $role);
353  $part->add($il_usr_id, $role);
354  $part->sendNotification(ilCourseMembershipMailNotification::TYPE_ADMISSION_MEMBER, $il_usr_id);
355  }
356  } else {
357  // no local user exists
358  if ($role_info['create']) {
359  $this->createMember($person_id);
360  $this->log->info('Added new user ' . $person_id);
362  $this->mapping->getAuthMode(),
363  (string) $person_id
364  );
365  }
366  // Assign to role
367  if ($role && $il_usr_id = ilObjUser::_lookupId($login)) {
368  $this->log->info('Assigning new role to existing user ' . $person_id . ' ' . 'to ' . ilObject::_lookupTitle($obj_id) . ' using role: ' . $role);
369  $part->add($il_usr_id, $role);
370  $part->sendNotification(ilCourseMembershipMailNotification::TYPE_ADMISSION_MEMBER, $il_usr_id);
371  }
372  }
373 
374  $assignment = new ilECSCourseMemberAssignment();
375  $assignment->setServer($this->getServer()->getServerId());
376  $assignment->setMid($this->mid);
377  $assignment->setCmsId($course_id);
378  $assignment->setCmsSubId(is_null($sub_id) ? $sub_id : (int) $sub_id);
379  $assignment->setObjId($obj_id);
380  $assignment->setUid((string) $person_id);
381  $assignment->save();
382  }
383  }
384  return true;
385  }
386 
390  protected function lookupRole(string $role_value, $a_obj_type): int
391  {
392  $role_mappings = $this->mapping->getRoleMappings();
393 
394  /* Zero is an allowed value */
395  if (!$role_value) {
396  $this->log->debug('No role assignment attribute: role');
397  }
398  foreach ($role_mappings as $name => $map) {
399  $this->log->debug('Role "name" is ' . $name);
400 
401  // map is a string of ids seperated by ","
402  $exploded_map = (array) explode(',', $map);
403  if (in_array($role_value, $exploded_map, true)) {
404  switch ($name) {
408  if ($a_obj_type === 'crs') {
409  $this->log->debug('Role: ' . $role_value . ' maps: ' . $map);
410  return $name;
411  }
412  break;
413 
416  if ($a_obj_type === 'grp') {
417  $this->log->debug('Role: ' . $role_value . ' maps: ' . $map);
418  return $name;
419  }
420  break;
421  }
422  }
423  }
424  $this->log->info('No role assignment mapping for role ' . $role_value);
425  return 0;
426  }
427 
431  private function createMember($a_person_id): void
432  {
433  if (!$this->mapping instanceof ilECSNodeMappingSettings) {
434  $this->log->warning('Node mapping settings not initialized.');
435  }
436  $auth_mode = $this->mapping->getAuthMode();
437 
438  if (
439  $this->mapping->getAuthMode() ===
441  ) {
442  $this->log->info('Not handling direct user creation for auth mode: ' . $auth_mode);
443  return;
444  }
445  if (strpos($auth_mode, 'ldap') !== 0) {
446  $this->log->info('Not handling direct user creation for auth mode: ' . $auth_mode);
447  return;
448  }
449 
450  try {
452  $server->doConnectionCheck();
453 
454  $query = new ilLDAPQuery($server);
455  $query->bind(ilLDAPQuery::LDAP_BIND_DEFAULT);
456 
457  $users = $query->fetchUser((string) $a_person_id);
458  if ($users) {
460 
461  $xml = new ilLDAPAttributeToUser($server);
462  $xml->setNewUserAuthMode($server->getAuthenticationMappingKey());
463  $xml->setUserData($users);
464  $xml->refresh();
465  }
466  } catch (ilLDAPQueryException $exc) {
467  $this->log->error($exc->getMessage());
468  }
469  }
470 
471 
475  private function readCourseMember(ilECSSetting $server, $a_content_id)
476  {
477  return (new ilECSCourseMemberConnector($server))->getCourseMember($a_content_id);
478  }
479 
483  private function readCourse($course_member)
484  {
485  $ecs_id = ilECSImportManager::getInstance()->lookupEContentIdByContentId(
486  $this->getServer()->getServerId(),
487  $this->getMid(),
488  $course_member->lectureID
489  );
490  if (0 === $ecs_id) {
491  return null;
492  }
493  return (new ilECSCourseConnector($this->getServer()))->getCourse($ecs_id);
494  }
495 }
handleCreate(ilECSSetting $server, $a_content_id)
Handle create.
static _getFirstActiveServer()
Get first active server.
static getInstance(int $a_server_id, int $mid)
Get instance by server id and mid.
static getRoleMappingInfo($a_role_type_info=0)
Get role mapping info.
const int AUTH_SHIBBOLETH
static getInstanceByServerId(int $a_server_id)
Get instance by server id.
static getInstanceByServerMid(int $a_server_id, int $a_mid)
Get instance.
if(!file_exists('../ilias.ini.php'))
static _lookupId($a_user_str)
lookupRole(string $role_value, $a_obj_type)
Lookup local role by assignment.
static _checkExternalAuthAccount(string $a_auth, string $a_account, bool $tryFallback=true)
check whether external account and authentication method matches with a user
server()
description: > This example shows how a Progress Bar can be rendered and updated by the server...
Definition: server.php:43
checkAllocationActivation(ilECSSetting $server, $a_content_id)
Check if course allocation is activated for one recipient of the.
static _getAuthModeName($a_auth_key)
Interface for all command queue handler classes.
handleDelete(ilECSSetting $server, $a_content_id)
Handle delete.
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
static lookupAssignment(int $a_cms_id, ?int $a_cms_sub_id, int $a_obj_id, string $a_usr_id)
Lookup assignment of user.
static getInstance()
Get the singleton instance of this ilECSImportManager.
static _lookupTitle(int $obj_id)
static _getInstanceByObjId(int $a_obj_id)
readAssignments($course, $course_member)
Read assignments for all parallel groups.
global $DIC
Definition: shib_login.php:26
static lookupUserIds(int $a_cms_id, ?int $a_cms_sub_id, int $a_obj_id)
Lookup user ids.
Connector for course member ressource.
Storage of ecs course assignments.
static _getInstanceByObjId(int $a_obj_id)
Get singleton instance.
readCourseMember(ilECSSetting $server, $a_content_id)
Read course from ecs.
handleUpdate(ilECSSetting $server, $a_content_id)
Handle update.
Update/create ILIAS user account by given LDAP attributes according to user attribute mapping setting...
refreshAssignmentStatus(object $course_member, int $obj_id, ?string $sub_id, $assigned)
Refresh status of course member assignments.
static _lookupType(int $id, bool $reference=false)