From fa74438f6652ae6cbd688a18528dd9fa9a3ae1b5 Mon Sep 17 00:00:00 2001 From: cgfhtw Date: Mon, 2 Oct 2023 16:38:11 +0200 Subject: [PATCH] Validation --- .../controllers/Studentenverwaltung.php | 3 +- .../controllers/components/stv/Student.php | 141 ++++++++------ application/views/Studentenverwaltung.php | 11 +- public/css/Studentenverwaltung.css | 13 +- .../js/components/Stv/Studentenverwaltung.js | 7 +- .../Studentenverwaltung/Details/Details.js | 175 ++++++++++++++---- 6 files changed, 258 insertions(+), 92 deletions(-) diff --git a/application/controllers/Studentenverwaltung.php b/application/controllers/Studentenverwaltung.php index 36b96af5e..64db67ef1 100644 --- a/application/controllers/Studentenverwaltung.php +++ b/application/controllers/Studentenverwaltung.php @@ -19,7 +19,8 @@ class Studentenverwaltung extends FHC_Controller $this->load->view('Studentenverwaltung', [ 'permissions' => [ - 'student/bpk' => $this->permissionlib->isBerechtigt('student/bpk') + 'student/bpk' => $this->permissionlib->isBerechtigt('student/bpk'), + 'student/alias' => $this->permissionlib->isBerechtigt('student/alias') ] ]); } diff --git a/application/controllers/components/stv/Student.php b/application/controllers/components/stv/Student.php index afb052861..a407d20c1 100644 --- a/application/controllers/components/stv/Student.php +++ b/application/controllers/components/stv/Student.php @@ -2,12 +2,19 @@ if (! defined('BASEPATH')) exit('No direct script access allowed'); +use \DateTime as DateTime; + class Student extends FHC_Controller { public function __construct() { // TODO(chris): access! parent::__construct(); + + // Load language phrases + $this->loadPhrases([ + 'ui' + ]); } public function get($prestudent_id) @@ -94,6 +101,7 @@ class Student extends FHC_Controller $this->outputJson(getData($result) ?: []); } } + public function save($prestudent_id) { // TODO(chris): stdSem from Variable @@ -104,7 +112,18 @@ class Student extends FHC_Controller $this->load->model('crm/Prestudent_model', 'PrestudentModel'); $this->load->model('education/Studentlehrverband_model', 'StudentlehrverbandModel'); - $data = json_decode(utf8_encode($this->input->raw_input_stream), true); + $this->load->library('form_validation'); + + $_POST = json_decode(utf8_encode($this->input->raw_input_stream), true); + + $this->form_validation->set_rules('gebdatum', 'Geburtsdatum', 'callback_isValidDate', [ + 'isValidDate' => $this->p->t('ui', 'error_invalid_date') + ]); + // TODO(chris): other validations? + + if ($this->form_validation->run() == false) { + return $this->outputJsonError($this->form_validation->error_array()); + } $result = $this->StudentModel->loadWhere(['prestudent_id' =>$prestudent_id]); if (isError($result)) { @@ -128,30 +147,17 @@ class Student extends FHC_Controller $person_id = $person->person_id; } - $array_allowed_props = ['verband','semester','gruppe']; - $update = array(); - foreach ($array_allowed_props as $prop) + $array_allowed_props_lehrverband = ['verband', 'semester', 'gruppe']; + $update_lehrverband = array(); + foreach ($array_allowed_props_lehrverband as $prop) { - if(isset($data[$prop])){ - $update[$prop] = $data[$prop]; + $val = $this->input->post($prop); + if ($val !== null) { + $update_lehrverband[$prop] = $val; } } - //TODO(chris): form validation verband - if (count($update)) - { - if($uid === null) - { - $this->output->set_status_header(REST_Controller::HTTP_BAD_REQUEST); - return $this->outputJson("Kein/e StudentIn vorhanden!"); - } - $this->StudentlehrverbandModel->update([ - 'studiensemester_kurzbz' => $studiensemester_kurzbz, - 'student_uid' => $uid], - $update - ); - } - $array_allowed_props = [ + $array_allowed_props_person = [ 'anrede', 'bpk', 'titelpre', @@ -160,7 +166,7 @@ class Student extends FHC_Controller 'vorname', 'vornamen', 'wahlname', - 'geburtsdatum', + 'gebdatum', 'gebort', 'geburtsnation', 'svnr', @@ -174,52 +180,83 @@ class Student extends FHC_Controller 'anmerkung', 'homepage' ]; - $update = array(); - foreach ($array_allowed_props as $prop) + $update_person = array(); + foreach ($array_allowed_props_person as $prop) { - if(isset($data[$prop])){ - $update[$prop] = $data[$prop]; + $val = $this->input->post($prop); + if ($val !== null) { + $update_person[$prop] = $val; } } - if (count($update)) + $array_allowed_props_student = ['matrikelnr']; + $update_student = array(); + foreach ($array_allowed_props_student as $prop) { - if($person_id === null) - { - $this->output->set_status_header(REST_Controller::HTTP_BAD_REQUEST); - return $this->outputJson("Keine Person vorhanden!"); + $val = $this->input->post($prop); + if ($val !== null) { + $update_student[$prop] = $val; } - $this->PersonModel->update( + } + + if (count($update_lehrverband) + count($update_student) && $uid === null) { + $this->output->set_status_header(REST_Controller::HTTP_BAD_REQUEST); + // TODO(chris): phrase + return $this->outputJson("Kein/e StudentIn vorhanden!"); + } + if (count($update_person) && $person_id === null) { + $this->output->set_status_header(REST_Controller::HTTP_BAD_REQUEST); + // TODO(chris): phrase + return $this->outputJson("Keine Person vorhanden!"); + } + + if (count($update_lehrverband)) + { + $result = $this->StudentlehrverbandModel->update([ + 'studiensemester_kurzbz' => $studiensemester_kurzbz, + 'student_uid' => $uid + ], $update_lehrverband); + if (isError($result)) { + $this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR); + return $this->outputJson(getError($result)); + } + } + + if (count($update_person)) + { + $result = $this->PersonModel->update( $person_id, - $update + $update_person ); + if (isError($result)) { + $this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR); + return $this->outputJson(getError($result)); + } } - $array_allowed_props = ['matrikelnr']; - $update = array(); - foreach ($array_allowed_props as $prop) + if (count($update_student)) { - if(isset($data[$prop])){ - $update[$prop] = $data[$prop]; - } - } - if (count($update)) - { - if ($uid === null) { - $this->output->set_status_header(REST_Controller::HTTP_BAD_REQUEST); - return $this->outputJson("Kein/e StudentIn vorhanden!"); - } - $this->StudentModel->update( + $result = $this->StudentModel->update( [$uid], - $update + $update_student ); + if (isError($result)) { + $this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR); + return $this->outputJson(getError($result)); + } } + $this->outputJsonSuccess(true); + } - - - - + public function isValidDate($date) + { + try { + new DateTime($date); + } catch (Exception $e) { + return false; + } + return true; } } diff --git a/application/views/Studentenverwaltung.php b/application/views/Studentenverwaltung.php index 18a67423e..5928a2b00 100644 --- a/application/views/Studentenverwaltung.php +++ b/application/views/Studentenverwaltung.php @@ -13,6 +13,9 @@ 'public/css/Studentenverwaltung.css', 'public/css/components/vue-datepicker.css' ], + 'customJSs' => [ + 'vendor/npm-asset/primevue/toast/toast.min.js' + ], 'customJSModules' => [ 'public/js/apps/Studentenverwaltung.js' ] @@ -22,7 +25,13 @@ ?>
- + +
load->view('templates/FHC-Footer', $includesArray); ?> diff --git a/public/css/Studentenverwaltung.css b/public/css/Studentenverwaltung.css index ccc5b0694..d48397cc7 100644 --- a/public/css/Studentenverwaltung.css +++ b/public/css/Studentenverwaltung.css @@ -57,4 +57,15 @@ } .stv-list > #filterTableDataset { flex: 1 1 auto; -} \ No newline at end of file +} + +.toast.toast-success { + color: #0f5132; + background-color: #d1e7dd!important; + border-color: #badbcc!important; +} +.toast.toast-danger { + color: #842029; + background-color: #f8d7da!important; + border-color: #f5c2c7!important; +} diff --git a/public/js/components/Stv/Studentenverwaltung.js b/public/js/components/Stv/Studentenverwaltung.js index 3b8fdbc82..bc30ed02a 100644 --- a/public/js/components/Stv/Studentenverwaltung.js +++ b/public/js/components/Stv/Studentenverwaltung.js @@ -31,15 +31,18 @@ export default { VerticalSplit }, props: { + config: Object, permissions: Object, cisRoot: String, activeAddons: String // semicolon separated list of active addons }, provide() { return { - hasBpkPermission: this.permissions['student/bpk'], cisRoot: this.cisRoot, - activeAddonBewerbung: this.activeAddons.split(';').includes('bewerbung') + activeAddonBewerbung: this.activeAddons.split(';').includes('bewerbung'), + configGenerateAlias: this.config.generateAlias, + hasBpkPermission: this.permissions['student/bpk'], + hasAliasPermission: this.permissions['student/alias'] } }, data() { diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Details.js b/public/js/components/Stv/Studentenverwaltung/Details/Details.js index df7a2e1f6..a3433584a 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Details.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Details.js @@ -5,7 +5,8 @@ import {CoreRESTClient} from '../../../../RESTClient.js'; export default { components: { VueDatePicker, - FormUploadImage + FormUploadImage, + PvToast: primevue.toast }, inject: { showBpk: { @@ -18,6 +19,14 @@ export default { }, cisRoot: { from: 'cisRoot' + }, + generateAlias: { + from: 'configGenerateAlias', + default: false + }, + hasAliasPermission: { + from: 'hasAliasPermission', + default: false } }, props: { @@ -35,13 +44,42 @@ export default { "v": "verheiratet", "w": "verwitwet" }, + original: null, data: null, - studentIn: null + changed: {}, + studentIn: null, + gebDatumIsValid: false, + gebDatumIsInvalid: false + } + }, + computed: { + aliasNotAllowed() { + return this.generateAlias === false && !this.hasAliasPermission; + }, + changedLength() { + return Object.keys(this.changed).length; } }, watch: { student(n) { this.updateStudent(n); + }, + data: { + handler(n) { + let res = {}; + for (var k in this.original) { + if (k == 'gebdatum') { + if (new Date(this.original[k]).toString() != new Date(n[k]).toString()) + res[k] = n[k]; + } else { + if (this.original[k] !== n[k]) + res[k] = n[k]; + } + } + this.changed = res; + this.resetErrors(); + }, + deep: true } }, methods: { @@ -53,6 +91,7 @@ export default { this.data = result; if (!this.data.familienstand) this.data.familienstand = ''; + this.original = {...this.data}; }) .catch(err => { console.error(err.response.data || err.message); @@ -60,7 +99,67 @@ export default { }, save() { CoreRESTClient - .post('components/stv/Student/save/' + this.student.prestudent_id, this.data) + .post('components/stv/Student/save/' + this.student.prestudent_id, this.changed) + .then(result => result.data) + .then(result => { + this.resetErrors(); + if (CoreRESTClient.isError(result)) { + let errors = CoreRESTClient.getError(result); + + if (errors === "Generic error") + console.error(errors, result); + else { + for (var k in errors) + this.addError(k, errors[k]); + } + } else { + for (var node of document.querySelectorAll(Object.keys(this.changed).map(el => '#stv-details-' + el).join(','))) + node.classList.add('is-valid'); + if (this.changed.gebdatum !== undefined) + this.gebDatumIsValid = true; + + // TODO(chris): phrase + this.addToast('Gespeichert', '', 'success'); + + this.original = {...this.data}; + this.changed = {}; + } + }) + .catch(err => { + // TODO(chris): phrase + this.addToast('Error', err?.response?.data || err?.message, 'error'); + }) + }, + resetErrors() { + Array.from(this.$refs.form.getElementsByClassName('is-valid')).forEach(el => el.classList.remove('is-valid')); + Array.from(this.$refs.form.getElementsByClassName('is-invalid')).forEach(el => el.classList.remove('is-invalid')); + Array.from(this.$refs.form.getElementsByClassName('invalid-feedback')).forEach(el => el.remove()); + this.gebDatumIsValid = false; + this.gebDatumIsInvalid = false; + }, + addError(field, msg) { + let id = 'stv-details-' + field; + + let input = document.getElementById(id); + if (field === 'gebdatum') { + this.gebDatumIsInvalid = true; + input = document.getElementById('dp-input-' + id).parentNode; + } + + input.classList.add('is-invalid'); + + let feedback = document.createElement('div'); + feedback.classList.add('invalid-feedback'); + feedback.innerHTML = msg; + input.after(feedback); + }, + addToast(header, msg, severity) { + this.$refs.responseToast.add({ + severity: severity, + summary: header, + detail: msg, + life: 3000 + }) } }, created() { @@ -90,68 +189,73 @@ export default { }); this.updateStudent(this.student); }, - //TODO(chris): Felder student_uid, person_id sperren, Personenkz + mounted() { + console.log(); + }, + //TODO(chris): Geburtszeit? Anzahl der Kinder? template: ` -
+
Person @@ -231,11 +335,11 @@ export default {
- +
- +
@@ -247,30 +351,31 @@ export default {
- +
- +
- +
- +
- +
Loading...
+
` }; \ No newline at end of file