From a7dba0c0caeae857b771b380f304b45c59a23bc6 Mon Sep 17 00:00:00 2001
From: David Siegfried <david.siegfried@uni-vechta.de>
Date: Fri, 22 Dec 2023 13:48:17 +0000
Subject: [PATCH] prevent php-error and cleanup unlinked db-entries, closes
 #3592

Closes #3592

Merge request studip/studip!2485
---
 db/migrations/5.5.14_cleanup_cw_tasks.php     | 23 +++++++++++++++++++
 .../JsonApi/Schemas/Courseware/Task.php       | 14 ++++++-----
 lib/classes/UserManagement.class.php          |  5 +++-
 lib/models/Statusgruppen.php                  | 14 ++++++++++-
 4 files changed, 48 insertions(+), 8 deletions(-)
 create mode 100644 db/migrations/5.5.14_cleanup_cw_tasks.php

diff --git a/db/migrations/5.5.14_cleanup_cw_tasks.php b/db/migrations/5.5.14_cleanup_cw_tasks.php
new file mode 100644
index 00000000000..94ab0198946
--- /dev/null
+++ b/db/migrations/5.5.14_cleanup_cw_tasks.php
@@ -0,0 +1,23 @@
+<?php
+
+final class CleanupCwTasks extends Migration
+{
+    public function description()
+    {
+        return 'deletes unlinked entries';
+    }
+
+    public function up()
+    {
+        DBManager::get()->exec('
+            DELETE FROM `cw_tasks`
+            WHERE `solver_type` = "user"
+              AND `solver_id` NOT IN (SELECT `user_id` FROM `auth_user_md5`)'
+        );
+        DBManager::get()->exec('
+            DELETE FROM `cw_tasks`
+            WHERE `solver_type` = "group"
+               AND `solver_id` NOT IN (SELECT `statusgruppe_id` FROM `statusgruppen`)'
+        );
+    }
+}
diff --git a/lib/classes/JsonApi/Schemas/Courseware/Task.php b/lib/classes/JsonApi/Schemas/Courseware/Task.php
index a87d335b64e..a0605e609d8 100644
--- a/lib/classes/JsonApi/Schemas/Courseware/Task.php
+++ b/lib/classes/JsonApi/Schemas/Courseware/Task.php
@@ -46,21 +46,23 @@ class Task extends SchemaProvider
     {
         $relationships = [];
 
-        $relationships[self::REL_FEEDBACK] = $resource->getFeedback()
+        $feedback = $resource->getFeedback();
+        $relationships[self::REL_FEEDBACK] = $feedback
             ? [
                 self::RELATIONSHIP_LINKS => [
-                    Link::RELATED => $this->createLinkToResource($resource->getFeedback()),
+                    Link::RELATED => $this->createLinkToResource($feedback),
                 ],
-                self::RELATIONSHIP_DATA => $resource->getFeedback(),
+                self::RELATIONSHIP_DATA => $feedback,
             ]
             : [self::RELATIONSHIP_DATA => null];
 
-        $relationships[self::REL_SOLVER] = $resource['solver_id']
+        $solver = $resource->getSolver();
+        $relationships[self::REL_SOLVER] = $solver
             ? [
                 self::RELATIONSHIP_LINKS => [
-                    Link::RELATED => $this->createLinkToResource($resource->getSolver()),
+                    Link::RELATED => $this->createLinkToResource($solver),
                 ],
-                self::RELATIONSHIP_DATA => $resource->getSolver(),
+                self::RELATIONSHIP_DATA => $solver,
             ]
             : [self::RELATIONSHIP_DATA => null];
 
diff --git a/lib/classes/UserManagement.class.php b/lib/classes/UserManagement.class.php
index 498036e2f7d..65ed310f5fa 100644
--- a/lib/classes/UserManagement.class.php
+++ b/lib/classes/UserManagement.class.php
@@ -987,7 +987,10 @@ class UserManagement
         \Courseware\UserDataField::deleteBySQL('user_id = ?', [$this->user_data['auth_user_md5.user_id']]);
         \Courseware\UserProgress::deleteBySQL('user_id = ?', [$this->user_data['auth_user_md5.user_id']]);
         \Courseware\Bookmark::deleteBySQL('user_id = ?', [$this->user_data['auth_user_md5.user_id']]);
-
+        \Courseware\Task::deleteBySQL(
+            '`solver_id` = ? AND `solver_type`= "user"',
+            [$this->user_data['auth_user_md5.user_id']]
+        );
         // delete courseware elements in courses of this user
         if ($delete_courseware) {
             \Courseware\Unit::deleteBySQL('creator_id = ?', [$this->user_data['auth_user_md5.user_id']]);
diff --git a/lib/models/Statusgruppen.php b/lib/models/Statusgruppen.php
index fa620f56602..be4ee6a2ffb 100644
--- a/lib/models/Statusgruppen.php
+++ b/lib/models/Statusgruppen.php
@@ -104,7 +104,7 @@ class Statusgruppen extends SimpleORMap implements PrivacyObject
 
         $config['registered_callbacks']['before_store'][] = 'cbAddPosition';
         $config['registered_callbacks']['after_delete'][] = 'cbReorderPositions';
-
+        $config['registered_callbacks']['after_delete'][] = 'cbRemoveTasks';
         $config['i18n_fields']['name'] = true;
         $config['i18n_fields']['name_w'] = true;
         $config['i18n_fields']['name_m'] = true;
@@ -701,6 +701,18 @@ class Statusgruppen extends SimpleORMap implements PrivacyObject
         self::reorderPositionsForRange($this->range_id);
     }
 
+    /**
+     * This callback is called after deleting a User.
+     * It removes courseware task entries that are associated with the group.
+     */
+    public function cbRemoveTask()
+    {
+        \Courseware\Task::deleteBySQL(
+            '`solver_id` = ? AND `solver_type`= "group"',
+            [$this->id]
+        );
+    }
+
     /**
      * Export available data of a given user into a storage object
      * (an instance of the StoredUserData class) for that user.
-- 
GitLab