From 7fbff20dd97d66a15cd0242214c96616530fe924 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Tue, 4 Feb 2025 14:49:41 +0100 Subject: [PATCH 001/139] new Tab Gruppen --- .../api/frontend/v1/stv/Config.php | 4 + .../api/frontend/v1/stv/Favorites.php | 2 +- .../api/frontend/v1/stv/Gruppen.php | 81 ++++++++ public/js/api/stv.js | 2 + public/js/api/stv/group.js | 8 + .../js/components/Stv/Studentenverwaltung.js | 1 + .../Studentenverwaltung/Details/Gruppen.js | 19 ++ .../Details/Gruppen/Gruppen.js | 182 ++++++++++++++++++ system/phrasesupdate.php | 83 ++++++++ 9 files changed, 381 insertions(+), 1 deletion(-) create mode 100644 application/controllers/api/frontend/v1/stv/Gruppen.php create mode 100644 public/js/api/stv/group.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Gruppen.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js diff --git a/application/controllers/api/frontend/v1/stv/Config.php b/application/controllers/api/frontend/v1/stv/Config.php index c28c49485..12cd77048 100644 --- a/application/controllers/api/frontend/v1/stv/Config.php +++ b/application/controllers/api/frontend/v1/stv/Config.php @@ -91,6 +91,10 @@ class Config extends FHCAPI_Controller 'title' => $this->p->t('stv', 'tab_resources'), 'component' => './Stv/Studentenverwaltung/Details/Betriebsmittel.js' ]; + $result['groups'] = [ + 'title' => $this->p->t('stv', 'tab_groups'), + 'component' => './Stv/Studentenverwaltung/Details/Gruppen.js' + ]; /* TODO(chris): Ausgeblendet für Testing $result['grades'] = [ 'title' => $this->p->t('stv', 'tab_grades'), diff --git a/application/controllers/api/frontend/v1/stv/Favorites.php b/application/controllers/api/frontend/v1/stv/Favorites.php index 8d7a6cd14..b8fe6f3d7 100644 --- a/application/controllers/api/frontend/v1/stv/Favorites.php +++ b/application/controllers/api/frontend/v1/stv/Favorites.php @@ -48,7 +48,7 @@ class Favorites extends FHCAPI_Controller if (!$data) $this->terminateWithSuccess(null); else - $this->terminateWithSuccess($data['stv_favorites']); + $this->terminateWithSuccess($data['stv_favorites'] ?? null); } public function set() diff --git a/application/controllers/api/frontend/v1/stv/Gruppen.php b/application/controllers/api/frontend/v1/stv/Gruppen.php new file mode 100644 index 000000000..39c5efe21 --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Gruppen.php @@ -0,0 +1,81 @@ + ['admin:r', 'assistenz:r'], + 'deleteGruppe' => ['admin:rw', 'assistenz:rw'], + ]); + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + + // Load language phrases + $this->loadPhrases([ + 'ui', 'gruppenmanagement' + ]); + + // Load models + $this->load->model('person/Benutzergruppe_model', 'BenutzergruppeModel'); + $this->load->model('organisation/Gruppe_model', 'GruppeModel'); + } + + public function getGruppen($student_uid) + { + $this->BenutzergruppeModel ->addSelect('gruppe_kurzbz'); + $this->BenutzergruppeModel ->addSelect('bezeichnung'); + $this->BenutzergruppeModel ->addSelect('generiert'); + $this->BenutzergruppeModel ->addSelect('uid'); + $this->BenutzergruppeModel ->addSelect('studiensemester_kurzbz'); + $this->BenutzergruppeModel ->addSelect('public.tbl_benutzergruppe.insertvon'); + $this->BenutzergruppeModel ->addJoin('public.tbl_gruppe', 'gruppe_kurzbz'); + $this->BenutzergruppeModel-> addOrder('bezeichnung', 'ASC'); + + $result = $this->BenutzergruppeModel->loadWhere( + array( + 'uid' => $student_uid + ) + ); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function deleteGruppe() + { + $student_uid = $this->input->post('id'); + $gruppe_kurzbz = $this->input->post('gruppe_kurzbz'); + + //Validate if automatic group generation + $result = $this->GruppeModel-> loadWhere( + array( + 'gruppe_kurzbz' => $gruppe_kurzbz + ) + ); + $data = $this->getDataOrTerminateWithError($result); + $generation = current($data); + + if($generation->generiert) + { + $this->terminateWithError($this->p->t('gruppenmanagement', 'error_deleteGeneratedGroups'), self::ERROR_TYPE_GENERAL); + } + + $result = $this->BenutzergruppeModel->delete( + array( + 'gruppe_kurzbz' => $gruppe_kurzbz, + 'uid' => $student_uid + ) + ); + + $data = $this->getDataOrTerminateWithError($result); + + return $this->terminateWithSuccess($data); + } +} diff --git a/public/js/api/stv.js b/public/js/api/stv.js index 14fcc6661..8b14beb14 100644 --- a/public/js/api/stv.js +++ b/public/js/api/stv.js @@ -2,12 +2,14 @@ import verband from './stv/verband.js'; import students from './stv/students.js'; import filter from './stv/filter.js'; import konto from './stv/konto.js'; +import group from './stv/group.js'; export default { verband, students, filter, konto, + group, configStudent() { return this.$fhcApi.get('api/frontend/v1/stv/config/student'); }, diff --git a/public/js/api/stv/group.js b/public/js/api/stv/group.js new file mode 100644 index 000000000..af6e6e122 --- /dev/null +++ b/public/js/api/stv/group.js @@ -0,0 +1,8 @@ +export default { + getGruppen(url, config, params) { + return this.$fhcApi.get('api/frontend/v1/stv/Gruppen/getGruppen/' + params.id); + }, + deleteGroup(params) { + return this.$fhcApi.post('api/frontend/v1/stv/Gruppen/deleteGruppe/', params); + } +} \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung.js b/public/js/components/Stv/Studentenverwaltung.js index 8779e4bf1..eaa253c2c 100644 --- a/public/js/components/Stv/Studentenverwaltung.js +++ b/public/js/components/Stv/Studentenverwaltung.js @@ -57,6 +57,7 @@ export default { hasPermissionToSkipStatusCheck: this.permissions['student/keine_studstatuspruefung'], hasPermissionRtAufsicht: this.permissions['lehre/reihungstestAufsicht'], lists: this.lists, + currentSemester: Vue.computed(() => this.studiensemesterKurzbz), defaultSemester: this.defaultSemester, $reloadList: () => { this.$refs.stvList.reload(); diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Gruppen.js b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen.js new file mode 100644 index 000000000..1c7c47d6b --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen.js @@ -0,0 +1,19 @@ +import GruppenList from './Gruppen/Gruppen.js'; + +export default { + components: { + GruppenList + }, + props: { + modelValue: Object + }, + methods: { + reload() { + this.$refs.gruppen.$refs.table.reloadTable(); + } + }, + template: ` +
+ +
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js new file mode 100644 index 000000000..6a657a793 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js @@ -0,0 +1,182 @@ +import {CoreFilterCmpt} from "../../../../filter/Filter.js"; + +export default { + components: { + CoreFilterCmpt, + }, + inject: { + currentSemester: { + from: 'currentSemester', + }, + }, + props: { + student: Object + }, + data() { + return { + tabulatorOptions: { + ajaxURL: 'dummy', + ajaxRequestFunc: this.$fhcApi.factory.stv.group.getGruppen, + ajaxParams: () => { + return { + id: this.student.uid + }; + }, + ajaxResponse: (url, params, response) => response.data, + initialFilter: [ + {field: "uid", type: "=", value: this.student.uid}, + [ + {field: "studiensemester_kurzbz", type: "=", value: this.currentSemester}, + {field: "insertvon", type: "=", value: "mlists_generate"} + ] + ], + columns: [ + {title: "Gruppe", field: "gruppe_kurzbz"}, + {title: "Bezeichnung", field: "bezeichnung"}, + {title: "Semester", field: "studiensemester_kurzbz"}, + { + title: "automatisch generiert", + field: "generiert", + formatter: "tickCross", + hozAlign: "center", + formatterParams: { + tickElement: '', + crossElement: '' + } + }, + {title: "UID", field: "uid"}, + {title: "InsertVon", field: "insertvon", visible: false}, + { + title: 'Aktionen', field: 'actions', + minWidth: 150, // Ensures Action-buttons will be always fully displayed + formatter: (cell, formatterParams, onRendered) => { + const container = document.createElement('div'); + container.className = "d-flex gap-2"; + + const data = cell.getData(); + + const button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = this.$p.t('ui', 'loeschen'); + button.addEventListener('click', () => + this.actionDeleteGroup(data.gruppe_kurzbz) + ); + if (data.generiert) + button.disabled = true; + container.append(button); + + return container; + }, + frozen: true + }, + ], + layout: 'fitDataFill', + height: 'auto', + selectable: true, + index: 'group_id', + persistenceID: 'stv-details-gruppe' + }, + tabulatorEvents: [ + { + event: 'tableBuilt', + handler: async () => { + + await this.$p.loadCategory(['global', 'person', 'stv', 'ui', 'gruppenmanagement']); + + let cm = this.$refs.table.tabulator.columnManager; + + cm.getColumnByField('gruppe_kurzbz').component.updateDefinition({ + title: this.$p.t('gruppenmanagement', 'gruppe') + }); + + cm.getColumnByField('bezeichnung').component.updateDefinition({ + title: this.$p.t('ui', 'bezeichnung') + }); + + cm.getColumnByField('generiert').component.updateDefinition({ + title: this.$p.t('gruppenmanagement', 'automatisch_generiert') + }); + + cm.getColumnByField('uid').component.updateDefinition({ + title: this.$p.t('ui', 'student_uid') + }); + + //Interference with Filter if not commented out + /* + cm.getColumnByField('studiensemester_kurzbz').component.updateDefinition({ + title: this.$p.t('lehre', 'studiensemester') + });*/ + + } + } + ], + } + }, + methods: { + actionDeleteGroup(gruppe_kurzbz) { + this.$fhcAlert + .confirmDelete() + .then(result => result + ? gruppe_kurzbz + : Promise.reject({handled: true})) + .then(this.deleteGroup) + .catch(this.$fhcAlert.handleSystemError); + + }, + deleteGroup(gruppe_kurzbz) { + const group_id = { + id: this.student.uid, + gruppe_kurzbz: gruppe_kurzbz + }; + + return this.$fhcApi.factory.stv.group.deleteGroup(group_id) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + window.scrollTo(0, 0); + this.reload(); + }); + }, + reload() { + this.$refs.table.reloadTable(); + }, + }, + watch: { + currentSemester(newVal) { + if (newVal) { + + this.$refs.table.tabulator.clearFilter(); // Clear old filters + + this.$refs.table.tabulator.setFilter([ + {field: "uid", type: "=", value: this.student.uid}, + [ + {field: "studiensemester_kurzbz", type: "=", value: newVal}, + {field: "insertvon", type: "=", value: "mlists_generate"} + ] + ]); + + + } + }, + student() { + this.$refs.table.reloadTable(); + } + }, + template: ` +
+
{{$p.t('stv', 'tab_groups')}}
+ + + +
+ ` +} \ No newline at end of file diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 746c24da3..160db2853 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -37297,7 +37297,90 @@ array( 'insertvon' => 'system' ) ) + ), + //////////// FHC4 Phrases Gruppen Start //////////// + array( + 'app' => 'core', + 'category' => 'stv', + 'phrase' => 'tab_groups', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Gruppen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Groups', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'gruppenmanagement', + 'phrase' => 'gruppe', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Gruppe', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Group', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'gruppenmanagement', + 'phrase' => 'automatisch_generiert', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'automatisch generiert', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'automatically generated', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'gruppenmanagement', + 'phrase' => 'error_deleteGeneratedGroups', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Automatisch generierte Gruppenzuordnungen können nicht gelöscht werden.', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Automatically generated group assignments cannot be deleted.', + 'description' => '', + 'insertvon' => 'system' + ) + ) ) + //////////// FHC4 Phrases Gruppen End //////////// + ); From 6eb9c2ac223e34fe6bd5e89310615e3822e58bf2 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Tue, 4 Feb 2025 14:57:35 +0100 Subject: [PATCH 002/139] update filtering --- application/controllers/api/frontend/v1/stv/Gruppen.php | 1 - .../Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/application/controllers/api/frontend/v1/stv/Gruppen.php b/application/controllers/api/frontend/v1/stv/Gruppen.php index 39c5efe21..c30816f2a 100644 --- a/application/controllers/api/frontend/v1/stv/Gruppen.php +++ b/application/controllers/api/frontend/v1/stv/Gruppen.php @@ -33,7 +33,6 @@ class Gruppen extends FHCAPI_Controller $this->BenutzergruppeModel ->addSelect('generiert'); $this->BenutzergruppeModel ->addSelect('uid'); $this->BenutzergruppeModel ->addSelect('studiensemester_kurzbz'); - $this->BenutzergruppeModel ->addSelect('public.tbl_benutzergruppe.insertvon'); $this->BenutzergruppeModel ->addJoin('public.tbl_gruppe', 'gruppe_kurzbz'); $this->BenutzergruppeModel-> addOrder('bezeichnung', 'ASC'); diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js index 6a657a793..63a9b24e1 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Gruppen/Gruppen.js @@ -27,7 +27,7 @@ export default { {field: "uid", type: "=", value: this.student.uid}, [ {field: "studiensemester_kurzbz", type: "=", value: this.currentSemester}, - {field: "insertvon", type: "=", value: "mlists_generate"} + {field: "studiensemester_kurzbz", type: "=", value: null} ] ], columns: [ @@ -45,7 +45,6 @@ export default { } }, {title: "UID", field: "uid"}, - {title: "InsertVon", field: "insertvon", visible: false}, { title: 'Aktionen', field: 'actions', minWidth: 150, // Ensures Action-buttons will be always fully displayed @@ -153,7 +152,7 @@ export default { {field: "uid", type: "=", value: this.student.uid}, [ {field: "studiensemester_kurzbz", type: "=", value: newVal}, - {field: "insertvon", type: "=", value: "mlists_generate"} + {field: "studiensemester_kurzbz", type: "=", value: null} ] ]); From 018220594a82590cffbcbc612f0f767a314387d7 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Thu, 6 Feb 2025 08:34:34 +0100 Subject: [PATCH 003/139] prepare basic framework --- .../api/frontend/v1/messages/Messages.php | 45 +++++++ .../api/frontend/v1/stv/Config.php | 4 + .../api/frontend/v1/stv/Favorites.php | 2 +- application/models/system/Message_model.php | 9 +- public/js/api/fhcapifactory.js | 4 +- public/js/api/messages.js | 5 + public/js/api/messages/person.js | 6 + .../components/Messages/Details/NewMessage.js | 13 ++ .../Messages/Details/TableMessages.js | 117 ++++++++++++++++++ public/js/components/Messages/Messages.js | 48 +++++++ .../Studentenverwaltung/Details/Messages.js | 25 ++++ system/phrasesupdate.php | 25 +++- 12 files changed, 297 insertions(+), 6 deletions(-) create mode 100644 application/controllers/api/frontend/v1/messages/Messages.php create mode 100644 public/js/api/messages.js create mode 100644 public/js/api/messages/person.js create mode 100644 public/js/components/Messages/Details/NewMessage.js create mode 100644 public/js/components/Messages/Details/TableMessages.js create mode 100644 public/js/components/Messages/Messages.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Messages.js diff --git a/application/controllers/api/frontend/v1/messages/Messages.php b/application/controllers/api/frontend/v1/messages/Messages.php new file mode 100644 index 000000000..f81e85e9a --- /dev/null +++ b/application/controllers/api/frontend/v1/messages/Messages.php @@ -0,0 +1,45 @@ + ['admin:r', 'assistenz:r'], + ]); + + //Load Models + $this->load->model('system/Message_model', 'MessageModel'); + + // Additional Permission Checks + //TODO(manu) check permissions + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + $this->load->library('form_validation'); + + // Load language phrases + $this->loadPhrases([ + 'ui' + ]); + } + + public function getMessages($id, $type_id) + { + //$this->terminateWithError("in backend " . $type_id . ": " . $id, self::ERROR_TYPE_GENERAL); + + if ($type_id != "person_id") + { + $this->terminateWithError("logic for type_id " . $type_id . " not defined yet", self::ERROR_TYPE_GENERAL); + } + + $result = $this->MessageModel->getMessagesOfPerson($id); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } +} \ No newline at end of file diff --git a/application/controllers/api/frontend/v1/stv/Config.php b/application/controllers/api/frontend/v1/stv/Config.php index c28c49485..9dec3015f 100644 --- a/application/controllers/api/frontend/v1/stv/Config.php +++ b/application/controllers/api/frontend/v1/stv/Config.php @@ -91,6 +91,10 @@ class Config extends FHCAPI_Controller 'title' => $this->p->t('stv', 'tab_resources'), 'component' => './Stv/Studentenverwaltung/Details/Betriebsmittel.js' ]; + $result['messages'] = [ + 'title' => $this->p->t('stv', 'tab_messages'), + 'component' => './Stv/Studentenverwaltung/Details/Messages.js' + ]; /* TODO(chris): Ausgeblendet für Testing $result['grades'] = [ 'title' => $this->p->t('stv', 'tab_grades'), diff --git a/application/controllers/api/frontend/v1/stv/Favorites.php b/application/controllers/api/frontend/v1/stv/Favorites.php index 8d7a6cd14..b8fe6f3d7 100644 --- a/application/controllers/api/frontend/v1/stv/Favorites.php +++ b/application/controllers/api/frontend/v1/stv/Favorites.php @@ -48,7 +48,7 @@ class Favorites extends FHCAPI_Controller if (!$data) $this->terminateWithSuccess(null); else - $this->terminateWithSuccess($data['stv_favorites']); + $this->terminateWithSuccess($data['stv_favorites'] ?? null); } public function set() diff --git a/application/models/system/Message_model.php b/application/models/system/Message_model.php index d9f8585ed..6288f54f3 100644 --- a/application/models/system/Message_model.php +++ b/application/models/system/Message_model.php @@ -85,7 +85,7 @@ class Message_model extends DB_Model */ public function getMessagesOfPerson($person_id, $status = null) { - $sql = 'SELECT m.message_id, + $sql = "SELECT m.message_id, m.person_id, m.subject, m.body, @@ -109,7 +109,10 @@ class Message_model extends DB_Model re.vornamen AS revornamen, s.status, s.statusinfo, - s.insertamum AS statusamum + s.insertamum AS statusamum, + CONCAT(se.titelpre, ' ', se.vorname, ' ', se.nachname, ' ', se.titelpost) as sender, + CONCAT(re.titelpre, ' ', re.vorname, ' ', re.nachname, ' ', re.titelpost ) as recipient, + TO_CHAR(s.insertamum::timestamp, 'DD.MM.YYYY HH24:MI') AS format_insertamum FROM public.tbl_msg_message m JOIN public.tbl_msg_recipient r ON m.message_id = r.message_id JOIN public.tbl_person se ON (m.person_id = se.person_id) @@ -122,7 +125,7 @@ class Message_model extends DB_Model ) s ON (m.message_id = s.message_id AND re.person_id = s.person_id) WHERE se.person_id = ? OR re.person_id = ? - '; + "; if (is_numeric($status)) { diff --git a/public/js/api/fhcapifactory.js b/public/js/api/fhcapifactory.js index c4106c3f6..7bc510b6e 100644 --- a/public/js/api/fhcapifactory.js +++ b/public/js/api/fhcapifactory.js @@ -33,6 +33,7 @@ import ort from "./ort.js"; import cms from "./cms.js"; import lehre from "./lehre.js"; import addons from "./addons.js"; +import messages from "./messages.js"; export default { search, @@ -52,5 +53,6 @@ export default { ort, cms, lehre, - addons + addons, + messages }; diff --git a/public/js/api/messages.js b/public/js/api/messages.js new file mode 100644 index 000000000..f1378c69d --- /dev/null +++ b/public/js/api/messages.js @@ -0,0 +1,5 @@ +import person from "./messages/person.js"; + +export default { + person +} \ No newline at end of file diff --git a/public/js/api/messages/person.js b/public/js/api/messages/person.js new file mode 100644 index 000000000..bfbdaf123 --- /dev/null +++ b/public/js/api/messages/person.js @@ -0,0 +1,6 @@ +export default { + getMessages(url, config, params){ + console.log("in api", params); + return this.$fhcApi.get('api/frontend/v1/messages/messages/getMessages/' + params.id + '/' + params.type); + }, +} \ No newline at end of file diff --git a/public/js/components/Messages/Details/NewMessage.js b/public/js/components/Messages/Details/NewMessage.js new file mode 100644 index 000000000..bf60842d2 --- /dev/null +++ b/public/js/components/Messages/Details/NewMessage.js @@ -0,0 +1,13 @@ +export default { + data(){ + return { + + } + }, + template: ` +
+

New Message

+
+ ` + +} \ No newline at end of file diff --git a/public/js/components/Messages/Details/TableMessages.js b/public/js/components/Messages/Details/TableMessages.js new file mode 100644 index 000000000..bc7e6a02a --- /dev/null +++ b/public/js/components/Messages/Details/TableMessages.js @@ -0,0 +1,117 @@ +import {CoreFilterCmpt} from "../../filter/Filter.js"; + +export default { + components: { + CoreFilterCmpt, + }, + props: { + endpoint: { + type: String, + required: true + }, + typeId: String, + id: { + type: [Number, String], + required: true + }, + }, + //TODO(Manu) endpoint macht Probleme + data(){ + return { + tabulatorOptions: { + ajaxURL: 'dummy', + ajaxRequestFunc: this.$fhcApi.factory.messages.person.getMessages, + ajaxParams: () => { + return { + id: this.id, + type: this.typeId + }; + }, + ajaxResponse: (url, params, response) => response.data, + columns: [ + {title: "subject", field: "subject"}, + {title: "body", field: "body", visible: false}, + {title: "message_id", field: "message_id", visible: false}, + {title: "datum", field: "format_insertamum"}, + {title: "sender", field: "sender"}, + {title: "recipient", field: "recipient"}, + {title: "sepersonid", field: "sepersonid"}, + {title: "repersonid", field: "repersonid"}, + {title: "status", field: "status"}, + { + title: 'Aktionen', field: 'actions', + width: 100, + formatter: (cell, formatterParams, onRendered) => { + let container = document.createElement('div'); + container.className = "d-flex gap-2"; + + let button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.title = this.$p.t('ui', 'notiz_edit'); + button.innerHTML = ''; + button.addEventListener( + 'click', + (event) => + this.actionEditNotiz(cell.getData().notiz_id) + ); + container.append(button); + + button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.title = this.$p.t('notiz', 'notiz_delete'); + button.innerHTML = ''; + button.addEventListener( + 'click', + () => + this.actionDeleteNotiz(cell.getData().notiz_id) + ); + container.append(button); + + return container; + }, + frozen: true + }], + layout: 'fitColumns', + layoutColumnsOnNewData: false, + height: '250', + selectableRangeMode: 'click', + selectable: true, + index: 'message_id', + persistenceID: 'core-message' + }, + } + }, +/* computed: { + statusText(){ + 0: this.$p.t('messsages', 'unread'), + 1: this.$p.t('messsages', 'read'), + 2: this.$p.t('messsages', 'archived'), + 0: this.$p.t('messsages', 'unread'), + 3: this.$p.t('person', 'deleted'), + } + },*/ + template: ` +
+

Table Messages

+

type_id: {{typeId}}

+

id: {{id}}

+

endpoint: {{endpoint}}

+ + + + + + +
+ ` + +} \ No newline at end of file diff --git a/public/js/components/Messages/Messages.js b/public/js/components/Messages/Messages.js new file mode 100644 index 000000000..6811a3aed --- /dev/null +++ b/public/js/components/Messages/Messages.js @@ -0,0 +1,48 @@ +import TableMessages from "./Details/TableMessages.js"; +import NewMessage from "./Details/NewMessage.js"; + +export default { + components: { + TableMessages, + NewMessage + }, + props: { + endpoint: { + type: String, + required: true + }, + typeId: String, + id: { + type: [Number, String], + required: true + }, + showNew: Boolean, + showTable: Boolean + }, + data() { + return {} + }, + template: ` +
+

endpoint: {{endpoint}}

+
+ + +
+ +
+ + + +
+ +
+ ` + +} \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Messages.js b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js new file mode 100644 index 000000000..7bd6d4b4d --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js @@ -0,0 +1,25 @@ +import CoreMessages from "../../../Messages/Messages.js"; + +export default { + components: { + CoreMessages + }, + props: { + modelValue: Object + }, + template: ` +
+ + + + + +
+ ` +}; \ No newline at end of file diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index cfaf85ec7..f25cc72ec 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -37297,7 +37297,30 @@ array( 'insertvon' => 'system' ) ) - ) + ), + /////////// FHC4 Phrases Messages START /////////// + array( + 'app' => 'core', + 'category' => 'stv', + 'phrase' => 'tab_messages', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Nachrichten', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Messages', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + /////////// FHC4 Phrases Messages END /////////// + ); From ae3072be924940441968f5d65a352245af043afc Mon Sep 17 00:00:00 2001 From: ma0068 Date: Tue, 11 Feb 2025 09:02:56 +0100 Subject: [PATCH 004/139] listTables with preview in two layouts --- .../api/frontend/v1/messages/Messages.php | 2 +- application/models/system/Message_model.php | 57 +++- public/css/Studentenverwaltung.css | 1 + public/css/components/Messages.css | 4 + public/js/api/messages/person.js | 1 - .../Messages/Details/TableMessages.js | 272 +++++++++++++++--- public/js/components/Messages/Messages.js | 15 +- .../Studentenverwaltung/Details/Messages.js | 3 +- system/phrasesupdate.php | 200 +++++++++++++ 9 files changed, 508 insertions(+), 47 deletions(-) create mode 100644 public/css/components/Messages.css diff --git a/application/controllers/api/frontend/v1/messages/Messages.php b/application/controllers/api/frontend/v1/messages/Messages.php index f81e85e9a..adf1d52e9 100644 --- a/application/controllers/api/frontend/v1/messages/Messages.php +++ b/application/controllers/api/frontend/v1/messages/Messages.php @@ -36,7 +36,7 @@ class Messages extends FHCAPI_Controller $this->terminateWithError("logic for type_id " . $type_id . " not defined yet", self::ERROR_TYPE_GENERAL); } - $result = $this->MessageModel->getMessagesOfPerson($id); + $result = $this->MessageModel->getMessagesForTable($id); $data = $this->getDataOrTerminateWithError($result); diff --git a/application/models/system/Message_model.php b/application/models/system/Message_model.php index 6288f54f3..1b201fc1b 100644 --- a/application/models/system/Message_model.php +++ b/application/models/system/Message_model.php @@ -109,10 +109,7 @@ class Message_model extends DB_Model re.vornamen AS revornamen, s.status, s.statusinfo, - s.insertamum AS statusamum, - CONCAT(se.titelpre, ' ', se.vorname, ' ', se.nachname, ' ', se.titelpost) as sender, - CONCAT(re.titelpre, ' ', re.vorname, ' ', re.nachname, ' ', re.titelpost ) as recipient, - TO_CHAR(s.insertamum::timestamp, 'DD.MM.YYYY HH24:MI') AS format_insertamum + s.insertamum AS statusamum FROM public.tbl_msg_message m JOIN public.tbl_msg_recipient r ON m.message_id = r.message_id JOIN public.tbl_person se ON (m.person_id = se.person_id) @@ -233,4 +230,56 @@ class Message_model extends DB_Model return $this->execQuery($query, $params); } + + /** + * Gets messages for a person for tableMessages. + * @param $person_id + * @param null $status message status. by default, latest status is returned + * @return array|null + */ + public function getMessagesForTable($person_id, $status = null) + { + $sql = " + SELECT + m.message_id AS message_id, + m.subject AS subject, + m.body AS body, + m.insertamum AS insertamum, + m.relationmessage_id AS relationmessage_id, + (SELECT COALESCE(titelpre,'') || ' ' || COALESCE(vorname,'') || ' ' || COALESCE(nachname,'') || ' ' || COALESCE(titelpost,'') FROM public.tbl_person WHERE person_id = m.person_id) as sender, + (SELECT COALESCE(titelpre,'') || ' ' || COALESCE(vorname,'') || ' ' || COALESCE(nachname,'') || ' ' || COALESCE(titelpost,'') FROM public.tbl_person WHERE person_id = r.person_id) as recipient, + m.person_id as sender_id, + r.person_id as recipient_id, + MAX(ss.status) as status, + MAX(ss.insertamum) as statusdatum + FROM public.tbl_msg_message m + JOIN public.tbl_msg_recipient r USING(message_id) + JOIN public.tbl_msg_status ss ON(r.message_id = ss.message_id AND ss.person_id = r.person_id) + WHERE m.person_id = ? + GROUP BY m.message_id, m.subject, m.body, m.insertamum, m.relationmessage_id, sender, recipient, sender_id, recipient_id + UNION ALL + SELECT + m.message_id AS message_id, + m.subject AS subject, + m.body AS body, + m.insertamum AS insertamum, + m.relationmessage_id AS relationmessage_id, + (SELECT COALESCE(titelpre,'') || ' ' || COALESCE(vorname,'') || ' ' || COALESCE(nachname,'') || ' ' || COALESCE(titelpost,'') FROM public.tbl_person WHERE person_id = m.person_id) as sender, + (SELECT COALESCE(titelpre,'') || ' ' || COALESCE(vorname,'') || ' ' || COALESCE(nachname,'') || ' ' || COALESCE(titelpost,'') FROM public.tbl_person WHERE person_id = r.person_id) as recipient, + m.person_id as sender_id, + r.person_id as recipient_id, + MAX(ss.status) as status, + MAX(ss.insertamum) as statusdatum + FROM public.tbl_msg_recipient r + JOIN public.tbl_msg_status ss USING(message_id, person_id) + JOIN public.tbl_msg_message m USING(message_id) + WHERE r.person_id = ? + GROUP BY m.message_id, m.subject, m.body, m.insertamum, m.relationmessage_id, sender, recipient, sender_id, recipient_id + ORDER BY insertamum + "; + + $parametersArray = array($person_id, $person_id); + + return $this->execQuery($sql, $parametersArray); + } } diff --git a/public/css/Studentenverwaltung.css b/public/css/Studentenverwaltung.css index f179c3667..cc2eff51d 100644 --- a/public/css/Studentenverwaltung.css +++ b/public/css/Studentenverwaltung.css @@ -4,6 +4,7 @@ @import './components/FilterComponent.css'; @import './components/Tabs.css'; @import './components/Notiz.css'; +@import './components/Messages.css'; html { font-size: .875em; diff --git a/public/css/components/Messages.css b/public/css/components/Messages.css new file mode 100644 index 000000000..1c004f6b0 --- /dev/null +++ b/public/css/components/Messages.css @@ -0,0 +1,4 @@ +.twoColumns { + height: 400px; + overflow-y: auto; +} diff --git a/public/js/api/messages/person.js b/public/js/api/messages/person.js index bfbdaf123..baf8bd39f 100644 --- a/public/js/api/messages/person.js +++ b/public/js/api/messages/person.js @@ -1,6 +1,5 @@ export default { getMessages(url, config, params){ - console.log("in api", params); return this.$fhcApi.get('api/frontend/v1/messages/messages/getMessages/' + params.id + '/' + params.type); }, } \ No newline at end of file diff --git a/public/js/components/Messages/Details/TableMessages.js b/public/js/components/Messages/Details/TableMessages.js index bc7e6a02a..c4fd4d4d7 100644 --- a/public/js/components/Messages/Details/TableMessages.js +++ b/public/js/components/Messages/Details/TableMessages.js @@ -1,8 +1,12 @@ import {CoreFilterCmpt} from "../../filter/Filter.js"; +import FormForm from '../../Form/Form.js'; +//import FormInput from '../../Form/Input.js'; export default { components: { CoreFilterCmpt, + FormForm, + // FormInput }, props: { endpoint: { @@ -14,6 +18,7 @@ export default { type: [Number, String], required: true }, + messageLayout: String, }, //TODO(Manu) endpoint macht Probleme data(){ @@ -32,12 +37,65 @@ export default { {title: "subject", field: "subject"}, {title: "body", field: "body", visible: false}, {title: "message_id", field: "message_id", visible: false}, - {title: "datum", field: "format_insertamum"}, + { + title: "Datum", + field: "insertamum", + formatter: function (cell) { + const dateStr = cell.getValue(); + const date = new Date(dateStr); // Convert to Date object + return date.toLocaleString("de-DE", { + day: "2-digit", + month: "2-digit", + year: "numeric", + hour: "2-digit", + minute: "2-digit", + hour12: false + }); + } + }, {title: "sender", field: "sender"}, {title: "recipient", field: "recipient"}, - {title: "sepersonid", field: "sepersonid"}, - {title: "repersonid", field: "repersonid"}, - {title: "status", field: "status"}, + {title: "senderId", field: "sender_id"}, + {title: "recipientId", field: "recipient_id"}, + { + title: "status", + field: "status", + formatter: function (cell) { + //TODO(Manu) get phrases in this context to work? + + /* const statusMap = { + 0: this.$p.t('messsages', 'unread'), + 1: this.$p.t('messsages', 'read'), + 2: this.$p.t('messsages', 'archived'), + 3: this.$p.t('messsages', 'deleted') + };*/ + const statusMap = { + 0: 'unread', + 1: 'read', + 2: 'archived', + 3: 'deleted' + }; + return statusMap[cell.getValue()]; + // return this.$p.t('messsages', 'deleted'); + } + + }, + { + title: "letzte Änderung", + field: "statusdatum", + formatter: function (cell) { + const dateStr = cell.getValue(); + const date = new Date(dateStr); // Convert to Date object + return date.toLocaleString("de-DE", { + day: "2-digit", + month: "2-digit", + year: "numeric", + hour: "2-digit", + minute: "2-digit", + hour12: false + }); + } + }, { title: 'Aktionen', field: 'actions', width: 100, @@ -47,23 +105,23 @@ export default { let button = document.createElement('button'); button.className = 'btn btn-outline-secondary btn-action'; - button.title = this.$p.t('ui', 'notiz_edit'); - button.innerHTML = ''; + button.title = this.$p.t('global', 'reply'); + button.innerHTML = ''; button.addEventListener( 'click', (event) => - this.actionEditNotiz(cell.getData().notiz_id) + this.reply(cell.getData().message_id) ); container.append(button); button = document.createElement('button'); button.className = 'btn btn-outline-secondary btn-action'; - button.title = this.$p.t('notiz', 'notiz_delete'); + button.title = this.$p.t('ui', 'loeschen'); button.innerHTML = ''; button.addEventListener( 'click', () => - this.actionDeleteNotiz(cell.getData().notiz_id) + this.deleteMessage(cell.getData().message_id) ); container.append(button); @@ -71,46 +129,186 @@ export default { }, frozen: true }], - layout: 'fitColumns', - layoutColumnsOnNewData: false, - height: '250', + layout: 'fitDataFill', + layoutColumnsOnNewData: false, + // height: 'auto', + height: '400', + selectable: true, + selectableRangeMode: 'click', +/* layoutColumnsOnNewData: false, + selectableRangeMode: 'click', selectable: true, index: 'message_id', - persistenceID: 'core-message' + persistenceID: 'core-message'*/ }, + tabulatorEvents: [ + { + event: 'dataLoaded', + handler: data => this.tabulatorData = data.map(item => { + return item; + }), + }, + { + event: 'tableBuilt', + handler: async() => { + await this.$p.loadCategory(['global', 'person', 'stv', 'messages', 'ui', 'notiz']); + + + let cm = this.$refs.table.tabulator.columnManager; + + cm.getColumnByField('subject').component.updateDefinition({ + title: this.$p.t('global', 'betreff') + }); + cm.getColumnByField('body').component.updateDefinition({ + title: this.$p.t('messages', 'body') + }); + cm.getColumnByField('message_id').component.updateDefinition({ + title: this.$p.t('messages', 'message_id') + }); + cm.getColumnByField('insertamum').component.updateDefinition({ + title: this.$p.t('global', 'datum') + }); + cm.getColumnByField('sender').component.updateDefinition({ + title: this.$p.t('messages', 'sender') + }); + cm.getColumnByField('recipient').component.updateDefinition({ + title: this.$p.t('messages', 'recipient') + }); + cm.getColumnByField('sender_id').component.updateDefinition({ + title: this.$p.t('messages', 'senderId') + }); + cm.getColumnByField('recipient_id').component.updateDefinition({ + title: this.$p.t('messages', 'recipientId') + }); + cm.getColumnByField('statusdatum').component.updateDefinition({ + title: this.$p.t('notiz', 'letzte_aenderung') + }); + /* + cm.getColumnByField('actions').component.updateDefinition({ + title: this.$p.t('global', 'aktionen') + }); + */ + } + }, + { + event: 'rowClick', + handler: (e, row) => { + const selectedMessage = row.getData().message_id; + const body = row.getData().body; + this.previewBody = body; + console.log(selectedMessage); + } + }, + ], + tabulatorData: [], + previewBody: "" } }, -/* computed: { + methods: { + reply(message_id){ + console.log("in reply " + message_id); + }, + deleteMessage(message_id){ + console.log("deleteMessage " + message_id); + }, + actionNewMessage(){ + console.log("action new message"); + }, + }, + computed: { statusText(){ - 0: this.$p.t('messsages', 'unread'), - 1: this.$p.t('messsages', 'read'), - 2: this.$p.t('messsages', 'archived'), - 0: this.$p.t('messsages', 'unread'), - 3: this.$p.t('person', 'deleted'), + return { + 0: this.$p.t('messsages', 'unread'), + 1: this.$p.t('messsages', 'read'), + 2: this.$p.t('messsages', 'archived'), + 3: this.$p.t('messsages', 'deleted') + } } - },*/ + }, + mounted() { + // change to target="_blank" +/* this.$nextTick(() => { + const links = document.querySelectorAll('.preview a'); + links.forEach(link => { + link.setAttribute('target', '_blank'); + link.setAttribute('rel', 'noopener noreferrer'); // Sicherheitsmaßnahme + }); + });*/ + }, template: `
-

Table Messages

-

type_id: {{typeId}}

-

id: {{id}}

endpoint: {{endpoint}}

+

{{messageLayout}}

+ + + + + + +
- - - - - +
+ +
+ + +
+ + +
+



+ +
+
+
+ +
+ +
+
+ + +
+ + +
+ + +
+ + +
+ +
+
+
+ +
+
+
` diff --git a/public/js/components/Messages/Messages.js b/public/js/components/Messages/Messages.js index 6811a3aed..3fd6e2a02 100644 --- a/public/js/components/Messages/Messages.js +++ b/public/js/components/Messages/Messages.js @@ -17,14 +17,24 @@ export default { required: true }, showNew: Boolean, - showTable: Boolean + showTable: Boolean, + messageLayout: { + type: String, + default: 'twoColumnsTableLeft', + validator(value) { + return [ + 'twoColumnsTableLeft', + 'listTableTop' + ].includes(value) + } + }, }, data() { return {} }, template: `
-

endpoint: {{endpoint}}

+

endpoint Messages.js: {{endpoint}}

diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Messages.js b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js index 7bd6d4b4d..e9f542945 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Messages.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js @@ -14,12 +14,11 @@ export default { endpoint="$fhcApi.factory.messages.person" type-id="person_id" :id="modelValue.person_id" + messageLayout="listTableTop" show-table > - -
` }; \ No newline at end of file diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index f25cc72ec..95a505a23 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -37319,6 +37319,206 @@ array( ) ) ), + array( + 'app' => 'core', + 'category' => 'messages', + 'phrase' => 'unread', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'ungelesen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'unread', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'messages', + 'phrase' => 'read', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'gelesen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'read', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'messages', + 'phrase' => 'archived', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'archiviert', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'archived', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'messages', + 'phrase' => 'deleted', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'gelöscht', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'deleted', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'messages', + 'phrase' => 'body', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Nachrichtentext', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Body', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'messages', + 'phrase' => 'message_id', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Message ID', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Message ID', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'messages', + 'phrase' => 'sender', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'SenderIn', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Sender', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'messages', + 'phrase' => 'recipient', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'EmpfängerIn', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Recipient', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'messages', + 'phrase' => 'senderId', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'SenderIn ID', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Sender ID', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'messages', + 'phrase' => 'recipientId', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'EmpfängerIn ID', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Recipient ID', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), /////////// FHC4 Phrases Messages END /////////// ); From f89c194d3288d83aec44082fd1f8db4b7010618c Mon Sep 17 00:00:00 2001 From: ma0068 Date: Wed, 19 Feb 2025 11:36:00 +0100 Subject: [PATCH 005/139] add Vorlagendropdown Component and Listboxes for Messaging Variables --- .../api/frontend/v1/messages/Messages.php | 246 +++++++++- .../api/frontend/v1/vorlagen/Vorlagen.php | 63 +++ application/models/system/Message_model.php | 42 ++ application/models/system/Vorlage_model.php | 116 +++++ public/js/api/fhcapifactory.js | 4 +- public/js/api/messages/person.js | 29 ++ public/js/api/vorlagen.js | 8 + .../components/Messages/Details/NewMessage.js | 440 +++++++++++++++++- .../Messages/Details/TableMessages.js | 53 ++- public/js/components/Messages/Messages.js | 6 +- .../Studentenverwaltung/Details/Messages.js | 7 +- .../VorlagenDropdown/VorlagenDropdown.js | 109 +++++ system/phrasesupdate.php | 20 + 13 files changed, 1123 insertions(+), 20 deletions(-) create mode 100644 application/controllers/api/frontend/v1/vorlagen/Vorlagen.php create mode 100644 public/js/api/vorlagen.js create mode 100644 public/js/components/VorlagenDropdown/VorlagenDropdown.js diff --git a/application/controllers/api/frontend/v1/messages/Messages.php b/application/controllers/api/frontend/v1/messages/Messages.php index adf1d52e9..ac107f687 100644 --- a/application/controllers/api/frontend/v1/messages/Messages.php +++ b/application/controllers/api/frontend/v1/messages/Messages.php @@ -9,6 +9,14 @@ class Messages extends FHCAPI_Controller { parent::__construct([ 'getMessages' => ['admin:r', 'assistenz:r'], + 'getVorlagen' => ['admin:r', 'assistenz:r'], + 'getMessageVarsPerson' => ['admin:r', 'assistenz:r'], + 'getMsgVarsPrestudent' => ['admin:r', 'assistenz:r'], + 'getMsgVarsLoggedInUser' => ['admin:r', 'assistenz:r'], + 'getNameOfDefaultRecipient' => ['admin:r', 'assistenz:r'], + 'sendMessage' => ['admin:r', 'assistenz:r'], + 'deleteMessage' => ['admin:r', 'assistenz:r'], + 'getVorlagentext' => ['admin:r', 'assistenz:r'], ]); //Load Models @@ -20,6 +28,7 @@ class Messages extends FHCAPI_Controller // Load Libraries $this->load->library('VariableLib', ['uid' => getAuthUID()]); $this->load->library('form_validation'); + $this->load->library('MessageLib'); // Load language phrases $this->loadPhrases([ @@ -29,11 +38,17 @@ class Messages extends FHCAPI_Controller public function getMessages($id, $type_id) { - //$this->terminateWithError("in backend " . $type_id . ": " . $id, self::ERROR_TYPE_GENERAL); - - if ($type_id != "person_id") + switch($type_id) { - $this->terminateWithError("logic for type_id " . $type_id . " not defined yet", self::ERROR_TYPE_GENERAL); + case 'uid': + $id = $this->_getPersonIdFromUid($id); + break; + case 'person_id': + $id = $id; + break; + default: + $this->terminateWithError("MESSAGES::getMessages logic for type_id " . $type_id . " not defined yet", self::ERROR_TYPE_GENERAL); + break; } $result = $this->MessageModel->getMessagesForTable($id); @@ -42,4 +57,227 @@ class Messages extends FHCAPI_Controller $this->terminateWithSuccess($data); } + + public function getVorlagen() + { + //get oe of user + $uid = getAuthUID(); + $this->load->model('person/Benutzerfunktion_model', 'BenutzerfunktionModel'); + $result = $this->BenutzerfunktionModel->getBenutzerfunktionByUid($uid, 'oezuordnung'); + + $data = $this->getDataOrTerminateWithError($result); + $oe_kurzbz = current($data); + + // $this->terminateWithError("oe: ". $oe_kurzbz->oe_kurzbz, self::ERROR_TYPE_GENERAL); + + $this->load->model('system/Vorlage_model', 'VorlageModel'); + + //39 Stück Variante OE + $result = $this->VorlageModel->getAllVorlagenByOe($oe_kurzbz->oe_kurzbz); + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + + //IF ADMIN 167 + $this->VorlageModel->addOrder('vorlage_kurzbz', 'ASC'); + //only HTML-vorlagen -> for admin + $result = $this->VorlageModel->loadWhere( + array( + 'mimetype' => 'text/html' + )); + + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getVorlagentext($vorlage_kurzbz) + { + //$this->terminateWithError("vor " . $vorlage_kurzbz, self::ERROR_TYPE_GENERAL); + //$studiengang_kz = 227; //TODO(Manu) check dynamisieren NULL + $studiengang_kz = 0; + $this->load->model('system/Vorlagestudiengang_model', 'VorlagestudiengangModel'); + $this->VorlagestudiengangModel->addOrder('version', 'DESC'); + + $result = $this->VorlagestudiengangModel->loadWhere( + [ + 'vorlage_kurzbz' =>$vorlage_kurzbz, + 'studiengang_kz' => $studiengang_kz + ]); + + $data = $this->getDataOrTerminateWithError($result); + + //not correct with Vorlage + $vorlage = current($data); + + //$this->terminateWithSuccess($data); + $this->terminateWithSuccess($vorlage->text); + } + + public function getMessageVarsPerson() + { + $result = $this->MessageModel->getMessageVarsPerson(); + + $data = $this->getDataOrTerminateWithError($result); + + + $this->terminateWithSuccess($data); + } + + public function getMsgVarsPrestudent($uid) + { + + $prestudent_id = $this-> _getPrestudentIdFromUid($uid); + + // $this->terminateWithError("prestudent_id " . $prestudent_id, self::ERROR_TYPE_GENERAL); + + $result = $this->MessageModel->getMsgVarsDataByPrestudentId($prestudent_id); + + $data = $this->getDataOrTerminateWithError($result); + + + $this->terminateWithSuccess($data); + } + + public function getMsgVarsLoggedInUser() + { + $uid = getAuthUID(); + + $result = $this->MessageModel->getMsgVarsLoggedInUser(); + + $data = $this->getDataOrTerminateWithError($result); + + + $this->terminateWithSuccess($data); + } + + public function getNameOfDefaultRecipient($id, $type_id) + { + switch($type_id) + { + case 'uid': + $id = $this->_getPersonIdFromUid($id); + break; + case 'person_id': + $id = $id; + break; + default: + $this->terminateWithError("MESSAGES::getNameOfDefaultRecipient logic for type_id " . $type_id . " not defined yet", self::ERROR_TYPE_GENERAL); + break; + } + + $this->load->model('person/Person_model', 'PersonModel'); + + $result = $this->PersonModel->load($id); + //$this->terminateWithSuccess($result); + $data = $this->getDataOrTerminateWithError($result); + $name = current($data); + + $this->terminateWithSuccess($name->vorname . " " . $name->nachname ); + } + + public function sendMessage($recipient_id) + { + //TODO(manu) Problems with Vorlagen... + //TODO(Manu) Problems with VARS + $receiversPersonId = $this->_getPersonIdFromUid($recipient_id); + + $uid = getAuthUID(); + $this->load->model('person/Benutzer_model', 'BenutzerModel'); + $result = $this->BenutzerModel->loadWhere( + ['uid' => $uid] + ); + + $data = $this->getDataOrTerminateWithError($result); + $benutzer = current($data); + + if (isset($_POST['data'])) + { + $data = json_decode($_POST['data']); + unset($_POST['data']); + foreach ($data as $k => $v) { + $_POST[$k] = $v; + } + } + + $subject = $this->input->post('subject'); + + $body = $this->input->post('body'); + + // $this->terminateWithError("rp_id " . $receiversPersonId, self::ERROR_TYPE_GENERAL); + +/* $subject = $this->input->post('subject'); + + $formData = $this->input->post('data');*/ + + //$_POST['subject'] = $formData['subject']; + // $subject = $formData['subject']; + // $body = $formData['body']; + + // $subject = isset($_POST['subject']) ? $_POST['subject'] : null; + // $body = isset($_POST['body']) ? $_POST['body'] : null; + + // $this->terminateWithError("person_id " . $receiversPersonId, self::ERROR_TYPE_GENERAL); + + // $this->terminateWithError("subject " . $subject, self::ERROR_TYPE_GENERAL); + // $this->terminateWithError("body " . $body, self::ERROR_TYPE_GENERAL); + + // $this->terminateWithError("person_id " . $benutzer->person_id, self::ERROR_TYPE_GENERAL); + // $this->terminateWithError("subject " . $subject, self::ERROR_TYPE_GENERAL); + $result = $this->messagelib->sendMessageUser($receiversPersonId, $subject, $body, $benutzer->person_id); + + $this->terminateWithSuccess($result); + } + + public function deleteMessage($messageId) + { + // Start DB transaction + $this->db->trans_begin(); + + $result = $this->MessageModel->deleteMessageRecipient($messageId); + if (isError($result)) { + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + + $result = $this->MessageModel->deleteMessageStatus($messageId); + if (isError($result)) { + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + + $result = $this->MessageModel->deleteMessage($messageId); + if (isError($result)) { + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + + $this->db->trans_commit(); + + $this->terminateWithSuccess($result); + } + + private function _getPersonIdFromUid($uid) + { + $this->load->model('person/Benutzer_model', 'BenutzerModel'); + $result = $this->BenutzerModel->loadWhere( + ['uid' => $uid] + ); + + $data = $this->getDataOrTerminateWithError($result); + $benutzer = current($data); + + return $benutzer->person_id; + } + + private function _getPrestudentIdFromUid($uid) + { + $this->load->model('crm/Student_model', 'StudentModel'); + $result = $this->StudentModel->loadWhere( + ['student_uid' => $uid] + ); + + $data = $this->getDataOrTerminateWithError($result); + $student = current($data); + + return $student->prestudent_id; + } } \ No newline at end of file diff --git a/application/controllers/api/frontend/v1/vorlagen/Vorlagen.php b/application/controllers/api/frontend/v1/vorlagen/Vorlagen.php new file mode 100644 index 000000000..01edb33d1 --- /dev/null +++ b/application/controllers/api/frontend/v1/vorlagen/Vorlagen.php @@ -0,0 +1,63 @@ + ['admin:r', 'assistenz:r'], + 'getVorlagenByLoggedInUser' => ['admin:r', 'assistenz:r'], + ]); + + //Load Models + $this->load->model('system/Vorlage_model', 'VorlageModel'); + + // Additional Permission Checks + //TODO(manu) check permissions + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + $this->load->library('form_validation'); + $this->load->library('VorlageLib'); + + // Load language phrases + $this->loadPhrases([ + 'ui' + ]); + } + + public function getVorlagen() + { + $this->load->model('system/Vorlage_model', 'VorlageModel'); + + $this->VorlageModel->addOrder('vorlage_kurzbz', 'ASC'); + + $result = $this->VorlageModel->loadWhere( + array( + 'mimetype' => 'text/html' + )); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getVorlagenByLoggedInUser() + { + //get oe of user + $uid = getAuthUID(); + $this->load->model('person/Benutzerfunktion_model', 'BenutzerfunktionModel'); + $result = $this->BenutzerfunktionModel->getBenutzerfunktionByUid($uid, 'oezuordnung'); + + $data = $this->getDataOrTerminateWithError($result); + $oe_kurzbz = current($data); + + $result = $this->VorlageModel->getAllVorlagenByOe($oe_kurzbz->oe_kurzbz); + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + +} \ No newline at end of file diff --git a/application/models/system/Message_model.php b/application/models/system/Message_model.php index 1b201fc1b..7ecb54a9e 100644 --- a/application/models/system/Message_model.php +++ b/application/models/system/Message_model.php @@ -282,4 +282,46 @@ class Message_model extends DB_Model return $this->execQuery($sql, $parametersArray); } + + /** + * Deletes a messages from tableMessages and tbl_msg_recipient + * TODO(MANU) CHECK IF NECESSARY + * dependency with other tables + * in case of reply... more messages + * maybe anonimize it + * @param $message_id + * @return boolean success + */ + public function deleteMessageRecipient($message_id) + { + $sql = " + DELETE FROM public.tbl_msg_recipient + WHERE message_id = ?; + "; + + return $this->execQuery($sql, array($message_id)); + } + + + public function deleteMessageStatus($message_id) + { + $sql = " + DELETE FROM public.tbl_msg_status + WHERE message_id = ?; + "; + + return $this->execQuery($sql, array($message_id)); + } + + public function deleteMessage($message_id) + { + $sql = " + DELETE FROM public.tbl_msg_message + WHERE message_id = ?; + "; + + return $this->execQuery($sql, array($message_id)); + } + + } diff --git a/application/models/system/Vorlage_model.php b/application/models/system/Vorlage_model.php index 8022e71fc..69aa0aa3f 100644 --- a/application/models/system/Vorlage_model.php +++ b/application/models/system/Vorlage_model.php @@ -21,4 +21,120 @@ class Vorlage_model extends DB_Model return $this->execQuery($query); } + + /** + * Returns all Vorlagen + * that belongs to the organisation units of the user + * and the parents of those organisation units until the root of the + * @param Array Array of $oe_kurzbz + * @return object Array of Vorlagen + */ + public function getAllVorlagenByOe($oe_kurzbz) + { + // Loads library OrganisationseinheitLib + $this->load->library('OrganisationseinheitLib'); + + $vorlage = success(array()); // Default value + + $table = '( + SELECT v.vorlage_kurzbz, + v.bezeichnung, + vs.version, + vs.oe_kurzbz, + vs.aktiv, + vs.subject, + vs.text, + v.mimetype + FROM tbl_vorlagestudiengang vs + JOIN tbl_vorlage v USING(vorlage_kurzbz) + ) templates'; + + $alias = 'templates'; + + $fields = array( + 'templates.vorlage_kurzbz AS id', + 'templates.bezeichnung || \' (\' || UPPER(templates.oe_kurzbz) || \')\' AS description' + ); + + $where = 'templates.aktiv = TRUE + AND templates.subject IS NOT NULL + AND templates.text IS NOT NULL + AND templates.mimetype = \'text/html\' + GROUP BY 1, 2, 3'; + + $order_by = 'description ASC'; + + if (!is_array($oe_kurzbz)) + { + $vorlage = $this->organisationseinheitlib->treeSearchEntire( + $table, + $alias, + $fields, + $where, + $order_by, + $oe_kurzbz + ); + } + else // is an array + { + // Get the vorlage for each organisation unit + foreach($oe_kurzbz as $val) + { + $tmpVorlage = $this->organisationseinheitlib->treeSearchEntire( + $table, + $alias, + $fields, + $where, + $order_by, + $val + ); + + // Everything is ok and data are inside + if (hasData($tmpVorlage)) + { + // If it's the first vorlage copy it + if (!hasData($vorlage)) + { + for ($j = 0; $j < count(getData($tmpVorlage)); $j++) + { + if (getData($tmpVorlage)[$j]->id != '') + { + array_push($vorlage->retval, getData($tmpVorlage)[$j]); + } + } + } + else // checks for duplicates, if it's not already present push it into the array getData($vorlage) + { + for ($j = 0; $j < count(getData($tmpVorlage)); $j++) + { + $found = false; + $currentTmpVorlageData = null; + + for ($i = 0; $i < count(getData($vorlage)); $i++) + { + $currentTmpVorlageData = getData($tmpVorlage)[$j]; + + if (getData($vorlage)[$i]->id == getData($tmpVorlage)[$j]->id + && getData($vorlage)[$i]->_pk == getData($tmpVorlage)[$j]->_pk + && getData($vorlage)[$i]->_ppk == getData($tmpVorlage)[$j]->_ppk + && getData($vorlage)[$i]->_jtpk == getData($tmpVorlage)[$j]->_jtpk) + { + $found = true; + break; + } + } + + if (!$found && $currentTmpVorlageData->id != '') + { + array_push($vorlage->retval, $currentTmpVorlageData); + } + } + } + } + } + } + + return $vorlage; + } + } diff --git a/public/js/api/fhcapifactory.js b/public/js/api/fhcapifactory.js index 7bc510b6e..8a4a2132a 100644 --- a/public/js/api/fhcapifactory.js +++ b/public/js/api/fhcapifactory.js @@ -34,6 +34,7 @@ import cms from "./cms.js"; import lehre from "./lehre.js"; import addons from "./addons.js"; import messages from "./messages.js"; +import vorlagen from "./vorlagen.js"; export default { search, @@ -54,5 +55,6 @@ export default { cms, lehre, addons, - messages + messages, + vorlagen }; diff --git a/public/js/api/messages/person.js b/public/js/api/messages/person.js index baf8bd39f..6a0ac8c7c 100644 --- a/public/js/api/messages/person.js +++ b/public/js/api/messages/person.js @@ -2,4 +2,33 @@ export default { getMessages(url, config, params){ return this.$fhcApi.get('api/frontend/v1/messages/messages/getMessages/' + params.id + '/' + params.type); }, + getVorlagen(){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getVorlagen/'); + }, + getMsgVarsLoggedInUser(){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getMsgVarsLoggedInUser/'); + }, + getMessageVarsPerson(){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getMessageVarsPerson/'); + }, + getMsgVarsPrestudent(uid){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getMsgVarsPrestudent/' + uid); + }, + getVorlagentext(vorlage_kurzbz){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getVorlagentext/' + vorlage_kurzbz); + }, + getNameOfDefaultRecipient(params){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getNameOfDefaultRecipient/' + params.id + '/' + params.type_id); + }, + sendMessage(form, id, data) { + console.log("factory " + id); + console.log(JSON.stringify(data)); + + return this.$fhcApi.post(form, 'api/frontend/v1/messages/messages/sendMessage/' + id, + data + ); + }, + deleteMessage(messageId){ + return this.$fhcApi.post('api/frontend/v1/messages/messages/deleteMessage/' + messageId); + } } \ No newline at end of file diff --git a/public/js/api/vorlagen.js b/public/js/api/vorlagen.js new file mode 100644 index 000000000..2933ccf97 --- /dev/null +++ b/public/js/api/vorlagen.js @@ -0,0 +1,8 @@ +export default { + getVorlagen() { + return this.$fhcApi.get('api/frontend/v1/vorlagen/vorlagen/getVorlagen/'); + }, + getVorlagenByLoggedInUser() { + return this.$fhcApi.get('api/frontend/v1/vorlagen/vorlagen/getVorlagenByLoggedInUser/'); + } +} \ No newline at end of file diff --git a/public/js/components/Messages/Details/NewMessage.js b/public/js/components/Messages/Details/NewMessage.js index bf60842d2..2d85c8e00 100644 --- a/public/js/components/Messages/Details/NewMessage.js +++ b/public/js/components/Messages/Details/NewMessage.js @@ -1,12 +1,448 @@ +import FormForm from '../../Form/Form.js'; +import FormInput from '../../Form/Input.js'; +import ListBox from "../../../../../index.ci.php/public/js/components/primevue/listbox/listbox.esm.min.js"; +import DropdownComponent from '../../VorlagenDropdown/VorlagenDropdown.js'; + + export default { + components: { + FormForm, + FormInput, + ListBox, + DropdownComponent + }, + props: { + endpoint: { + type: String, + required: true + }, + typeId: String, + id: { + type: [Number, String], + required: true + }, + }, data(){ return { - + formData: { + recipient: this.id, + subject: null, + body: null, + vorlage_kurzbz: null, + selectedValue: '', + }, + statusNew: true, + vorlagen: [], + defaultRecipient: null, + editor: null, + isVisible: true, + fieldsUser: [], + fieldsPerson: [], + fieldsPrestudent: [], + selectedFieldPrestudent: null, + selectedFieldUser: null, + selectedFieldPerson: null, + itemsPrestudent: [], + itemsPerson: [], + itemsUser: [], + selectedFieldStudent: null, + itemsStudent: [ + { label: "Variable 1", value: "var1" }, + { label: "Variable 2", value: "var2" }, + { label: "Variable 3", value: "var3" } + ] } }, + methods: { + initTinyMCE() { + const vm = this; + tinymce.init({ + target: this.$refs.editor.$refs.input, //Important: not selector: to enable multiple import of component + //height: 800, + //plugins: ['lists'], + toolbar: 'styleselect | bold italic underline | alignleft aligncenter alignright alignjustify', + style_formats: [ + {title: 'Blocks', block: 'div'}, + {title: 'Paragraph', block: 'p'}, + {title: 'Heading 1', block: 'h1'}, + {title: 'Heading 2', block: 'h2'}, + {title: 'Heading 3', block: 'h3'}, + {title: 'Heading 4', block: 'h4'}, + {title: 'Heading 5', block: 'h5'}, + {title: 'Heading 6', block: 'h6'}, + ], + autoresize_bottom_margin: 16, + + setup: (editor) => { + vm.editor = editor; + + editor.on('input', () => { + const newContent = editor.getContent(); + vm.formData.body = newContent; + }); + }, + }); + }, + updateText(value) { + this.formData.body = value; + }, + sendMessage(){ + //TODO(Manu) check default recipient(s) + const data = new FormData(); + + data.append('data', JSON.stringify(this.formData)); + return this.$fhcApi.factory.messages.person.sendMessage(this.$refs.formVorlage, this.id, data) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); + //this.hideModal('messageModal'); + this.resetForm(); + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + //this.resetForm(); + //closeModal + //closewindwo + } + ); + }, + getVorlagentext(vorlage_kurzbz){ + //console.log(typeof vorlage_kurzbz); + return this.$fhcApi.factory.messages.person.getVorlagentext(vorlage_kurzbz) + .then(response => { + //this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); + //this.hideModal('messageModal'); + //this.resetForm(); + //TODO(Manu) CHECK + this.formData.body = response.data; + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + //this.resetForm(); + //closeModal + //closewindwo + }); + }, + insertVariable(selectedItem){ + if (this.editor) { + this.editor.insertContent(selectedItem.value + " "); + } else { + console.error("Editor instance is not available."); + } + }, + //TODO(Manu) refactor +/* insertVariablePrestudent() { + if (this.editor) { + //const lastVariable = this.selectedFieldsPrestudent[this.selectedFieldsPrestudent.length - 1].value; + const lastVariable = this.selectedFieldPrestudent.value; + + //Use insertContent method + this.editor.insertContent(lastVariable + " "); + } else { + console.error("Editor instance is not available."); + } + },*/ +/* insertVariablePrestudentByClick(selectedItem) { + + if (selectedItem) { + this.editor.insertContent(selectedItem.value + " "); + console.log("Eingefügte Variable:", selectedItem); + } else { + console.warn("Keine Variable ausgewählt!"); + } + }, + + insertVariablePerson() { + if (this.editor) { + //const lastVariable = this.selectedFieldsPrestudent[this.selectedFieldsPrestudent.length - 1].value; + const lastVariable = this.selectedFieldPerson.value; + + //Use insertContent method + this.editor.insertContent(lastVariable + " "); + } else { + console.error("Editor instance is not available."); + } + }, + insertVariableUser() { + if (this.editor) { + console.log(this.selectedFieldUser.value); + const lastVariable = this.selectedFieldUser.value; + + //Multiple + //const lastVariable = this.selectedFieldsPrestudent[this.selectedFieldsPrestudent.length - 1].value; + + //Use insertContent method + this.editor.insertContent(lastVariable + " "); + this.selectedFieldUser = null; + } else { + console.error("Editor instance is not available."); + } + }, + insertVariableStudent(selectedItem) { + if (selectedItem) { + console.log("Eingefügte Variable:", selectedItem); + this.editor.insertContent(selectedItem.value + " "); + } else { + console.warn("Keine Variable ausgewählt!"); + } + },*/ + replyMessage(message_id){ + console.log("auf message " + message_id + " antworten"); + }, + resetForm(){ + this.formData = { + vorlage_kurzbz: null, + body: null, + subject: null, + }; + if (this.editor) { + this.editor.setContent(""); + } + this.$refs.dropdownComp.setValue(null); + + }, + toggleDivNewMessage(){ + this.isVisible = !this.isVisible; + }, + handleSelectedVorlage(vorlage_kurzbz) { + if (typeof vorlage_kurzbz === "string") { + this.getVorlagentext(vorlage_kurzbz); + this.formData.subject = vorlage_kurzbz; + } + }, + }, + watch: { + 'formData.body': { + handler(newVal) { + const tinymcsVal = this.editor.getContent(); + + if (newVal && tinymcsVal != newVal) { + //Inhalt des Editors aktualisieren + this.editor.setContent(newVal); + } + } + }, + 'formData.vorlage_kurzbz': { + handler(newVal){ + // console.log("Vorlage: " + newVal); + + if (newVal && newVal != null) { + this.formData.subject = newVal; + return this.getVorlagentext(newVal); + } + //TODO(Manu) own function or retval to getVorlagentext + //component VorlagenComponent + + } + } + }, + created(){ + + if(this.typeId == 'person_id'){ + this.$fhcApi.factory.messages.person.getMessageVarsPerson() + .then(result => { + this.fieldsPerson = result.data; + this.itemsPerson = Object.entries(this.fieldsPerson).map(([key, value]) => ({ + label: value, + value: '{' + value + '}' + })); + }) + .catch(this.$fhcAlert.handleSystemError); + } + + if(this.typeId == 'uid') { + this.$fhcApi.factory.messages.person.getMsgVarsPrestudent(this.id) + .then(result => { + this.fieldsPrestudent = result.data; + const prestudent = this.fieldsPrestudent[0]; + //Just for testing with inserting values +/* this.itemsPrestudent = Object.entries(prestudent).map(([key, value]) => ({ + label: key, + value: value + }));*/ + this.itemsPrestudent = Object.entries(prestudent).map(([key, value]) => ({ + label: key, + value: '{' + key + '}' + })); + }) + .catch(this.$fhcAlert.handleSystemError); + } + + this.$fhcApi.factory.messages.person.getMsgVarsLoggedInUser() + .then(result => { + this.fieldsUser = result.data; + const user = this.fieldsUser; + this.itemsUser = Object.entries(user).map(([key, value]) => ({ + label: value, + value: '{' + value + '}' + })); + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$fhcApi.factory.messages.person.getNameOfDefaultRecipient({ + id: this.id, + type_id: this.typeId}) + .then(result => { + this.defaultRecipient = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + async mounted() { + this.initTinyMCE(); + }, + beforeDestroy() { + this.editor.destroy(); + }, template: `
-

New Message

+ +
+

New Message

+ + {{typeId}} {{id}} + + {{formData.subject}} + {{formData.vorlage_kurzbz}} + +

+ formData.body befüllt +

+ +
+ +
+ + + +
+ + + +
+ +
+ + +
+ + +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+ Felder Prestudent +
+ + + + + +
+ + +

{{selectedFieldPrestudent}}

+ +
+ +
+ Felder Person +
+ + + + + +
+ +

{{selectedFieldPerson}}

+
+ +
+ Meine Felder +
+ + + + + +
+ +
+ + +
+ + + + + +
+ +
+ +
+
+ +
+ +
` diff --git a/public/js/components/Messages/Details/TableMessages.js b/public/js/components/Messages/Details/TableMessages.js index c4fd4d4d7..0025d7b47 100644 --- a/public/js/components/Messages/Details/TableMessages.js +++ b/public/js/components/Messages/Details/TableMessages.js @@ -1,12 +1,15 @@ import {CoreFilterCmpt} from "../../filter/Filter.js"; import FormForm from '../../Form/Form.js'; -//import FormInput from '../../Form/Input.js'; export default { components: { CoreFilterCmpt, FormForm, - // FormInput + }, + inject: { + cisRoot: { + from: 'cisRoot' + }, }, props: { endpoint: { @@ -121,7 +124,7 @@ export default { button.addEventListener( 'click', () => - this.deleteMessage(cell.getData().message_id) + this.actionDeleteMessage(cell.getData().message_id) ); container.append(button); @@ -197,7 +200,6 @@ export default { const selectedMessage = row.getData().message_id; const body = row.getData().body; this.previewBody = body; - console.log(selectedMessage); } }, ], @@ -209,11 +211,45 @@ export default { reply(message_id){ console.log("in reply " + message_id); }, + actionDeleteMessage(message_id){ + this.$fhcAlert + .confirmDelete() + .then(result => result + ? message_id + : Promise.reject({handled: true})) + .then(this.deleteMessage) + .catch(this.$fhcAlert.handleSystemError); + }, deleteMessage(message_id){ - console.log("deleteMessage " + message_id); + // console.log("deleteMessage " + message_id); + return this.$fhcApi.factory.messages.person.deleteMessage(message_id) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); + }).catch(this.$fhcAlert.handleSystemError) + .finally(()=> { + window.scrollTo(0, 0); + this.reload(); + }); }, actionNewMessage(){ - console.log("action new message"); + //console.log("action new message"); + if (this.openMode == "window") { + console.log("openInNewWindow") + const linkWindowNewMessage = this.cisRoot + '/public/js/components/Messages/Details/NewMessage.js'; + window.open(linkWindowNewMessage, '_blank'); + } + else if (this.openmode == "modal"){ + console.log("open with bootstrap Modal"); + } + else if (this.openmode == "showDiv"){ + console.log("open div in NewMessage.js"); + //emit to NewMessage.js + } + else + console.log("no valid openmode: yet to be developed"); + }, + reload() { + this.$refs.table.reloadTable(); }, }, computed: { @@ -238,8 +274,9 @@ export default { }, template: `
-

endpoint: {{endpoint}}

-

{{messageLayout}}

+ + +
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Messages.js b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js index e9f542945..14d74e56c 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Messages.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js @@ -12,10 +12,11 @@ export default { diff --git a/public/js/components/VorlagenDropdown/VorlagenDropdown.js b/public/js/components/VorlagenDropdown/VorlagenDropdown.js new file mode 100644 index 000000000..e4c48501a --- /dev/null +++ b/public/js/components/VorlagenDropdown/VorlagenDropdown.js @@ -0,0 +1,109 @@ +import {CoreFilterCmpt} from "../filter/Filter.js"; +import FormForm from '../Form/Form'; +import FormInput from '../Form/Input.js'; + +export default { + components: { + FormForm, + FormInput, + CoreFilterCmpt + }, + props: { + label: { + type: String, + required: true + }, + modelValue: { + type: String, + required: true + }, +/* oe: { + type: Array, + required: false + }, */ + isAdmin: { + type: Boolean, + required: true + }, + useLoggedInUserOe: { + type: Boolean, + required: true + } + }, + data() { + return { + vorlagen: [], + selectedValue: null, + vorlagenOe: [] + } + }, + methods: { + updateValue() { + // console.log("in COMPO: update: " + this.selectedValue + ' jetzt ' + 'InfocenterMailErgaenzungsprfEng'); + this.$emit('change', this.selectedValue); + //this.$emit('change', this.selectedValue); // Emit-Event beim Ändern des Wertes + }, + setValue(value) { + this.selectedValue = value; + }, + }, + created() { + + if(this.isAdmin) { + this.$fhcApi.factory.vorlagen.getVorlagen() + .then(result => { + this.vorlagen = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + } + + if(this.useLoggedInUserOe){ + this.$fhcApi.factory.vorlagen.getVorlagenByLoggedInUser() + .then(result => { + console.log(this.vorlagenOe); + this.vorlagenOe = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + } + }, +template: ` +
+
+ + + +
+ +
+ + + +
+ +
+ `, +} \ No newline at end of file diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 95a505a23..63cf34038 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -37519,6 +37519,26 @@ array( ) ) ), + array( + 'app' => 'core', + 'category' => 'ui', + 'phrase' => 'successSent', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Nachricht erfolgreich versandt', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Message sent successfully', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), /////////// FHC4 Phrases Messages END /////////// ); From b989eae461b52e2b7f89d6b4d5794f64fae4722f Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Thu, 20 Feb 2025 20:07:07 +0100 Subject: [PATCH 006/139] added archive tab to Studierendenverwaltung, possibility to archive documents --- application/config/javascript.php | 4 +- .../controllers/api/frontend/v1/Documents.php | 83 +++++- .../api/frontend/v1/stv/Archiv.php | 202 +++++++++++++++ .../api/frontend/v1/stv/Config.php | 17 +- application/models/crm/Akte_model.php | 10 +- application/models/system/Vorlage_model.php | 12 +- public/js/api/stv.js | 2 + public/js/api/stv/archiv.js | 30 +++ .../Stv/Studentenverwaltung/Details/Archiv.js | 241 ++++++++++++++++++ system/phrasesupdate.php | 40 +++ 10 files changed, 625 insertions(+), 16 deletions(-) create mode 100644 application/controllers/api/frontend/v1/stv/Archiv.php create mode 100644 public/js/api/stv/archiv.js create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Archiv.js diff --git a/application/config/javascript.php b/application/config/javascript.php index 5e9aa270a..bfcf8d540 100644 --- a/application/config/javascript.php +++ b/application/config/javascript.php @@ -2,6 +2,6 @@ if (! defined('BASEPATH')) exit('No direct script access allowed'); // use vuejs dev version -$config['use_vuejs_dev_version'] = false; +$config['use_vuejs_dev_version'] = true; // use bundled javascript -$config['use_bundled_javascript'] = false; \ No newline at end of file +$config['use_bundled_javascript'] = false; diff --git a/application/controllers/api/frontend/v1/Documents.php b/application/controllers/api/frontend/v1/Documents.php index 60010e14d..42a2d3433 100644 --- a/application/controllers/api/frontend/v1/Documents.php +++ b/application/controllers/api/frontend/v1/Documents.php @@ -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,34 @@ 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 + * @return object success or error + */ + 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 +206,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 +227,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 +375,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 +471,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 + ] + ]; } } diff --git a/application/controllers/api/frontend/v1/stv/Archiv.php b/application/controllers/api/frontend/v1/stv/Archiv.php new file mode 100644 index 000000000..dc93c2c4c --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Archiv.php @@ -0,0 +1,202 @@ +. + */ + +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', 'assistenz: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*/ + } + + + /** + * 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(); + } +} diff --git a/application/controllers/api/frontend/v1/stv/Config.php b/application/controllers/api/frontend/v1/stv/Config.php index c77ebc07b..2cc2228c9 100644 --- a/application/controllers/api/frontend/v1/stv/Config.php +++ b/application/controllers/api/frontend/v1/stv/Config.php @@ -91,6 +91,7 @@ class Config extends FHCAPI_Controller 'title' => $this->p->t('stv', 'tab_resources'), 'component' => './Stv/Studentenverwaltung/Details/Betriebsmittel.js' ]; + /* TODO(chris): Ausgeblendet für Testing $result['grades'] = [ 'title' => $this->p->t('stv', 'tab_grades'), 'component' => './Stv/Studentenverwaltung/Details/Noten.js', @@ -103,7 +104,14 @@ class Config extends FHCAPI_Controller 'documentslist' => $this->gradesDocumentsList() ] ]; - + */ + $result['archive'] = [ + 'title' => $this->p->t('stv', 'tab_archive'), + 'component' => './Stv/Studentenverwaltung/Details/Archiv.js' + //~ 'config' => [ + //~ //'columns' => $this->kontoColumns() + //~ ] + ]; Events::trigger('stv_conf_student', function & () use (&$result) { return $result; @@ -138,6 +146,13 @@ class Config extends FHCAPI_Controller 'changeStatusToAbsolvent' => $this->permissionlib->isBerechtigt('admin') ] ]; + $result['archive'] = [ + 'title' => $this->p->t('stv', 'tab_archive'), + 'component' => './Stv/Studentenverwaltung/Details/Archiv.js' + //~ 'config' => [ + //~ //'columns' => $this->kontoColumns() + //~ ] + ]; Events::trigger('stv_conf_students', function & () use (&$result) { return $result; diff --git a/application/models/crm/Akte_model.php b/application/models/crm/Akte_model.php index 57b6e0665..2fa69d5b0 100644 --- a/application/models/crm/Akte_model.php +++ b/application/models/crm/Akte_model.php @@ -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 ]); } diff --git a/application/models/system/Vorlage_model.php b/application/models/system/Vorlage_model.php index 8022e71fc..d36eedba3 100644 --- a/application/models/system/Vorlage_model.php +++ b/application/models/system/Vorlage_model.php @@ -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); + } } diff --git a/public/js/api/stv.js b/public/js/api/stv.js index 9a2f08f1d..b0f96415b 100644 --- a/public/js/api/stv.js +++ b/public/js/api/stv.js @@ -3,6 +3,7 @@ import students from './stv/students.js'; import filter from './stv/filter.js'; import konto from './stv/konto.js'; import grades from './stv/grades.js'; +import archiv from './stv/archiv.js'; export default { verband, @@ -10,6 +11,7 @@ export default { filter, konto, grades, + archiv, configStudent() { return this.$fhcApi.get('api/frontend/v1/stv/config/student'); }, diff --git a/public/js/api/stv/archiv.js b/public/js/api/stv/archiv.js new file mode 100644 index 000000000..0f303684b --- /dev/null +++ b/public/js/api/stv/archiv.js @@ -0,0 +1,30 @@ +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/archiveSigned', + data + ); + }, + //~ edit(data) { + //~ return this.$fhcApi.post('api/frontend/v1/stv/konto/update', data); + //~ }, + delete({akte_id, studiengang_kz}) { + return this.$fhcApi.post('api/frontend/v1/stv/archiv/delete', {akte_id, studiengang_kz}); + } +}; diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Archiv.js b/public/js/components/Stv/Studentenverwaltung/Details/Archiv.js new file mode 100644 index 000000000..7858dbd5e --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Archiv.js @@ -0,0 +1,241 @@ +import {CoreFilterCmpt} from "../../../filter/Filter.js"; +import FormInput from "../../../Form/Input.js"; +//~ import KontoNew from "./Konto/New.js"; +//~ import KontoEdit from "./Konto/Edit.js"; + +export default { + components: { + CoreFilterCmpt, + FormInput + //~ KontoNew, + //~ KontoEdit + }, + inject: { + defaultSemester: { + from: 'defaultSemester' + } + }, + props: { + modelValue: Object, + config: { + type: Object, + default: {} + } + }, + data() { + return { + loading: false, + vorlage_kurzbz: '', + 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: "Titel", field: "titel"}, + {title: "Bezeichnung", field: "bezeichnung"}, + {title: "Erstelldatum", field: "erstelltam"}, + {title: "Signiert", field: "erstelltam"}, + {title: "Selfservice", field: "signiert"}, + {title: "AkzeptiertAmUm", field: "akzeptiertamum"}, + {title: "Gedruckt", field: "gedruckt", visible: false}, + { + title: 'Aktionen', field: 'actions', + formatter: (cell, formatterParams, onRendered) => { + let container = document.createElement('div'); + container.className = "d-flex gap-2"; + + //~ let button = document.createElement('button'); + //~ button.className = 'btn btn-outline-secondary'; + //~ button.innerHTML = ''; + //~ button.addEventListener('click', () => + //~ this.$refs.edit.open(cell.getData()) + //~ ); + //~ container.append(button); + + let button = document.createElement('button'); + button.className = 'btn btn-outline-secondary'; + button.innerHTML = ''; + button.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(button); + + 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(); + // TODO(chris): check children (!delete?, multiple children) + //this.$refs.table.tabulator.updateOrAddData(data.map(row => row.buchungsnr_verweis ? {buchungsnr:row.buchungsnr_verweis, _children:row} : row)); + this.$refs.table.tabulator.updateOrAddData(data); + }, + actionArchive() { + this.loading = true; + this.$fhcApi + .factory.stv.archiv.archive({ + xml: this.getXmlByXsl(this.vorlage_kurzbz), + xsl: this.vorlage_kurzbz, + ss: this.defaultSemester, + uid: this.modelValue.uid, + prestudent_id: this.modelValue.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/archiv/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.vorlage_kurzbz = result.data.length > 0 ? result.data[0].vorlage_kurzbz : '';}) + .catch(this.$fhcAlert.handleSystemError); + + }, + template: ` +
+ + + +
` +}; + //~ + //~ diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 72572b317..846b07f10 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -38181,6 +38181,46 @@ array( 'insertvon' => 'system' ) ) + ), + 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' + ) + ) ) ); From 3c34b17d2d37dcc87489cdf26d478e44a01fbe33 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Fri, 21 Feb 2025 14:58:59 +0100 Subject: [PATCH 007/139] add Preview-logic, update function sendMessage --- .../api/frontend/v1/messages/Messages.php | 96 +++- application/models/system/Message_model.php | 1 - public/js/api/messages/person.js | 12 +- .../components/Messages/Details/NewMessage.js | 411 +++++++++++------- .../Messages/Details/TableMessages.js | 10 +- public/js/components/Messages/Messages.js | 33 +- .../Studentenverwaltung/Details/Messages.js | 2 + .../VorlagenDropdown/VorlagenDropdown.js | 8 +- 8 files changed, 368 insertions(+), 205 deletions(-) diff --git a/application/controllers/api/frontend/v1/messages/Messages.php b/application/controllers/api/frontend/v1/messages/Messages.php index ac107f687..788c8861e 100644 --- a/application/controllers/api/frontend/v1/messages/Messages.php +++ b/application/controllers/api/frontend/v1/messages/Messages.php @@ -17,10 +17,12 @@ class Messages extends FHCAPI_Controller 'sendMessage' => ['admin:r', 'assistenz:r'], 'deleteMessage' => ['admin:r', 'assistenz:r'], 'getVorlagentext' => ['admin:r', 'assistenz:r'], + 'getPreviewText' => ['admin:r', 'assistenz:r'], ]); //Load Models $this->load->model('system/Message_model', 'MessageModel'); + $this->load->model('CL/Messages_model', 'MessagesModel'); // Additional Permission Checks //TODO(manu) check permissions @@ -179,8 +181,7 @@ class Messages extends FHCAPI_Controller public function sendMessage($recipient_id) { - //TODO(manu) Problems with Vorlagen... - //TODO(Manu) Problems with VARS + //default setting $receiversPersonId = $this->_getPersonIdFromUid($recipient_id); $uid = getAuthUID(); @@ -201,35 +202,94 @@ class Messages extends FHCAPI_Controller } } - $subject = $this->input->post('subject'); + $this->load->library('form_validation'); + $this->form_validation->set_rules('subject', 'Betreff', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Betreff']) + ]); + + $this->form_validation->set_rules('body', 'Text', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Text']) + ]); + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $subject = $this->input->post('subject'); $body = $this->input->post('body'); - // $this->terminateWithError("rp_id " . $receiversPersonId, self::ERROR_TYPE_GENERAL); -/* $subject = $this->input->post('subject'); - $formData = $this->input->post('data');*/ + $typeId = $this->input->post('type_id'); + $id = $this->input->post('id'); - //$_POST['subject'] = $formData['subject']; - // $subject = $formData['subject']; - // $body = $formData['body']; + if($typeId == 'uid') + { + //$this->terminateWithError("uid ", self::ERROR_TYPE_GENERAL); + $prestudent_id = $this-> _getPrestudentIdFromUid($id); - // $subject = isset($_POST['subject']) ? $_POST['subject'] : null; - // $body = isset($_POST['body']) ? $_POST['body'] : null; + //parseMessagetext for variables Prestudent + $result = $this->MessagesModel->parseMessageTextPrestudent($prestudent_id, $body); + $bodyParsed = $this->getDataOrTerminateWithError($result); + } + elseif($typeId == 'person_id') + { + $this->terminateWithError("person_id ", self::ERROR_TYPE_GENERAL); - // $this->terminateWithError("person_id " . $receiversPersonId, self::ERROR_TYPE_GENERAL); + $result = $this->MessagesModel->parseMessageTextPerson($id, $body); + $bodyParsed = $this->getDataOrTerminateWithError($result); + } + elseif($typeId == 'prestudent_id') + { + $this->terminateWithError("prestudent_id ", self::ERROR_TYPE_GENERAL); - // $this->terminateWithError("subject " . $subject, self::ERROR_TYPE_GENERAL); - // $this->terminateWithError("body " . $body, self::ERROR_TYPE_GENERAL); + $result = $this->MessagesModel->parseMessageTextPrestudent($id, $body); + $bodyParsed = $this->getDataOrTerminateWithError($result); + } + else + { + $this->terminateWithError("type_id " . $typeId . " not valid", self::ERROR_TYPE_GENERAL); + } - // $this->terminateWithError("person_id " . $benutzer->person_id, self::ERROR_TYPE_GENERAL); - // $this->terminateWithError("subject " . $subject, self::ERROR_TYPE_GENERAL); - $result = $this->messagelib->sendMessageUser($receiversPersonId, $subject, $body, $benutzer->person_id); + $result = $this->messagelib->sendMessageUser($receiversPersonId, $subject, $bodyParsed, $benutzer->person_id); $this->terminateWithSuccess($result); } + public function getPreviewText($id, $type_id) + { + if (isset($_POST['data'])) + { + $data = json_decode($_POST['data']); + unset($_POST['data']); + + } + else + $this->terminateWithError("Textbody missing ", self::ERROR_TYPE_GENERAL); + + switch($type_id) + { + case 'uid': + $prestudent_id = $this->_getPrestudentIdFromUid($id); + $result = $this->MessagesModel->parseMessageTextPrestudent($prestudent_id, $data); + + break; + case 'person_id': + $id = $id; + break; + default: + $this->terminateWithError("MESSAGES::getPreviewText logic for type_id " . $type_id . " not defined yet", self::ERROR_TYPE_GENERAL); + break; + } + + //$this->terminateWithSuccess($result); + $bodyParsed = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($bodyParsed); + } + public function deleteMessage($messageId) { // Start DB transaction @@ -238,6 +298,7 @@ class Messages extends FHCAPI_Controller $result = $this->MessageModel->deleteMessageRecipient($messageId); if (isError($result)) { return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); } $result = $this->MessageModel->deleteMessageStatus($messageId); @@ -265,6 +326,7 @@ class Messages extends FHCAPI_Controller $data = $this->getDataOrTerminateWithError($result); $benutzer = current($data); + //return $data->person_id; return $benutzer->person_id; } diff --git a/application/models/system/Message_model.php b/application/models/system/Message_model.php index 7ecb54a9e..0fdb39736 100644 --- a/application/models/system/Message_model.php +++ b/application/models/system/Message_model.php @@ -323,5 +323,4 @@ class Message_model extends DB_Model return $this->execQuery($sql, array($message_id)); } - } diff --git a/public/js/api/messages/person.js b/public/js/api/messages/person.js index 6a0ac8c7c..5cbb49550 100644 --- a/public/js/api/messages/person.js +++ b/public/js/api/messages/person.js @@ -20,13 +20,13 @@ export default { getNameOfDefaultRecipient(params){ return this.$fhcApi.get('api/frontend/v1/messages/messages/getNameOfDefaultRecipient/' + params.id + '/' + params.type_id); }, + getPreviewText(params, data){ + return this.$fhcApi.post('api/frontend/v1/messages/messages/getPreviewText/' + params.id + '/' + params.type_id, + data); + }, sendMessage(form, id, data) { - console.log("factory " + id); - console.log(JSON.stringify(data)); - - return this.$fhcApi.post(form, 'api/frontend/v1/messages/messages/sendMessage/' + id, - data - ); + return this.$fhcApi.post(form,'api/frontend/v1/messages/messages/sendMessage/' + id, + data); }, deleteMessage(messageId){ return this.$fhcApi.post('api/frontend/v1/messages/messages/deleteMessage/' + messageId); diff --git a/public/js/components/Messages/Details/NewMessage.js b/public/js/components/Messages/Details/NewMessage.js index 2d85c8e00..c8aae2124 100644 --- a/public/js/components/Messages/Details/NewMessage.js +++ b/public/js/components/Messages/Details/NewMessage.js @@ -3,7 +3,6 @@ import FormInput from '../../Form/Input.js'; import ListBox from "../../../../../index.ci.php/public/js/components/primevue/listbox/listbox.esm.min.js"; import DropdownComponent from '../../VorlagenDropdown/VorlagenDropdown.js'; - export default { components: { FormForm, @@ -21,6 +20,7 @@ export default { type: [Number, String], required: true }, + openMode: String, }, data(){ return { @@ -45,12 +45,14 @@ export default { itemsPrestudent: [], itemsPerson: [], itemsUser: [], - selectedFieldStudent: null, +/* selectedFieldStudent: null, itemsStudent: [ { label: "Variable 1", value: "var1" }, { label: "Variable 2", value: "var2" }, { label: "Variable 3", value: "var3" } - ] + ]*/ + previewText: null, + previewBody: "" } }, methods: { @@ -86,22 +88,35 @@ export default { updateText(value) { this.formData.body = value; }, - sendMessage(){ + sendMessage() { //TODO(Manu) check default recipient(s) const data = new FormData(); + const params = { + id: this.id, + type_id: this.typeId + }; + const merged = { + ...this.formData, + ...params + }; + data.append('data', JSON.stringify(merged)); - data.append('data', JSON.stringify(this.formData)); - return this.$fhcApi.factory.messages.person.sendMessage(this.$refs.formVorlage, this.id, data) + return this.$fhcApi.factory.messages.person.sendMessage( + this.$refs.formMessage, + this.id, + data) .then(response => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); //this.hideModal('messageModal'); + this.hideTemplate(); this.resetForm(); }).catch(this.$fhcAlert.handleSystemError) .finally(() => { - //this.resetForm(); - //closeModal - //closewindwo - } + //this.resetForm(); + //closeModal + //closewindwo + this.$emit('reloadTable'); + } ); }, getVorlagentext(vorlage_kurzbz){ @@ -120,9 +135,37 @@ export default { //closewindwo }); }, + getPreviewText(){ + const data = new FormData(); + + data.append('data', JSON.stringify(this.formData.body)); + return this.$fhcApi.factory.messages.person.getPreviewText({ + id: this.id, + type_id: this.typeId}, data) + .then(response => { + this.previewText = response.data; + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + //this.resetForm(); + //closeModal + //closewindwo + }); + }, insertVariable(selectedItem){ if (this.editor) { this.editor.insertContent(selectedItem.value + " "); + //TODO(Manu) check: nicht mal mit Punkt adden gehts ohne eintrag nach vars +/* this.editor.focus(); + this.editor.setDirty(true);*/ + + //this.editor.fire('change'); //forces + + //this.editor.undoManager.add(); + + //this.editor.insertContent(selectedItem.value + "\u00A0"); + //this.editor.insertContent(`${selectedItem.value} `); + //this.editor.selection.setCursorLocation(this.editor.getBody(), 1); + } else { console.error("Editor instance is not available."); } @@ -207,6 +250,19 @@ export default { this.formData.subject = vorlage_kurzbz; } }, + hideTemplate(){ + if (this.openMode == "showDiv") + this.isVisible = false; + }, + showTemplate(){ + if (this.openMode == "showDiv") + this.isVisible = true; + }, + showPreview(){ + this.getPreviewText().then(() => { + this.previewBody = this.previewText; + }); + } }, watch: { 'formData.body': { @@ -227,14 +283,10 @@ export default { this.formData.subject = newVal; return this.getVorlagentext(newVal); } - //TODO(Manu) own function or retval to getVorlagentext - //component VorlagenComponent - } } }, created(){ - if(this.typeId == 'person_id'){ this.$fhcApi.factory.messages.person.getMessageVarsPerson() .then(result => { @@ -246,7 +298,6 @@ export default { }) .catch(this.$fhcAlert.handleSystemError); } - if(this.typeId == 'uid') { this.$fhcApi.factory.messages.person.getMsgVarsPrestudent(this.id) .then(result => { @@ -258,8 +309,8 @@ export default { value: value }));*/ this.itemsPrestudent = Object.entries(prestudent).map(([key, value]) => ({ - label: key, - value: '{' + key + '}' + label: key.toLowerCase(), + value: '{' + key.toLowerCase() + '}' })); }) .catch(this.$fhcAlert.handleSystemError); @@ -292,157 +343,185 @@ export default { }, template: `
- -
-

New Message

- - {{typeId}} {{id}} - - {{formData.subject}} - {{formData.vorlage_kurzbz}} - -

- formData.body befüllt -

- -
- -
- - - -
- - - -
- -
- - -
- - -
- - -
- -
- - -
- -
-
- -
- -
- Felder Prestudent -
- - - - - -
- - -

{{selectedFieldPrestudent}}

- -
- -
- Felder Person -
- - - - - -
- -

{{selectedFieldPerson}}

-
- -
- Meine Felder -
- - - - - -
- -
- - -
- - - - - -
- -
- -
-
- -
+

+ +
+
+ +

New Message

+ + +
+
+ + + +
+ + + +
+ +
+ + +
+ + +
+ + +
+ +
+ + +
+ +
+
+ +
+
+ Felder Prestudent +
+ + + + + +
+ + +

{{selectedFieldPrestudent}}

+ +
+ +
+ Felder Person +
+ + + + + +
+ +

{{selectedFieldPerson}}

+
+ +
+ Meine Felder +
+ + + + + +
+ +
+ +
+ + + + + +
+ +
+ +
+ +
+ +

Vorschau:

+
+ + +
+ + +
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+ +
+ +
+ +
+
` diff --git a/public/js/components/Messages/Details/TableMessages.js b/public/js/components/Messages/Details/TableMessages.js index 0025d7b47..10210ece4 100644 --- a/public/js/components/Messages/Details/TableMessages.js +++ b/public/js/components/Messages/Details/TableMessages.js @@ -22,6 +22,7 @@ export default { required: true }, messageLayout: String, + openMode: String }, //TODO(Manu) endpoint macht Probleme data(){ @@ -238,15 +239,14 @@ export default { const linkWindowNewMessage = this.cisRoot + '/public/js/components/Messages/Details/NewMessage.js'; window.open(linkWindowNewMessage, '_blank'); } - else if (this.openmode == "modal"){ + else if (this.openMode == "modal"){ console.log("open with bootstrap Modal"); } - else if (this.openmode == "showDiv"){ - console.log("open div in NewMessage.js"); - //emit to NewMessage.js + else if (this.openMode == "showDiv"){ + this.$emit('showNewMessageTemplate'); } else - console.log("no valid openmode: yet to be developed"); + console.log("no valid openMode"); }, reload() { this.$refs.table.reloadTable(); diff --git a/public/js/components/Messages/Messages.js b/public/js/components/Messages/Messages.js index a7cccb8cb..f862ebc46 100644 --- a/public/js/components/Messages/Messages.js +++ b/public/js/components/Messages/Messages.js @@ -28,31 +28,56 @@ export default { ].includes(value) } }, + openMode: { + type: String, + default: 'window', + validator(value) { + return [ + 'window', + 'modal', + 'showDiv' + ].includes(value) + } + } }, data() { return {} }, + methods: { + showNewMessageTemplate(){ + this.$refs.templateNewMessage.showTemplate(); + }, + reloadTable(){ + this.$refs.templateTableMessage.reload(); + } + }, template: `
- - +
- - +
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Messages.js b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js index 14d74e56c..bc07401e6 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Messages.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js @@ -1,4 +1,5 @@ import CoreMessages from "../../../Messages/Messages.js"; +//import CoreMessages from "@/Messages/Messages.js"; export default { components: { @@ -17,6 +18,7 @@ export default { messageLayout="twoColumnsTableLeft" show-table show-new + open-mode="showDiv" > diff --git a/public/js/components/VorlagenDropdown/VorlagenDropdown.js b/public/js/components/VorlagenDropdown/VorlagenDropdown.js index e4c48501a..b074711f4 100644 --- a/public/js/components/VorlagenDropdown/VorlagenDropdown.js +++ b/public/js/components/VorlagenDropdown/VorlagenDropdown.js @@ -1,5 +1,5 @@ import {CoreFilterCmpt} from "../filter/Filter.js"; -import FormForm from '../Form/Form'; +import FormForm from '../Form/Form.js'; import FormInput from '../Form/Input.js'; export default { @@ -39,16 +39,13 @@ export default { }, methods: { updateValue() { - // console.log("in COMPO: update: " + this.selectedValue + ' jetzt ' + 'InfocenterMailErgaenzungsprfEng'); this.$emit('change', this.selectedValue); - //this.$emit('change', this.selectedValue); // Emit-Event beim Ändern des Wertes }, setValue(value) { this.selectedValue = value; }, }, - created() { - + created() { if(this.isAdmin) { this.$fhcApi.factory.vorlagen.getVorlagen() .then(result => { @@ -103,7 +100,6 @@ template: `
-
`, } \ No newline at end of file From 00b77d726cf5201ce8bec4fcfd50ceb75f7b53c4 Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Wed, 26 Feb 2025 18:11:07 +0100 Subject: [PATCH 008/139] Studverwaltung Archiv: update of archived documents is possible, enabled archiving via multi-select --- .../api/frontend/v1/stv/Archiv.php | 74 +++++++++- .../api/frontend/v1/stv/Config.php | 26 ++-- public/js/api/stv/archiv.js | 6 +- .../Stv/Studentenverwaltung/Details/Archiv.js | 129 +++++++++++------- .../Details/Archiv/Edit.js | 116 ++++++++++++++++ 5 files changed, 281 insertions(+), 70 deletions(-) create mode 100644 public/js/components/Stv/Studentenverwaltung/Details/Archiv/Edit.js diff --git a/application/controllers/api/frontend/v1/stv/Archiv.php b/application/controllers/api/frontend/v1/stv/Archiv.php index dc93c2c4c..91fc9643d 100644 --- a/application/controllers/api/frontend/v1/stv/Archiv.php +++ b/application/controllers/api/frontend/v1/stv/Archiv.php @@ -38,7 +38,7 @@ class Archiv extends FHCAPI_Controller 'getArchivVorlagen' => ['admin:r', 'assistenz:r'], 'archive' => ['admin:w', 'assistenz:w'], 'download' => ['admin:w', 'assistenz:w'], - //'update' => ['admin:w', 'assistenz:w'], + 'update' => ['admin:w'], 'delete' => ['admin:w', 'assistenz:w'] ]); @@ -147,13 +147,83 @@ class Archiv extends FHCAPI_Controller $result = $this->aktelib->get($akte_id); } - /* * $fileObj->filename + /* $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 diff --git a/application/controllers/api/frontend/v1/stv/Config.php b/application/controllers/api/frontend/v1/stv/Config.php index 2cc2228c9..3415c8e41 100644 --- a/application/controllers/api/frontend/v1/stv/Config.php +++ b/application/controllers/api/frontend/v1/stv/Config.php @@ -94,23 +94,15 @@ class Config extends FHCAPI_Controller /* TODO(chris): Ausgeblendet für Testing $result['grades'] = [ 'title' => $this->p->t('stv', 'tab_grades'), - 'component' => './Stv/Studentenverwaltung/Details/Noten.js', - 'showOnlyWithUid' => true, - 'config' => [ - 'usePoints' => defined('CIS_GESAMTNOTE_PUNKTE') && CIS_GESAMTNOTE_PUNKTE, - 'edit' => 'both', // Possible values: both|header|inline - 'delete' => 'both', // Possible values: both|header|inline - 'documents' => 'both', // Possible values: both|header|inline - 'documentslist' => $this->gradesDocumentsList() - ] + 'component' => './Stv/Studentenverwaltung/Details/Noten.js' ]; */ $result['archive'] = [ 'title' => $this->p->t('stv', 'tab_archive'), - 'component' => './Stv/Studentenverwaltung/Details/Archiv.js' - //~ 'config' => [ - //~ //'columns' => $this->kontoColumns() - //~ ] + 'component' => './Stv/Studentenverwaltung/Details/Archiv.js', + 'config' => [ + 'showEdit' => $this->permissionlib->isBerechtigt('admin') + ] ]; Events::trigger('stv_conf_student', function & () use (&$result) { @@ -148,10 +140,10 @@ class Config extends FHCAPI_Controller ]; $result['archive'] = [ 'title' => $this->p->t('stv', 'tab_archive'), - 'component' => './Stv/Studentenverwaltung/Details/Archiv.js' - //~ 'config' => [ - //~ //'columns' => $this->kontoColumns() - //~ ] + 'component' => './Stv/Studentenverwaltung/Details/Archiv.js', + 'config' => [ + 'showEdit' => $this->permissionlib->isBerechtigt('admin') + ] ]; Events::trigger('stv_conf_students', function & () use (&$result) { diff --git a/public/js/api/stv/archiv.js b/public/js/api/stv/archiv.js index 0f303684b..76dbecec8 100644 --- a/public/js/api/stv/archiv.js +++ b/public/js/api/stv/archiv.js @@ -21,9 +21,9 @@ export default { data ); }, - //~ edit(data) { - //~ return this.$fhcApi.post('api/frontend/v1/stv/konto/update', 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}); } diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Archiv.js b/public/js/components/Stv/Studentenverwaltung/Details/Archiv.js index 7858dbd5e..f69e89838 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Archiv.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Archiv.js @@ -1,14 +1,12 @@ import {CoreFilterCmpt} from "../../../filter/Filter.js"; import FormInput from "../../../Form/Input.js"; -//~ import KontoNew from "./Konto/New.js"; -//~ import KontoEdit from "./Konto/Edit.js"; +import AkteEdit from "./Archiv/Edit.js"; export default { components: { CoreFilterCmpt, - FormInput - //~ KontoNew, - //~ KontoEdit + FormInput, + AkteEdit }, inject: { defaultSemester: { @@ -76,31 +74,62 @@ export default { tabulatorColumns() { const columns = [ {title: "Akte Id", field: "akte_id", visible: false}, - {title: "Titel", field: "titel"}, - {title: "Bezeichnung", field: "bezeichnung"}, - {title: "Erstelldatum", field: "erstelltam"}, - {title: "Signiert", field: "erstelltam"}, - {title: "Selfservice", field: "signiert"}, - {title: "AkzeptiertAmUm", field: "akzeptiertamum"}, - {title: "Gedruckt", field: "gedruckt", 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: '', + crossElement: '' + } + }, + { + title: "Selfservice", + field: "stud_selfservice", + formatter:"tickCross", + hozAlign:"center", + formatterParams: { + tickElement: '', + crossElement: '' + }, + }, + {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: '', + crossElement: '' + } + }, { title: 'Aktionen', field: 'actions', formatter: (cell, formatterParams, onRendered) => { let container = document.createElement('div'); container.className = "d-flex gap-2"; - //~ let button = document.createElement('button'); - //~ button.className = 'btn btn-outline-secondary'; - //~ button.innerHTML = ''; - //~ button.addEventListener('click', () => - //~ this.$refs.edit.open(cell.getData()) - //~ ); - //~ container.append(button); + if (this.config.showEdit) + { + let editButton = document.createElement('button'); + editButton.className = 'btn btn-outline-secondary'; + editButton.innerHTML = ''; + editButton.addEventListener('click', () => + this.$refs.edit.open(cell.getData()) + ); + container.append(editButton); + } - let button = document.createElement('button'); - button.className = 'btn btn-outline-secondary'; - button.innerHTML = ''; - button.addEventListener('click', evt => { + let deleteButton = document.createElement('button'); + deleteButton.className = 'btn btn-outline-secondary'; + deleteButton.innerHTML = ''; + deleteButton.addEventListener('click', evt => { evt.stopPropagation(); this.$fhcAlert .confirmDelete() @@ -112,7 +141,7 @@ export default { }) .catch(this.$fhcAlert.handleSystemError); }); - container.append(button); + container.append(deleteButton); return container; }, @@ -158,31 +187,36 @@ export default { updateData(data) { if (!data) return this.reload(); - // TODO(chris): check children (!delete?, multiple children) - //this.$refs.table.tabulator.updateOrAddData(data.map(row => row.buchungsnr_verweis ? {buchungsnr:row.buchungsnr_verweis, _children:row} : row)); this.$refs.table.tabulator.updateOrAddData(data); }, actionArchive() { - this.loading = true; - this.$fhcApi - .factory.stv.archiv.archive({ - xml: this.getXmlByXsl(this.vorlage_kurzbz), - xsl: this.vorlage_kurzbz, - ss: this.defaultSemester, - uid: this.modelValue.uid, - prestudent_id: this.modelValue.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; - }); + console.log(this.modelValue); + let archiveDataArr = Array.isArray(this.modelValue) ? this.modelValue : [this.modelValue]; + + for (let archiveData of archiveDataArr) + { + this.loading = true; + this.$fhcApi + .factory.stv.archiv.archive({ + xml: this.getXmlByXsl(this.vorlage_kurzbz), + xsl: this.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( @@ -235,7 +269,6 @@ export default { + ` }; - //~ - //~ diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Archiv/Edit.js b/public/js/components/Stv/Studentenverwaltung/Details/Archiv/Edit.js new file mode 100644 index 000000000..35777b6ac --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Archiv/Edit.js @@ -0,0 +1,116 @@ +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: ` + + + +
+
+ {{ data.titel }} ({{ data.bezeichnung }}) +
+ + +
+ + + +
+ + + + +
+ + + +
+
` +}; \ No newline at end of file From 9bd5f6dcb62573ce62c33a7007d47a109f62abfa Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Wed, 26 Feb 2025 19:38:09 +0100 Subject: [PATCH 009/139] Studierendenverwaltung Archiv: enabled download of documents --- .../controllers/api/frontend/v1/stv/Akte.php | 70 +++++++++++++++++++ .../Stv/Studentenverwaltung/Details/Archiv.js | 2 +- 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 application/controllers/api/frontend/v1/stv/Akte.php diff --git a/application/controllers/api/frontend/v1/stv/Akte.php b/application/controllers/api/frontend/v1/stv/Akte.php new file mode 100644 index 000000000..1d38c96d4 --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Akte.php @@ -0,0 +1,70 @@ +. + */ + +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(); + } + } +} diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Archiv.js b/public/js/components/Stv/Studentenverwaltung/Details/Archiv.js index f69e89838..1856815a1 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Archiv.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Archiv.js @@ -221,7 +221,7 @@ export default { actionDownload(akte_id) { window.open( FHC_JS_DATA_STORAGE_OBJECT.app_root - + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/api/frontend/v1/stv/archiv/download?akte_id=' + encodeURIComponent(akte_id), + + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/api/frontend/v1/stv/akte/download?akte_id=' + encodeURIComponent(akte_id), '_blank' ); }, From f9f185bfef0291274011e99fe057da8a3b42f994 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Thu, 27 Feb 2025 14:06:25 +0100 Subject: [PATCH 010/139] Views modal, new tab, new page, app and controller for newMessage to open in tab or window --- application/controllers/NeueNachricht.php | 30 ++ .../api/frontend/v1/messages/Messages.php | 2 +- application/views/Nachrichten.php | 48 ++ public/js/apps/Messages/NewMessage.js | 27 + public/js/apps/Nachrichten.js | 25 + .../components/Messages/Details/NewMessage.js | 92 +--- .../Messages/Details/NewMessage/Modal.js | 468 +++++++++++++++++ .../Messages/Details/NewMessage/NewDiv.js | 488 ++++++++++++++++++ .../Messages/Details/TableMessages.js | 32 +- public/js/components/Messages/Messages.js | 108 +++- .../Studentenverwaltung/Details/Messages.js | 2 +- .../VorlagenDropdown/VorlagenDropdown.js | 2 +- 12 files changed, 1218 insertions(+), 106 deletions(-) create mode 100644 application/controllers/NeueNachricht.php create mode 100644 application/views/Nachrichten.php create mode 100644 public/js/apps/Messages/NewMessage.js create mode 100644 public/js/apps/Nachrichten.js create mode 100644 public/js/components/Messages/Details/NewMessage/Modal.js create mode 100644 public/js/components/Messages/Details/NewMessage/NewDiv.js diff --git a/application/controllers/NeueNachricht.php b/application/controllers/NeueNachricht.php new file mode 100644 index 000000000..9e9e0a39b --- /dev/null +++ b/application/controllers/NeueNachricht.php @@ -0,0 +1,30 @@ +method] = ['vertrag/mitarbeiter:r']; + parent::__construct($permissions); + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + } + + /** + * @return void + */ + public function _remap() + { + //now working + $this->load->view('Nachrichten', [ + 'permissions' => [ + 'vertragsverwaltung_schreibrechte' => $this->permissionlib->isBerechtigt('vertrag/mitarbeiter', 'suid') + ] + ]); + } +} diff --git a/application/controllers/api/frontend/v1/messages/Messages.php b/application/controllers/api/frontend/v1/messages/Messages.php index 788c8861e..4bc9a13ab 100644 --- a/application/controllers/api/frontend/v1/messages/Messages.php +++ b/application/controllers/api/frontend/v1/messages/Messages.php @@ -129,7 +129,7 @@ class Messages extends FHCAPI_Controller public function getMsgVarsPrestudent($uid) { - + //$this->terminateWithError($uid, self::ERROR_TYPE_GENERAL); $prestudent_id = $this-> _getPrestudentIdFromUid($uid); // $this->terminateWithError("prestudent_id " . $prestudent_id, self::ERROR_TYPE_GENERAL); diff --git a/application/views/Nachrichten.php b/application/views/Nachrichten.php new file mode 100644 index 000000000..cf34bfd53 --- /dev/null +++ b/application/views/Nachrichten.php @@ -0,0 +1,48 @@ + 'Nachrichten', + 'axios027' => true, + 'bootstrap5' => true, + 'fontawesome6' => true, + 'vue3' => true, + 'primevue3' => true, + #'filtercomponent' => true, + 'tabulator5' => true, + 'tinymce5' => true, + 'phrases' => array( + 'global', + 'ui', + ), + 'customCSSs' => [ + 'public/css/components/vue-datepicker.css', + 'public/css/components/primevue.css', + ], + 'customJSs' => [ + #'vendor/npm-asset/primevue/tree/tree.min.js', + #'vendor/npm-asset/primevue/toast/toast.min.js' + ], + 'customJSModules' => [ + 'public/js/apps/Nachrichten.js' + ] +); + +$this->load->view('templates/FHC-Header', $includesArray); +?> + + !defined('DOMAIN') ? 'notDefined' : DOMAIN, +]; +?> + +
+ + +
+ +load->view('templates/FHC-Footer', $includesArray); ?> + diff --git a/public/js/apps/Messages/NewMessage.js b/public/js/apps/Messages/NewMessage.js new file mode 100644 index 000000000..693c8b0e2 --- /dev/null +++ b/public/js/apps/Messages/NewMessage.js @@ -0,0 +1,27 @@ +//TODO Manu +//use this instead of Nachrichten.js +import NewMessage from "../../components/Messages/Details/NewMessage/NewDiv.js"; +import Phrasen from "../../plugin/Phrasen.js"; + +const ciPath = FHC_JS_DATA_STORAGE_OBJECT.app_root.replace(/(https:|)(^|\/\/)(.*?\/)/g, '') + FHC_JS_DATA_STORAGE_OBJECT.ci_router; + +const router = VueRouter.createRouter({ + history: VueRouter.createWebHistory(), + routes: [ + { path: `/${ciPath}/NeueNachricht`, component: NewMessage }, + { path: `/${ciPath}/NeueNachricht/:id`, component: NewMessage }, + { path: `/${ciPath}/NeueNachricht/:id/:typeId`, component: NewMessage }, + ] +}); + +const app = Vue.createApp(); + +app + .use(router) + .use(primevue.config.default, { + zIndex: { + overlay: 1100 + } + }) + .use(Phrasen) + .mount('#main'); diff --git a/public/js/apps/Nachrichten.js b/public/js/apps/Nachrichten.js new file mode 100644 index 000000000..0f921a9f8 --- /dev/null +++ b/public/js/apps/Nachrichten.js @@ -0,0 +1,25 @@ +import NewMessage from "../components/Messages/Details/NewMessage/NewDiv.js"; + +import Phrasen from "../plugin/Phrasen.js"; + +const ciPath = FHC_JS_DATA_STORAGE_OBJECT.app_root.replace(/(https:|)(^|\/\/)(.*?\/)/g, '') + FHC_JS_DATA_STORAGE_OBJECT.ci_router; + +const router = VueRouter.createRouter({ + history: VueRouter.createWebHistory(), + routes: [ + { path: `/${ciPath}/NeueNachricht/:id/:typeId`, component: NewMessage }, + ] +}); + + +const app = Vue.createApp(); + +app + .use(router) + .use(primevue.config.default, { + zIndex: { + overlay: 1100 + } + }) + .use(Phrasen) + .mount('#main'); \ No newline at end of file diff --git a/public/js/components/Messages/Details/NewMessage.js b/public/js/components/Messages/Details/NewMessage.js index c8aae2124..33ff74d9c 100644 --- a/public/js/components/Messages/Details/NewMessage.js +++ b/public/js/components/Messages/Details/NewMessage.js @@ -2,13 +2,15 @@ import FormForm from '../../Form/Form.js'; import FormInput from '../../Form/Input.js'; import ListBox from "../../../../../index.ci.php/public/js/components/primevue/listbox/listbox.esm.min.js"; import DropdownComponent from '../../VorlagenDropdown/VorlagenDropdown.js'; +import MessageModal from "../Details/NewMessage/Modal.js"; export default { components: { FormForm, FormInput, ListBox, - DropdownComponent + DropdownComponent, + MessageModal, }, props: { endpoint: { @@ -35,7 +37,7 @@ export default { vorlagen: [], defaultRecipient: null, editor: null, - isVisible: true, + isVisible: false, fieldsUser: [], fieldsPerson: [], fieldsPrestudent: [], @@ -45,12 +47,6 @@ export default { itemsPrestudent: [], itemsPerson: [], itemsUser: [], -/* selectedFieldStudent: null, - itemsStudent: [ - { label: "Variable 1", value: "var1" }, - { label: "Variable 2", value: "var2" }, - { label: "Variable 3", value: "var3" } - ]*/ previewText: null, previewBody: "" } @@ -170,62 +166,6 @@ export default { console.error("Editor instance is not available."); } }, - //TODO(Manu) refactor -/* insertVariablePrestudent() { - if (this.editor) { - //const lastVariable = this.selectedFieldsPrestudent[this.selectedFieldsPrestudent.length - 1].value; - const lastVariable = this.selectedFieldPrestudent.value; - - //Use insertContent method - this.editor.insertContent(lastVariable + " "); - } else { - console.error("Editor instance is not available."); - } - },*/ -/* insertVariablePrestudentByClick(selectedItem) { - - if (selectedItem) { - this.editor.insertContent(selectedItem.value + " "); - console.log("Eingefügte Variable:", selectedItem); - } else { - console.warn("Keine Variable ausgewählt!"); - } - }, - - insertVariablePerson() { - if (this.editor) { - //const lastVariable = this.selectedFieldsPrestudent[this.selectedFieldsPrestudent.length - 1].value; - const lastVariable = this.selectedFieldPerson.value; - - //Use insertContent method - this.editor.insertContent(lastVariable + " "); - } else { - console.error("Editor instance is not available."); - } - }, - insertVariableUser() { - if (this.editor) { - console.log(this.selectedFieldUser.value); - const lastVariable = this.selectedFieldUser.value; - - //Multiple - //const lastVariable = this.selectedFieldsPrestudent[this.selectedFieldsPrestudent.length - 1].value; - - //Use insertContent method - this.editor.insertContent(lastVariable + " "); - this.selectedFieldUser = null; - } else { - console.error("Editor instance is not available."); - } - }, - insertVariableStudent(selectedItem) { - if (selectedItem) { - console.log("Eingefügte Variable:", selectedItem); - this.editor.insertContent(selectedItem.value + " "); - } else { - console.warn("Keine Variable ausgewählt!"); - } - },*/ replyMessage(message_id){ console.log("auf message " + message_id + " antworten"); }, @@ -241,9 +181,9 @@ export default { this.$refs.dropdownComp.setValue(null); }, - toggleDivNewMessage(){ +/* toggleDivNewMessage(){ this.isVisible = !this.isVisible; - }, + },*/ handleSelectedVorlage(vorlage_kurzbz) { if (typeof vorlage_kurzbz === "string") { this.getVorlagentext(vorlage_kurzbz); @@ -254,15 +194,17 @@ export default { if (this.openMode == "showDiv") this.isVisible = false; }, - showTemplate(){ + showTemplate(id, typeId){ if (this.openMode == "showDiv") this.isVisible = true; + //just for testing: + this.isVisible = true; }, showPreview(){ this.getPreviewText().then(() => { this.previewBody = this.previewText; }); - } + }, }, watch: { 'formData.body': { @@ -343,9 +285,19 @@ export default { }, template: `
-
+ + + +
diff --git a/public/js/components/Messages/Details/NewMessage/Modal.js b/public/js/components/Messages/Details/NewMessage/Modal.js new file mode 100644 index 000000000..9bfe49929 --- /dev/null +++ b/public/js/components/Messages/Details/NewMessage/Modal.js @@ -0,0 +1,468 @@ +import BsModal from "../../../Bootstrap/Modal.js"; +import FormForm from "../../../Form/Form.js"; +import FormInput from '../../../Form/Input.js'; +import ListBox from "../../../../../../index.ci.php/public/js/components/primevue/listbox/listbox.esm.min.js"; +import DropdownComponent from "../../../VorlagenDropdown/VorlagenDropdown.js"; + +export default { + components: { + BsModal, + FormForm, + DropdownComponent, + FormInput, + ListBox + }, + props: { + endpoint: { + type: String, + required: true + }, + typeId: String, + id: { + type: [Number, String], + required: true + }, + openMode: String, + }, + data(){ + return { + formData: { + recipient: this.id, + subject: null, + body: null, + vorlage_kurzbz: null, + selectedValue: '', + }, + statusNew: true, + vorlagen: [], + defaultRecipient: null, + editor: null, + fieldsUser: [], + fieldsPerson: [], + fieldsPrestudent: [], + selectedFieldPrestudent: null, + selectedFieldUser: null, + selectedFieldPerson: null, + itemsPrestudent: [], + itemsPerson: [], + itemsUser: [], + previewText: null, + previewBody: "" + } + }, + methods: { + initTinyMCE() { + const vm = this; + tinymce.init({ + target: this.$refs.editor.$refs.input, //Important: not selector: to enable multiple import of component + //height: 800, + //plugins: ['lists'], + toolbar: 'styleselect | bold italic underline | alignleft aligncenter alignright alignjustify', + style_formats: [ + {title: 'Blocks', block: 'div'}, + {title: 'Paragraph', block: 'p'}, + {title: 'Heading 1', block: 'h1'}, + {title: 'Heading 2', block: 'h2'}, + {title: 'Heading 3', block: 'h3'}, + {title: 'Heading 4', block: 'h4'}, + {title: 'Heading 5', block: 'h5'}, + {title: 'Heading 6', block: 'h6'}, + ], + autoresize_bottom_margin: 16, + + setup: (editor) => { + vm.editor = editor; + + editor.on('input', () => { + const newContent = editor.getContent(); + vm.formData.body = newContent; + }); + }, + }); + }, + updateText(value) { + this.formData.body = value; + }, + sendMessage() { + //TODO(Manu) check default recipient(s) + const data = new FormData(); + const params = { + id: this.id, + type_id: this.typeId + }; + const merged = { + ...this.formData, + ...params + }; + data.append('data', JSON.stringify(merged)); + + return this.$fhcApi.factory.messages.person.sendMessage( + this.$refs.formMessage, + this.id, + data) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); + //this.hideModal('messageModal'); + this.hideTemplate(); + this.resetForm(); + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + //this.resetForm(); + //closeModal + //closewindwo + this.$emit('reloadTable'); + } + ); + }, + getVorlagentext(vorlage_kurzbz){ + //console.log(typeof vorlage_kurzbz); + return this.$fhcApi.factory.messages.person.getVorlagentext(vorlage_kurzbz) + .then(response => { + //this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); + //this.hideModal('messageModal'); + //this.resetForm(); + //TODO(Manu) CHECK + this.formData.body = response.data; + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + //this.resetForm(); + //closeModal + //closewindwo + }); + }, + getPreviewText(){ + const data = new FormData(); + + data.append('data', JSON.stringify(this.formData.body)); + return this.$fhcApi.factory.messages.person.getPreviewText({ + id: this.id, + type_id: this.typeId}, data) + .then(response => { + this.previewText = response.data; + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + //this.resetForm(); + //closeModal + //closewindwo + }); + }, + insertVariable(selectedItem){ + if (this.editor) { + this.editor.insertContent(selectedItem.value + " "); + //TODO(Manu) check: nicht mal mit Punkt adden gehts ohne eintrag nach vars + /* this.editor.focus(); + this.editor.setDirty(true);*/ + + //this.editor.fire('change'); //forces + + //this.editor.undoManager.add(); + + //this.editor.insertContent(selectedItem.value + "\u00A0"); + //this.editor.insertContent(`${selectedItem.value} `); + //this.editor.selection.setCursorLocation(this.editor.getBody(), 1); + + } else { + console.error("Editor instance is not available."); + } + }, + replyMessage(message_id){ + console.log("auf message " + message_id + " antworten"); + }, + resetForm(){ + this.formData = { + vorlage_kurzbz: null, + body: null, + subject: null, + }; + if (this.editor) { + this.editor.setContent(""); + } + this.$refs.dropdownComp.setValue(null); + + }, + handleSelectedVorlage(vorlage_kurzbz) { + if (typeof vorlage_kurzbz === "string") { + this.getVorlagentext(vorlage_kurzbz); + this.formData.subject = vorlage_kurzbz; + } + }, + hideTemplate(){ + if (this.openMode == "showDiv") + this.isVisible = false; + }, + showTemplate(){ + if (this.openMode == "showDiv") + this.isVisible = true; + }, + showPreview(){ + this.getPreviewText().then(() => { + this.previewBody = this.previewText; + }); + }, + show(){ + this.$refs.modalNewMessage.show(); + } + }, + watch: { + 'formData.body': { + handler(newVal) { + const tinymcsVal = this.editor.getContent(); + + if (newVal && tinymcsVal != newVal) { + //Inhalt des Editors aktualisieren + this.editor.setContent(newVal); + } + } + }, + 'formData.vorlage_kurzbz': { + handler(newVal){ + // console.log("Vorlage: " + newVal); + + if (newVal && newVal != null) { + this.formData.subject = newVal; + return this.getVorlagentext(newVal); + } + } + } + }, + created(){ + if(this.typeId == 'person_id'){ + this.$fhcApi.factory.messages.person.getMessageVarsPerson() + .then(result => { + this.fieldsPerson = result.data; + this.itemsPerson = Object.entries(this.fieldsPerson).map(([key, value]) => ({ + label: value, + value: '{' + value + '}' + })); + }) + .catch(this.$fhcAlert.handleSystemError); + } + if(this.typeId == 'uid') { + this.$fhcApi.factory.messages.person.getMsgVarsPrestudent(this.id) + .then(result => { + this.fieldsPrestudent = result.data; + const prestudent = this.fieldsPrestudent[0]; + //Just for testing with inserting values + /* this.itemsPrestudent = Object.entries(prestudent).map(([key, value]) => ({ + label: key, + value: value + }));*/ + this.itemsPrestudent = Object.entries(prestudent).map(([key, value]) => ({ + label: key.toLowerCase(), + value: '{' + key.toLowerCase() + '}' + })); + }) + .catch(this.$fhcAlert.handleSystemError); + } + + this.$fhcApi.factory.messages.person.getMsgVarsLoggedInUser() + .then(result => { + this.fieldsUser = result.data; + const user = this.fieldsUser; + this.itemsUser = Object.entries(user).map(([key, value]) => ({ + label: value, + value: '{' + value + '}' + })); + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$fhcApi.factory.messages.person.getNameOfDefaultRecipient({ + id: this.id, + type_id: this.typeId}) + .then(result => { + this.defaultRecipient = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + async mounted() { + this.initTinyMCE(); + }, + beforeDestroy() { + this.editor.destroy(); + }, + template: ` + + + + + + +
+ + +
+
+ + + +
+ + + +
+ +
+ + +
+ + +
+ + +
+ +
+ + +
+ +
+
+ +
+
+ Felder Prestudent +
+ + + + + +
+ + +

{{selectedFieldPrestudent}}

+ +
+ +
+ Felder Person +
+ + + + + +
+ +

{{selectedFieldPerson}}

+
+ +
+ Meine Felder +
+ + + + + +
+ +
+ +
+ +
+ +
+ +

Vorschau:

+
+ + +
+ + +
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+ +
+ +
+ +
+ + + +
+ +
+ `, +} \ No newline at end of file diff --git a/public/js/components/Messages/Details/NewMessage/NewDiv.js b/public/js/components/Messages/Details/NewMessage/NewDiv.js new file mode 100644 index 000000000..b31cd9932 --- /dev/null +++ b/public/js/components/Messages/Details/NewMessage/NewDiv.js @@ -0,0 +1,488 @@ +import FormForm from '../../../Form/Form.js'; +import FormInput from '../../../Form/Input.js'; +import ListBox from "../../../../../../index.ci.php/public/js/components/primevue/listbox/listbox.esm.min.js"; +import DropdownComponent from '../../../VorlagenDropdown/VorlagenDropdown.js'; + +export default { + components: { + FormForm, + FormInput, + ListBox, + DropdownComponent, + }, + props: { + endpoint: { + type: String, + required: true + }, + //for open in div and modal +/* typeId: String, + id: { + type: [Number, String], + required: true + },*/ + openMode: String, + }, + computed: { + //params with routes for new tab and new window AND props +/* id(){ + return this.$route.params.id || this.id; + }, + typeId(){ + return this.$route.params.typeId || this.typeId; + },*/ + id(){ + return this.$route.params.id || this.$props.id; + }, + typeId(){ + return this.$route.params.typeId || this.$props.id; + } + }, + data(){ + return { + formData: { + recipient: this.id, + subject: null, + body: null, + vorlage_kurzbz: null, + selectedValue: '', + }, + statusNew: true, + vorlagen: [], + defaultRecipient: null, + editor: null, + isVisible: false, + fieldsUser: [], + fieldsPerson: [], + fieldsPrestudent: [], + selectedFieldPrestudent: null, + selectedFieldUser: null, + selectedFieldPerson: null, + itemsPrestudent: [], + itemsPerson: [], + itemsUser: [], + previewText: null, + previewBody: "" + } + }, + methods: { + initTinyMCE() { + const vm = this; + tinymce.init({ + target: this.$refs.editor.$refs.input, //Important: not selector: to enable multiple import of component + //height: 800, + //plugins: ['lists'], + toolbar: 'styleselect | bold italic underline | alignleft aligncenter alignright alignjustify', + style_formats: [ + {title: 'Blocks', block: 'div'}, + {title: 'Paragraph', block: 'p'}, + {title: 'Heading 1', block: 'h1'}, + {title: 'Heading 2', block: 'h2'}, + {title: 'Heading 3', block: 'h3'}, + {title: 'Heading 4', block: 'h4'}, + {title: 'Heading 5', block: 'h5'}, + {title: 'Heading 6', block: 'h6'}, + ], + autoresize_bottom_margin: 16, + + setup: (editor) => { + vm.editor = editor; + + editor.on('input', () => { + const newContent = editor.getContent(); + vm.formData.body = newContent; + }); + }, + }); + }, + updateText(value) { + this.formData.body = value; + }, + sendMessage() { + //TODO(Manu) check default recipient(s) + const data = new FormData(); + const params = { + id: this.id, + type_id: this.typeId + }; + const merged = { + ...this.formData, + ...params + }; + data.append('data', JSON.stringify(merged)); + + return this.$fhcApi.factory.messages.person.sendMessage( + this.$refs.formMessage, + this.id, + data) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); + //this.hideModal('messageModal'); + this.hideTemplate(); + this.resetForm(); + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + //this.resetForm(); + //closeModal + //closewindwo + this.$emit('reloadTable'); + } + ); + }, + getVorlagentext(vorlage_kurzbz){ + return this.$fhcApi.factory.messages.person.getVorlagentext(vorlage_kurzbz) + .then(response => { + //this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); + //this.hideModal('messageModal'); + //this.resetForm(); + //TODO(Manu) CHECK + this.formData.body = response.data; + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + //this.resetForm(); + //closeModal + //closewindwo + }); + }, + getPreviewText(){ + const data = new FormData(); + + data.append('data', JSON.stringify(this.formData.body)); + return this.$fhcApi.factory.messages.person.getPreviewText({ + id: this.id, + type_id: this.typeId}, data) + .then(response => { + this.previewText = response.data; + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + //this.resetForm(); + //closeModal + //closewindwo + }); + }, + insertVariable(selectedItem){ + if (this.editor) { + this.editor.insertContent(selectedItem.value + " "); + //TODO(Manu) check: nicht mal mit Punkt adden gehts ohne eintrag nach vars + /* this.editor.focus(); + this.editor.setDirty(true);*/ + + //this.editor.fire('change'); //forces + + //this.editor.undoManager.add(); + + //this.editor.insertContent(selectedItem.value + "\u00A0"); + //this.editor.insertContent(`${selectedItem.value} `); + //this.editor.selection.setCursorLocation(this.editor.getBody(), 1); + + } else { + console.error("Editor instance is not available."); + } + }, + replyMessage(message_id){ + console.log("auf message " + message_id + " antworten"); + }, + resetForm(){ + this.formData = { + vorlage_kurzbz: null, + body: null, + subject: null, + }; + if (this.editor) { + this.editor.setContent(""); + } + this.$refs.dropdownComp.setValue(null); + + this.previewBody = null; + + }, + toggleDivNewMessage(){ + this.isVisible = !this.isVisible; + }, + handleSelectedVorlage(vorlage_kurzbz) { + if (typeof vorlage_kurzbz === "string") { + this.getVorlagentext(vorlage_kurzbz); + this.formData.subject = vorlage_kurzbz; + } + }, + hideTemplate(){ + if (this.openMode == "showDiv") + this.isVisible = false; + }, + showTemplate(){ + if (this.openMode == "showDiv") + this.isVisible = true; + //just for testing: + this.isVisible = true; + }, + showPreview(){ + this.getPreviewText().then(() => { + this.previewBody = this.previewText; + }); + }, + }, + watch: { + 'formData.body': { + handler(newVal) { + const tinymcsVal = this.editor.getContent(); + + if (newVal && tinymcsVal != newVal) { + //Inhalt des Editors aktualisieren + this.editor.setContent(newVal); + } + } + }, + 'formData.vorlage_kurzbz': { + handler(newVal){ + // console.log("Vorlage: " + newVal); + + if (newVal && newVal != null) { + this.formData.subject = newVal; + return this.getVorlagentext(newVal); + } + } + }, + }, + created(){ + if(this.typeId == 'person_id'){ + this.$fhcApi.factory.messages.person.getMessageVarsPerson() + .then(result => { + this.fieldsPerson = result.data; + this.itemsPerson = Object.entries(this.fieldsPerson).map(([key, value]) => ({ + label: value, + value: '{' + value + '}' + })); + }) + .catch(this.$fhcAlert.handleSystemError); + } + if(this.typeId == 'uid') { + this.$fhcApi.factory.messages.person.getMsgVarsPrestudent(this.id) + .then(result => { + this.fieldsPrestudent = result.data; + const prestudent = this.fieldsPrestudent[0]; + //Just for testing with inserting values + /* this.itemsPrestudent = Object.entries(prestudent).map(([key, value]) => ({ + label: key, + value: value + }));*/ + this.itemsPrestudent = Object.entries(prestudent).map(([key, value]) => ({ + label: key.toLowerCase(), + value: '{' + key.toLowerCase() + '}' + })); + }) + .catch(this.$fhcAlert.handleSystemError); + } + + this.$fhcApi.factory.messages.person.getMsgVarsLoggedInUser() + .then(result => { + this.fieldsUser = result.data; + const user = this.fieldsUser; + this.itemsUser = Object.entries(user).map(([key, value]) => ({ + label: value, + value: '{' + value + '}' + })); + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$fhcApi.factory.messages.person.getNameOfDefaultRecipient({ + id: this.id, + type_id: this.typeId + }) + .then(result => { + this.defaultRecipient = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + }, + async mounted() { + this.initTinyMCE(); + }, + beforeDestroy() { + this.editor.destroy(); + }, + template: ` + +
+ + + + + +
+ + {{id}} || {{typeId}} + +

New Message

+ + +
+
+ + + +
+ + + +
+ +
+ + +
+ + +
+ + +
+ +
+ + +
+ +
+
+ +
+
+ Felder Prestudent +
+ + + + + +
+ +
+ +
+ +
+ Felder Person +
+ + + + + +
+ +
+ +
+ Meine Felder +
+ + + + + +
+ +
+ +
+ +
+ + + + + +
+ +
+ +
+ +
+ +

Vorschau:

+
+ + +
+ + +
+ +
+
+ +
+
+ +
+
+
+
+
+ +
+ +
+ +
+ +
+ ` + +} \ No newline at end of file diff --git a/public/js/components/Messages/Details/TableMessages.js b/public/js/components/Messages/Details/TableMessages.js index 10210ece4..7994cbe1d 100644 --- a/public/js/components/Messages/Details/TableMessages.js +++ b/public/js/components/Messages/Details/TableMessages.js @@ -1,10 +1,12 @@ import {CoreFilterCmpt} from "../../filter/Filter.js"; import FormForm from '../../Form/Form.js'; +import NewMessage from "../Details/NewMessage.js"; export default { components: { CoreFilterCmpt, FormForm, + NewMessage, }, inject: { cisRoot: { @@ -205,7 +207,8 @@ export default { }, ], tabulatorData: [], - previewBody: "" + previewBody: "", + open: false } }, methods: { @@ -233,20 +236,9 @@ export default { }); }, actionNewMessage(){ + this.$emit('newMessage', this.id, this.typeId); //console.log("action new message"); - if (this.openMode == "window") { - console.log("openInNewWindow") - const linkWindowNewMessage = this.cisRoot + '/public/js/components/Messages/Details/NewMessage.js'; - window.open(linkWindowNewMessage, '_blank'); - } - else if (this.openMode == "modal"){ - console.log("open with bootstrap Modal"); - } - else if (this.openMode == "showDiv"){ - this.$emit('showNewMessageTemplate'); - } - else - console.log("no valid openMode"); + }, reload() { this.$refs.table.reloadTable(); @@ -274,19 +266,10 @@ export default { }, template: `
- - - - - - -
- +
@@ -307,7 +290,6 @@ export default {




-
diff --git a/public/js/components/Messages/Messages.js b/public/js/components/Messages/Messages.js index f862ebc46..49fdbdf79 100644 --- a/public/js/components/Messages/Messages.js +++ b/public/js/components/Messages/Messages.js @@ -1,10 +1,20 @@ import TableMessages from "./Details/TableMessages.js"; import NewMessage from "./Details/NewMessage.js"; - +import FormOnly from "./Details/NewMessage/NewDiv.js"; +import FhcApi from "../../../../public/js/plugin/FhcApi.js"; +import Phrasen from "../../../../public/js/plugin/Phrasen.js"; export default { components: { TableMessages, - NewMessage + NewMessage, + FormOnly, + FhcApi, + Phrasen + }, + inject: { + cisRoot: { + from: 'cisRoot' + } }, props: { endpoint: { @@ -34,6 +44,7 @@ export default { validator(value) { return [ 'window', + 'newTab', 'modal', 'showDiv' ].includes(value) @@ -41,18 +52,85 @@ export default { } }, data() { - return {} + return { + showDiv: false + } }, methods: { - showNewMessageTemplate(){ - this.$refs.templateNewMessage.showTemplate(); - }, reloadTable(){ this.$refs.templateTableMessage.reload(); - } + }, + newMessage(id, typeId){ + if (this.openMode == "window") { + this.openInNewWindow(id, typeId); + } + else if (this.openMode == "newTab"){ + this.openInNewTab(id, typeId); + } + else if (this.openMode == "modal"){ + this.openInModal(id, typeId); + } + else if (this.openMode == "showDiv"){ + this.$refs.templateNewMessage.showTemplate(id, typeId); + } + else + console.log("no valid openMode"); + }, + openInDiv(id, typeId){ + this.$refs.templateNewMessage.showTemplate(id, typeId); + //this.showDiv = true; //local variante + //this.$refs.templateNewMessage.showTemplate(); + }, + openInModal(id, typeId){ + //TODO(manu) define bs-modal in this component + this.$refs.templateNewMessage.$refs.modalMsg.show(); + }, + openInNewTab(id, typeId){ + //TODO(MANU) check if array of ids... +/* let path = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router; + path += "/NeueNachricht/" + this.id + "/" + this.typeId;*/ + + //als param + let path = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router; + path += "/NeueNachricht/" + id + "/" + typeId; + + const newTab = window.open(path, "_blank"); + }, + openInNewWindow(id, typeId){ + //TODO(MANU) check if array of ids... + let path = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router; + path += "/NeueNachricht/" + id + "/" + typeId; + + const newTab = window.open(path, "_blank"); + + const width = Math.round(window.innerWidth * 0.75); + const height = Math.round(window.innerHeight * 0.75); + const left = Math.round((window.innerWidth - width) / 2); + const top = Math.round((window.innerHeight - height) / 2); + + const newWindow = window.open(path, "_blank", `width=${width},height=${height},left=${left},top=${top}`); + }, + }, template: `
+ + + + +
+ + +
+ + +
+
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Messages.js b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js index bc07401e6..44f1a6aa2 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Messages.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Messages.js @@ -18,7 +18,7 @@ export default { messageLayout="twoColumnsTableLeft" show-table show-new - open-mode="showDiv" + open-mode="newTab" > diff --git a/public/js/components/VorlagenDropdown/VorlagenDropdown.js b/public/js/components/VorlagenDropdown/VorlagenDropdown.js index b074711f4..e5d80077e 100644 --- a/public/js/components/VorlagenDropdown/VorlagenDropdown.js +++ b/public/js/components/VorlagenDropdown/VorlagenDropdown.js @@ -57,7 +57,7 @@ export default { if(this.useLoggedInUserOe){ this.$fhcApi.factory.vorlagen.getVorlagenByLoggedInUser() .then(result => { - console.log(this.vorlagenOe); + //console.log(this.vorlagenOe); this.vorlagenOe = result.data; }) .catch(this.$fhcAlert.handleSystemError); From b3481194882cdc9c40068e77168bc442cafbe529 Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Thu, 27 Feb 2025 14:45:57 +0100 Subject: [PATCH 011/139] added comment to Documents api controller --- application/controllers/api/frontend/v1/Documents.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/application/controllers/api/frontend/v1/Documents.php b/application/controllers/api/frontend/v1/Documents.php index 42a2d3433..ebd1b269b 100644 --- a/application/controllers/api/frontend/v1/Documents.php +++ b/application/controllers/api/frontend/v1/Documents.php @@ -149,9 +149,11 @@ class Documents extends FHCAPI_Controller } /** + * @param string $xml + * @param string $xsl + * @param string $sign_user (optional) * - * @param - * @return object success or error + * @return array with Akte data and export data */ private function _getAkteExportData($xml, $xsl, $sign_user = null) { From 815307e392cb245dd696e10edf1ae018040bd5fb Mon Sep 17 00:00:00 2001 From: ma0068 Date: Tue, 4 Mar 2025 07:32:14 +0100 Subject: [PATCH 012/139] Reply functionality and Pagination --- application/controllers/NeueNachricht.php | 2 +- .../api/frontend/v1/messages/Messages.php | 82 +++++++++++++++++-- application/models/system/Message_model.php | 4 +- public/js/api/messages/person.js | 7 ++ public/js/apps/Nachrichten.js | 1 + .../Messages/Details/NewMessage/NewDiv.js | 29 +++++-- .../Messages/Details/TableMessages.js | 29 +++++-- public/js/components/Messages/Messages.js | 41 ++++++++-- 8 files changed, 162 insertions(+), 33 deletions(-) diff --git a/application/controllers/NeueNachricht.php b/application/controllers/NeueNachricht.php index 9e9e0a39b..9b61b78ef 100644 --- a/application/controllers/NeueNachricht.php +++ b/application/controllers/NeueNachricht.php @@ -23,7 +23,7 @@ class NeueNachricht extends Auth_Controller //now working $this->load->view('Nachrichten', [ 'permissions' => [ - 'vertragsverwaltung_schreibrechte' => $this->permissionlib->isBerechtigt('vertrag/mitarbeiter', 'suid') + 'assistenz_schreibrechte' => $this->permissionlib->isBerechtigt('assistenz','suid'), ] ]); } diff --git a/application/controllers/api/frontend/v1/messages/Messages.php b/application/controllers/api/frontend/v1/messages/Messages.php index 4bc9a13ab..d080cbee3 100644 --- a/application/controllers/api/frontend/v1/messages/Messages.php +++ b/application/controllers/api/frontend/v1/messages/Messages.php @@ -18,6 +18,8 @@ class Messages extends FHCAPI_Controller 'deleteMessage' => ['admin:r', 'assistenz:r'], 'getVorlagentext' => ['admin:r', 'assistenz:r'], 'getPreviewText' => ['admin:r', 'assistenz:r'], + 'getReplyData' => ['admin:r', 'assistenz:r'], + 'getPersonIdFromUid' => ['admin:r', 'assistenz:r'], ]); //Load Models @@ -70,8 +72,6 @@ class Messages extends FHCAPI_Controller $data = $this->getDataOrTerminateWithError($result); $oe_kurzbz = current($data); - // $this->terminateWithError("oe: ". $oe_kurzbz->oe_kurzbz, self::ERROR_TYPE_GENERAL); - $this->load->model('system/Vorlage_model', 'VorlageModel'); //39 Stück Variante OE @@ -129,11 +129,8 @@ class Messages extends FHCAPI_Controller public function getMsgVarsPrestudent($uid) { - //$this->terminateWithError($uid, self::ERROR_TYPE_GENERAL); $prestudent_id = $this-> _getPrestudentIdFromUid($uid); - // $this->terminateWithError("prestudent_id " . $prestudent_id, self::ERROR_TYPE_GENERAL); - $result = $this->MessageModel->getMsgVarsDataByPrestudentId($prestudent_id); $data = $this->getDataOrTerminateWithError($result); @@ -290,6 +287,46 @@ class Messages extends FHCAPI_Controller $this->terminateWithSuccess($bodyParsed); } + public function getReplyData($messageId) + { + // return $this->terminateWithError("in get ReplyBody" . $messageId, self::ERROR_TYPE_GENERAL); + //TODO(Manu) validation of messageId: if number + + + $this->MessageModel->addSelect('public.tbl_msg_message.*'); + $this->MessageModel->addSelect('r.*'); + $this->MessageModel->addSelect('p.nachname'); + $this->MessageModel->addSelect('p.vorname'); + $this->MessageModel->addJoin('public.tbl_msg_recipient r', 'ON (r.message_id = public.tbl_msg_message.message_id)'); + $this->MessageModel->addJoin('public.tbl_person p', 'ON (p.person_id = public.tbl_msg_message.person_id)'); + + $result = $this->MessageModel->loadWhere( + array('r.message_id' => $messageId) + ); + + // $this->terminateWithSuccess((getData($result) ?: [])); + $dataMessage = $this->getDataOrTerminateWithError($result); + + $prefix = "Re: "; // reply subject prefix + +/* $body = current($dataMessage->body); + $subject = $dataMessage->subject;*/ + + $subject = $dataMessage[0]->subject; + $body = $dataMessage[0]->body; + + + $replyBody = $this->_getReplyBody($body, $dataMessage[0]->nachname, $dataMessage[0]->vorname, $dataMessage[0]->insertamum); + + $dataMessage[0]->replyBody = $replyBody; + $dataMessage[0]->rest = "Help Manu"; + $dataMessage[0]->replySubject = $prefix . $subject; + + $this->terminateWithSuccess($dataMessage); + + + } + public function deleteMessage($messageId) { // Start DB transaction @@ -298,7 +335,7 @@ class Messages extends FHCAPI_Controller $result = $this->MessageModel->deleteMessageRecipient($messageId); if (isError($result)) { return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); - return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } $result = $this->MessageModel->deleteMessageStatus($messageId); @@ -316,6 +353,19 @@ class Messages extends FHCAPI_Controller $this->terminateWithSuccess($result); } + public function getPersonIdFromUid($uid) + { + $this->load->model('person/Benutzer_model', 'BenutzerModel'); + $result = $this->BenutzerModel->loadWhere( + ['uid' => $uid] + ); + + $data = $this->getDataOrTerminateWithError($result); + $benutzer = current($data); + + $this->terminateWithSuccess($benutzer->person_id); + } + private function _getPersonIdFromUid($uid) { $this->load->model('person/Benutzer_model', 'BenutzerModel'); @@ -326,7 +376,6 @@ class Messages extends FHCAPI_Controller $data = $this->getDataOrTerminateWithError($result); $benutzer = current($data); - //return $data->person_id; return $benutzer->person_id; } @@ -342,4 +391,23 @@ class Messages extends FHCAPI_Controller return $student->prestudent_id; } + + private function _getReplyBody($body, $receiverName, $receiverSurname, $sentDate) + { + // To quote a reply body message + $bodyFormat = "
+
+
+ + On %s %s %s wrote: + +
+
+ %s +
"; + return sprintf( + $bodyFormat, + date_format(date_create($sentDate), 'd.m.Y H:i'), $receiverName, $receiverSurname, $body + ); + } } \ No newline at end of file diff --git a/application/models/system/Message_model.php b/application/models/system/Message_model.php index 0fdb39736..38defa383 100644 --- a/application/models/system/Message_model.php +++ b/application/models/system/Message_model.php @@ -275,7 +275,7 @@ class Message_model extends DB_Model JOIN public.tbl_msg_message m USING(message_id) WHERE r.person_id = ? GROUP BY m.message_id, m.subject, m.body, m.insertamum, m.relationmessage_id, sender, recipient, sender_id, recipient_id - ORDER BY insertamum + ORDER BY insertamum DESC "; $parametersArray = array($person_id, $person_id); @@ -287,7 +287,7 @@ class Message_model extends DB_Model * Deletes a messages from tableMessages and tbl_msg_recipient * TODO(MANU) CHECK IF NECESSARY * dependency with other tables - * in case of reply... more messages + * in case of reply... more messages?? delete all dependent ones? * maybe anonimize it * @param $message_id * @return boolean success diff --git a/public/js/api/messages/person.js b/public/js/api/messages/person.js index 5cbb49550..7693c5189 100644 --- a/public/js/api/messages/person.js +++ b/public/js/api/messages/person.js @@ -14,6 +14,9 @@ export default { getMsgVarsPrestudent(uid){ return this.$fhcApi.get('api/frontend/v1/messages/messages/getMsgVarsPrestudent/' + uid); }, + getPersonIdFromUid(uid){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getPersonIdFromUid/' + uid); + }, getVorlagentext(vorlage_kurzbz){ return this.$fhcApi.get('api/frontend/v1/messages/messages/getVorlagentext/' + vorlage_kurzbz); }, @@ -24,6 +27,10 @@ export default { return this.$fhcApi.post('api/frontend/v1/messages/messages/getPreviewText/' + params.id + '/' + params.type_id, data); }, + getReplyData(messageId){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getReplyData/' + messageId); + + }, sendMessage(form, id, data) { return this.$fhcApi.post(form,'api/frontend/v1/messages/messages/sendMessage/' + id, data); diff --git a/public/js/apps/Nachrichten.js b/public/js/apps/Nachrichten.js index 0f921a9f8..84b9ddee5 100644 --- a/public/js/apps/Nachrichten.js +++ b/public/js/apps/Nachrichten.js @@ -8,6 +8,7 @@ const router = VueRouter.createRouter({ history: VueRouter.createWebHistory(), routes: [ { path: `/${ciPath}/NeueNachricht/:id/:typeId`, component: NewMessage }, + { path: `/${ciPath}/NeueNachricht/:id/:typeId/:messageId`, component: NewMessage }, ] }); diff --git a/public/js/components/Messages/Details/NewMessage/NewDiv.js b/public/js/components/Messages/Details/NewMessage/NewDiv.js index b31cd9932..1eb59aa20 100644 --- a/public/js/components/Messages/Details/NewMessage/NewDiv.js +++ b/public/js/components/Messages/Details/NewMessage/NewDiv.js @@ -36,6 +36,9 @@ export default { }, typeId(){ return this.$route.params.typeId || this.$props.id; + }, + messageId(){ + return this.$route.params.messageId; } }, data(){ @@ -62,7 +65,8 @@ export default { itemsPerson: [], itemsUser: [], previewText: null, - previewBody: "" + previewBody: "", + replyData: null } }, methods: { @@ -179,9 +183,9 @@ export default { console.error("Editor instance is not available."); } }, - replyMessage(message_id){ +/* replyMessage(message_id){ console.log("auf message " + message_id + " antworten"); - }, + },*/ resetForm(){ this.formData = { vorlage_kurzbz: null, @@ -293,6 +297,19 @@ export default { }) .catch(this.$fhcAlert.handleSystemError); + if(this.messageId != null) { + + //get replayBody.. body receivername, receiverSurname, sentDate of message + this.$fhcApi.factory.messages.person.getReplyData(this.messageId) + .then(result => { + this.replyData = result.data; + this.formData.subject = this.replyData[0].replySubject; + this.formData.body = this.replyData[0].replyBody; + }) + .catch(this.$fhcAlert.handleSystemError); + + } + }, async mounted() { this.initTinyMCE(); @@ -309,13 +326,7 @@ export default {
- - {{id}} || {{typeId}} -

New Message

-
diff --git a/public/js/components/Messages/Details/TableMessages.js b/public/js/components/Messages/Details/TableMessages.js index 7994cbe1d..ab6a76599 100644 --- a/public/js/components/Messages/Details/TableMessages.js +++ b/public/js/components/Messages/Details/TableMessages.js @@ -1,12 +1,12 @@ import {CoreFilterCmpt} from "../../filter/Filter.js"; import FormForm from '../../Form/Form.js'; -import NewMessage from "../Details/NewMessage.js"; +//import NewMessage from "../Details/NewMessage.js"; export default { components: { CoreFilterCmpt, FormForm, - NewMessage, + // NewMessage, }, inject: { cisRoot: { @@ -110,13 +110,15 @@ export default { container.className = "d-flex gap-2"; let button = document.createElement('button'); + if (this.personId != cell.getData().recipient_id) + button.disabled = true; button.className = 'btn btn-outline-secondary btn-action'; button.title = this.$p.t('global', 'reply'); button.innerHTML = ''; button.addEventListener( 'click', (event) => - this.reply(cell.getData().message_id) + this.actionReplyToMessage(cell.getData().message_id) ); container.append(button); @@ -141,6 +143,8 @@ export default { height: '400', selectable: true, selectableRangeMode: 'click', + pagination: true, + // paginationSize: 5, /* layoutColumnsOnNewData: false, selectableRangeMode: 'click', @@ -208,13 +212,11 @@ export default { ], tabulatorData: [], previewBody: "", - open: false + open: false, + personId: null } }, methods: { - reply(message_id){ - console.log("in reply " + message_id); - }, actionDeleteMessage(message_id){ this.$fhcAlert .confirmDelete() @@ -225,7 +227,6 @@ export default { .catch(this.$fhcAlert.handleSystemError); }, deleteMessage(message_id){ - // console.log("deleteMessage " + message_id); return this.$fhcApi.factory.messages.person.deleteMessage(message_id) .then(response => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); @@ -240,6 +241,9 @@ export default { //console.log("action new message"); }, + actionReplyToMessage(message_id){ + this.$emit('replyToMessage', this.id, this.typeId, message_id); + }, reload() { this.$refs.table.reloadTable(); }, @@ -264,6 +268,15 @@ export default { }); });*/ }, + created(){ + if(this.typeId == 'uid') { + this.$fhcApi.factory.messages.person.getPersonIdFromUid(this.id) + .then(result => { + this.personId = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + } + }, template: `
diff --git a/public/js/components/Messages/Messages.js b/public/js/components/Messages/Messages.js index 49fdbdf79..e6947a72a 100644 --- a/public/js/components/Messages/Messages.js +++ b/public/js/components/Messages/Messages.js @@ -76,6 +76,23 @@ export default { else console.log("no valid openMode"); }, + handleMessage(id, typeId, messageId){ + console.log("in handleMessage " + messageId); + if (this.openMode == "window") { + this.openInNewWindow(id, typeId, messageId); + } + else if (this.openMode == "newTab"){ + this.openInNewTab(id, typeId, messageId); + } + else if (this.openMode == "modal"){ + this.openInModal(id, typeId, messageId); + } + else if (this.openMode == "showDiv"){ + this.$refs.templateNewMessage.showTemplate(id, typeId, messageId); + } + else + console.log("no valid openMode"); + }, openInDiv(id, typeId){ this.$refs.templateNewMessage.showTemplate(id, typeId); //this.showDiv = true; //local variante @@ -85,15 +102,26 @@ export default { //TODO(manu) define bs-modal in this component this.$refs.templateNewMessage.$refs.modalMsg.show(); }, - openInNewTab(id, typeId){ +/* openInNewTab(id, typeId){ //TODO(MANU) check if array of ids... -/* let path = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router; - path += "/NeueNachricht/" + this.id + "/" + this.typeId;*/ - - //als param let path = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router; path += "/NeueNachricht/" + id + "/" + typeId; + const newTab = window.open(path, "_blank"); + },*/ + openInNewTab(id, typeId, messageId=null){ + //TODO(MANU) check if array of ids... + let path = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router; + + if (messageId){ + path += "/NeueNachricht/" + id + "/" + typeId + "/" + messageId; + } + + else { + path += "/NeueNachricht/" + id + "/" + typeId; + } + + const newTab = window.open(path, "_blank"); }, openInNewWindow(id, typeId){ @@ -152,7 +180,8 @@ export default { :endpoint="endpoint" :messageLayout="messageLayout" :openMode="openMode" - @newMessage="newMessage" + @newMessage="newMessage" + @replyToMessage="handleMessage" > From 1989e65d72d1532ab943c71eaaff4b6207581c79 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Mon, 10 Mar 2025 07:51:53 +0100 Subject: [PATCH 013/139] Tree structure for messages, preview in NewDiv, Note to close window, check recipient_id, save relationmessage_id --- .../api/frontend/v1/messages/Messages.php | 163 ++++++++++-------- public/js/api/messages/person.js | 12 +- .../Messages/Details/NewMessage/NewDiv.js | 117 ++++++++++--- .../Messages/Details/TableMessages.js | 144 +++++++++++++--- public/js/components/Messages/Messages.js | 3 +- .../Studentenverwaltung/Details/Messages.js | 14 +- 6 files changed, 329 insertions(+), 124 deletions(-) diff --git a/application/controllers/api/frontend/v1/messages/Messages.php b/application/controllers/api/frontend/v1/messages/Messages.php index d080cbee3..65c354c4f 100644 --- a/application/controllers/api/frontend/v1/messages/Messages.php +++ b/application/controllers/api/frontend/v1/messages/Messages.php @@ -19,7 +19,8 @@ class Messages extends FHCAPI_Controller 'getVorlagentext' => ['admin:r', 'assistenz:r'], 'getPreviewText' => ['admin:r', 'assistenz:r'], 'getReplyData' => ['admin:r', 'assistenz:r'], - 'getPersonIdFromUid' => ['admin:r', 'assistenz:r'], + 'getPersonId' => ['admin:r', 'assistenz:r'], + 'getUid' => ['admin:r', 'assistenz:r'], ]); //Load Models @@ -42,17 +43,8 @@ class Messages extends FHCAPI_Controller public function getMessages($id, $type_id) { - switch($type_id) - { - case 'uid': - $id = $this->_getPersonIdFromUid($id); - break; - case 'person_id': - $id = $id; - break; - default: - $this->terminateWithError("MESSAGES::getMessages logic for type_id " . $type_id . " not defined yet", self::ERROR_TYPE_GENERAL); - break; + if($type_id != 'person_id'){ + $id = $this->_getPersonId($id, $type_id); } $result = $this->MessageModel->getMessagesForTable($id); @@ -74,15 +66,13 @@ class Messages extends FHCAPI_Controller $this->load->model('system/Vorlage_model', 'VorlageModel'); - //39 Stück Variante OE $result = $this->VorlageModel->getAllVorlagenByOe($oe_kurzbz->oe_kurzbz); $data = $this->getDataOrTerminateWithError($result); $this->terminateWithSuccess($data); - //IF ADMIN 167 + //If admin $this->VorlageModel->addOrder('vorlage_kurzbz', 'ASC'); - //only HTML-vorlagen -> for admin $result = $this->VorlageModel->loadWhere( array( 'mimetype' => 'text/html' @@ -97,7 +87,7 @@ class Messages extends FHCAPI_Controller public function getVorlagentext($vorlage_kurzbz) { //$this->terminateWithError("vor " . $vorlage_kurzbz, self::ERROR_TYPE_GENERAL); - //$studiengang_kz = 227; //TODO(Manu) check dynamisieren NULL + //$studiengang_kz = 227; //TODO(Manu) dynamisieren NULL $studiengang_kz = 0; $this->load->model('system/Vorlagestudiengang_model', 'VorlagestudiengangModel'); $this->VorlagestudiengangModel->addOrder('version', 'DESC'); @@ -127,49 +117,32 @@ class Messages extends FHCAPI_Controller $this->terminateWithSuccess($data); } - public function getMsgVarsPrestudent($uid) + public function getMsgVarsPrestudent($id, $typeId) { - $prestudent_id = $this-> _getPrestudentIdFromUid($uid); + $prestudent_id = ($typeId == 'prestudent_id') ? $id : $this->_getPrestudentIdFromUid($id); $result = $this->MessageModel->getMsgVarsDataByPrestudentId($prestudent_id); $data = $this->getDataOrTerminateWithError($result); - $this->terminateWithSuccess($data); } public function getMsgVarsLoggedInUser() { - $uid = getAuthUID(); - $result = $this->MessageModel->getMsgVarsLoggedInUser(); - $data = $this->getDataOrTerminateWithError($result); - $this->terminateWithSuccess($data); } public function getNameOfDefaultRecipient($id, $type_id) { - switch($type_id) - { - case 'uid': - $id = $this->_getPersonIdFromUid($id); - break; - case 'person_id': - $id = $id; - break; - default: - $this->terminateWithError("MESSAGES::getNameOfDefaultRecipient logic for type_id " . $type_id . " not defined yet", self::ERROR_TYPE_GENERAL); - break; - } + $id = $type_id!='person_id)' ? $this->_getPersonId($id, $type_id) : $id; $this->load->model('person/Person_model', 'PersonModel'); $result = $this->PersonModel->load($id); - //$this->terminateWithSuccess($result); $data = $this->getDataOrTerminateWithError($result); $name = current($data); @@ -178,8 +151,11 @@ class Messages extends FHCAPI_Controller public function sendMessage($recipient_id) { + //is always uid in FAS + //TODO(Manu) make dynamic for other ids + //default setting - $receiversPersonId = $this->_getPersonIdFromUid($recipient_id); + $receiversPersonId = $this->_getPersonId($recipient_id, 'uid'); $uid = getAuthUID(); $this->load->model('person/Benutzer_model', 'BenutzerModel'); @@ -216,15 +192,13 @@ class Messages extends FHCAPI_Controller $subject = $this->input->post('subject'); $body = $this->input->post('body'); - - + $relationmessage_id = $this->input->post('relationmessage_id'); $typeId = $this->input->post('type_id'); $id = $this->input->post('id'); if($typeId == 'uid') { - //$this->terminateWithError("uid ", self::ERROR_TYPE_GENERAL); $prestudent_id = $this-> _getPrestudentIdFromUid($id); //parseMessagetext for variables Prestudent @@ -240,7 +214,7 @@ class Messages extends FHCAPI_Controller } elseif($typeId == 'prestudent_id') { - $this->terminateWithError("prestudent_id ", self::ERROR_TYPE_GENERAL); + // $this->terminateWithError("prestudent_id ", self::ERROR_TYPE_GENERAL); $result = $this->MessagesModel->parseMessageTextPrestudent($id, $body); $bodyParsed = $this->getDataOrTerminateWithError($result); @@ -250,7 +224,7 @@ class Messages extends FHCAPI_Controller $this->terminateWithError("type_id " . $typeId . " not valid", self::ERROR_TYPE_GENERAL); } - $result = $this->messagelib->sendMessageUser($receiversPersonId, $subject, $bodyParsed, $benutzer->person_id); + $result = $this->messagelib->sendMessageUser($receiversPersonId, $subject, $bodyParsed, $benutzer->person_id, null, $relationmessage_id); $this->terminateWithSuccess($result); } @@ -271,17 +245,15 @@ class Messages extends FHCAPI_Controller case 'uid': $prestudent_id = $this->_getPrestudentIdFromUid($id); $result = $this->MessagesModel->parseMessageTextPrestudent($prestudent_id, $data); - break; - case 'person_id': - $id = $id; + case 'prestudent_id': + $result = $this->MessagesModel->parseMessageTextPrestudent($id, $data); break; default: $this->terminateWithError("MESSAGES::getPreviewText logic for type_id " . $type_id . " not defined yet", self::ERROR_TYPE_GENERAL); break; } - //$this->terminateWithSuccess($result); $bodyParsed = $this->getDataOrTerminateWithError($result); $this->terminateWithSuccess($bodyParsed); @@ -289,10 +261,8 @@ class Messages extends FHCAPI_Controller public function getReplyData($messageId) { - // return $this->terminateWithError("in get ReplyBody" . $messageId, self::ERROR_TYPE_GENERAL); //TODO(Manu) validation of messageId: if number - $this->MessageModel->addSelect('public.tbl_msg_message.*'); $this->MessageModel->addSelect('r.*'); $this->MessageModel->addSelect('p.nachname'); @@ -304,14 +274,9 @@ class Messages extends FHCAPI_Controller array('r.message_id' => $messageId) ); - // $this->terminateWithSuccess((getData($result) ?: [])); $dataMessage = $this->getDataOrTerminateWithError($result); - $prefix = "Re: "; // reply subject prefix -/* $body = current($dataMessage->body); - $subject = $dataMessage->subject;*/ - $subject = $dataMessage[0]->subject; $body = $dataMessage[0]->body; @@ -323,8 +288,6 @@ class Messages extends FHCAPI_Controller $dataMessage[0]->replySubject = $prefix . $subject; $this->terminateWithSuccess($dataMessage); - - } public function deleteMessage($messageId) @@ -353,30 +316,94 @@ class Messages extends FHCAPI_Controller $this->terminateWithSuccess($result); } - public function getPersonIdFromUid($uid) + public function getPersonId($id, $typeId) { - $this->load->model('person/Benutzer_model', 'BenutzerModel'); - $result = $this->BenutzerModel->loadWhere( - ['uid' => $uid] - ); + if ($typeId == 'uid') + { + $this->load->model('person/Benutzer_model', 'BenutzerModel'); + $result = $this->BenutzerModel->loadWhere( + ['uid' => $id] + ); + } + elseif($typeId == 'prestudent_id') + { + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + $result = $this->PrestudentModel->loadWhere( + ['prestudent_id' => $id] + ); + } $data = $this->getDataOrTerminateWithError($result); - $benutzer = current($data); + $person = current($data); - $this->terminateWithSuccess($benutzer->person_id); + $this->terminateWithSuccess($person->person_id); } - private function _getPersonIdFromUid($uid) + public function getUid($id, $typeId) { - $this->load->model('person/Benutzer_model', 'BenutzerModel'); - $result = $this->BenutzerModel->loadWhere( - ['uid' => $uid] - ); + if (!$typeId) + { + $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Type ID']), self::ERROR_TYPE_GENERAL); + } + elseif ($typeId == 'person_id') + { + $this->load->model('person/Benutzer_model', 'BenutzerModel'); + $result = $this->BenutzerModel->loadWhere( + ['person_id' => $id] + ); + } + elseif($typeId == 'prestudent_id') + { + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + $result = $this->PrestudentModel->loadWhere( + ['prestudent_id' => $id] + ); + + $data = $this->getDataOrTerminateWithError($result); + $person = current($data); + $person_id = $person->person_id; + + $this->load->model('person/Benutzer_model', 'BenutzerModel'); + $result = $this->BenutzerModel->loadWhere( + ['person_id' => $person_id] + ); + } + elseif($typeId == 'uid') + { + $this->terminateWithSuccess($id); + } + else + { + $this->terminateWithError("MESSAGES::getUID logic for type_id " . $typeId . " not defined yet", self::ERROR_TYPE_GENERAL); + } $data = $this->getDataOrTerminateWithError($result); $benutzer = current($data); - return $benutzer->person_id; + $this->terminateWithSuccess($benutzer->uid); + } + + private function _getPersonId($id, $typeId) + { + if ($typeId == 'uid') + { + $this->load->model('person/Benutzer_model', 'BenutzerModel'); + $result = $this->BenutzerModel->loadWhere( + ['uid' => $id] + ); + } + elseif($typeId == 'prestudent_id') + { + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + $result = $this->PrestudentModel->loadWhere( + ['prestudent_id' => $id] + ); + } + + $data = $this->getDataOrTerminateWithError($result); + $person = current($data); + + return $person->person_id; } private function _getPrestudentIdFromUid($uid) diff --git a/public/js/api/messages/person.js b/public/js/api/messages/person.js index 7693c5189..e53f23f6a 100644 --- a/public/js/api/messages/person.js +++ b/public/js/api/messages/person.js @@ -11,11 +11,14 @@ export default { getMessageVarsPerson(){ return this.$fhcApi.get('api/frontend/v1/messages/messages/getMessageVarsPerson/'); }, - getMsgVarsPrestudent(uid){ - return this.$fhcApi.get('api/frontend/v1/messages/messages/getMsgVarsPrestudent/' + uid); + getMsgVarsPrestudent(params){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getMsgVarsPrestudent/' + params.id + '/' + params.type_id); }, - getPersonIdFromUid(uid){ - return this.$fhcApi.get('api/frontend/v1/messages/messages/getPersonIdFromUid/' + uid); + getPersonId(params){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getPersonId/'+ params.id + '/' + params.type_id); + }, + getUid(params){ + return this.$fhcApi.get('api/frontend/v1/messages/messages/getUid/'+ params.id + '/' + params.type_id); }, getVorlagentext(vorlage_kurzbz){ return this.$fhcApi.get('api/frontend/v1/messages/messages/getVorlagentext/' + vorlage_kurzbz); @@ -29,7 +32,6 @@ export default { }, getReplyData(messageId){ return this.$fhcApi.get('api/frontend/v1/messages/messages/getReplyData/' + messageId); - }, sendMessage(form, id, data) { return this.$fhcApi.post(form,'api/frontend/v1/messages/messages/sendMessage/' + id, diff --git a/public/js/components/Messages/Details/NewMessage/NewDiv.js b/public/js/components/Messages/Details/NewMessage/NewDiv.js index 1eb59aa20..d8611d611 100644 --- a/public/js/components/Messages/Details/NewMessage/NewDiv.js +++ b/public/js/components/Messages/Details/NewMessage/NewDiv.js @@ -44,14 +44,16 @@ export default { data(){ return { formData: { - recipient: this.id, + recipient: null, subject: null, body: null, vorlage_kurzbz: null, selectedValue: '', + relationmessage_id: null }, statusNew: true, vorlagen: [], + recipientsArray: [], defaultRecipient: null, editor: null, isVisible: false, @@ -66,7 +68,9 @@ export default { itemsUser: [], previewText: null, previewBody: "", - replyData: null + replyData: null, + uid: null, + messageSent: false } }, methods: { @@ -105,19 +109,22 @@ export default { sendMessage() { //TODO(Manu) check default recipient(s) const data = new FormData(); + const params = { id: this.id, type_id: this.typeId }; + const merged = { ...this.formData, ...params }; data.append('data', JSON.stringify(merged)); + //this.uid is important for existing sendFunction return this.$fhcApi.factory.messages.person.sendMessage( this.$refs.formMessage, - this.id, + this.uid, data) .then(response => { this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); @@ -129,6 +136,10 @@ export default { //this.resetForm(); //closeModal //closewindwo + this.messageSent = true; + //TODO(Manu) hier route definieren? ist kein child sondern mit route aufgerufen + //würde allerdings neues fenster aktualisiert öffnen, altes bleibt ohne reload gleich + //Reload vorheriges tab??? this.$emit('reloadTable'); } ); @@ -148,13 +159,13 @@ export default { //closewindwo }); }, - getPreviewText(){ + getPreviewText(id, typeId){ const data = new FormData(); data.append('data', JSON.stringify(this.formData.body)); return this.$fhcApi.factory.messages.person.getPreviewText({ - id: this.id, - type_id: this.typeId}, data) + id: id, + type_id: typeId}, data) .then(response => { this.previewText = response.data; }).catch(this.$fhcAlert.handleSystemError) @@ -167,7 +178,8 @@ export default { insertVariable(selectedItem){ if (this.editor) { this.editor.insertContent(selectedItem.value + " "); - //TODO(Manu) check: nicht mal mit Punkt adden gehts ohne eintrag nach vars + //TODO(Manu) check: Laden von Variblen geht nicht wenn kein Zeichen danach kommt + // nicht mal mit Punkt adden gehts ohne eintrag nach vars /* this.editor.focus(); this.editor.setDirty(true);*/ @@ -183,9 +195,6 @@ export default { console.error("Editor instance is not available."); } }, -/* replyMessage(message_id){ - console.log("auf message " + message_id + " antworten"); - },*/ resetForm(){ this.formData = { vorlage_kurzbz: null, @@ -219,11 +228,22 @@ export default { //just for testing: this.isVisible = true; }, - showPreview(){ - this.getPreviewText().then(() => { + showPreview(id, typeId){ + this.getPreviewText(id, typeId).then(() => { this.previewBody = this.previewText; }); }, + getUid(id, typeId){ + const params = { + id: id, + type_id: typeId + }; + this.$fhcApi.factory.messages.person.getUid(params) + .then(result => { + this.uid = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + } }, watch: { 'formData.body': { @@ -238,7 +258,6 @@ export default { }, 'formData.vorlage_kurzbz': { handler(newVal){ - // console.log("Vorlage: " + newVal); if (newVal && newVal != null) { this.formData.subject = newVal; @@ -248,6 +267,9 @@ export default { }, }, created(){ + if(this.typeId != 'uid') + this.getUid(this.id, this.typeId); + if(this.typeId == 'person_id'){ this.$fhcApi.factory.messages.person.getMessageVarsPerson() .then(result => { @@ -259,8 +281,13 @@ export default { }) .catch(this.$fhcAlert.handleSystemError); } - if(this.typeId == 'uid') { - this.$fhcApi.factory.messages.person.getMsgVarsPrestudent(this.id) + + if(this.typeId == 'uid' || this.typeId == 'prestudent_id') { + const params = { + id: this.id, + type_id: this.typeId + }; + this.$fhcApi.factory.messages.person.getMsgVarsPrestudent(params) .then(result => { this.fieldsPrestudent = result.data; const prestudent = this.fieldsPrestudent[0]; @@ -294,20 +321,21 @@ export default { }) .then(result => { this.defaultRecipient = result.data; + this.recipientsArray.push({'uid': this.uid, + 'details': this.defaultRecipient}); }) .catch(this.$fhcAlert.handleSystemError); + //case of reply if(this.messageId != null) { - - //get replayBody.. body receivername, receiverSurname, sentDate of message this.$fhcApi.factory.messages.person.getReplyData(this.messageId) .then(result => { this.replyData = result.data; this.formData.subject = this.replyData[0].replySubject; this.formData.body = this.replyData[0].replyBody; + this.formData.relationmessage_id = this.messageId; }) .catch(this.$fhcAlert.handleSystemError); - } }, @@ -320,12 +348,11 @@ export default { template: `
- -
+

New Message

@@ -465,19 +492,26 @@ export default {
-
+
+ +

- +
@@ -492,6 +526,43 @@ export default {
+ + +
+
+
+
+
+ Message sent successfully! +
+
+ Nachricht erfolgreich versandt! +
+
+ +
+
+ You can safely close this window. +
+
+ Sie können dieses Fenster schließen. +
+
+
+
+

+ Fachhochschule Technikum Wien | University of Applied Sciences Technikum Wien +
Hoechstaedtplatz 6, 1200 Wien, AUSTRIA +
www.technikum-wien.at +

+ +
+ + +
+ +
+
` diff --git a/public/js/components/Messages/Details/TableMessages.js b/public/js/components/Messages/Details/TableMessages.js index ab6a76599..317291c56 100644 --- a/public/js/components/Messages/Details/TableMessages.js +++ b/public/js/components/Messages/Details/TableMessages.js @@ -26,7 +26,6 @@ export default { messageLayout: String, openMode: String }, - //TODO(Manu) endpoint macht Probleme data(){ return { tabulatorOptions: { @@ -38,7 +37,7 @@ export default { type: this.typeId }; }, - ajaxResponse: (url, params, response) => response.data, + ajaxResponse: (url, params, response) => this.buildTreemap(response.data), columns: [ {title: "subject", field: "subject"}, {title: "body", field: "body", visible: false}, @@ -63,6 +62,7 @@ export default { {title: "recipient", field: "recipient"}, {title: "senderId", field: "sender_id"}, {title: "recipientId", field: "recipient_id"}, + {title: "relationmessage_id", field: "relationmessage_id"}, { title: "status", field: "status", @@ -110,7 +110,7 @@ export default { container.className = "d-flex gap-2"; let button = document.createElement('button'); - if (this.personId != cell.getData().recipient_id) + if (this.personId != cell.getData().sender_id) button.disabled = true; button.className = 'btn btn-outline-secondary btn-action'; button.title = this.$p.t('global', 'reply'); @@ -136,29 +136,23 @@ export default { return container; }, frozen: true - }], + } + ], layout: 'fitDataFill', layoutColumnsOnNewData: false, - // height: 'auto', height: '400', - selectable: true, selectableRangeMode: 'click', - pagination: true, - // paginationSize: 5, -/* layoutColumnsOnNewData: false, - - selectableRangeMode: 'click', - selectable: true, index: 'message_id', - persistenceID: 'core-message'*/ + pagination: true, + dataTree: true, + headerSort: true, + dataTreeChildField: "children", + dataTreeCollapseElement:"", + dataTreeChildIndent: 15, + dataTreeStartExpanded: false, + persistenceID: 'core-message' }, tabulatorEvents: [ - { - event: 'dataLoaded', - handler: data => this.tabulatorData = data.map(item => { - return item; - }), - }, { event: 'tableBuilt', handler: async() => { @@ -213,7 +207,59 @@ export default { tabulatorData: [], previewBody: "", open: false, - personId: null + personId: null, + //Testdata +/* messages: [ + { + message_id: 7, + subject: "Antwort auf 4", + body: "Text 5", + insertamum: "2024-03-05", + relationmessage_id: 6, + }, + { + message_id: 1, + subject: "Hauptnachricht", + body: "Text 1", + insertamum: "2024-03-05", + relationmessage_id: null, + }, + { + message_id: 2, + subject: "Antwort auf 1", + body: "Text 2", + insertamum: "2024-03-05", + relationmessage_id: 1, + }, + { + message_id: 3, + subject: "Antwort auf 2", + body: "Text 3", + insertamum: "2024-03-05", + relationmessage_id: 2, + }, + { + message_id: 4, + subject: "Neue Nachricht", + body: "Text 4", + insertamum: "2024-03-05", + relationmessage_id: null, + }, + { + message_id: 5, + subject: "Antwort auf 4", + body: "Text 5", + insertamum: "2024-03-05", + relationmessage_id: 4, + }, + { + message_id: 6, + subject: "Antwort auf 4", + body: "Text 5", + insertamum: "2024-03-05", + relationmessage_id: 5, + }, + ],*/ } }, methods: { @@ -237,7 +283,11 @@ export default { }); }, actionNewMessage(){ + // this.$emit('newMessage', this.id, this.typeId); + + //here already use person_id?? this.$emit('newMessage', this.id, this.typeId); + //console.log("action new message"); }, @@ -247,6 +297,47 @@ export default { reload() { this.$refs.table.reloadTable(); }, + buildTreemap(messages) { + const messageMap = new Map(); + const messageNested = []; + const remainingMessages = new Set(messages); + + //save all Data in Map + messages.forEach(msg => messageMap.set(msg.message_id, msg)); + + let iteration = 0; + let changes = true; + + // do until each relationmessage_id finds message_id (not sensitive to order) + while (changes) { + changes = false; + iteration++; + + remainingMessages.forEach(msg => { + if (msg.relationmessage_id === null) { + messageNested.push(messageMap.get(msg.message_id)); + remainingMessages.delete(msg); + changes = true; + } else if (messageMap.has(msg.relationmessage_id)) { + + const parent = messageMap.get(msg.relationmessage_id); + + if (!parent.children) { + parent.children = []; + } + parent.children.push(messageMap.get(msg.message_id)); + remainingMessages.delete(msg); + changes = true; + } + }); + + // to avoid endless loop + if (iteration > messages.length) break; + } + return messageNested; +} + + }, computed: { statusText(){ @@ -256,7 +347,7 @@ export default { 2: this.$p.t('messsages', 'archived'), 3: this.$p.t('messsages', 'deleted') } - } + }, }, mounted() { // change to target="_blank" @@ -269,8 +360,12 @@ export default { });*/ }, created(){ - if(this.typeId == 'uid') { - this.$fhcApi.factory.messages.person.getPersonIdFromUid(this.id) + if(this.typeId == 'uid' || this.typeId == 'prestudent_id') { + const params = { + id: this.id, + type_id: this.typeId + }; + this.$fhcApi.factory.messages.person.getPersonId(params) .then(result => { this.personId = result.data; }) @@ -279,7 +374,7 @@ export default { }, template: `
- +
@@ -313,6 +408,7 @@ export default {
+
diff --git a/public/js/components/Messages/Messages.js b/public/js/components/Messages/Messages.js index e6947a72a..fc73768f1 100644 --- a/public/js/components/Messages/Messages.js +++ b/public/js/components/Messages/Messages.js @@ -58,6 +58,7 @@ export default { }, methods: { reloadTable(){ + console.log("in parent reload"); this.$refs.templateTableMessage.reload(); }, newMessage(id, typeId){ @@ -121,7 +122,6 @@ export default { path += "/NeueNachricht/" + id + "/" + typeId; } - const newTab = window.open(path, "_blank"); }, openInNewWindow(id, typeId){ @@ -160,6 +160,7 @@ export default {
--> +
+ + +
` From f8eb265eb0914d39d9655148385c0b9b9c95db74 Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Mon, 10 Mar 2025 22:35:14 +0100 Subject: [PATCH 014/139] Studentenverwaltung Archiv: non-signable documents can be archived, set correct default Vorlage (Zeugnis) --- public/js/api/stv/archiv.js | 6 +++ .../Stv/Studentenverwaltung/Details/Archiv.js | 52 ++++++++++--------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/public/js/api/stv/archiv.js b/public/js/api/stv/archiv.js index 76dbecec8..9b8bdf416 100644 --- a/public/js/api/stv/archiv.js +++ b/public/js/api/stv/archiv.js @@ -16,6 +16,12 @@ export default { 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 diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Archiv.js b/public/js/components/Stv/Studentenverwaltung/Details/Archiv.js index 1856815a1..fd174e16f 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Archiv.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Archiv.js @@ -23,7 +23,7 @@ export default { data() { return { loading: false, - vorlage_kurzbz: '', + selectedVorlage: {}, vorlagenArchiv: [], vorlageXmlXslMappings: { 'zeugnis.rdf.php': [ @@ -190,32 +190,34 @@ export default { this.$refs.table.tabulator.updateOrAddData(data); }, actionArchive() { - console.log(this.modelValue); let archiveDataArr = Array.isArray(this.modelValue) ? this.modelValue : [this.modelValue]; for (let archiveData of archiveDataArr) { this.loading = true; - this.$fhcApi - .factory.stv.archiv.archive({ - xml: this.getXmlByXsl(this.vorlage_kurzbz), - xsl: this.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; - }); - + 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) { @@ -237,7 +239,7 @@ export default { created() { this.$fhcApi .factory.stv.archiv.getArchivVorlagen() - .then(result => {this.vorlagenArchiv = result.data; this.vorlage_kurzbz = result.data.length > 0 ? result.data[0].vorlage_kurzbz : '';}) + .then(result => {this.vorlagenArchiv = result.data; this.selectedVorlage = result.data.filter(o => o.vorlage_kurzbz == 'Zeugnis')[0];}) .catch(this.$fhcAlert.handleSystemError); }, @@ -253,8 +255,8 @@ export default { >