adds topic field to the cis_profil_update table and changes the layout of the editProfil Modul

This commit is contained in:
SimonGschnell
2024-01-09 15:51:50 +01:00
parent 5b597dbc31
commit b1d8a2f5a4
7 changed files with 211 additions and 169 deletions
+31 -18
View File
@@ -70,17 +70,28 @@ class Profil extends Auth_Controller
public function editProfil()
{
$json = $this->input->raw_input_stream;
$json = json_decode($this->input->raw_input_stream);
$data = ["uid" => $this->uid, "requested_change" => $json, "change_timestamp" => "NOW()"];
$data = ["uid" => $this->uid, "requested_change" => json_encode($json->payload), "change_timestamp" => "NOW()", "topic"=>$json->topic];
//? gets all the requested changes from a user
$res = $this->ProfilChangeModel->loadWhere(["uid"=>$this->uid]);
$res = hasData($res) ? getData($res) : null;
//? checks if the user already made a request to change a topic
//! which is an constraint added to the public.tbl_cis_profil_update table
foreach($res as $update_request){
if($update_request->topic == $json->topic && $update_request->uid == $this->uid){
echo json_encode(error("uid and topic combination exists already"));
return;
}
}
$insert_res = $this->ProfilChangeModel->insert($data);
if(isError($insert_res)){
//catch error
@@ -504,13 +515,15 @@ class Profil extends Auth_Controller
}
//? querying if the user already has a pending profil information update request
/* $editData_res = $this->ProfilChangeModel->load([$this->uid]);
if(isError($editData_res)){
//? querying if the user has profil update requests
$profilUpdates = $this->ProfilChangeModel->loadWhere(["uid"=>$this->uid]);
if(isError($profilUpdates)){
//error handling
}else{
$editData_res = hasData($editData_res) ? getData($editData_res)[0] : null;
} */
//? array containing all the requested profil information changes from the current user
$profilUpdates = hasData($profilUpdates) ? getData($profilUpdates) : null;
}
$res = new stdClass();
$res->foto = $person_res->foto;
@@ -551,9 +564,8 @@ class Profil extends Auth_Controller
//telefon nummer von dem Standort
$res->standort_telefon = $telefon_res;
/* $res->editData = $editData_res? json_decode($editData_res->profil_data): null;
$res->editDataTimestamp = $editData_res? date_create($editData_res->change_timestamp)->format('d/m/Y') : null;
*/
$res->profilUpdates = $profilUpdates?: null;
return $res;
}
@@ -707,13 +719,15 @@ class Profil extends Auth_Controller
}
}
//? querying if the user already has a pending profil information update request
/* $editData_res = $this->ProfilChangeModel->load([$this->uid]);
if(isError($editData_res)){
//? querying if the user has profil update requests
$profilUpdates = $this->ProfilChangeModel->loadWhere(["uid"=>$this->uid]);
if(isError($profilUpdates)){
//error handling
}else{
$editData_res = hasData($editData_res) ? getData($editData_res)[0] : null;
} */
//? array containing all the requested profil information changes from the current user
$profilUpdates = hasData($profilUpdates) ? getData($profilUpdates) : null;
}
$res = new stdClass();
@@ -752,9 +766,8 @@ class Profil extends Auth_Controller
$res->mailverteiler = $mailverteiler_res;
/* $res->editData = $editData_res? json_decode($editData_res->profil_data): null;
$res->editDataTimestamp = $editData_res? date_create($editData_res->change_timestamp)->format('d/m/Y'): null;
*/
$res->profilUpdates = $profilUpdates?: null;
return $res;
+3 -2
View File
@@ -3,10 +3,11 @@ export default {
//! API Calls for Profil Views
editProfil: function(payload) {
editProfil: function(topic, payload) {
const url = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router+
`/Cis/Profil/editProfil`;
return axios.post(url,payload);
return axios.post(url,{topic, payload});
},
getEditProfil: function() {
+71 -117
View File
@@ -1,6 +1,6 @@
import BsModal from "../../Bootstrap/Modal.js";
import Alert from "../../Bootstrap/Alert.js";
const infos = {};
export default {
components: {
@@ -27,93 +27,50 @@ export default {
},
data() {
return {
selection: null,
propertySelection:true,
selectedProperty:null,
inputField:null,
detailSelection:false,
editData: this.value,
//? tracks what specific profil data was changed
changesData: {},
editTimestamp: this.timestamp,
selectionOrder: {firstSelect: true, secondSelect:false},
topic:null,
firstSelectedOption:null,
secondSelectedOption: null,
secondSelectedOptionIndex: null,
result: true,
info: null,
}
inputField:null,
editData: this.value,
//? tracks what specific profil data was changed
changesData: {},
editTimestamp: this.timestamp,
result: true,
info: null,
}
},
methods: {
formSelection: function(selection){
if(Array.isArray(selection)){
return ['a','b'];
}else if(typeof(selection) === 'object'){
console.log(selection);
return Object.keys(selection);
}else{
// it is not an array or and object
return null;
}
createDeepCopy: function(object){
//? using Vue.toRaw because deep clones with structuredClone can not be done on proxies
return structuredClone(Vue.toRaw(object));
},
updateData: function(event,key,ArrayKey,ObjectKey=null){
const cleanUpObjectProperties= () => {
Object.entries(this.changesData).forEach( ([property, value]) => { if(!Object.keys(value).length) delete this.changesData[property]; })
}
let newValue = event.target.value;
if(!this.changesData[key]){
Array.isArray(this.editData[key])? this.changesData[key] = [] : this.changesData[key] = {};
}
if(Array.isArray(this.editData[key])){
if(newValue.length > 0) this.editData[key][ArrayKey][ObjectKey]= newValue;
else this.editData[key][ArrayKey][ObjectKey]= null;
changeInput: function(event, inputField,index){
let newValue = event.target.value? event.target.value: null;
inputField[index] = newValue;
let Obj = {key:ArrayKey, new: this.editData[key][ArrayKey], old: JSON.parse(this.originalEditData)[key][ArrayKey]};
if(JSON.stringify(this.editData[key][ArrayKey]) === JSON.stringify(JSON.parse(this.originalEditData)[key][ArrayKey]) ){
this.changesData[key] = this.changesData[key].filter( arrayElement => arrayElement.key !== ArrayKey );
cleanUpObjectProperties();
}else{
if(!this.changesData[key].filter( arrayElement => arrayElement.key === ArrayKey ).length){
this.changesData[key].push(Obj);
}
}
}else{
if(newValue.length > 0) this.editData[key][ArrayKey]= newValue;
else this.editData[key][ArrayKey]= null;
let Obj = { new: this.editData[key][ArrayKey], old: JSON.parse(this.originalEditData)[key][ArrayKey]};
if(JSON.stringify(this.editData[key][ArrayKey]) === JSON.stringify(JSON.parse(this.originalEditData)[key][ArrayKey])){
delete this.changesData[key][ArrayKey];
cleanUpObjectProperties();
}else{
this.changesData[key][ArrayKey]= Obj;
}
}
},
submitProfilChange(){
//* only inserts new row if the inputField value is different from the original value
if(this.isInputFieldChanged && this.topic){
//? inserts new row in public.tbl_cis_profil_update
Vue.$fhcapi.UserData.editProfil(this.inputField).then((res)=>{
Vue.$fhcapi.UserData.editProfil(this.topic,this.inputField).then((res)=>{
this.result = {
editData: this.editData,
timestamp: res.data.retval,
@@ -129,54 +86,34 @@ export default {
//
});
}
},
},
computed: {
isInputFieldChanged: function(){
if(this.inputField){
return JSON.stringify(this.inputField) !== JSON.stringify(this.secondSelectedOption);
}
return false;
},
firstSelection(){
return Object.keys(this.value);
},
secondSelection(){
switch(this.selectedProperty){
case "Personen_Informationen": return Object.keys(this.editData[this.selectedProperty]);
case "Private_Kontakte": return this.editData[this.selectedProperty];
case "Private_Adressen": return this.editData[this.selectedProperty];
switch(this.firstSelectedOption){
case "Personen_Informationen": return Object.keys(this.editData[this.firstSelectedOption]);
case "Private_Kontakte": return this.editData[this.firstSelectedOption];
case "Private_Adressen": return this.editData[this.firstSelectedOption];
default: return [];
}
},
isEditDataChanged(){
return this.originalEditData != JSON.stringify(this.editData)
},
},
created() {
this.originalEditData = JSON.stringify(this.editData);
/*
if (infos[this.lehrveranstaltung_id]) {
this.info = infos[this.lehrveranstaltung_id];
} else {
axios
.get(
FHC_JS_DATA_STORAGE_OBJECT.app_root +
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
"/components/Cis/Mylv/Info/" +
this.studien_semester +
"/" +
this.lehrveranstaltung_id
)
.then((res) => {
this.info = infos[this.lehrveranstaltung_id] = res.data.retval || [];
})
.catch(() => (this.info = {}));
} */
},
mounted() {
this.modal = this.$refs.modalContainer.modal;
@@ -192,19 +129,35 @@ export default {
</template>
<template v-slot:default>
<!-- Breadcrumbs -->
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item" v-if="firstSelectedOption">{{firstSelectedOption}}</li>
<li class="breadcrumb-item" v-if="secondSelectedOption" >{{firstSelectedOption ==="Personen_Informationen" ? Object.keys(secondSelectedOption)[0] : secondSelectedOptionIndex+1 }}</li>
<!--<li class="breadcrumb-item" aria-current="page">Drei</li>-->
</ol>
</nav>
<select v-if="!selectedProperty" class="form-select" size="3" aria-label="size 3 select example">
<option @click="selectedProperty=option; " v-for="option in firstSelection" :value="option">{{option}}</option>
<select v-if="!firstSelectedOption" v-model="firstSelectedOption" class="form-select" size="3" aria-label="size 3 select example">
<option v-for="option in firstSelection" :value="option">{{option}}</option>
</select>
<select v-if="selectedProperty && !inputField" class="form-select" size="3" aria-label="size 3 select example">
<select v-if="firstSelectedOption && !secondSelectedOption" class="form-select" size="3" aria-label="size 3 select example">
<option @click="
if(Array.isArray(editData[selectedProperty])){
inputField=option
if(Array.isArray(editData[firstSelectedOption])){
secondSelectedOptionIndex = index;
secondSelectedOption = createDeepCopy(option);
inputField= createDeepCopy(option);
//* topic is the property in which the array is stored when it is an array
topic = firstSelectedOption;
}else{
inputField={[option]:editData[selectedProperty][option]};
}" v-for="option in secondSelection" :value="option"><div v-if="typeof(option)==='object'"><p v-for="(value,property) in option">{{property}}:{{value}}</p></div><template v-else>{{option}}</template></option>
secondSelectedOption={[option]:editData[firstSelectedOption][option]};
inputField={[option]:editData[firstSelectedOption][option]};
//* topic is the selected property if is an object
topic = option;
}" v-for="(option, index) in secondSelection" :value="option"><div v-if="typeof(option)==='object'"><span class="m-2 d-block" v-for="(value,property) in option">{{property}}:{{value}}</span></div><template v-else>{{option}}</template></option>
</select>
<div v-if="inputField">
<div v-for="(field,index) in inputField">
@@ -212,7 +165,7 @@ export default {
<div class="form-underline">
<div class="form-underline-titel">{{index}}</div>
<input class="form-control" :id="index" v-model="inputField[index]" :placeholder="field">
<input class="form-control" :id="index" :value="inputField[index]" @input="changeInput($event,inputField,index)" :placeholder="field">
</div>
</div>
@@ -225,9 +178,10 @@ export default {
</template>
<!-- optional footer -->
<template v-slot:footer>
<button class="btn btn-outline-danger " @click="hide">Abbrechen</button>
<p v-if="editTimestamp" class="flex-fill">Letzte Anfrage: {{editTimestamp}}</p>
<button @click="submitProfilChange" role="button" class="btn btn-primary">Senden</button>
<button v-if="isInputFieldChanged" @click="submitProfilChange" role="button" class="btn btn-primary">Senden</button>
</template>
<!-- end of optional footer -->
</bs-modal>`,
@@ -303,7 +303,7 @@ export default {
<!-- HIDDEN QUICK LINKS -->
<div class="d-md-none col-12 ">
<div class="row py-2">
<div class="row mb-3">
<div class="col">
<p class="m-0">
<div class="card">
@@ -328,8 +328,25 @@ export default {
</div>
</div>
<!-- HERE STARTS THE ROW WITH REQUESTED CHANGES FROM THE USER -->
<div class="row mb-3">
<div class="col">
<div class="card">
<div class="card-header">
Profil Informations Änderungen Anfragen</div>
<div class="card-body">
<p v-for="update in data.profilUpdates">{{update.requested_change}}</p>
</div>
<!-- END OF HIDDEN QUCK LINKS -->
</div>
</div>
</div>
</div>
<!-- END OF HIDDEN ROW (HIDDEN IN VIEWPORTS GREATER THEN-EQUAL MD) -->
@@ -771,8 +788,27 @@ export default {
<!-- START OF THE FIRDT ROW IN THE SIDE PANEL -->
<!-- THESE QUCK LINKS ARE ONLY VISIBLE UNTIL VIEWPORT MD -->
<div class="row d-none d-md-block mb-3">
<div class="col">
<div class="row d-none d-md-block mb-3">
<div class="col mb-3">
<div class="card">
<div class="card-header">
Something else
</div>
<div class="card-body">
<p v-for="update in data.profilUpdates">{{JSON.stringify(update)}}</p>
</div>
</div>
</div>
</div>
<div class="row d-none d-md-block mb-3">
<div class="col">
<div class="card">
<div class="card-header">
@@ -1,3 +1,60 @@
// Legacy function that constructed a result object where the old and the new versions of the changed data was stored
updateData: function(event,key,ArrayKey,ObjectKey=null){
const cleanUpObjectProperties= () => {
Object.entries(this.changesData).forEach( ([property, value]) => { if(!Object.keys(value).length) delete this.changesData[property]; })
}
let newValue = event.target.value;
if(!this.changesData[key]){
Array.isArray(this.editData[key])? this.changesData[key] = [] : this.changesData[key] = {};
}
if(Array.isArray(this.editData[key])){
if(newValue.length > 0) this.editData[key][ArrayKey][ObjectKey]= newValue;
else this.editData[key][ArrayKey][ObjectKey]= null;
let Obj = {key:ArrayKey, new: this.editData[key][ArrayKey], old: JSON.parse(this.originalEditData)[key][ArrayKey]};
if(JSON.stringify(this.editData[key][ArrayKey]) === JSON.stringify(JSON.parse(this.originalEditData)[key][ArrayKey]) ){
this.changesData[key] = this.changesData[key].filter( arrayElement => arrayElement.key !== ArrayKey );
cleanUpObjectProperties();
}else{
if(!this.changesData[key].filter( arrayElement => arrayElement.key === ArrayKey ).length){
this.changesData[key].push(Obj);
}
}
}else{
if(newValue.length > 0) this.editData[key][ArrayKey]= newValue;
else this.editData[key][ArrayKey]= null;
let Obj = { new: this.editData[key][ArrayKey], old: JSON.parse(this.originalEditData)[key][ArrayKey]};
if(JSON.stringify(this.editData[key][ArrayKey]) === JSON.stringify(JSON.parse(this.originalEditData)[key][ArrayKey])){
delete this.changesData[key][ArrayKey];
cleanUpObjectProperties();
}else{
this.changesData[key][ArrayKey]= Obj;
}
}
},
<!-- START OF THE ACCORDION
<pre>{{JSON.stringify(changesData,null,2)}}</pre>
+1 -1
View File
@@ -223,7 +223,7 @@ $tabellen=array(
"public.tbl_benutzerfunktion" => array("benutzerfunktion_id","fachbereich_kurzbz","uid","oe_kurzbz","funktion_kurzbz","semester", "datum_von","datum_bis", "updateamum","updatevon","insertamum","insertvon","ext_id","bezeichnung","wochenstunden"),
"public.tbl_benutzergruppe" => array("uid","gruppe_kurzbz","studiensemester_kurzbz","updateamum","updatevon","insertamum","insertvon","ext_id"),
"public.tbl_bewerbungstermine" => array("bewerbungstermin_id","studiengang_kz","studiensemester_kurzbz","beginn","ende","nachfrist","nachfrist_ende","anmerkung", "insertamum", "insertvon", "updateamum", "updatevon","studienplan_id","nationengruppe_kurzbz"),
"public.tbl_cis_profil_update" => array("profil_update_id","uid","requested_change","change_timestamp"),
"public.tbl_cis_profil_update" => array("profil_update_id","topic","uid","requested_change","change_timestamp"),
"public.tbl_buchungstyp" => array("buchungstyp_kurzbz","beschreibung","standardbetrag","standardtext","aktiv","credit_points"),
"public.tbl_dokument" => array("dokument_kurzbz","bezeichnung","ext_id","bezeichnung_mehrsprachig","dokumentbeschreibung_mehrsprachig","ausstellungsdetails"),
"public.tbl_dokumentprestudent" => array("dokument_kurzbz","prestudent_id","mitarbeiter_uid","datum","updateamum","updatevon","insertamum","insertvon","ext_id"),
+8 -27
View File
@@ -4,6 +4,7 @@
{
$qry = "CREATE TABLE public.tbl_cis_profil_update (
profil_update_id INTEGER NOT NULL,
topic VARCHAR(32) NOT NULL,
uid VARCHAR(32) NOT NULL,
requested_change jsonb NOT NULL,
change_timestamp TIMESTAMP NOT NULL,
@@ -16,8 +17,9 @@
NO MAXVALUE
NO MINVALUE
CACHE 1;
ALTER TABLE public.tbl_cis_profil_update ALTER COLUMN profil_update_id SET DEFAULT nextval('public.tbl_cis_profil_update_id_seq');
ALTER TABLE public.tbl_cis_profil_update ADD CONSTRAINT cis_profil_udpate_topic_uid_unique UNIQUE (uid,topic);
GRANT SELECT, INSERT, UPDATE, DELETE ON public.tbl_cis_profil_update TO vilesci;
GRANT SELECT, INSERT, UPDATE, DELETE ON public.tbl_cis_profil_update TO web;
@@ -31,35 +33,14 @@
echo '<br>public.tbl_cis_profil_update: table created';
}
/* else{
$qry = "DROP TABLE public.tbl_cis_profil_update;";
if(!$db->db_query($qry))
echo '<strong> was not able to delete public.tbl_cis_profil_update: '.$db->db_last_error().'</strong><br>';
else
echo '<br>public.tbl_cis_profil_update: table deleted';
} */
/* if($db->db_num_rows($result)==0)
{
$qry = "INSERT INTO public.tbl_cis_profil_update(uid, profil_data, profil_changes, change_timestamp) VALUES('ma0594','{\"test\":\"data\"}', NOW());";
if(!$db->db_query($qry))
echo '<strong>Prüfungstyp: '.$db->db_last_error().'</strong><br>';
else
echo '<br>test eintrag in public.tbl_cis_profil_update hinzugefügt';
} */
//! was used to add an extra column to the table after the table was already created
/*
if(!$result = @$db->db_query("SELECT profil_data FROM public.tbl_cis_profil_update LIMIT 1"))
//? would add a column if the column is missing in the table
/* if(!$result = @$db->db_query("SELECT topic FROM public.tbl_cis_profil_update LIMIT 1"))
{
$qry = "ALTER TABLE public.tbl_cis_profil_update ADD COLUMN profil_data jsonb;";
$qry = "ALTER TABLE public.tbl_cis_profil_update ADD COLUMN topic varchar(32) NOT NULL;";
if(!$db->db_query($qry))
echo '<strong>public.tbl_cis_profil_update: '.$db->db_last_error().'</strong><br>';
else
echo '<br>public.tbl_cis_profil_update: Spalte profil_data hinzugefuegt';
} */
echo '<br>public.tbl_cis_profil_update: Spalte topic hinzugefuegt';
} */