Compare commits

..

17 Commits

Author SHA1 Message Date
Johann Hoffmann d40040efd8 added new fkey to tbl_widget for system.tbl_berechtigung; check for permission status during load & in widget picker; if widget was already picked/configured but not permitted anymore -> show a generalized "missing permission" screen via fallback component during widget init; 2026-07-21 18:14:26 +02:00
Harald Bamberger c84146fcbd Merge branch 'bug-77989/StudVW_Datepicker_check_modeltype' 2026-07-17 10:36:23 +02:00
ma0068 35decf476c make fields deletable with keyboard: Konto Buchungsdatum, Prüfung Datum, Abschlussprüfung Datum und Sponsion, Mobilität von und bis 2026-07-17 09:12:02 +02:00
Harald Bamberger 6cfc4b0973 Merge branch 'master' into bug-77989/StudVW_Datepicker_check_modeltype 2026-07-16 16:01:25 +02:00
Harald Bamberger 6296b87ea5 Merge branch 'bug-77989/StudVW_Datepicker_check_modeltype' 2026-07-16 15:54:18 +02:00
Harald Bamberger 576a44838f datetime format bewerbung_abgeschickt_am 2026-07-16 15:53:32 +02:00
Harald Bamberger c00e7a182c Merge branch 'master' into bug-77989/StudVW_Datepicker_check_modeltype 2026-07-16 15:00:45 +02:00
ma0068 fd1b5daf9c enable deletion of zgv and zgv master date with null and empty string 2026-07-16 14:51:38 +02:00
Harald Bamberger c0b5f2f748 add permission to DetailHeader function for use in pv21 2026-07-16 12:58:00 +02:00
ma0068 b217681ee5 use model-type for interessenten anlegen, listNew 2026-07-14 15:23:06 +02:00
ma0068 7841a73fc0 prepare field bewerbung_abgeschicktamum for showing in frontend (datestamp in database) and add also model-type to datepicker 2026-07-14 15:05:54 +02:00
ma0068 2064008f9e add model-type to fields Betriebsmittel/ausgegebenam, Betriebsmittel/retouram, Funktionen/datumvon und Funktionen/datumbis 2026-07-14 14:31:13 +02:00
ma0068 19b9906c86 Aufnahmetermine: use model-type isodate for field anmeldedatum 2026-07-14 14:23:37 +02:00
ma0068 2c3913a763 Mobility: use model-type isodate for fields von and bis 2026-07-14 14:19:25 +02:00
ma0068 9111edf442 Dokumente: use model-type isodate for field nachgereicht_am 2026-07-14 14:06:59 +02:00
ma0068 b1c47da3c3 use model-type isodate for fields in StatusModal datum and bestaetigtam 2026-07-14 14:01:12 +02:00
ma0068 67eb238876 use model-type isodate for field Details Gebdatum 2026-07-14 13:37:19 +02:00
35 changed files with 263 additions and 289 deletions
@@ -1,50 +0,0 @@
<?php
/**
* Copyright (C) 2024 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');
class Permission extends FHCAPI_Controller
{
public function __construct()
{
parent::__construct([
'isBerechtigt' => self::PERM_LOGGED
]);
// Load the library SearchBarLib
$this->load->library('PermissionLib');
}
public function isBerechtigt()
{
$payload = json_decode($this->input->raw_input_stream, TRUE);
if( !isset($payload['berechtigung_kurzbz']) || empty($payload['berechtigung_kurzbz']) )
{
$this->terminateWithError('Missing Parameter "berechtigung_kurzbz"');
}
$berechtigung_kurzbz = $payload['berechtigung_kurzbz'];
$art = isset($payload['art']) ? $payload['art'] : null;
$oe_kurzbz = isset($payload['oe_kurzbz']) ? $payload['oe_kurzbz'] : null;
$kostenstelle_id = isset($payload['kostenstelle_id']) ? $payload['kostenstelle_id'] : null;
$payload['isBerechtigt'] = $this->permissionlib->isBerechtigt(
$berechtigung_kurzbz, $art, $oe_kurzbz, $kostenstelle_id
);
$this->terminateWithSuccess($payload);
}
}
@@ -259,7 +259,7 @@ class BetriebsmittelP extends FHCAPI_Controller
$kaution = $this->input->post('kaution');
if($kaution) $kaution = str_replace(',', '.', $kaution);
$ausgegebenam = $this->input->post('ausgegebenam');
$retouram = $this->input->post('retouram');
$retouram = $this->input->post('retouram') == "" ? null : $this->input->post('retouram');
// NOTE(chris): transform_kartennummer
if ($betriebsmitteltyp == 'Zutrittskarte' && $nummer)
@@ -101,6 +101,9 @@ class Widget extends FHCAPI_Controller
$tmpsetup = json_decode($widget->setup);
$tmpsetup->file = absoluteJsImportUrl($tmpsetup->file);
$widget->setup = $tmpsetup;
$widget->permitted = empty($widget->berechtigung_kurzbz)
|| $this->permissionlib->isBerechtigt($widget->berechtigung_kurzbz);
return $widget;
}, $widgets);
@@ -9,9 +9,9 @@ class Detailheader extends FHCAPI_Controller
public function __construct()
{
parent::__construct([
'getHeader' => ['vertrag/mitarbeiter:r'],
'getPersonAbteilung' => ['vertrag/mitarbeiter:r'],
'getLeitungOrg' => ['vertrag/mitarbeiter:r'],
'getHeader' => ['vertrag/mitarbeiter:r', 'basis/mitarbeiter:r'],
'getPersonAbteilung' => ['vertrag/mitarbeiter:r', 'basis/mitarbeiter:r'],
'getLeitungOrg' => ['vertrag/mitarbeiter:r', 'basis/mitarbeiter:r'],
]);
}
@@ -294,6 +294,10 @@ class Funktionen extends FHCAPI_Controller
{
$this->terminateWithValidationErrors($this->form_validation->error_array());
}
if($datum_von == '')
$datum_von = null;
if($datum_bis == '')
$datum_bis = null;
$result = $this->BenutzerfunktionModel->update(
[
@@ -371,6 +371,9 @@ class Abschlusspruefung extends FHCAPI_Controller
$this->terminateWithValidationErrors($this->form_validation->error_array());
}
$datum = $formData['datum'] == '' ? null : $formData['datum'];
$sponsion = $formData['sponsion'] == '' ? null : $formData['sponsion'];
$result = $this->AbschlusspruefungModel->update(
[
'abschlusspruefung_id' => $abschlusspruefung_id
@@ -382,8 +385,8 @@ class Abschlusspruefung extends FHCAPI_Controller
'vorsitz' => $vorsitz,
'pruefungsantritt_kurzbz' => $formData['pruefungsantritt_kurzbz'],
'abschlussbeurteilung_kurzbz' => $formData['abschlussbeurteilung_kurzbz'],
'datum' => $formData['datum'],
'sponsion' => $formData['sponsion'],
'datum' => $datum,
'sponsion' => $sponsion,
'pruefer1' => $pruefer1,
'pruefer2' => $pruefer2,
'pruefer3' => $pruefer3,
@@ -170,6 +170,8 @@ class Dokumente extends FHCAPI_Controller
$this->terminateWithValidationErrors($this->form_validation->error_array());
}
$nachgereicht_am = $this->input->post('nachgereicht_am') == '' ? null : $this->input->post('nachgereicht_am');
$uid = getAuthUID();
$result = $this->AkteModel->update(
@@ -180,7 +182,7 @@ class Dokumente extends FHCAPI_Controller
'dokument_kurzbz' => $this->input->post('dokument_kurzbz'),
'anmerkung_intern' => $this->input->post('anmerkung_intern'),
'titel_intern' => $this->input->post('titel_intern'),
'nachgereicht_am' => $this->input->post('nachgereicht_am'),
'nachgereicht_am' => $nachgereicht_am,
'updateamum' => date('c'),
'updatevon' => $uid,
]
@@ -429,9 +429,12 @@ class Konto extends FHCAPI_Controller
'updateamum' => date('c'),
'updatevon' => getAuthUID()
];
foreach ($allowed as $field)
if ($this->input->post($field) !== null)
$data[$field] = $this->input->post($field);
if($data['buchungsdatum'] == '')
$data['buchungsdatum'] = null;
$result = $this->KontoModel->update($id, $data);
@@ -237,8 +237,8 @@ class Mobility extends FHCAPI_Controller
}
$formData = $this->input->post('formData');
$von = $formData['von'] ?? null;
$bis = $formData['bis'] ?? null;
$von = ($formData['von'] ?? '') ?: null;
$bis = ($formData['bis'] ?? '') ?: null;
$nation_code = $formData['nation_code'] ?? null;
$mobilitaetsprogramm_code = $formData['mobilitaetsprogramm_code'] ?? null;
$herkunftsland_code = $formData['herkunftsland_code'] ?? null;
@@ -193,7 +193,7 @@ class Prestudent extends FHCAPI_Controller
}
elseif (
$val === ''
&& in_array($prop, ['zgvnation', 'zgvmanation', 'zgvdoktornation', 'berufstaetigkeit_code', 'ausbildungcode'])
&& in_array($prop, ['zgvnation', 'zgvmanation', 'zgvdoktornation', 'berufstaetigkeit_code', 'ausbildungcode', 'zgvdatum', 'zgvmadatum'])
)
{
$val = null;
@@ -448,8 +448,10 @@ class Pruefung extends FHCAPI_Controller
}
}
$datum = $this->input->post('datum') == '' ? null : $this->input->post('datum');
if(intval($pruefung_id) > 0)
{
$result = $this->PruefungModel->update(
[
'pruefung_id' => $pruefung_id
@@ -459,7 +461,7 @@ class Pruefung extends FHCAPI_Controller
'mitarbeiter_uid' => $this->input->post('mitarbeiter_uid'),
'note' => $this->input->post('note'),
'pruefungstyp_kurzbz' => $this->input->post('pruefungstyp_kurzbz'),
'datum' => $this->input->post('datum'),
'datum' => $datum,
'anmerkung' => $this->input->post('anmerkung'),
'updatevon' => $authUID,
'updateamum' => date('c'),
@@ -472,7 +474,7 @@ class Pruefung extends FHCAPI_Controller
'lehreinheit_id' => $this->input->post('lehreinheit_id'),
'student_uid' => $this->input->post('student_uid'),
'mitarbeiter_uid' => $this->input->post('mitarbeiter_uid'),
'datum' => $this->input->post('datum'),
'datum' => $datum,
'pruefungstyp_kurzbz' => $this->input->post('pruefungstyp_kurzbz'),
'note' => $this->input->post('note'),
'anmerkung' => $this->input->post('anmerkung'),
@@ -520,7 +522,7 @@ class Pruefung extends FHCAPI_Controller
'studiensemester_kurzbz' => $studiensemester_kurzbz,
'note' => $this->input->post('note'),
'uebernahmedatum' => date('c'),
'benotungsdatum' => $this->input->post('datum'),
'benotungsdatum' => $datum,
'insertamum' => date('c'),
'insertvon' => $authUID,
'punkte' => $this->input->post('punkte') ? str_replace(',', '.', $this->input->post('punkte')) : null
@@ -555,7 +557,7 @@ class Pruefung extends FHCAPI_Controller
], [
'note' => $this->input->post('note'),
'uebernahmedatum' => date('c'),
'benotungsdatum' => $this->input->post('datum'),
'benotungsdatum' => $datum,
'updateamum' => date('c'),
'updatevon' => $authUID,
'punkte' => $this->input->post('punkte') ? str_replace(',', '.', $this->input->post('punkte')) : null
@@ -296,6 +296,10 @@ class Student extends FHCAPI_Controller
$fotoval = ($val == '') ? null : str_replace('data:image/jpeg;base64,', '', $val);
$update_person[$prop] = $fotoval;
}
else if ($prop == 'gebdatum')
{
$update_person[$prop] = ($val == '') ? null : $val;
}
else
{
$update_person[$prop] = $val;
@@ -15,13 +15,6 @@ class GehaltsbestandteilLib
protected $CI;
/** @var Gehaltsbestandteil_model */
protected $GehaltsbestandteilModel;
/** @var Dienstverhaeltnis_model */
protected $DienstverhaeltnisModel;
/**
* @var PermissionLib
*/
protected $PermissionLib;
protected $loggedInUser;
@@ -31,25 +24,7 @@ class GehaltsbestandteilLib
$this->CI = get_instance();
$this->CI->load->model('vertragsbestandteil/Gehaltsbestandteil_model',
'GehaltsbestandteilModel');
$this->CI->load->model('vertragsbestandteil/Dienstverhaeltnis_model',
'DienstverhaeltnisModel');
$this->DienstverhaeltnisModel = $this->CI->DienstverhaeltnisModel;
$this->CI->load->library('extensions/FHC-Core-Personalverwaltung/abrechnung/GehaltsLib');
$this->GehaltsbestandteilModel = $this->CI->GehaltsbestandteilModel;
$this->CI->load->library('PermissionLib', null, 'PermissionLib');
$this->PermissionLib = $this->CI->PermissionLib;
}
public function fetchDienstverhaeltnis($dienstverhaeltnis_id)
{
$result = $this->DienstverhaeltnisModel->load($dienstverhaeltnis_id);
$dv = null;
if(null !== ($row = getData($result)))
{
$dv = new Dienstverhaeltnis();
$dv->hydrateByStdClass($row[0], true);
}
return $dv;
}
public function fetchGehaltsbestandteileValorisiertForChart($dienstverhaeltnis_id, $stichtag=null, $includefuture=false)
@@ -145,24 +120,12 @@ class GehaltsbestandteilLib
{
$this->setUIDtoPGSQL();
$dv = $this->fetchDienstverhaeltnis($gehaltsbestandteil->getDienstverhaeltnis_id());
if($dv && $this->PermissionLib->isberechtigt('basis/gehaelter', 'd', $dv->getOe_kurzbz()))
{
// delete Gehaltsabrechnung
$ret = $this->CI->gehaltslib->deleteAbrechnung($gehaltsbestandteil);
//
$ret = $this->GehaltsbestandteilModel->delete($gehaltsbestandteil->getGehaltsbestandteil_id());
if (isError($ret))
{
throw new Exception('error deleting gehaltsbestandteil');
}
} else {
throw new Exception('permission denied for deleting gehaltsbestandteil');
}
$ret = $this->GehaltsbestandteilModel->delete($gehaltsbestandteil->getGehaltsbestandteil_id());
if (isError($ret))
{
throw new Exception('error deleting gehaltsbestandteil');
}
}
public function endGehaltsbestandteil(Gehaltsbestandteil $gehaltsbestandteil, $enddate)
@@ -1,19 +0,0 @@
<?php
namespace vertragsbestandteil;
class NoPermissionException extends \Exception
{
// Redefine the exception so message isn't optional
public function __construct($message, $code = 0, ?\Throwable $previous = null) {
// make sure everything is assigned properly
parent::__construct($message, $code, $previous);
}
// custom string representation of object
public function __toString() {
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
}
}
@@ -13,12 +13,10 @@ require_once __DIR__ . '/VertragsbestandteilKarenz.php';
require_once __DIR__ . '/VertragsbestandteilLohnguide.php';
require_once __DIR__ . '/VertragsbestandteilFactory.php';
require_once __DIR__ . '/OverlapChecker.php';
require_once __DIR__ . '/NoPermissionException.php';
use vertragsbestandteil\Dienstverhaeltnis;
use vertragsbestandteil\Vertragsbestandteil;
use vertragsbestandteil\VertragsbestandteilFactory;
use vertragsbestandteil\NoPermissionException;
/**
* Description of VertragsbestandteilLib
@@ -37,8 +35,6 @@ class VertragsbestandteilLib
protected $DienstverhaeltnisModel;
/** @var Vertragsbestandteil_model */
protected $VertragsbestandteilModel;
/** @var GehaltsbestandeilModel */
protected $GehaltbestandteilModel;
/** @var Benutzer_model */
protected $BenutzerModel;
/**
@@ -48,11 +44,6 @@ class VertragsbestandteilLib
protected $loggedInUser;
/**
* @var PermissionLib
*/
protected $PermissionLib;
public function __construct()
{
$this->loggedInUser = getAuthUID();
@@ -63,17 +54,12 @@ class VertragsbestandteilLib
$this->CI->load->model('vertragsbestandteil/Vertragsbestandteil_model',
'VertragsbestandteilModel');
$this->VertragsbestandteilModel = $this->CI->VertragsbestandteilModel;
$this->CI->load->model('vertragsbestandteil/Gehaltsbestandteil_model',
'GehaltbestandteilModel');
$this->GehaltbestandteilModel = $this->CI->GehaltbestandteilModel;
$this->CI->load->model('person/benutzer_model',
'BenutzerModel');
$this->BenutzerModel = $this->CI->BenutzerModel;
$this->CI->load->library('vertragsbestandteil/GehaltsbestandteilLib',
null, 'GehaltsbestandteilLib');
$this->GehaltsbestandteilLib = $this->CI->GehaltsbestandteilLib;
$this->CI->load->library('PermissionLib', null, 'PermissionLib');
$this->PermissionLib = $this->CI->PermissionLib;
}
public function handleGUIData($guidata, $employeeUID, $userUID)
@@ -113,14 +99,9 @@ class VertragsbestandteilLib
$vbs = $this->VertragsbestandteilModel->getVertragsbestandteile(
$dienstverhaeltnis_id, $stichtag, $includefuture
);
$dv = $this->fetchDienstverhaeltnis($dienstverhaeltnis_id);
$gbs = array();
if($dv && $this->PermissionLib->isberechtigt('basis/gehaelter', 's', $dv->getOe_kurzbz()))
{
$gbs = $this->GehaltsbestandteilLib->fetchGehaltsbestandteile(
$dienstverhaeltnis_id, $stichtag, $includefuture, $withvalorisationhistory
);
}
$gbs = $this->GehaltsbestandteilLib->fetchGehaltsbestandteile(
$dienstverhaeltnis_id, $stichtag, $includefuture, $withvalorisationhistory
);
$gbsByVBid = array();
foreach( $gbs as $gb )
@@ -254,12 +235,8 @@ class VertragsbestandteilLib
throw new Exception("Transaction failed");
}
$this->CI->db->trans_commit();
} catch (NoPermissionException $e) {
log_message('debug', "Transaction rolled back. " . $e->getMessage());
$this->CI->db->trans_rollback();
// rethrow and let GUIHandler catch it to display error message
throw $e;
} catch (Exception $ex)
}
catch (Exception $ex)
{
log_message('debug', "Transaction rolled back. " . $ex->getMessage());
$this->CI->db->trans_rollback();
@@ -337,15 +314,6 @@ class VertragsbestandteilLib
private function deleteVertragsbestandteilHelper(Vertragsbestandteil $vertragsbestandteil)
{
$dv = $this->fetchDienstverhaeltnis($vertragsbestandteil->getDienstverhaeltnis_id());
$hasGehaltsPermission = $this->PermissionLib->isberechtigt('basis/gehaelter', 's', $dv->getOe_kurzbz());
$vbHasGehaltsbestandteile = $this->GehaltbestandteilModel->existsGehaltsbestandteil($vertragsbestandteil->getVertragsbestandteil_id());
if (!$hasGehaltsPermission && $vbHasGehaltsbestandteile)
{
throw new NoPermissionException('delete Gehaltsbestandteil permission denied');
}
$specialisedModel = VertragsbestandteilFactory::getVertragsbestandteilDBModel(
$vertragsbestandteil->getVertragsbestandteiltyp_kurzbz());
@@ -129,15 +129,6 @@ LEFT JOIN
array($dienstverhaeltnis_id),
$this->getEncryptedColumns());
}
public function existsGehaltsbestandteil($vertragsbestandteil_id)
{
$qry = "select count(*) from hr.tbl_gehaltsbestandteil where vertragsbestandteil_id=?";
$ret = $this->execQuery($qry,
array($vertragsbestandteil_id));
$d = getData($ret);
return $d !== null && $d > 0;
}
public function getGehaltsbestandteile($dienstverhaeltnis_id, $stichtag=null,
$includefuture=false, $withvalorisationhistory=true)
@@ -148,9 +148,6 @@
generateJSsInclude('vendor/npm-asset/primevue/autocomplete/autocomplete.min.js');
generateJSsInclude('vendor/npm-asset/primevue/overlaypanel/overlaypanel.min.js');
generateJSsInclude('vendor/npm-asset/primevue/datatable/datatable.min.js');
generateJSsInclude('vendor/npm-asset/primevue/fileupload/fileupload.min.js');
generateJSsInclude('vendor/npm-asset/primevue/tabview/tabview.min.js');
generateJSsInclude('vendor/npm-asset/primevue/tabpanel/tabpanel.min.js');
// TODO check ob notwendig
generateJSsInclude('vendor/npm-asset/primevue/toast/toast.min.js');
generateJSsInclude('vendor/npm-asset/primevue/toastservice/toastservice.min.js');
-27
View File
@@ -1,27 +0,0 @@
/**
* Copyright (C) 2025 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/>.
*/
export default {
isBerechtigt(berechtigung_kurzbz, art, oe_kurzbz, kostenstelle_id) {
return {
method: 'post',
url: '/api/frontend/v1/Permission/isBerechtigt',
params: { berechtigung_kurzbz, art, oe_kurzbz, kostenstelle_id }
};
},
};
+1 -2
View File
@@ -39,7 +39,6 @@ import studiengang from "./studiengang.js";
import menu from "./menu.js";
import dashboard from "./dashboard.js";
import authinfo from "./authinfo.js";
import permission from "./permission.js";
import vertraege from "./vertraege.js";
import studium from "./studium.js";
import language from "./language.js";
@@ -66,10 +65,10 @@ export default {
addons,
messages,
vorlagen,
addons,
studiengang,
menu,
authinfo,
permission,
vertraege,
studium,
language
-17
View File
@@ -1,17 +0,0 @@
export default {
isBerechtigt: function(berechtigung_kurzbz, art, oe_kurzbz, kostenstelle_id) {
var url = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router
+ '/api/frontend/v1/Permission/isBerechtigt';
var payload = {
"berechtigung_kurzbz": berechtigung_kurzbz,
"art": art,
"oe_kurzbz": oe_kurzbz,
"kostenstelle_id": kostenstelle_id
};
return axios.post(url, payload, {
headers: {
'Content-Type': 'application/json'
}
});
}
}
@@ -433,6 +433,7 @@ export default {
:label="$p.t('wawi/ausgegebenam')"
name="ausgegebenam"
v-model="formData.ausgegebenam"
model-type="yyyy-MM-dd"
auto-apply
:enable-time-picker="false"
text-input
@@ -449,6 +450,7 @@ export default {
:label="$p.t('wawi/retouram')"
name="retouram"
v-model="formData.retouram"
model-type="yyyy-MM-dd"
auto-apply
:enable-time-picker="false"
text-input
+13 -2
View File
@@ -1,5 +1,6 @@
import BsModal from "../Bootstrap/Modal.js";
import HeightTransition from "../Tranistion/HeightTransition.js";
import MissingPermissionWidget from "../DashboardWidget/MissingPermission.js";
import { enableDragDropTouch } from "../../../../vendor/drag-drop-touch-js/dragdroptouch/dist/drag-drop-touch.esm.min.js";
@@ -113,6 +114,12 @@ export default {
isPinned() {
return this.place?.pinned ? true : false;
},
permitted() {
// widgets without a linked permission (or before the template loaded)
// are considered permitted; the backend sets permitted === false only
// when the user is missing the widget's required permission
return this.widgetTemplate?.permitted !== false;
},
ready() {
return this.component && this.arguments !== null;
},
@@ -178,7 +185,11 @@ export default {
&& this.widgetTemplate.widget_id
&& this.widgetTemplate.arguments
) {
let component = (await import(this.widgetTemplate.setup.file)).default;
// render the "missing permission" screen instead of the actual
// widget when the user does not hold the widget's linked permission
let component = this.permitted
? (await import(this.widgetTemplate.setup.file)).default
: MissingPermissionWidget;
this.$options.components["widget" + this.widgetTemplate.widget_id] = component;
this.component = "widget" + this.widgetTemplate.widget_id;
this.arguments = { ...this.widgetTemplate.arguments, ...this.config };
@@ -280,7 +291,7 @@ export default {
</template>
<!-- widget link -->
<a
v-if="widgetTemplate.setup.cis4link"
v-if="widgetTemplate.setup.cis4link && permitted"
:href="getWidgetC4Link(widgetTemplate)"
class="col-auto ms-auto"
:aria-label="$p.t('dashboard/widget_link')"
@@ -12,6 +12,12 @@ export default {
data: () => ({
callbacks: {}
}),
computed: {
// filter widgets away the user has no permissions for
availableWidgets() {
return (this.widgets || []).filter(widget => widget.permitted !== false);
}
},
methods: {
getWidget() {
return new Promise((resolve,reject) => {
@@ -37,17 +43,17 @@ export default {
<bs-modal
ref="modal"
class="fade"
:dialog-class="{ 'modal-fullscreen-sm-down': 1, 'modal-xl': widgets && widgets.length > 0 }"
:dialog-class="{ 'modal-fullscreen-sm-down': 1, 'modal-xl': availableWidgets.length > 0 }"
@hiddenBsModal="close"
>
<template v-slot:title>{{ $p.t('dashboard/createWidget') }}</template>
<template v-slot:default>
<div v-if="widgets" class="row g-2">
<div v-if="!widgets.length">
<div v-if="!availableWidgets.length">
{{ $p.t('dashboard/noWidgetsAvailable') }}
</div>
<div
v-for="widget in widgets"
v-for="widget in availableWidgets"
:key="widget.widget_id"
class="widget-icon-container col-sm-6 col-md-4 col-lg-3 col-xl-2"
>
@@ -0,0 +1,21 @@
import AbstractWidget from './Abstract.js';
/**
* Fallback screen rendered in place of a widget when the current user is missing
* the permission (berechtigung_kurzbz) linked to that widget. Used for widgets
* that are already on a user's dashboard but whose required permission the user
* no longer holds.
*/
export default {
mixins: [
AbstractWidget
],
created() {
this.$emit('setConfig', false);
},
template: /*html*/`
<div class="dashboard-widget-missing-permission d-flex flex-column justify-content-center align-items-center text-center h-100 p-3 text-body-secondary">
<i class="fa-solid fa-lock fa-2x mb-2" aria-hidden="true"></i>
<p class="mb-0">{{ $p.t('dashboard/widget_missing_permission') }}</p>
</div>`
}
@@ -551,6 +551,7 @@ export default {
container-class="mb-3 col-3"
type="DatePicker"
v-model="formData.datum_von"
model-type="yyyy-MM-dd"
name="datum_von"
:label="$p.t('ui/from') + ' *'"
auto-apply
@@ -566,6 +567,7 @@ export default {
container-class="mb-3 col-3"
type="DatePicker"
v-model="formData.datum_bis"
model-type="yyyy-MM-dd"
name="datum_bis"
:label="$p.t('global/bis')"
auto-apply
@@ -470,6 +470,7 @@ export default {
:label="$p.t('admission', 'anmeldundRtAm')"
type="DatePicker"
v-model="formData.anmeldedatum"
model-type="yyyy-MM-dd"
auto-apply
:enable-time-picker="false"
text-input
@@ -293,6 +293,7 @@ export default {
:label="$p.t('person', 'geburtsdatum')"
type="DatePicker"
v-model="data.gebdatum"
model-type="yyyy-MM-dd"
name="gebdatum"
:clearable="false"
no-today
@@ -103,6 +103,7 @@ export default {
<form-input
type="DatePicker"
v-model="formData.nachgereicht_am"
model-type="yyyy-MM-dd"
name="nachgereicht_am"
:label="$p.t('dokumente/nachreichungAm')"
auto-apply
@@ -467,6 +467,7 @@ export default {
:label="$p.t('ui', 'von')"
type="DatePicker"
v-model="formData.von"
model-type="yyyy-MM-dd"
auto-apply
:enable-time-picker="false"
text-input
@@ -501,6 +502,7 @@ export default {
:label="$p.t('global', 'bis')"
type="DatePicker"
v-model="formData.bis"
model-type="yyyy-MM-dd"
auto-apply
:enable-time-picker="false"
text-input
@@ -276,6 +276,7 @@ export default{
container-class="mb-3"
type="DatePicker"
v-model="formData.datum"
model-type="yyyy-MM-dd"
name="datum"
:label="$p.t('global/datum')"
auto-apply
@@ -291,6 +292,7 @@ export default{
container-class="mb-3"
type="DatePicker"
v-model="formData.bestaetigtam"
model-type="yyyy-MM-dd"
name="bestaetigtam"
:label="$p.t('lehre/bestaetigt_am')"
auto-apply
@@ -306,13 +308,14 @@ export default{
container-class="mb-3"
type="DatePicker"
v-model="formData.bewerbung_abgeschicktamum"
model-type="yyyy-MM-dd HH:mm:ss"
name="bewerbung_abgeschicktamum"
:label="$p.t('lehre/bewerbung_abgeschickt_am')"
auto-apply
:enable-time-picker="false"
format="dd.MM.yyyy"
:enable-time-picker="true"
format="dd.MM.yyyy HH:mm:ss"
text-input
preview-format="dd.MM.yyyy"
preview-format="dd.MM.yyyy HH:mm:ss"
:teleport="true"
:disabled="bisLocked || !hasPrestudentstatusPermission"
>
@@ -285,6 +285,7 @@ export default {
uid="stv-list-new-gebdatum"
name="gebdatum"
v-model="formDataPerson['gebdatum']"
model-type="yyyy-MM-dd"
:disabled="!!person"
@update:model-value="loadSuggestions"
text-input
+1
View File
@@ -98,6 +98,7 @@ require_once('dbupdate_3.4/75888_reihungstest_mehrfachdurchfuehrung.php');
require_once('dbupdate_3.4/76150_perm_other_lv_plan.php');
require_once('dbupdate_3.4/68957_dashboard_bookmark_neue_Spalte_sort.php');
require_once('dbupdate_3.4/68530_Dashboard_Cleanup.php');
require_once('dbupdate_3.4/77757_widgets_berechtigungen.php');
// *** Pruefung und hinzufuegen der neuen Attribute und Tabellen
echo '<H2>Pruefe Tabellen und Attribute!</H2>';
@@ -1,41 +0,0 @@
<?php
/* Copyright (C) 2017 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Authors: Harald Bamberger <harald.bamberger@technikum-wien.at>,
*
* Beschreibung:
* Permissions f. DV erstellen und bearbeiten bzw. korrigieren, Gehaelter
*/
if (! defined('DB_NAME')) exit('No direct script access allowed');
// Add permission: basis/gehaelter
if($result = @$db->db_query("SELECT 1 FROM system.tbl_berechtigung WHERE berechtigung_kurzbz = 'basis/gehaelter';"))
{
if($db->db_num_rows($result) == 0)
{
$qry = "INSERT INTO system.tbl_berechtigung(berechtigung_kurzbz, beschreibung) VALUES('basis/gehaelter', 'Zugriff auf gehaelter');";
if(!$db->db_query($qry))
{
echo '<strong>system.tbl_berechtigung '.$db->db_last_error().'</strong><br>';
}
else
{
echo 'system.tbl_berechtigung: Added permission "basis/gehaelter"<br>';
}
}
}
@@ -0,0 +1,57 @@
<?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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Beschreibung:
* Dashboard Widgets: Verknüpfung einer (einzelnen) Berechtigung pro Widget.
* Neue Spalte dashboard.tbl_widget.berechtigung_kurzbz mit FK auf
* system.tbl_berechtigung. Ist die Spalte NULL, erfordert das Widget keine
* gesonderte Berechtigung. Benutzer denen die verknüpfte Berechtigung fehlt,
* bekommen das Widget nicht mehr zur Auswahl angezeigt bzw. sehen (falls bereits
* am Dashboard) einen "Fehlende Berechtigung"-Screen.
*/
if (! defined('DB_NAME')) exit('No direct script access allowed');
// Add column dashboard.tbl_widget.berechtigung_kurzbz (FK => system.tbl_berechtigung)
if ($result = @$db->db_query("
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'dashboard'
AND table_name = 'tbl_widget'
AND column_name = 'berechtigung_kurzbz';"))
{
if ($db->db_num_rows($result) == 0)
{
$qry = "
ALTER TABLE dashboard.tbl_widget
ADD COLUMN berechtigung_kurzbz VARCHAR(32) NULL;
ALTER TABLE dashboard.tbl_widget
ADD CONSTRAINT tbl_widget_berechtigung_fk
FOREIGN KEY (berechtigung_kurzbz)
REFERENCES system.tbl_berechtigung (berechtigung_kurzbz)
ON UPDATE CASCADE ON DELETE SET NULL;";
if (!$db->db_query($qry))
{
echo '<strong>dashboard.tbl_widget: '.$db->db_last_error().'</strong><br>';
}
else
{
echo 'dashboard.tbl_widget: Spalte berechtigung_kurzbz (FK system.tbl_berechtigung) hinzugefuegt<br>';
}
}
}
+100 -20
View File
@@ -27580,26 +27580,6 @@ array(
)
)
),
array(
'app' => 'personalverwaltung',
'category' => 'person',
'phrase' => 'weiterbildung',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Weiterbildung',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Training',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'personalverwaltung',
'category' => 'person',
@@ -32534,6 +32514,86 @@ array(
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'anwKontrolle',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Anwesenheitskontrolle',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Attendance check',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'anwKontrolleOeffnen',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Anwesenheitskontrolle öffnen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Open attendance check',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'anwKeinUnterricht',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Kein Unterricht in diesem Zeitraum',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'No lessons in this period',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
'phrase' => 'anwJetzt',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Jetzt',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Now',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'anwesenheiten',
'category' => 'global',
@@ -48701,6 +48761,26 @@ array(
)
)
),
array(
'app' => 'core',
'category' => 'dashboard',
'phrase' => 'widget_missing_permission',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Ihnen fehlt die erforderliche Berechtigung, um dieses Widget anzuzeigen.',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'You do not have the permission required to display this widget.',
'description' => '',
'insertvon' => 'system'
)
)
),
// CIS4 phrases from legacy code end
// FHC4 Phrases Abschlusspruefung
array(