From 97994ba76c4c806b3bf410dc1ddff7777a2c1d33 Mon Sep 17 00:00:00 2001
From: Jan-Hendrik Willms <tleilax+studip@gmail.com>
Date: Wed, 3 Jan 2024 18:55:42 +0000
Subject: [PATCH] fixes #3206

Closes #3206

Merge request studip/studip!2173
---
 lib/calendar/CalendarWriterICalendar.class.php           | 3 ++-
 lib/classes/I18N.php                                     | 5 +++--
 lib/classes/JsonApi/Middlewares/Authentication.php       | 9 +++++++--
 .../JsonApi/Routes/Files/FileRefsCreateByUpload.php      | 2 +-
 .../JsonApi/Routes/Forum/ForumCategoryEntriesCreate.php  | 8 +++++++-
 lib/classes/JsonApi/Routes/Messages/InboxShow.php        | 2 +-
 lib/classes/JsonApi/settings.php                         | 4 ++--
 lib/classes/SemClass.class.php                           | 2 +-
 lib/classes/calendar/CalendarScheduleModel.php           | 6 +++---
 lib/filesystem/StandardFile.php                          | 4 ++--
 lib/messaging.inc.php                                    | 2 +-
 lib/models/CourseEvent.class.php                         | 4 ++--
 lib/models/EventData.class.php                           | 2 +-
 lib/models/File.php                                      | 2 +-
 lib/models/SeminarCycleDate.class.php                    | 2 +-
 lib/models/User.class.php                                | 2 +-
 tests/_support/Helper/Jsonapi.php                        | 4 ++--
 tests/_support/_generated/JsonapiTesterActions.php       | 2 +-
 tests/jsonapi/BlubberCommentsByThreadIndexTest.php       | 2 +-
 tests/jsonapi/BlubberCommentsDeleteTest.php              | 2 +-
 tests/jsonapi/BlubberCommentsShowTest.php                | 2 +-
 tests/jsonapi/BlubberTestHelper.php                      | 2 +-
 tests/jsonapi/ConsultationsBlockShowTest.php             | 2 +-
 tests/jsonapi/ConsultationsBookingShowTest.php           | 2 +-
 tests/jsonapi/ConsultationsSlotShowTest.php              | 2 +-
 tests/jsonapi/FilesTestHelper.php                        | 2 +-
 tests/jsonapi/MessagesOutboxTest.php                     | 2 +-
 tests/jsonapi/SeminarCycleDatesShowTest.php              | 4 ++--
 tests/jsonapi/StructuralElementsShowTest.php             | 4 ++--
 tests/jsonapi/StudipPropertiesIndexTest.php              | 4 ++++
 tests/jsonapi/UserEventsIcalTest.php                     | 2 +-
 tests/jsonapi/WikiIndexTest.php                          | 6 +++---
 tests/jsonapi/_bootstrap.php                             | 4 +++-
 33 files changed, 63 insertions(+), 44 deletions(-)

diff --git a/lib/calendar/CalendarWriterICalendar.class.php b/lib/calendar/CalendarWriterICalendar.class.php
index b416dde82e9..e65a89f98d5 100644
--- a/lib/calendar/CalendarWriterICalendar.class.php
+++ b/lib/calendar/CalendarWriterICalendar.class.php
@@ -39,7 +39,8 @@ class CalendarWriterICalendar extends CalendarWriter
         if ($this->client_identifier) {
             $header .= "PRODID:" . $this->client_identifier . $this->newline;
         } else {
-            $header .= "PRODID:-//Stud.IP@{$_SERVER['SERVER_NAME']}//Stud.IP_iCalendar Library";
+            $host = $_SERVER['SERVER_NAME'] ?? parse_url($GLOBALS['ABSOLUTE_URI_STUDIP'], PHP_URL_HOST);
+            $header .= "PRODID:-//Stud.IP@{$host}//Stud.IP_iCalendar Library";
             $header .= " //EN" . $this->newline;
         }
         $header .= "METHOD:PUBLISH" . $this->newline;
diff --git a/lib/classes/I18N.php b/lib/classes/I18N.php
index 99a48b01183..d34ed0b3ce7 100644
--- a/lib/classes/I18N.php
+++ b/lib/classes/I18N.php
@@ -48,8 +48,9 @@ class I18N
      */
     public static function isEnabled()
     {
-        return is_array($GLOBALS['CONTENT_LANGUAGES']) &&
-            count($GLOBALS['CONTENT_LANGUAGES']) > 1;
+        return isset($GLOBALS['CONTENT_LANGUAGES'])
+            && is_array($GLOBALS['CONTENT_LANGUAGES'])
+            && count($GLOBALS['CONTENT_LANGUAGES']) > 1;
     }
 
     protected $template;
diff --git a/lib/classes/JsonApi/Middlewares/Authentication.php b/lib/classes/JsonApi/Middlewares/Authentication.php
index 5b097d677a3..de92e15c9c0 100644
--- a/lib/classes/JsonApi/Middlewares/Authentication.php
+++ b/lib/classes/JsonApi/Middlewares/Authentication.php
@@ -80,7 +80,10 @@ class Authentication
      */
     private function provideUser(Request $request, \User $user): Request
     {
-        if ('nobody' === $GLOBALS['user']->id) {
+        if (
+            !isset($GLOBALS['user'])
+            || 'nobody' === $GLOBALS['user']->id
+        ) {
             $GLOBALS['user'] = new \Seminar_User($user);
             $GLOBALS['auth'] = new \Seminar_Auth();
             $GLOBALS['auth']->auth = [
@@ -90,7 +93,9 @@ class Authentication
             ];
             $GLOBALS['perm'] = new \Seminar_Perm();
             $GLOBALS['MAIL_VALIDATE_BOX'] = false;
-            $GLOBALS['sess']->delete();
+            if (isset($GLOBALS['sess'])) {
+                $GLOBALS['sess']->delete();
+            }
             setTempLanguage($user->id);
         }
 
diff --git a/lib/classes/JsonApi/Routes/Files/FileRefsCreateByUpload.php b/lib/classes/JsonApi/Routes/Files/FileRefsCreateByUpload.php
index 8c18ca1aaae..9db9bd31b32 100644
--- a/lib/classes/JsonApi/Routes/Files/FileRefsCreateByUpload.php
+++ b/lib/classes/JsonApi/Routes/Files/FileRefsCreateByUpload.php
@@ -22,7 +22,7 @@ class FileRefsCreateByUpload extends NonJsonApiController
             throw new AuthorizationFailedException();
         }
 
-        $term_id = $request->getParsedBody()['term-id'];
+        $term_id = $request->getParsedBody()['term-id'] ?? null;
 
         $fileRef = $this->handleUpload($request, $folder);
 
diff --git a/lib/classes/JsonApi/Routes/Forum/ForumCategoryEntriesCreate.php b/lib/classes/JsonApi/Routes/Forum/ForumCategoryEntriesCreate.php
index 86b3c8ccce0..7199e39b100 100644
--- a/lib/classes/JsonApi/Routes/Forum/ForumCategoryEntriesCreate.php
+++ b/lib/classes/JsonApi/Routes/Forum/ForumCategoryEntriesCreate.php
@@ -18,9 +18,15 @@ class ForumCategoryEntriesCreate extends AbstractEntriesCreate
     {
         $json = $this->validate($request);
         $categoryId = $args['id'];
+
+        if (!ForumCat::exists($categoryId)) {
+            throw new RecordNotFoundException('Could not find category.');
+        }
+
         $courseId = ForumCat::find($categoryId)->seminar_id;
+        $course = \Course::find($courseId);
 
-        if (!$course = \Course::find($courseId)) {
+        if (!$course) {
             throw new RecordNotFoundException('Could not find course.');
         }
 
diff --git a/lib/classes/JsonApi/Routes/Messages/InboxShow.php b/lib/classes/JsonApi/Routes/Messages/InboxShow.php
index 4d9be460c8a..ec60b9fe9fd 100644
--- a/lib/classes/JsonApi/Routes/Messages/InboxShow.php
+++ b/lib/classes/JsonApi/Routes/Messages/InboxShow.php
@@ -15,7 +15,7 @@ class InboxShow extends BoxController
     public function __invoke(Request $request, Response $response, $args)
     {
         $filtering = $this->getQueryParameters()->getFilteringParameters();
-        $onlyUnread = (bool) $filtering['unread'];
+        $onlyUnread = !empty($filtering['unread']);
 
         return $this->getBoxResponse($request, $args, 'rec', $onlyUnread);
     }
diff --git a/lib/classes/JsonApi/settings.php b/lib/classes/JsonApi/settings.php
index dfb8185089c..10396b8b29b 100644
--- a/lib/classes/JsonApi/settings.php
+++ b/lib/classes/JsonApi/settings.php
@@ -11,8 +11,8 @@ return function (ContainerBuilder $containerBuilder) {
     // Global Settings Object
     $containerBuilder->addDefinitions([
         'studip-current-user' => function () {
-            if ($user = $GLOBALS['user']) {
-                return $user->getAuthenticatedUser();
+            if (isset($GLOBALS['user'])) {
+                return $GLOBALS['user']->getAuthenticatedUser();
             }
 
             return null;
diff --git a/lib/classes/SemClass.class.php b/lib/classes/SemClass.class.php
index 0fd486870df..cec05cc0ef0 100644
--- a/lib/classes/SemClass.class.php
+++ b/lib/classes/SemClass.class.php
@@ -520,7 +520,7 @@ class SemClass implements ArrayAccess
                return (bool) $this->data['is_group'];
         }
         //ansonsten
-        return $this->data[$offset];
+        return $this->data[$offset] ?? null;
     }
 
     /**
diff --git a/lib/classes/calendar/CalendarScheduleModel.php b/lib/classes/calendar/CalendarScheduleModel.php
index ce404b2335d..4b8a63af6b3 100644
--- a/lib/classes/calendar/CalendarScheduleModel.php
+++ b/lib/classes/calendar/CalendarScheduleModel.php
@@ -31,14 +31,14 @@ class CalendarScheduleModel
      */
     static function storeEntry($data)
     {
-        if ($data['id']) {     // update
+        if (!empty($data['id'])) {     // update
             $stmt = DBManager::get()->prepare("UPDATE schedule
                 SET start = ?, end = ?, day = ?, title = ?, content = ?, color = ?, user_id = ?
                 WHERE id = ?");
             $stmt->execute([$data['start'], $data['end'], $data['day'], $data['title'],
                 $data['content'], $data['color'], $data['user_id'], $data['id']]);
 
-            NotificationCenter::postNotification('ScheduleDidUpdate', $GLOBALS['user']->id, ['values' => $data]);
+            NotificationCenter::postNotification('ScheduleDidUpdate', $GLOBALS['user']->id ?? null, ['values' => $data]);
 
         } else {
             $stmt = DBManager::get()->prepare("INSERT INTO schedule
@@ -46,7 +46,7 @@ class CalendarScheduleModel
                 VALUES (?, ?, ?, ?, ?, ?, ?)");
             $stmt->execute([$data['start'], $data['end'], $data['day'], $data['title'],
                 $data['content'], $data['color'], $data['user_id']]);
-            NotificationCenter::postNotification('ScheduleDidCreate', $GLOBALS['user']->id, ['values' => $data]);
+            NotificationCenter::postNotification('ScheduleDidCreate', $GLOBALS['user']->id ?? null, ['values' => $data]);
         }
     }
 
diff --git a/lib/filesystem/StandardFile.php b/lib/filesystem/StandardFile.php
index 4f7c6164b15..e051871e8a4 100644
--- a/lib/filesystem/StandardFile.php
+++ b/lib/filesystem/StandardFile.php
@@ -36,8 +36,8 @@ class StandardFile implements FileType, ArrayAccess, StandardFileInterface
         $user_id || $user_id = $GLOBALS['user']->id;
 
         $filename   = $data['name'];
-        $mime_type  = $data['type'] ?: get_mime_type($data['name']);
-        $filesize   = $data['size'] ?: filesize($data['tmp_name']);
+        $mime_type  = $data['type'] ?? get_mime_type($data['name']);
+        $filesize   = $data['size'] ?? filesize($data['tmp_name']);
         $file_path  = $data['tmp_name'];
         $error_code = $data['error'] ?? '';
 
diff --git a/lib/messaging.inc.php b/lib/messaging.inc.php
index 2330bc64785..8f2b6ce61ec 100644
--- a/lib/messaging.inc.php
+++ b/lib/messaging.inc.php
@@ -381,7 +381,7 @@ class messaging
             : 'Stud.IP-System';
         foreach ($rec_id as $one) {
             $insert->execute([$tmp_message_id, $one, $one == $snd_user_id ? 1 : 0]);
-            if ($GLOBALS['MESSAGING_FORWARD_AS_EMAIL']) {
+            if (!empty($GLOBALS['MESSAGING_FORWARD_AS_EMAIL'])) {
                 // mail to original receiver
                 $mailstatus_original = $this->user_wants_email($one);
                 if ($mailstatus_original == 2 || ($mailstatus_original == 3 && $email_request == 1) || $force_email) {
diff --git a/lib/models/CourseEvent.class.php b/lib/models/CourseEvent.class.php
index 971eca38854..fa68b136a10 100644
--- a/lib/models/CourseEvent.class.php
+++ b/lib/models/CourseEvent.class.php
@@ -69,8 +69,8 @@ class CourseEvent extends CourseDate implements Event
             return null;
         };
         $config['additional_fields']['uid']['get'] = function ($date) {
-            return 'Stud.IP-SEM-' . $date->getId()
-                . '@' . $_SERVER['SERVER_NAME'];
+            $host = $_SERVER['SERVER_NAME'] ?? parse_url($GLOBALS['ABSOLUTE_URI_STUDIP'], PHP_URL_HOST);
+            return 'Stud.IP-SEM-' . $date->getId() . '@' . $host;
         };
         $config['additional_fields']['summary']['get'] = function ($date) {
             return $date->course->name;
diff --git a/lib/models/EventData.class.php b/lib/models/EventData.class.php
index 75e6f0c36ea..453272d30fd 100644
--- a/lib/models/EventData.class.php
+++ b/lib/models/EventData.class.php
@@ -113,7 +113,7 @@ class EventData extends SimpleORMap implements PrivacyObject
     protected function cbDefaultValues()
     {
         if (empty($this->content['uid'])) {
-            $this->content['uid'] = 'Stud.IP-' . $this->event_id . '@' . $_SERVER['SERVER_NAME'];
+            $this->content['uid'] = 'Stud.IP-' . $this->event_id . '@' . ($_SERVER['SERVER_NAME'] ?? parse_url($GLOBALS['ABSOLUTE_URI_STUDIP'],  PHP_URL_HOST));
         }
     }
 
diff --git a/lib/models/File.php b/lib/models/File.php
index 097d2a31b38..6cd0151e0a6 100644
--- a/lib/models/File.php
+++ b/lib/models/File.php
@@ -129,7 +129,7 @@ class File extends SimpleORMap
             $this->user_id = User::findCurrent()->id;
         }
         if (!$this->author_name) {
-            $user = $this->user_id === User::findCurrent()->id
+            $user = (User::findCurrent() && $this->user_id === User::findCurrent()->id)
                   ? User::findCurrent()
                   : $this->owner;
             $this->author_name = $user ? $user->getFullName('no_title') : "";
diff --git a/lib/models/SeminarCycleDate.class.php b/lib/models/SeminarCycleDate.class.php
index 36884f04b72..f3844268954 100644
--- a/lib/models/SeminarCycleDate.class.php
+++ b/lib/models/SeminarCycleDate.class.php
@@ -612,7 +612,7 @@ class SeminarCycleDate extends SimpleORMap
                 //check for calculatable holidays
                 if ($termin instanceof CourseDate) {
                     $holy_type = SemesterHoliday::isHoliday($start_time, false);
-                    if ($holy_type["col"] == 3) {
+                    if (!is_bool($holy_type) && $holy_type['col'] == 3) {
                         $termin = new CourseExDate();
                     }
                 }
diff --git a/lib/models/User.class.php b/lib/models/User.class.php
index 434a0487956..7f6a402f44f 100644
--- a/lib/models/User.class.php
+++ b/lib/models/User.class.php
@@ -263,7 +263,7 @@ class User extends AuthUserMd5 implements Range, PrivacyObject
      */
     public static function findCurrent()
     {
-        if (is_object($GLOBALS['user'])) {
+        if (isset($GLOBALS['user']) && is_object($GLOBALS['user'])) {
             return $GLOBALS['user']->getAuthenticatedUser();
         }
 
diff --git a/tests/_support/Helper/Jsonapi.php b/tests/_support/Helper/Jsonapi.php
index 81d112c36cd..8d98e6a55e9 100644
--- a/tests/_support/Helper/Jsonapi.php
+++ b/tests/_support/Helper/Jsonapi.php
@@ -29,8 +29,8 @@ class Jsonapi extends \Codeception\Module
     public function withPHPLib($credentials, $function)
     {
         // EVIL HACK
-        $oldPerm = $GLOBALS['perm'];
-        $oldUser = $GLOBALS['user'];
+        $oldPerm = $GLOBALS['perm'] ?? null;
+        $oldUser = $GLOBALS['user'] ?? null;
         $GLOBALS['perm'] = new \Seminar_Perm();
         $GLOBALS['user'] = new \Seminar_User(\User::find($credentials['id']));
 
diff --git a/tests/_support/_generated/JsonapiTesterActions.php b/tests/_support/_generated/JsonapiTesterActions.php
index 9faaeec96db..c191a3e0c39 100644
--- a/tests/_support/_generated/JsonapiTesterActions.php
+++ b/tests/_support/_generated/JsonapiTesterActions.php
@@ -1,4 +1,4 @@
-<?php  //[STAMP] bc9d12565d6304b308d375b50b9e8556
+<?php  //[STAMP] 7e4574f977226c21c1b7dd8a4f07ec4e
 namespace _generated;
 
 // This class was automatically generated by build task
diff --git a/tests/jsonapi/BlubberCommentsByThreadIndexTest.php b/tests/jsonapi/BlubberCommentsByThreadIndexTest.php
index 30005e583f4..a437fa0b766 100644
--- a/tests/jsonapi/BlubberCommentsByThreadIndexTest.php
+++ b/tests/jsonapi/BlubberCommentsByThreadIndexTest.php
@@ -32,7 +32,7 @@ class BlubberCommentsByThreadIndexTest extends \Codeception\Test\Unit
         $thread = $this->createPublicBlubberThreadForUser($credentials, 'Who knows Daskylos?');
 
         // Workaround old-style Stud.IP-API using $GLOBALS['user']
-        $oldUser = $GLOBALS['user'];
+        $oldUser = $GLOBALS['user'] ?? null;
         $GLOBALS['user'] = new \Seminar_User(\User::find($credentials['id']));
 
         $this->createBlubberComment($credentials, $thread, 'Autolykos knows him.');
diff --git a/tests/jsonapi/BlubberCommentsDeleteTest.php b/tests/jsonapi/BlubberCommentsDeleteTest.php
index 09cb84c22da..cbe4b7b07ab 100644
--- a/tests/jsonapi/BlubberCommentsDeleteTest.php
+++ b/tests/jsonapi/BlubberCommentsDeleteTest.php
@@ -32,7 +32,7 @@ class BlubberCommentsDeleteTest extends \Codeception\Test\Unit
         $thread = $this->createPublicBlubberThreadForUser($credentials2, 'Who knows Daskylos?');
 
         // Workaround old-style Stud.IP-API using $GLOBALS['user']
-        $oldUser = $GLOBALS['user'];
+        $oldUser = $GLOBALS['user'] ?? null;
         $GLOBALS['user'] = new \Seminar_User(\User::find($credentials1['id']));
 
         $num = \BlubberComment::countBySQL('1');
diff --git a/tests/jsonapi/BlubberCommentsShowTest.php b/tests/jsonapi/BlubberCommentsShowTest.php
index 832adb685d8..d041fae6b58 100644
--- a/tests/jsonapi/BlubberCommentsShowTest.php
+++ b/tests/jsonapi/BlubberCommentsShowTest.php
@@ -28,7 +28,7 @@ class BlubberCommentsShowTest extends \Codeception\Test\Unit
         $thread = $this->createPublicBlubberThreadForUser($credentials, 'Who knows Daskylos?');
 
         // Workaround old-style Stud.IP-API using $GLOBALS['user']
-        $oldUser = $GLOBALS['user'];
+        $oldUser = $GLOBALS['user'] ?? null;
         $GLOBALS['user'] = new \Seminar_User(\User::find($credentials['id']));
 
         $comment = $this->createBlubberComment($credentials, $thread, 'Autolykos knows him.');
diff --git a/tests/jsonapi/BlubberTestHelper.php b/tests/jsonapi/BlubberTestHelper.php
index cb43d783da9..e4241d4a133 100644
--- a/tests/jsonapi/BlubberTestHelper.php
+++ b/tests/jsonapi/BlubberTestHelper.php
@@ -84,7 +84,7 @@ trait BlubberTestHelper
     private function createBlubberComment(array $credentials, \BlubberThread $thread, $content)
     {
         // Workaround old-style Stud.IP-API using $GLOBALS['user']
-        $oldUser = $GLOBALS['user'];
+        $oldUser = $GLOBALS['user'] ?? null;
         $GLOBALS['user'] = new \Seminar_User(\User::find($credentials['id']));
 
         $blubber = \BlubberComment::create(
diff --git a/tests/jsonapi/ConsultationsBlockShowTest.php b/tests/jsonapi/ConsultationsBlockShowTest.php
index 62c7ed700d9..4c856e9d12c 100644
--- a/tests/jsonapi/ConsultationsBlockShowTest.php
+++ b/tests/jsonapi/ConsultationsBlockShowTest.php
@@ -25,7 +25,7 @@ class ConsultationsBlockShowTest extends Codeception\Test\Unit
 
         $resourceObject = $document->primaryResource();
         $this->assertTrue(is_string($resourceObject->id()));
-        $this->assertSame($block->id, $resourceObject->id());
+        $this->assertEquals($block->id, $resourceObject->id());
         $this->assertSame(Schema::TYPE, $resourceObject->type());
 
         $this->assertEquals($block->start, strtotime($resourceObject->attribute('start')));
diff --git a/tests/jsonapi/ConsultationsBookingShowTest.php b/tests/jsonapi/ConsultationsBookingShowTest.php
index 8788b77205e..7295c017089 100644
--- a/tests/jsonapi/ConsultationsBookingShowTest.php
+++ b/tests/jsonapi/ConsultationsBookingShowTest.php
@@ -31,7 +31,7 @@ class ConsultationsBookingShowTest extends Codeception\Test\Unit
 
         $resourceObject = $document->primaryResource();
         $this->assertTrue(is_string($resourceObject->id()));
-        $this->assertSame($booking->id, $resourceObject->id());
+        $this->assertEquals($booking->id, $resourceObject->id());
         $this->assertSame(Schema::TYPE, $resourceObject->type());
 
         $this->assertEquals(self::$BOOKING_DATA['reason'], $resourceObject->attribute('reason'));
diff --git a/tests/jsonapi/ConsultationsSlotShowTest.php b/tests/jsonapi/ConsultationsSlotShowTest.php
index be8f5b7e427..8219d48a0be 100644
--- a/tests/jsonapi/ConsultationsSlotShowTest.php
+++ b/tests/jsonapi/ConsultationsSlotShowTest.php
@@ -26,7 +26,7 @@ class ConsultationsSlotShowTest extends Codeception\Test\Unit
 
         $resourceObject = $document->primaryResource();
         $this->assertTrue(is_string($resourceObject->id()));
-        $this->assertSame($slot->id, $resourceObject->id());
+        $this->assertEquals($slot->id, $resourceObject->id());
         $this->assertSame(Schema::TYPE, $resourceObject->type());
 
         $this->assertEquals($slot->start_time, strtotime($resourceObject->attribute('start_time')));
diff --git a/tests/jsonapi/FilesTestHelper.php b/tests/jsonapi/FilesTestHelper.php
index 44fd99da366..3a7650e5934 100644
--- a/tests/jsonapi/FilesTestHelper.php
+++ b/tests/jsonapi/FilesTestHelper.php
@@ -14,7 +14,7 @@ trait FilesTestHelper
         $course = \Course::find($courseId);
         $this->assertNotNull($course);
 
-        $oldUser = $GLOBALS['user'];
+        $oldUser = $GLOBALS['user'] ?? null;
         $GLOBALS['user'] = new \Seminar_User($credentials['id']);
 
         $rootFolder = Folder::createTopFolder($course->id, 'course');
diff --git a/tests/jsonapi/MessagesOutboxTest.php b/tests/jsonapi/MessagesOutboxTest.php
index 21b59cd3d13..ef29f8976ce 100644
--- a/tests/jsonapi/MessagesOutboxTest.php
+++ b/tests/jsonapi/MessagesOutboxTest.php
@@ -58,7 +58,7 @@ class MessagesOutboxTest extends \Codeception\Test\Unit
     private function sendMessage(array $credentials)
     {
         // EVIL HACK
-        $oldUser = $GLOBALS['user'];
+        $oldUser = $GLOBALS['user'] ?? null;
         $GLOBALS['user'] = \User::find($credentials['id']);
 
         $message = \Message::send($credentials['id'], [$credentials['username']], 'empty subject', 'empty message');
diff --git a/tests/jsonapi/SeminarCycleDatesShowTest.php b/tests/jsonapi/SeminarCycleDatesShowTest.php
index 29535777295..46f8b9334d6 100644
--- a/tests/jsonapi/SeminarCycleDatesShowTest.php
+++ b/tests/jsonapi/SeminarCycleDatesShowTest.php
@@ -45,8 +45,8 @@ class SeminarCycleDatesShowTest extends \Codeception\Test\Unit
     private function createSeminarCycleDate($credentials, \Course $course)
     {
         // EVIL HACK
-        $oldUser = $GLOBALS['user'];
-        $oldAuth = $GLOBALS['auth'];
+        $oldUser = $GLOBALS['user'] ?? null;
+        $oldAuth = $GLOBALS['auth'] ?? null;
 
         $GLOBALS['user'] = new \Seminar_User(
             \User::find($credentials['id'])
diff --git a/tests/jsonapi/StructuralElementsShowTest.php b/tests/jsonapi/StructuralElementsShowTest.php
index 231a4495f4c..8cc168ab4b5 100644
--- a/tests/jsonapi/StructuralElementsShowTest.php
+++ b/tests/jsonapi/StructuralElementsShowTest.php
@@ -32,7 +32,7 @@ class StructuralElementsShowTest extends \Codeception\Test\Unit
         $this->assertTrue($response->isSuccessfulDocument([200]));
 
         $document = $response->document();
-        $this->assertSame($structuralElement->id, $document->primaryResource()->id());
+        $this->assertEquals($structuralElement->id, $document->primaryResource()->id());
         $this->assertFalse($document->hasAnyIncludedResources());
     }
 
@@ -45,7 +45,7 @@ class StructuralElementsShowTest extends \Codeception\Test\Unit
         $this->assertTrue($response->isSuccessfulDocument([200]));
 
         $document = $response->document();
-        $this->assertSame($structuralElement->id, $document->primaryResource()->id());
+        $this->assertEquals($structuralElement->id, $document->primaryResource()->id());
         $this->assertTrue($document->hasAnyIncludedResources());
 
         $includedResources = $document->includedResources();
diff --git a/tests/jsonapi/StudipPropertiesIndexTest.php b/tests/jsonapi/StudipPropertiesIndexTest.php
index 2f83cb4579f..bf44755d7f8 100644
--- a/tests/jsonapi/StudipPropertiesIndexTest.php
+++ b/tests/jsonapi/StudipPropertiesIndexTest.php
@@ -11,6 +11,10 @@ class StudipPropertiesIndexTest extends \Codeception\Test\Unit
 
     protected function _before()
     {
+        if (!isset($GLOBALS['SOFTWARE_VERSION'])) {
+            $GLOBALS['SOFTWARE_VERSION'] = '';
+        }
+
         \DBManager::getInstance()->setConnection('studip', $this->getModule('\\Helper\\StudipDb')->dbh);
     }
 
diff --git a/tests/jsonapi/UserEventsIcalTest.php b/tests/jsonapi/UserEventsIcalTest.php
index 3d0a78a31c1..81230d457c6 100644
--- a/tests/jsonapi/UserEventsIcalTest.php
+++ b/tests/jsonapi/UserEventsIcalTest.php
@@ -27,7 +27,7 @@ class UserEventsIcalTest extends \Codeception\Test\Unit
         $event = $calendar->getNewEvent();
         $event->setTitle('blypyp');
 
-        $oldUser = $GLOBALS['user'];
+        $oldUser = $GLOBALS['user'] ?? null;
         $GLOBALS['user'] = \User::find($credentials['id']);
 
         $calendar->storeEvent($event, [$credentials['id']]);
diff --git a/tests/jsonapi/WikiIndexTest.php b/tests/jsonapi/WikiIndexTest.php
index 1113672ef04..8fd8e96bf75 100644
--- a/tests/jsonapi/WikiIndexTest.php
+++ b/tests/jsonapi/WikiIndexTest.php
@@ -66,8 +66,8 @@ class WikiIndexTest extends \Codeception\Test\Unit
     private function createWikiPage($userId, $courseId, $keyword, $body)
     {
         // EVIL HACK
-        $oldPerm = $GLOBALS['perm'];
-        $oldUser = $GLOBALS['user'];
+        $oldPerm = $GLOBALS['perm'] ?? null;
+        $oldUser = $GLOBALS['user'] ?? null;
         $GLOBALS['perm'] = new \Seminar_Perm();
         $GLOBALS['user'] = \User::find($userId);
 
@@ -77,7 +77,7 @@ class WikiIndexTest extends \Codeception\Test\Unit
                 'user_id' => $userId,
                 'range_id' => $courseId,
                 'keyword' => $keyword,
-                'version' => $latest->version + 1,
+                'version' => $latest ? $latest->version + 1 : 1,
                 'body' => $body
             ]
         );
diff --git a/tests/jsonapi/_bootstrap.php b/tests/jsonapi/_bootstrap.php
index a6177dff77c..61325efc82c 100644
--- a/tests/jsonapi/_bootstrap.php
+++ b/tests/jsonapi/_bootstrap.php
@@ -2,7 +2,7 @@
 
 // Here you can initialize variables that will be available to your tests
 
-global $STUDIP_BASE_PATH, $ABSOLUTE_URI_STUDIP, $CACHING_ENABLE, $CACHING_FILECACHE_PATH, $SYMBOL_SHORT, $TMP_PATH, $UPLOAD_PATH;
+global $STUDIP_BASE_PATH, $ABSOLUTE_URI_STUDIP, $CACHING_ENABLE, $CACHING_FILECACHE_PATH, $SYMBOL_SHORT, $TMP_PATH, $UPLOAD_PATH, $DYNAMIC_CONTENT_PATH, $DYNAMIC_CONTENT_URL;
 
 // common set-up, usually done by lib/bootstraph.php and
 // config/config_local.inc.php when run on web server
@@ -11,6 +11,8 @@ if (!isset($STUDIP_BASE_PATH)) {
     $ABSOLUTE_PATH_STUDIP = $STUDIP_BASE_PATH.'/public/';
     $UPLOAD_PATH = $STUDIP_BASE_PATH.'/data/upload_doc';
     $TMP_PATH = $TMP_PATH ?: '/tmp';
+    $DYNAMIC_CONTENT_PATH = '';
+    $DYNAMIC_CONTENT_URL = '';
 }
 
 // set include path
-- 
GitLab