mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-07-18 23:42:17 +00:00
Merge branch 'feature-55354/Studierendenverwaltung_Karteireiter_Archiv' into merge_FHC4_55354_55991_55992_60874_60875_61229_61230_61231
This commit is contained in:
@@ -6,4 +6,4 @@ $config['use_vuejs_dev_version'] = false;
|
||||
// use bundled javascript
|
||||
$config['use_bundled_javascript'] = false;
|
||||
// systemerror_mailto use in FHC-Alert Plugin - if empty Link will not be rendered
|
||||
$config['systemerror_mailto'] = '';
|
||||
$config['systemerror_mailto'] = '';
|
||||
|
||||
@@ -43,7 +43,8 @@ class Documents extends FHCAPI_Controller
|
||||
parent::__construct([
|
||||
'permissionAlternativeFormat' => self::PERM_LOGGED,
|
||||
'archive' => ['admin:rw', 'assistenz:rw'],
|
||||
'archiveSigned' => ['admin:rw', 'assistenz:rw']
|
||||
'archiveSigned' => ['admin:rw', 'assistenz:rw'],
|
||||
'download' => ['admin:rw', 'assistenz:rw']
|
||||
]);
|
||||
|
||||
// Load Phrases
|
||||
@@ -66,7 +67,7 @@ class Documents extends FHCAPI_Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Download a not signed document.
|
||||
* Archive a not signed document.
|
||||
*
|
||||
* @param string $xml (optional)
|
||||
* @param string $xsl (optional)
|
||||
@@ -79,7 +80,7 @@ class Documents extends FHCAPI_Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Download a signed document.
|
||||
* Archive a signed document.
|
||||
*
|
||||
* @param string $xml (optional)
|
||||
* @param string $xsl (optional)
|
||||
@@ -91,6 +92,42 @@ class Documents extends FHCAPI_Controller
|
||||
return $this->_archive($xml, $xsl, getAuthUID());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function download($xml, $xsl, $sign_user = null)
|
||||
{
|
||||
$akteExportData = $this->_getAkteExportData($xml, $xsl, $sign_user);
|
||||
|
||||
$akteData = $akteData['akteData'];
|
||||
$exportData = $akteData['exportData'];
|
||||
|
||||
/**
|
||||
* [
|
||||
'vorlage' => $vorlage,
|
||||
'xml_data' => $data,
|
||||
'oe_kurzbz' => $xsl_oe_kurzbz,
|
||||
'version' => $version,
|
||||
'outputformat' => $outputformat,
|
||||
'sign_user' => $sign_user
|
||||
]
|
||||
*/
|
||||
|
||||
// Output
|
||||
$result = $this->documentexportlib->showContent(
|
||||
$akteData['akteData']['inhalt'],
|
||||
$exportData['vorlage'],
|
||||
$exportData['xml_data'],
|
||||
$exportData['oe_kurzbz'],
|
||||
$exportData['version'],
|
||||
$exportData['outputformat'],
|
||||
$exportData['sign_user']
|
||||
);
|
||||
|
||||
$this->terminateWithSuccess(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for archive() and archiveSigned()
|
||||
*
|
||||
@@ -100,16 +137,36 @@ class Documents extends FHCAPI_Controller
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function _archive($xml, $xsl, $sign_user = null)
|
||||
private function _archive($xml, $xsl, $sign_user = null)
|
||||
{
|
||||
$akteData = $this->_getAkteExportData($xml, $xsl, $sign_user);
|
||||
|
||||
$this->load->model('crm/Akte_model', 'AkteModel');
|
||||
$result = $this->AkteModel->insert($akteData['akteData']);
|
||||
$this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $xml
|
||||
* @param string $xsl
|
||||
* @param string $sign_user (optional)
|
||||
*
|
||||
* @return array with Akte data and export data
|
||||
*/
|
||||
private function _getAkteExportData($xml, $xsl, $sign_user = null)
|
||||
{
|
||||
if (!$xml || !$xsl) {
|
||||
$this->load->library('form_validation');
|
||||
if (!$xml) {
|
||||
$xml = $this->input->post_get('xml');
|
||||
$this->addMeta('xml', $xml);
|
||||
$this->form_validation->set_rules('xml', 'xml', 'required');
|
||||
}
|
||||
if (!$xsl) {
|
||||
$xsl = $this->input->post_get('xsl');
|
||||
$this->addMeta('xsl', $xsl);
|
||||
$this->form_validation->set_rules('xsl', 'xsl', 'required');
|
||||
}
|
||||
|
||||
@@ -151,6 +208,7 @@ class Documents extends FHCAPI_Controller
|
||||
$this->load->model('system/Vorlage_model', 'VorlageModel');
|
||||
|
||||
$result = $this->VorlageModel->load($xsl);
|
||||
$this->addMeta("ress", $result);
|
||||
$vorlage = current($this->getDataOrTerminateWithError($result));
|
||||
if (!$vorlage)
|
||||
show_404();
|
||||
@@ -171,6 +229,7 @@ class Documents extends FHCAPI_Controller
|
||||
$studiengang_kz = null;
|
||||
if ($akteData['uid']) {
|
||||
$this->load->model('crm/Student_model', 'StudentModel');
|
||||
$this->StudentModel->addSelect('tbl_student.*, UPPER(typ || kurzbz) AS kuerzel');
|
||||
$this->StudentModel->addJoin('public.tbl_studiengang', 'studiengang_kz', 'LEFT');
|
||||
$result = $this->StudentModel->load([$akteData['uid']]);
|
||||
$student = current($this->getDataOrTerminateWithError($result));
|
||||
@@ -318,6 +377,7 @@ class Documents extends FHCAPI_Controller
|
||||
|
||||
$result = $this->VorlagestudiengangModel->getCurrent($xsl, $xsl_oe_kurzbz, $version);
|
||||
$access_rights = current($this->getDataOrTerminateWithError($result));
|
||||
// TODO: was bedeutet wenn keine berechtigung?
|
||||
if (!$access_rights || !$access_rights->berechtigung)
|
||||
return show_404();
|
||||
|
||||
@@ -413,10 +473,17 @@ class Documents extends FHCAPI_Controller
|
||||
$akteData['titel'] .= '.pdf';
|
||||
$akteData['inhalt'] = base64_encode($content);
|
||||
|
||||
$this->load->model('crm/Akte_model', 'AkteModel');
|
||||
$result = $this->AkteModel->insert($akteData);
|
||||
$this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess(true);
|
||||
return [
|
||||
'akteData' => $akteData,
|
||||
'exportData' =>
|
||||
[
|
||||
'vorlage' => $vorlage,
|
||||
'xml_data' => $data,
|
||||
'oe_kurzbz' => $xsl_oe_kurzbz,
|
||||
'version' => $version,
|
||||
'outputformat' => $outputformat,
|
||||
'sign_user' => $sign_user
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
<?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');
|
||||
|
||||
/**
|
||||
* Controller for downloading Akte
|
||||
*/
|
||||
class Akte extends Auth_Controller
|
||||
{
|
||||
/**
|
||||
* Calls the parent's constructor and prepares libraries and phrases
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'download' => ['admin:w', 'assistenz:w'],
|
||||
]);
|
||||
|
||||
// Load models
|
||||
$this->load->model('crm/Akte_model', 'AkteModel');
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
|
||||
/**
|
||||
*
|
||||
* Downloads an Akte
|
||||
*/
|
||||
public function download()
|
||||
{
|
||||
$akte_id = $this->input->get('akte_id');
|
||||
|
||||
if (!is_numeric($akte_id)) $this->terminateWithError('akte Id missing');
|
||||
|
||||
$result = $this->AkteModel->load($akte_id);
|
||||
|
||||
if (!hasData($result)) $this->terminateWithError('Akte not found');
|
||||
|
||||
$data = getData($result)[0];
|
||||
|
||||
if (isset($data->inhalt) && $data->inhalt != '')
|
||||
{
|
||||
header('Content-Description: File Transfer');
|
||||
header('Content-Type: '. $data->mimetype);
|
||||
header('Expires: 0');
|
||||
header('Cache-Control: must-revalidate');
|
||||
header('Pragma: public');
|
||||
header('Content-Disposition: attachment; filename="'.$data->titel.'"');
|
||||
echo base64_decode($data->inhalt);
|
||||
die();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
<?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');
|
||||
|
||||
use CI3_Events as Events;
|
||||
|
||||
/**
|
||||
* This controller operates between (interface) the JS (GUI) and the back-end
|
||||
* Provides data to the ajax get calls about archive documents
|
||||
* Listens to ajax post calls to change the archive documents
|
||||
* This controller works with JSON calls on the HTTP GET or POST and the output is always JSON
|
||||
*/
|
||||
class Archiv extends FHCAPI_Controller
|
||||
{
|
||||
/**
|
||||
* Calls the parent's constructor and prepares libraries and phrases
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'get' => ['admin:r', 'assistenz:r'],
|
||||
'getArchivVorlagen' => ['admin:r', 'assistenz:r'],
|
||||
'archive' => ['admin:w', 'assistenz:w'],
|
||||
'download' => ['admin:w', 'assistenz:w'],
|
||||
'update' => ['admin:w'],
|
||||
'delete' => ['admin:w', 'assistenz:w']
|
||||
]);
|
||||
|
||||
// Load models
|
||||
$this->load->model('crm/Akte_model', 'AkteModel');
|
||||
$this->load->model('system/Vorlage_model', 'VorlageModel');
|
||||
|
||||
// Load language phrases
|
||||
$this->loadPhrases([
|
||||
'archiv'
|
||||
]);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
|
||||
/**
|
||||
* Get archive documents for a person
|
||||
|
||||
* @return void
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
$person_id = $this->input->post('person_id');
|
||||
|
||||
$this->load->library('form_validation');
|
||||
|
||||
if (!$person_id || !is_array($person_id))
|
||||
{
|
||||
$this->form_validation->set_rules('person_id', 'Person ID', 'required');
|
||||
|
||||
if (!$this->form_validation->run())
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
}
|
||||
|
||||
$result = $this->AkteModel->getArchiv($person_id);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Vorlagen for archiving documents
|
||||
* @return void
|
||||
*/
|
||||
public function getArchivVorlagen()
|
||||
{
|
||||
$result = $this->VorlageModel->getArchivVorlagen();
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param
|
||||
* @return object success or error
|
||||
*/
|
||||
public function download()
|
||||
{
|
||||
$akte_id = $this->input->get('akte_id');
|
||||
|
||||
if (!is_numeric($akte_id)) $this->terminateWithError('akte Id missing');
|
||||
|
||||
$result = $this->AkteModel->load($akte_id);
|
||||
|
||||
|
||||
if (!hasData($result)) $this->terminateWithError('Akte not found');
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$data = getData($result)[0];
|
||||
//$this->addMeta("daa", $data->inhalt);
|
||||
|
||||
$fileObj = new stdClass();
|
||||
if (isset($data->inhalt) && $data->inhalt != '')
|
||||
{
|
||||
// Define handle to output stream
|
||||
$tmpFilePointer = fopen("php://output", 'w');
|
||||
$meta_data = stream_get_meta_data($tmpFilePointer);
|
||||
$filename = $meta_data["uri"];
|
||||
fwrite($tmpFilePointer, $data->inhalt);
|
||||
|
||||
header('Content-Description: File Transfer');
|
||||
header('Content-Type: '. $data->mimetype);
|
||||
header('Expires: 0');
|
||||
header('Cache-Control: must-revalidate');
|
||||
header('Pragma: public');
|
||||
//header('Content-Length: ' . filesize($fileObj->file));
|
||||
//header("Content-type: $data->mimetype");
|
||||
header('Content-Disposition: attachment; filename="'.$data->titel.'"');
|
||||
readfile($filename);
|
||||
//echo base64_decode($data->inhalt);
|
||||
die();
|
||||
//~ $fileObj->file = $data->inhalt;
|
||||
//~ $fileObj->name = $data->titel;
|
||||
//~ $fileObj->mimetype = $data->mimetype;
|
||||
//~ $fileObj->disposition = 'attachment';
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->load->library('AkteLib');
|
||||
|
||||
$result = $this->aktelib->get($akte_id);
|
||||
}
|
||||
|
||||
/* $fileObj->filename
|
||||
* $fileObj->file
|
||||
* $fileObj->name
|
||||
* $fileObj->mimetype
|
||||
* $fileObj->disposition*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Updating an Akte
|
||||
* @return void
|
||||
*/
|
||||
public function update()
|
||||
{
|
||||
$this->load->library('form_validation');
|
||||
|
||||
$this->form_validation->set_rules('akte_id', 'Akte Id', 'required');
|
||||
$this->form_validation->set_rules('signiert', 'Signiert', 'is_bool');
|
||||
$this->form_validation->set_rules('stud_selfservice', 'Self-Service', 'is_bool');
|
||||
|
||||
//Events::trigger('konto_update_validation', $this->form_validation);
|
||||
|
||||
if (!$this->form_validation->run())
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
|
||||
$id = $this->input->post('akte_id');
|
||||
|
||||
// get the akte
|
||||
$result = $this->AkteModel->load($id);
|
||||
|
||||
if (!hasData($result)) $this->terminateWithError("Akte not found!");
|
||||
|
||||
$akte = getData($result)[0];
|
||||
|
||||
$allowed = [
|
||||
'signiert',
|
||||
'stud_selfservice'
|
||||
];
|
||||
|
||||
$data = [
|
||||
'updateamum' => date('c'),
|
||||
'updatevon' => getAuthUID()
|
||||
];
|
||||
|
||||
// if Akte has Inhalt directly in Akte table
|
||||
if (isset($_FILES['datei']['tmp_name']))
|
||||
{
|
||||
$this->addMeta('read', "read");
|
||||
// update inhalt directly
|
||||
|
||||
// get tmp file
|
||||
$filename = $_FILES['datei']['tmp_name'];
|
||||
// open it
|
||||
$fp = fopen($filename,'r');
|
||||
// read it
|
||||
$content = fread($fp, filesize($filename));
|
||||
fclose($fp);
|
||||
// encode it
|
||||
$data['inhalt'] = base64_encode($content);
|
||||
$this->addMeta('content', base64_encode($content));
|
||||
}
|
||||
|
||||
|
||||
foreach ($allowed as $field)
|
||||
if ($this->input->post($field) !== null)
|
||||
$data[$field] = $this->input->post($field);
|
||||
|
||||
$this->addMeta("data", $data);
|
||||
|
||||
$result = $this->AkteModel->update($id, $data);
|
||||
|
||||
$this->getDataOrTerminateWithError($result);
|
||||
|
||||
$result = null;
|
||||
|
||||
$this->terminateWithSuccess($result);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete archived Akte
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
$this->load->library('form_validation');
|
||||
|
||||
$this->form_validation->set_rules('akte_id', 'Akte ID', 'required');
|
||||
$this->form_validation->set_rules('studiengang_kz', 'Studiengang', 'has_permissions_for_stg[admin:rw,assistenz:rw]');
|
||||
|
||||
if (!$this->form_validation->run())
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
|
||||
$akte_id = $this->input->post('akte_id');
|
||||
|
||||
$result = $this->AkteModel->load($akte_id);
|
||||
|
||||
if (!hasData($result))
|
||||
{
|
||||
$this->terminateWithError($this->p->t('archiv', 'error_missing', [
|
||||
'akte_id' => $akte_id
|
||||
]));
|
||||
}
|
||||
|
||||
$result = getData($result)[0];
|
||||
|
||||
if ($result->dokument_kurzbz == 'Ausbvert'
|
||||
&& isset($result->akzeptiertamum)
|
||||
&& !isEmptyString($result->akzeptiertamum)
|
||||
&& !has_permissions_for_stg($this->input->post('studiengang_kz'), 'admin:rw')
|
||||
)
|
||||
{
|
||||
$this->terminateWithError($this->p->t('archiv', 'nur_admins_loschen_ausbildungsvertraege', [
|
||||
'akte_id' => $akte_id
|
||||
]));
|
||||
}
|
||||
|
||||
$result = $this->AkteModel->delete($akte_id);
|
||||
if (isError($result)) $this->terminateWithError(getError($result));
|
||||
|
||||
$this->terminateWithSuccess();
|
||||
}
|
||||
}
|
||||
@@ -128,6 +128,14 @@ class Config extends FHCAPI_Controller
|
||||
'component' => './Stv/Studentenverwaltung/Details/Mobility.js'
|
||||
];
|
||||
|
||||
$result['archive'] = [
|
||||
'title' => $this->p->t('stv', 'tab_archive'),
|
||||
'component' => './Stv/Studentenverwaltung/Details/Archiv.js',
|
||||
'config' => [
|
||||
'showEdit' => $this->permissionlib->isBerechtigt('admin')
|
||||
]
|
||||
];
|
||||
|
||||
Events::trigger('stv_conf_student', function & () use (&$result) {
|
||||
return $result;
|
||||
});
|
||||
@@ -167,6 +175,13 @@ class Config extends FHCAPI_Controller
|
||||
'component' => './Stv/Studentenverwaltung/Details/Abschlusspruefung.js',
|
||||
'config' => $config['finalexam']
|
||||
];
|
||||
$result['archive'] = [
|
||||
'title' => $this->p->t('stv', 'tab_archive'),
|
||||
'component' => './Stv/Studentenverwaltung/Details/Archiv.js',
|
||||
'config' => [
|
||||
'showEdit' => $this->permissionlib->isBerechtigt('admin')
|
||||
]
|
||||
];
|
||||
|
||||
Events::trigger('stv_conf_students', function & () use (&$result) {
|
||||
return $result;
|
||||
|
||||
@@ -195,9 +195,9 @@ class Akte_model extends DB_Model
|
||||
}
|
||||
|
||||
/**
|
||||
* Liefert die Archivdokumente einer Person
|
||||
* Liefert die Archivdokumente einer Person/mehrerer Personen
|
||||
*
|
||||
* @param integer $person_id
|
||||
* @param integer/array $person_id
|
||||
* @param boolean|null $signiert Wenn true werden nur Dokumente geliefert die digital signiert wurden.
|
||||
* @param boolean|null $stud_selfservice Wenn true werden nur Dokumente geliefert die Studierende selbst herunterladen duerfen.
|
||||
*
|
||||
@@ -237,10 +237,14 @@ class Akte_model extends DB_Model
|
||||
if ($stud_selfservice !== null)
|
||||
$this->db->where('stud_selfservice', (boolean)$stud_selfservice);
|
||||
|
||||
if (is_array($person_id))
|
||||
$this->db->where_in('person_id', $person_id);
|
||||
else
|
||||
$this->db->where('person_id', $person_id);
|
||||
|
||||
$this->addOrder('erstelltam', 'DESC');
|
||||
|
||||
return $this->loadWhere([
|
||||
'person_id' => $person_id,
|
||||
'archiv' => true
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ class Vorlage_model extends DB_Model
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns mume types
|
||||
* Returns mime types
|
||||
*/
|
||||
public function getMimeTypes()
|
||||
{
|
||||
@@ -21,4 +21,14 @@ class Vorlage_model extends DB_Model
|
||||
|
||||
return $this->execQuery($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all Vorlagen for archive
|
||||
*/
|
||||
public function getArchivVorlagen()
|
||||
{
|
||||
$query ="SELECT * FROM public.tbl_vorlage WHERE archivierbar=true ORDER BY bezeichnung";
|
||||
|
||||
return $this->execQuery($query);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import exam from './stv/exam.js';
|
||||
import abschlusspruefung from './stv/abschlusspruefung.js';
|
||||
import grades from './stv/grades.js';
|
||||
import mobility from './stv/mobility.js';
|
||||
import archiv from './stv/archiv.js';
|
||||
|
||||
export default {
|
||||
verband,
|
||||
@@ -24,6 +25,7 @@ export default {
|
||||
abschlusspruefung,
|
||||
grades,
|
||||
mobility,
|
||||
archiv,
|
||||
configStudent() {
|
||||
return this.$fhcApi.get('api/frontend/v1/stv/config/student');
|
||||
},
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
export default {
|
||||
tabulatorConfig(config, self) {
|
||||
config.ajaxURL = 'api/frontend/v1/stv/archiv/get';
|
||||
config.ajaxParams = () => {
|
||||
const params = {
|
||||
person_id: self.modelValue.person_id || self.modelValue.map(e => e.person_id)
|
||||
};
|
||||
return params;
|
||||
};
|
||||
config.ajaxRequestFunc = (url, config, params) => this.$fhcApi.post(url, params, config);
|
||||
config.ajaxResponse = (url, params, response) => response.data;
|
||||
|
||||
return config;
|
||||
},
|
||||
getArchivVorlagen() {
|
||||
return this.$fhcApi.post('api/frontend/v1/stv/archiv/getArchivVorlagen');
|
||||
},
|
||||
archive(data) {
|
||||
return this.$fhcApi.post(
|
||||
'api/frontend/v1/documents/archive',
|
||||
data
|
||||
);
|
||||
},
|
||||
archiveSigned(data) {
|
||||
return this.$fhcApi.post(
|
||||
'api/frontend/v1/documents/archiveSigned',
|
||||
data
|
||||
);
|
||||
},
|
||||
update(data) {
|
||||
return this.$fhcApi.post('api/frontend/v1/stv/archiv/update', data);
|
||||
},
|
||||
delete({akte_id, studiengang_kz}) {
|
||||
return this.$fhcApi.post('api/frontend/v1/stv/archiv/delete', {akte_id, studiengang_kz});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,276 @@
|
||||
import {CoreFilterCmpt} from "../../../filter/Filter.js";
|
||||
import FormInput from "../../../Form/Input.js";
|
||||
import AkteEdit from "./Archiv/Edit.js";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CoreFilterCmpt,
|
||||
FormInput,
|
||||
AkteEdit
|
||||
},
|
||||
inject: {
|
||||
defaultSemester: {
|
||||
from: 'defaultSemester'
|
||||
}
|
||||
},
|
||||
props: {
|
||||
modelValue: Object,
|
||||
config: {
|
||||
type: Object,
|
||||
default: {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
selectedVorlage: {},
|
||||
vorlagenArchiv: [],
|
||||
vorlageXmlXslMappings: {
|
||||
'zeugnis.rdf.php': [
|
||||
'Zeugnis',
|
||||
'ZeugnisEng'
|
||||
],
|
||||
'abschlusspruefung.rdf.php': [
|
||||
'PrProtokollBakk',
|
||||
'PrProtBakkEng',
|
||||
'PrProtBA',
|
||||
'PrProtBAEng',
|
||||
'PrProtokollDipl',
|
||||
'PrProtDiplEng',
|
||||
'PrProtMA',
|
||||
'PrProtMAEng',
|
||||
'Bescheid',
|
||||
'BescheidEng',
|
||||
'Bakkurkunde',
|
||||
'BakkurkundeEng',
|
||||
'Diplomurkunde',
|
||||
'DiplomurkundeEng',
|
||||
],
|
||||
'diplomasupplement.xml.php': [
|
||||
'DiplSupplement',
|
||||
'SZeugnis'
|
||||
],
|
||||
'studienblatt.xml.php': [
|
||||
'Studienblatt',
|
||||
'StudienblattEng'
|
||||
],
|
||||
'ausbildungsvertrag.xml.php': [
|
||||
'Ausbildungsver',
|
||||
'AusbVerEng'
|
||||
],
|
||||
'abschlussdokument_lehrgaenge.xml.php': [
|
||||
'AbschlussdokumentLehrgaenge'
|
||||
]
|
||||
}
|
||||
//studiengang_kz: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
//~ personIds() {
|
||||
//~ if (this.modelValue.person_id)
|
||||
//~ return [this.modelValue.person_id];
|
||||
//~ return this.modelValue.map(e => e.person_id);
|
||||
//~ },
|
||||
tabulatorColumns() {
|
||||
const columns = [
|
||||
{title: "Akte Id", field: "akte_id", visible: false},
|
||||
{title: this.$p.t('stv', 'archiv_title'), field: "titel"},
|
||||
{title: this.$p.t('stv', 'archiv_description'), field: "bezeichnung"},
|
||||
{title: this.$p.t('stv', 'archiv_creation_date'), field: "erstelltam"},
|
||||
{
|
||||
title: this.$p.t('stv', 'archiv_signiert'),
|
||||
field: "signiert",
|
||||
formatter:"tickCross",
|
||||
hozAlign:"center",
|
||||
formatterParams: {
|
||||
tickElement: '<i class="fa fa-check text-success"></i>',
|
||||
crossElement: '<i class="fa fa-xmark text-danger"></i>'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Selfservice",
|
||||
field: "stud_selfservice",
|
||||
formatter:"tickCross",
|
||||
hozAlign:"center",
|
||||
formatterParams: {
|
||||
tickElement: '<i class="fa fa-check text-success"></i>',
|
||||
crossElement: '<i class="fa fa-xmark text-danger"></i>'
|
||||
},
|
||||
},
|
||||
{title: this.$p.t('stv', 'archiv_accepted_on_at'), field: "akzeptiertamum"},
|
||||
{
|
||||
title: this.$p.t('stv', 'archiv_gedruckt'),
|
||||
field: "gedruckt",
|
||||
visible: false,
|
||||
formatter:"tickCross",
|
||||
hozAlign:"center",
|
||||
formatterParams: {
|
||||
tickElement: '<i class="fa fa-check text-success"></i>',
|
||||
crossElement: '<i class="fa fa-xmark text-danger"></i>'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Aktionen', field: 'actions',
|
||||
formatter: (cell, formatterParams, onRendered) => {
|
||||
let container = document.createElement('div');
|
||||
container.className = "d-flex gap-2";
|
||||
|
||||
if (this.config.showEdit)
|
||||
{
|
||||
let editButton = document.createElement('button');
|
||||
editButton.className = 'btn btn-outline-secondary';
|
||||
editButton.innerHTML = '<i class="fa fa-edit"></i>';
|
||||
editButton.addEventListener('click', () =>
|
||||
this.$refs.edit.open(cell.getData())
|
||||
);
|
||||
container.append(editButton);
|
||||
}
|
||||
|
||||
let deleteButton = document.createElement('button');
|
||||
deleteButton.className = 'btn btn-outline-secondary';
|
||||
deleteButton.innerHTML = '<i class="fa fa-trash"></i>';
|
||||
deleteButton.addEventListener('click', evt => {
|
||||
evt.stopPropagation();
|
||||
this.$fhcAlert
|
||||
.confirmDelete()
|
||||
.then(result => result ? {akte_id: cell.getData().akte_id, studiengang_kz: this.modelValue.studiengang_kz} : Promise.reject({handled:true}))
|
||||
.then(this.$fhcApi.factory.stv.archiv.delete)
|
||||
.then(() => {
|
||||
//cell.getRow().delete();
|
||||
this.reload();
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
});
|
||||
container.append(deleteButton);
|
||||
|
||||
return container;
|
||||
},
|
||||
minWidth: 150, // Ensures Action-buttons will be always fully displayed
|
||||
maxWidth: 150,
|
||||
frozen: true
|
||||
}
|
||||
];
|
||||
return Object.values(columns);
|
||||
},
|
||||
tabulatorOptions() {
|
||||
return this.$fhcApi.factory.stv.archiv.tabulatorConfig({
|
||||
layout:"fitDataTable",
|
||||
columns: this.tabulatorColumns,
|
||||
//selectable: true,
|
||||
//selectableRangeMode: 'click',
|
||||
index: 'akte_id',
|
||||
persistenceID: 'stv-details-archiv'
|
||||
}, this);
|
||||
},
|
||||
tabulatorEvents() {
|
||||
const events = [
|
||||
{
|
||||
event: "rowDblClick",
|
||||
handler: (e, row) => {
|
||||
this.actionDownload(row.getData().akte_id);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
return events;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue() {
|
||||
this.$refs.table.reloadTable();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
reload() {
|
||||
this.$refs.table.reloadTable();
|
||||
},
|
||||
updateData(data) {
|
||||
if (!data)
|
||||
return this.reload();
|
||||
this.$refs.table.tabulator.updateOrAddData(data);
|
||||
},
|
||||
actionArchive() {
|
||||
let archiveDataArr = Array.isArray(this.modelValue) ? this.modelValue : [this.modelValue];
|
||||
|
||||
for (let archiveData of archiveDataArr)
|
||||
{
|
||||
this.loading = true;
|
||||
let archiveFunction =
|
||||
this.selectedVorlage.signierbar
|
||||
? this.$fhcApi.factory.stv.archiv.archiveSigned
|
||||
: this.$fhcApi.factory.stv.archiv.archive;
|
||||
|
||||
archiveFunction({
|
||||
xml: this.getXmlByXsl(this.selectedVorlage.vorlage_kurzbz),
|
||||
xsl: this.selectedVorlage.vorlage_kurzbz,
|
||||
ss: this.defaultSemester,
|
||||
uid: archiveData.uid,
|
||||
prestudent_id: archiveData.prestudent_id
|
||||
})
|
||||
.then(result => result.data)
|
||||
.then(() => {
|
||||
this.reload();
|
||||
this.loading = false;
|
||||
})
|
||||
.then(() => this.$p.t('ui/gespeichert'))
|
||||
.then(this.$fhcAlert.alertSuccess)
|
||||
.catch(error => {
|
||||
this.$fhcAlert.handleSystemError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
actionDownload(akte_id) {
|
||||
window.open(
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root
|
||||
+ FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/api/frontend/v1/stv/akte/download?akte_id=' + encodeURIComponent(akte_id),
|
||||
'_blank'
|
||||
);
|
||||
},
|
||||
getXmlByXsl(xsl) {
|
||||
for (let xml in this.vorlageXmlXslMappings) {
|
||||
let xslArr = this.vorlageXmlXslMappings[xml];
|
||||
|
||||
if (xslArr.includes(xsl)) return xml;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$fhcApi
|
||||
.factory.stv.archiv.getArchivVorlagen()
|
||||
.then(result => {this.vorlagenArchiv = result.data; this.selectedVorlage = result.data.filter(o => o.vorlage_kurzbz == 'Zeugnis')[0];})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
|
||||
},
|
||||
template: `
|
||||
<div class="stv-details-konto h-100 d-flex flex-column">
|
||||
<core-filter-cmpt
|
||||
ref="table"
|
||||
table-only
|
||||
:side-menu="false"
|
||||
:tabulator-options="tabulatorOptions"
|
||||
:tabulator-events="tabulatorEvents"
|
||||
reload
|
||||
>
|
||||
<template #actions>
|
||||
<div class="input-group w-auto">
|
||||
<select class="form-select" v-model="selectedVorlage">
|
||||
<option v-for="vorlage in vorlagenArchiv" :key="vorlage.vorlage_kurzbz" :value="vorlage">
|
||||
{{ vorlage.bezeichnung }}
|
||||
</option>
|
||||
</select>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
@click="actionArchive()"
|
||||
:disabled="loading"
|
||||
>
|
||||
<i v-if="loading" class="fa fa-spinner fa-spin"></i>
|
||||
{{ $p.t('stv/archiv_dokument_archivieren') }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</core-filter-cmpt>
|
||||
<akte-edit ref="edit" :config="config" @saved="updateData"></akte-edit>
|
||||
</div>`
|
||||
};
|
||||
@@ -0,0 +1,118 @@
|
||||
import BsModal from "../../../../Bootstrap/Modal.js";
|
||||
import CoreForm from "../../../../Form/Form.js";
|
||||
import FormValidation from "../../../../Form/Validation.js";
|
||||
import FormInput from "../../../../Form/Input.js";
|
||||
import FormUploadDms from '../../../../Form/Upload/Dms.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BsModal,
|
||||
CoreForm,
|
||||
FormValidation,
|
||||
FormInput,
|
||||
FormUploadDms
|
||||
},
|
||||
inject: {
|
||||
lists: {
|
||||
from: 'lists'
|
||||
}
|
||||
},
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
default: {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
//file: [],
|
||||
data: {
|
||||
datei: []
|
||||
}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
save() {
|
||||
this.$refs.form.clearValidation();
|
||||
this.loading = true;
|
||||
|
||||
//~ const formData = new FormData();
|
||||
//~ formData.append('data', JSON.stringify(this.data));
|
||||
//Object.entries(this.data.anhang).forEach(([k, v]) => formData.append(k, v));
|
||||
|
||||
this.$refs.form
|
||||
.factory.stv.archiv.update(this.data)
|
||||
.then(result => {
|
||||
this.$emit('saved', result.data);
|
||||
this.loading = false;
|
||||
this.$refs.modal.hide();
|
||||
this.$fhcAlert.alertSuccess(this.$p.t('ui/gespeichert'));
|
||||
})
|
||||
.catch(error => {
|
||||
this.$fhcAlert.handleSystemError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
open(data) {
|
||||
this.data.datei = [];
|
||||
this.data = {...this.data, ...data};
|
||||
this.$refs.modal.show();
|
||||
},
|
||||
preventCloseOnLoading(ev) {
|
||||
if (this.loading)
|
||||
ev.returnValue = false;
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<core-form ref="form" class="stv-details-archiv-edit" @submit.prevent="save">
|
||||
<bs-modal ref="modal" @hide-bs-modal="preventCloseOnLoading">
|
||||
<form-validation></form-validation>
|
||||
<fieldset :disabled="loading">
|
||||
<div class="mb-3">
|
||||
{{ data.titel }} ({{ data.bezeichnung }})
|
||||
</div>
|
||||
<form-input
|
||||
v-model="data.akte_id"
|
||||
name="akte_id"
|
||||
:label="$p.t('stv/archiv_akte_id')"
|
||||
disabled
|
||||
>
|
||||
</form-input>
|
||||
<div class="position-relative">
|
||||
<label for="text" class="form-label col-sm-2">{{ $p.t('stv/archiv_new_file') }}</label>
|
||||
<!--Upload Component-->
|
||||
<FormUploadDms ref="upload" id="inhalt" v-model="data.datei"></FormUploadDms>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<form-input
|
||||
container-class="form-check"
|
||||
type="checkbox"
|
||||
name="signiert"
|
||||
:label="$p.t('stv/archiv_signiert')"
|
||||
v-model="data.signiert"
|
||||
>
|
||||
</form-input>
|
||||
<form-input
|
||||
container-class="form-check"
|
||||
type="checkbox"
|
||||
name="stud_selfservice"
|
||||
:label="'Selfservice'"
|
||||
v-model="data.stud_selfservice"
|
||||
>
|
||||
</div>
|
||||
</form-input>
|
||||
</fieldset>
|
||||
|
||||
<template #title>
|
||||
{{ $p.t('stv/archiv_title_edit', data) }}
|
||||
</template>
|
||||
<template #footer>
|
||||
<button type="submit" class="btn btn-primary" :disabled="loading">
|
||||
<i v-if="loading" class="fa fa-spinner fa-spin"></i>
|
||||
{{ $p.t('ui/speichern') }}
|
||||
</button>
|
||||
</template>
|
||||
</bs-modal>
|
||||
</core-form>`
|
||||
};
|
||||
@@ -40692,6 +40692,266 @@ array(
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'archiv_dokument_archivieren',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Dokument archivieren',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Archive document',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'tab_archive',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Archiv',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Archive',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'archiv_title',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Titel',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Title',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'archiv_description',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Bezeichnung',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Description',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'archiv_creation_date',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Erstelldatum',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Creation date',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'archiv_accepted_on_at',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'AkzeptiertAmUm',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'AcceptionOnAt',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'archiv_gedruckt',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Gedruckt',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Printed',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'archiv_signiert',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Signiert',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Signed',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'archiv_title_edit',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Akte aktualisieren',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Edit document',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'archiv_akte',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Akte',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Document',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'archiv_new_file',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Neue Datei',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'New file',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'archiv_akte_id',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Akte ID',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Document ID',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'stv',
|
||||
'phrase' => 'archiv_signed',
|
||||
'insertvon' => 'system',
|
||||
'phrases' => array(
|
||||
array(
|
||||
'sprache' => 'German',
|
||||
'text' => 'Signiert',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
),
|
||||
array(
|
||||
'sprache' => 'English',
|
||||
'text' => 'Signed',
|
||||
'description' => '',
|
||||
'insertvon' => 'system'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'app' => 'core',
|
||||
'category' => 'mobility',
|
||||
|
||||
Reference in New Issue
Block a user