From 7abf792f02366b517c243b963cbc3768e64bfe54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Sch=C3=BCttl=C3=B6ffel?= <schuettloeffel@zqs.uni-hannover.de> Date: Tue, 26 Nov 2024 09:30:35 +0000 Subject: [PATCH] =?UTF-8?q?Resolve=20"VA=20automatisch=20l=C3=B6schen=20we?= =?UTF-8?q?nn=20sie=20keine=20Mitglieder=20mehr=20hat"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #4289 Merge request studip/studip!3144 --- db/migrations/6.0.34_add_dummy_teacher.php | 57 +++++++++++++ lib/classes/UserManagement.php | 99 +++++++++++++--------- tests/jsonapi/UsersIndexTest.php | 4 +- 3 files changed, 119 insertions(+), 41 deletions(-) create mode 100644 db/migrations/6.0.34_add_dummy_teacher.php diff --git a/db/migrations/6.0.34_add_dummy_teacher.php b/db/migrations/6.0.34_add_dummy_teacher.php new file mode 100644 index 00000000000..d987dc20cfd --- /dev/null +++ b/db/migrations/6.0.34_add_dummy_teacher.php @@ -0,0 +1,57 @@ +<?php +class AddDummyTeacher extends Migration +{ + public function description() + { + return 'Adds a dummy teacher (N.N.). Adds config to set dummy teachers id. @see tic #4289'; + } + + protected function up() + { + // Add dummy teacher + $stm = DBManager::get()->prepare("SELECT * FROM `auth_user_md5` WHERE `username` = 'N.N.'"); + $stm->execute(); + if ($stm->rowCount() > 0) { + $res = $stm->fetch(); + $user_id = $res['user_id']; + } else { + $user_id = '2afaa0dce05f0b12a7318075e52879e2'; + DBManager::get()->execute( + "INSERT INTO `auth_user_md5` (user_id, username, perms, Vorname, Nachname, visible) VALUES (:user_id, :username, :perms, :Vorname, :Nachname, :visible)", + [ + 'user_id' => $user_id, + 'username' => 'N.N.', + 'perms' => 'dozent', + 'Vorname' => 'N.', + 'Nachname' => 'N.', + 'visible' => 'never' + ] + ); + } + + // Add config + DBManager::get()->execute( + "INSERT IGNORE INTO `config` VALUES (:field, :value, :type, :range, :section, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), :desc)", + [ + 'field' => 'DUMMY_TEACHER_ID', + 'value' => $user_id, + 'type' => 'string', + 'range' => 'global', + 'section' => 'global', + 'desc' => 'ID of user that should be added to course if no teacher is left' + ] + ); + } + + protected function down() + { + // Dont delete dummy user, maybe it existed before this migration + + // Delete config + $query = "DELETE `config`, `config_values` + FROM `config` + LEFT JOIN `config_values` USING (`field`) + WHERE `field` = 'DUMMY_TEACHER_ID'"; + DBManager::get()->exec($query); + } +} diff --git a/lib/classes/UserManagement.php b/lib/classes/UserManagement.php index 8e7821044a6..f4c47108e55 100644 --- a/lib/classes/UserManagement.php +++ b/lib/classes/UserManagement.php @@ -812,39 +812,61 @@ class UserManagement } } - // active dozent? - $query = "SELECT COUNT(*) - FROM ( - SELECT 1 - FROM `seminar_user` AS `su1` - -- JOIN seminar_user to check for other teachers - INNER JOIN `seminar_user` AS `su2` - ON (`su1`.`seminar_id` = `su2`.`seminar_id` AND `su2`.`status` = 'dozent') - -- JOIN seminare to check the status for studygroup mode - INNER JOIN `seminare` - ON (`su1`.`seminar_id` = `seminare`.`seminar_id`) - WHERE `su1`.`user_id` = :user_id - AND `su1`.`status` = 'dozent' - AND `seminare`.`status` NOT IN ( - -- Select all status ids for studygroups - SELECT `id` - FROM `sem_classes` - WHERE `studygroup_mode` = 1 - ) - GROUP BY `su1`.`seminar_id` - HAVING COUNT(*) = 1 - ORDER BY NULL - ) AS `sub`"; - $statement = DBManager::get()->prepare($query); - $statement->bindValue(':user_id', $this->user_data['auth_user_md5.user_id']); - $statement->execute(); - $active_count = $statement->fetchColumn() ?: 0; - - if ($active_count && $delete_memberships) { - $this->msg .= 'error§' . sprintf(_('<em>%s</em> ist Lehrkraft in %s aktiven Veranstaltungen und kann daher nicht gelöscht werden.'), $this->user_data['auth_user_md5.username'], $active_count) . '§'; + // Check if dummy teacher exists + if (!Config::get()->DUMMY_TEACHER_ID || !User::find(Config::get()->DUMMY_TEACHER_ID)) { + $this->msg .= 'error§' . sprintf( + _('Dummy-Dozent (id: %s) nicht gefunden. Bitte DUMMY_TEACHER_ID in Konfiguration setzen.'), + Config::get()->DUMMY_TEACHER_ID) . '§'; return false; - //founder of studygroup? - } elseif (Config::get()->STUDYGROUPS_ENABLE) { + } + + // Delete courses where user is the only one left (besides the dummy teacher) + $members = CourseMember::findBySQL( + "LEFT JOIN seminare USING(Seminar_id) + WHERE seminare.status NOT IN (?) AND user_id != ? + GROUP BY Seminar_id + HAVING COUNT(DISTINCT user_id) = 1 AND user_id = ?", + [ + studygroup_sem_types(), + Config::get()->DUMMY_TEACHER_ID, + $this->user->id + ] + ); + foreach ($members as $member) { + $this->msg .= 'info§' . sprintf( + _('User ist einziges Mitglied in Veranstaltung (%s), lösche Veranstaltung.'), + $member->course->id + ) . '§'; + $member->course->delete(); + } + + // Add dummy teacher to courses when only the user is left as teacher + $members = CourseMember::findBySQL( + "LEFT JOIN seminare USING(Seminar_id) + WHERE seminare.status NOT IN (?) AND user_id != ? AND seminar_user.status = 'dozent' + GROUP BY Seminar_id + HAVING COUNT(DISTINCT user_id) = 1 AND user_id = ?", + [ + studygroup_sem_types(), + Config::get()->DUMMY_TEACHER_ID, + $this->user->id + ] + ); + foreach ($members as $member) { + $this->msg .= 'info§' . sprintf( + _('User ist einziger Dozent in Veranstaltung (id: %s), füge Dummy-Dozent hinzu.'), + $member->course->id + ) . '§'; + CourseMember::insertCourseMember( + $member->course->id, + Config::get()->DUMMY_TEACHER_ID, + 'dozent' + ); + + } + + // Founder of studygroup? + if (Config::get()->STUDYGROUPS_ENABLE) { $status = studygroup_sem_types(); if (empty($status)) { @@ -896,6 +918,11 @@ class UserManagement // delete user from instituts $this->logInstUserDel($this->user_data['auth_user_md5.user_id']); + // Delete from all courses and studygroups + if ($count = CourseMember::deleteByUser_id($this->user->id)) { + $this->msg .= 'info§' . sprintf(_('Aus %s Veranstaltungen/Studiengruppen ausgetragen.'), $count) . '§'; + } + if ($delete_memberships) { $query = "DELETE FROM user_inst WHERE user_id = ?"; $statement = DBManager::get()->prepare($query); @@ -927,14 +954,6 @@ class UserManagement $this->re_sort_position_in_seminar_user(); - // delete user from seminars (postings will be preserved) - $query = "DELETE FROM seminar_user WHERE user_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$this->user_data['auth_user_md5.user_id']]); - if ($count = $statement->rowCount()) { - $this->msg .= 'info§' . sprintf(_('%s Einträge aus Veranstaltungen gelöscht.'), $count) . '§'; - } - $query = "DELETE FROM `termin_related_persons` WHERE `user_id` = ?"; $statement = DBManager::get()->prepare($query); $statement->execute([$this->user_data['auth_user_md5.user_id']]); diff --git a/tests/jsonapi/UsersIndexTest.php b/tests/jsonapi/UsersIndexTest.php index adffee632ce..6c79cae8fd6 100644 --- a/tests/jsonapi/UsersIndexTest.php +++ b/tests/jsonapi/UsersIndexTest.php @@ -28,7 +28,9 @@ class UsersIndexTest extends \Codeception\Test\Unit $response = $this->getUsers($credentials); $this->tester->assertTrue($response->isSuccessfulDocument([200])); - $numberOfAllUsers = \User::countBySQL(); + $vis_query = get_vis_query(context: 'search'); + $condition = "LEFT JOIN user_visibility ON (user_visibility.user_id = auth_user_md5.user_id) WHERE {$vis_query}"; + $numberOfAllUsers = \User::countBySQL($condition); $this->tester->assertSame($numberOfAllUsers, count($response->document()->primaryResources())); $this->assertValidResourceObject($response, 'users'); -- GitLab