aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRasmus Fuhse <fuhse@data-quest.de>2025-12-19 12:20:47 +0000
committerRasmus Fuhse <fuhse@data-quest.de>2025-12-19 12:20:47 +0000
commit680de640261a0b9005a6b3c084506d6abf51b433 (patch)
tree3527474ecb01e621b4bbbf338f29ce6888ae1380 /lib
parent47fd6fe31f93c06f816d4bb27e8fdb6c013af606 (diff)
Resolve "Widget Aktiver Prozesse"
Closes #5675 Merge request studip/studip!4299
Diffstat (limited to 'lib')
-rw-r--r--lib/classes/Processes/ProcessProvider.php13
-rw-r--r--lib/classes/Processes/Questionnaires.php86
-rw-r--r--lib/classes/Processes/TimedFolders.php42
-rw-r--r--lib/classes/RunningProcess.php37
-rw-r--r--lib/modules/RunningProcessesWidget.php26
-rw-r--r--lib/plugins/core/RunningProcessPlugin.php11
6 files changed, 215 insertions, 0 deletions
diff --git a/lib/classes/Processes/ProcessProvider.php b/lib/classes/Processes/ProcessProvider.php
new file mode 100644
index 0000000..fcce4bd
--- /dev/null
+++ b/lib/classes/Processes/ProcessProvider.php
@@ -0,0 +1,13 @@
+<?php
+namespace Studip\Processes;
+
+interface ProcessProvider
+{
+
+ /**
+ * Returns an array of RunningProcess objects for the given user.
+ *
+ * @return array : RunningProcess[]
+ */
+ public static function getProcesses(\User $user): array;
+}
diff --git a/lib/classes/Processes/Questionnaires.php b/lib/classes/Processes/Questionnaires.php
new file mode 100644
index 0000000..2354c95
--- /dev/null
+++ b/lib/classes/Processes/Questionnaires.php
@@ -0,0 +1,86 @@
+<?php
+
+namespace Studip\Processes;
+
+class Questionnaires implements ProcessProvider
+{
+ /**
+ * Retrieves all active questionnaires accessible to the given user.
+ *
+ * This method fetches questionnaires that:
+ * - Are currently active (within start and stop dates)
+ * - Are visible
+ * - Are assigned to courses, institutes, or status groups where the user is a member
+ * - Are either unanswered or still editable by the user
+ *
+ * For each qualifying questionnaire, it creates a RunningProcess object containing:
+ * - Context information (course/institute/status group)
+ * - Questionnaire details (title, URL)
+ * - Time constraints (start and end dates)
+ * - Response statistics (number of answers / total possible respondents)
+ *
+ * @return array : RunningProcess[]
+ */
+ public static function getProcesses(\User $user) : array
+ {
+ $statement = \DBManager::get()->prepare("
+ SELECT `questionnaires`.*
+ FROM `questionnaires`
+ INNER JOIN `questionnaire_assignments` USING (`questionnaire_id`)
+ LEFT JOIN `seminar_user` ON (`seminar_user`.`Seminar_id` = `questionnaire_assignments`.`range_id` AND `questionnaire_assignments`.`range_type` = 'course')
+ LEFT JOIN `user_inst` ON (`user_inst`.`Institut_id` = `questionnaire_assignments`.`range_id` AND `questionnaire_assignments`.`range_type` = 'institute')
+ LEFT JOIN `statusgruppe_user` ON (`statusgruppe_user`.`statusgruppe_id` = `questionnaire_assignments`.`range_id` AND `questionnaire_assignments`.`range_type` = 'statusgruppe')
+ LEFT JOIN `statusgruppen` ON (`statusgruppen`.`statusgruppe_id` = `questionnaire_assignments`.`range_id` AND `questionnaire_assignments`.`range_type` = 'statusgruppe')
+ LEFT JOIN `seminar_user` AS `teacher` ON (`teacher`.`Seminar_id` = `statusgruppen`.`range_id` AND `questionnaire_assignments`.`range_type` = 'statusgruppe' AND `teacher`.`status` IN ('tutor', 'dozent'))
+ WHERE `questionnaires`.`startdate` <= UNIX_TIMESTAMP()
+ AND `questionnaires`.`stopdate` >= UNIX_TIMESTAMP()
+ AND `questionnaires`.`visible` = 1
+ AND (`seminar_user`.`user_id` = :user_id OR `teacher`.`user_id` = :user_id OR `user_inst`.`user_id` = :user_id OR `statusgruppe_user`.`user_id` = :user_id)
+ GROUP BY `questionnaires`.`questionnaire_id`
+ ");
+ $statement->execute(['user_id' => $user->id]);
+ $questionnaires = $statement->fetchAll(\PDO::FETCH_ASSOC);
+ $result = [];
+
+ foreach ($questionnaires as $questionnaire_data) {
+ $questionnaire = \Questionnaire::buildExisting($questionnaire_data);
+ if ($questionnaire->isViewable() && (!$questionnaire->isAnswered() || $questionnaire->isEditable())) {
+ foreach ($questionnaire->assignments as $assignment) {
+ if ($questionnaire->isAnswerable() || $questionnaire->isEditable()) {
+
+ $answers = $questionnaire->countAnswers();
+ if ($assignment->range_type === 'course') {
+ $allPersons = \CourseMember::countBySQL("`Seminar_id` = ?", [$assignment->range_id]);
+ $range_id = $assignment->range_id;
+ } elseif($assignment->range_type === 'institute') {
+ $allPersons = \InstituteMember::countBySQL("`Institut_id` = ?", [$assignment->range_id]);
+ $range_id = $assignment->range_id;
+ } elseif($assignment->range_type === 'statusgruppe') {
+ $allPersons = \StatusgruppeUser::countBySQL("`statusgruppe_id` = ?", [$assignment->range_id]);
+ $statusgroup = \Statusgruppen::find($assignment->range_id);
+ if ($statusgroup) {
+ $range_id = $statusgroup->range_id;
+ }
+ }
+
+ $result[] = new \RunningProcess(
+ $range_id,
+ \Icon::create("vote"),
+ _('Fragebogen'),
+ $questionnaire->isEditable()
+ ? \URLHelper::getURL('dispatch.php/questionnaire/evaluate/'.$questionnaire->id)
+ : \URLHelper::getURL('dispatch.php/questionnaire/answer/'.$questionnaire->id),
+ $questionnaire->startdate,
+ $questionnaire->stopdate,
+ true,
+ $questionnaire->title,
+ $questionnaire->isEditable() ? $answers.'/'.$allPersons : '',
+ $questionnaire->isEditable() ? sprintf(_('Rücklaufquote: %s'), $answers.'/'.$allPersons) : ''
+ );
+ }
+ }
+ }
+ }
+ return $result;
+ }
+}
diff --git a/lib/classes/Processes/TimedFolders.php b/lib/classes/Processes/TimedFolders.php
new file mode 100644
index 0000000..1460183
--- /dev/null
+++ b/lib/classes/Processes/TimedFolders.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace Studip\Processes;
+
+class TimedFolders implements ProcessProvider
+{
+ /**
+ * Retrieves an array of timed folder processes that are visible, active, and linked to the given user.
+ * The method fetches folders of type "TimedFolder" for which the user has access,
+ * processes each folder to check its visibility and end time, and compiles them into a list
+ * of ongoing processes with relevant details such as folder name, start time, end time, and file information.
+ *
+ * @return array : RunningProcess[]
+ */
+ public static function getProcesses(\User $user) : array
+ {
+ $folders = \Folder::findBySQL("LEFT JOIN `seminar_user` ON (`seminar_user`.`Seminar_id` = `folders`.`range_id` AND `folders`.`range_type` = 'course')
+ LEFT JOIN `user_inst` ON (`user_inst`.`Institut_id` = `folders`.`range_id` AND `folders`.`range_type` = 'institute')
+ WHERE `folders`.`folder_type` = 'TimedFolder'
+ AND (`seminar_user`.`user_id` = :user_id OR `user_inst`.`user_id` = :user_id)
+ ", ['user_id' => $user->id]);
+ $result = [];
+ foreach ($folders as $folder) {
+ $folderType = $folder->getTypedFolder();
+ if ($folderType->isVisible($user->id) && ($folderType->end_time > 0)) {
+ $files = $folderType->getFiles();
+ $result[] = new \RunningProcess(
+ $folder->range_id,
+ $folderType->getIcon(),
+ _('Zeitgesteuerter Ordner'),
+ \URLHelper::getURL('dispatch.php/course/files/index/'.$folder->id, ['cid' => $folder->range_id]),
+ $folderType->start_time,
+ $folderType->end_time,
+ false,
+ $folder->name,
+ $folderType->isReadable($user->id) && (count($files) > 0) ? sprintf(ngettext('%d Datei', '%d Dateien', count($files)), count($files)) : ''
+ );
+ }
+ }
+ return $result;
+ }
+}
diff --git a/lib/classes/RunningProcess.php b/lib/classes/RunningProcess.php
new file mode 100644
index 0000000..ca71068
--- /dev/null
+++ b/lib/classes/RunningProcess.php
@@ -0,0 +1,37 @@
+<?php
+
+class RunningProcess
+{
+ public readonly string $id;
+ public function __construct(
+ public readonly string $context_id,
+ public readonly Icon $icon,
+ public readonly string $type,
+ public readonly string $url,
+ public readonly int $begin,
+ public readonly int $end,
+ public readonly bool $dialog = false,
+ public readonly string $title = '',
+ public readonly string $additionalShortInfo = '',
+ public readonly string $additionalInfoTitleTag = ''
+ ) {
+ $this->id = uniqid();
+ }
+
+ public function toArray()
+ {
+ return [
+ 'id' => $this->id,
+ 'context_id' => $this->context_id,
+ 'icon' => $this->icon->asImagePath(),
+ 'type' => $this->type,
+ 'url' => $this->url,
+ 'begin' => $this->begin,
+ 'end' => $this->end,
+ 'dialog' => $this->dialog,
+ 'title' => $this->title,
+ 'additionalShortInfo' => $this->additionalShortInfo,
+ 'additionalInfoTitleTag' => $this->additionalInfoTitleTag
+ ];
+ }
+}
diff --git a/lib/modules/RunningProcessesWidget.php b/lib/modules/RunningProcessesWidget.php
new file mode 100644
index 0000000..54a4bd4
--- /dev/null
+++ b/lib/modules/RunningProcessesWidget.php
@@ -0,0 +1,26 @@
+<?php
+
+class RunningProcessesWidget extends CorePlugin implements PortalPlugin
+{
+ public function getPluginName()
+ {
+ return _('Meine Prozesse');
+ }
+
+ public function getMetadata()
+ {
+ return [
+ 'description' => _('Dieses Widget zeigt offene Prozesse, wie unbearbeitete Fragebögen oder zeitgesteuerte Dateiordner, aus Ihren Veranstaltungen oder Einrichtungen an.')
+ ];
+ }
+
+ function getPortalTemplate()
+ {
+ $controller = app(\Trails\Dispatcher::class)->load_controller('running_processes');
+ $response = $controller->relayWithRedirect('running_processes/widget');
+ $template = $GLOBALS['template_factory']->open('shared/string');
+ $template->content = $response->body;
+
+ return $template;
+ }
+}
diff --git a/lib/plugins/core/RunningProcessPlugin.php b/lib/plugins/core/RunningProcessPlugin.php
new file mode 100644
index 0000000..e64e75c
--- /dev/null
+++ b/lib/plugins/core/RunningProcessPlugin.php
@@ -0,0 +1,11 @@
+<?php
+
+interface RunningProcessPlugin
+{
+ /**
+ * Returns an array of RunningProcess objects, that should be displayed in the running processes widget..
+ *
+ * @return array : [RunningProcess, RunningProcess, ...]
+ */
+ public function getRunningProcesses() : array;
+}