From b20613f5d772e54c87399de4e0014542cd8b6bd7 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Fri, 27 Mar 2026 09:40:14 +0100 Subject: [PATCH 01/28] Basic Structure Automatic Tagging - new library libTag - new Job TagJob - new entries for automatic tags in config stv.php - automatic tagging of wiederholer and prewiederholer --- application/config/stv.php | 33 +++- application/controllers/jobs/TagJob.php | 236 ++++++++++++++++++++++++ application/libraries/TagLib.php | 90 +++++++++ public/css/tags.css | 4 + public/js/tabulator/formatter/tags.js | 3 + 5 files changed, 363 insertions(+), 3 deletions(-) create mode 100644 application/controllers/jobs/TagJob.php create mode 100644 application/libraries/TagLib.php diff --git a/application/config/stv.php b/application/config/stv.php index 34a30a96e..320121ba7 100644 --- a/application/config/stv.php +++ b/application/config/stv.php @@ -139,7 +139,34 @@ $config['stv_prestudent_tags'] = [ 'hinweis_kf' => ['readonly' => true], 'hinweis_lehrende' => ['readonly' => false], 'hinweis_stg_kf' => ['readonly' => true], - 'finished_stg' => ['readonly' => true], - 'finished_kf' => ['readonly' => true], - 'inwork_kf' => ['readonly' => true], + 'finished_stg' => ['readonly' => false], + 'finished_kf' => ['readonly' => false], + 'inwork_kf' => ['readonly' => false], + 'dd_auto' => ['readonly' => false], + 'wh_auto' => ['readonly' => false], + 'prewh_auto' => ['readonly' => false], + 'out_auto' => ['readonly' => false], + 'zgv_auto' => ['readonly' => false], + 'wiedereinstieg_auto' => ['readonly' => false], + 'stbtr_erh_auto' => ['readonly' => false], + 'beitr_befr_auto' => ['readonly' => false], + 'jgv_auto' => ['readonly' => false], + 'nachteilausgl_auto' => ['readonly' => false], ]; + +//TODO(manu) check ob das besser als param für job übergeben werden soll +$config['stv_automatic_tags'] = [ + 'dd_auto', + 'wh_auto', + 'out_auto', + 'prewh_auto', + 'zgv_auto', + 'wiedereinstieg_auto', + 'stbtr_erh_auto', + 'beitr_befr_auto', + 'jgv_auto', + 'nachteilausgl_auto' +]; + +$config['stv_stgs_to_tag'] = ['254']; + diff --git a/application/controllers/jobs/TagJob.php b/application/controllers/jobs/TagJob.php new file mode 100644 index 000000000..bad45dd04 --- /dev/null +++ b/application/controllers/jobs/TagJob.php @@ -0,0 +1,236 @@ +load->config('stv'); + + // Library + $this->load->library('TagLib'); + + // Tag-Helper + + // Load Models + $this->load->model('crm/Prestudentstatus_model', 'PrestudentstatusModel'); + + $this->load->model('organisation/Studiengang_model', 'StudiengangModel'); + $this->load->model('person/Notiz_model', 'NotizModel'); + $this->load->model('system/Notiztyp_model', 'NotiztypModel'); + $this->load->model('person/Notizzuordnung_model', 'NotizzuordnungModel'); + + $this->loadPhrases([ + 'lehre' + ]); + } + + /** + * Test createTags + */ + public function createAutomatedTagsForPrestudents(...$prestudentIds) + { + print_r( PHP_EOL . "Start Job create Automated Tags" . PHP_EOL); + + $tag_typ_kurzbz = "wh_auto"; + $notiz = "TEST AUTOMATED TAG"; + $zuordnung_typ = "prestudent_id"; + $count = 0; + + $values = ($prestudentIds != null) ? $prestudentIds : [ 125239, 167955]; + + $checkZuordnungType = $this->NotizzuordnungModel->isValidType($zuordnung_typ); + if (!isSuccess($checkZuordnungType)) + return error('Error occurred'); + + $values = array_unique($values); + + foreach ($values as $value) + { + //TODO(uid) + $resultInsertNotiz = $this->NotizModel->insert(array( + 'titel' => 'TAG', + 'text' => $notiz, + 'verfasser_uid' => self::BATCHUSER, + 'erledigt' => false, + 'insertamum' => date('Y-m-d H:i:s'), + 'insertvon' => self::BATCHUSER, + 'typ' => $tag_typ_kurzbz + )); + + if (isError($resultInsertNotiz)) + return error ('Error occurred insert Result ' . $value); + + $resultInsertZuordnung = $this->NotizzuordnungModel->insert(array( + 'notiz_id' => $resultInsertNotiz->retval, + $zuordnung_typ => $value + )); + + print_r( PHP_EOL . "Tag vom Typ " . $tag_typ_kurzbz . " für " . $zuordnung_typ . " " . $value . " erstellt"); + + if (isError($resultInsertZuordnung)) + return error ('Error occurred insert Zuordnung' . $value); + + $count++; + } + + print_r( PHP_EOL . "Automatically created Tags: " . $count . PHP_EOL); + print_r( PHP_EOL . "End Job create Automated Tags" . PHP_EOL); + + } + + public function createAutomatedTags() + { + print_r( PHP_EOL . "Start Job create Automated Tags: " . PHP_EOL); + + $automaticTags = $this->config->item('stv_automatic_tags'); + print_r( implode( ", ", $automaticTags) . PHP_EOL); + + if(in_array('wh_auto', $automaticTags)) + { + print_r(PHP_EOL . "create Tags wiederholer " . PHP_EOL); + $result = $this->PrestudentstatusModel-> loadWhere(array( + 'statusgrund_id' => 16, + 'studiensemester_kurzbz' => 'SS2026' + )); + $data = $result->retval; + $ids = array_map(function($item) { + return $item->prestudent_id; + }, $data); + + $result = $this->taglib->getAutomatedTags('wh_auto', $ids); + if (isError($result)) + return error ('Error occurred getAutomatedTags'); + + $data = $result->retval; + + print_r( PHP_EOL . "Automatically created Tags of Type WIEDERHOLER: " . $data[0] . PHP_EOL); + print_r( "prestudents: " . implode( ", ", $data[1]) . PHP_EOL); + } + + if(in_array('prewh_auto', $automaticTags)) + { + print_r(PHP_EOL . "create Tags pre-wiederholer " . PHP_EOL); + + $result = $this->PrestudentstatusModel-> loadWhere(array( + 'statusgrund_id' => 15, + 'studiensemester_kurzbz' => 'SS2026' + )); + $data = $result->retval; + $ids = array_map(function($item) { + return $item->prestudent_id; + }, $data); + + $result = $this->taglib->getAutomatedTags('prewh_auto', $ids); + if (isError($result)) + return error ('Error occurred getAutomatedTags'); + + $data = $result->retval; + + print_r( PHP_EOL . "Automatically created Tags of Type PRE-WIEDERHOLER: " . $data[0] . PHP_EOL); + print_r( "prestudents: " . implode( ", ", $data[1]) . PHP_EOL); + } + + if(in_array('dd_auto', $automaticTags)) + { + print_r(PHP_EOL . "create Tags double degree" . PHP_EOL); + + + print_r( PHP_EOL . "Automatically created Tags of Type DOUBLE DEGREE: " . $data[0] . PHP_EOL); + print_r( "prestudents: " . implode( ", ", $data[1]) . PHP_EOL); + } + + + +/* $tag_typ_kurzbz = "wh_auto"; + $notiz = "TEST AUTOMATED TAG"; + $zuordnung_typ = "prestudent_id"; + $count = 0; + + $values = ($arrayToTag != null) ? $arrayToTag : [ 125239, 167955]; + + $checkZuordnungType = $this->NotizzuordnungModel->isValidType($zuordnung_typ); + if (!isSuccess($checkZuordnungType)) + return error('Error occurred'); + + $values = array_unique($values); + + foreach ($values as $value) + { + //TODO(uid) + $resultInsertNotiz = $this->NotizModel->insert(array( + 'titel' => 'TAG', + 'text' => $notiz, + 'verfasser_uid' => self::BATCHUSER, + 'erledigt' => false, + 'insertamum' => date('Y-m-d H:i:s'), + 'insertvon' => self::BATCHUSER, + 'typ' => $tag_typ_kurzbz + )); + + if (isError($resultInsertNotiz)) + return error ('Error occurred insert Result ' . $value); + + $resultInsertZuordnung = $this->NotizzuordnungModel->insert(array( + 'notiz_id' => $resultInsertNotiz->retval, + $zuordnung_typ => $value + )); + + print_r( PHP_EOL . "Tag vom Typ " . $tag_typ_kurzbz . " für " . $zuordnung_typ . " " . $value . " erstellt"); + + if (isError($resultInsertZuordnung)) + return error ('Error occurred insert Zuordnung' . $value); + + $count++; + } + + print_r( PHP_EOL . "Automatically created Tags: " . $count . PHP_EOL);*/ + print_r( PHP_EOL . "End Job create Automated Tags" . PHP_EOL); + + } + + /** + * delete All Automatic Tags + */ + public function deleteAllAutomatedTags() + { + print_r( PHP_EOL . "Start Job delete ALL Automated Tags" . PHP_EOL); + // $this->NotizModel->select('notiz_id'); + $resultToDelete = $this->NotizModel->loadWhere(array('insertvon' => self::BATCHUSER)); + + $data = $resultToDelete->retval; + $notiz_ids = array_map(function($item) { + return $item->notiz_id; + }, $data); + + print_r($notiz_ids); + + foreach ($notiz_ids as $notiz_id) + { + $result = $this->NotizzuordnungModel->delete([ + 'notiz_id' => $notiz_id + ]); + if (isError($result)) + return error ('Error occurred delete Notizzuordnung' . $notiz_id); + + $result = $this->NotizModel->delete([ + 'notiz_id' => $notiz_id + ]); + if (isError($result)) + return error ('Error occurred delete Notiz' . $notiz_id); + } + print_r( PHP_EOL . "End Job delete Automated Tags" . PHP_EOL); + } +} diff --git a/application/libraries/TagLib.php b/application/libraries/TagLib.php new file mode 100644 index 000000000..144863978 --- /dev/null +++ b/application/libraries/TagLib.php @@ -0,0 +1,90 @@ +_ci =& get_instance(); + + // Configs + $this->_ci->load->config('stv'); + + // Models + $this->_ci->load->model('organisation/Studiengang_model', 'StudiengangModel'); + $this->_ci->load->model('crm/Prestudent_model', 'PrestudentModel'); + $this->_ci->load->model('person/Person_model', 'PersonModel'); + $this->_ci->load->model('person/Notiz_model', 'NotizModel'); + $this->_ci->load->model('system/Notiztyp_model', 'NotiztypModel'); + $this->_ci->load->model('person/Notizzuordnung_model', 'NotizzuordnungModel'); + + // Tag-Helper + + + // Libraries + $this->_ci->load->library('PermissionLib'); + $this->_ci->load->library('PrestudentLib'); + + + } + + public function getAutomatedTags($tag, $prestudentIds) + { + $prestudentIds = array_unique($prestudentIds); + $count = 0; + $tagged = []; + foreach ($prestudentIds as $value) + { + $resultInsertNotiz = $this->_ci->NotizModel->insert(array( + 'titel' => 'TAG', + 'text' => 'AUTOMATED TAG', + 'verfasser_uid' => self::BATCHUSER, + 'erledigt' => false, + 'insertamum' => date('Y-m-d H:i:s'), + 'insertvon' => self::BATCHUSER, + 'typ' => $tag + )); + + if (isError($resultInsertNotiz)) + return error ('Error occurred insert Result ' . $value); + + $resultInsertZuordnung = $this->_ci->NotizzuordnungModel->insert(array( + 'notiz_id' => $resultInsertNotiz->retval, + self::TYP_ZUORDNUNG => $value + )); + + if (isError($resultInsertZuordnung)) + return error ('Error occurred insert Zuordnung' . $value); + + $count++; + $tagged[] = $value; + } + return success([$count, $tagged]); + + } + + public function getAutomatedTagsStudiengang($studiengang_Kzs= null) + { + + } + + +} \ No newline at end of file diff --git a/public/css/tags.css b/public/css/tags.css index e92f415b2..bb122d6ed 100644 --- a/public/css/tags.css +++ b/public/css/tags.css @@ -75,6 +75,10 @@ text-decoration: line-through; } +.tag_auto { + border: 2px solid #8BCF8A; +} + .display_all { background-color: darkgrey !important; border: none; diff --git a/public/js/tabulator/formatter/tags.js b/public/js/tabulator/formatter/tags.js index 0d2f5004c..22a6e7971 100644 --- a/public/js/tabulator/formatter/tags.js +++ b/public/js/tabulator/formatter/tags.js @@ -38,6 +38,9 @@ export function tagFormatter(cell, tagComponent) tagElement.className = "tag " + tag.style; if (tag.done) tagElement.className += " tag_done"; + //TODO automated styling + if (tag.automatisiert) tagElement.className += " tag_done"; + tagElement.addEventListener('click', (event) => { event.stopPropagation(); event.preventDefault(); From 5dbddb4beb8e2971f7412a9d2b7c341eded9b1f7 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Fri, 27 Mar 2026 09:46:48 +0100 Subject: [PATCH 02/28] remove char --- public/js/tabulator/formatter/tags.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/tabulator/formatter/tags.js b/public/js/tabulator/formatter/tags.js index 22a6e7971..f68fafaf8 100644 --- a/public/js/tabulator/formatter/tags.js +++ b/public/js/tabulator/formatter/tags.js @@ -44,7 +44,7 @@ export function tagFormatter(cell, tagComponent) tagElement.addEventListener('click', (event) => { event.stopPropagation(); event.preventDefault(); - tagComponent.editTag(tag.id); + tagComponent.editTag(tag.id) }); container.appendChild(tagElement); From 50af6694d0b0d9a5737e8d4b2cddec0bbd338a2f Mon Sep 17 00:00:00 2001 From: ma0068 Date: Tue, 31 Mar 2026 12:48:27 +0200 Subject: [PATCH 03/28] show Tags in CoreHeader --- application/config/stv.php | 2 +- application/controllers/jobs/TagJob.php | 10 +-- application/core/Tag_Controller.php | 61 +++++++++++++- public/css/tags.css | 2 +- public/js/api/factory/stv/tag.js | 9 ++ .../components/DetailHeader/DetailHeader.js | 82 ++++++++++++++++++- public/js/components/Tag/tagFormatter.js | 78 ++++++++++++++++++ public/js/tabulator/formatter/tags.js | 27 +++++- 8 files changed, 257 insertions(+), 14 deletions(-) create mode 100644 public/js/components/Tag/tagFormatter.js diff --git a/application/config/stv.php b/application/config/stv.php index 320121ba7..be49fed97 100644 --- a/application/config/stv.php +++ b/application/config/stv.php @@ -144,7 +144,7 @@ $config['stv_prestudent_tags'] = [ 'inwork_kf' => ['readonly' => false], 'dd_auto' => ['readonly' => false], 'wh_auto' => ['readonly' => false], - 'prewh_auto' => ['readonly' => false], + 'prewh_auto' => ['readonly' => true], //when readonly kein rendering für automatisierte tags 'out_auto' => ['readonly' => false], 'zgv_auto' => ['readonly' => false], 'wiedereinstieg_auto' => ['readonly' => false], diff --git a/application/controllers/jobs/TagJob.php b/application/controllers/jobs/TagJob.php index bad45dd04..93bcee521 100644 --- a/application/controllers/jobs/TagJob.php +++ b/application/controllers/jobs/TagJob.php @@ -8,6 +8,8 @@ class TagJob extends JOB_Controller { const BATCHUSER = 'sftest'; + const SEMESTER = 'SS2024'; //docker + //TODO semester /** * API constructor @@ -22,8 +24,6 @@ class TagJob extends JOB_Controller // Library $this->load->library('TagLib'); - // Tag-Helper - // Load Models $this->load->model('crm/Prestudentstatus_model', 'PrestudentstatusModel'); @@ -103,7 +103,7 @@ class TagJob extends JOB_Controller print_r(PHP_EOL . "create Tags wiederholer " . PHP_EOL); $result = $this->PrestudentstatusModel-> loadWhere(array( 'statusgrund_id' => 16, - 'studiensemester_kurzbz' => 'SS2026' + 'studiensemester_kurzbz' => self::SEMESTER )); $data = $result->retval; $ids = array_map(function($item) { @@ -126,7 +126,7 @@ class TagJob extends JOB_Controller $result = $this->PrestudentstatusModel-> loadWhere(array( 'statusgrund_id' => 15, - 'studiensemester_kurzbz' => 'SS2026' + 'studiensemester_kurzbz' => self::SEMESTER )); $data = $result->retval; $ids = array_map(function($item) { @@ -204,7 +204,7 @@ class TagJob extends JOB_Controller /** * delete All Automatic Tags */ - public function deleteAllAutomatedTags() + public function deleteAutomatedTags() { print_r( PHP_EOL . "Start Job delete ALL Automated Tags" . PHP_EOL); // $this->NotizModel->select('notiz_id'); diff --git a/application/core/Tag_Controller.php b/application/core/Tag_Controller.php index 5b9bac6c5..d3b071f96 100644 --- a/application/core/Tag_Controller.php +++ b/application/core/Tag_Controller.php @@ -19,6 +19,7 @@ class Tag_Controller extends FHCAPI_Controller 'updateTag' => self::BERECHTIGUNG_KURZBZ, 'doneTag' => self::BERECHTIGUNG_KURZBZ, 'deleteTag' => self::BERECHTIGUNG_KURZBZ, + 'getAllTags' => self::BERECHTIGUNG_KURZBZ, ]; $merged_permissions = array_merge($default_permissions, $permissions); @@ -65,6 +66,7 @@ class Tag_Controller extends FHCAPI_Controller array_to_json(bezeichnung_mehrsprachig::varchar[])->>". $language. " as bezeichnung, tbl_notiz.notiz_id, tbl_notiz_typ.style, + tbl_notiz_typ.automatisiert, tbl_notiz.erledigt as done, tbl_notiz.insertamum, tbl_notiz.updateamum, @@ -82,6 +84,7 @@ class Tag_Controller extends FHCAPI_Controller $notiz = $this->NotizModel->loadWhere(array('notiz_id' => $id)); + $this->terminateWithSuccess(hasData($notiz) ? getData($notiz)[0] : array()); } @@ -92,7 +95,8 @@ class Tag_Controller extends FHCAPI_Controller array_to_json(bezeichnung_mehrsprachig::varchar[])->>0 as bezeichnung, style, beschreibung, - tag + tag, + automatisiert ' ); $this->NotiztypModel->addOrder('prioritaet'); @@ -271,6 +275,61 @@ class Tag_Controller extends FHCAPI_Controller $this->terminateWithSuccess($deleteNotiz); } + public function getAllTags($readonly_tags = false){ + $language = $this->_getLanguageIndex(); + $prestudent_id = $this->input->get('prestudent_id'); + // $this->terminateWithError("id: " . $prestudent_id, self::ERROR_TYPE_GENERAL); + + //TODO check for readonly: necessary? + if (is_array($readonly_tags) && !isEmptyArray($readonly_tags)) + { + $readonly_tags = $this->_filterTag($readonly_tags, true); + + foreach ($readonly_tags as $key => $tag) + { + $readonly_tags[$key] = $this->NotizModel->db->escape($tag); + } + $tags = '(' . implode(',', $readonly_tags) . ')'; + + $this->NotizModel->addSelect(" + CASE + WHEN tbl_notiz_typ.typ_kurzbz IN $tags + THEN TRUE + ELSE FALSE + END as readonly + "); + } + + $this->NotizModel->addSelect( + "tbl_notiz.titel, + tbl_notiz.text, + array_to_json(bezeichnung_mehrsprachig::varchar[])->>". $language. " as bezeichnung, + tbl_notiz.notiz_id, + tbl_notiz_typ.style, + tbl_notiz_typ.automatisiert, + tbl_notiz.erledigt as done, + tbl_notiz.insertamum, + tbl_notiz.updateamum, + (verfasserperson.vorname || ' ' || verfasserperson.nachname || ' ' || '(' || verfasserbenutzer.uid || ')') as verfasser, + (bearbeiterperson.vorname || ' ' || bearbeiterperson.nachname || ' ' || '(' || bearbeiterbenutzer.uid || ')') as bearbeiter + " + ); + $this->NotizModel->addJoin('public.tbl_notiz_typ', 'public.tbl_notiz.typ = public.tbl_notiz_typ.typ_kurzbz'); + + $this->NotizModel->addJoin('public.tbl_benutzer verfasserbenutzer', 'tbl_notiz.verfasser_uid = verfasserbenutzer.uid', 'LEFT'); + $this->NotizModel->addJoin('public.tbl_person verfasserperson', 'verfasserbenutzer.person_id = verfasserperson.person_id', 'LEFT'); + + $this->NotizModel->addJoin('public.tbl_benutzer bearbeiterbenutzer', 'tbl_notiz.bearbeiter_uid = bearbeiterbenutzer.uid', 'LEFT'); + $this->NotizModel->addJoin('public.tbl_person bearbeiterperson', 'bearbeiterbenutzer.person_id = bearbeiterperson.person_id', 'LEFT'); + + $this->NotizModel->addJoin('public.tbl_notizzuordnung notizzuordnung', 'tbl_notiz.notiz_id = notizzuordnung.notiz_id'); + + $notiz = $this->NotizModel->loadWhere(array('prestudent_id' => $prestudent_id)); + + + $this->terminateWithSuccess(hasData($notiz) ? getData($notiz) : array()); + } + private function _setAuthUID() { $this->_uid = getAuthUID(); diff --git a/public/css/tags.css b/public/css/tags.css index bb122d6ed..995a7d43a 100644 --- a/public/css/tags.css +++ b/public/css/tags.css @@ -76,7 +76,7 @@ } .tag_auto { - border: 2px solid #8BCF8A; + border: 1px dashed white; } .display_all { diff --git a/public/js/api/factory/stv/tag.js b/public/js/api/factory/stv/tag.js index 29675f6d4..a5db6cb73 100644 --- a/public/js/api/factory/stv/tag.js +++ b/public/js/api/factory/stv/tag.js @@ -51,4 +51,13 @@ export default { params: data }; }, + + //TODO expand to other types + getAllTagsPrestudent(prestudent_id){ + return { + method: 'get', + url: 'api/frontend/v1/stv/Tags/getAllTags', + params: prestudent_id + }; + } }; \ No newline at end of file diff --git a/public/js/components/DetailHeader/DetailHeader.js b/public/js/components/DetailHeader/DetailHeader.js index 0b846df9c..3207cddaa 100644 --- a/public/js/components/DetailHeader/DetailHeader.js +++ b/public/js/components/DetailHeader/DetailHeader.js @@ -1,11 +1,15 @@ import ApiDetailHeader from "../../api/factory/detailHeader.js"; import ApiHandleFoto from "../../api/factory/fotoHandling.js"; import ModalUploadFoto from "./Modal/UploadFoto.js"; +import CoreTag from "../Tag/Tag.js"; +import ApiTag from "../../api/factory/stv/tag.js"; +import { idTagFormatter } from "../Tag/tagFormatter.js"; export default { name: 'DetailHeader', components: { - ModalUploadFoto + ModalUploadFoto, + CoreTag }, props: { headerData: { @@ -40,6 +44,12 @@ export default { } } }, + inject: { + tagsEnabled: { + from: 'configStvTagsEnabled', + default: false + }, + }, computed: { appRoot() { return FHC_JS_DATA_STORAGE_OBJECT.app_root; @@ -61,13 +71,23 @@ export default { hasTileUIDSlot() { return !!this.$slots.uid }, - + prestudentIds() { + if (this.headerData[0].prestudent_id) + { + return [this.headerData[0].prestudent_id]; + } + }, }, created(){ if (this.typeHeader === 'student') { if (!this.headerData) { throw new Error('[DetailHeader] "headerData" is required.') } + + if(this.tagsEnabled) { + this.loadTagsAndRender(this.headerData[0].prestudent_id); + } + } else if (this.typeHeader === 'mitarbeiter') { if (!this.person_id || !this.mitarbeiter_uid || !this.domain) { throw new Error( @@ -86,13 +106,23 @@ export default { }, deep: true, }, + headerData: { + handler(newVal) { + if(this.tagsEnabled) { + this.loadTagsAndRender(this.headerData[0].prestudent_id); + } + }, + deep: true, + } }, data(){ return{ headerDataMa: {}, departmentData: {}, leitungData: {}, - isFetchingIssues: false + isFetchingIssues: false, + tagEndpoint: ApiTag, + tagData: null, }; }, methods: { @@ -179,7 +209,41 @@ export default { } else { return 'data:image/jpeg;base64,' + foto; } - } + }, + //methods tags + async loadTagsAndRender(prestudent_id) { + await this.getAllTags(prestudent_id); + + const container = idTagFormatter( + prestudent_id, + this.tagData, + this.$refs.tagComponent, + 'prestudent_id' + ); + + this.$refs.tagWrapper.innerHTML = ''; + this.$refs.tagWrapper.appendChild(container); + }, + getAllTags(prestudent_id){ + return this.$api + .call(ApiTag.getAllTagsPrestudent({prestudent_id})) + .then(result => { + this.tagData = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + addedTag(addedTag) + { + this.reload(); + }, + deletedTag(id) + { + this.reload(); + }, + updatedTag(updatedTag) + { + this.reload(); + }, }, template: `
@@ -245,6 +309,15 @@ export default { , {{headerData[0].titelpost}} +
unruly
@@ -267,6 +340,7 @@ export default { | Status {{headerData[0].statusofsemester}} +
diff --git a/public/js/components/Tag/tagFormatter.js b/public/js/components/Tag/tagFormatter.js new file mode 100644 index 000000000..03f067596 --- /dev/null +++ b/public/js/components/Tag/tagFormatter.js @@ -0,0 +1,78 @@ + + +export function idTagFormatter (id, tagData, tagComponent, typeId) +{ + if (!id) return; + + const parsedTags = tagData.map(tag => ({ + id: tag.notiz_id, + typ_kurzbz: tag.titel?.toLowerCase(), + beschreibung: tag.bezeichnung, + notiz: tag.text || "", + style: tag.style, + done: tag.done, + automatisiert: tag.automatisiert, + typeId: id + })); + + let container = document.createElement('div'); + container.className = "d-flex gap-1"; + + let maxVisibleTags = 5; + let expanded = false; + const renderTags = () => { + container.innerHTML = ''; + + let filtered = parsedTags.filter(t => t != null); + + filtered.sort((a, b) => { + let adone = a.done ? 1 : 0; + let bdone = b.done ? 1 : 0; + + if (adone !== bdone) return adone - bdone; + return b.id - a.id; + }); + + const tagsToShow = expanded + ? filtered + : filtered.slice(0, maxVisibleTags); + + tagsToShow.forEach(tag => { + let tagElement = document.createElement('span'); + tagElement.innerText = tag.beschreibung; + tagElement.title = tag.notiz; + tagElement.className = "tag " + tag.style; + + if (tag.done) { + tagElement.className += " tag_done"; + } + if (tag.automatisiert) + tagElement.className += " tag_auto"; + + tagElement.addEventListener('click', (event) => { + event.stopPropagation(); + event.preventDefault(); + tagComponent.editTag(tag.id); + }); + + container.appendChild(tagElement); + }); + + if (filtered.length > maxVisibleTags) { + let toggle = document.createElement('button'); + toggle.innerText = (expanded ? '- ' : '+ ') + (filtered.length - maxVisibleTags); + toggle.className = "display_all"; + + toggle.addEventListener('click', () => { + expanded = !expanded; + renderTags(); + }); + + container.appendChild(toggle); + } + }; + + renderTags(); + + return container; +} \ No newline at end of file diff --git a/public/js/tabulator/formatter/tags.js b/public/js/tabulator/formatter/tags.js index f68fafaf8..855bdba82 100644 --- a/public/js/tabulator/formatter/tags.js +++ b/public/js/tabulator/formatter/tags.js @@ -1,5 +1,13 @@ export function tagFormatter(cell, tagComponent) { + //TODO readOnlyComponents nicht in der TagComponent enthalten + //console.log(JSON.stringify(tagComponent)); + const mappedData = tagComponent.tags.map(tag => ({ + typ_kurzbz: tag.tag_typ_kurzbz, + automatisiert: tag.automatisiert + })); + + let tags = cell.getValue(); if (!tags) return; @@ -32,14 +40,29 @@ export function tagFormatter(cell, tagComponent) tagsToShow.forEach(tag => { if (!tag) return; + let tagElement = document.createElement('span'); tagElement.innerText = tag.beschreibung; tagElement.title = tag.notiz; tagElement.className = "tag " + tag.style; if (tag.done) tagElement.className += " tag_done"; - //TODO automated styling - if (tag.automatisiert) tagElement.className += " tag_done"; + const tagDef = mappedData.find(t => t.typ_kurzbz === tag.typ_kurzbz); + + if (tagDef?.automatisiert) + tagElement.className += " tag_auto"; + +/* TODO delete Testoutputs + if (!tagDef) { + console.log(tag.typ_kurzbz + " nicht in TagComponent enthalten"); + tagElement.className += " tag_auto"; + } + else if (tagDef?.automatisiert) { + console.log(tag.typ_kurzbz + " ist automatisiert"); + tagElement.className += " tag_auto"; + } else + console.log (tag.typ_kurzbz + " nicht automatisiert"); +*/ tagElement.addEventListener('click', (event) => { event.stopPropagation(); From e9e614aa523ea1f7b140049821ef1bd18627736d Mon Sep 17 00:00:00 2001 From: ma0068 Date: Wed, 8 Apr 2026 14:26:14 +0200 Subject: [PATCH 04/28] Add Functionality Frontend: triggering of reloading tags for prestudent from studentHeader Refactoring: Recycling of tags instead of deleting it and creating new ones --- application/config/stv.php | 2 +- .../controllers/api/frontend/v1/stv/Tags.php | 1 + application/controllers/jobs/TagJob.php | 189 ++---------- application/core/Tag_Controller.php | 17 +- application/libraries/TagLib.php | 275 +++++++++++++++++- public/js/api/factory/stv/tag.js | 10 +- .../components/DetailHeader/DetailHeader.js | 16 + 7 files changed, 336 insertions(+), 174 deletions(-) diff --git a/application/config/stv.php b/application/config/stv.php index be49fed97..f902b30ce 100644 --- a/application/config/stv.php +++ b/application/config/stv.php @@ -144,7 +144,7 @@ $config['stv_prestudent_tags'] = [ 'inwork_kf' => ['readonly' => false], 'dd_auto' => ['readonly' => false], 'wh_auto' => ['readonly' => false], - 'prewh_auto' => ['readonly' => true], //when readonly kein rendering für automatisierte tags + 'prewh_auto' => ['readonly' => false], //when readonly kein rendering für automatisierte tags 'out_auto' => ['readonly' => false], 'zgv_auto' => ['readonly' => false], 'wiedereinstieg_auto' => ['readonly' => false], diff --git a/application/controllers/api/frontend/v1/stv/Tags.php b/application/controllers/api/frontend/v1/stv/Tags.php index 3004a1f3b..e5af9becc 100644 --- a/application/controllers/api/frontend/v1/stv/Tags.php +++ b/application/controllers/api/frontend/v1/stv/Tags.php @@ -45,4 +45,5 @@ class Tags extends Tag_Controller { parent::doneTag($this->config->item('stv_prestudent_tags')); } + } diff --git a/application/controllers/jobs/TagJob.php b/application/controllers/jobs/TagJob.php index 93bcee521..689bb6ac9 100644 --- a/application/controllers/jobs/TagJob.php +++ b/application/controllers/jobs/TagJob.php @@ -8,7 +8,7 @@ class TagJob extends JOB_Controller { const BATCHUSER = 'sftest'; - const SEMESTER = 'SS2024'; //docker + const SEMESTER = 'WS2025'; //docker //TODO semester /** @@ -37,70 +37,15 @@ class TagJob extends JOB_Controller ]); } - /** - * Test createTags - */ - public function createAutomatedTagsForPrestudents(...$prestudentIds) + public function rebuildAutomatedTags() { - print_r( PHP_EOL . "Start Job create Automated Tags" . PHP_EOL); - - $tag_typ_kurzbz = "wh_auto"; - $notiz = "TEST AUTOMATED TAG"; - $zuordnung_typ = "prestudent_id"; - $count = 0; - - $values = ($prestudentIds != null) ? $prestudentIds : [ 125239, 167955]; - - $checkZuordnungType = $this->NotizzuordnungModel->isValidType($zuordnung_typ); - if (!isSuccess($checkZuordnungType)) - return error('Error occurred'); - - $values = array_unique($values); - - foreach ($values as $value) - { - //TODO(uid) - $resultInsertNotiz = $this->NotizModel->insert(array( - 'titel' => 'TAG', - 'text' => $notiz, - 'verfasser_uid' => self::BATCHUSER, - 'erledigt' => false, - 'insertamum' => date('Y-m-d H:i:s'), - 'insertvon' => self::BATCHUSER, - 'typ' => $tag_typ_kurzbz - )); - - if (isError($resultInsertNotiz)) - return error ('Error occurred insert Result ' . $value); - - $resultInsertZuordnung = $this->NotizzuordnungModel->insert(array( - 'notiz_id' => $resultInsertNotiz->retval, - $zuordnung_typ => $value - )); - - print_r( PHP_EOL . "Tag vom Typ " . $tag_typ_kurzbz . " für " . $zuordnung_typ . " " . $value . " erstellt"); - - if (isError($resultInsertZuordnung)) - return error ('Error occurred insert Zuordnung' . $value); - - $count++; - } - - print_r( PHP_EOL . "Automatically created Tags: " . $count . PHP_EOL); - print_r( PHP_EOL . "End Job create Automated Tags" . PHP_EOL); - - } - - public function createAutomatedTags() - { - print_r( PHP_EOL . "Start Job create Automated Tags: " . PHP_EOL); - + print_r( PHP_EOL . "Start Job rebuild" . PHP_EOL); $automaticTags = $this->config->item('stv_automatic_tags'); print_r( implode( ", ", $automaticTags) . PHP_EOL); + //TODO(Manu) use a loop in library? if(in_array('wh_auto', $automaticTags)) { - print_r(PHP_EOL . "create Tags wiederholer " . PHP_EOL); $result = $this->PrestudentstatusModel-> loadWhere(array( 'statusgrund_id' => 16, 'studiensemester_kurzbz' => self::SEMESTER @@ -110,127 +55,51 @@ class TagJob extends JOB_Controller return $item->prestudent_id; }, $data); - $result = $this->taglib->getAutomatedTags('wh_auto', $ids); - if (isError($result)) - return error ('Error occurred getAutomatedTags'); + $result = $this->taglib->updateAutomatedTags('wh_auto', $ids); $data = $result->retval; + if (isError($result)) + return error ('Error occurred during updateAutomatedTags'); - print_r( PHP_EOL . "Automatically created Tags of Type WIEDERHOLER: " . $data[0] . PHP_EOL); - print_r( "prestudents: " . implode( ", ", $data[1]) . PHP_EOL); + print_r(PHP_EOL ."ALL TAGS 'wh_auto' " . count($data[0]) . " TO ADD " . count($data[1]) . " TO RECYLE: " . count($data[2]) . " TO DELETE: " . count($data[3])); + + + print_r( PHP_EOL . "Count Recycled: "); + print_r($data[4]); + print_r( PHP_EOL . "Count Added: "); + print_r($data[6]); + print_r( PHP_EOL . "Count Deleted: "); + print_r($data[8] . PHP_EOL); } if(in_array('prewh_auto', $automaticTags)) { - print_r(PHP_EOL . "create Tags pre-wiederholer " . PHP_EOL); - - $result = $this->PrestudentstatusModel-> loadWhere(array( + $result = $this->PrestudentstatusModel->loadWhere(array( 'statusgrund_id' => 15, 'studiensemester_kurzbz' => self::SEMESTER )); $data = $result->retval; - $ids = array_map(function($item) { + $ids = array_map(function ($item) { return $item->prestudent_id; }, $data); - $result = $this->taglib->getAutomatedTags('prewh_auto', $ids); + $result = $this->taglib->updateAutomatedTags('prewh_auto', $ids); if (isError($result)) - return error ('Error occurred getAutomatedTags'); + return error('Error occurred during updateAutomatedTags'); $data = $result->retval; - print_r( PHP_EOL . "Automatically created Tags of Type PRE-WIEDERHOLER: " . $data[0] . PHP_EOL); - print_r( "prestudents: " . implode( ", ", $data[1]) . PHP_EOL); + print_r(PHP_EOL . "ALL TAGS 'prewh_auto' " . count($data[0]) . " TO ADD " . count($data[1]) . " TO RECYLE: " . count($data[2]) . " TO DELETE: " . count($data[3])); + + print_r(PHP_EOL . "Count Recycled: "); + print_r($data[4]); + print_r(PHP_EOL . "Count Added: "); + print_r($data[6]); + print_r(PHP_EOL . "Count Deleted: "); + print_r($data[8] . PHP_EOL); } - if(in_array('dd_auto', $automaticTags)) - { - print_r(PHP_EOL . "create Tags double degree" . PHP_EOL); + print_r( PHP_EOL . "End Job rebuild" . PHP_EOL); - - print_r( PHP_EOL . "Automatically created Tags of Type DOUBLE DEGREE: " . $data[0] . PHP_EOL); - print_r( "prestudents: " . implode( ", ", $data[1]) . PHP_EOL); - } - - - -/* $tag_typ_kurzbz = "wh_auto"; - $notiz = "TEST AUTOMATED TAG"; - $zuordnung_typ = "prestudent_id"; - $count = 0; - - $values = ($arrayToTag != null) ? $arrayToTag : [ 125239, 167955]; - - $checkZuordnungType = $this->NotizzuordnungModel->isValidType($zuordnung_typ); - if (!isSuccess($checkZuordnungType)) - return error('Error occurred'); - - $values = array_unique($values); - - foreach ($values as $value) - { - //TODO(uid) - $resultInsertNotiz = $this->NotizModel->insert(array( - 'titel' => 'TAG', - 'text' => $notiz, - 'verfasser_uid' => self::BATCHUSER, - 'erledigt' => false, - 'insertamum' => date('Y-m-d H:i:s'), - 'insertvon' => self::BATCHUSER, - 'typ' => $tag_typ_kurzbz - )); - - if (isError($resultInsertNotiz)) - return error ('Error occurred insert Result ' . $value); - - $resultInsertZuordnung = $this->NotizzuordnungModel->insert(array( - 'notiz_id' => $resultInsertNotiz->retval, - $zuordnung_typ => $value - )); - - print_r( PHP_EOL . "Tag vom Typ " . $tag_typ_kurzbz . " für " . $zuordnung_typ . " " . $value . " erstellt"); - - if (isError($resultInsertZuordnung)) - return error ('Error occurred insert Zuordnung' . $value); - - $count++; - } - - print_r( PHP_EOL . "Automatically created Tags: " . $count . PHP_EOL);*/ - print_r( PHP_EOL . "End Job create Automated Tags" . PHP_EOL); - - } - - /** - * delete All Automatic Tags - */ - public function deleteAutomatedTags() - { - print_r( PHP_EOL . "Start Job delete ALL Automated Tags" . PHP_EOL); - // $this->NotizModel->select('notiz_id'); - $resultToDelete = $this->NotizModel->loadWhere(array('insertvon' => self::BATCHUSER)); - - $data = $resultToDelete->retval; - $notiz_ids = array_map(function($item) { - return $item->notiz_id; - }, $data); - - print_r($notiz_ids); - - foreach ($notiz_ids as $notiz_id) - { - $result = $this->NotizzuordnungModel->delete([ - 'notiz_id' => $notiz_id - ]); - if (isError($result)) - return error ('Error occurred delete Notizzuordnung' . $notiz_id); - - $result = $this->NotizModel->delete([ - 'notiz_id' => $notiz_id - ]); - if (isError($result)) - return error ('Error occurred delete Notiz' . $notiz_id); - } - print_r( PHP_EOL . "End Job delete Automated Tags" . PHP_EOL); } } diff --git a/application/core/Tag_Controller.php b/application/core/Tag_Controller.php index d3b071f96..a5a3e2a62 100644 --- a/application/core/Tag_Controller.php +++ b/application/core/Tag_Controller.php @@ -20,6 +20,7 @@ class Tag_Controller extends FHCAPI_Controller 'doneTag' => self::BERECHTIGUNG_KURZBZ, 'deleteTag' => self::BERECHTIGUNG_KURZBZ, 'getAllTags' => self::BERECHTIGUNG_KURZBZ, + 'rebuildTagsPrestudent' => self::BERECHTIGUNG_KURZBZ, ]; $merged_permissions = array_merge($default_permissions, $permissions); @@ -27,6 +28,10 @@ class Tag_Controller extends FHCAPI_Controller parent::__construct($merged_permissions); $this->_setAuthUID(); + + // Library + $this->load->library('TagLib'); + $this->load->model('person/Notiz_model', 'NotizModel'); $this->load->model('system/Notiztyp_model', 'NotiztypModel'); $this->load->model('person/Notizzuordnung_model', 'NotizzuordnungModel'); @@ -278,7 +283,6 @@ class Tag_Controller extends FHCAPI_Controller public function getAllTags($readonly_tags = false){ $language = $this->_getLanguageIndex(); $prestudent_id = $this->input->get('prestudent_id'); - // $this->terminateWithError("id: " . $prestudent_id, self::ERROR_TYPE_GENERAL); //TODO check for readonly: necessary? if (is_array($readonly_tags) && !isEmptyArray($readonly_tags)) @@ -330,6 +334,17 @@ class Tag_Controller extends FHCAPI_Controller $this->terminateWithSuccess(hasData($notiz) ? getData($notiz) : array()); } + public function rebuildTagsPrestudent() + { + $prestudent_id = $this->input->get('prestudent_id'); + + $result = $this->taglib->rebuildTagsForPrestudent($prestudent_id); + if (isError($result)) + return error ('Error occurred during updateAutomatedTags'); + + $this->terminateWithSuccess($result); + } + private function _setAuthUID() { $this->_uid = getAuthUID(); diff --git a/application/libraries/TagLib.php b/application/libraries/TagLib.php index 144863978..2200e16d9 100644 --- a/application/libraries/TagLib.php +++ b/application/libraries/TagLib.php @@ -18,6 +18,8 @@ class TagLib { const BATCHUSER = 'sftest'; const TYP_ZUORDNUNG = 'prestudent_id'; + const SEMESTER = 'WS2025'; + /** * Object initialization */ @@ -35,7 +37,7 @@ class TagLib $this->_ci->load->model('person/Notiz_model', 'NotizModel'); $this->_ci->load->model('system/Notiztyp_model', 'NotiztypModel'); $this->_ci->load->model('person/Notizzuordnung_model', 'NotizzuordnungModel'); - + $this->_ci->load->model('crm/Prestudentstatus_model', 'PrestudentstatusModel'); // Tag-Helper @@ -46,20 +48,82 @@ class TagLib } - public function getAutomatedTags($tag, $prestudentIds) + public function updateAutomatedTags($tag, $prestudentIds) { $prestudentIds = array_unique($prestudentIds); - $count = 0; - $tagged = []; + + $toRecycle = []; + $toAdd = []; + $toDelete = []; + $allTags = []; + + $this->_ci->NotizModel->addSelect('nz.notiz_id'); + $this->_ci->NotizModel->addSelect('prestudent_id'); + $this->_ci->NotizModel->addJoin('public.tbl_notizzuordnung nz', 'notiz_id'); + $resultAllTags = $this->_ci->NotizModel->loadWhere([ + 'typ' => $tag + ]); + + $allTagsData = getData($resultAllTags); + + if (!empty($allTagsData)) { + foreach ($allTagsData as $row) { + $allTags[$row->prestudent_id] = $row->notiz_id; + } + } + + foreach ($prestudentIds as $value) { + if (isset($allTags[$value])) { + // if already existing: recyceln: nothing to do + $toRecycle[$value] = $allTags[$value] ; + } else { + $toAdd[] = $value; + } + } + + foreach ($allTags as $prestudent_id => $notiz_id) { + if (!in_array($prestudent_id, $prestudentIds)) { + $toDelete[$prestudent_id] = $notiz_id; + } + } + + //RECYCLE: Just insert new update Date + $countRecyled = 0; + $retagged = []; + foreach ($toRecycle as $value) + { + //TODO(Manu) refactor for recycle, add + $resultUpdateNotiz = $this->_ci->NotizModel->update( + [ + 'notiz_id' => $value + ], + array( + 'updateamum' => date('Y-m-d H:i:s'), + 'updatevon' => 'BatchJobTagUpdate', + )); + + if (isError($resultUpdateNotiz)) + return error ('Error occurred update Result ' . $value); + + $countRecyled++; + $retagged[] = $resultUpdateNotiz->retval; + } + + //ADD: Create new Tags + $countAdded = 0; + $tagged = []; + foreach ($toAdd as $value) + { + //TODO(Manu) refactor for recycle, add $resultInsertNotiz = $this->_ci->NotizModel->insert(array( 'titel' => 'TAG', 'text' => 'AUTOMATED TAG', - 'verfasser_uid' => self::BATCHUSER, + 'verfasser_uid' => self::BATCHUSER, //has to be an uid 'erledigt' => false, 'insertamum' => date('Y-m-d H:i:s'), - 'insertvon' => self::BATCHUSER, + 'insertvon' => 'BatchJobTagAdd', 'typ' => $tag )); @@ -74,17 +138,206 @@ class TagLib if (isError($resultInsertZuordnung)) return error ('Error occurred insert Zuordnung' . $value); - $count++; - $tagged[] = $value; + $countAdded++; + $tagged[$resultInsertNotiz->retval] = $value; } - return success([$count, $tagged]); + + //DELETE OLD Tags, no more valid + $countDeleted = 0; + $deleted = []; + foreach ($toDelete as $value) + { + $result = $this->_ci->NotizzuordnungModel->delete([ + 'notiz_id' => $value + ]); + if (isError($result)) + return error ('Error occurred delete Notizzuordnung' . $notiz_id); + + $result = $this->_ci->NotizModel->delete([ + 'notiz_id' => $notiz_id + ]); + if (isError($result)) + return error ('Error occurred delete Notiz' . $notiz_id); + + $countDeleted++; + $deleted[] = $value; + } + + return success([$allTags, $toAdd, $toRecycle, $toDelete, $countRecyled, $retagged, $countAdded, $tagged, $countDeleted, $deleted]); } - public function getAutomatedTagsStudiengang($studiengang_Kzs= null) + public function updateAutomatedTagsForPrestudent($tag, $prestudent_id) { + $return = null; + $notiz_id = null; + + $this->_ci->NotizModel->addSelect('nz.notiz_id'); + $this->_ci->NotizModel->addSelect('prestudent_id'); + $this->_ci->NotizModel->addJoin('public.tbl_notizzuordnung nz', 'notiz_id'); + $resultAllTags = $this->_ci->NotizModel->loadWhere([ + 'typ' => $tag, + 'prestudent_id' => $prestudent_id + ]); + if(hasData($resultAllTags)) + { + $notiz_id = $resultAllTags->retval[0]->notiz_id; + } + + //RECYCLE + if ($notiz_id !== null) + { + //TODO(Manu) refactor for recycle, add + $resultUpdateNotiz = $this->_ci->NotizModel->update( + [ + 'notiz_id' => $notiz_id + ], + array( + 'updateamum' => date('Y-m-d H:i:s'), + 'updatevon' => 'Manually', + )); + + if (isError($resultUpdateNotiz)) + return error ('Error occurred update Result ' . $notiz_id); + + $return = ['recycled' => $notiz_id]; + } + else + { + //TODO(Manu) refactor for recycle, add + $resultInsertNotiz = $this->_ci->NotizModel->insert(array( + 'titel' => 'TAG', + 'text' => 'AUTOMATED TAG', + 'verfasser_uid' => self::BATCHUSER, //has to be an uid //TODO (auth UID) + 'erledigt' => false, + 'insertamum' => date('Y-m-d H:i:s'), + 'insertvon' => 'Manually', + 'typ' => $tag + )); + + if (isError($resultInsertNotiz)) + return error ('Error occurred insert Result ' . $prestudent_id); + + $resultInsertZuordnung = $this->_ci->NotizzuordnungModel->insert(array( + 'notiz_id' => $resultInsertNotiz->retval, + self::TYP_ZUORDNUNG => $prestudent_id + )); + + if (isError($resultInsertZuordnung)) + return error ('Error occurred insert Zuordnung' . $prestudent_id); + + $return = ['added' => $resultInsertNotiz->retval]; + } + + return success($return); } +/* + * main function for rebuild Tags for single prestudent + * manually triggered + * */ + public function rebuildTagsForPrestudent($prestudent_id) + { + $automaticTags = $this->_ci->config->item('stv_automatic_tags'); + $return = []; -} \ No newline at end of file + foreach ($automaticTags as $tag) + { + if($this->isCriteriaSetFor($tag, $prestudent_id)) + { + $result = $this->updateAutomatedTagsForPrestudent($tag, $prestudent_id); + if (isError($result)) + return error ('Error occurred during updateAutomatedTags' . $tag); + + else + $return[$tag] = $result; + } + else { + $result = $this->checkForDelete($tag, $prestudent_id); + if($result != null) + $return[$tag] = $result; + } + } + + + return success($return); + + } + + public function checkForDelete($tag, $prestudent_id) + { + $return = null; + $notiz_id = null; + + if (!is_numeric($prestudent_id)) + return error ("prestudent_id " . $prestudent_id . "not numeric"); + + $this->_ci->NotizModel->addSelect('nz.notiz_id'); + $this->_ci->NotizModel->addSelect('prestudent_id'); + $this->_ci->NotizModel->addJoin('public.tbl_notizzuordnung nz', 'notiz_id'); + $resultAllTags = $this->_ci->NotizModel->loadWhere([ + 'typ' => $tag, + 'prestudent_id' => $prestudent_id + ]); + if(hasData($resultAllTags)) + { + $notiz_id = $resultAllTags->retval[0]->notiz_id; + } + + if($notiz_id) + { + $result = $this->_ci->NotizzuordnungModel->delete([ + 'notiz_id' => $notiz_id + ]); + if (isError($result)) + return error ('Error occurred during delete Notizzuordnung' . $notiz_id); + + $result = $this->_ci->NotizModel->delete([ + 'notiz_id' => $notiz_id + ]); + if (isError($result)) + return error ('Error occurred during delete Notiz' . $notiz_id); + + $return = ['deleted' => $notiz_id]; + } + return $return; + } + + public function isCriteriaSetFor($tag, $prestudent_id) + { + //TODO(finish list) + if($tag == 'wh_auto') + { + $result = $this->_ci->PrestudentstatusModel->loadWhere(array( + 'statusgrund_id' => 16, + 'studiensemester_kurzbz' => self::SEMESTER, + 'prestudent_id' => $prestudent_id + )); + if(hasData($result)) + { + return true; + } + else + return false; + } + + if($tag == 'prewh_auto') + { + $result = $this->_ci->PrestudentstatusModel->loadWhere(array( + 'statusgrund_id' => 15, + 'studiensemester_kurzbz' => self::SEMESTER, + 'prestudent_id' => $prestudent_id + )); + if(hasData($result)) + { + return true; + } + else + return false; + } + + return false; + + } +} diff --git a/public/js/api/factory/stv/tag.js b/public/js/api/factory/stv/tag.js index a5db6cb73..d78e7f685 100644 --- a/public/js/api/factory/stv/tag.js +++ b/public/js/api/factory/stv/tag.js @@ -52,12 +52,20 @@ export default { }; }, - //TODO expand to other types + //TODO check if necessary to expand to other idTypes getAllTagsPrestudent(prestudent_id){ return { method: 'get', url: 'api/frontend/v1/stv/Tags/getAllTags', params: prestudent_id }; + }, + + rebuildTagsPrestudent(prestudent_id){ + return { + method: 'get', + url: 'api/frontend/v1/stv/Tags/rebuildTagsPrestudent', + params: prestudent_id + }; } }; \ No newline at end of file diff --git a/public/js/components/DetailHeader/DetailHeader.js b/public/js/components/DetailHeader/DetailHeader.js index 3207cddaa..01635e31e 100644 --- a/public/js/components/DetailHeader/DetailHeader.js +++ b/public/js/components/DetailHeader/DetailHeader.js @@ -123,6 +123,7 @@ export default { isFetchingIssues: false, tagEndpoint: ApiTag, tagData: null, + rebuildData: null }; }, methods: { @@ -244,6 +245,17 @@ export default { { this.reload(); }, + rebuildPrestudentTags(){ + const prestudent_id = this.headerData[0].prestudent_id; + return this.$api + .call(ApiTag.rebuildTagsPrestudent({prestudent_id})) + .then(result => { + this.rebuildData = result.data; + console.log("Rebuild manually triggered"); + this.reload(); + }) + .catch(this.$fhcAlert.handleSystemError); + } }, template: `
@@ -318,6 +330,10 @@ export default { @updated="updatedTag" zuordnung_typ="prestudent_id" > +
+ +
unruly
From 4f8e98f5d5a0519071041b5fa169d27e9e78717a Mon Sep 17 00:00:00 2001 From: ma0068 Date: Wed, 8 Apr 2026 15:11:58 +0200 Subject: [PATCH 05/28] restyle button reloadTags --- public/js/components/DetailHeader/DetailHeader.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/public/js/components/DetailHeader/DetailHeader.js b/public/js/components/DetailHeader/DetailHeader.js index 01635e31e..7cbc52c37 100644 --- a/public/js/components/DetailHeader/DetailHeader.js +++ b/public/js/components/DetailHeader/DetailHeader.js @@ -330,8 +330,12 @@ export default { @updated="updatedTag" zuordnung_typ="prestudent_id" > -
-
unruly
From 49cbbfc50cdcc8526913737efa67b6cdb117f66d Mon Sep 17 00:00:00 2001 From: ma0068 Date: Wed, 8 Apr 2026 15:24:06 +0200 Subject: [PATCH 06/28] update user --- application/libraries/TagLib.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/application/libraries/TagLib.php b/application/libraries/TagLib.php index 2200e16d9..e64f9819e 100644 --- a/application/libraries/TagLib.php +++ b/application/libraries/TagLib.php @@ -194,7 +194,7 @@ class TagLib ], array( 'updateamum' => date('Y-m-d H:i:s'), - 'updatevon' => 'Manually', + 'updatevon' => getAuthUID(), )); if (isError($resultUpdateNotiz)) @@ -208,10 +208,10 @@ class TagLib $resultInsertNotiz = $this->_ci->NotizModel->insert(array( 'titel' => 'TAG', 'text' => 'AUTOMATED TAG', - 'verfasser_uid' => self::BATCHUSER, //has to be an uid //TODO (auth UID) + 'verfasser_uid' => getAuthUID(), 'erledigt' => false, 'insertamum' => date('Y-m-d H:i:s'), - 'insertvon' => 'Manually', + 'insertvon' => getAuthUID(), 'typ' => $tag )); From fdb037da96e81de8ab2682f5de2a5e636d1a17fc Mon Sep 17 00:00:00 2001 From: Harald Bamberger Date: Thu, 9 Apr 2026 08:36:13 +0200 Subject: [PATCH 07/28] poc move logic for single tags to libs, and add lib loading path and name to extra column in tbl_notiztyp --- application/controllers/jobs/TagJob.php | 17 ++++++++ .../libraries/tags/CoreWiederholerTagLib.php | 42 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 application/libraries/tags/CoreWiederholerTagLib.php diff --git a/application/controllers/jobs/TagJob.php b/application/controllers/jobs/TagJob.php index 689bb6ac9..c70063707 100644 --- a/application/controllers/jobs/TagJob.php +++ b/application/controllers/jobs/TagJob.php @@ -37,6 +37,23 @@ class TagJob extends JOB_Controller ]); } + public function pocTagLibs() + { + $automatedTagsRes = $this->NotiztypModel->loadWhere(array('automatisiert' => true, 'taglib IS NOT NULL' => null)); + //echo $this->NotiztypModel->db->last_query(); + $automatedTags = hasData($automatedTagsRes) ? getData($automatedTagsRes) : []; + print_r($automatedTags); + + foreach($automatedTags as $autoTag) + { + $taglib = strtolower(basename($autoTag->taglib)); + $this->load->library($autoTag->taglib); + + $ids = $this->$taglib->getZuordnungIds(array('studiensemester_kurzbz' => 'SS2026')); + print_r($ids); + } + } + public function rebuildAutomatedTags() { print_r( PHP_EOL . "Start Job rebuild" . PHP_EOL); diff --git a/application/libraries/tags/CoreWiederholerTagLib.php b/application/libraries/tags/CoreWiederholerTagLib.php new file mode 100644 index 000000000..f25a0e02c --- /dev/null +++ b/application/libraries/tags/CoreWiederholerTagLib.php @@ -0,0 +1,42 @@ +ci = get_instance(); + $this->ci->load->model('crm/Prestudentstatus_model', 'PrestudentstatusModel'); + } + + public function getZuordnungIds(array $params) + { + if(!isset($params['studiensemester_kurzbz'])) + { + return (object) array( + 'prestudent_id' => [] + ); + } + + $semester = $params['studiensemester_kurzbz']; + $result = $this->ci->PrestudentstatusModel-> loadWhere(array( + 'statusgrund_id' => 16, + 'studiensemester_kurzbz' => $semester + )); + $data = $result->retval; + $ids = array_map(function($item) { + return $item->prestudent_id; + }, $data); + + return (object) array( + 'prestudent_id' => $ids + ); + } + + +} From ee6f28c06dff664b56f44b4296b19af802e5c0d4 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Thu, 9 Apr 2026 13:58:42 +0200 Subject: [PATCH 08/28] Refactor TagJob and TabLib: use dynamic approach with column taglib for creating Tags --- application/controllers/jobs/TagJob.php | 90 ++++++++++++++++++- application/libraries/TagLib.php | 70 +++++++++++++-- .../tags/CorePrewiederholerTagLib.php | 66 ++++++++++++++ .../libraries/tags/CoreWiederholerTagLib.php | 23 +++++ 4 files changed, 239 insertions(+), 10 deletions(-) create mode 100644 application/libraries/tags/CorePrewiederholerTagLib.php diff --git a/application/controllers/jobs/TagJob.php b/application/controllers/jobs/TagJob.php index c70063707..644f9b521 100644 --- a/application/controllers/jobs/TagJob.php +++ b/application/controllers/jobs/TagJob.php @@ -8,7 +8,7 @@ class TagJob extends JOB_Controller { const BATCHUSER = 'sftest'; - const SEMESTER = 'WS2025'; //docker + const SEMESTER = 'SS2026'; //docker //TODO semester /** @@ -49,7 +49,40 @@ class TagJob extends JOB_Controller $taglib = strtolower(basename($autoTag->taglib)); $this->load->library($autoTag->taglib); - $ids = $this->$taglib->getZuordnungIds(array('studiensemester_kurzbz' => 'SS2026')); + $ids = $this->$taglib->getZuordnungIds(array('studiensemester_kurzbz' => self::SEMESTER)); + print_r($ids); + } + } + + public function loadTagLibs() + { + $automatedTagsRes = $this->NotiztypModel->loadWhere(array('automatisiert' => true, 'taglib IS NOT NULL' => null)); + //echo $this->NotiztypModel->db->last_query(); + $automatedTags = hasData($automatedTagsRes) ? getData($automatedTagsRes) : []; + print_r($automatedTags); + + foreach($automatedTags as $autoTag) + { + // getPath: must not be lost + $filePath = APPPATH . 'libraries/' . $autoTag->taglib . '.php'; // APPPATH = application/ + + if(file_exists($filePath)) { + require_once($filePath); + } else { + echo "File not found: " . $filePath; + continue; + } + + // className without PATH (basename) + $className = basename($autoTag->taglib); + + $obj = new $className(); + $ids = $obj->getZuordnungIds(['studiensemester_kurzbz' => self::SEMESTER]); + + $kurz_bz = $autoTag->typ_kurzbz; + + echo PHP_EOL . $className . ": "; + echo PHP_EOL . $kurz_bz . ": "; print_r($ids); } } @@ -60,6 +93,59 @@ class TagJob extends JOB_Controller $automaticTags = $this->config->item('stv_automatic_tags'); print_r( implode( ", ", $automaticTags) . PHP_EOL); + $automatedTagsRes = $this->NotiztypModel->loadWhere(array('automatisiert' => true, 'taglib IS NOT NULL' => null)); + //echo $this->NotiztypModel->db->last_query(); + $automatedTags = hasData($automatedTagsRes) ? getData($automatedTagsRes) : []; + print_r($automatedTags); + + + foreach($automatedTags as $autoTag) + { + // getPath: must not be lost + $filePath = APPPATH . 'libraries/' . $autoTag->taglib . '.php'; // APPPATH = application/ + + if(file_exists($filePath)) { + require_once($filePath); + } else { + echo "File not found: " . $filePath . PHP_EOL; + continue; + } + + $kurz_bz = $autoTag->typ_kurzbz; + // className without PATH (basename) + $className = basename($autoTag->taglib); + + $obj = new $className(); + $ids = $obj->getZuordnungIds(['studiensemester_kurzbz' => self::SEMESTER]); + + $idsArray = $ids->prestudent_id; + + $result = $this->taglib->updateAutomatedTags($kurz_bz, $idsArray); + $data = $result->retval; + if (isError($result)) + return error ('Error occurred during updateAutomatedTags'); + + print_r(PHP_EOL ."ALL TAGS " . $kurz_bz . " " . count($data[0]) . " TO ADD " . count($data[1]) . " TO RECYLE: " . count($data[2]) . " TO DELETE: " . count($data[3])); + + + print_r( PHP_EOL . "Count Recycled: "); + print_r($data[4]); + print_r( PHP_EOL . "Count Added: "); + print_r($data[6]); + print_r( PHP_EOL . "Count Deleted: "); + print_r($data[8] . PHP_EOL . PHP_EOL); + + } + print_r( PHP_EOL . "End Job rebuild" . PHP_EOL); + + } + + public function rebuildAutomatedTags_DEPR() + { + print_r( PHP_EOL . "Start Job rebuild" . PHP_EOL); + $automaticTags = $this->config->item('stv_automatic_tags'); + print_r( implode( ", ", $automaticTags) . PHP_EOL); + //TODO(Manu) use a loop in library? if(in_array('wh_auto', $automaticTags)) { diff --git a/application/libraries/TagLib.php b/application/libraries/TagLib.php index e64f9819e..aa9fb640e 100644 --- a/application/libraries/TagLib.php +++ b/application/libraries/TagLib.php @@ -18,7 +18,7 @@ class TagLib { const BATCHUSER = 'sftest'; const TYP_ZUORDNUNG = 'prestudent_id'; - const SEMESTER = 'WS2025'; + const SEMESTER = 'SS2026'; /** * Object initialization @@ -233,11 +233,67 @@ class TagLib } -/* - * main function for rebuild Tags for single prestudent - * manually triggered - * */ + /* + * main function for rebuild Tags for single prestudent + * manually triggered + * */ public function rebuildTagsForPrestudent($prestudent_id) + { + $automatedTagsRes = $this->_ci->NotiztypModel->loadWhere(array('automatisiert' => true, 'taglib IS NOT NULL' => null)); + //echo $this->NotiztypModel->db->last_query(); + $automatedTags = hasData($automatedTagsRes) ? getData($automatedTagsRes) : []; + print_r($automatedTags); + + $return = []; + + foreach($automatedTags as $autoTag) + { + // getPath: must not be lost + $filePath = APPPATH . 'libraries/' . $autoTag->taglib . '.php'; // APPPATH = application/ + + if (file_exists($filePath)) { + require_once($filePath); + } else { + echo "File not found: " . $filePath; + continue; + } + + // className without PATH (basename) + $className = basename($autoTag->taglib); + + $obj = new $className(); + $criteriaIsSet = $obj->isCriteriaSetFor([ + 'prestudent_id' => $prestudent_id, + 'studiensemester_kurzbz' => self::SEMESTER + ]); + //$return = $this->_ci->PrestudentstatusModel->db->last_query(); + $kurz_bz = $autoTag->typ_kurzbz; + + // $return[$kurz_bz] = $criteriaIsSet; + + if($criteriaIsSet) + { + $result = $this->updateAutomatedTagsForPrestudent($kurz_bz, $prestudent_id); + if (isError($result)) + return error ('Error occurred during updateAutomatedTags' . $kurz_bz); + + else + $return[$kurz_bz] = $result; + } + else { + $result = $this->checkForDelete($kurz_bz, $prestudent_id); + if($result != null) + $return[$kurz_bz] = $result; + } + + } + + + return success($return); + + } + + public function rebuildTagsForPrestudentDEPR($prestudent_id) { $automaticTags = $this->_ci->config->item('stv_automatic_tags'); $return = []; @@ -259,8 +315,6 @@ class TagLib $return[$tag] = $result; } } - - return success($return); } @@ -304,7 +358,7 @@ class TagLib return $return; } - public function isCriteriaSetFor($tag, $prestudent_id) + public function isCriteriaSetFor_DEPR($tag, $prestudent_id) { //TODO(finish list) if($tag == 'wh_auto') diff --git a/application/libraries/tags/CorePrewiederholerTagLib.php b/application/libraries/tags/CorePrewiederholerTagLib.php new file mode 100644 index 000000000..ac6d152c6 --- /dev/null +++ b/application/libraries/tags/CorePrewiederholerTagLib.php @@ -0,0 +1,66 @@ +ci = get_instance(); + $this->ci->load->model('crm/Prestudentstatus_model', 'PrestudentstatusModel'); + } + + public function getZuordnungIds(array $params) + { + if(!isset($params['studiensemester_kurzbz'])) + { + return (object) array( + 'prestudent_id' => [] + ); + } + + $semester = $params['studiensemester_kurzbz']; + $result = $this->ci->PrestudentstatusModel-> loadWhere(array( + 'statusgrund_id' => 15, + 'studiensemester_kurzbz' => $semester + )); + $data = $result->retval; + $ids = array_map(function($item) { + return $item->prestudent_id; + }, $data); + + return (object) array( + 'prestudent_id' => $ids + ); + } + + public function isCriteriaSetFor(array $params) + { + if(!isset($params['prestudent_id']) || !isset($params['studiensemester_kurzbz'])) + { + return (object) array( + 'isSet' => false + ); + } + + $semester = $params['studiensemester_kurzbz']; + $prestudent_id = $params['prestudent_id']; + + $result = $this->ci->PrestudentstatusModel->loadWhere(array( + 'statusgrund_id' => 15, + 'studiensemester_kurzbz' => $semester, + 'prestudent_id' => $prestudent_id + )); + if(hasData($result)) + { + return true; + } + else + return false; + } + +} diff --git a/application/libraries/tags/CoreWiederholerTagLib.php b/application/libraries/tags/CoreWiederholerTagLib.php index f25a0e02c..9f0dc3720 100644 --- a/application/libraries/tags/CoreWiederholerTagLib.php +++ b/application/libraries/tags/CoreWiederholerTagLib.php @@ -38,5 +38,28 @@ class CoreWiederholerTagLib ); } + public function isCriteriaSetFor(array $params) + { + if(!isset($params['prestudent_id']) || !isset($params['studiensemester_kurzbz'])) + { + return (object) array( + 'isSet' => false + ); + } + $semester = $params['studiensemester_kurzbz']; + $prestudent_id = $params['prestudent_id']; + + $result = $this->ci->PrestudentstatusModel->loadWhere(array( + 'statusgrund_id' => 16, + 'studiensemester_kurzbz' => $semester, + 'prestudent_id' => $prestudent_id + )); + if(hasData($result)) + { + return true; + } + else + return false; + } } From 1339077b5784d56a17b758870a014e770b4d64b5 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Wed, 15 Apr 2026 09:45:57 +0200 Subject: [PATCH 09/28] use single tagLibs for dynamisation new tagLibs (doubleDegree, jgv, missingZgv, Outgoing, StudienbeitragErhoeht, Unterbrecher) refactor tagJob rebuildAutomatedTags --- application/config/stv.php | 17 ----- application/controllers/jobs/TagJob.php | 21 ++--- application/libraries/TagLib.php | 24 +++++- .../libraries/tags/CoreDoubleDegreeTagLib.php | 67 ++++++++++++++++ application/libraries/tags/CoreJgvTagLib.php | 60 +++++++++++++++ .../libraries/tags/CoreMissingZgvTagLib.php | 76 +++++++++++++++++++ .../libraries/tags/CoreOutgoingTagLib.php | 59 ++++++++++++++ .../tags/CorePrewiederholerTagLib.php | 4 +- .../tags/CoreStudienbeitragErhoehtTagLib.php | 68 +++++++++++++++++ .../libraries/tags/CoreUnterbrecherTagLib.php | 64 ++++++++++++++++ .../libraries/tags/CoreWiederholerTagLib.php | 4 +- application/models/codex/Bisio_model.php | 52 +++++++++++++ .../models/person/Benutzerfunktion_model.php | 59 ++++++++++++++ 13 files changed, 536 insertions(+), 39 deletions(-) create mode 100644 application/libraries/tags/CoreDoubleDegreeTagLib.php create mode 100644 application/libraries/tags/CoreJgvTagLib.php create mode 100644 application/libraries/tags/CoreMissingZgvTagLib.php create mode 100644 application/libraries/tags/CoreOutgoingTagLib.php create mode 100644 application/libraries/tags/CoreStudienbeitragErhoehtTagLib.php create mode 100644 application/libraries/tags/CoreUnterbrecherTagLib.php diff --git a/application/config/stv.php b/application/config/stv.php index f902b30ce..6aa621a84 100644 --- a/application/config/stv.php +++ b/application/config/stv.php @@ -153,20 +153,3 @@ $config['stv_prestudent_tags'] = [ 'jgv_auto' => ['readonly' => false], 'nachteilausgl_auto' => ['readonly' => false], ]; - -//TODO(manu) check ob das besser als param für job übergeben werden soll -$config['stv_automatic_tags'] = [ - 'dd_auto', - 'wh_auto', - 'out_auto', - 'prewh_auto', - 'zgv_auto', - 'wiedereinstieg_auto', - 'stbtr_erh_auto', - 'beitr_befr_auto', - 'jgv_auto', - 'nachteilausgl_auto' -]; - -$config['stv_stgs_to_tag'] = ['254']; - diff --git a/application/controllers/jobs/TagJob.php b/application/controllers/jobs/TagJob.php index 644f9b521..9ff43def4 100644 --- a/application/controllers/jobs/TagJob.php +++ b/application/controllers/jobs/TagJob.php @@ -90,14 +90,10 @@ class TagJob extends JOB_Controller public function rebuildAutomatedTags() { print_r( PHP_EOL . "Start Job rebuild" . PHP_EOL); - $automaticTags = $this->config->item('stv_automatic_tags'); - print_r( implode( ", ", $automaticTags) . PHP_EOL); $automatedTagsRes = $this->NotiztypModel->loadWhere(array('automatisiert' => true, 'taglib IS NOT NULL' => null)); - //echo $this->NotiztypModel->db->last_query(); $automatedTags = hasData($automatedTagsRes) ? getData($automatedTagsRes) : []; - print_r($automatedTags); - + //print_r($automatedTags); foreach($automatedTags as $autoTag) { @@ -125,15 +121,12 @@ class TagJob extends JOB_Controller if (isError($result)) return error ('Error occurred during updateAutomatedTags'); - print_r(PHP_EOL ."ALL TAGS " . $kurz_bz . " " . count($data[0]) . " TO ADD " . count($data[1]) . " TO RECYLE: " . count($data[2]) . " TO DELETE: " . count($data[3])); - - - print_r( PHP_EOL . "Count Recycled: "); - print_r($data[4]); - print_r( PHP_EOL . "Count Added: "); - print_r($data[6]); - print_r( PHP_EOL . "Count Deleted: "); - print_r($data[8] . PHP_EOL . PHP_EOL); + //Output with Summary and Details + print_r(PHP_EOL . "-- TAG " . $result->retval['input']['tag'] . " --"); + print_r( PHP_EOL . "Count Recycled: " . $result->retval['summary']['recycled']); + print_r(PHP_EOL . "Count Added: ". $result->retval['summary']['added']); + print_r(PHP_EOL . "Count Deleted: ". $result->retval['summary']['deleted']); + print_r(PHP_EOL); } print_r( PHP_EOL . "End Job rebuild" . PHP_EOL); diff --git a/application/libraries/TagLib.php b/application/libraries/TagLib.php index aa9fb640e..c84cd19f8 100644 --- a/application/libraries/TagLib.php +++ b/application/libraries/TagLib.php @@ -163,8 +163,28 @@ class TagLib $deleted[] = $value; } - return success([$allTags, $toAdd, $toRecycle, $toDelete, $countRecyled, $retagged, $countAdded, $tagged, $countDeleted, $deleted]); - + return success([ + 'input' => [ + 'tag' => $tag, + 'prestudentIds' => $prestudentIds, + ], + 'summary' => [ + 'recycled' => $countRecyled, + 'added' => $countAdded, + 'deleted' => $countDeleted, + ], + 'details' => [ + 'existingTags' => $allTags, + 'toAdd' => $toAdd, + 'toRecycle' => $toRecycle, + 'toDelete' => $toDelete, + ], + 'results' => [ + 'retaggedNotizIds' => $retagged, + 'newTags' => $tagged, + 'deletedNotizIds' => $deleted, + ] + ]); } public function updateAutomatedTagsForPrestudent($tag, $prestudent_id) diff --git a/application/libraries/tags/CoreDoubleDegreeTagLib.php b/application/libraries/tags/CoreDoubleDegreeTagLib.php new file mode 100644 index 000000000..eed489fae --- /dev/null +++ b/application/libraries/tags/CoreDoubleDegreeTagLib.php @@ -0,0 +1,67 @@ +ci = get_instance(); + $this->ci->load->model('codex/Mobilitaet_model', 'MobilitaetModel'); + } + + public function getZuordnungIds(array $params) + { + if(!isset($params['studiensemester_kurzbz'])) + { + return (object) array( + 'prestudent_id' => [] + ); + } + + $semester = $params['studiensemester_kurzbz']; + + $this->ci->MobilitaetModel->addJoin('bis.tbl_gsprogramm', 'gsprogramm_id'); + $result = $this->ci->MobilitaetModel-> loadWhere(array( + 'gsprogrammtyp_kurzbz' => 'Double', + 'studiensemester_kurzbz' => $semester + )); + $data = $result->retval; + $ids = array_map(function($item) { + return $item->prestudent_id; + }, $data); + + return (object) array( + 'prestudent_id' => $ids + ); + } + + public function isCriteriaSetFor(array $params) + { + if(!isset($params['prestudent_id']) || !isset($params['studiensemester_kurzbz'])) + { + return false; + } + + $semester = $params['studiensemester_kurzbz']; + $prestudent_id = $params['prestudent_id']; + + $this->ci->MobilitaetModel->addJoin('bis.tbl_gsprogramm', 'gsprogramm_id'); + $result = $this->ci->MobilitaetModel->loadWhere(array( + 'gsprogrammtyp_kurzbz' => 'Double', + 'studiensemester_kurzbz' => $semester, + 'prestudent_id' => $prestudent_id + )); + if(hasData($result)) + { + return true; + } + else + return false; + } + +} diff --git a/application/libraries/tags/CoreJgvTagLib.php b/application/libraries/tags/CoreJgvTagLib.php new file mode 100644 index 000000000..1117e997b --- /dev/null +++ b/application/libraries/tags/CoreJgvTagLib.php @@ -0,0 +1,60 @@ +ci = get_instance(); + $this->ci->load->model('person/Benutzerfunktion_model', 'BenutzerfunktionModel'); + } + + public function getZuordnungIds(array $params) + { + if(!isset($params['studiensemester_kurzbz'])) + { + return (object) array( + 'prestudent_id' => [] + ); + } + + $semester = $params['studiensemester_kurzbz']; + + $result = $this->ci->BenutzerfunktionModel->getPrestudentsOfJgv($semester); + + $data = $result->retval; + $ids = array_map(function($item) { + return $item->prestudent_id; + }, $data); + + return (object) array( + 'prestudent_id' => $ids + ); + } + + public function isCriteriaSetFor(array $params) + { + if(!isset($params['prestudent_id']) || !isset($params['studiensemester_kurzbz'])) + { + return false; + } + + $semester = $params['studiensemester_kurzbz']; + $prestudent_id = $params['prestudent_id']; + + $result = $this->ci->BenutzerfunktionModel->isJgv($semester, $prestudent_id); + + if(hasData($result)) + { + return true; + } + else + return false; + } + +} diff --git a/application/libraries/tags/CoreMissingZgvTagLib.php b/application/libraries/tags/CoreMissingZgvTagLib.php new file mode 100644 index 000000000..acf71c4d2 --- /dev/null +++ b/application/libraries/tags/CoreMissingZgvTagLib.php @@ -0,0 +1,76 @@ +ci = get_instance(); + $this->ci->load->model('crm/Prestudent_model', 'PrestudentModel'); + } + + public function getZuordnungIds(array $params) + { + if(!isset($params['studiensemester_kurzbz'])) + { + return (object) array( + 'prestudent_id' => [] + ); + } + + $semester = $params['studiensemester_kurzbz']; + + $this->ci->PrestudentModel->addJoin('public.tbl_prestudentstatus', 'prestudent_id'); + $this->ci->PrestudentModel->addJoin('public.tbl_benutzer bn', 'person_id'); + $this->ci->PrestudentModel->addJoin('public.tbl_studiengang', 'studiengang_kz'); + $result = $this->ci->PrestudentModel-> loadWhere(array( + 'bn.aktiv' => true, //check if necessary + 'zgvdatum' => null, + 'typ' => 'b', + 'studiensemester_kurzbz' => $semester + )); + + $data = $result->retval; + $ids = array_map(function($item) { + return $item->prestudent_id; + }, $data); + + return (object) array( + 'prestudent_id' => $ids + ); + } + + public function isCriteriaSetFor(array $params) + { + if(!isset($params['prestudent_id']) || !isset($params['studiensemester_kurzbz'])) + { + return false; + } + + $semester = $params['studiensemester_kurzbz']; + $prestudent_id = $params['prestudent_id']; + + $this->ci->PrestudentModel->addJoin('public.tbl_prestudentstatus', 'prestudent_id'); + $this->ci->PrestudentModel->addJoin('public.tbl_benutzer bn', 'person_id'); + $this->ci->PrestudentModel->addJoin('public.tbl_studiengang', 'studiengang_kz'); + $result = $this->ci->PrestudentModel->loadWhere(array( + 'bn.aktiv' => true, //check if necessary + 'zgvdatum' => null, + 'typ' => 'b', + 'studiensemester_kurzbz' => $semester, + 'prestudent_id' => $prestudent_id + )); + if(hasData($result)) + { + return true; + } + else + return false; + } + +} diff --git a/application/libraries/tags/CoreOutgoingTagLib.php b/application/libraries/tags/CoreOutgoingTagLib.php new file mode 100644 index 000000000..f1764611a --- /dev/null +++ b/application/libraries/tags/CoreOutgoingTagLib.php @@ -0,0 +1,59 @@ +ci = get_instance(); + $this->ci->load->model('codex/Bisio_model', 'BisioModel'); + } + + public function getZuordnungIds(array $params) + { + if(!isset($params['studiensemester_kurzbz'])) + { + return (object) array( + 'prestudent_id' => [] + ); + } + + $semester = $params['studiensemester_kurzbz']; + + $result = $this->ci->BisioModel->getOutgoingsOfSemester($semester); + + $data = $result->retval; + $ids = array_map(function($item) { + return $item->prestudent_id; + }, $data); + + return (object) array( + 'prestudent_id' => $ids + ); + } + + public function isCriteriaSetFor(array $params) + { + if(!isset($params['prestudent_id']) || !isset($params['studiensemester_kurzbz'])) + { + return false; + } + + $semester = $params['studiensemester_kurzbz']; + $prestudent_id = $params['prestudent_id']; + + $result = $this->ci->BisioModel->isPrestudentOutgoing($semester, $prestudent_id); + if(hasData($result)) + { + return true; + } + else + return false; + } + +} diff --git a/application/libraries/tags/CorePrewiederholerTagLib.php b/application/libraries/tags/CorePrewiederholerTagLib.php index ac6d152c6..cf15bd938 100644 --- a/application/libraries/tags/CorePrewiederholerTagLib.php +++ b/application/libraries/tags/CorePrewiederholerTagLib.php @@ -42,9 +42,7 @@ class CorePrewiederholerTagLib { if(!isset($params['prestudent_id']) || !isset($params['studiensemester_kurzbz'])) { - return (object) array( - 'isSet' => false - ); + return false; } $semester = $params['studiensemester_kurzbz']; diff --git a/application/libraries/tags/CoreStudienbeitragErhoehtTagLib.php b/application/libraries/tags/CoreStudienbeitragErhoehtTagLib.php new file mode 100644 index 000000000..3e0eaaa26 --- /dev/null +++ b/application/libraries/tags/CoreStudienbeitragErhoehtTagLib.php @@ -0,0 +1,68 @@ +ci = get_instance(); + $this->ci->load->model('crm/Konto_model', 'KontoModel'); + } + + public function getZuordnungIds(array $params) + { + if(!isset($params['studiensemester_kurzbz'])) + { + return (object) array( + 'prestudent_id' => [] + ); + } + + $semester = $params['studiensemester_kurzbz']; + + $this->ci->KontoModel->addJoin('public.tbl_prestudent', 'person_id'); + $result = $this->ci->KontoModel-> loadWhere(array( + 'buchungstyp_kurzbz' => 'StudiengebuehrErhoeht', + 'studiensemester_kurzbz' => $semester + )); + $data = $result->retval; + $ids = array_map(function($item) { + return $item->prestudent_id; + }, $data); + + return (object) array( + 'prestudent_id' => $ids + ); + } + + public function isCriteriaSetFor(array $params) + { + if(!isset($params['prestudent_id']) || !isset($params['studiensemester_kurzbz'])) + { + return false; + } + + $semester = $params['studiensemester_kurzbz']; + $prestudent_id = $params['prestudent_id']; + + $this->ci->KontoModel->addJoin('public.tbl_prestudent', 'person_id'); + $result = $this->ci->KontoModel-> loadWhere(array( + 'buchungstyp_kurzbz' => 'StudiengebuehrErhoeht', + 'studiensemester_kurzbz' => $semester, + 'prestudent_id' => $prestudent_id + )); + + if(hasData($result)) + { + return true; + } + else + return false; + } + +} diff --git a/application/libraries/tags/CoreUnterbrecherTagLib.php b/application/libraries/tags/CoreUnterbrecherTagLib.php new file mode 100644 index 000000000..8ea16e378 --- /dev/null +++ b/application/libraries/tags/CoreUnterbrecherTagLib.php @@ -0,0 +1,64 @@ +ci = get_instance(); + $this->ci->load->model('crm/Prestudentstatus_model', 'PrestudentstatusModel'); + } + + public function getZuordnungIds(array $params) + { + if(!isset($params['studiensemester_kurzbz'])) + { + return (object) array( + 'prestudent_id' => [] + ); + } + + $semester = $params['studiensemester_kurzbz']; + $result = $this->ci->PrestudentstatusModel-> loadWhere(array( + 'status_kurzbz' => 'Unterbrecher', + 'studiensemester_kurzbz' => $semester + )); + $data = $result->retval; + $ids = array_map(function($item) { + return $item->prestudent_id; + }, $data); + + return (object) array( + 'prestudent_id' => $ids + ); + } + + public function isCriteriaSetFor(array $params) + { + if(!isset($params['prestudent_id']) || !isset($params['studiensemester_kurzbz'])) + { + return false; + } + + $semester = $params['studiensemester_kurzbz']; + $prestudent_id = $params['prestudent_id']; + + $result = $this->ci->PrestudentstatusModel-> loadWhere(array( + 'status_kurzbz' => 'Unterbrecher', + 'studiensemester_kurzbz' => $semester, + 'prestudent_id' => $prestudent_id + )); + if(hasData($result)) + { + return true; + } + else + return false; + } + +} diff --git a/application/libraries/tags/CoreWiederholerTagLib.php b/application/libraries/tags/CoreWiederholerTagLib.php index 9f0dc3720..43fa6fce3 100644 --- a/application/libraries/tags/CoreWiederholerTagLib.php +++ b/application/libraries/tags/CoreWiederholerTagLib.php @@ -42,9 +42,7 @@ class CoreWiederholerTagLib { if(!isset($params['prestudent_id']) || !isset($params['studiensemester_kurzbz'])) { - return (object) array( - 'isSet' => false - ); + return false; } $semester = $params['studiensemester_kurzbz']; diff --git a/application/models/codex/Bisio_model.php b/application/models/codex/Bisio_model.php index 1cff1dc54..765f01b84 100644 --- a/application/models/codex/Bisio_model.php +++ b/application/models/codex/Bisio_model.php @@ -44,4 +44,56 @@ class Bisio_model extends DB_Model else return success("Bisio not found"); } + + /** + * Gets outgoing students of certain Semester + * @param String studiensemester_kurzbz + * @return array of prestudent_ids + */ + public function getOutgoingsOfSemester($studiensemester_kurzbz) + { + $query = " + SELECT DISTINCT ps.prestudent_id + FROM bis.tbl_bisio + JOIN public.tbl_student USING (student_uid) + JOIN public.tbl_prestudent ps USING (prestudent_id) + JOIN public.tbl_prestudentstatus pss ON (ps.prestudent_id = pss.prestudent_id) + JOIN public.tbl_studiensemester ss ON (pss.studiensemester_kurzbz = ss.studiensemester_kurzbz) + WHERE ss.studiensemester_kurzbz = ? + AND ( + tbl_bisio.von <= ss.ende + AND ( + tbl_bisio.bis >= ss.start + OR tbl_bisio.bis IS NULL + ) + ) + "; + + return $this->execQuery($query, array($studiensemester_kurzbz)); + } + + public function isPrestudentOutgoing($studiensemester_kurzbz, $prestudent_id) + { + $query = " + SELECT + * + FROM bis.tbl_bisio + JOIN public.tbl_student USING (student_uid) + JOIN public.tbl_prestudent ps USING (prestudent_id) + JOIN public.tbl_prestudentstatus pss ON (ps.prestudent_id = pss.prestudent_id) + JOIN public.tbl_studiensemester ss ON (pss.studiensemester_kurzbz = ss.studiensemester_kurzbz) + WHERE ss.studiensemester_kurzbz = ? + AND pss.status_kurzbz = 'Student' + AND ( + tbl_bisio.von <= ss.ende + AND ( + tbl_bisio.bis >= ss.start + OR tbl_bisio.bis IS NULL + ) + ) + AND ps.prestudent_id = ? + "; + + return $this->execQuery($query, array($studiensemester_kurzbz, $prestudent_id)); + } } diff --git a/application/models/person/Benutzerfunktion_model.php b/application/models/person/Benutzerfunktion_model.php index 8c43e4f84..f5a453bd0 100644 --- a/application/models/person/Benutzerfunktion_model.php +++ b/application/models/person/Benutzerfunktion_model.php @@ -314,5 +314,64 @@ class Benutzerfunktion_model extends DB_Model return success($funktionJson); } + /** + * Gets all Prestudents with details for a given Benutzerfunktion and optionally semester + * + * @param String $studiensemester_kurzbz + * @return object |null + */ + public function getPrestudentsOfJgv($semester) + { + $query = " + SELECT DISTINCT ps.prestudent_id + FROM public.tbl_benutzerfunktion bf + JOIN public.tbl_benutzer bn USING (uid) + JOIN public.tbl_prestudent ps USING (person_id) + JOIN public.tbl_prestudentstatus pss ON (ps.prestudent_id = pss.prestudent_id) + JOIN public.tbl_studiensemester ss ON (pss.studiensemester_kurzbz = ss.studiensemester_kurzbz) + WHERE ss.studiensemester_kurzbz = ? + AND bf.funktion_kurzbz = 'jgv' + AND ( + bf.datum_von <= ss.ende + AND ( + bf.datum_bis >= ss.start + OR bf.datum_bis IS NULL + ) + ) + "; + + return $this->execQuery($query, array($semester)); + } + + /** + * Checks if a certain prestudent has the Benutzerfunktion jgv for a certain semester + * + * @param String $studiensemester_kurzbz + * @param $prestudent_id + * @return object |null + */ + public function isJgv($semester, $prestudent_id) + { + $query = " + SELECT * + FROM public.tbl_benutzerfunktion bf + JOIN public.tbl_benutzer bn USING (uid) + JOIN public.tbl_prestudent ps USING (person_id) + JOIN public.tbl_prestudentstatus pss ON (ps.prestudent_id = pss.prestudent_id) + JOIN public.tbl_studiensemester ss ON (pss.studiensemester_kurzbz = ss.studiensemester_kurzbz) + WHERE ss.studiensemester_kurzbz = ? + AND bf.funktion_kurzbz = 'jgv' + AND ( + bf.datum_von <= ss.ende + AND ( + bf.datum_bis >= ss.start + OR bf.datum_bis IS NULL + ) + ) + AND ps.prestudent_id = ? + "; + + return $this->execQuery($query, array($semester, $prestudent_id)); + } } From 695f3455e6d3f99163978e12a4acb3d35d864c41 Mon Sep 17 00:00:00 2001 From: Harald Bamberger Date: Thu, 16 Apr 2026 15:20:11 +0200 Subject: [PATCH 10/28] add function generateCSSsIncludeIfExtensionCssExists and use to load additional tag.css from extensions if exists --- application/helpers/hlp_header_helper.php | 22 ++++++++++++++++++++++ application/views/templates/FHC-Header.php | 6 +++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/application/helpers/hlp_header_helper.php b/application/helpers/hlp_header_helper.php index 27dfba5a1..53a5f5ba3 100644 --- a/application/helpers/hlp_header_helper.php +++ b/application/helpers/hlp_header_helper.php @@ -270,6 +270,28 @@ function absoluteJsImportUrl($relurl) return $url; } +/* + * Generate Css File Include if Extension contains file + * + * @param $relativeFilePath path relative to Extension public/css dir + */ +function generateCSSsIncludeIfExtensionCssExists($relativeFilePath) +{ + $fsiterator = new FilesystemIterator(FHCPATH . 'application/extensions'); + foreach ($fsiterator as $fsitem) + { + if(preg_match('/^FHC-Core-/', $fsitem->getBasename())) + { + $extensionfile = 'public/extensions/' . $fsitem->getBasename() + . '/css/' . $relativeFilePath; + if(is_readable(FHCPATH . $extensionfile)) + { + generateCSSsInclude($extensionfile); + } + } + } +} + /* * Manipulate CI views includes Array to load * - public/js/FhcApps.js via customJSs and diff --git a/application/views/templates/FHC-Header.php b/application/views/templates/FHC-Header.php index 7b53cbf5d..4203aa571 100644 --- a/application/views/templates/FHC-Header.php +++ b/application/views/templates/FHC-Header.php @@ -132,7 +132,11 @@ if ($cis === true) generateCSSsInclude(defined('CIS4') ? 'public/css/cis4.css' : 'public/css/cis_bs5.css'); //Tags - if ($tags === true) generateCSSsInclude('public/css/tags.css'); + if ($tags === true) + { + generateCSSsInclude('public/css/tags.css'); + generateCSSsIncludeIfExtensionCssExists('tags.css'); + } $extapphelper = ExtendableAppsHelper::getInstance(); $extapphelper->init($customCSSs, $customJSs, $customJSModules); From c7b25e66321684ea9382c2e9712335c7bb227bbb Mon Sep 17 00:00:00 2001 From: Harald Bamberger Date: Thu, 16 Apr 2026 16:21:33 +0200 Subject: [PATCH 11/28] add name to TagComponent, combine action slot definition for tagcomponent with definition for filter active --- .../Stv/Studentenverwaltung/List.js | 29 ++++++++++--------- public/js/components/Tag/Tag.js | 1 + 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/public/js/components/Stv/Studentenverwaltung/List.js b/public/js/components/Stv/Studentenverwaltung/List.js index 1aa2c6b70..4fe8b5eb6 100644 --- a/public/js/components/Stv/Studentenverwaltung/List.js +++ b/public/js/components/Stv/Studentenverwaltung/List.js @@ -637,22 +637,23 @@ export default { @updated="updatedTag" zuordnung_typ="prestudent_id" > - - diff --git a/public/js/tabulator/formatter/tags.js b/public/js/tabulator/formatter/tags.js index 906f2fc6c..0af1953fd 100644 --- a/public/js/tabulator/formatter/tags.js +++ b/public/js/tabulator/formatter/tags.js @@ -46,6 +46,7 @@ export function tagFormatter(cell, tagComponent) const tagDef = mappedData.find(t => t.typ_kurzbz === tag.typ_kurzbz); + //todo: check trigger manually after creation of manual automatic tag if (!tagDef && tag.typ_kurzbz.includes("_auto") || tagDef?.automatisiert) { tagElement.className += " tag_auto"; tagElement.innerHTML = " " + tag.beschreibung; From e5e22931a97a72885cb63615fe540899c50a184c Mon Sep 17 00:00:00 2001 From: ma0068 Date: Fri, 24 Apr 2026 12:49:00 +0200 Subject: [PATCH 14/28] add db queries for update system, update tags in config --- application/config/stv.php | 4 +- ...ehtTagLib.php => CoreStbErhoehtTagLib.php} | 2 +- system/dbupdate_3.4.php | 1 + .../75959_StudVw_Automatische_Tags.php | 125 ++++++++++++++++++ 4 files changed, 128 insertions(+), 4 deletions(-) rename application/libraries/tags/{CoreStudienbeitragErhoehtTagLib.php => CoreStbErhoehtTagLib.php} (97%) create mode 100644 system/dbupdate_3.4/75959_StudVw_Automatische_Tags.php diff --git a/application/config/stv.php b/application/config/stv.php index 2b11224d5..b0db82b34 100644 --- a/application/config/stv.php +++ b/application/config/stv.php @@ -147,9 +147,7 @@ $config['stv_prestudent_tags'] = [ 'prewh_auto' => ['readonly' => true], 'out_auto' => ['readonly' => false], 'zgv_auto' => ['readonly' => true], - 'wiedereinstieg_auto' => ['readonly' => true], + 'unterbrecher_auto' => ['readonly' => true], 'stbtr_erh_auto' => ['readonly' => true], - 'beitr_befr_auto' => ['readonly' => true], 'jgv_auto' => ['readonly' => false], - 'nachteilausgl_auto' => ['readonly' => true], ]; diff --git a/application/libraries/tags/CoreStudienbeitragErhoehtTagLib.php b/application/libraries/tags/CoreStbErhoehtTagLib.php similarity index 97% rename from application/libraries/tags/CoreStudienbeitragErhoehtTagLib.php rename to application/libraries/tags/CoreStbErhoehtTagLib.php index 82dcee3b8..2c0b47d2e 100644 --- a/application/libraries/tags/CoreStudienbeitragErhoehtTagLib.php +++ b/application/libraries/tags/CoreStbErhoehtTagLib.php @@ -4,7 +4,7 @@ * * @author ma0068 */ -class CoreStudienbeitragErhoehtTagLib +class CoreStbErhoehtTagLib { protected $ci; diff --git a/system/dbupdate_3.4.php b/system/dbupdate_3.4.php index 4ddb38203..5d108a90a 100644 --- a/system/dbupdate_3.4.php +++ b/system/dbupdate_3.4.php @@ -92,6 +92,7 @@ require_once('dbupdate_3.4/68744_StV_settings.php'); require_once('dbupdate_3.4/62889_reihungstest_ueberwachung_mit_constructor.php'); require_once('dbupdate_3.4/71399_dashboard_update_widget_paths.php'); require_once('dbupdate_3.4/71645_studvw_messagetab_ladezeit.php'); +require_once('dbupdate_3.4/75959_StudVw_Automatische_Tags.php'); // *** Pruefung und hinzufuegen der neuen Attribute und Tabellen echo '

Pruefe Tabellen und Attribute!

'; diff --git a/system/dbupdate_3.4/75959_StudVw_Automatische_Tags.php b/system/dbupdate_3.4/75959_StudVw_Automatische_Tags.php new file mode 100644 index 000000000..c75d0ce14 --- /dev/null +++ b/system/dbupdate_3.4/75959_StudVw_Automatische_Tags.php @@ -0,0 +1,125 @@ +db_query("SELECT taglib FROM public.tbl_notiz_typ LIMIT 1")) +{ + $qry = 'ALTER TABLE public.tbl_notiz_typ ADD COLUMN taglib character varying(32);'; + + if(!$db->db_query($qry)) + echo ' public.tbl_notiz_typ '.$db->db_last_error().'
'; + else + echo '
public.tbl_notiz_typ: Neue Spalte taglib hinzugefügt'; +} + +//automatic tags anlegen +$tags = [ + [ + 'typ_kurzbz' => 'wh_auto', + 'bezeichnung' => '{Wiederholer, repeater}', + 'style' => 'tag_dark_grey', + 'prioritaet' => 11, + 'taglib' => 'tags/CoreWiederholerTagLib' + ], + [ + 'typ_kurzbz' => 'dd_auto', + 'bezeichnung' => '{DoubleDegree, DoubleDegree}', + 'style' => 'tag_braun', + 'prioritaet' => 10, + 'taglib' => 'tags/CoreDoubleDegreeTagLib' + ], + [ + 'typ_kurzbz' => 'out_auto', + 'bezeichnung' => '{Outgoing, Outgoing}', + 'style' => 'tag_limette', + 'prioritaet' => 12, + 'taglib' => 'tags/CoreOutgoingTagLib' + ], + [ + 'typ_kurzbz' => 'prewh_auto', + 'bezeichnung' => '{Pre-Wiederholer, pre-repeater}', + 'style' => 'tag_light_grey', + 'prioritaet' => 13, + 'taglib' => 'tags/CorePrewiederholerTagLib' + ], + [ + 'typ_kurzbz' => 'zgv_auto', + 'bezeichnung' => '{ZGV offen, ZGV missing}', + 'style' => 'tag_lavendel', + 'prioritaet' => 14, + 'taglib' => 'tags/CoreMissingZgvTagLib' + ], + [ + 'typ_kurzbz' => 'unterbrecher_auto', + 'bezeichnung' => '{Unterbrecher, Interrupter}', + 'style' => 'tag_blau', + 'prioritaet' => 15, + 'taglib' => 'tags/CoreUnterbrecherTagLib' + ], + [ + 'typ_kurzbz' => 'stbtr_erh_auto', + 'bezeichnung' => '{erh.Studienbeitrag, Incr. Tuition Fees}', + 'style' => 'tag_pfirsich', + 'prioritaet' => 16, + 'taglib' => 'tags/CoreStbErhoehtTagLib' + ], + [ + 'typ_kurzbz' => 'jgv_auto', + 'bezeichnung' => '{JGV, Year Group Representative}', + 'style' => 'tag_gelb', + 'prioritaet' => 17, + 'taglib' => 'tags/CoreJgvTagLib' + ], + +]; + +foreach ($tags as $tag) { + + $checkQry = " + SELECT 1 + FROM public.tbl_notiz_typ + WHERE typ_kurzbz = '".$tag['typ_kurzbz']."' + "; + + if ($result = $db->db_query($checkQry)) { + + if ($db->db_num_rows($result) == 0) { + + $qry = " + INSERT INTO public.tbl_notiz_typ + ( + typ_kurzbz, + bezeichnung_mehrsprachig, + automatisiert, + aktiv, + tag, + style, + vorrueckung, + prioritaet, + taglib + ) + VALUES + ( + '".$tag['typ_kurzbz']."', + '".$tag['bezeichnung']."', + true, + true, + true, + '".$tag['style']."', + false, + '".$tag['prioritaet']."', + '".$tag['taglib']."' + ) + "; + + if (!$db->db_query($qry)) + { + echo 'public.tbl_notiz_typ: '. $tag['typ_kurzbz']. ' '. $db->db_last_error().'
'; + } + else + { + echo '
public.tbl_notiz_typ: Automatic Tag '.$tag['typ_kurzbz'].' hinzugefuegt'; + } + } + } +} From 2723d6a741b20560591c12ea8d70026f895d8544 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Fri, 24 Apr 2026 14:07:14 +0200 Subject: [PATCH 15/28] get Semester of Model instead of Using CONST, delete unused models --- application/controllers/jobs/TagJob.php | 18 ++++++++++-------- application/libraries/TagLib.php | 18 +++++++++++------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/application/controllers/jobs/TagJob.php b/application/controllers/jobs/TagJob.php index 52c0326c9..9db55c929 100644 --- a/application/controllers/jobs/TagJob.php +++ b/application/controllers/jobs/TagJob.php @@ -8,8 +8,6 @@ class TagJob extends JOB_Controller { const BATCHUSER = 'sftest'; - const SEMESTER = 'SS2026'; //docker - //TODO semester /** * API constructor @@ -26,11 +24,8 @@ class TagJob extends JOB_Controller // Load Models $this->load->model('crm/Prestudentstatus_model', 'PrestudentstatusModel'); - - $this->load->model('organisation/Studiengang_model', 'StudiengangModel'); - $this->load->model('person/Notiz_model', 'NotizModel'); + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); $this->load->model('system/Notiztyp_model', 'NotiztypModel'); - $this->load->model('person/Notizzuordnung_model', 'NotizzuordnungModel'); $this->loadPhrases([ 'lehre' @@ -43,7 +38,14 @@ class TagJob extends JOB_Controller $automatedTagsRes = $this->NotiztypModel->loadWhere(array('automatisiert' => true, 'taglib IS NOT NULL' => null)); $automatedTags = hasData($automatedTagsRes) ? getData($automatedTagsRes) : []; - //print_r($automatedTags); + + $result = $this->StudiensemesterModel->getLastOrAktSemester(); + if (isError($result)) + return error ('Error occurred during retrieving studiensemester'); + if (empty($result->retval) || !isset($result->retval[0])) { + return error('No studiensemester found'); + } + $studiensemester_kurzbz = $result->retval[0]->studiensemester_kurzbz ?? null; foreach($automatedTags as $autoTag) { @@ -63,7 +65,7 @@ class TagJob extends JOB_Controller $obj = new $className(); - $outputArray = $obj->getZuordnungIds(['studiensemester_kurzbz' => self::SEMESTER]); + $outputArray = $obj->getZuordnungIds(['studiensemester_kurzbz' => $studiensemester_kurzbz]); $data = $outputArray->data; $result = $this->taglib->updateAutomatedTags($kurz_bz, $data); diff --git a/application/libraries/TagLib.php b/application/libraries/TagLib.php index 353c8eb56..5724d3ff5 100644 --- a/application/libraries/TagLib.php +++ b/application/libraries/TagLib.php @@ -18,7 +18,6 @@ class TagLib { const BATCHUSER = 'sftest'; const TYP_ZUORDNUNG = 'prestudent_id'; - const SEMESTER = 'SS2026'; /** * Object initialization @@ -31,15 +30,11 @@ class TagLib $this->_ci->load->config('stv'); // Models - $this->_ci->load->model('organisation/Studiengang_model', 'StudiengangModel'); - $this->_ci->load->model('crm/Prestudent_model', 'PrestudentModel'); - $this->_ci->load->model('person/Person_model', 'PersonModel'); $this->_ci->load->model('person/Notiz_model', 'NotizModel'); $this->_ci->load->model('system/Notiztyp_model', 'NotiztypModel'); $this->_ci->load->model('person/Notizzuordnung_model', 'NotizzuordnungModel'); $this->_ci->load->model('crm/Prestudentstatus_model', 'PrestudentstatusModel'); - // Tag-Helper - + $this->_ci->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); // Libraries $this->_ci->load->library('PermissionLib'); @@ -316,6 +311,15 @@ class TagLib $automatedTagsRes = $this->_ci->NotiztypModel->loadWhere(array('automatisiert' => true, 'taglib IS NOT NULL' => null)); //echo $this->NotiztypModel->db->last_query(); $automatedTags = hasData($automatedTagsRes) ? getData($automatedTagsRes) : []; + + $result = $this->_ci->StudiensemesterModel->getLastOrAktSemester(); + if (isError($result)) + return error ('Error occurred during retrieving studiensemester'); + if (empty($result->retval) || !isset($result->retval[0])) { + return error('No studiensemester found'); + } + $studiensemester_kurzbz = $result->retval[0]->studiensemester_kurzbz ?? null; + print_r($automatedTags); $return = []; @@ -338,7 +342,7 @@ class TagLib $obj = new $className(); $criteriaIsSet = $obj->isCriteriaSetFor([ 'prestudent_id' => $prestudent_id, - 'studiensemester_kurzbz' => self::SEMESTER + 'studiensemester_kurzbz' => $studiensemester_kurzbz ]); //$return = $this->_ci->PrestudentstatusModel->db->last_query(); $kurz_bz = $autoTag->typ_kurzbz; From e856c8ad6bb98999b751137182e4ac553b833150 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Mon, 27 Apr 2026 10:01:54 +0200 Subject: [PATCH 16/28] change settings bezeichnung_mehrsprachig::varchar[] in TagController functions getTag and getTags --- application/config/stv.php | 2 +- application/core/Tag_Controller.php | 15 +++++++-------- public/js/components/Tag/tagFormatter.js | 1 + public/js/tabulator/formatter/tags.js | 3 +-- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/application/config/stv.php b/application/config/stv.php index b0db82b34..4ca40f62b 100644 --- a/application/config/stv.php +++ b/application/config/stv.php @@ -147,7 +147,7 @@ $config['stv_prestudent_tags'] = [ 'prewh_auto' => ['readonly' => true], 'out_auto' => ['readonly' => false], 'zgv_auto' => ['readonly' => true], - 'unterbrecher_auto' => ['readonly' => true], + 'unterbrecher_auto' => ['readonly' => false], 'stbtr_erh_auto' => ['readonly' => true], 'jgv_auto' => ['readonly' => false], ]; diff --git a/application/core/Tag_Controller.php b/application/core/Tag_Controller.php index b3726ceed..ecfb6f5de 100644 --- a/application/core/Tag_Controller.php +++ b/application/core/Tag_Controller.php @@ -43,7 +43,6 @@ class Tag_Controller extends FHCAPI_Controller public function getTag($readonly_tags = null) { - $language = $this->_getLanguageIndex(); $id = $this->input->get('id'); if (is_array($readonly_tags) && !isEmptyArray($readonly_tags)) @@ -68,7 +67,7 @@ class Tag_Controller extends FHCAPI_Controller $this->NotizModel->addSelect( "tbl_notiz.titel, tbl_notiz.text, - array_to_json(bezeichnung_mehrsprachig::varchar[])->>". $language. " as bezeichnung, + array_to_json(bezeichnung_mehrsprachig::varchar[])->>0 as bezeichnung, tbl_notiz.notiz_id, tbl_notiz_typ.style, tbl_notiz_typ.automatisiert, @@ -97,14 +96,16 @@ class Tag_Controller extends FHCAPI_Controller public function getTags($tags = null) { + $language = $this->_getLanguageIndex(); + $this->NotiztypModel->addSelect( - 'typ_kurzbz as tag_typ_kurzbz, - array_to_json(bezeichnung_mehrsprachig::varchar[])->>0 as bezeichnung, + "typ_kurzbz as tag_typ_kurzbz, + array_to_json(bezeichnung_mehrsprachig::varchar[])->>". $language. " as bezeichnung, style, beschreibung, tag, automatisiert - ' + " ); $this->NotiztypModel->addOrder('prioritaet'); @@ -283,7 +284,6 @@ class Tag_Controller extends FHCAPI_Controller } public function getAllTags($readonly_tags = false){ - $language = $this->_getLanguageIndex(); $prestudent_id = $this->input->get('prestudent_id'); //TODO check for readonly: necessary? @@ -305,11 +305,10 @@ class Tag_Controller extends FHCAPI_Controller END as readonly "); } - $this->NotizModel->addSelect( "tbl_notiz.titel, tbl_notiz.text, - array_to_json(bezeichnung_mehrsprachig::varchar[])->>". $language. " as bezeichnung, + array_to_json(bezeichnung_mehrsprachig::varchar[])->>0 as bezeichnung, tbl_notiz.notiz_id, tbl_notiz_typ.style, tbl_notiz_typ.automatisiert, diff --git a/public/js/components/Tag/tagFormatter.js b/public/js/components/Tag/tagFormatter.js index 76471ec42..e438c4c55 100644 --- a/public/js/components/Tag/tagFormatter.js +++ b/public/js/components/Tag/tagFormatter.js @@ -3,6 +3,7 @@ export function idTagFormatter (id, tagData, tagComponent, typeId) { if (!id) return; + console.log(tagData); const parsedTags = tagData.map(tag => ({ id: tag.notiz_id, diff --git a/public/js/tabulator/formatter/tags.js b/public/js/tabulator/formatter/tags.js index 0af1953fd..b9578dbd4 100644 --- a/public/js/tabulator/formatter/tags.js +++ b/public/js/tabulator/formatter/tags.js @@ -46,8 +46,7 @@ export function tagFormatter(cell, tagComponent) const tagDef = mappedData.find(t => t.typ_kurzbz === tag.typ_kurzbz); - //todo: check trigger manually after creation of manual automatic tag - if (!tagDef && tag.typ_kurzbz.includes("_auto") || tagDef?.automatisiert) { + if (!tagDef && tag.typ_kurzbz?.includes("_auto") || tagDef?.automatisiert) { tagElement.className += " tag_auto"; tagElement.innerHTML = " " + tag.beschreibung; } From 21eb95bb2339337ac2250d8c87e988981ef32ef4 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Tue, 28 Apr 2026 16:24:30 +0200 Subject: [PATCH 17/28] manually triggering of updateTag --- application/core/Tag_Controller.php | 2 +- application/libraries/TagLib.php | 129 ++++++++++++++---- .../libraries/tags/CoreDoubleDegreeTagLib.php | 13 +- application/libraries/tags/CoreJgvTagLib.php | 4 +- .../libraries/tags/CoreMissingZgvTagLib.php | 4 +- .../libraries/tags/CoreOutgoingTagLib.php | 64 +-------- .../tags/CorePrewiederholerTagLib.php | 10 +- .../libraries/tags/CoreStbErhoehtTagLib.php | 9 +- .../libraries/tags/CoreUnterbrecherTagLib.php | 10 +- .../libraries/tags/CoreWiederholerTagLib.php | 14 +- .../models/person/Benutzerfunktion_model.php | 2 +- public/js/components/Tag/tagFormatter.js | 1 - 12 files changed, 158 insertions(+), 104 deletions(-) diff --git a/application/core/Tag_Controller.php b/application/core/Tag_Controller.php index ecfb6f5de..44fd06891 100644 --- a/application/core/Tag_Controller.php +++ b/application/core/Tag_Controller.php @@ -100,7 +100,7 @@ class Tag_Controller extends FHCAPI_Controller $this->NotiztypModel->addSelect( "typ_kurzbz as tag_typ_kurzbz, - array_to_json(bezeichnung_mehrsprachig::varchar[])->>". $language. " as bezeichnung, + array_to_json(bezeichnung_mehrsprachig::varchar[])->>0 as bezeichnung, style, beschreibung, tag, diff --git a/application/libraries/TagLib.php b/application/libraries/TagLib.php index 5724d3ff5..721215965 100644 --- a/application/libraries/TagLib.php +++ b/application/libraries/TagLib.php @@ -39,15 +39,12 @@ class TagLib // Libraries $this->_ci->load->library('PermissionLib'); $this->_ci->load->library('PrestudentLib'); - - } public function updateAutomatedTags($tag, $inputData) { /* - $inputData expected pattern - + $params array expected pattern [ [ 'prestudent_id' => 123456, @@ -64,6 +61,8 @@ class TagLib $zeitraum = []; $prestudentIds = []; + //TODO(Manu) check minimal input: + foreach ($inputData as $row) { $pid = $row['prestudent_id']; @@ -74,7 +73,6 @@ class TagLib 'bis' => $row['bis'] ?? null ]; } - $prestudentIds = array_unique($prestudentIds); // --------------------------------- @@ -239,11 +237,18 @@ class TagLib ]); } - public function updateAutomatedTagsForPrestudent($tag, $prestudent_id) + public function updateAutomatedTagsForPrestudent_DEPR($tag, $prestudent_id) { + $_ci = get_instance(); + $_ci->addMeta( + 'IN OLD FUNCTION updateTags', $tag + ); $return = null; $notiz_id = null; + //von und bis auslesen + + $this->_ci->NotizModel->addSelect('nz.notiz_id'); $this->_ci->NotizModel->addSelect('prestudent_id'); $this->_ci->NotizModel->addJoin('public.tbl_notizzuordnung nz', 'notiz_id'); @@ -275,6 +280,7 @@ class TagLib $return = ['recycled' => $notiz_id]; } else + { //TODO(Manu) refactor for recycle, add $resultInsertNotiz = $this->_ci->NotizModel->insert(array( @@ -303,28 +309,96 @@ class TagLib return success($return); } + public function updateAutomatedTagsForPrestudent(array $params) + { + $return = null; + $notiz_id = null; + + $von = $params['von']; + $bis = $params['bis']; + $tag = $params['kurzbz']; + $prestudent_id = $params['prestudent_id']; + + $this->_ci->NotizModel->addSelect('nz.notiz_id'); + $this->_ci->NotizModel->addSelect('prestudent_id'); + $this->_ci->NotizModel->addJoin('public.tbl_notizzuordnung nz', 'notiz_id'); + $resultAllTags = $this->_ci->NotizModel->loadWhere([ + 'typ' => $tag, + 'prestudent_id' => $prestudent_id + ]); + if(hasData($resultAllTags)) + { + $notiz_id = $resultAllTags->retval[0]->notiz_id; + } + + //RECYCLE + if ($notiz_id !== null) + { + //TODO(Manu) refactor for recycle, add + $resultUpdateNotiz = $this->_ci->NotizModel->update( + [ + 'notiz_id' => $notiz_id + ], + array( + 'updateamum' => date('Y-m-d H:i:s'), + 'updatevon' => getAuthUID(), + )); + + if (isError($resultUpdateNotiz)) + return error ('Error occurred update Result ' . $notiz_id); + + $return = ['recycled' => $notiz_id]; + } + else + + { + $resultInsertNotiz = $this->_ci->NotizModel->insert(array( + 'titel' => 'TAG', + 'text' => 'AUTOMATED TAG', + 'verfasser_uid' => getAuthUID(), + 'erledigt' => false, + 'insertamum' => date('Y-m-d H:i:s'), + 'insertvon' => getAuthUID(), + 'typ' => $tag, + 'start' => $von, + 'ende' => $bis + )); + + if (isError($resultInsertNotiz)) + return error ('Error occurred insert Result ' . $prestudent_id); + + $resultInsertZuordnung = $this->_ci->NotizzuordnungModel->insert(array( + 'notiz_id' => $resultInsertNotiz->retval, + self::TYP_ZUORDNUNG => $prestudent_id + )); + + if (isError($resultInsertZuordnung)) + return error ('Error occurred insert Zuordnung' . $prestudent_id); + + $return = ['added' => $resultInsertNotiz->retval]; + } + return success($return); + } + /* * main function for rebuild Tags for single prestudent * */ public function rebuildTagsForPrestudent($prestudent_id) { $automatedTagsRes = $this->_ci->NotiztypModel->loadWhere(array('automatisiert' => true, 'taglib IS NOT NULL' => null)); - //echo $this->NotiztypModel->db->last_query(); $automatedTags = hasData($automatedTagsRes) ? getData($automatedTagsRes) : []; $result = $this->_ci->StudiensemesterModel->getLastOrAktSemester(); if (isError($result)) - return error ('Error occurred during retrieving studiensemester'); + return error('Error occurred during retrieving studiensemester'); if (empty($result->retval) || !isset($result->retval[0])) { return error('No studiensemester found'); } $studiensemester_kurzbz = $result->retval[0]->studiensemester_kurzbz ?? null; - print_r($automatedTags); - $return = []; - foreach($automatedTags as $autoTag) + foreach ($automatedTags as $autoTag) { // getPath: must not be lost $filePath = APPPATH . 'libraries/' . $autoTag->taglib . '.php'; // APPPATH = application/ @@ -338,37 +412,40 @@ class TagLib // className without PATH (basename) $className = basename($autoTag->taglib); + $kurz_bz = $autoTag->typ_kurzbz; $obj = new $className(); $criteriaIsSet = $obj->isCriteriaSetFor([ 'prestudent_id' => $prestudent_id, 'studiensemester_kurzbz' => $studiensemester_kurzbz ]); - //$return = $this->_ci->PrestudentstatusModel->db->last_query(); - $kurz_bz = $autoTag->typ_kurzbz; - // $return[$kurz_bz] = $criteriaIsSet; - - if($criteriaIsSet) + if (hasData($criteriaIsSet)) { - $result = $this->updateAutomatedTagsForPrestudent($kurz_bz, $prestudent_id); + $von = isset($criteriaIsSet->retval[0]->von) ? $criteriaIsSet->retval[0]->von : ''; + $bis = isset($criteriaIsSet->retval[0]->bis) ? $criteriaIsSet->retval[0]->bis : ''; + + $params = [ + 'von' => $von, + 'bis' => $bis, + 'kurzbz' => $autoTag->typ_kurzbz, + 'prestudent_id' => $prestudent_id + ]; + + $result = $this->updateAutomatedTagsForPrestudent($params); if (isError($result)) - return error ('Error occurred during updateAutomatedTags' . $kurz_bz); + return error('Error occurred during updateAutomatedTags' . $kurz_bz); - else - $return[$kurz_bz] = $result; + return $result; } - else { + else + { $result = $this->checkForDelete($kurz_bz, $prestudent_id); - if($result != null) + if ($result != null) $return[$kurz_bz] = $result; } - } - - return success($return); - } public function checkForDelete($tag, $prestudent_id) diff --git a/application/libraries/tags/CoreDoubleDegreeTagLib.php b/application/libraries/tags/CoreDoubleDegreeTagLib.php index 038d29ae1..6de5b053d 100644 --- a/application/libraries/tags/CoreDoubleDegreeTagLib.php +++ b/application/libraries/tags/CoreDoubleDegreeTagLib.php @@ -49,6 +49,7 @@ class CoreDoubleDegreeTagLib public function isCriteriaSetFor(array $params) { + if(!isset($params['prestudent_id']) || !isset($params['studiensemester_kurzbz'])) { return false; @@ -57,18 +58,26 @@ class CoreDoubleDegreeTagLib $semester = $params['studiensemester_kurzbz']; $prestudent_id = $params['prestudent_id']; + $this->ci->MobilitaetModel->addSelect('prestudent_id'); + $this->ci->MobilitaetModel->addSelect('start as von'); + $this->ci->MobilitaetModel->addSelect('ende as bis'); + $this->ci->MobilitaetModel->addJoin('bis.tbl_gsprogramm', 'gsprogramm_id'); + $this->ci->MobilitaetModel->addJoin('public.tbl_studiensemester', 'studiensemester_kurzbz'); + $result = $this->ci->MobilitaetModel->loadWhere(array( 'gsprogrammtyp_kurzbz' => 'Double', 'studiensemester_kurzbz' => $semester, 'prestudent_id' => $prestudent_id )); + if(hasData($result)) { - return true; + //array mit prestudent_id, von und bis + return $result; } else - return false; + return null; } } diff --git a/application/libraries/tags/CoreJgvTagLib.php b/application/libraries/tags/CoreJgvTagLib.php index 028c172a2..7342a38ff 100644 --- a/application/libraries/tags/CoreJgvTagLib.php +++ b/application/libraries/tags/CoreJgvTagLib.php @@ -56,10 +56,10 @@ class CoreJgvTagLib if(hasData($result)) { - return true; + return $result; } else - return false; + return null; } } diff --git a/application/libraries/tags/CoreMissingZgvTagLib.php b/application/libraries/tags/CoreMissingZgvTagLib.php index f108adb78..1ad87ab7a 100644 --- a/application/libraries/tags/CoreMissingZgvTagLib.php +++ b/application/libraries/tags/CoreMissingZgvTagLib.php @@ -73,10 +73,10 @@ class CoreMissingZgvTagLib )); if(hasData($result)) { - return true; + return $result; } else - return false; + return null; } } diff --git a/application/libraries/tags/CoreOutgoingTagLib.php b/application/libraries/tags/CoreOutgoingTagLib.php index 185c3a92b..146513c6d 100644 --- a/application/libraries/tags/CoreOutgoingTagLib.php +++ b/application/libraries/tags/CoreOutgoingTagLib.php @@ -55,67 +55,11 @@ class CoreOutgoingTagLib $result = $this->ci->BisioModel->isPrestudentOutgoing($semester, $prestudent_id); + if (hasData($result)) { - return true; - } else - return false; - } - -/* if(hasData($result)) - { - return array( - $result - ); - - var_dump($result); - die(); - - $row = $result->data->retval[0] ?? null; - return [ - 'prestudent_id' => $row->prestudent_id, //trying to get property of non-object - 'von' => $row->von, //trying to get property of non-object - 'bis' => $row->bis //trying to get property of non-object - ]; - - - return current($result);//-> warum retvall = [] - return getData($result); //-> warum retvall = [] - - $row = $result->data->retval[0] ?? null; - $row = $result->data->retval[0] ?? null; - return [ - 'prestudent_id' => $row->prestudent_id, - 'von' => $row->von, - 'bis' => $row->bis - ]; - } - else - return false;*/ - - //return $result; -/* if(hasData($result)) - { - $data = $result->retval; return $result; - return [ - 'prestudent_id' => $data->prestudent_id, - 'von' => $data->von, - 'bis' => $data->bis - ]; - } - else - return [ - 'prestudent_id' => $prestudent_id, - 'von' => null, - 'bis' => null - ];*/ - -/* return (object) array( - 'data' => $data - );*/ - - // return $data; - - //} + } else + return null; + } } diff --git a/application/libraries/tags/CorePrewiederholerTagLib.php b/application/libraries/tags/CorePrewiederholerTagLib.php index a968fa9a7..f0dee27b3 100644 --- a/application/libraries/tags/CorePrewiederholerTagLib.php +++ b/application/libraries/tags/CorePrewiederholerTagLib.php @@ -55,6 +55,12 @@ class CorePrewiederholerTagLib $semester = $params['studiensemester_kurzbz']; $prestudent_id = $params['prestudent_id']; + $this->ci->PrestudentstatusModel->addSelect('prestudent_id'); + $this->ci->PrestudentstatusModel->addSelect('start as von'); + $this->ci->PrestudentstatusModel->addSelect('ende as bis'); + + $this->ci->PrestudentstatusModel->addJoin('public.tbl_studiensemester', 'studiensemester_kurzbz'); + $result = $this->ci->PrestudentstatusModel->loadWhere(array( 'statusgrund_id' => 15, 'studiensemester_kurzbz' => $semester, @@ -62,10 +68,10 @@ class CorePrewiederholerTagLib )); if(hasData($result)) { - return true; + return $result; } else - return false; + return null; } } diff --git a/application/libraries/tags/CoreStbErhoehtTagLib.php b/application/libraries/tags/CoreStbErhoehtTagLib.php index 2c0b47d2e..76269e998 100644 --- a/application/libraries/tags/CoreStbErhoehtTagLib.php +++ b/application/libraries/tags/CoreStbErhoehtTagLib.php @@ -57,7 +57,12 @@ class CoreStbErhoehtTagLib $semester = $params['studiensemester_kurzbz']; $prestudent_id = $params['prestudent_id']; + $this->ci->KontoModel->addSelect('prestudent_id'); + $this->ci->KontoModel->addSelect('start as von'); + $this->ci->KontoModel->addSelect('ende as bis'); $this->ci->KontoModel->addJoin('public.tbl_prestudent', 'person_id'); + $this->ci->KontoModel->addJoin('public.tbl_studiensemester', 'studiensemester_kurzbz'); + $result = $this->ci->KontoModel-> loadWhere(array( 'buchungstyp_kurzbz' => 'StudiengebuehrErhoeht', 'studiensemester_kurzbz' => $semester, @@ -66,10 +71,10 @@ class CoreStbErhoehtTagLib if(hasData($result)) { - return true; + return $result; } else - return false; + return null; } } diff --git a/application/libraries/tags/CoreUnterbrecherTagLib.php b/application/libraries/tags/CoreUnterbrecherTagLib.php index 160881d48..aa05030e7 100644 --- a/application/libraries/tags/CoreUnterbrecherTagLib.php +++ b/application/libraries/tags/CoreUnterbrecherTagLib.php @@ -55,17 +55,23 @@ class CoreUnterbrecherTagLib $semester = $params['studiensemester_kurzbz']; $prestudent_id = $params['prestudent_id']; + $this->ci->PrestudentstatusModel->addSelect('prestudent_id'); + $this->ci->PrestudentstatusModel->addSelect('start as von'); + $this->ci->PrestudentstatusModel->addSelect('ende as bis'); + + $this->ci->PrestudentstatusModel->addJoin('public.tbl_studiensemester', 'studiensemester_kurzbz'); $result = $this->ci->PrestudentstatusModel-> loadWhere(array( 'status_kurzbz' => 'Unterbrecher', 'studiensemester_kurzbz' => $semester, 'prestudent_id' => $prestudent_id )); + if(hasData($result)) { - return true; + return $result; } else - return false; + return null; } } diff --git a/application/libraries/tags/CoreWiederholerTagLib.php b/application/libraries/tags/CoreWiederholerTagLib.php index c02fca608..6cd78bb36 100644 --- a/application/libraries/tags/CoreWiederholerTagLib.php +++ b/application/libraries/tags/CoreWiederholerTagLib.php @@ -47,6 +47,7 @@ class CoreWiederholerTagLib public function isCriteriaSetFor(array $params) { + if(!isset($params['prestudent_id']) || !isset($params['studiensemester_kurzbz'])) { return false; @@ -55,16 +56,23 @@ class CoreWiederholerTagLib $semester = $params['studiensemester_kurzbz']; $prestudent_id = $params['prestudent_id']; + $this->ci->PrestudentstatusModel->addSelect('prestudent_id'); + $this->ci->PrestudentstatusModel->addSelect('start as von'); + $this->ci->PrestudentstatusModel->addSelect('ende as bis'); + + $this->ci->PrestudentstatusModel->addJoin('public.tbl_studiensemester', 'studiensemester_kurzbz'); + $result = $this->ci->PrestudentstatusModel->loadWhere(array( 'statusgrund_id' => 16, 'studiensemester_kurzbz' => $semester, - 'prestudent_id' => $prestudent_id + 'prestudent_id' => $prestudent_id, )); + if(hasData($result)) { - return true; + return $result; } else - return false; + return null; } } diff --git a/application/models/person/Benutzerfunktion_model.php b/application/models/person/Benutzerfunktion_model.php index 2ce83d181..0d54cd9c7 100644 --- a/application/models/person/Benutzerfunktion_model.php +++ b/application/models/person/Benutzerfunktion_model.php @@ -353,7 +353,7 @@ class Benutzerfunktion_model extends DB_Model public function isJgv($semester, $prestudent_id) { $query = " - SELECT * + SELECT ps.prestudent_id, ss.start as von, ss.ende as bis FROM public.tbl_benutzerfunktion bf JOIN public.tbl_benutzer bn USING (uid) JOIN public.tbl_prestudent ps USING (person_id) diff --git a/public/js/components/Tag/tagFormatter.js b/public/js/components/Tag/tagFormatter.js index e438c4c55..76471ec42 100644 --- a/public/js/components/Tag/tagFormatter.js +++ b/public/js/components/Tag/tagFormatter.js @@ -3,7 +3,6 @@ export function idTagFormatter (id, tagData, tagComponent, typeId) { if (!id) return; - console.log(tagData); const parsedTags = tagData.map(tag => ({ id: tag.notiz_id, From d1fa5f64c4e5b6842cea66de53faffb469dd3822 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Thu, 30 Apr 2026 11:17:39 +0200 Subject: [PATCH 18/28] refactor TagJob, TagLib and single TagLibs for dynamic use of typeId, add temporary testfile application/libraries/tags/CoreFiftyFiveTagLib.php for testing person_id --- application/controllers/jobs/TagJob.php | 5 +- application/core/Tag_Controller.php | 9 +- application/libraries/TagLib.php | 131 +++++------------- .../libraries/tags/CoreDoubleDegreeTagLib.php | 5 +- .../libraries/tags/CoreFiftyFiveTagLib.php | 92 ++++++++++++ application/libraries/tags/CoreJgvTagLib.php | 11 +- .../libraries/tags/CoreMissingZgvTagLib.php | 11 +- .../libraries/tags/CoreOutgoingTagLib.php | 16 +-- .../tags/CorePrewiederholerTagLib.php | 11 +- .../libraries/tags/CoreStbErhoehtTagLib.php | 11 +- .../libraries/tags/CoreUnterbrecherTagLib.php | 11 +- .../libraries/tags/CoreWiederholerTagLib.php | 12 +- application/models/person/Person_model.php | 29 ++++ public/js/api/factory/stv/tag.js | 6 +- .../components/DetailHeader/DetailHeader.js | 8 +- 15 files changed, 211 insertions(+), 157 deletions(-) create mode 100644 application/libraries/tags/CoreFiftyFiveTagLib.php diff --git a/application/controllers/jobs/TagJob.php b/application/controllers/jobs/TagJob.php index 9db55c929..68bc35fe8 100644 --- a/application/controllers/jobs/TagJob.php +++ b/application/controllers/jobs/TagJob.php @@ -56,7 +56,7 @@ class TagJob extends JOB_Controller require_once($filePath); } else { echo "File not found: " . $filePath . PHP_EOL; - continue; + continue; } $kurz_bz = $autoTag->typ_kurzbz; @@ -68,6 +68,8 @@ class TagJob extends JOB_Controller $outputArray = $obj->getZuordnungIds(['studiensemester_kurzbz' => $studiensemester_kurzbz]); $data = $outputArray->data; + print_r($kurz_bz . " " . $autoTag->taglib); + $result = $this->taglib->updateAutomatedTags($kurz_bz, $data); $data = $result->retval; @@ -80,7 +82,6 @@ class TagJob extends JOB_Controller print_r(PHP_EOL . "Count Added: ". $result->retval['summary']['added']); print_r(PHP_EOL . "Count Deleted: ". $result->retval['summary']['deleted']); print_r(PHP_EOL); - } print_r( PHP_EOL . "End Job rebuild" . PHP_EOL); diff --git a/application/core/Tag_Controller.php b/application/core/Tag_Controller.php index 44fd06891..a631639e5 100644 --- a/application/core/Tag_Controller.php +++ b/application/core/Tag_Controller.php @@ -20,7 +20,7 @@ class Tag_Controller extends FHCAPI_Controller 'doneTag' => self::BERECHTIGUNG_KURZBZ, 'deleteTag' => self::BERECHTIGUNG_KURZBZ, 'getAllTags' => self::BERECHTIGUNG_KURZBZ, - 'rebuildTagsPrestudent' => self::BERECHTIGUNG_KURZBZ, + 'rebuildTagsForTypeId' => self::BERECHTIGUNG_KURZBZ, ]; $merged_permissions = array_merge($default_permissions, $permissions); @@ -337,11 +337,12 @@ class Tag_Controller extends FHCAPI_Controller $this->terminateWithSuccess(hasData($notiz) ? getData($notiz) : array()); } - public function rebuildTagsPrestudent() + public function rebuildTagsForTypeId() { - $prestudent_id = $this->input->get('prestudent_id'); + $id = $this->input->get('id'); + $typeId = $this->input->get('typeId'); - $result = $this->taglib->rebuildTagsForPrestudent($prestudent_id); + $result = $this->taglib->rebuildTagsForTypeId($typeId, $id); if (isError($result)) return error ('Error occurred during updateAutomatedTags'); diff --git a/application/libraries/TagLib.php b/application/libraries/TagLib.php index 721215965..d49843ad9 100644 --- a/application/libraries/TagLib.php +++ b/application/libraries/TagLib.php @@ -17,7 +17,6 @@ use \stdClass as stdClass; class TagLib { const BATCHUSER = 'sftest'; - const TYP_ZUORDNUNG = 'prestudent_id'; /** * Object initialization @@ -47,7 +46,8 @@ class TagLib $params array expected pattern [ [ - 'prestudent_id' => 123456, + 'id' => 123456, + 'typeId' => 123456, 'von' => '2026-04-01', 'bis' => '2026-06-30' ], @@ -64,7 +64,8 @@ class TagLib //TODO(Manu) check minimal input: foreach ($inputData as $row) { - $pid = $row['prestudent_id']; + $pid = $row['id']; + $typeId = $row['typeId']; $prestudentIds[] = $pid; @@ -81,7 +82,7 @@ class TagLib $allTags = []; $this->_ci->NotizModel->addSelect('nz.notiz_id'); - $this->_ci->NotizModel->addSelect('prestudent_id'); + $this->_ci->NotizModel->addSelect($typeId); $this->_ci->NotizModel->addJoin('public.tbl_notizzuordnung nz', 'notiz_id'); $resultAllTags = $this->_ci->NotizModel->loadWhere([ @@ -92,7 +93,7 @@ class TagLib if (!empty($allTagsData)) { foreach ($allTagsData as $row) { - $allTags[$row->prestudent_id] = $row->notiz_id; + $allTags[$row->$typeId] = $row->notiz_id; } } @@ -171,7 +172,7 @@ class TagLib $resultZuordnung = $this->_ci->NotizzuordnungModel->insert([ 'notiz_id' => $notizId, - self::TYP_ZUORDNUNG => $pid + $typeId => $pid ]); if (isError($resultZuordnung)) { @@ -237,79 +238,7 @@ class TagLib ]); } - public function updateAutomatedTagsForPrestudent_DEPR($tag, $prestudent_id) - { - $_ci = get_instance(); - $_ci->addMeta( - 'IN OLD FUNCTION updateTags', $tag - ); - $return = null; - $notiz_id = null; - - //von und bis auslesen - - - $this->_ci->NotizModel->addSelect('nz.notiz_id'); - $this->_ci->NotizModel->addSelect('prestudent_id'); - $this->_ci->NotizModel->addJoin('public.tbl_notizzuordnung nz', 'notiz_id'); - $resultAllTags = $this->_ci->NotizModel->loadWhere([ - 'typ' => $tag, - 'prestudent_id' => $prestudent_id - ]); - if(hasData($resultAllTags)) - { - $notiz_id = $resultAllTags->retval[0]->notiz_id; - } - - //RECYCLE - if ($notiz_id !== null) - { - //TODO(Manu) refactor for recycle, add - $resultUpdateNotiz = $this->_ci->NotizModel->update( - [ - 'notiz_id' => $notiz_id - ], - array( - 'updateamum' => date('Y-m-d H:i:s'), - 'updatevon' => getAuthUID(), - )); - - if (isError($resultUpdateNotiz)) - return error ('Error occurred update Result ' . $notiz_id); - - $return = ['recycled' => $notiz_id]; - } - else - - { - //TODO(Manu) refactor for recycle, add - $resultInsertNotiz = $this->_ci->NotizModel->insert(array( - 'titel' => 'TAG', - 'text' => 'AUTOMATED TAG', - 'verfasser_uid' => getAuthUID(), - 'erledigt' => false, - 'insertamum' => date('Y-m-d H:i:s'), - 'insertvon' => getAuthUID(), - 'typ' => $tag - )); - - if (isError($resultInsertNotiz)) - return error ('Error occurred insert Result ' . $prestudent_id); - - $resultInsertZuordnung = $this->_ci->NotizzuordnungModel->insert(array( - 'notiz_id' => $resultInsertNotiz->retval, - self::TYP_ZUORDNUNG => $prestudent_id - )); - - if (isError($resultInsertZuordnung)) - return error ('Error occurred insert Zuordnung' . $prestudent_id); - - $return = ['added' => $resultInsertNotiz->retval]; - } - return success($return); - } - - public function updateAutomatedTagsForPrestudent(array $params) + public function updateAutomatedTagsForTypeId(array $params) { $return = null; $notiz_id = null; @@ -317,14 +246,15 @@ class TagLib $von = $params['von']; $bis = $params['bis']; $tag = $params['kurzbz']; - $prestudent_id = $params['prestudent_id']; + $id = $params['id']; + $typeId = $params['typeId']; $this->_ci->NotizModel->addSelect('nz.notiz_id'); - $this->_ci->NotizModel->addSelect('prestudent_id'); + $this->_ci->NotizModel->addSelect($typeId); $this->_ci->NotizModel->addJoin('public.tbl_notizzuordnung nz', 'notiz_id'); $resultAllTags = $this->_ci->NotizModel->loadWhere([ 'typ' => $tag, - 'prestudent_id' => $prestudent_id + $typeId => $id ]); if(hasData($resultAllTags)) { @@ -334,7 +264,6 @@ class TagLib //RECYCLE if ($notiz_id !== null) { - //TODO(Manu) refactor for recycle, add $resultUpdateNotiz = $this->_ci->NotizModel->update( [ 'notiz_id' => $notiz_id @@ -369,25 +298,26 @@ class TagLib $resultInsertZuordnung = $this->_ci->NotizzuordnungModel->insert(array( 'notiz_id' => $resultInsertNotiz->retval, - self::TYP_ZUORDNUNG => $prestudent_id + $typeId => $id )); if (isError($resultInsertZuordnung)) - return error ('Error occurred insert Zuordnung' . $prestudent_id); - + return error ('Error occurred insert Zuordnung ' . $id); $return = ['added' => $resultInsertNotiz->retval]; } return success($return); } /* - * main function for rebuild Tags for single prestudent + * main function for rebuild Tags for typeId * */ - public function rebuildTagsForPrestudent($prestudent_id) + public function rebuildTagsForTypeId($typeId, $id) { $automatedTagsRes = $this->_ci->NotiztypModel->loadWhere(array('automatisiert' => true, 'taglib IS NOT NULL' => null)); $automatedTags = hasData($automatedTagsRes) ? getData($automatedTagsRes) : []; + $_ci = get_instance(); + $result = $this->_ci->StudiensemesterModel->getLastOrAktSemester(); if (isError($result)) return error('Error occurred during retrieving studiensemester'); @@ -395,7 +325,6 @@ class TagLib return error('No studiensemester found'); } $studiensemester_kurzbz = $result->retval[0]->studiensemester_kurzbz ?? null; - $return = []; foreach ($automatedTags as $autoTag) @@ -415,8 +344,10 @@ class TagLib $kurz_bz = $autoTag->typ_kurzbz; $obj = new $className(); + $criteriaIsSet = $obj->isCriteriaSetFor([ - 'prestudent_id' => $prestudent_id, + 'typeId' => $typeId, + 'id' => $id, 'studiensemester_kurzbz' => $studiensemester_kurzbz ]); @@ -429,10 +360,11 @@ class TagLib 'von' => $von, 'bis' => $bis, 'kurzbz' => $autoTag->typ_kurzbz, - 'prestudent_id' => $prestudent_id + 'typeId' => $typeId, + 'id' => $id, ]; - $result = $this->updateAutomatedTagsForPrestudent($params); + $result = $this->updateAutomatedTagsForTypeId($params); if (isError($result)) return error('Error occurred during updateAutomatedTags' . $kurz_bz); @@ -440,7 +372,8 @@ class TagLib } else { - $result = $this->checkForDelete($kurz_bz, $prestudent_id); + $result = $this->checkForDelete($kurz_bz, $typeId, $id); + if ($result != null) $return[$kurz_bz] = $result; } @@ -448,25 +381,27 @@ class TagLib return success($return); } - public function checkForDelete($tag, $prestudent_id) + public function checkForDelete($tag, $typeId, $id) { $return = null; $notiz_id = null; - if (!is_numeric($prestudent_id)) - return error ("prestudent_id " . $prestudent_id . "not numeric"); + if (!is_numeric($id)) + return error ("id " . $id . "not numeric"); $this->_ci->NotizModel->addSelect('nz.notiz_id'); - $this->_ci->NotizModel->addSelect('prestudent_id'); + $this->_ci->NotizModel->addSelect($typeId); $this->_ci->NotizModel->addJoin('public.tbl_notizzuordnung nz', 'notiz_id'); $resultAllTags = $this->_ci->NotizModel->loadWhere([ 'typ' => $tag, - 'prestudent_id' => $prestudent_id + $typeId => $id ]); if(hasData($resultAllTags)) { $notiz_id = $resultAllTags->retval[0]->notiz_id; } + else + return null; if($notiz_id) { diff --git a/application/libraries/tags/CoreDoubleDegreeTagLib.php b/application/libraries/tags/CoreDoubleDegreeTagLib.php index 6de5b053d..264891c3d 100644 --- a/application/libraries/tags/CoreDoubleDegreeTagLib.php +++ b/application/libraries/tags/CoreDoubleDegreeTagLib.php @@ -19,7 +19,7 @@ class CoreDoubleDegreeTagLib if(!isset($params['studiensemester_kurzbz'])) { return (object) array( - 'prestudent_id' => [] + 'idArray' => [] ); } @@ -36,7 +36,8 @@ class CoreDoubleDegreeTagLib $doubledegree_data = array_map(function($item) { return [ - 'prestudent_id' => $item->prestudent_id, + 'typeId' => 'prestudent_id', + 'id' => $item->prestudent_id, 'von' => $item->start, 'bis' => $item->ende ]; diff --git a/application/libraries/tags/CoreFiftyFiveTagLib.php b/application/libraries/tags/CoreFiftyFiveTagLib.php new file mode 100644 index 000000000..5d4990e5d --- /dev/null +++ b/application/libraries/tags/CoreFiftyFiveTagLib.php @@ -0,0 +1,92 @@ +ci = get_instance(); + $this->ci->load->model('person/Person_model', 'PersonModel'); + $this->ci-> load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + } + + public function getZuordnungIds(array $params) + { + if(!isset($params['studiensemester_kurzbz'])) + { + return (object) array( + 'person_id' => [] + ); + } + + $semester = $params['studiensemester_kurzbz']; + + $result = $this->ci->StudiensemesterModel->loadWhere(array( + 'studiensemester_kurzbz' => $semester + )); + $data = $result->retval[0]; + + $semVon = $data->start; + $semBis = $data->ende; + $result = $this->ci->PersonModel->getFiftyFivers($semVon, $semBis); + + $data = $result->retval; + $fiftyFiveData = array_map(function($item) { + return [ + 'id' => $item->person_id, + 'typeId' => 'person_id', + ]; + }, $data); + + return (object) array( + 'data' => $fiftyFiveData + ); + } + + public function isCriteriaSetFor(array $params) + { + if(!isset($params['person_id']) || !isset($params['studiensemester_kurzbz'])) + { + return false; + } + $semester = $params['studiensemester_kurzbz']; + $person_id = $params['id']; + $typeId = $params['typeId']; + + if($typeId != 'person_id') + return null; + + $result = $this->ci->StudiensemesterModel->loadWhere(array( + 'studiensemester_kurzbz' => $semester + )); + $data = $result->retval[0]; + + $semVon = $data->start; + $semBis = $data->ende; + $result = $this->ci->PersonModel->isFiftyFive($semVon, $semBis, $person_id); + + $data = $result->retval; + $fiftyFiveData = array_map(function($item) { + return [ + 'id' => $item->person_id, + 'typeId' => 'person_id', + ]; + }, $data); + + if(hasData($result)) + { + //array mit prestudent_id, von und bis + return $result; + } + else + return null; + } + +} + diff --git a/application/libraries/tags/CoreJgvTagLib.php b/application/libraries/tags/CoreJgvTagLib.php index 7342a38ff..479da7da0 100644 --- a/application/libraries/tags/CoreJgvTagLib.php +++ b/application/libraries/tags/CoreJgvTagLib.php @@ -19,7 +19,7 @@ class CoreJgvTagLib if(!isset($params['studiensemester_kurzbz'])) { return (object) array( - 'prestudent_id' => [] + 'idArray' => [] ); } @@ -31,7 +31,8 @@ class CoreJgvTagLib $jgv_data = array_map(function($item) { return [ - 'prestudent_id' => $item->prestudent_id, + 'typeId' => 'prestudent_id', + 'id' => $item->prestudent_id, 'von' => $item->datum_von, 'bis' => $item->datum_bis ]; @@ -44,13 +45,11 @@ class CoreJgvTagLib public function isCriteriaSetFor(array $params) { - if(!isset($params['prestudent_id']) || !isset($params['studiensemester_kurzbz'])) - { + if ( !isset($params['id'], $params['studiensemester_kurzbz'], $params['typeId']) || $params['typeId'] !== 'prestudent_id') return false; - } $semester = $params['studiensemester_kurzbz']; - $prestudent_id = $params['prestudent_id']; + $prestudent_id = $params['id']; $result = $this->ci->BenutzerfunktionModel->isJgv($semester, $prestudent_id); diff --git a/application/libraries/tags/CoreMissingZgvTagLib.php b/application/libraries/tags/CoreMissingZgvTagLib.php index 1ad87ab7a..73fa9021f 100644 --- a/application/libraries/tags/CoreMissingZgvTagLib.php +++ b/application/libraries/tags/CoreMissingZgvTagLib.php @@ -19,7 +19,7 @@ class CoreMissingZgvTagLib if(!isset($params['studiensemester_kurzbz'])) { return (object) array( - 'prestudent_id' => [] + 'idArray' => [] ); } @@ -39,7 +39,8 @@ class CoreMissingZgvTagLib $zgvmissing_data = array_map(function($item) { return [ - 'prestudent_id' => $item->prestudent_id, + 'typeId' => 'prestudent_id', + 'id' => $item->prestudent_id, 'von' => null, 'bis' => null ]; @@ -53,13 +54,11 @@ class CoreMissingZgvTagLib public function isCriteriaSetFor(array $params) { - if(!isset($params['prestudent_id']) || !isset($params['studiensemester_kurzbz'])) - { + if ( !isset($params['id'], $params['studiensemester_kurzbz'], $params['typeId']) || $params['typeId'] !== 'prestudent_id') return false; - } $semester = $params['studiensemester_kurzbz']; - $prestudent_id = $params['prestudent_id']; + $prestudent_id = $params['id']; $this->ci->PrestudentModel->addJoin('public.tbl_prestudentstatus', 'prestudent_id'); $this->ci->PrestudentModel->addJoin('public.tbl_benutzer bn', 'person_id'); diff --git a/application/libraries/tags/CoreOutgoingTagLib.php b/application/libraries/tags/CoreOutgoingTagLib.php index 146513c6d..e076d0adf 100644 --- a/application/libraries/tags/CoreOutgoingTagLib.php +++ b/application/libraries/tags/CoreOutgoingTagLib.php @@ -19,7 +19,7 @@ class CoreOutgoingTagLib if(!isset($params['studiensemester_kurzbz'])) { return (object) array( - 'prestudent_id' => [] + 'idArray' => [] ); } @@ -31,7 +31,8 @@ class CoreOutgoingTagLib $outgoing_data = array_map(function($item) { return [ - 'prestudent_id' => $item->prestudent_id, + 'typeId' => 'prestudent_id', + 'id' => $item->prestudent_id, 'von' => $item->von, 'bis' => $item->bis ]; @@ -40,25 +41,22 @@ class CoreOutgoingTagLib return (object) array( 'data' => $outgoing_data ); - - } public function isCriteriaSetFor(array $params) { - if (!isset($params['prestudent_id']) || !isset($params['studiensemester_kurzbz'])) { + if ( !isset($params['id'], $params['studiensemester_kurzbz'], $params['typeId']) || $params['typeId'] !== 'prestudent_id') return false; - } $semester = $params['studiensemester_kurzbz']; - $prestudent_id = $params['prestudent_id']; + $prestudent_id = $params['id']; $result = $this->ci->BisioModel->isPrestudentOutgoing($semester, $prestudent_id); - if (hasData($result)) { return $result; - } else + } + else return null; } diff --git a/application/libraries/tags/CorePrewiederholerTagLib.php b/application/libraries/tags/CorePrewiederholerTagLib.php index f0dee27b3..cb2f0a77a 100644 --- a/application/libraries/tags/CorePrewiederholerTagLib.php +++ b/application/libraries/tags/CorePrewiederholerTagLib.php @@ -19,7 +19,7 @@ class CorePrewiederholerTagLib if(!isset($params['studiensemester_kurzbz'])) { return (object) array( - 'prestudent_id' => [] + 'idArray' => [] ); } @@ -34,7 +34,8 @@ class CorePrewiederholerTagLib $prewiederholer_data = array_map(function($item) { return [ - 'prestudent_id' => $item->prestudent_id, + 'typeId' => 'prestudent_id', + 'id' => $item->prestudent_id, 'von' => $item->start, 'bis' => $item->ende ]; @@ -47,13 +48,11 @@ class CorePrewiederholerTagLib public function isCriteriaSetFor(array $params) { - if(!isset($params['prestudent_id']) || !isset($params['studiensemester_kurzbz'])) - { + if ( !isset($params['id'], $params['studiensemester_kurzbz'], $params['typeId']) || $params['typeId'] !== 'prestudent_id') return false; - } $semester = $params['studiensemester_kurzbz']; - $prestudent_id = $params['prestudent_id']; + $prestudent_id = $params['id']; $this->ci->PrestudentstatusModel->addSelect('prestudent_id'); $this->ci->PrestudentstatusModel->addSelect('start as von'); diff --git a/application/libraries/tags/CoreStbErhoehtTagLib.php b/application/libraries/tags/CoreStbErhoehtTagLib.php index 76269e998..5795f8348 100644 --- a/application/libraries/tags/CoreStbErhoehtTagLib.php +++ b/application/libraries/tags/CoreStbErhoehtTagLib.php @@ -19,7 +19,7 @@ class CoreStbErhoehtTagLib if(!isset($params['studiensemester_kurzbz'])) { return (object) array( - 'prestudent_id' => [] + 'idArray' => [] ); } @@ -36,7 +36,8 @@ class CoreStbErhoehtTagLib $konto_data = array_map(function($item) { return [ - 'prestudent_id' => $item->prestudent_id, + 'typeId' => 'prestudent_id', + 'id' => $item->prestudent_id, 'von' => $item->start, 'bis' => $item->ende ]; @@ -49,13 +50,11 @@ class CoreStbErhoehtTagLib public function isCriteriaSetFor(array $params) { - if(!isset($params['prestudent_id']) || !isset($params['studiensemester_kurzbz'])) - { + if ( !isset($params['id'], $params['studiensemester_kurzbz'], $params['typeId']) || $params['typeId'] !== 'prestudent_id') return false; - } $semester = $params['studiensemester_kurzbz']; - $prestudent_id = $params['prestudent_id']; + $prestudent_id = $params['id']; $this->ci->KontoModel->addSelect('prestudent_id'); $this->ci->KontoModel->addSelect('start as von'); diff --git a/application/libraries/tags/CoreUnterbrecherTagLib.php b/application/libraries/tags/CoreUnterbrecherTagLib.php index aa05030e7..c205c746c 100644 --- a/application/libraries/tags/CoreUnterbrecherTagLib.php +++ b/application/libraries/tags/CoreUnterbrecherTagLib.php @@ -19,7 +19,7 @@ class CoreUnterbrecherTagLib if(!isset($params['studiensemester_kurzbz'])) { return (object) array( - 'prestudent_id' => [] + 'idArray' => [] ); } @@ -34,7 +34,8 @@ class CoreUnterbrecherTagLib $unterbrecher_data = array_map(function($item) { return [ - 'prestudent_id' => $item->prestudent_id, + 'typeId' => 'prestudent_id', + 'id' => $item->prestudent_id, 'von' => $item->start, 'bis' => $item->ende ]; @@ -47,13 +48,11 @@ class CoreUnterbrecherTagLib public function isCriteriaSetFor(array $params) { - if(!isset($params['prestudent_id']) || !isset($params['studiensemester_kurzbz'])) - { + if ( !isset($params['id'], $params['studiensemester_kurzbz'], $params['typeId']) || $params['typeId'] !== 'prestudent_id') return false; - } $semester = $params['studiensemester_kurzbz']; - $prestudent_id = $params['prestudent_id']; + $prestudent_id = $params['id']; $this->ci->PrestudentstatusModel->addSelect('prestudent_id'); $this->ci->PrestudentstatusModel->addSelect('start as von'); diff --git a/application/libraries/tags/CoreWiederholerTagLib.php b/application/libraries/tags/CoreWiederholerTagLib.php index 6cd78bb36..3d75e562e 100644 --- a/application/libraries/tags/CoreWiederholerTagLib.php +++ b/application/libraries/tags/CoreWiederholerTagLib.php @@ -19,7 +19,7 @@ class CoreWiederholerTagLib if(!isset($params['studiensemester_kurzbz'])) { return (object) array( - 'prestudent_id' => [] + 'idArray' => [] ); } @@ -34,7 +34,8 @@ class CoreWiederholerTagLib $wiederholer_data = array_map(function($item) { return [ - 'prestudent_id' => $item->prestudent_id, + 'typeId' => 'prestudent_id', + 'id' => $item->prestudent_id, 'von' => $item->start, 'bis' => $item->ende ]; @@ -47,14 +48,11 @@ class CoreWiederholerTagLib public function isCriteriaSetFor(array $params) { - - if(!isset($params['prestudent_id']) || !isset($params['studiensemester_kurzbz'])) - { + if ( !isset($params['id'], $params['studiensemester_kurzbz'], $params['typeId']) || $params['typeId'] !== 'prestudent_id') return false; - } $semester = $params['studiensemester_kurzbz']; - $prestudent_id = $params['prestudent_id']; + $prestudent_id = $params['id']; $this->ci->PrestudentstatusModel->addSelect('prestudent_id'); $this->ci->PrestudentstatusModel->addSelect('start as von'); diff --git a/application/models/person/Person_model.php b/application/models/person/Person_model.php index e72b24de4..13196b38f 100644 --- a/application/models/person/Person_model.php +++ b/application/models/person/Person_model.php @@ -433,4 +433,33 @@ class Person_model extends DB_Model return $this->execReadOnlyQuery($qry, [$person_id]); } + + //just a test function for a person_id tag + //alle personen die innerhalb dieses Zeitraumens 55 werden + public function getFiftyFivers($von, $bis) + { + $qry = " + SELECT + p.person_id + FROM public.tbl_person p + WHERE p.gebdatum >= DATE ? - INTERVAL '55 years' + AND p.gebdatum <= DATE ? - INTERVAL '55 years'; + "; + return $this->execReadOnlyQuery($qry, [$von, $bis]); + } + + //just a test function for a person_id tag + //check if Person gets 55 in this time + public function isFiftyFive($von, $bis, $person_id) + { + $qry = " + SELECT + p.person_id + FROM public.tbl_person p + WHERE p.gebdatum >= DATE ? - INTERVAL '55 years' + AND p.gebdatum <= DATE ? - INTERVAL '55 years' + AND p.persond_id = ?; + "; + return $this->execReadOnlyQuery($qry, [$von, $bis, $person_id]); + } } diff --git a/public/js/api/factory/stv/tag.js b/public/js/api/factory/stv/tag.js index d78e7f685..b0c416e2d 100644 --- a/public/js/api/factory/stv/tag.js +++ b/public/js/api/factory/stv/tag.js @@ -61,11 +61,11 @@ export default { }; }, - rebuildTagsPrestudent(prestudent_id){ + rebuildTagsforTypeId(data){ return { method: 'get', - url: 'api/frontend/v1/stv/Tags/rebuildTagsPrestudent', - params: prestudent_id + url: 'api/frontend/v1/stv/Tags/rebuildTagsForTypeId/', + params: data }; } }; \ No newline at end of file diff --git a/public/js/components/DetailHeader/DetailHeader.js b/public/js/components/DetailHeader/DetailHeader.js index 7cbc52c37..516ecdd87 100644 --- a/public/js/components/DetailHeader/DetailHeader.js +++ b/public/js/components/DetailHeader/DetailHeader.js @@ -246,9 +246,13 @@ export default { this.reload(); }, rebuildPrestudentTags(){ - const prestudent_id = this.headerData[0].prestudent_id; + const params = { + id : this.headerData[0].prestudent_id, + typeId: 'prestudent_id' + }; + return this.$api - .call(ApiTag.rebuildTagsPrestudent({prestudent_id})) + .call(ApiTag.rebuildTagsforTypeId(params)) .then(result => { this.rebuildData = result.data; console.log("Rebuild manually triggered"); From ef1347c7d59236738adc2bf79a7705a1c2391837 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Tue, 5 May 2026 15:20:02 +0200 Subject: [PATCH 19/28] - use function getAktOrNextSemester - restructure single libs to isolate typeId of data - refactor Job: use params, details output - use functions insert, update, delete - use timeperiode for getAllTags and checkIfExistingTag - controller: rebuild function: change to POST - updated insertVon Batchuser --- application/controllers/jobs/TagJob.php | 69 +++- application/core/Tag_Controller.php | 6 +- application/libraries/TagLib.php | 369 +++++++++--------- .../libraries/tags/CoreDoubleDegreeTagLib.php | 4 +- .../libraries/tags/CoreFiftyFiveTagLib.php | 21 +- application/libraries/tags/CoreJgvTagLib.php | 4 +- .../libraries/tags/CoreMissingZgvTagLib.php | 2 +- .../libraries/tags/CoreOutgoingTagLib.php | 4 +- .../tags/CorePrewiederholerTagLib.php | 4 +- .../libraries/tags/CoreStbErhoehtTagLib.php | 4 +- .../libraries/tags/CoreUnterbrecherTagLib.php | 4 +- .../libraries/tags/CoreWiederholerTagLib.php | 2 +- application/models/person/Notiz_model.php | 55 +++ public/js/api/factory/stv/tag.js | 2 +- 14 files changed, 329 insertions(+), 221 deletions(-) diff --git a/application/controllers/jobs/TagJob.php b/application/controllers/jobs/TagJob.php index 68bc35fe8..65e4b052e 100644 --- a/application/controllers/jobs/TagJob.php +++ b/application/controllers/jobs/TagJob.php @@ -39,13 +39,16 @@ class TagJob extends JOB_Controller $automatedTagsRes = $this->NotiztypModel->loadWhere(array('automatisiert' => true, 'taglib IS NOT NULL' => null)); $automatedTags = hasData($automatedTagsRes) ? getData($automatedTagsRes) : []; - $result = $this->StudiensemesterModel->getLastOrAktSemester(); + $result = $this->StudiensemesterModel->getAktOrNextSemester(); if (isError($result)) return error ('Error occurred during retrieving studiensemester'); if (empty($result->retval) || !isset($result->retval[0])) { return error('No studiensemester found'); } $studiensemester_kurzbz = $result->retval[0]->studiensemester_kurzbz ?? null; + $params = array( + 'studiensemester_kurzbz' => $studiensemester_kurzbz + ); foreach($automatedTags as $autoTag) { @@ -56,7 +59,7 @@ class TagJob extends JOB_Controller require_once($filePath); } else { echo "File not found: " . $filePath . PHP_EOL; - continue; + continue; } $kurz_bz = $autoTag->typ_kurzbz; @@ -65,25 +68,69 @@ class TagJob extends JOB_Controller $obj = new $className(); - $outputArray = $obj->getZuordnungIds(['studiensemester_kurzbz' => $studiensemester_kurzbz]); - $data = $outputArray->data; + $outputArray = $obj->getZuordnungIds($params); + $typeId = $outputArray->typeId; - print_r($kurz_bz . " " . $autoTag->taglib); + $paramsTag = array( + 'studiensemester_kurzbz' => $studiensemester_kurzbz, + 'kurzbz' => $kurz_bz, + 'data' => $outputArray->data, + 'typeId' => $typeId + ); - $result = $this->taglib->updateAutomatedTags($kurz_bz, $data); + $result = $this->taglib->updateAutomatedTags($paramsTag); - $data = $result->retval; - if (isError($result)) - return error ('Error occurred during updateAutomatedTags'); + if (isError($result)) { + return error('Error occurred during updateAutomatedTags'); + } + + $data = is_array($result) ? $result['retval'] : $result->retval; + + //PRINT OUTPUT CONSOLE + //SUMMARY + print_r(PHP_EOL . "-- TAG " . $result->retval['input']['tag'] . " | TYPE_ID " . $typeId . " --"); - //Output with Summary and Details - print_r(PHP_EOL . "-- TAG " . $result->retval['input']['tag'] . " --"); print_r( PHP_EOL . "Count Recycled: " . $result->retval['summary']['recycled']); print_r(PHP_EOL . "Count Added: ". $result->retval['summary']['added']); print_r(PHP_EOL . "Count Deleted: ". $result->retval['summary']['deleted']); + + //DETAILS + //print_r(PHP_EOL . "New tag(s) [". $typeId . "]: " . implode(', ', $result->retval['results']['newTags'])); + //print_r(PHP_EOL . "Deleted tags(s) [". $typeId . "]: " . implode(', ', $result->retval['results']['deletedTagsIds'])); + //print_r(PHP_EOL . "Recycled tag(s) [". $typeId . "]: " . implode(', ', $result->retval['results']['retaggedIds'])); print_r(PHP_EOL); } print_r( PHP_EOL . "End Job rebuild" . PHP_EOL); } + + public function deleteAllAutomatedTags() + { + print_r( PHP_EOL . "Start Job delete ALL Automated Tags" . PHP_EOL); + + $resultToDelete = $this->NotizModel->loadWhere(array('insertvon' => 'BatchJobTagAdd')); + + $data = $resultToDelete->retval; + $notiz_ids = array_map(function($item) { + return $item->notiz_id; + }, $data); + + print_r($notiz_ids); + + foreach ($notiz_ids as $notiz_id) + { + $result = $this->NotizzuordnungModel->delete([ + 'notiz_id' => $notiz_id + ]); + if (isError($result)) + return error ('Error occurred delete Notizzuordnung' . $notiz_id); + + $result = $this->NotizModel->delete([ + 'notiz_id' => $notiz_id + ]); + if (isError($result)) + return error ('Error occurred delete Notiz' . $notiz_id); + } + print_r( PHP_EOL . "End Job delete Automated Tags" . PHP_EOL); + } } diff --git a/application/core/Tag_Controller.php b/application/core/Tag_Controller.php index a631639e5..082cb9ac4 100644 --- a/application/core/Tag_Controller.php +++ b/application/core/Tag_Controller.php @@ -339,10 +339,12 @@ class Tag_Controller extends FHCAPI_Controller public function rebuildTagsForTypeId() { - $id = $this->input->get('id'); - $typeId = $this->input->get('typeId'); + $id = $this->input->post('id'); + $typeId = $this->input->post('typeId'); $result = $this->taglib->rebuildTagsForTypeId($typeId, $id); + //TODO (refactor; um semester, studiengang_kz) + //$result = $this->taglib->rebuildTagsForTypeId($params); if (isError($result)) return error ('Error occurred during updateAutomatedTags'); diff --git a/application/libraries/TagLib.php b/application/libraries/TagLib.php index d49843ad9..2442b2fab 100644 --- a/application/libraries/TagLib.php +++ b/application/libraries/TagLib.php @@ -40,60 +40,63 @@ class TagLib $this->_ci->load->library('PrestudentLib'); } - public function updateAutomatedTags($tag, $inputData) + public function updateAutomatedTags($paramsTag) { - /* - $params array expected pattern - [ - [ - 'id' => 123456, - 'typeId' => 123456, - 'von' => '2026-04-01', - 'bis' => '2026-06-30' - ], - ... - ] - */ + // --------------------------------- + // check params + // --------------------------------- + $required = ['kurzbz', 'data', 'typeId']; + + foreach ($required as $key) { + if (!isset($paramsTag[$key])) { + return error('Missing Parameter: ' . $key); + } + } + + $studiensemester_kurzbz = (isset ($paramsTag['studiensemester_kurzbz']) ? $paramsTag['studiensemester_kurzbz'] : null); + $tag = $paramsTag['kurzbz']; + $inputData = $paramsTag['data']; + $typeId = $paramsTag['typeId']; // --------------------------------- // prepare input // --------------------------------- $zeitraum = []; - $prestudentIds = []; + $arrayIds = []; - //TODO(Manu) check minimal input: + foreach ($inputData as $item) { + $id = $item['id']; + $arrayIds[] = $id; - foreach ($inputData as $row) { - $pid = $row['id']; - $typeId = $row['typeId']; - - $prestudentIds[] = $pid; - - $zeitraum[$pid] = [ - 'von' => $row['von'] ?? null, - 'bis' => $row['bis'] ?? null + $zeitraum[$id] = [ + 'von' => $item['von'] ?? null, + 'bis' => $item['bis'] ?? null ]; } - $prestudentIds = array_unique($prestudentIds); + $arrayIds = array_unique($arrayIds); + + $result = $this->_ci->StudiensemesterModel->load($studiensemester_kurzbz); + if (isError($result)) { + return $result; + } + $data = $result->retval[0] ?? null; + + $von = $data->start ?? null; + $bis = $data->ende ?? null; // --------------------------------- // load existing tags // --------------------------------- $allTags = []; - - $this->_ci->NotizModel->addSelect('nz.notiz_id'); - $this->_ci->NotizModel->addSelect($typeId); - $this->_ci->NotizModel->addJoin('public.tbl_notizzuordnung nz', 'notiz_id'); - - $resultAllTags = $this->_ci->NotizModel->loadWhere([ - 'typ' => $tag - ]); - + $resultAllTags = $this->_ci->NotizModel->getAllTags($tag, $von, $bis); + if (isError($resultAllTags)) { + return $resultAllTags; + } $allTagsData = getData($resultAllTags); if (!empty($allTagsData)) { - foreach ($allTagsData as $row) { - $allTags[$row->$typeId] = $row->notiz_id; + foreach ($allTagsData as $item) { + $allTags[$item->$typeId] = $item->notiz_id; } } @@ -104,17 +107,18 @@ class TagLib $toAdd = []; $toDelete = []; - foreach ($prestudentIds as $pid) { - if (isset($allTags[$pid])) { - $toRecycle[$pid] = $allTags[$pid]; + foreach ($arrayIds as $id) { + if (isset($allTags[$id])) { + $toRecycle[$id] = $allTags[$id]; } else { - $toAdd[] = $pid; + $toAdd[] = $id; } } - foreach ($allTags as $pid => $notizId) { - if (!in_array($pid, $prestudentIds)) { - $toDelete[$pid] = $notizId; + foreach ($allTags as $id => $notizId) { + if (!in_array($id, $arrayIds)) { + $toDelete[$id] = $notizId; + } } @@ -124,24 +128,13 @@ class TagLib $countRecycled = 0; $retagged = []; - foreach ($toRecycle as $pid => $notizId) { - - $result = $this->_ci->NotizModel->update( - ['notiz_id' => $notizId], - [ - 'updateamum' => date('Y-m-d H:i:s'), - 'updatevon' => 'BatchJobTagUpdate', - 'start' => $zeitraum[$pid]['von'], - 'ende' => $zeitraum[$pid]['bis'] - ] - ); - - if (isError($result)) { - return error('Error updating tag ' . $notizId); - } + foreach ($toRecycle as $id => $notizId) + { + $this->_updateTag($notizId, $zeitraum[$id]['von'], $zeitraum[$id]['bis']); $countRecycled++; - $retagged[] = $notizId; + $retagged[] = $id; + //$retagged[] = $notizId; //notiz_id } // --------------------------------- @@ -150,37 +143,15 @@ class TagLib $countAdded = 0; $tagged = []; - foreach ($toAdd as $pid) { - - $resultInsert = $this->_ci->NotizModel->insert([ - 'titel' => 'TAG', - 'text' => 'AUTOMATED TAG', - 'verfasser_uid' => self::BATCHUSER, - 'erledigt' => false, - 'insertamum' => date('Y-m-d H:i:s'), - 'insertvon' => 'BatchJobTagAdd', - 'typ' => $tag, - 'start' => $zeitraum[$pid]['von'], - 'ende' => $zeitraum[$pid]['bis'] - ]); - - if (isError($resultInsert)) { - return error('Error inserting tag for prestudent ' . $pid); + foreach ($toAdd as $id) + { + $result = $this->_insertTag($typeId, $id, $tag, $zeitraum[$id]['von'], $zeitraum[$id]['bis']); + if (isError($result)) { + return $result; } - - $notizId = $resultInsert->retval; - - $resultZuordnung = $this->_ci->NotizzuordnungModel->insert([ - 'notiz_id' => $notizId, - $typeId => $pid - ]); - - if (isError($resultZuordnung)) { - return error('Error inserting relation for prestudent ' . $pid); - } - $countAdded++; - $tagged[$notizId] = $pid; + //$tagged[] = $result->retval[0]->notiz_id; //notiz_id + $tagged[] = $id; } // --------------------------------- @@ -189,26 +160,17 @@ class TagLib $countDeleted = 0; $deleted = []; - foreach ($toDelete as $pid => $notizId) { - - $result = $this->_ci->NotizzuordnungModel->delete([ - 'notiz_id' => $notizId - ]); + foreach ($toDelete as $id => $notizId) + { + $result = $this->_deleteTag($notizId); if (isError($result)) { - return error('Error deleting relation ' . $notizId); - } - - $result = $this->_ci->NotizModel->delete([ - 'notiz_id' => $notizId - ]); - - if (isError($result)) { - return error('Error deleting note ' . $notizId); + return $result; } $countDeleted++; - $deleted[] = $notizId; + //$deleted[] = $result->retval['deleted']; //notizId + $deleted[] = $id; } // --------------------------------- @@ -217,7 +179,7 @@ class TagLib return success([ 'input' => [ 'tag' => $tag, - 'prestudentIds' => $prestudentIds + 'arrayIds' => $arrayIds ], 'summary' => [ 'recycled' => $countRecycled, @@ -231,9 +193,9 @@ class TagLib 'toDelete' => $toDelete ], 'results' => [ - 'retaggedNotizIds' => $retagged, + 'retaggedIds' => $retagged, 'newTags' => $tagged, - 'deletedNotizIds' => $deleted + 'deletedTagsIds' => $deleted ] ]); } @@ -264,46 +226,14 @@ class TagLib //RECYCLE if ($notiz_id !== null) { - $resultUpdateNotiz = $this->_ci->NotizModel->update( - [ - 'notiz_id' => $notiz_id - ], - array( - 'updateamum' => date('Y-m-d H:i:s'), - 'updatevon' => getAuthUID(), - )); - - if (isError($resultUpdateNotiz)) - return error ('Error occurred update Result ' . $notiz_id); - - $return = ['recycled' => $notiz_id]; + $resultUpdateNotiz = $this->_updateTag($notiz_id, $von, $bis); + $return = ['recycled' => $resultUpdateNotiz]; } else - + //ADD { - $resultInsertNotiz = $this->_ci->NotizModel->insert(array( - 'titel' => 'TAG', - 'text' => 'AUTOMATED TAG', - 'verfasser_uid' => getAuthUID(), - 'erledigt' => false, - 'insertamum' => date('Y-m-d H:i:s'), - 'insertvon' => getAuthUID(), - 'typ' => $tag, - 'start' => $von, - 'ende' => $bis - )); - - if (isError($resultInsertNotiz)) - return error ('Error occurred insert Result ' . $prestudent_id); - - $resultInsertZuordnung = $this->_ci->NotizzuordnungModel->insert(array( - 'notiz_id' => $resultInsertNotiz->retval, - $typeId => $id - )); - - if (isError($resultInsertZuordnung)) - return error ('Error occurred insert Zuordnung ' . $id); - $return = ['added' => $resultInsertNotiz->retval]; + $resultInsertNotiz = $this->_insertTag($typeId, $id, $tag, $von, $bis); + $return = ['added' => $resultInsertNotiz]; } return success($return); } @@ -311,20 +241,23 @@ class TagLib /* * main function for rebuild Tags for typeId * */ - public function rebuildTagsForTypeId($typeId, $id) + public function rebuildTagsForTypeId($typeId, $id) //TODO aktSem of frontend { $automatedTagsRes = $this->_ci->NotiztypModel->loadWhere(array('automatisiert' => true, 'taglib IS NOT NULL' => null)); $automatedTags = hasData($automatedTagsRes) ? getData($automatedTagsRes) : []; - $_ci = get_instance(); - - $result = $this->_ci->StudiensemesterModel->getLastOrAktSemester(); + //TODO change to chosen Studiensemester in frontend + $result = $this->_ci->StudiensemesterModel->getAktOrNextSemester(); if (isError($result)) return error('Error occurred during retrieving studiensemester'); if (empty($result->retval) || !isset($result->retval[0])) { return error('No studiensemester found'); } $studiensemester_kurzbz = $result->retval[0]->studiensemester_kurzbz ?? null; + + //for checkDelete + $startSem = $result->retval[0]->start ?? null; + $endeSem = $result->retval[0]->ende ?? null; $return = []; foreach ($automatedTags as $autoTag) @@ -339,7 +272,6 @@ class TagLib continue; } - // className without PATH (basename) $className = basename($autoTag->taglib); $kurz_bz = $autoTag->typ_kurzbz; @@ -368,58 +300,141 @@ class TagLib if (isError($result)) return error('Error occurred during updateAutomatedTags' . $kurz_bz); - return $result; + $return[$kurz_bz] = $result; } else { - $result = $this->checkForDelete($kurz_bz, $typeId, $id); - - if ($result != null) - $return[$kurz_bz] = $result; + //CHECK FOR DELETE + $params = [ + 'von' => $startSem, + 'bis' => $endeSem, + 'kurzbz' => $autoTag->typ_kurzbz, + 'typeId' => $typeId, + 'id' => $id, + ]; + $result = $this->_ci->NotizModel->checkIfExistingTag($kurz_bz, $typeId, $id, $startSem, $endeSem); + if (hasData($result)) + { + $notizId = $result->retval[0]->notiz_id; + $this->_deleteTag($notizId); + $return[$kurz_bz] = ['deleted' => $notizId]; + } } } return success($return); } - public function checkForDelete($tag, $typeId, $id) + public function checkForDeleteDEPR($tag, $typeId, $id, $start, $ende) { + //TODO Zeitbezug $return = null; $notiz_id = null; + $_ci = get_instance(); + $_ci->addMeta( + 'in checkForDelete', $tag + ); + if (!is_numeric($id)) return error ("id " . $id . "not numeric"); - $this->_ci->NotizModel->addSelect('nz.notiz_id'); - $this->_ci->NotizModel->addSelect($typeId); - $this->_ci->NotizModel->addJoin('public.tbl_notizzuordnung nz', 'notiz_id'); - $resultAllTags = $this->_ci->NotizModel->loadWhere([ - 'typ' => $tag, - $typeId => $id - ]); - if(hasData($resultAllTags)) + $result = $this->_ci->NotizModel->checkIfValidTag($tag, $typeId, $id, $start, $ende); + if (isError($result)) { + return error('Error checking valid tag for ' . $typeId . ': ' . $id); + } + + if(hasData($result)) { - $notiz_id = $resultAllTags->retval[0]->notiz_id; + $notiz_id = $result->retval[0]->notiz_id; + $_ci = get_instance(); + $_ci->addMeta( + 'checkDeleteHas DAta', $notiz_id + ); } else return null; if($notiz_id) { - $result = $this->_ci->NotizzuordnungModel->delete([ - 'notiz_id' => $notiz_id - ]); - if (isError($result)) - return error ('Error occurred during delete Notizzuordnung' . $notiz_id); - - $result = $this->_ci->NotizModel->delete([ - 'notiz_id' => $notiz_id - ]); - if (isError($result)) - return error ('Error occurred during delete Notiz' . $notiz_id); - - $return = ['deleted' => $notiz_id]; + $_ci->addMeta( + 'TO DELETE', $notiz_id + ); + $result = $this->_deleteTag($notiz_id); } - return $return; + return ['deleted' => $result]; + } + + private function _insertTag($typeId, $id, $tag, $von, $bis) + { + $resultInsert = $this->_ci->NotizModel->insert([ + 'titel' => 'TAG', + 'text' => 'AUTOMATED TAG', + 'verfasser_uid' => self::BATCHUSER, + 'erledigt' => false, + 'insertamum' => date('Y-m-d H:i:s'), + 'insertvon' => 'BatchJobTagAdd', + 'typ' => $tag, + 'start' => $von, + 'ende' => $bis + ]); + + if (isError($resultInsert)) { + return error('Error inserting tag for ' . $typeId . ': ' . $id); + } + + $notizId = $resultInsert->retval; + + $resultZuordnung = $this->_ci->NotizzuordnungModel->insert([ + 'notiz_id' => $notizId, + $typeId => $id + ]); + + if (isError($resultZuordnung)) { + return error('Error inserting relation for ' . $typeId . ': ' . $id); + } + + return $notizId; + } + + private function _updateTag($notiz_id, $von, $bis) + { + $resultUpdateNotiz = $this->_ci->NotizModel->update( + [ + 'notiz_id' => $notiz_id + ], + array( + 'updateamum' => date('Y-m-d H:i:s'), + 'updatevon' => 'BatchJobTagUpdate', + 'start' => $von, + 'ende' => $bis + )); + + + if (isError($resultUpdateNotiz)) + return error ('Error occurred during Update ' . $notiz_id); + + return $notiz_id; + } + + private function _deleteTag($notiz_id) + { + $result = $this->_ci->NotizzuordnungModel->delete([ + 'notiz_id' => $notiz_id + ]); + if (isError($result)) { + return error('Error occurred during delete Notizzuordnung ' . $notiz_id); + } + + $result = $this->_ci->NotizModel->delete([ + 'notiz_id' => $notiz_id + ]); + if (isError($result)) { + return error('Error occurred during delete Notiz ' . $notiz_id); + } + + return success([ + 'deleted' => $notiz_id + ]); } } diff --git a/application/libraries/tags/CoreDoubleDegreeTagLib.php b/application/libraries/tags/CoreDoubleDegreeTagLib.php index 264891c3d..fa9670843 100644 --- a/application/libraries/tags/CoreDoubleDegreeTagLib.php +++ b/application/libraries/tags/CoreDoubleDegreeTagLib.php @@ -36,7 +36,6 @@ class CoreDoubleDegreeTagLib $doubledegree_data = array_map(function($item) { return [ - 'typeId' => 'prestudent_id', 'id' => $item->prestudent_id, 'von' => $item->start, 'bis' => $item->ende @@ -44,7 +43,8 @@ class CoreDoubleDegreeTagLib }, $data); return (object) array( - 'data' => $doubledegree_data + 'data' => $doubledegree_data, + 'typeId' => 'prestudent_id' ); } diff --git a/application/libraries/tags/CoreFiftyFiveTagLib.php b/application/libraries/tags/CoreFiftyFiveTagLib.php index 5d4990e5d..4e2738e8b 100644 --- a/application/libraries/tags/CoreFiftyFiveTagLib.php +++ b/application/libraries/tags/CoreFiftyFiveTagLib.php @@ -39,28 +39,25 @@ class CoreFiftyFiveTagLib $data = $result->retval; $fiftyFiveData = array_map(function($item) { return [ - 'id' => $item->person_id, - 'typeId' => 'person_id', + 'id' => $item->person_id ]; }, $data); return (object) array( - 'data' => $fiftyFiveData + 'data' => $fiftyFiveData, + 'typeId' => 'person_id' ); } public function isCriteriaSetFor(array $params) { - if(!isset($params['person_id']) || !isset($params['studiensemester_kurzbz'])) - { + if ( !isset($params['id'], $params['studiensemester_kurzbz'], $params['typeId']) || $params['typeId'] !== 'person_id') return false; - } + $semester = $params['studiensemester_kurzbz']; $person_id = $params['id']; $typeId = $params['typeId']; - if($typeId != 'person_id') - return null; $result = $this->ci->StudiensemesterModel->loadWhere(array( 'studiensemester_kurzbz' => $semester @@ -71,17 +68,9 @@ class CoreFiftyFiveTagLib $semBis = $data->ende; $result = $this->ci->PersonModel->isFiftyFive($semVon, $semBis, $person_id); - $data = $result->retval; - $fiftyFiveData = array_map(function($item) { - return [ - 'id' => $item->person_id, - 'typeId' => 'person_id', - ]; - }, $data); if(hasData($result)) { - //array mit prestudent_id, von und bis return $result; } else diff --git a/application/libraries/tags/CoreJgvTagLib.php b/application/libraries/tags/CoreJgvTagLib.php index 479da7da0..15e77dc98 100644 --- a/application/libraries/tags/CoreJgvTagLib.php +++ b/application/libraries/tags/CoreJgvTagLib.php @@ -31,7 +31,6 @@ class CoreJgvTagLib $jgv_data = array_map(function($item) { return [ - 'typeId' => 'prestudent_id', 'id' => $item->prestudent_id, 'von' => $item->datum_von, 'bis' => $item->datum_bis @@ -39,7 +38,8 @@ class CoreJgvTagLib }, $data); return (object) array( - 'data' => $jgv_data + 'data' => $jgv_data, + 'typeId' => 'prestudent_id' ); } diff --git a/application/libraries/tags/CoreMissingZgvTagLib.php b/application/libraries/tags/CoreMissingZgvTagLib.php index 73fa9021f..e25aed4cc 100644 --- a/application/libraries/tags/CoreMissingZgvTagLib.php +++ b/application/libraries/tags/CoreMissingZgvTagLib.php @@ -39,7 +39,6 @@ class CoreMissingZgvTagLib $zgvmissing_data = array_map(function($item) { return [ - 'typeId' => 'prestudent_id', 'id' => $item->prestudent_id, 'von' => null, 'bis' => null @@ -47,6 +46,7 @@ class CoreMissingZgvTagLib }, $data); return (object) array( + 'typeId' => 'prestudent_id', 'data' => $zgvmissing_data ); diff --git a/application/libraries/tags/CoreOutgoingTagLib.php b/application/libraries/tags/CoreOutgoingTagLib.php index e076d0adf..904839dee 100644 --- a/application/libraries/tags/CoreOutgoingTagLib.php +++ b/application/libraries/tags/CoreOutgoingTagLib.php @@ -31,7 +31,6 @@ class CoreOutgoingTagLib $outgoing_data = array_map(function($item) { return [ - 'typeId' => 'prestudent_id', 'id' => $item->prestudent_id, 'von' => $item->von, 'bis' => $item->bis @@ -39,7 +38,8 @@ class CoreOutgoingTagLib }, $data); return (object) array( - 'data' => $outgoing_data + 'data' => $outgoing_data, + 'typeId' => 'prestudent_id', ); } diff --git a/application/libraries/tags/CorePrewiederholerTagLib.php b/application/libraries/tags/CorePrewiederholerTagLib.php index cb2f0a77a..8b7037b07 100644 --- a/application/libraries/tags/CorePrewiederholerTagLib.php +++ b/application/libraries/tags/CorePrewiederholerTagLib.php @@ -34,7 +34,6 @@ class CorePrewiederholerTagLib $prewiederholer_data = array_map(function($item) { return [ - 'typeId' => 'prestudent_id', 'id' => $item->prestudent_id, 'von' => $item->start, 'bis' => $item->ende @@ -42,7 +41,8 @@ class CorePrewiederholerTagLib }, $data); return (object) array( - 'data' => $prewiederholer_data + 'data' => $prewiederholer_data, + 'typeId' => 'prestudent_id', ); } diff --git a/application/libraries/tags/CoreStbErhoehtTagLib.php b/application/libraries/tags/CoreStbErhoehtTagLib.php index 5795f8348..886aff468 100644 --- a/application/libraries/tags/CoreStbErhoehtTagLib.php +++ b/application/libraries/tags/CoreStbErhoehtTagLib.php @@ -36,7 +36,6 @@ class CoreStbErhoehtTagLib $konto_data = array_map(function($item) { return [ - 'typeId' => 'prestudent_id', 'id' => $item->prestudent_id, 'von' => $item->start, 'bis' => $item->ende @@ -44,7 +43,8 @@ class CoreStbErhoehtTagLib }, $data); return (object) array( - 'data' => $konto_data + 'data' => $konto_data, + 'typeId' => 'prestudent_id' ); } diff --git a/application/libraries/tags/CoreUnterbrecherTagLib.php b/application/libraries/tags/CoreUnterbrecherTagLib.php index c205c746c..ddf8f33cd 100644 --- a/application/libraries/tags/CoreUnterbrecherTagLib.php +++ b/application/libraries/tags/CoreUnterbrecherTagLib.php @@ -34,7 +34,6 @@ class CoreUnterbrecherTagLib $unterbrecher_data = array_map(function($item) { return [ - 'typeId' => 'prestudent_id', 'id' => $item->prestudent_id, 'von' => $item->start, 'bis' => $item->ende @@ -42,7 +41,8 @@ class CoreUnterbrecherTagLib }, $data); return (object) array( - 'data' => $unterbrecher_data + 'data' => $unterbrecher_data, + 'typeId' => 'prestudent_id' ); } diff --git a/application/libraries/tags/CoreWiederholerTagLib.php b/application/libraries/tags/CoreWiederholerTagLib.php index 3d75e562e..8f4eb1dd7 100644 --- a/application/libraries/tags/CoreWiederholerTagLib.php +++ b/application/libraries/tags/CoreWiederholerTagLib.php @@ -34,7 +34,6 @@ class CoreWiederholerTagLib $wiederholer_data = array_map(function($item) { return [ - 'typeId' => 'prestudent_id', 'id' => $item->prestudent_id, 'von' => $item->start, 'bis' => $item->ende @@ -42,6 +41,7 @@ class CoreWiederholerTagLib }, $data); return (object) array( + 'typeId' => 'prestudent_id', 'data' => $wiederholer_data ); } diff --git a/application/models/person/Notiz_model.php b/application/models/person/Notiz_model.php index 64fce8944..1dc09caaf 100644 --- a/application/models/person/Notiz_model.php +++ b/application/models/person/Notiz_model.php @@ -296,4 +296,59 @@ class Notiz_model extends DB_Model return $this->loadWhere(array('anrechnung_id' => $anrechnung_id)); } + + /** + * check if a given Tag for a certain notizzuordnung id is valid + * + * @param $tag typ_kurzbz to check + * @param $typeId typeId to check + * @param $id id to check + * @param $von start of time period or NULL + * @param $bis end of time period or NULL + * + * @return array + */ + public function checkIfExistingTag($tag, $typeId, $id, $von=null, $bis=null) + { + $query = " + SELECT * + FROM public.tbl_notiz + JOIN public.tbl_notizzuordnung nz USING (notiz_id) + WHERE typ = ? + AND {$typeId} = ? + AND ( + start IS NULL + OR ende IS NULL + OR (start <= ? AND ende >= ?) + ) + "; + + return $this->execQuery($query, [$tag, $id, $bis, $von]); + } + + /** + * returns all existing tags of a certain tag within a time period + * + * @param $tag typ_kurzbz of tag + * @param $von start of time period or NULL + * @param $bis end of time period or NULL + * + * @return array + */ + public function getAllTags($tag, $von=null, $bis=null) + { + $query = " + SELECT * + FROM public.tbl_notiz + JOIN public.tbl_notizzuordnung nz USING (notiz_id) + WHERE typ = ? + AND ( + start IS NULL + OR ende IS NULL + OR (start <= ? AND ende >= ?) + ); + "; + + return $this->execQuery($query, array($tag, $bis, $von)); + } } diff --git a/public/js/api/factory/stv/tag.js b/public/js/api/factory/stv/tag.js index b0c416e2d..26aacca69 100644 --- a/public/js/api/factory/stv/tag.js +++ b/public/js/api/factory/stv/tag.js @@ -63,7 +63,7 @@ export default { rebuildTagsforTypeId(data){ return { - method: 'get', + method: 'post', url: 'api/frontend/v1/stv/Tags/rebuildTagsForTypeId/', params: data }; From 3dcf72d6792c2f9cbc168fc700e38e2ac3de1b09 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Thu, 7 May 2026 17:36:34 +0200 Subject: [PATCH 20/28] add semester filter for tags - in detailheader: use currentSem for manual triggering and refactor formatter - in list: preload list of ids with start and end for tabulator formatter to enable filtering --- application/core/Tag_Controller.php | 39 +++++- application/libraries/TagLib.php | 7 +- public/js/api/factory/stv/tag.js | 15 +++ .../components/DetailHeader/DetailHeader.js | 38 +++++- .../Stv/Studentenverwaltung/List.js | 73 ++++++++++- public/js/components/Tag/tagFormatter.js | 39 +++++- public/js/tabulator/formatter/tags.js | 113 ++++++++++++++++-- 7 files changed, 293 insertions(+), 31 deletions(-) diff --git a/application/core/Tag_Controller.php b/application/core/Tag_Controller.php index 082cb9ac4..b321bac92 100644 --- a/application/core/Tag_Controller.php +++ b/application/core/Tag_Controller.php @@ -15,11 +15,12 @@ class Tag_Controller extends FHCAPI_Controller 'getTag' => self::BERECHTIGUNG_KURZBZ, 'getTags' => self::BERECHTIGUNG_KURZBZ, 'addTag' => self::BERECHTIGUNG_KURZBZ, - 'updateTag' => self::BERECHTIGUNG_KURZBZ, 'doneTag' => self::BERECHTIGUNG_KURZBZ, 'deleteTag' => self::BERECHTIGUNG_KURZBZ, 'getAllTags' => self::BERECHTIGUNG_KURZBZ, + 'getSemDates' => self::BERECHTIGUNG_KURZBZ, + 'getAllStartAndEndAutomatedTags' => self::BERECHTIGUNG_KURZBZ, 'rebuildTagsForTypeId' => self::BERECHTIGUNG_KURZBZ, ]; @@ -341,16 +342,46 @@ class Tag_Controller extends FHCAPI_Controller { $id = $this->input->post('id'); $typeId = $this->input->post('typeId'); + $semester = $this->input->post('sem'); + + $result = $this->taglib->rebuildTagsForTypeId($typeId, $id, $semester); - $result = $this->taglib->rebuildTagsForTypeId($typeId, $id); - //TODO (refactor; um semester, studiengang_kz) - //$result = $this->taglib->rebuildTagsForTypeId($params); if (isError($result)) return error ('Error occurred during updateAutomatedTags'); $this->terminateWithSuccess($result); } + public function getSemDates() + { + $studiensemester_kurzbz = $this->input->get('semester'); + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + $result = $this->StudiensemesterModel->loadWhere(array('studiensemester_kurzbz' => $studiensemester_kurzbz)); + if (isError($result)) + return error('Error occurred during retrieving studiensemester'); + $data = getData($result); + $this->terminateWithSuccess(current($data)); + + } + + public function getAllStartAndEndAutomatedTags() + { + $this->NotizModel->addSelect('notiz_id as id'); + $this->NotizModel->addSelect('start'); + $this->NotizModel->addSelect('ende'); + $this->NotizModel->addSelect('typ'); + + $result = $this->NotizModel->loadWhere(array( + 'titel' => 'TAG', + 'verfasser_uid' => 'sftest' + )); + + if (isError($result)) + return error('Error occurred during retrieving intervalls automated tags'); + $data = getData($result); + $this->terminateWithSuccess($data); + } + private function _setAuthUID() { $this->_uid = getAuthUID(); diff --git a/application/libraries/TagLib.php b/application/libraries/TagLib.php index 2442b2fab..4eb8dedef 100644 --- a/application/libraries/TagLib.php +++ b/application/libraries/TagLib.php @@ -241,21 +241,18 @@ class TagLib /* * main function for rebuild Tags for typeId * */ - public function rebuildTagsForTypeId($typeId, $id) //TODO aktSem of frontend + public function rebuildTagsForTypeId($typeId, $id, $studiensemester_kurzbz) { $automatedTagsRes = $this->_ci->NotiztypModel->loadWhere(array('automatisiert' => true, 'taglib IS NOT NULL' => null)); $automatedTags = hasData($automatedTagsRes) ? getData($automatedTagsRes) : []; - //TODO change to chosen Studiensemester in frontend - $result = $this->_ci->StudiensemesterModel->getAktOrNextSemester(); + $result = $this->_ci->StudiensemesterModel->load($studiensemester_kurzbz); if (isError($result)) return error('Error occurred during retrieving studiensemester'); if (empty($result->retval) || !isset($result->retval[0])) { return error('No studiensemester found'); } - $studiensemester_kurzbz = $result->retval[0]->studiensemester_kurzbz ?? null; - //for checkDelete $startSem = $result->retval[0]->start ?? null; $endeSem = $result->retval[0]->ende ?? null; $return = []; diff --git a/public/js/api/factory/stv/tag.js b/public/js/api/factory/stv/tag.js index 26aacca69..3a3f78167 100644 --- a/public/js/api/factory/stv/tag.js +++ b/public/js/api/factory/stv/tag.js @@ -61,6 +61,21 @@ export default { }; }, + getSemDates(studiensemester_kurzbz){ + return { + method: 'get', + url: 'api/frontend/v1/stv/Tags/getSemDates', + params: studiensemester_kurzbz + }; + }, + + getAllStartAndEndAutomatedTags(){ + return { + method: 'get', + url: 'api/frontend/v1/stv/Tags/getAllStartAndEndAutomatedTags', + }; + }, + rebuildTagsforTypeId(data){ return { method: 'post', diff --git a/public/js/components/DetailHeader/DetailHeader.js b/public/js/components/DetailHeader/DetailHeader.js index 516ecdd87..076b7db56 100644 --- a/public/js/components/DetailHeader/DetailHeader.js +++ b/public/js/components/DetailHeader/DetailHeader.js @@ -49,6 +49,10 @@ export default { from: 'configStvTagsEnabled', default: false }, + currentSemester: { + from: 'currentSemester', + required: true + }, }, computed: { appRoot() { @@ -85,6 +89,7 @@ export default { } if(this.tagsEnabled) { + this.getSemesterDates(this.currentSemester); this.loadTagsAndRender(this.headerData[0].prestudent_id); } @@ -113,6 +118,14 @@ export default { } }, deep: true, + }, + currentSemester: { + handler(newVal) { + if (newVal) { + this.getSemesterDates(newVal); + } + }, + deep: true, } }, data(){ @@ -123,7 +136,8 @@ export default { isFetchingIssues: false, tagEndpoint: ApiTag, tagData: null, - rebuildData: null + rebuildData: null, + semDates: {} }; }, methods: { @@ -219,7 +233,9 @@ export default { prestudent_id, this.tagData, this.$refs.tagComponent, - 'prestudent_id' + 'prestudent_id', + this.semDates.start, + this.semDates.ende ); this.$refs.tagWrapper.innerHTML = ''; @@ -248,7 +264,8 @@ export default { rebuildPrestudentTags(){ const params = { id : this.headerData[0].prestudent_id, - typeId: 'prestudent_id' + typeId: 'prestudent_id', + sem: this.currentSemester }; return this.$api @@ -259,6 +276,17 @@ export default { this.reload(); }) .catch(this.$fhcAlert.handleSystemError); + }, + getSemesterDates(semester){ + const params = { + studiensemester_kurzbz: semester + }; + return this.$api + .call(ApiTag.getSemDates({semester})) + .then(result => { + this.semDates = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); } }, template: ` @@ -339,8 +367,10 @@ export default { v-if="tagsEnabled" @click="rebuildPrestudentTags" class="btn btn-outline btn-light mb-1" - title="Automatische Tags neu laden"> + :title="'Automatische Tags fuer ' + currentSemester + ' neu laden'" + > + {{currentSemester}}
unruly
diff --git a/public/js/components/Stv/Studentenverwaltung/List.js b/public/js/components/Stv/Studentenverwaltung/List.js index 4fe8b5eb6..d98883165 100644 --- a/public/js/components/Stv/Studentenverwaltung/List.js +++ b/public/js/components/Stv/Studentenverwaltung/List.js @@ -237,7 +237,9 @@ export default { dragSource: [], oldScrollUrl: '', oldScrollLeft: 0, - oldScrollTop: 0 + oldScrollTop: 0, + semDates: {}, //TODO(Manu) check injections + intervalMap: {} } }, computed: { @@ -293,7 +295,12 @@ export default { }, }, created: function() { + if(this.tagsEnabled) { + this.getSemesterDates(this.currentSemester); + + this.loadIntervals(); //preload + const coltags = { title: 'Tags', field: 'tags', @@ -301,7 +308,36 @@ export default { headerFilter: "input", headerFilterFunc: tagHeaderFilter, headerFilterFuncParams: {field: 'tags'}, - formatter: (cell) => tagFormatter(cell, this.$refs.tagComponent), + //formatter: (cell) => tagFormatter(cell, this.$refs.tagComponent), //prev. Version without filter + formatter: (cell) => { + const raw = cell.getValue(); + + const tags = + Array.isArray(raw) + ? raw + : (typeof raw === 'string' + ? JSON.parse(raw) + : []); + + const id = tags?.[0]?.id; + + const interval = id + ? this.intervalMap[id] + : null; + + const enrichedTags = { + tags: tags, + start: interval?.start || null, + ende: interval?.end || null, + }; + + return tagFormatter( + enrichedTags, + this.$refs.tagComponent, + this.semDates.start, + this.semDates.ende + ); + }, width: 150, }; this.tabulatorOptions.columns.splice(2, 0, coltags); @@ -312,9 +348,40 @@ export default { if (n !== o && o !== undefined && this.$refs.table.tableBuilt) { this.translateTabulator(); } + }, + currentSemester: { + handler(newVal) { + if (newVal) { + this.getSemesterDates(newVal); + } + }, + deep: true, } }, methods: { + loadIntervals() { + return this.$api + .call(ApiTag.getAllStartAndEndAutomatedTags()) + .then(result => { + const data = result.data || []; + this.intervalMap = {}; + data.forEach(item => { + this.intervalMap[item.id] = item; + }); + }) + .catch(this.$fhcAlert.handleSystemError); + }, + getSemesterDates(semester){ //TODO(check for injections) + const params = { + studiensemester_kurzbz: semester + }; + return this.$api + .call(ApiTag.getSemDates({semester})) + .then(result => { + this.semDates = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + }, translateTabulator() { this.$p .loadCategory(['global', 'person', 'lehre', 'ui', 'profilUpdate', 'admission', 'stv']) @@ -398,7 +465,6 @@ export default { //for tags this.selectedRows = this.$refs.table.tabulator.getSelectedRows(); this.selectedColumnValues = this.selectedRows.filter(row => row.getData().prestudent_id !== undefined && row.getData().prestudent_id).map(row => row.getData().prestudent_id); - this.$emit('update:selected', data); }, autoSelectRows(data) { @@ -601,6 +667,7 @@ export default { // TODO(chris): filter component column chooser has no accessibilty features template: `
+ test manu: currentSEM: {{semDates.start}} - {{semDates.ende}}
({ id: tag.notiz_id, typ_kurzbz: tag.titel?.toLowerCase(), @@ -12,9 +15,33 @@ export function idTagFormatter (id, tagData, tagComponent, typeId) style: tag.style, done: tag.done, automatisiert: tag.automatisiert, - typeId: id + typeId: id, + validFrom: tag.start ? new Date(tag.start) : null, + validTo: tag.ende ? new Date(tag.ende) : null })); + const isInSemester = (tag) => { + if (!hasSemesterFilter) return true; + + if (!tag.validFrom && !tag.validTo) return true; + + if (!tag.validFrom && !tag.validTo) return true; + + if (tag.validFrom && tag.validTo) { + return tag.validFrom <= semEnd && tag.validTo >= semStart; + } + + if (tag.validFrom && !tag.validTo) { + return tag.validFrom <= semEnd; + } + + if (!tag.validFrom && tag.validTo) { + return tag.validTo >= semStart; + } + + return false; + }; + let container = document.createElement('div'); container.className = "d-flex gap-1"; @@ -23,7 +50,9 @@ export function idTagFormatter (id, tagData, tagComponent, typeId) const renderTags = () => { container.innerHTML = ''; - let filtered = parsedTags.filter(t => t != null); + let filtered = parsedTags + .filter(t => t != null) + .filter(isInSemester); filtered.sort((a, b) => { let adone = a.done ? 1 : 0; diff --git a/public/js/tabulator/formatter/tags.js b/public/js/tabulator/formatter/tags.js index b9578dbd4..d9a5244fd 100644 --- a/public/js/tabulator/formatter/tags.js +++ b/public/js/tabulator/formatter/tags.js @@ -1,28 +1,115 @@ -export function tagFormatter(cell, tagComponent) -{ +export function tagFormatter( + cell, + tagComponent, + semesterStart = null, + semesterEnd = null +) { + + // support both call versions + // 1. previous Tabulator cell: old version + // 2. custom enriched object: with start and end for tags plus semesterDates + // for check if valid tag + + const isTabulatorCell = + cell && typeof cell.getValue === 'function'; + + const normalized = isTabulatorCell + ? { + tags: cell.getValue() || [], + start: null, + ende: null, + rowData: cell.getRow().getData(), + } + : { + tags: cell.tags || [], + start: cell.start || null, + ende: cell.ende || null, + rowData: cell.rowData || {}, + }; + + const tags = normalized.tags || []; + + if (!tags.length) { + return ""; + } + const mappedData = tagComponent.tags.map(tag => ({ typ_kurzbz: tag.tag_typ_kurzbz, - automatisiert: tag.automatisiert + automatisiert: tag.automatisiert, + validFrom: normalized.start + ? new Date(normalized.start) + : null, + validTo: normalized.ende + ? new Date(normalized.ende) + : null })); + const hasSemesterFilter = + !!(semesterStart && semesterEnd); - let tags = cell.getValue(); - if (!tags) return; + const semStart = hasSemesterFilter ? new Date(semesterStart) : null; + + const semEnd = hasSemesterFilter ? new Date(semesterEnd) : null; + + const isInSemester = (tag) => { + + if (!hasSemesterFilter) { + return true; + } + + if (!tag.validFrom && !tag.validTo) { + return true; + } + + if (tag.validFrom && tag.validTo) { + return ( + tag.validFrom <= semEnd && + tag.validTo >= semStart + ); + } + + if (tag.validFrom && !tag.validTo) { + return tag.validFrom <= semEnd; + } + + if (!tag.validFrom && tag.validTo) { + return tag.validTo >= semStart; + } + + return false; + }; + + // parse tags if needed + let parsedTags = + typeof tags === 'string' + ? JSON.parse(tags) + : tags; let container = document.createElement('div'); container.className = "d-flex gap-1"; - let parsedTags = JSON.parse(tags); let maxVisibleTags = 2; - const rowData = cell.getRow().getData(); + const rowData = normalized.rowData; + if (rowData._tagExpanded === undefined) { rowData._tagExpanded = false; } const renderTags = () => { container.innerHTML = ''; - parsedTags = parsedTags.filter(item => item !== null); + + parsedTags = parsedTags.filter(tag => { + const mapped = mappedData.find( + m => m.typ_kurzbz === tag.typ_kurzbz + ); + + if (!mapped) { + return true; + } + + return isInSemester(mapped); + }); parsedTags.sort((a, b) => { let adone = a.done ? 1 : 0; @@ -34,10 +121,14 @@ export function tagFormatter(cell, tagComponent) } return b.id - a.id; }); - const tagsToShow = rowData._tagExpanded ? parsedTags : parsedTags.slice(0, maxVisibleTags); + + const tagsToShow = rowData._tagExpanded + ? parsedTags + : parsedTags.slice(0, maxVisibleTags); tagsToShow.forEach(tag => { if (!tag) return; + let tagElement = document.createElement('span'); tagElement.innerText = tag.beschreibung; tagElement.title = tag.notiz; @@ -60,8 +151,10 @@ export function tagFormatter(cell, tagComponent) container.appendChild(tagElement); }); - if (parsedTags.length > maxVisibleTags) { + // show expand button + if ( parsedTags.length > maxVisibleTags) { let toggle = document.createElement('button'); + toggle.innerText = (rowData._tagExpanded ? '- ' : '+ ') + (parsedTags.length - maxVisibleTags); toggle.className = "display_all"; toggle.title = rowData._tagExpanded ? "Tags ausblenden" : "Tags einblenden"; From ede93232244ed33f3bc729215762a1b8c8b372e2 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Fri, 8 May 2026 08:33:53 +0200 Subject: [PATCH 21/28] refactor manual triggering for double degree lib --- application/libraries/tags/CoreDoubleDegreeTagLib.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/application/libraries/tags/CoreDoubleDegreeTagLib.php b/application/libraries/tags/CoreDoubleDegreeTagLib.php index fa9670843..13b113a21 100644 --- a/application/libraries/tags/CoreDoubleDegreeTagLib.php +++ b/application/libraries/tags/CoreDoubleDegreeTagLib.php @@ -50,14 +50,11 @@ class CoreDoubleDegreeTagLib public function isCriteriaSetFor(array $params) { - - if(!isset($params['prestudent_id']) || !isset($params['studiensemester_kurzbz'])) - { + if ( !isset($params['id'], $params['studiensemester_kurzbz'], $params['typeId']) || $params['typeId'] !== 'prestudent_id') return false; - } $semester = $params['studiensemester_kurzbz']; - $prestudent_id = $params['prestudent_id']; + $prestudent_id = $params['id']; $this->ci->MobilitaetModel->addSelect('prestudent_id'); $this->ci->MobilitaetModel->addSelect('start as von'); From 7320dc448e83ae65293d818239b7ce02f1010959 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Fri, 8 May 2026 10:57:19 +0200 Subject: [PATCH 22/28] correct bezeichnung interval.ende --- public/js/components/Stv/Studentenverwaltung/List.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/components/Stv/Studentenverwaltung/List.js b/public/js/components/Stv/Studentenverwaltung/List.js index d98883165..e8c8dce41 100644 --- a/public/js/components/Stv/Studentenverwaltung/List.js +++ b/public/js/components/Stv/Studentenverwaltung/List.js @@ -328,7 +328,7 @@ export default { const enrichedTags = { tags: tags, start: interval?.start || null, - ende: interval?.end || null, + ende: interval?.ende || null, }; return tagFormatter( From 6fa0a7c10246711a9400e972bb19c71e559be708 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Fri, 8 May 2026 11:53:47 +0200 Subject: [PATCH 23/28] use injected studiensemester instead of api call for studiensemester --- application/core/Tag_Controller.php | 13 -------- public/js/api/factory/stv/tag.js | 8 ----- .../components/DetailHeader/DetailHeader.js | 32 +++++------------- .../Stv/Studentenverwaltung/List.js | 33 ++++--------------- 4 files changed, 16 insertions(+), 70 deletions(-) diff --git a/application/core/Tag_Controller.php b/application/core/Tag_Controller.php index b321bac92..09f42922c 100644 --- a/application/core/Tag_Controller.php +++ b/application/core/Tag_Controller.php @@ -19,7 +19,6 @@ class Tag_Controller extends FHCAPI_Controller 'doneTag' => self::BERECHTIGUNG_KURZBZ, 'deleteTag' => self::BERECHTIGUNG_KURZBZ, 'getAllTags' => self::BERECHTIGUNG_KURZBZ, - 'getSemDates' => self::BERECHTIGUNG_KURZBZ, 'getAllStartAndEndAutomatedTags' => self::BERECHTIGUNG_KURZBZ, 'rebuildTagsForTypeId' => self::BERECHTIGUNG_KURZBZ, ]; @@ -352,18 +351,6 @@ class Tag_Controller extends FHCAPI_Controller $this->terminateWithSuccess($result); } - public function getSemDates() - { - $studiensemester_kurzbz = $this->input->get('semester'); - $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); - $result = $this->StudiensemesterModel->loadWhere(array('studiensemester_kurzbz' => $studiensemester_kurzbz)); - if (isError($result)) - return error('Error occurred during retrieving studiensemester'); - $data = getData($result); - $this->terminateWithSuccess(current($data)); - - } - public function getAllStartAndEndAutomatedTags() { $this->NotizModel->addSelect('notiz_id as id'); diff --git a/public/js/api/factory/stv/tag.js b/public/js/api/factory/stv/tag.js index 3a3f78167..522dfa3ff 100644 --- a/public/js/api/factory/stv/tag.js +++ b/public/js/api/factory/stv/tag.js @@ -61,14 +61,6 @@ export default { }; }, - getSemDates(studiensemester_kurzbz){ - return { - method: 'get', - url: 'api/frontend/v1/stv/Tags/getSemDates', - params: studiensemester_kurzbz - }; - }, - getAllStartAndEndAutomatedTags(){ return { method: 'get', diff --git a/public/js/components/DetailHeader/DetailHeader.js b/public/js/components/DetailHeader/DetailHeader.js index 076b7db56..486f363d9 100644 --- a/public/js/components/DetailHeader/DetailHeader.js +++ b/public/js/components/DetailHeader/DetailHeader.js @@ -53,6 +53,10 @@ export default { from: 'currentSemester', required: true }, + lists: { + from: 'lists', + required: true + }, }, computed: { appRoot() { @@ -81,6 +85,9 @@ export default { return [this.headerData[0].prestudent_id]; } }, + semesterDates(){ + return this.lists.studiensemester?.find(item => item.studiensemester_kurzbz === this.currentSemester) || {}; + } }, created(){ if (this.typeHeader === 'student') { @@ -89,7 +96,6 @@ export default { } if(this.tagsEnabled) { - this.getSemesterDates(this.currentSemester); this.loadTagsAndRender(this.headerData[0].prestudent_id); } @@ -119,14 +125,6 @@ export default { }, deep: true, }, - currentSemester: { - handler(newVal) { - if (newVal) { - this.getSemesterDates(newVal); - } - }, - deep: true, - } }, data(){ return{ @@ -137,7 +135,6 @@ export default { tagEndpoint: ApiTag, tagData: null, rebuildData: null, - semDates: {} }; }, methods: { @@ -234,8 +231,8 @@ export default { this.tagData, this.$refs.tagComponent, 'prestudent_id', - this.semDates.start, - this.semDates.ende + this.semesterDates.start, + this.semesterDates.ende ); this.$refs.tagWrapper.innerHTML = ''; @@ -277,17 +274,6 @@ export default { }) .catch(this.$fhcAlert.handleSystemError); }, - getSemesterDates(semester){ - const params = { - studiensemester_kurzbz: semester - }; - return this.$api - .call(ApiTag.getSemDates({semester})) - .then(result => { - this.semDates = result.data; - }) - .catch(this.$fhcAlert.handleSystemError); - } }, template: `
diff --git a/public/js/components/Stv/Studentenverwaltung/List.js b/public/js/components/Stv/Studentenverwaltung/List.js index e8c8dce41..ae7a577ee 100644 --- a/public/js/components/Stv/Studentenverwaltung/List.js +++ b/public/js/components/Stv/Studentenverwaltung/List.js @@ -238,7 +238,6 @@ export default { oldScrollUrl: '', oldScrollLeft: 0, oldScrollTop: 0, - semDates: {}, //TODO(Manu) check injections intervalMap: {} } }, @@ -293,12 +292,13 @@ export default { .replace(/\//g, '_'); return "StudentList_" + today + ".csv"; }, + semesterDates(){ + return this.lists.studiensemester?.find(item => item.studiensemester_kurzbz === this.currentSemester) || {}; + } }, created: function() { if(this.tagsEnabled) { - this.getSemesterDates(this.currentSemester); - this.loadIntervals(); //preload const coltags = { @@ -333,9 +333,9 @@ export default { return tagFormatter( enrichedTags, - this.$refs.tagComponent, - this.semDates.start, - this.semDates.ende + this.$refs?.tagComponent, + this.semesterDates?.start, + this.semesterDates?.ende ); }, width: 150, @@ -349,14 +349,6 @@ export default { this.translateTabulator(); } }, - currentSemester: { - handler(newVal) { - if (newVal) { - this.getSemesterDates(newVal); - } - }, - deep: true, - } }, methods: { loadIntervals() { @@ -371,17 +363,6 @@ export default { }) .catch(this.$fhcAlert.handleSystemError); }, - getSemesterDates(semester){ //TODO(check for injections) - const params = { - studiensemester_kurzbz: semester - }; - return this.$api - .call(ApiTag.getSemDates({semester})) - .then(result => { - this.semDates = result.data; - }) - .catch(this.$fhcAlert.handleSystemError); - }, translateTabulator() { this.$p .loadCategory(['global', 'person', 'lehre', 'ui', 'profilUpdate', 'admission', 'stv']) @@ -667,7 +648,7 @@ export default { // TODO(chris): filter component column chooser has no accessibilty features template: `
- test manu: currentSEM: {{semDates.start}} - {{semDates.ende}} + test manu: currentSEM: {{semesterDates.start}} - {{semesterDates.ende}}
Date: Mon, 11 May 2026 09:20:59 +0200 Subject: [PATCH 24/28] create log entries for Summary, Details and Errors --- application/controllers/jobs/TagJob.php | 41 +++++++++++++++---------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/application/controllers/jobs/TagJob.php b/application/controllers/jobs/TagJob.php index 65e4b052e..c97a74bb2 100644 --- a/application/controllers/jobs/TagJob.php +++ b/application/controllers/jobs/TagJob.php @@ -34,16 +34,22 @@ class TagJob extends JOB_Controller public function rebuildAutomatedTags() { - print_r( PHP_EOL . "Start Job rebuild" . PHP_EOL); + $this->logInfo('Start Job rebuild Automated Tags'); $automatedTagsRes = $this->NotiztypModel->loadWhere(array('automatisiert' => true, 'taglib IS NOT NULL' => null)); $automatedTags = hasData($automatedTagsRes) ? getData($automatedTagsRes) : []; + $result = $this->StudiensemesterModel->getAktOrNextSemester(); if (isError($result)) - return error ('Error occurred during retrieving studiensemester'); + { + $this->logError('Error occurred during retrieving studiensemester'); + return $this->logInfo('End Job rebuild Automated Tags'); + } + if (empty($result->retval) || !isset($result->retval[0])) { - return error('No studiensemester found'); + $this->logInfo('No Studiensemester found'); + return $this->logInfo('End Job rebuild Automated Tags'); } $studiensemester_kurzbz = $result->retval[0]->studiensemester_kurzbz ?? null; $params = array( @@ -58,7 +64,7 @@ class TagJob extends JOB_Controller if(file_exists($filePath)) { require_once($filePath); } else { - echo "File not found: " . $filePath . PHP_EOL; + $this->logInfo("File not found: " . $filePath . PHP_EOL); continue; } @@ -81,26 +87,29 @@ class TagJob extends JOB_Controller $result = $this->taglib->updateAutomatedTags($paramsTag); if (isError($result)) { - return error('Error occurred during updateAutomatedTags'); + $this->logError('Error occurred during updateAutomatedTags ' . $kurz_bz); + continue; } $data = is_array($result) ? $result['retval'] : $result->retval; //PRINT OUTPUT CONSOLE //SUMMARY - print_r(PHP_EOL . "-- TAG " . $result->retval['input']['tag'] . " | TYPE_ID " . $typeId . " --"); - - print_r( PHP_EOL . "Count Recycled: " . $result->retval['summary']['recycled']); - print_r(PHP_EOL . "Count Added: ". $result->retval['summary']['added']); - print_r(PHP_EOL . "Count Deleted: ". $result->retval['summary']['deleted']); + $this->logInfo("Tag " . $result->retval['input']['tag'] . " | TYPE_ID " . $typeId . " --" + . " Count Recycled: " . $result->retval['summary']['recycled'] + . " Count Added: ". $result->retval['summary']['added'] + . " Count Deleted: ". $result->retval['summary']['deleted']); //DETAILS - //print_r(PHP_EOL . "New tag(s) [". $typeId . "]: " . implode(', ', $result->retval['results']['newTags'])); - //print_r(PHP_EOL . "Deleted tags(s) [". $typeId . "]: " . implode(', ', $result->retval['results']['deletedTagsIds'])); - //print_r(PHP_EOL . "Recycled tag(s) [". $typeId . "]: " . implode(', ', $result->retval['results']['retaggedIds'])); - print_r(PHP_EOL); + if($result->retval['results']['newTags']) + $this->logInfo("Tag " . $result->retval['input']['tag'] . "New tag(s): " . implode(', ', $result->retval['results']['newTags'])); + if($result->retval['results']['deletedTagsIds']) + $this->logInfo("Tag " . $result->retval['input']['tag'] . "Deleted tags(s: " . implode(', ', $result->retval['results']['deletedTagsIds'])); + if ($result->retval['results']['retaggedIds']) + $this->logInfo("Tag " . $result->retval['input']['tag'] . "Recycled tag(s): " . implode(', ', $result->retval['results']['retaggedIds'])); + } - print_r( PHP_EOL . "End Job rebuild" . PHP_EOL); + $this->logInfo( PHP_EOL . "End Job rebuild Automated Tags"); } @@ -123,7 +132,7 @@ class TagJob extends JOB_Controller 'notiz_id' => $notiz_id ]); if (isError($result)) - return error ('Error occurred delete Notizzuordnung' . $notiz_id); + $this->logError ('Error occurred delete Notizzuordnung' . $notiz_id); $result = $this->NotizModel->delete([ 'notiz_id' => $notiz_id From 6fedb4b10873a4f9fa4461a4f4c548afa326afae Mon Sep 17 00:00:00 2001 From: ma0068 Date: Mon, 11 May 2026 10:07:28 +0200 Subject: [PATCH 25/28] delete unused code --- application/controllers/jobs/TagJob.php | 30 ------------ application/libraries/TagLib.php | 49 +------------------ .../components/DetailHeader/DetailHeader.js | 2 +- .../Stv/Studentenverwaltung/List.js | 1 - 4 files changed, 3 insertions(+), 79 deletions(-) diff --git a/application/controllers/jobs/TagJob.php b/application/controllers/jobs/TagJob.php index c97a74bb2..5a04204d7 100644 --- a/application/controllers/jobs/TagJob.php +++ b/application/controllers/jobs/TagJob.php @@ -112,34 +112,4 @@ class TagJob extends JOB_Controller $this->logInfo( PHP_EOL . "End Job rebuild Automated Tags"); } - - public function deleteAllAutomatedTags() - { - print_r( PHP_EOL . "Start Job delete ALL Automated Tags" . PHP_EOL); - - $resultToDelete = $this->NotizModel->loadWhere(array('insertvon' => 'BatchJobTagAdd')); - - $data = $resultToDelete->retval; - $notiz_ids = array_map(function($item) { - return $item->notiz_id; - }, $data); - - print_r($notiz_ids); - - foreach ($notiz_ids as $notiz_id) - { - $result = $this->NotizzuordnungModel->delete([ - 'notiz_id' => $notiz_id - ]); - if (isError($result)) - $this->logError ('Error occurred delete Notizzuordnung' . $notiz_id); - - $result = $this->NotizModel->delete([ - 'notiz_id' => $notiz_id - ]); - if (isError($result)) - return error ('Error occurred delete Notiz' . $notiz_id); - } - print_r( PHP_EOL . "End Job delete Automated Tags" . PHP_EOL); - } } diff --git a/application/libraries/TagLib.php b/application/libraries/TagLib.php index 4eb8dedef..a9322cd12 100644 --- a/application/libraries/TagLib.php +++ b/application/libraries/TagLib.php @@ -134,7 +134,6 @@ class TagLib $countRecycled++; $retagged[] = $id; - //$retagged[] = $notizId; //notiz_id } // --------------------------------- @@ -145,12 +144,9 @@ class TagLib foreach ($toAdd as $id) { - $result = $this->_insertTag($typeId, $id, $tag, $zeitraum[$id]['von'], $zeitraum[$id]['bis']); - if (isError($result)) { - return $result; - } + $this->_insertTag($typeId, $id, $tag, $zeitraum[$id]['von'], $zeitraum[$id]['bis']); $countAdded++; - //$tagged[] = $result->retval[0]->notiz_id; //notiz_id + $tagged[] = $id; } @@ -169,7 +165,6 @@ class TagLib } $countDeleted++; - //$deleted[] = $result->retval['deleted']; //notizId $deleted[] = $id; } @@ -321,46 +316,6 @@ class TagLib return success($return); } - public function checkForDeleteDEPR($tag, $typeId, $id, $start, $ende) - { - //TODO Zeitbezug - $return = null; - $notiz_id = null; - - $_ci = get_instance(); - $_ci->addMeta( - 'in checkForDelete', $tag - ); - - if (!is_numeric($id)) - return error ("id " . $id . "not numeric"); - - $result = $this->_ci->NotizModel->checkIfValidTag($tag, $typeId, $id, $start, $ende); - if (isError($result)) { - return error('Error checking valid tag for ' . $typeId . ': ' . $id); - } - - if(hasData($result)) - { - $notiz_id = $result->retval[0]->notiz_id; - $_ci = get_instance(); - $_ci->addMeta( - 'checkDeleteHas DAta', $notiz_id - ); - } - else - return null; - - if($notiz_id) - { - $_ci->addMeta( - 'TO DELETE', $notiz_id - ); - $result = $this->_deleteTag($notiz_id); - } - return ['deleted' => $result]; - } - private function _insertTag($typeId, $id, $tag, $von, $bis) { $resultInsert = $this->_ci->NotizModel->insert([ diff --git a/public/js/components/DetailHeader/DetailHeader.js b/public/js/components/DetailHeader/DetailHeader.js index 486f363d9..3f81c3134 100644 --- a/public/js/components/DetailHeader/DetailHeader.js +++ b/public/js/components/DetailHeader/DetailHeader.js @@ -102,7 +102,7 @@ export default { } else if (this.typeHeader === 'mitarbeiter') { if (!this.person_id || !this.mitarbeiter_uid || !this.domain) { throw new Error( - '[DetailHeader] "person_id", "mitarbeiter_uid", and "domain" are requried.' + '[DetailHeader] "person_id", "mitarbeiter_uid", and "domain" are required.' ) } this.loadHeaderData(this.person_id, this.mitarbeiter_uid); diff --git a/public/js/components/Stv/Studentenverwaltung/List.js b/public/js/components/Stv/Studentenverwaltung/List.js index ae7a577ee..19cb451ae 100644 --- a/public/js/components/Stv/Studentenverwaltung/List.js +++ b/public/js/components/Stv/Studentenverwaltung/List.js @@ -648,7 +648,6 @@ export default { // TODO(chris): filter component column chooser has no accessibilty features template: `
- test manu: currentSEM: {{semesterDates.start}} - {{semesterDates.ende}}
Date: Mon, 11 May 2026 13:18:56 +0200 Subject: [PATCH 26/28] add tagFilter for semester to students endpoint, add decoding jsonResult in Tags --- .../api/frontend/v1/stv/Students.php | 51 +++++++++++++++---- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/application/controllers/api/frontend/v1/stv/Students.php b/application/controllers/api/frontend/v1/stv/Students.php index f87e527e0..b5ad79cf0 100644 --- a/application/controllers/api/frontend/v1/stv/Students.php +++ b/application/controllers/api/frontend/v1/stv/Students.php @@ -147,7 +147,7 @@ class Students extends FHCAPI_Controller $data = $this->getDataOrTerminateWithError($result); - + $this->decodeTagsJsonInResult($data); $this->terminateWithSuccess($data); } @@ -214,7 +214,7 @@ class Students extends FHCAPI_Controller $data = $this->getDataOrTerminateWithError($result); - + $this->decodeTagsJsonInResult($data); $this->terminateWithSuccess($data); } @@ -267,7 +267,7 @@ class Students extends FHCAPI_Controller $data = $this->getDataOrTerminateWithError($result); - + $this->decodeTagsJsonInResult($data); $this->terminateWithSuccess($data); } @@ -474,7 +474,7 @@ class Students extends FHCAPI_Controller $result = $this->PrestudentModel->loadWhere($where); $data = $this->getDataOrTerminateWithError($result); - + $this->decodeTagsJsonInResult($data); $this->terminateWithSuccess($data); } @@ -628,10 +628,22 @@ class Students extends FHCAPI_Controller $result = $this->PrestudentModel->loadWhere($where); $data = $this->getDataOrTerminateWithError($result); - + $this->decodeTagsJsonInResult($data); $this->terminateWithSuccess($data); } + protected function decodeTagsJsonInResult(&$data) + { + if(defined('STV_TAGS_ENABLED') && STV_TAGS_ENABLED) { + array_walk($data, function($item, $key) { + if(isset($item->tags)) + { + $item->tags = json_decode($item->tags); + } + }); + } + } + /** * @param string $prestudent_id * @@ -676,7 +688,7 @@ class Students extends FHCAPI_Controller ]); $data = $this->getDataOrTerminateWithError($result); - + $this->decodeTagsJsonInResult($data); $this->terminateWithSuccess($data); } @@ -719,7 +731,7 @@ class Students extends FHCAPI_Controller ]); $data = $this->getDataOrTerminateWithError($result); - + $this->decodeTagsJsonInResult($data); $this->terminateWithSuccess($data); } @@ -761,7 +773,7 @@ class Students extends FHCAPI_Controller ]); $data = $this->getDataOrTerminateWithError($result); - + $this->decodeTagsJsonInResult($data); $this->terminateWithSuccess($data); } @@ -836,7 +848,7 @@ class Students extends FHCAPI_Controller $result = $this->PrestudentModel->load(); $data = $this->getDataOrTerminateWithError($result); - + $this->decodeTagsJsonInResult($data); $this->terminateWithSuccess($data); } @@ -878,12 +890,31 @@ class Students extends FHCAPI_Controller n.text AS notiz, nt.style, n.erledigt AS done, - nz.prestudent_id + nz.prestudent_id, + n.start, + n.ende FROM public.tbl_notizzuordnung AS nz JOIN public.tbl_notiz AS n ON nz.notiz_id = n.notiz_id JOIN public.tbl_notiz_typ AS nt ON n.typ = nt.typ_kurzbz " . $whereTags . " + WHERE + COALESCE(n.start, '1970-01-01') <= ( + SELECT + ende + FROM + public.tbl_studiensemester + WHERE + studiensemester_kurzbz = '{$studiensemester_kurzbz}' + ) + AND COALESCE(n.ende, '2170-12-31') >= ( + SELECT + start + FROM + public.tbl_studiensemester + WHERE + studiensemester_kurzbz = '{$studiensemester_kurzbz}' + ) ) AS tag GROUP BY tag.prestudent_id ) AS tag_data_agg From 368eded1fdb36ed144b2827b2c17668f154f5c14 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Mon, 11 May 2026 15:12:53 +0200 Subject: [PATCH 27/28] remove frontend filtering list for studiensemester, update logs TagJob --- application/controllers/jobs/TagJob.php | 14 ++- application/core/Tag_Controller.php | 19 --- public/js/api/factory/stv/tag.js | 8 -- .../Stv/Studentenverwaltung/List.js | 51 +------- public/js/tabulator/formatter/tags.js | 119 +++--------------- 5 files changed, 26 insertions(+), 185 deletions(-) diff --git a/application/controllers/jobs/TagJob.php b/application/controllers/jobs/TagJob.php index 5a04204d7..d12231b06 100644 --- a/application/controllers/jobs/TagJob.php +++ b/application/controllers/jobs/TagJob.php @@ -34,7 +34,7 @@ class TagJob extends JOB_Controller public function rebuildAutomatedTags() { - $this->logInfo('Start Job rebuild Automated Tags'); + $automatedTagsRes = $this->NotiztypModel->loadWhere(array('automatisiert' => true, 'taglib IS NOT NULL' => null)); $automatedTags = hasData($automatedTagsRes) ? getData($automatedTagsRes) : []; @@ -43,12 +43,14 @@ class TagJob extends JOB_Controller $result = $this->StudiensemesterModel->getAktOrNextSemester(); if (isError($result)) { + $this->logInfo('Start Job rebuild Automated Tags'); $this->logError('Error occurred during retrieving studiensemester'); return $this->logInfo('End Job rebuild Automated Tags'); } if (empty($result->retval) || !isset($result->retval[0])) { - $this->logInfo('No Studiensemester found'); + $this->logInfo('Start Job rebuild Automated Tags'); + $this->logError('No Studiensemester found'); return $this->logInfo('End Job rebuild Automated Tags'); } $studiensemester_kurzbz = $result->retval[0]->studiensemester_kurzbz ?? null; @@ -56,6 +58,7 @@ class TagJob extends JOB_Controller 'studiensemester_kurzbz' => $studiensemester_kurzbz ); + $this->logInfo('Start Job rebuild Automated Tags ' . $studiensemester_kurzbz); foreach($automatedTags as $autoTag) { // getPath: must not be lost @@ -64,7 +67,7 @@ class TagJob extends JOB_Controller if(file_exists($filePath)) { require_once($filePath); } else { - $this->logInfo("File not found: " . $filePath . PHP_EOL); + $this->logInfo("File not found: " . $filePath); continue; } @@ -93,9 +96,8 @@ class TagJob extends JOB_Controller $data = is_array($result) ? $result['retval'] : $result->retval; - //PRINT OUTPUT CONSOLE //SUMMARY - $this->logInfo("Tag " . $result->retval['input']['tag'] . " | TYPE_ID " . $typeId . " --" + $this->logInfo("Tag " . $result->retval['input']['tag'] . " | type_id " . $typeId . " --" . " Count Recycled: " . $result->retval['summary']['recycled'] . " Count Added: ". $result->retval['summary']['added'] . " Count Deleted: ". $result->retval['summary']['deleted']); @@ -109,7 +111,7 @@ class TagJob extends JOB_Controller $this->logInfo("Tag " . $result->retval['input']['tag'] . "Recycled tag(s): " . implode(', ', $result->retval['results']['retaggedIds'])); } - $this->logInfo( PHP_EOL . "End Job rebuild Automated Tags"); + $this->logInfo( "End Job rebuild Automated Tags"); } } diff --git a/application/core/Tag_Controller.php b/application/core/Tag_Controller.php index 09f42922c..fb14563ba 100644 --- a/application/core/Tag_Controller.php +++ b/application/core/Tag_Controller.php @@ -19,7 +19,6 @@ class Tag_Controller extends FHCAPI_Controller 'doneTag' => self::BERECHTIGUNG_KURZBZ, 'deleteTag' => self::BERECHTIGUNG_KURZBZ, 'getAllTags' => self::BERECHTIGUNG_KURZBZ, - 'getAllStartAndEndAutomatedTags' => self::BERECHTIGUNG_KURZBZ, 'rebuildTagsForTypeId' => self::BERECHTIGUNG_KURZBZ, ]; @@ -351,24 +350,6 @@ class Tag_Controller extends FHCAPI_Controller $this->terminateWithSuccess($result); } - public function getAllStartAndEndAutomatedTags() - { - $this->NotizModel->addSelect('notiz_id as id'); - $this->NotizModel->addSelect('start'); - $this->NotizModel->addSelect('ende'); - $this->NotizModel->addSelect('typ'); - - $result = $this->NotizModel->loadWhere(array( - 'titel' => 'TAG', - 'verfasser_uid' => 'sftest' - )); - - if (isError($result)) - return error('Error occurred during retrieving intervalls automated tags'); - $data = getData($result); - $this->terminateWithSuccess($data); - } - private function _setAuthUID() { $this->_uid = getAuthUID(); diff --git a/public/js/api/factory/stv/tag.js b/public/js/api/factory/stv/tag.js index 522dfa3ff..4a22a009e 100644 --- a/public/js/api/factory/stv/tag.js +++ b/public/js/api/factory/stv/tag.js @@ -52,7 +52,6 @@ export default { }; }, - //TODO check if necessary to expand to other idTypes getAllTagsPrestudent(prestudent_id){ return { method: 'get', @@ -61,13 +60,6 @@ export default { }; }, - getAllStartAndEndAutomatedTags(){ - return { - method: 'get', - url: 'api/frontend/v1/stv/Tags/getAllStartAndEndAutomatedTags', - }; - }, - rebuildTagsforTypeId(data){ return { method: 'post', diff --git a/public/js/components/Stv/Studentenverwaltung/List.js b/public/js/components/Stv/Studentenverwaltung/List.js index 19cb451ae..480004f8c 100644 --- a/public/js/components/Stv/Studentenverwaltung/List.js +++ b/public/js/components/Stv/Studentenverwaltung/List.js @@ -237,8 +237,7 @@ export default { dragSource: [], oldScrollUrl: '', oldScrollLeft: 0, - oldScrollTop: 0, - intervalMap: {} + oldScrollTop: 0 } }, computed: { @@ -292,15 +291,10 @@ export default { .replace(/\//g, '_'); return "StudentList_" + today + ".csv"; }, - semesterDates(){ - return this.lists.studiensemester?.find(item => item.studiensemester_kurzbz === this.currentSemester) || {}; - } }, created: function() { if(this.tagsEnabled) { - this.loadIntervals(); //preload - const coltags = { title: 'Tags', field: 'tags', @@ -308,36 +302,7 @@ export default { headerFilter: "input", headerFilterFunc: tagHeaderFilter, headerFilterFuncParams: {field: 'tags'}, - //formatter: (cell) => tagFormatter(cell, this.$refs.tagComponent), //prev. Version without filter - formatter: (cell) => { - const raw = cell.getValue(); - - const tags = - Array.isArray(raw) - ? raw - : (typeof raw === 'string' - ? JSON.parse(raw) - : []); - - const id = tags?.[0]?.id; - - const interval = id - ? this.intervalMap[id] - : null; - - const enrichedTags = { - tags: tags, - start: interval?.start || null, - ende: interval?.ende || null, - }; - - return tagFormatter( - enrichedTags, - this.$refs?.tagComponent, - this.semesterDates?.start, - this.semesterDates?.ende - ); - }, + formatter: (cell) => tagFormatter(cell, this.$refs.tagComponent), width: 150, }; this.tabulatorOptions.columns.splice(2, 0, coltags); @@ -351,18 +316,6 @@ export default { }, }, methods: { - loadIntervals() { - return this.$api - .call(ApiTag.getAllStartAndEndAutomatedTags()) - .then(result => { - const data = result.data || []; - this.intervalMap = {}; - data.forEach(item => { - this.intervalMap[item.id] = item; - }); - }) - .catch(this.$fhcAlert.handleSystemError); - }, translateTabulator() { this.$p .loadCategory(['global', 'person', 'lehre', 'ui', 'profilUpdate', 'admission', 'stv']) diff --git a/public/js/tabulator/formatter/tags.js b/public/js/tabulator/formatter/tags.js index d9a5244fd..367a8a5fb 100644 --- a/public/js/tabulator/formatter/tags.js +++ b/public/js/tabulator/formatter/tags.js @@ -1,115 +1,34 @@ -export function tagFormatter( - cell, - tagComponent, - semesterStart = null, - semesterEnd = null -) { - - // support both call versions - // 1. previous Tabulator cell: old version - // 2. custom enriched object: with start and end for tags plus semesterDates - // for check if valid tag - - const isTabulatorCell = - cell && typeof cell.getValue === 'function'; - - const normalized = isTabulatorCell - ? { - tags: cell.getValue() || [], - start: null, - ende: null, - rowData: cell.getRow().getData(), - } - : { - tags: cell.tags || [], - start: cell.start || null, - ende: cell.ende || null, - rowData: cell.rowData || {}, - }; - - const tags = normalized.tags || []; - - if (!tags.length) { - return ""; - } - +export function tagFormatter(cell, tagComponent) +{ const mappedData = tagComponent.tags.map(tag => ({ typ_kurzbz: tag.tag_typ_kurzbz, - automatisiert: tag.automatisiert, - validFrom: normalized.start - ? new Date(normalized.start) - : null, - validTo: normalized.ende - ? new Date(normalized.ende) - : null + automatisiert: tag.automatisiert })); - const hasSemesterFilter = - !!(semesterStart && semesterEnd); - const semStart = hasSemesterFilter ? new Date(semesterStart) : null; - - const semEnd = hasSemesterFilter ? new Date(semesterEnd) : null; - - const isInSemester = (tag) => { - - if (!hasSemesterFilter) { - return true; - } - - if (!tag.validFrom && !tag.validTo) { - return true; - } - - if (tag.validFrom && tag.validTo) { - return ( - tag.validFrom <= semEnd && - tag.validTo >= semStart - ); - } - - if (tag.validFrom && !tag.validTo) { - return tag.validFrom <= semEnd; - } - - if (!tag.validFrom && tag.validTo) { - return tag.validTo >= semStart; - } - - return false; - }; - - // parse tags if needed - let parsedTags = - typeof tags === 'string' - ? JSON.parse(tags) - : tags; + let tags = cell.getValue(); + if (!tags) return; let container = document.createElement('div'); container.className = "d-flex gap-1"; + let parsedTags = []; + if (typeof tags === 'string') { + parsedTags = JSON.parse(tags); + } else if (Array.isArray(tags)) { + parsedTags = tags; + } + let maxVisibleTags = 2; - const rowData = normalized.rowData; - + const rowData = cell.getRow().getData(); if (rowData._tagExpanded === undefined) { rowData._tagExpanded = false; } const renderTags = () => { container.innerHTML = ''; - - parsedTags = parsedTags.filter(tag => { - const mapped = mappedData.find( - m => m.typ_kurzbz === tag.typ_kurzbz - ); - - if (!mapped) { - return true; - } - - return isInSemester(mapped); - }); + parsedTags = parsedTags.filter(item => item !== null); parsedTags.sort((a, b) => { let adone = a.done ? 1 : 0; @@ -121,14 +40,10 @@ export function tagFormatter( } return b.id - a.id; }); - - const tagsToShow = rowData._tagExpanded - ? parsedTags - : parsedTags.slice(0, maxVisibleTags); + const tagsToShow = rowData._tagExpanded ? parsedTags : parsedTags.slice(0, maxVisibleTags); tagsToShow.forEach(tag => { if (!tag) return; - let tagElement = document.createElement('span'); tagElement.innerText = tag.beschreibung; tagElement.title = tag.notiz; @@ -151,10 +66,8 @@ export function tagFormatter( container.appendChild(tagElement); }); - // show expand button - if ( parsedTags.length > maxVisibleTags) { + if (parsedTags.length > maxVisibleTags) { let toggle = document.createElement('button'); - toggle.innerText = (rowData._tagExpanded ? '- ' : '+ ') + (parsedTags.length - maxVisibleTags); toggle.className = "display_all"; toggle.title = rowData._tagExpanded ? "Tags ausblenden" : "Tags einblenden"; From 1b822fc8f846464079b7300cdd79623368b08fe3 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Mon, 11 May 2026 15:15:06 +0200 Subject: [PATCH 28/28] reset config stv to readonly for automated tags --- application/config/stv.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/application/config/stv.php b/application/config/stv.php index 4ca40f62b..3090e3f2e 100644 --- a/application/config/stv.php +++ b/application/config/stv.php @@ -142,12 +142,12 @@ $config['stv_prestudent_tags'] = [ 'finished_stg' => ['readonly' => false], 'finished_kf' => ['readonly' => false], 'inwork_kf' => ['readonly' => false], - 'dd_auto' => ['readonly' => false], + 'dd_auto' => ['readonly' => true], 'wh_auto' => ['readonly' => true], 'prewh_auto' => ['readonly' => true], - 'out_auto' => ['readonly' => false], + 'out_auto' => ['readonly' => true], 'zgv_auto' => ['readonly' => true], - 'unterbrecher_auto' => ['readonly' => false], + 'unterbrecher_auto' => ['readonly' => true], 'stbtr_erh_auto' => ['readonly' => true], - 'jgv_auto' => ['readonly' => false], + 'jgv_auto' => ['readonly' => true], ];