From 410f0c4b6afb35d6834ce5eab7bfbc09e8caffb8 Mon Sep 17 00:00:00 2001 From: Johann Hoffmann Date: Tue, 11 Nov 2025 13:44:47 +0100 Subject: [PATCH] fixtermin -> "kein neichreichen erlaubt" phrase/bool logic change; signatur message on enduploads fetched from signatur server on every load request; Inplace toggle for further infos in offcanvas timeline & student details on mobile view(tooltips); reworked col/row structure on detail views for mobile; --- .../controllers/api/frontend/v1/Abgabe.php | 127 ++++++---- application/views/Cis/Abgabetool.php | 1 + .../views/CisRouterView/CisRouterView.php | 1 + public/js/api/factory/abgabe.js | 5 - .../Cis/Abgabetool/AbgabeMitarbeiterDetail.js | 117 ++++++--- .../Cis/Abgabetool/AbgabeStudentDetail.js | 172 +++++++++---- .../Cis/Abgabetool/AbgabetoolAssistenz.js | 12 +- .../Cis/Abgabetool/AbgabetoolStudent.js | 14 +- .../Cis/Abgabetool/DeadlineOverview.js | 2 +- system/phrasesupdate.php | 226 +++++++++++++++++- 10 files changed, 528 insertions(+), 149 deletions(-) diff --git a/application/controllers/api/frontend/v1/Abgabe.php b/application/controllers/api/frontend/v1/Abgabe.php index df687acea..b1eaa9914 100644 --- a/application/controllers/api/frontend/v1/Abgabe.php +++ b/application/controllers/api/frontend/v1/Abgabe.php @@ -45,6 +45,7 @@ class Abgabe extends FHCAPI_Controller ]); $this->load->library('PhrasesLib'); + $this->load->library('SignatureLib'); // Loads LogLib with different debug trace levels to get data of the job that extends this class // It also specify parameters to set database fields @@ -113,6 +114,10 @@ class Abgabe extends FHCAPI_Controller $ret = $this->ProjektarbeitModel->getProjektarbeitAbgabetermine($projektarbeit_id); + foreach($ret->retval as $termin) { + $this->checkAbgabeSignatur($termin, $projektarbeit); + } + $this->terminateWithSuccess(array($ret, $paIsCurrent)); } @@ -134,7 +139,7 @@ class Abgabe extends FHCAPI_Controller $this->addMeta('isZugeteilterBetreuer', $isZugeteilterBetreuer); $isMitarbeiter = $this->MitarbeiterModel->isMitarbeiter(getAuthUID()); - if ($isMitarbeiter && $isZugeteilterBetreuer){ + if ($isMitarbeiter) { $result = $this->ProjektarbeitModel->getStudentProjektarbeitenWithBetreuer($uid); } else { $result = $this->ProjektarbeitModel->getStudentProjektarbeitenWithBetreuer(getAuthUID()); @@ -152,7 +157,7 @@ class Abgabe extends FHCAPI_Controller } if($pa->zweitbetreuer_person_id !== null) { - // TODO: dont have to wait for 2038, see assistenz query in projektarbeit_model + // TODO: see assistenz query in projektarbeit_model // zweitbetreuer info since the 'getStudentProjektarbeitenWithBetreuer' query got quiete large, // enjoy optimizing that one in 2038. we need this to render a string like @@ -165,8 +170,6 @@ class Abgabe extends FHCAPI_Controller $pa->zweitbetreuer = $data[0]; } } - - } } @@ -206,7 +209,8 @@ class Abgabe extends FHCAPI_Controller 'updateamum' => date('Y-m-d H:i:s') )); - $this->sendUploadEmail($bperson_id, $projektarbeit_id, $paabgabetyp_kurzbz, $student_uid); + // TODO: consider this for daily abgabetool email job +// $this->sendUploadEmail($bperson_id, $projektarbeit_id, $paabgabetyp_kurzbz, $student_uid); $this->logLib->logInfoDB(array('zwischenupload',$res, array( 'abgabedatum' => date('Y-m-d'), @@ -256,48 +260,53 @@ class Abgabe extends FHCAPI_Controller if(file_exists(PAABGABE_PATH.$paabgabe_id.'_'.$student_uid.'.pdf')) { - // Loads Libraries - $this->load->library('SignatureLib'); + $this->load->model('education/Projektarbeit_model', 'ProjektarbeitModel'); - // Check if the document is signed - $signaturVorhanden = true; - $signList = SignatureLib::list(PAABGABE_PATH.$paabgabe_id.'_'.$student_uid.'.pdf'); - if (is_array($signList) && count($signList) > 0) - { - // The document is signed - $uploadedDocumentSigned = 'The document is signed'; - } - elseif ($signList === null) - { - $uploadedDocumentSigned = 'WARNING: signature server error'; - } - else - { - $signaturVorhanden = false; - $uploadedDocumentSigned = 'No document signature found'; - } - $this->addMeta('signaturInfo', $uploadedDocumentSigned); + $result = $this->ProjektarbeitModel->load($projektarbeit_id); + $projektarbeitArr = $this->getDataOrTerminateWithError($result); - if ($signaturVorhanden === false) + if(count($projektarbeitArr) > 0) { + $projektarbeit = $projektarbeitArr[0]; + } else { + $this->terminateWithError($this->p->t('global','projektarbeitNichtGefunden'), 'general'); + } + + $this->load->model('education/Paabgabe_model', 'PaabgabeModel'); + $result = $this->PaabgabeModel->load($paabgabe_id); + $paabgabeArr = $this->getDataOrTerminateWithError($result); + + if(count($paabgabeArr) > 0) { + $paabgabe = $paabgabeArr[0]; + } else { + $this->terminateWithError($this->p->t('global','projektabgabeNichtGefunden'), 'general'); + } + + $this->checkAbgabeSignatur($paabgabe, $projektarbeit); + $signaturstatus = $paabgabe->signatur; + + if ($paabgabe->signatur === false) { $this->signaturFehltEmail($student_uid); } // update projektarbeit cols - $this->load->model('education/Projektarbeit_model', 'ProjektarbeitModel'); $this->ProjektarbeitModel->updateProjektarbeit($projektarbeit_id,$sprache,$abstract,$abstract_en ,$schlagwoerter, $schlagwoerter_en, $seitenanzahl); // update paabgabe datum - $this->load->model('education/Paabgabe_model', 'PaabgabeModel'); $res = $this->PaabgabeModel->update($paabgabe_id, array( 'abgabedatum' => date('Y-m-d'), 'updatevon' => getAuthUID(), 'updateamum' => date('Y-m-d H:i:s') )); - $this->sendUploadEmail($bperson_id, $projektarbeit_id, $paabgabetyp_kurzbz, $student_uid); + $res = $this->PaabgabeModel->load($res->retval); + $abgabe = getData($res)[0]; + $abgabe->signatur = $signaturstatus; + + // TODO: consider for email job +// $this->sendUploadEmail($bperson_id, $projektarbeit_id, $paabgabetyp_kurzbz, $student_uid); $this->logLib->logInfoDB(array('endupload',$res, array( 'abgabedatum' => date('Y-m-d'), @@ -306,7 +315,7 @@ class Abgabe extends FHCAPI_Controller ), getAuthUID(), getAuthPersonId(), array($projektarbeit_id,$sprache,$abstract,$abstract_en ,$schlagwoerter, $schlagwoerter_en, $seitenanzahl))); - $this->terminateWithSuccess($res); + $this->terminateWithSuccess($abgabe); } else { $this->terminateWithError('Error moving File'); } @@ -436,12 +445,12 @@ class Abgabe extends FHCAPI_Controller if ($zweitbegutachterRes) { - $zweitbegutachterResults = $zweitbegutachterRes->retval; + $zweitbegutachterResults = getData($zweitbegutachterRes->retval)[0]; foreach ($zweitbegutachterResults as $begutachter) { // token generieren, wenn noch nicht vorhanden und notwendig (wird in methode überprüft) - $tokenGenRes = $zweitbegutachter->generateZweitbegutachterToken($begutachter->person_id, $projektarbeit_id); + $tokenGenRes = $this->ProjektbetreuerModel->generateZweitbegutachterToken($begutachter->person_id, $projektarbeit_id); if (!$tokenGenRes) { @@ -870,6 +879,7 @@ class Abgabe extends FHCAPI_Controller if (!isset($studiengang_kz) || isEmptyString($studiengang_kz)) $this->terminateWithError($this->p->t('global', 'wrongParameters'), 'general'); + $result = $this->ProjektarbeitModel->getProjektarbeitenForStudiengang($studiengang_kz, $benotet); $projektarbeiten = $this->getDataOrTerminateWithError($result); @@ -886,15 +896,17 @@ class Abgabe extends FHCAPI_Controller $projektabgaben = $this->getDataOrTerminateWithError($ret); // map the abgaben into projektarbeiten - foreach($projektarbeiten as $projektarbeit) { $filterFunc = function($projektabgabe) use ($projektarbeit) { return $projektabgabe->projektarbeit_id == $projektarbeit->projektarbeit_id; }; - $projektarbeit->abgabetermine = array_values(array_filter($projektabgaben, $filterFunc)); - + + // check the signature status for enduploads + foreach($projektarbeit->abgabetermine as $abgabe) { + $this->checkAbgabeSignatur($abgabe, $projektarbeit); + } } $this->terminateWithSuccess(array($projektarbeiten, DOMAIN)); @@ -935,18 +947,10 @@ class Abgabe extends FHCAPI_Controller if(getAuthUID() == $student_uid || $isZugeteilterBetreuer || $isAssistenz) { $file_path = PAABGABE_PATH.$paabgabe_id.'_'.$student_uid.'.pdf'; + + if(file_exists($file_path)) { - - header('Content-Description: File Transfer'); - header('Content-Type: application/octet-stream'); - header('Expires: 0'); - header('Cache-Control: must-revalidate'); - header('Pragma: public'); - header('Content-Disposition: attachment; filename="'.basename($file_path).'"'); - header('Content-Length: ' . filesize($file_path)); - - flush(); // send headers first just in case - readfile($file_path); // read file content to output buffer + $this->terminateWithFileOutput('application/octet-stream', filesize($file_path), basename($file_path)); } else { $this->terminateWithError('File not found'); @@ -955,5 +959,36 @@ class Abgabe extends FHCAPI_Controller $this->terminateWithError('Keine Zuordnung!'); } } + + private function checkAbgabeSignatur($abgabe, $projektarbeit) { + if($abgabe->paabgabetyp_kurzbz != 'end') { + return; + } + + $path = PAABGABE_PATH.$abgabe->paabgabe_id.'_'.$projektarbeit->student_uid.'.pdf'; + + $signaturVorhanden = null; // if frontend receives null -> indicates no file found at path + if(file_exists($path)) { + + // Check if the document is signed + $signList = SignatureLib::list($path); + if (is_array($signList) && count($signList) > 0) + { + // The document is signed + $signaturVorhanden = true; + } + elseif ($signList === null) + { + // frontend knows to handle it this way for signatures + $signaturVorhanden = 'error'; + } + else + { + $signaturVorhanden = false; + } + + $abgabe->signatur = $signaturVorhanden; + } + } } \ No newline at end of file diff --git a/application/views/Cis/Abgabetool.php b/application/views/Cis/Abgabetool.php index 422ae1087..2e1daf2cd 100644 --- a/application/views/Cis/Abgabetool.php +++ b/application/views/Cis/Abgabetool.php @@ -26,6 +26,7 @@ $includesArray = array( 'vendor/npm-asset/primevue/textarea/textarea.min.js', 'vendor/npm-asset/primevue/timeline/timeline.min.js', 'vendor/npm-asset/primevue/inplace/inplace.min.js', + 'vendor/npm-asset/primevue/message/message.min.js', 'vendor/moment/luxonjs/luxon.min.js' ), 'customJSModules' => array( diff --git a/application/views/CisRouterView/CisRouterView.php b/application/views/CisRouterView/CisRouterView.php index af35cd4eb..1b3e767b2 100644 --- a/application/views/CisRouterView/CisRouterView.php +++ b/application/views/CisRouterView/CisRouterView.php @@ -34,6 +34,7 @@ $includesArray = array( 'vendor/npm-asset/primevue/textarea/textarea.min.js', 'vendor/npm-asset/primevue/timeline/timeline.min.js', 'vendor/npm-asset/primevue/inplace/inplace.min.js', + 'vendor/npm-asset/primevue/message/message.min.js', 'vendor/moment/luxonjs/luxon.min.js' ), 'customJSModules' => array( diff --git a/public/js/api/factory/abgabe.js b/public/js/api/factory/abgabe.js index 417e5fab3..6f86939b5 100644 --- a/public/js/api/factory/abgabe.js +++ b/public/js/api/factory/abgabe.js @@ -35,11 +35,6 @@ export default { config: {Headers: { "Content-Type": "multipart/form-data" }} }; }, - getStudentProjektarbeitAbgabeFile(paabgabe_id, student_uid) { - const url = `/api/frontend/v1/Abgabe/getStudentProjektarbeitAbgabeFile?paabgabe_id=${paabgabe_id}&student_uid=${student_uid}`; - - window.open(FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + url) - }, getMitarbeiterProjektarbeiten(all) { return { method: 'get', diff --git a/public/js/components/Cis/Abgabetool/AbgabeMitarbeiterDetail.js b/public/js/components/Cis/Abgabetool/AbgabeMitarbeiterDetail.js index 1e39e0ddb..e46067c38 100644 --- a/public/js/components/Cis/Abgabetool/AbgabeMitarbeiterDetail.js +++ b/public/js/components/Cis/Abgabetool/AbgabeMitarbeiterDetail.js @@ -14,6 +14,7 @@ export const AbgabeMitarbeiterDetail = { SpeedDial: primevue.speeddial, Accordion: primevue.accordion, AccordionTab: primevue.accordiontab, + Message: primevue.message, VueDatePicker }, inject: [ @@ -74,6 +75,9 @@ export const AbgabeMitarbeiterDetail = { const paabgabe_id = termin.paabgabe_id termin.note_pk = termin.note?.note ?? null termin.betreuer_person_id = this.projektarbeit.betreuer_person_id + + // phrasentext 'no late submission allowed' to 'late submission allowed' + boolean UI invert + termin.fixtermin = !termin.invertedFixtermin return this.$api.call(ApiAbgabe.postProjektarbeitAbgabe(termin)).then( (res) => { if(res?.meta?.status == 'success') { this.$fhcAlert.alertSuccess(this.$p.t('ui/gespeichert')) @@ -121,6 +125,7 @@ export const AbgabeMitarbeiterDetail = { 'paabgabe_id': -1, 'projektarbeit_id': this.projektarbeit.projektarbeit_id, 'fixtermin': false, + 'inertedFixtermin': true, 'kurzbz': '', // todo kurzbz textfield value vorschlag für qualgates 'datum': new Date().toISOString().split('T')[0], 'note': this.allowedNotenOptions.find(opt => opt.note == 9), @@ -177,7 +182,10 @@ export const AbgabeMitarbeiterDetail = { return true; }, downloadAbgabe(termin) { - this.$api.call(ApiAbgabe.getStudentProjektarbeitAbgabeFile(termin.paabgabe_id, this.projektarbeit.student_uid)) + const url = `/api/frontend/v1/Abgabe/getStudentProjektarbeitAbgabeFile?paabgabe_id=${termin.paabgabe_id}&student_uid=${this.projektarbeit.student_uid}`; + + window.open(FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + url) + // this.$api.call(ApiAbgabe.getStudentProjektarbeitAbgabeFile(termin.paabgabe_id, this.projektarbeit.student_uid)) }, dateDiffInDays(datum, today){ const oneDayMs = 1000 * 60 * 60 * 24 @@ -258,6 +266,7 @@ export const AbgabeMitarbeiterDetail = { 'paabgabe_id': -1, 'projektarbeit_id': this.projektarbeit.projektarbeit_id, 'fixtermin': false, + 'invertedFixtermin': true, 'kurzbz': '', 'datum': new Date().toISOString().split('T')[0], 'note': this.allowedNotenOptions.find(opt => opt.note == 9), @@ -292,6 +301,7 @@ export const AbgabeMitarbeiterDetail = { 'paabgabe_id': -1, 'projektarbeit_id': this.projektarbeit.projektarbeit_id, 'fixtermin': false, + 'invertedFixtermin': true, 'kurzbz': '', 'datum': new Date().toISOString().split('T')[0], 'note': this.allowedNotenOptions.find(opt => opt.note == 9), @@ -314,6 +324,21 @@ export const AbgabeMitarbeiterDetail = { }, computed: { + getMessagePtStyle() { + // adjust outer spacing and internal padding to appear similar to doenload button in size + return { + root: { + style: { + margin: '0px' + } + }, + wrapper: { + style: { + padding: '6px' + } + } + } + }, getActiveIndexTabArray() { // here we try to assume which abgabetermine are the most relevant to the current user @@ -397,6 +422,12 @@ export const AbgabeMitarbeiterDetail = { class: "custom-tooltip" } }, + getTooltipAbgabeDetected() { + return { + value: this.$capitalize(this.$p.t('abgabetool/c4tooltipAbgabeDetected')), + class: "custom-tooltip" + } + }, getTooltipNotAllowedToSave() { return { value: this.$p.t('abgabetool/c4notAllowedToEditAbgabeTermin'), @@ -430,7 +461,12 @@ export const AbgabeMitarbeiterDetail = { } this.newTermin.upload_allowed = newVal.upload_allowed_default - } + }, + 'projektarbeit'(newVal) { + // set invertedFixtermin field for UI/UX purposes -> avoid double negation in text + + newVal?.abgabetermine?.forEach(termin => termin.invertedFixtermin = !termin.fixtermin) + } }, created() { @@ -454,20 +490,18 @@ export const AbgabeMitarbeiterDetail = {
-
{{$p.t('abgabetool/c4fixterminv3')}}
-
+
{{$capitalize( $p.t('abgabetool/c4fixterminv4') )}}
+
@@ -600,8 +637,8 @@ export const AbgabeMitarbeiterDetail = {
-
{{$capitalize( $p.t('abgabetool/c4zieldatum') )}}
-
+
{{$capitalize( $p.t('abgabetool/c4zieldatum') )}}
+
-
{{$capitalize( $p.t('abgabetool/c4abgabetyp') )}}
-
+
{{$capitalize( $p.t('abgabetool/c4abgabetyp') )}}
+
-
{{$capitalize( $p.t('abgabetool/c4upload_allowed') )}}
-
+
{{$capitalize( $p.t('abgabetool/c4upload_allowed') )}}
+
-
{{$capitalize( $p.t('abgabetool/c4note') )}}
-
+
{{$capitalize( $p.t('abgabetool/c4note') )}}
+
-
{{$capitalize( $p.t('abgabetool/c4notizQualGatev2') )}}
-
+
{{$capitalize( $p.t('abgabetool/c4notizQualGatev2') )}}
+
-
{{$capitalize( $p.t('abgabetool/c4abgabekurzbz') )}}
-
+
{{$capitalize( $p.t('abgabetool/c4abgabekurzbz') )}}
+
-
{{$capitalize( $p.t('abgabetool/c4abgabedatum') )}}
-
+
{{$capitalize( $p.t('abgabetool/c4abgabedatum') )}}
+
@@ -268,7 +270,7 @@ export const AbgabetoolStudent = {