diff --git a/application/controllers/Cis/ProfilUpdate.php b/application/controllers/Cis/ProfilUpdate.php index df7dd4ae8..a16248a3b 100755 --- a/application/controllers/Cis/ProfilUpdate.php +++ b/application/controllers/Cis/ProfilUpdate.php @@ -12,6 +12,7 @@ class ProfilUpdate extends Auth_Controller public function __construct(){ parent::__construct([ 'index' => ['student/stammdaten:r','mitarbeiter/stammdaten:r'], + 'id' => ['student/stammdaten:r','mitarbeiter/stammdaten:r'], 'getProfilUpdateWithPermission' => ['student/stammdaten:r','mitarbeiter/stammdaten:r'], 'acceptProfilRequest'=>['student/stammdaten:rw','mitarbeiter/stammdaten:rw'], 'denyProfilRequest'=>['student/stammdaten:rw','mitarbeiter/stammdaten:rw'], @@ -25,6 +26,7 @@ class ProfilUpdate extends Auth_Controller 'getProfilRequestFiles' => ['student/anrechnung_beantragen:r', 'user:r'], + ]); @@ -51,6 +53,9 @@ class ProfilUpdate extends Auth_Controller $this->load->view('Cis/ProfilUpdate'); } + public function id($profil_update_id=null){ + $this->load->view('Cis/ProfilUpdate',['profil_update_id'=>$profil_update_id]); + } private function sendEmail_onProfilUpdate_response($uid,$topic,$status){ @@ -60,15 +65,15 @@ class ProfilUpdate extends Auth_Controller //? translation of the english version of the status to german $status_de = $status == 'accepted' ? 'akzeptiert' : 'abgelehnt'; - $mail_res = sendSanchoMail("profil_update_response",['topic'=>$topic,'status_de'=>$status_de,'status_en'=>$status,'href'=>'https://c3p0.ma0594.technikum-wien.at/fh-core/cis.php/Cis/Profil'],$email,("Profil Änderung ".$status)); + $mail_res = sendSanchoMail("profil_update_response",['topic'=>$topic,'status_de'=>$status_de,'status_en'=>$status,'href'=>APP_ROOT.'Cis/Profil'],$email,("Profil Änderung ".$status)); if(!$mail_res){ show_error("failed to send email to " . $email); } - var_dump($mail_res); } - private function sendEmail_onProfilUpdate_insertion($uid,$topic){ + private function sendEmail_onProfilUpdate_insertion($uid,$profil_update_id,$topic){ + $this->load->helper('hlp_sancho_helper'); $emails = []; @@ -125,7 +130,7 @@ class ProfilUpdate extends Auth_Controller $mail_res =[]; //? sending email foreach($emails as $email){ - array_push($mail_res,sendSanchoMail("profil_update",['uid'=>$uid,'topic'=>$topic,'href'=>'https://c3p0.ma0594.technikum-wien.at/fh-core/cis.php/Cis/ProfilUpdate'],$email,("Profil Änderung von ".$uid))); + array_push($mail_res,sendSanchoMail("profil_update",['uid'=>$uid,'topic'=>$topic,'href'=>APP_ROOT.'Cis/ProfilUpdate/id/'.$profil_update_id],$email,("Profil Änderung von ".$uid))); } foreach($mail_res as $m_res){ if(!$m_res){ @@ -153,7 +158,7 @@ class ProfilUpdate extends Auth_Controller { // Get file to be downloaded from DMS $newFilename= $this->uid."/document_".$dms_id; - $download = $this->dmslib->download($dms_id, $newFilename); + $download = $this->dmslib->download($dms_id); if (isError($download)) return $download; // Download file @@ -219,6 +224,7 @@ class ProfilUpdate extends Auth_Controller ]; $tmp_res=$this->dmslib->upload($dms , 'files', array("jpg", "png", "pdf")); + $tmp_res = hasData($tmp_res)? getData($tmp_res) : null; array_push($res,$tmp_res); } @@ -292,6 +298,7 @@ class ProfilUpdate extends Auth_Controller public function insertProfilRequest() { + $json = json_decode($this->input->raw_input_stream); $payload = $json->payload; @@ -354,7 +361,7 @@ class ProfilUpdate extends Auth_Controller $insertID = hasData($insertID)? getData($insertID): null; //? sends emails to the correspondents of the $uid - $this->sendEmail_onProfilUpdate_insertion($this->uid,$json->topic); + $this->sendEmail_onProfilUpdate_insertion($this->uid,$insertID,$json->topic); echo json_encode(success($insertID)); } } @@ -374,6 +381,7 @@ class ProfilUpdate extends Auth_Controller //catch error }else{ $updateID = hasData($updateID)? getData($updateID)[0]: null; + //TODO: should an email be sent to the responsable people when the user changes his profil update echo json_encode(success($updateID)); } } diff --git a/application/views/Cis/ProfilUpdate.php b/application/views/Cis/ProfilUpdate.php index 1c50bf458..ff303b159 100755 --- a/application/views/Cis/ProfilUpdate.php +++ b/application/views/Cis/ProfilUpdate.php @@ -8,8 +8,9 @@ $includesArray = ['title'=> 'Profil Änderungen', $this->load->view('templates/CISHTML-Header',$includesArray); ?> -
+
+
load->view('templates/CISHTML-Footer',$includesArray); ?> \ No newline at end of file diff --git a/public/js/apps/Cis/ProfilUpdateRequests.js b/public/js/apps/Cis/ProfilUpdateRequests.js index cfc824b90..5132b84bb 100755 --- a/public/js/apps/Cis/ProfilUpdateRequests.js +++ b/public/js/apps/Cis/ProfilUpdateRequests.js @@ -1,275 +1,19 @@ import fhcapifactory from "../api/fhcapifactory.js"; -import { CoreFilterCmpt } from "../../components/filter/Filter.js"; -import AcceptDenyUpdate from "../../components/Cis/ProfilUpdate/AcceptDenyUpdate.js"; -import Alert from "../../components/Bootstrap/Alert.js"; +import ProfilUpdateView from "../../components/Cis/ProfilUpdate/ProfilUpdateView.js"; Vue.$fhcapi = fhcapifactory; -const sortProfilUpdates = (ele1, ele2) => { - let result = 0; - if (ele1.status === "pending") { - result = -1; - } else if (ele1.status === "accepted") { - result = ele2.status === "rejected" ? -1 : 1; - } else { - result = 1; - } - //? if they have the same status the insert date is used for ordering - if (ele1.status === ele2.status) { - result = - new Date(ele2.insertamum.split(".").reverse().join("-")) - - new Date(ele1.insertamum.split(".").reverse().join("-")); - } - return result; -}; + const app = Vue.createApp({ components: { - CoreFilterCmpt, + ['profil-update-view']:ProfilUpdateView + }, data() { return { - showAll: false, - - profil_updates_table_options: { - ajaxURL: - FHC_JS_DATA_STORAGE_OBJECT.app_root + - FHC_JS_DATA_STORAGE_OBJECT.ci_router + - `/Cis/ProfilUpdate/`, - - ajaxURLGenerator: (url, config, params) => { - //? this function needs to be an array function in order to access the this properties of the Vue component - if (this.showAll) { - return url + "getProfilUpdateWithPermission"; - } else { - return url + "getProfilUpdateWithPermission/pending"; - } - }, - ajaxResponse: function (url, params, response) { - //url - the URL of the request - //params - the parameters passed with the request - //response - the JSON object returned in the body of the response. - //? sorts the response data from the backend - if (response) response.sort(sortProfilUpdates); - - return response; - }, - //? adds tooltip with the status message of a profil update request if its status is not pending - columnDefaults: { - tooltip: (e, cell, onRendered) =>{ - //e - mouseover event - //cell - cell component - //onRendered - onRendered callback registration function - let statusMessage = cell.getData().status_message; - let statusDate = cell.getData().status_timestamp; - let status = cell.getData().status; - if (!statusMessage) { - return null; - } - let el = document.createElement("div"); - el.classList.add("border", "border-dark"); - - let statusDateEl = document.createElement("span"); - statusDateEl.classList.add("d-block","mb-1"); - statusDateEl.innerHTML = - "Request was " + status + " on " + statusDate; - let statusMessageEl = document.createElement("span"); - statusMessageEl.innerHTML = "Status message: " + statusMessage; - - el.appendChild(statusDateEl); - el.appendChild(statusMessageEl); - return el; - }, - }, - rowContextMenu: (e, component) => { - let menu = []; - if (component.getData().status === "pending") { - menu.push( - { - label: " Accept Request", - action: (e, column) => { - Vue.$fhcapi.ProfilUpdate.acceptProfilRequest(column.getData()) - .then((res) => { - this.$refs.UpdatesTable.tabulator.setData(); - }) - .catch((e) => { - Alert.popup(Vue.h('div',{innerHTML:e.response.data})); - }); - }, - }, - { - separator: true, - }, - { - label: - " Deny Request", - action: (e, column) => { - Vue.$fhcapi.ProfilUpdate.denyProfilRequest( - column.getData() - ).then((res) => { - this.$refs.UpdatesTable.tabulator.setData(); - }).catch((e) => { - Alert.popup(Vue.h('div',{innerHTML:e.response.data})); - }); - }, - }, - { - separator: true, - }, - { - label: " Show Request", - action: (e, column) => { - this.showModal(column.getData()); - - }, - } - ); - } else { - menu.push({ - label: " Show Request", - action: (e, column) => { - this.showModal(column.getData()); - }, - }); - } - return menu; - }, - - height: 600, - layout: "fitColumns", - - columns: [ - { - title: "UID", - field: "uid", - minWidth: 200, - resizable: true, - headerFilter: true, - //responsive:0, - }, - { - title: "Name", - field: "name", - minWidth: 200, - resizable: true, - headerFilter: true, - //responsive:0, - }, - { - title: "Topic", - field: "topic", - resizable: true, - minWidth: 200, - headerFilter: true, - //responsive:0, - }, - { - title: "Insert Date", - field: "insertamum", - resizable: true, - headerFilter: true, - minWidth: 200, - //responsive:0, - }, - { - title: "Status", - field: "status", - hozAlign: "center", - headerFilter: true, - formatter: function (cell, para) { - switch (cell.getValue()) { - case "pending": - return "
pending
"; - case "accepted": - return "
accepted
"; - case "rejected": - return "
rejected
"; - default: - return "

default

"; - } - }, - - resizable: true, - minWidth: 200, - //responsive:0, - }, - { - title: "View", - formatter: function () { - return ""; - }, - resizable: true, - minWidth: 200, - hozAlign: "center", - cellClick: (e, cell) => { - //! function that is called when clicking on a row in the table - let cellData = cell.getRow().getData(); - this.showModal(cellData); - }, - //responsive:0, - }, - ], - }, - }; - }, - computed: { - getFetchUrl: function () { - let url = - FHC_JS_DATA_STORAGE_OBJECT.app_root + - FHC_JS_DATA_STORAGE_OBJECT.ci_router + - `/Cis/ProfilUpdate/`; - if (this.showAll) { - url + "getAllRequests"; - } else { - url + "getPendingRequests"; - } - return url; - }, - }, - methods: { - showModal: function (value) { - AcceptDenyUpdate.popup({ value: value }) - .then((res) => { - - //? refetches the data, if any request was denied or accepted - //* setData will call the ajaxURL again to refresh the data - this.$refs.UpdatesTable.tabulator.setData(); - }).catch(err=>{ - - }) - - }, - updateData: function (event) { - this.$refs.UpdatesTable.tabulator.setData(); - //? store the selected view in the session storage of the browser - sessionStorage.setItem("showAll", event.target.value); - }, - }, - mounted() { - - if (!(sessionStorage.getItem("showAll") === null)) { - //? converting string into a boolean: https://sentry.io/answers/how-can-i-convert-a-string-to-a-boolean-in-javascript/ - this.showAll = sessionStorage.getItem("showAll")==="true"; - } }, - template: ` -
-
-
Show
- - - -
- - - - - -
`, }); app.mount("#content"); diff --git a/public/js/components/Cis/Profil/EditProfil.js b/public/js/components/Cis/Profil/EditProfil.js index d72925639..9fac1ffbe 100755 --- a/public/js/components/Cis/Profil/EditProfil.js +++ b/public/js/components/Cis/Profil/EditProfil.js @@ -114,6 +114,7 @@ export default { await Vue.$fhcapi.ProfilUpdate.insertFile(formData,this.editData.updateID).then(res => { return res.data?.map((file) => file.dms_id); }) + : //? fresh insert of new attachment await Vue.$fhcapi.ProfilUpdate.insertFile(formData).then(res => { diff --git a/public/js/components/Cis/Profil/MitarbeiterProfil.js b/public/js/components/Cis/Profil/MitarbeiterProfil.js index 818858473..96587dd1c 100755 --- a/public/js/components/Cis/Profil/MitarbeiterProfil.js +++ b/public/js/components/Cis/Profil/MitarbeiterProfil.js @@ -243,7 +243,6 @@ export default { }, template: /*html*/` -
test
diff --git a/public/js/components/Cis/ProfilUpdate/ProfilUpdateView.js b/public/js/components/Cis/ProfilUpdate/ProfilUpdateView.js new file mode 100644 index 000000000..e04bf321b --- /dev/null +++ b/public/js/components/Cis/ProfilUpdate/ProfilUpdateView.js @@ -0,0 +1,297 @@ + +import { CoreFilterCmpt } from "../../filter/Filter.js"; +import AcceptDenyUpdate from "./AcceptDenyUpdate.js"; +import Alert from "../../../components/Bootstrap/Alert.js"; + + +const sortProfilUpdates = (ele1, ele2) => { + let result = 0; + if (ele1.status === "pending") { + result = -1; + } else if (ele1.status === "accepted") { + result = ele2.status === "rejected" ? -1 : 1; + } else { + result = 1; + } + //? if they have the same status the insert date is used for ordering + if (ele1.status === ele2.status) { + result = + new Date(ele2.insertamum.split(".").reverse().join("-")) - + new Date(ele1.insertamum.split(".").reverse().join("-")); + } + return result; +}; + +export default{ + components: { + CoreFilterCmpt, + }, + props:{ + id:{ + type:Number, + } + }, + data() { + return { + + showAll: false, + events:[], + profil_update_id:Number(this.id), + profil_updates_table_options: { + + ajaxURL: + FHC_JS_DATA_STORAGE_OBJECT.app_root + + FHC_JS_DATA_STORAGE_OBJECT.ci_router + + `/Cis/ProfilUpdate/`, + + ajaxURLGenerator: (url, config, params) => { + //? this function needs to be an array function in order to access the this properties of the Vue component + if (this.showAll) { + return url + "getProfilUpdateWithPermission"; + } else { + return url + "getProfilUpdateWithPermission/pending"; + } + }, + ajaxResponse: function (url, params, response) { + //url - the URL of the request + //params - the parameters passed with the request + //response - the JSON object returned in the body of the response. + //? sorts the response data from the backend + if (response) response.sort(sortProfilUpdates); + + return response; + }, + //? adds tooltip with the status message of a profil update request if its status is not pending + columnDefaults: { + tooltip: (e, cell, onRendered) =>{ + //e - mouseover event + //cell - cell component + //onRendered - onRendered callback registration function + let statusMessage = cell.getData().status_message; + let statusDate = cell.getData().status_timestamp; + let status = cell.getData().status; + if (!statusMessage) { + return null; + } + let el = document.createElement("div"); + el.classList.add("border", "border-dark"); + + let statusDateEl = document.createElement("span"); + statusDateEl.classList.add("d-block","mb-1"); + statusDateEl.innerHTML = + "Request was " + status + " on " + statusDate; + let statusMessageEl = document.createElement("span"); + statusMessageEl.innerHTML = "Status message: " + statusMessage; + + el.appendChild(statusDateEl); + el.appendChild(statusMessageEl); + return el; + }, + }, + rowContextMenu: (e, component) => { + let menu = []; + if (component.getData().status === "pending") { + menu.push( + { + label: " Accept Request", + action: (e, column) => { + Vue.$fhcapi.ProfilUpdate.acceptProfilRequest(column.getData()) + .then((res) => { + this.$refs.UpdatesTable.tabulator.setData(); + }) + .catch((e) => { + Alert.popup(Vue.h('div',{innerHTML:e.response.data})); + }); + }, + }, + { + separator: true, + }, + { + label: + " Deny Request", + action: (e, column) => { + Vue.$fhcapi.ProfilUpdate.denyProfilRequest( + column.getData() + ).then((res) => { + this.$refs.UpdatesTable.tabulator.setData(); + }).catch((e) => { + Alert.popup(Vue.h('div',{innerHTML:e.response.data})); + }); + }, + }, + { + separator: true, + }, + { + label: " Show Request", + action: (e, column) => { + this.showModal(column.getData()); + + }, + } + ); + } else { + menu.push({ + label: " Show Request", + action: (e, column) => { + this.showModal(column.getData()); + }, + }); + } + return menu; + }, + + height: 600, + layout: "fitColumns", + + columns: [ + { + title: "UID", + field: "uid", + minWidth: 200, + resizable: true, + headerFilter: true, + //responsive:0, + }, + { + title: "Name", + field: "name", + minWidth: 200, + resizable: true, + headerFilter: true, + //responsive:0, + }, + { + title: "Topic", + field: "topic", + resizable: true, + minWidth: 200, + headerFilter: true, + //responsive:0, + }, + { + title: "Insert Date", + field: "insertamum", + resizable: true, + headerFilter: true, + minWidth: 200, + //responsive:0, + }, + { + title: "Status", + field: "status", + hozAlign: "center", + headerFilter: true, + formatter: function (cell, para) { + switch (cell.getValue()) { + case "pending": + return "
pending
"; + case "accepted": + return "
accepted
"; + case "rejected": + return "
rejected
"; + default: + return "

default

"; + } + }, + + resizable: true, + minWidth: 200, + //responsive:0, + }, + { + title: "View", + formatter: function () { + return ""; + }, + resizable: true, + minWidth: 200, + hozAlign: "center", + cellClick: (e, cell) => { + //! function that is called when clicking on a row in the table + let cellData = cell.getRow().getData(); + this.showModal(cellData); + }, + //responsive:0, + }, + ], + }, + }; + }, + computed: { + getFetchUrl: function () { + let url = + FHC_JS_DATA_STORAGE_OBJECT.app_root + + FHC_JS_DATA_STORAGE_OBJECT.ci_router + + `/Cis/ProfilUpdate/`; + if (this.showAll) { + url + "getAllRequests"; + } else { + url + "getPendingRequests"; + } + return url; + }, + }, + methods: { + + showModal: function (value) { + AcceptDenyUpdate.popup({ value: value }) + .then((res) => { + + //? refetches the data, if any request was denied or accepted + //* setData will call the ajaxURL again to refresh the data + this.$refs.UpdatesTable.tabulator.setData(); + }).catch(err=>{ + + }) + + }, + updateData: function (event) { + this.$refs.UpdatesTable.tabulator.setData(); + //? store the selected view in the session storage of the browser + sessionStorage.setItem("showAll", event.target.value); + }, + }, + + mounted() { + + //? opens the AcceptDenyUpdate Modal if the a preselected profil_update_id was passed to the component (used for email links) + if(this.profil_update_id){ + + this.$refs.UpdatesTable.tabulator.on("dataProcessed", ()=>{ + const arrayRowData = this.$refs.UpdatesTable.tabulator.getData().filter(row => { + return row.profil_update_id === this.profil_update_id; + }); + if(arrayRowData.length){ + this.showModal(arrayRowData[0]); + } + }) + } + + + if (!(sessionStorage.getItem("showAll") === null)) { + //? converting string into a boolean: https://sentry.io/answers/how-can-i-convert-a-string-to-a-boolean-in-javascript/ + this.showAll = sessionStorage.getItem("showAll")==="true"; + + } + }, + template: ` +
+ +
+
Show
+ + + +
+ + + + + +
`, +};