Merge branch 'master' into feature-61599/DocumentExportLib_erweitern

This commit is contained in:
Paolo
2026-04-27 13:03:56 +02:00
75 changed files with 9450 additions and 1284 deletions
@@ -0,0 +1,121 @@
<?php
/**
* Copyright (C) 2026 fhcomplete.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
if (! defined('BASEPATH')) exit('No direct script access allowed');
/**
* This controller operates between (interface) the JS (GUI) and the back-end
* Provides data to the ajax get calls about addresses
* This controller works with JSON calls on the HTTP GET or POST and the output is always JSON
*/
class Board extends FHCAPI_Controller
{
public function __construct()
{
parent::__construct([
'list' => 'dashboard/admin:r',
'create' => 'dashboard/admin:rw',
'update' => 'dashboard/admin:rw',
'delete' => 'dashboard/admin:rw'
]);
// Models
$this->load->model('dashboard/Dashboard_model', 'DashboardModel');
}
public function list()
{
$result = $this->DashboardModel->load();
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($result);
}
public function create()
{
$dashboard_kurzbz = $this->input->post('dashboard_kurzbz');
$result = $this->DashboardModel->insert([
'dashboard_kurzbz' => $dashboard_kurzbz
]);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
public function update()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('dashboard_id', 'Dashboard ID', 'required');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
$dashboard_id = $this->input->post('dashboard_id');
$dashboard_kurzbz = $this->input->post('dashboard_kurzbz');
$beschreibung = $this->input->post('beschreibung');
$result = $this->DashboardModel->update([
'dashboard_id' => $dashboard_id
], [
'dashboard_kurzbz' => $dashboard_kurzbz,
'beschreibung' => $beschreibung
]);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($result);
}
public function delete()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('dashboard_id', 'Dashboard ID', 'required');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
$dashboard_id = $this->input->post('dashboard_id');
//delete all presets
$this->load->model('dashboard/Dashboard_Preset_model', 'DashboardPresetModel');
$result = $this->DashboardPresetModel->delete([
'dashboard_id' => $dashboard_id
]);
$this->getDataOrTerminateWithError($result);
//delete all widgets
$this->load->model('dashboard/Dashboard_Widget_model', 'DashboardWidgetModel');
$result = $this->DashboardWidgetModel->delete([
'dashboard_id' => $dashboard_id
]);
$this->getDataOrTerminateWithError($result);
$result = $this->DashboardModel->delete($dashboard_id);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($result);
}
}
@@ -0,0 +1,200 @@
<?php
/**
* Copyright (C) 2026 fhcomplete.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
if (! defined('BASEPATH')) exit('No direct script access allowed');
/**
* This controller operates between (interface) the JS (GUI) and the back-end
* Provides data to the ajax get calls about addresses
* This controller works with JSON calls on the HTTP GET or POST and the output is always JSON
*/
class Preset extends FHCAPI_Controller
{
public function __construct()
{
parent::__construct([
'list' => 'dashboard/admin:r',
'getBatch' => 'dashboard/admin:r',
'addWidget' => 'dashboard/admin:rw',
'removeWidget' => 'dashboard/admin:rw'
]);
// Load language phrases
$this->loadPhrases([
'ui'
]);
// Libraries
$this->load->library('dashboard/DashboardLib');
// Models
$this->load->model('ressource/Funktion_model', 'FunktionModel');
}
public function list($dashboard_kurzbz)
{
$sql = "
WITH
dashboard_presets AS (
SELECT
*
FROM
dashboard.tbl_dashboard_preset dp
JOIN
dashboard.tbl_dashboard d ON d.dashboard_id = dp.dashboard_id
WHERE
d.dashboard_kurzbz = {$this->db->escape($dashboard_kurzbz)}
),
general AS (
SELECT
'general' AS funktion_kurzbz,
'Allgemein' AS beschreibung
)
(
SELECT
f.funktion_kurzbz,
f.beschreibung,
COUNT(p.preset_id) AS has_preset
FROM
general f
LEFT JOIN
dashboard_presets p ON p.funktion_kurzbz IS NULL
GROUP BY
f.funktion_kurzbz, f.beschreibung
)
UNION ALL
(
SELECT
f.funktion_kurzbz,
f.beschreibung,
COUNT(p.preset_id) AS has_preset
FROM
public.tbl_funktion f
LEFT JOIN
dashboard_presets p ON p.funktion_kurzbz = f.funktion_kurzbz
GROUP BY
f.funktion_kurzbz, f.beschreibung
ORDER BY
f.beschreibung ASC
)
";
$result = $this->FunktionModel->execReadOnlyQuery($sql);
$funktionen = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($funktionen);
}
public function getBatch()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('db', 'Dashboard', 'required');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
$db = $this->input->post('db');
$funktionen = $this->input->post('funktionen') ?: [];
$result = [];
foreach ($funktionen as $funktion) {
$conf = $this->dashboardlib->getPreset($db, $funktion);
if ($conf) {
$preset = json_decode($conf->preset, true);
if (!isset($preset[$funktion]) || !isset($preset[$funktion]['widgets']))
$result[$funktion] = [];
else
$result[$funktion] = $preset[$funktion]['widgets'];
} else {
$result[$funktion] = [];
}
}
return $this->terminateWithSuccess($result);
}
public function addWidget()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('dashboard', 'Dashboard', 'required');
$this->form_validation->set_rules('funktion_kurzbz', 'Funktion', 'required');
$this->form_validation->set_rules('widget[widget]', 'Widget', 'required');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
$dashboard_kurzbz = $this->input->post('dashboard');
$funktion_kurzbz = $this->input->post('funktion_kurzbz');
$widget = $this->input->post('widget');
if (!isset($widget['widgetid']))
$widget['widgetid'] = $this->dashboardlib->generateWidgetId($dashboard_kurzbz);
$preset = $this->dashboardlib->getPresetOrCreateEmptyPreset($dashboard_kurzbz, $funktion_kurzbz);
$preset_decoded = json_decode($preset->preset, true);
$this->dashboardlib->addWidgetsToWidgets($preset_decoded, $dashboard_kurzbz, $funktion_kurzbz, [$widget]);
$preset->preset = json_encode($preset_decoded);
$result = $this->dashboardlib->insertOrUpdatePreset($preset);
$this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($widget['widgetid']);
}
public function removeWidget()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('db', 'Dashboard', 'required');
$this->form_validation->set_rules('funktion_kurzbz', 'Funktion', 'required');
$this->form_validation->set_rules('widgetid', 'Widget', 'required');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
$dashboard_kurzbz = $this->input->post('db');
$funktion_kurzbz = $this->input->post('funktion_kurzbz');
$widgetid = $this->input->post('widgetid');
$preset = $this->dashboardlib->getPreset($dashboard_kurzbz, $funktion_kurzbz);
if (!$preset)
show_404();
$preset_decoded = json_decode($preset->preset, true);
if (!$this->dashboardlib->removeWidgetFromWidgets($preset_decoded, $funktion_kurzbz, $widgetid))
show_404();
$preset->preset = json_encode($preset_decoded);
$result = $this->dashboardlib->insertOrUpdatePreset($preset);
$this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess(array('msg' => $this->p->t('dashboard', 'success_savePreset')));
}
}
@@ -0,0 +1,159 @@
<?php
/**
* Copyright (C) 2026 fhcomplete.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
if (! defined('BASEPATH')) exit('No direct script access allowed');
/**
* This controller operates between (interface) the JS (GUI) and the back-end
* Provides data to the ajax get calls about the users dashboard
* This controller works with JSON calls on the HTTP GET or POST and the output is always JSON
*/
class User extends FHCAPI_Controller
{
public function __construct()
{
parent::__construct([
'get' => 'dashboard/benutzer:r',
'addWidget' => 'dashboard/benutzer:rw',
'removeWidget' => 'dashboard/benutzer:rw'
]);
// Libraries
$this->load->library('dashboard/DashboardLib');
// Models
$this->load->model('ressource/Funktion_model', 'FunktionModel');
}
public function get($dashboard_kurzbz)
{
$dashboard = $this->dashboardlib->getDashboardByKurzbz($dashboard_kurzbz);
if (!$dashboard)
show_404();
$uid = $this->authlib->getAuthObj()->username;
/*$mergedconfig = $this->dashboardlib->getMergedConfig($dashboard->dashboard_id, $uid);
$this->terminateWithSuccess([
'general' => call_user_func_array(
'array_merge_recursive',
$mergedconfig
)
]);*/
$defaultconfig = $this->dashboardlib->getDefaultConfig($dashboard->dashboard_id);
$userconfig = $this->dashboardlib->getUserConfig($dashboard->dashboard_id, $uid);
$defaultconfig_squashed = $defaultconfig ? call_user_func_array('array_replace_recursive', $defaultconfig) : [];
$userconfig_squashed = $userconfig ? call_user_func_array('array_replace_recursive', $userconfig) : [];
$mergedconfig = array_replace_recursive($defaultconfig_squashed, $userconfig_squashed);
$this->terminateWithSuccess([
DashboardLib::SECTION_IF_FUNKTION_KURZBZ_IS_NULL => $mergedconfig
]);
}
public function addWidget()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('dashboard', 'Dashboard', 'required');
$this->form_validation->set_rules('widget[widget]', 'Widget', 'required');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
$widget = $this->input->post('widget');
$dashboard_kurzbz = $this->input->post('dashboard');
$uid = $this->authlib->getAuthObj()->username;
if (!isset($widget['widgetid']))
$widget['widgetid'] = $this->dashboardlib->generateWidgetId($dashboard_kurzbz);
$override = $this->dashboardlib->getOverrideOrCreateEmptyOverride($dashboard_kurzbz, $uid);
$override_decoded = json_decode($override->override, true);
if (!isset($override_decoded['general']) || !is_array($override_decoded['general']))
$override_decoded['general'] = [];
if (!isset($override_decoded['general']['widgets']))
$override_decoded['general']['widgets'] = [];
$override_decoded['general']['widgets'][$widget['widgetid']] = $widget;
// NOTE(chris): remove doubles in other funktionen
foreach ($override_decoded as $funktion => $array) {
if ($funktion == 'general')
continue;
if (isset($array['widgets']) && isset($array['widgets'][$widget['widgetid']]))
unset($override_decoded[$funktion]['widgets'][$widget['widgetid']]);
}
$override->override = json_encode($override_decoded);
$result = $this->dashboardlib->insertOrUpdateOverride($override);
$this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($widget['widgetid']);
}
public function removeWidget()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('dashboard', 'Dashboard', 'required');
$this->form_validation->set_rules('widget', 'Widget', 'required');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
$widget_id = $this->input->post('widget');
$dashboard_kurzbz = $this->input->post('dashboard');
$uid = $this->authlib->getAuthObj()->username;
$override = $this->dashboardlib->getOverride($dashboard_kurzbz, $uid);
if (!$override)
show_404();
$override_decoded = json_decode($override->override, true);
foreach (array_keys($override_decoded) as $k) {
if (!isset($override_decoded[$k]["widgets"])) {
unset($override_decoded[$k]);
continue;
}
if (isset($override_decoded[$k]["widgets"][$widget_id])) {
unset($override_decoded[$k]["widgets"][$widget_id]);
}
if (!$override_decoded[$k]["widgets"]) {
unset($override_decoded[$k]);
}
}
$override->override = json_encode($override_decoded);
$result = $this->dashboardlib->insertOrUpdateOverride($override);
$this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess();
}
}
@@ -0,0 +1,137 @@
<?php
/**
* Copyright (C) 2026 fhcomplete.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
if (! defined('BASEPATH')) exit('No direct script access allowed');
/**
* This controller operates between (interface) the JS (GUI) and the back-end
* Provides data to the ajax get calls about the users dashboard
* This controller works with JSON calls on the HTTP GET or POST and the output is always JSON
*/
class Widget extends FHCAPI_Controller
{
public function __construct()
{
parent::__construct([
'get' => ['dashboard/benutzer:r', 'dashboard/admin:r'],
'list' => 'dashboard/admin:r',
'listAllowed' => ['dashboard/benutzer:rw', 'dashboard/admin:r'],
'setAllowed' => 'dashboard/admin:rw'
]);
// Libraries
$this->load->library('dashboard/DashboardLib');
// Models
$this->load->model('dashboard/Widget_model', 'WidgetModel');
}
public function get($id)
{
$result = $this->WidgetModel->load($id);
$widget = $this->getDataOrTerminateWithError($result);
if (!$widget)
return $this->terminateWithSuccess([
"widget_id" => 0,
"widget_kurzbz" => "notfound",
"arguments" => [
"className" => 'alert-danger',
"title" => 'Widget Not Found',
"msg" => 'The widget with the id ' . $id . ' could not be found'
],
"setup" => [
"name" => 'Widget Not Found',
"file" => absoluteJsImportUrl('public/js/components/DashboardWidget/Default.js'),
"width" => 1,
"height" => 1
]
]);
$widget = current($widget);
$widget->arguments = json_decode($widget->arguments);
$tmpsetup = json_decode($widget->setup);
$tmpsetup->file = absoluteJsImportUrl($tmpsetup->file);
$widget->setup = $tmpsetup;
$this->terminateWithSuccess($widget);
}
public function list($dashboard)
{
$result = $this->WidgetModel->getWithAllowedForDashboard($dashboard);
$widgets = $this->getDataOrTerminateWithError($result);
$widgets = array_map(function ($widget) {
$widget->arguments = json_decode($widget->arguments);
$tmpsetup = json_decode($widget->setup);
$tmpsetup->file = absoluteJsImportUrl($tmpsetup->file);
$widget->setup = $tmpsetup;
return $widget;
}, $widgets);
$this->terminateWithSuccess($widgets);
}
public function listAllowed($dashboard)
{
$result = $this->WidgetModel->getForDashboard($dashboard);
$widgets = $this->getDataOrTerminateWithError($result);
$widgets = array_map(function ($widget) {
$widget->arguments = json_decode($widget->arguments);
$tmpsetup = json_decode($widget->setup);
$tmpsetup->file = absoluteJsImportUrl($tmpsetup->file);
$widget->setup = $tmpsetup;
return $widget;
}, $widgets);
$this->terminateWithSuccess($widgets);
}
public function setAllowed()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('dashboard_id', 'Dashboard', 'required');
$this->form_validation->set_rules('widget_id', 'Widget', 'required');
$this->form_validation->set_rules('allowed', 'Allowed', 'is_bool');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
$data = [
'dashboard_id' => $this->input->post('dashboard_id'),
'widget_id' => $this->input->post('widget_id')
];
$this->load->model('dashboard/Dashboard_Widget_model', 'DashboardWidgetModel');
if ($this->input->post('allowed'))
$result = $this->DashboardWidgetModel->insert($data);
else
$result = $this->DashboardWidgetModel->delete($data);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
}
@@ -42,14 +42,22 @@ class Messages extends FHCAPI_Controller
]);
}
public function getMessages($id, $type_id, $size, $page)
public function getMessages($id, $type_id, $size=null, $page=null)
{
if($type_id != 'person_id'){
$id = $this->_getPersonId($id, $type_id);
}
$offset = $size * ($page - 1);
$limit = $size;
if(!(is_null($size) && is_null($page)))
{
$offset = $size * ($page - 1);
$limit = $size;
}
else
{
$offset = null;
$limit = null;
}
$result = $this->MessageModel->getMessagesForTable($id, $offset, $limit);
@@ -626,7 +626,7 @@ class Students extends FHCAPI_Controller
$this->addFilter($studiensemester_kurzbz);
$result = $this->PrestudentModel->loadWhere($where);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
@@ -851,40 +851,44 @@ class Students extends FHCAPI_Controller
$stdsemEsc = $studiensemester_kurzbz ? $this->PrestudentModel->escape($studiensemester_kurzbz) : 'NULL';
$this->load->config('stv');
$tags = $this->config->item('stv_prestudent_tags');
$whereTags = '';
if (is_array($tags) && !isEmptyArray($tags)) {
$tags = array_keys($tags);
if(defined('STV_TAGS_ENABLED') && STV_TAGS_ENABLED)
{
$tags = $this->config->item('stv_prestudent_tags');
foreach ($tags as $key => $tag) {
$tags[$key] = $this->db->escape($tag);
$whereTags = '';
if (is_array($tags) && !isEmptyArray($tags)) {
$tags = array_keys($tags);
foreach ($tags as $key => $tag) {
$tags[$key] = $this->db->escape($tag);
}
$whereTags = " AND nt.typ_kurzbz IN (" . implode(",", $tags) . ")";
}
$whereTags = " AND nt.typ_kurzbz IN (" . implode(",", $tags) . ")";
$subQueryTag = "
(
SELECT
tag.prestudent_id,
COALESCE(json_agg(tag ORDER BY tag.done), '[]'::json) AS tags
FROM (
SELECT DISTINCT ON (n.notiz_id)
n.notiz_id AS id,
nt.typ_kurzbz,
array_to_json(nt.bezeichnung_mehrsprachig)->>0 AS beschreibung,
n.text AS notiz,
nt.style,
n.erledigt AS done,
nz.prestudent_id
FROM public.tbl_notizzuordnung AS nz
JOIN public.tbl_notiz AS n ON nz.notiz_id = n.notiz_id
JOIN public.tbl_notiz_typ AS nt ON n.typ = nt.typ_kurzbz "
. $whereTags .
"
) AS tag
GROUP BY tag.prestudent_id
) AS tag_data_agg
";
}
$subQueryTag = "
(
SELECT
tag.prestudent_id,
COALESCE(json_agg(tag ORDER BY tag.done), '[]'::json) AS tags
FROM (
SELECT DISTINCT ON (n.notiz_id)
n.notiz_id AS id,
nt.typ_kurzbz,
array_to_json(nt.bezeichnung_mehrsprachig)->>0 AS beschreibung,
n.text AS notiz,
nt.style,
n.erledigt AS done,
nz.prestudent_id
FROM public.tbl_notizzuordnung AS nz
JOIN public.tbl_notiz AS n ON nz.notiz_id = n.notiz_id
JOIN public.tbl_notiz_typ AS nt ON n.typ = nt.typ_kurzbz "
. $whereTags .
"
) AS tag
GROUP BY tag.prestudent_id
) AS tag_data_agg
";
$this->PrestudentModel->addJoin('public.tbl_studiengang stg', 'studiengang_kz', 'LEFT');
$this->PrestudentModel->addJoin('public.tbl_person p', 'person_id');
@@ -907,11 +911,17 @@ class Students extends FHCAPI_Controller
AND ps.studiensemester_kurzbz=public.get_stdsem_prestudent(tbl_prestudent.prestudent_id, ' . $stdsemEsc . ')
AND ps.ausbildungssemester=public.get_absem_prestudent(tbl_prestudent.prestudent_id, ' . $stdsemEsc . ')', 'LEFT');
$this->PrestudentModel->addJoin($subQueryTag, 'tag_data_agg.prestudent_id = tbl_prestudent.prestudent_id', 'LEFT');
if(defined('STV_TAGS_ENABLED') && STV_TAGS_ENABLED)
{
$this->PrestudentModel->addJoin($subQueryTag, 'tag_data_agg.prestudent_id = tbl_prestudent.prestudent_id', 'LEFT');
}
$this->PrestudentModel->addSelect("b.uid");
$this->PrestudentModel->addSelect('tag_data_agg.tags');
if(defined('STV_TAGS_ENABLED') && STV_TAGS_ENABLED)
{
$this->PrestudentModel->addSelect('tag_data_agg.tags');
}
$this->PrestudentModel->addSelect('titelpre');
$this->PrestudentModel->addSelect('nachname');
$this->PrestudentModel->addSelect('vorname');