From 7cbba1ec8a0de90e02632fe06beebb2e672a07a2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Arne=20Schr=C3=B6der=2C=20M=2E=20A=2E?=
 <schroeder@data-quest.de>
Date: Thu, 19 Dec 2024 13:38:22 +0000
Subject: [PATCH] =?UTF-8?q?Resolve=20"Accountmanagement=20f=C3=BCr=20verkn?=
 =?UTF-8?q?=C3=BCpfte=20ILIAS-Accounts=20in=20Stud.IP"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #4263

Merge request studip/studip!3368
---
 app/controllers/admin/ilias_interface.php     |  2 +
 app/controllers/admin/user.php                | 12 ++++
 app/controllers/my_ilias_accounts.php         | 64 ++++++++++++++++++
 .../admin/ilias_interface/edit_content.php    |  4 ++
 app/views/admin/user/edit.php                 | 37 ++++++++++-
 .../administrate_account.php                  | 65 +++++++++++++++++++
 lib/ilias_interface/ConnectedIlias.php        | 17 +++--
 lib/ilias_interface/IliasUser.php             |  3 +-
 8 files changed, 197 insertions(+), 7 deletions(-)
 create mode 100644 app/views/my_ilias_accounts/administrate_account.php

diff --git a/app/controllers/admin/ilias_interface.php b/app/controllers/admin/ilias_interface.php
index d0e59ea7775..750e33d9118 100644
--- a/app/controllers/admin/ilias_interface.php
+++ b/app/controllers/admin/ilias_interface.php
@@ -129,6 +129,7 @@ class Admin_IliasInterfaceController extends AuthenticatedController
                             'url' => _('https://<URL zur ILIAS-Installation>'),
                             'client' => '',
                             'ldap_enable' => '',
+                            'reconnect_accounts' => false,
                             'no_account_updates' => false,
                             'admin' => 'ilias_soap_admin',
                             'admin_pw' => '',
@@ -351,6 +352,7 @@ class Admin_IliasInterfaceController extends AuthenticatedController
                         $this->ilias_configs[$index]['course_veranstaltungsnummer'] = Request::get('ilias_course_veranstaltungsnummer');
                     }
                     $this->ilias_configs[$index]['delete_ilias_users'] = Request::get('ilias_delete_ilias_users');
+                    $this->ilias_configs[$index]['reconnect_accounts'] = Request::bool('ilias_reconnect_accounts', false);
                     $this->ilias_configs[$index]['delete_ilias_courses'] = Request::get('ilias_delete_ilias_courses');
                     $this->ilias_configs[$index]['category_create_on_add_module'] = Request::get('ilias_category_create_on_add_module');
                     $this->ilias_configs[$index]['category_to_desktop'] = Request::get('ilias_category_to_desktop');
diff --git a/app/controllers/admin/user.php b/app/controllers/admin/user.php
index 4af6b42470b..9a610598935 100644
--- a/app/controllers/admin/user.php
+++ b/app/controllers/admin/user.php
@@ -415,6 +415,18 @@ class Admin_UserController extends AuthenticatedController
 
         $this->user_roles = $this->user->getRoles();
 
+        // get ilias account data 
+        if ($GLOBALS['perm']->have_perm('root') && Config::get()->ILIAS_INTERFACE_ENABLE) {
+            $this->ilias_list = [];
+            foreach (Config::get()->ILIAS_INTERFACE_SETTINGS as $ilias_index => $ilias_config) {
+                if ($ilias_config['is_active']) {
+                    $this->ilias_list[$ilias_index] = new ConnectedIlias($ilias_index);
+                    $this->ilias_list[$ilias_index]->soap_client->clearCache();
+                    $this->ilias_user[$ilias_index] = new IliasUser($ilias_index, $ilias_config['version'], $user_id);
+                }
+            }
+        }
+
         // Änderungen speichern
         if (Request::submitted('edit')) {
             CSRFProtection::verifyUnsafeRequest();
diff --git a/app/controllers/my_ilias_accounts.php b/app/controllers/my_ilias_accounts.php
index b82ec7d88ec..84060acf9b5 100644
--- a/app/controllers/my_ilias_accounts.php
+++ b/app/controllers/my_ilias_accounts.php
@@ -161,6 +161,70 @@ class MyIliasAccountsController extends AuthenticatedController
         $this->redirect($this->url_for('my_ilias_accounts/index'));
     }
 
+    /**
+     * Administrate account for ILIAS installation
+     * @param $user_id studip user id
+     * @param $index Index of ILIAS installation
+     * @param $mode action type
+     */
+    public function administrate_account_action($user_id, $index)
+    {
+        if (!$GLOBALS['perm']->have_perm('root')) {
+            throw new AccessDeniedException();
+        }
+
+        $ilias_configs = Config::get()->ILIAS_INTERFACE_SETTINGS;
+        if ($ilias_configs[$index]['is_active']) {
+            $this->ilias = new ConnectedIlias($index);
+            $this->ilias_index = $index;
+            $this->ilias_login = '';
+            $this->matched_user = false;
+            $this->external_account_login = '';
+            $this->external_account_id = false;
+            $this->user_exists = false;
+            $this->user = new IliasUser($index, $ilias_configs[$index]['version'], $user_id);
+
+            if (Request::submitted('lookup_account')) {
+                $this->ilias_login = trim(Request::option('ilias_login'));
+                $this->matched_user = $this->ilias->soap_client->lookupUser($this->ilias_login);
+                if (empty($this->matched_user)) {
+                    PageLayout::postError(sprintf(_('Es wurde kein Account mit dem Loginnamen "%s" gefunden.'), htmlReady($this->ilias_login)));
+                } else {
+                    PageLayout::postInfo(sprintf(_('Account "%s" wurde gefunden.'), htmlReady($this->ilias_login)));
+                }
+            } elseif (Request::submitted('connect_account')) {
+                $new_user = $this->ilias->soap_client->getUser(Request::option('ilias_user_id'));
+                if ($new_user['usr_id'] && $new_user['login']) {
+                    $this->user->id = $new_user['usr_id'];
+                    $this->user->login = $new_user['login'];
+                    $this->user->setConnection(IliasUser::USER_TYPE_ORIGINAL);
+                    PageLayout::postSuccess(_('Account zugeordnet.'));
+                }
+            } elseif (Request::submitted('disconnect_account')) {
+                if ($this->user->unsetConnection(true)) {
+                    PageLayout::postSuccess(_('Account-Zuordnung entfernt.'));
+                }
+            } elseif (Request::submitted('new_account')) {
+                $this->ilias->user = new IliasUser($index, $ilias_configs[$index]['version'], $user_id);
+                $this->ilias->soap_client->setCachingStatus(false);
+                $this->ilias->soap_client->clearCache();
+                $this->ilias->newUser();
+                PageLayout::postSuccess(_('Account angelegt.'));
+            }
+
+            // check if connection is valid / available
+            if ($this->user->isConnected()) {
+                $existing_user = $this->ilias->soap_client->getUser($this->user->id);
+                if ($existing_user && $existing_user['usr_id'] === $this->user->id) {
+                    $this->user_exists = true;
+                }
+            } else {
+                $this->external_account_login = $ilias_configs[$index]['user_prefix'] . $this->user->studip_login;
+                $this->external_account_id = $this->ilias->soap_client->lookupUser($this->external_account_login);
+            }
+        }
+    }
+
     /**
      * Redirect to ILIAS installation
      * @param $index Index of ILIAS installation
diff --git a/app/views/admin/ilias_interface/edit_content.php b/app/views/admin/ilias_interface/edit_content.php
index d0eb47e21e0..77c76eb9fb9 100644
--- a/app/views/admin/ilias_interface/edit_content.php
+++ b/app/views/admin/ilias_interface/edit_content.php
@@ -38,6 +38,10 @@
         <input type="checkbox" name="ilias_delete_ilias_users" value="1" <?= $ilias_config['delete_ilias_users'] ? 'checked' : '' ?>>
         <span><?= _('Beim Löschen von Stud.IP-Accounts ILIAS-Accounts ebenfalls löschen (alle zugehörigen Objekte werden gelöscht!)') ?></span>
     </label>
+    <label>
+        <input type="checkbox" name="ilias_reconnect_accounts" value="1" <?= $ilias_config['reconnect_accounts'] ? 'checked' : '' ?>>
+        <span><?= _('Externe User-Accounts automatisch verbinden, wenn sie den passenden Loginnamen haben') ?></span>
+    </label>
     <label>
         <span><?= _('Prefix für automatisch angelegte Usernamen') ?></span>
         <? if ($ilias_config['is_active']) : ?>
diff --git a/app/views/admin/user/edit.php b/app/views/admin/user/edit.php
index 47596a99496..3313e6ab608 100644
--- a/app/views/admin/user/edit.php
+++ b/app/views/admin/user/edit.php
@@ -232,8 +232,6 @@ use Studip\Button, Studip\LinkButton;
         <? endif ?>
     </fieldset>
 
-
-
     <fieldset>
         <legend>
             <?= _('Registrierungsdaten') ?>
@@ -368,6 +366,41 @@ use Studip\Button, Studip\LinkButton;
         </section>
     </fieldset>
 
+    <? if ($GLOBALS['perm']->have_perm('root') && Config::get()->ILIAS_INTERFACE_ENABLE) : ?>
+        <? foreach ($ilias_list as $ilias_index => $ilias) : ?>
+            <fieldset>
+                <legend>
+                    <?= htmlReady(sprintf(_('Account in %s'), htmlReady($ilias->getName()))) ?>
+                </legend>
+
+                <? if ($ilias_user[$ilias_index]->isConnected()) : ?>
+                    <label>
+                        <?= _('Loginname des verknüpften Accounts:') ?>
+                        <?= htmlReady($ilias_user[$ilias_index]->getUsername()) ?>
+                    </label>
+                    <label>
+                        <?= LinkButton::create(
+                            _('Verknüpfung bearbeiten'),
+                            $controller->url_for('my_ilias_accounts/administrate_account/' . $ilias_user[$ilias_index]->studip_id . '/' . $ilias_index . '/edit'),
+                            ['data-dialog' => 'reload-on-close']
+                        ) ?>
+                    </label>
+                <? else : ?>
+                    <label>
+                        <?= _('Kein Account verknüpft') ?>
+                    </label>
+                    <label>
+                        <?= LinkButton::create(
+                            _('Verknüpfung erstellen'),
+                            $controller->url_for('my_ilias_accounts/administrate_account/' . $ilias_user[$ilias_index]->studip_id . '/' . $ilias_index . '/edit'),
+                            ['data-dialog' => 'reload-on-close']
+                        ) ?>
+                    </label>
+                <? endif ?>
+            </fieldset>
+        <? endforeach ?>
+    <? endif ?>
+
     <? if (in_array($user->perms, ['autor', 'tutor', 'dozent'])): ?>
     <fieldset>
         <legend>
diff --git a/app/views/my_ilias_accounts/administrate_account.php b/app/views/my_ilias_accounts/administrate_account.php
new file mode 100644
index 00000000000..6b86fd8d168
--- /dev/null
+++ b/app/views/my_ilias_accounts/administrate_account.php
@@ -0,0 +1,65 @@
+<form class="default" action="<?= $controller->link_for('my_ilias_accounts/administrate_account/' . $user->studip_id . '/' . $ilias_index) ?>" method="post" data-dialog="reload-on-close">
+    <?= CSRFProtection::tokenTag() ?>
+    <fieldset>
+        <legend>
+            <?= _('Bestehenden Account zuordnen') ?>
+        </legend>
+        <? if (!$matched_user) : ?>
+            <label>
+                <span><?= _('Loginname') ?></span>
+                <input type="text" name="ilias_login" size="50" maxlength="50" value="<?= htmlReady($ilias_login) ?>">
+                <?= Studip\Button::createAccept(_('Account Suchen'), 'lookup_account') ?>
+            </label>
+        <? else : ?>
+            <label>
+                <span><?= htmlReady(sprintf(_('ILIAS Account %s (ID %s)'), $ilias_login, $matched_user)) ?></span>
+            </label>
+            <input type="hidden" name="ilias_user_id" value="<?= htmlReady($matched_user) ?>">
+            <?= Studip\Button::createAccept(_('Account zuordnen'), 'connect_account') ?>
+        <? endif ?>
+    </fieldset>
+    <? if ($user->isConnected()) : ?>
+        <fieldset>
+            <legend>
+                <?= _('Verknüpfter Account') ?>
+            </legend>
+            <table class="default nohover">
+                <tr>
+                    <td><?= _('Loginname des verknüpften Accounts:') ?></td>
+                    <td>
+                        <?= htmlReady($user->getUsername()) ?>
+                        <? if (!$user_exists): ?>
+                            - <?= _('Der verknüpfte Account wurde im angebundenen ILIAS-System nicht gefunden!') ?>
+                        <? endif; ?>
+                    </td>
+                </tr>
+                <tr>
+                    <td><?= _('Eigene Kategorie:') ?></td>
+                    <td><?= !empty($user->getCategory()) ? _('ID') . ' ' . htmlReady($user->getCategory()) : _('nicht vorhanden') ?></td>
+                </tr>
+                <tr>
+                    <td><?= _('Account-Typ:') ?></td>
+                    <td><?= $user->getUserType() == IliasUser::USER_TYPE_ORIGINAL ? _('Lokaler ILIAS-Account') : _('Automatisch erstellter Account') ?></td>
+                </tr>
+            </table>
+            <?= Studip\Button::createCancel(_('Verknüpfung aufheben'), 'disconnect_account') ?>
+        </fieldset>
+    <? else : ?>
+        <fieldset>
+            <legend>
+                <?= _('Kein Account verknüpft') ?>
+            </legend>
+            <? if ($external_account_id) : ?>
+                <label>
+                    <?= sprintf(_('Es existiert bereits ein ILIAS-Account mit dem Loginnamen %s.'), htmlReady($external_account_login)) ?>
+                    <input type="hidden" name="ilias_user_id" value="<?= htmlReady($external_account_id) ?>">
+                    <?= Studip\Button::createAccept(_('Mit externem Account verknüpfen'), 'connect_account') ?>
+                </label>
+            <? else : ?>
+                <label>
+                    <?= Studip\Button::createAccept(_('Neuen Account anlegen'), 'new_account') ?>
+                </label>
+            <? endif ?>
+        </fieldset>
+    <? endif ?>
+</form>
\ No newline at end of file
diff --git a/lib/ilias_interface/ConnectedIlias.php b/lib/ilias_interface/ConnectedIlias.php
index 94c6ad81413..e90f75b6fde 100644
--- a/lib/ilias_interface/ConnectedIlias.php
+++ b/lib/ilias_interface/ConnectedIlias.php
@@ -336,8 +336,17 @@ class ConnectedIlias
                 ($this->user->auth_plugin == $this->ilias_config['ldap_enable'])) {
             $this->user->id = $user_exists;
             $this->user->login = $user_data["login"];
-            $this->user->setConnection($this->user->getUserType(), true);
-            PageLayout::postSuccess(sprintf(_("Verbindung mit Nutzer ID %s wiederhergestellt."), $this->user->id));
+            $this->user->setConnection($this->user->getUserType());
+            PageLayout::postSuccess(sprintf(
+                _('Verbindung mit Account ID %s wiederhergestellt.'),
+                htmlReady($this->user->id)
+            ));
+            return true;
+        } elseif ($user_exists && $this->ilias_config['reconnect_accounts']) {
+            $this->user->id = $user_exists;
+            $this->user->login = $user_data["login"];
+            $this->user->setConnection($this->user->getUserType());
+            PageLayout::postSuccess(sprintf(_('Verbindung mit Account ID %s wiederhergestellt.'), htmlReady($this->user->id)));
             return true;
         } elseif ($user_exists) {
             $this->error[] = sprintf(_('Externer Account konnte nicht angelegt werden. Es existiert bereits ein User mit dem Login %s in %s'), $user_data["login"], $this->ilias_config['name']);
@@ -361,7 +370,7 @@ class ConnectedIlias
         }
 
         // set role according to Stud.IP perm
-        if (User::findCurrent()->perms === 'root') {
+        if (User::find($this->user->studip_id)->perms === 'root') {
             $role_id = 2;
         } else {
             $role_id = 4;
@@ -519,7 +528,7 @@ class ConnectedIlias
 
         // data for user category in ILIAS
         $object_data["title"] = sprintf(_("Eigene Daten von %s (%s)."), $this->user->getName(), $this->user->getId());
-        $object_data["description"] = sprintf(_("Hier befinden sich die persönlichen Lernmodule des Benutzers %s."), $this->user->getName());
+        $object_data['description'] = sprintf(_('Hier befinden sich die persönlichen Lernmodule von %s.'), $this->user->getName());
         $object_data["type"] = "cat";
         $object_data["owner"] = $this->user->getId();
 
diff --git a/lib/ilias_interface/IliasUser.php b/lib/ilias_interface/IliasUser.php
index c9233df4330..fbd15cec893 100644
--- a/lib/ilias_interface/IliasUser.php
+++ b/lib/ilias_interface/IliasUser.php
@@ -502,7 +502,7 @@ class IliasUser
     function unsetConnection($ignore_usertype = false)
     {
         if (!$ignore_usertype && ($this->getUserType() != self::USER_TYPE_ORIGINAL)) {
-            return;
+            return false;
         }
 
         $query = "DELETE FROM auth_extern WHERE studip_user_id = ? AND external_user_system_type = ? AND external_user_type = ?";
@@ -515,6 +515,7 @@ class IliasUser
 
         $this->is_connected = false;
         $this->readData();
+        return true;
     }
 
     /**
-- 
GitLab