diff --git a/application/controllers/Cis/Profil.php b/application/controllers/Cis/Profil.php
index 77f6ffb07..83b8f5493 100644
--- a/application/controllers/Cis/Profil.php
+++ b/application/controllers/Cis/Profil.php
@@ -55,15 +55,16 @@ class Profil extends Auth_Controller
*/
public function index()
{
-
+
$this->load->library('ProfilLib');
$profil_data = $this->profillib->getView(getAuthUID());
$profil_data = hasData($profil_data) ? getData($profil_data) : null;
$viewData = array(
- 'editable'=>true,
+ 'editable' => true,
'profil_data' => $profil_data,
+ 'calendarSyncUrls' => $this->getCalendarSyncUrlData(),
);
- $this->load->view('CisRouterView/CisRouterView.php',['viewData' => $viewData, 'route' => 'profilIndex']);
+ $this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'profilIndex']);
}
/**
@@ -76,17 +77,17 @@ class Profil extends Auth_Controller
$this->load->library('ProfilLib');
$profil_data = $this->profillib->getView($uid);
$profil_data = hasData($profil_data) ? getData($profil_data) : null;
- $viewData = array (
+ $viewData = array(
'uid' => $uid,
- 'profil_data'=>$profil_data,
+ 'profil_data' => $profil_data,
'permissions' => [
'basis/other_lv_plan' => $this->permissionlib->isBerechtigt(('basis/other_lv_plan')),
]
);
- if($uid == getAuthUID()){
+ if ($uid == getAuthUID()) {
$viewData['editable'] = true;
}
- $this->load->view('CisRouterView/CisRouterView.php',['viewData' => $viewData, 'route' => 'profilViewUid']);
+ $this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'profilViewUid']);
}
/**
@@ -265,23 +266,23 @@ class Profil extends Auth_Controller
$this->GemeindeModel->addDistinct();
$this->GemeindeModel->addSelect(["name"]);
if ($nation == "A") {
- if (isset($zip) && $zip > 999 && $zip < 32000) {
+ if (isset($zip) && $zip > 999 && $zip < 32000) {
- $gemeinde_res = $this->GemeindeModel->loadWhere(['plz' => $zip]);
- if (isError($gemeinde_res)) {
- show_error("error while trying to query bis.tbl_gemeinde");
- }
- $gemeinde_res = hasData($gemeinde_res) ? getData($gemeinde_res) : null;
- $gemeinde_res = array_map(function ($obj) {
- return $obj->name;
- }, $gemeinde_res);
- echo json_encode($gemeinde_res);
-
- } else {
- echo json_encode(error("ortschaftskennziffer code was not valid"));
+ $gemeinde_res = $this->GemeindeModel->loadWhere(['plz' => $zip]);
+ if (isError($gemeinde_res)) {
+ show_error("error while trying to query bis.tbl_gemeinde");
}
+ $gemeinde_res = hasData($gemeinde_res) ? getData($gemeinde_res) : null;
+ $gemeinde_res = array_map(function ($obj) {
+ return $obj->name;
+ }, $gemeinde_res);
+ echo json_encode($gemeinde_res);
+
+ } else {
+ echo json_encode(error("ortschaftskennziffer code was not valid"));
+ }
} else {
- echo json_encode(error("Nation was not 'A' (Austria)"));
+ echo json_encode(error("Nation was not 'A' (Austria)"));
}
}
@@ -754,5 +755,29 @@ class Profil extends Auth_Controller
return $zutrittskarte_ausgegebenam;
}
-
+ /**
+ * gets the identifier, phrase, and url for each calendar sync option
+ * @access private
+ * @return array array of arrays, where each child array is a sync option
+ */
+ private function getCalendarSyncUrlData()
+ {
+ return [
+ [
+ "identifier" => "cal_dav",
+ "labelPhrase" => "profil/calendar_sync_cal_dav",
+ "url" => APP_ROOT . "webdav/lvplan.php/calendars/" . $this->uid . "/LVPlan-" . $this->uid,
+ ],
+ [
+ "identifier" => "cal_dav_principal",
+ "labelPhrase" => "profil/calendar_sync_cal_dav_principal",
+ "url" => APP_ROOT . "webdav/lvplan.php/principals/" . $this->uid,
+ ],
+ [
+ "identifier" => "i_cal",
+ "labelPhrase" => "profil/calendar_sync_i_cal",
+ "url" => APP_ROOT . "webdav/google.php?cal=" . encryptData($this->uid, LVPLAN_CYPHER_KEY) . "&" . microtime(true),
+ ],
+ ];
+ }
}
diff --git a/public/js/components/Cis/Profil/MitarbeiterProfil.js b/public/js/components/Cis/Profil/MitarbeiterProfil.js
index 98b5a822b..44e0ca6eb 100644
--- a/public/js/components/Cis/Profil/MitarbeiterProfil.js
+++ b/public/js/components/Cis/Profil/MitarbeiterProfil.js
@@ -9,6 +9,7 @@ import QuickLinks from "./ProfilComponents/QuickLinks.js";
import ProfilEmails from "./ProfilComponents/ProfilEmails.js";
import RoleInformation from "./ProfilComponents/RoleInformation.js";
import ProfilInformation from "./ProfilComponents/ProfilInformation.js";
+import CalendarSync from "./ProfilComponents/CalendarSync.js";
import ApiProfilUpdate from '../../../api/factory/profilUpdate.js';
import { dateFilter } from '../../../tabulator/filters/Dates.js';
@@ -26,6 +27,7 @@ export default {
ProfilEmails,
RoleInformation,
ProfilInformation,
+ CalendarSync,
},
inject: ["sortProfilUpdates", "collapseFunction", "language","isEditable"],
@@ -160,6 +162,7 @@ export default {
props: {
data: Object,
editData: Object,
+ calendarSyncUrls: Array,
},
methods: {
@@ -313,7 +316,6 @@ export default {
});
//? sorts the profil Updates: pending -> accepted -> rejected
this.data.profilUpdates?.sort(this.sortProfilUpdates);
-
},
watch: {
'data.funktionen'(newVal) {
@@ -489,12 +491,17 @@ export default {
-
diff --git a/public/js/components/Cis/Profil/Profil.js b/public/js/components/Cis/Profil/Profil.js
index c2d64982c..b5f3fd552 100644
--- a/public/js/components/Cis/Profil/Profil.js
+++ b/public/js/components/Cis/Profil/Profil.js
@@ -4,8 +4,8 @@ import ViewStudentProfil from "./StudentViewProfil.js";
import ViewMitarbeiterProfil from "./MitarbeiterViewProfil.js";
import Loading from "../../Loader.js";
-import ApiProfil from '../../../api/factory/profil.js';
-import ApiProfilUpdate from '../../../api/factory/profilUpdate.js';
+import ApiProfil from "../../../api/factory/profil.js";
+import ApiProfilUpdate from "../../../api/factory/profilUpdate.js";
Vue.$collapseFormatter = function (data) {
//data - an array of objects containing the column title and value for each cell
@@ -35,7 +35,7 @@ Vue.$collapseFormatter = function (data) {
};
export const Profil = {
- name: 'Profil',
+ name: "Profil",
components: {
StudentProfil,
MitarbeiterProfil,
@@ -46,11 +46,11 @@ export const Profil = {
props: {
uid: {
type: String,
- required:false,
+ required: false,
},
viewData: {
type: Object,
- }
+ },
},
data() {
return {
@@ -67,12 +67,12 @@ export const Profil = {
},
provide() {
return {
- isEditable: Vue.computed(()=>this.isEditable),
+ isEditable: Vue.computed(() => this.isEditable),
profilUpdateStates: Vue.computed(() =>
- this.profilUpdateStates ? this.profilUpdateStates : false
+ this.profilUpdateStates ? this.profilUpdateStates : false,
),
profilUpdateTopic: Vue.computed(() =>
- this.profilUpdateTopic ? this.profilUpdateTopic : false
+ this.profilUpdateTopic ? this.profilUpdateTopic : false,
),
setLoading: (newValue) => {
this.loading = newValue;
@@ -130,8 +130,12 @@ export const Profil = {
//? 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("-"));
+ new Date(
+ ele2.insertamum.split(".").reverse().join("-"),
+ ) -
+ new Date(
+ ele1.insertamum.split(".").reverse().join("-"),
+ );
}
return result;
},
@@ -157,11 +161,11 @@ export const Profil = {
.catch((error) => {
console.error(error);
});
-
-
+
this.$api
- .call(ApiProfil.profilViewData(this.$route.params.uid??null))
- .then((response) => response.data).then(data=>{
+ .call(ApiProfil.profilViewData(this.$route.params.uid ?? null))
+ .then((response) => response.data)
+ .then((data) => {
this.view = data?.profil_data.view;
this.data = data?.profil_data.data;
this.isEditable = data?.editable ?? false;
@@ -169,8 +173,6 @@ export const Profil = {
.catch((error) => {
console.error(error);
});
-
-
},
zustellAdressenCount() {
if (!this.data || !this.data.adressen) {
@@ -186,7 +188,7 @@ export const Profil = {
})
.map((adresse) => {
return adresse.requested_change.adresse_id;
- })
+ }),
);
}
@@ -197,8 +199,9 @@ export const Profil = {
.every((adresse) =>
this.data.profilUpdates.some(
(update) =>
- update.requested_change.adresse_id == adresse.adresse_id
- )
+ update.requested_change.adresse_id ==
+ adresse.adresse_id,
+ ),
)
) {
adressenArray = adressenArray.concat(
@@ -208,12 +211,11 @@ export const Profil = {
})
.map((adr) => {
return adr.adresse_id;
- })
+ }),
);
}
return [...new Set(adressenArray)];
-
},
zustellKontakteCount() {
if (!this.data || !this.data.kontakte) {
@@ -226,14 +228,17 @@ export const Profil = {
kontakteArray = kontakteArray.concat(
this.data.profilUpdates
.filter((update) => {
- return update.status === 'Pending' && update.requested_change.zustellung;
+ return (
+ update.status === "Pending" &&
+ update.requested_change.zustellung
+ );
})
.map((kontant) => {
return {
- kontakt_id: kontant.requested_change.kontakt_id,
- kontakttyp: kontant.requested_change.kontakttyp
- };
- })
+ kontakt_id: kontant.requested_change.kontakt_id,
+ kontakttyp: kontant.requested_change.kontakttyp,
+ };
+ }),
);
}
@@ -244,8 +249,10 @@ export const Profil = {
.every((kontakt) =>
this.data.profilUpdates.some(
(update) =>
- update.status === 'Pending' && update.requested_change.kontakt_id == kontakt.kontakt_id
- )
+ update.status === "Pending" &&
+ update.requested_change.kontakt_id ==
+ kontakt.kontakt_id,
+ ),
)
) {
kontakteArray = kontakteArray.concat(
@@ -255,10 +262,10 @@ export const Profil = {
})
.map((kon) => {
return {
- kontakt_id: kon.kontakt_id,
- kontakttyp: kon.kontakttyp
- };
- })
+ kontakt_id: kon.kontakt_id,
+ kontakttyp: kon.kontakttyp,
+ };
+ }),
);
}
@@ -266,7 +273,6 @@ export const Profil = {
},
},
computed: {
-
filteredEditData() {
if (!this.data) {
return;
@@ -330,8 +336,12 @@ export const Profil = {
// excludes all contacts that are already used in pending profil update requests
return !this.data.profilUpdates?.some(
(update) =>
- update.status === this.profilUpdateStates["Pending"] &&
- update.requested_change?.kontakt_id === item.kontakt_id
+ update.status ===
+ this.profilUpdateStates[
+ "Pending"
+ ] &&
+ update.requested_change?.kontakt_id ===
+ item.kontakt_id,
);
})
.map((kontakt) => {
@@ -347,12 +357,18 @@ export const Profil = {
topic: this.profilUpdateTopic?.["Private Adressen"],
data: this.data.adressen
?.filter((item) => {
- return !this.data.profilUpdates?.some((update) => {
- return (
- update.status === this.profilUpdateStates["Pending"] &&
- update.requested_change?.adresse_id == item.adresse_id
- );
- });
+ return !this.data.profilUpdates?.some(
+ (update) => {
+ return (
+ update.status ===
+ this.profilUpdateStates[
+ "Pending"
+ ] &&
+ update.requested_change
+ ?.adresse_id == item.adresse_id
+ );
+ },
+ );
})
.map((adresse) => {
return {
@@ -374,9 +390,9 @@ export const Profil = {
this.$refs.loadingModalRef.hide();
}
},
- uid (newVal, oldVal) {
- this.load()
- }
+ uid(newVal, oldVal) {
+ this.load();
+ },
},
created() {
this.load();
@@ -388,9 +404,14 @@ export const Profil = {
-
+
`,
-}
+};
-export default Profil
\ No newline at end of file
+export default Profil;
diff --git a/public/js/components/Cis/Profil/ProfilComponents/CalendarSync.js b/public/js/components/Cis/Profil/ProfilComponents/CalendarSync.js
new file mode 100644
index 000000000..9f0df6dd5
--- /dev/null
+++ b/public/js/components/Cis/Profil/ProfilComponents/CalendarSync.js
@@ -0,0 +1,52 @@
+export default {
+ name: "CalendarSync",
+ props: { uid: String, calendarSyncUrls: Array },
+ data() {
+ return {
+ syncInstructionsUrlWithoutParam:
+ FHC_JS_DATA_STORAGE_OBJECT.app_root +
+ "cms/content.php?content_id=",
+ };
+ },
+ methods: {
+ copyUrlToClipboard(url) {
+ navigator.clipboard.writeText(url);
+ this.$fhcAlert.alertSuccess(
+ this.$p.t("profil/calendar_sync_clipboard_copy_confirmation"),
+ );
+ },
+ },
+ template: `
+`,
+};
diff --git a/public/js/components/Cis/Profil/StudentProfil.js b/public/js/components/Cis/Profil/StudentProfil.js
index 638bb15b4..e3e90d3bf 100644
--- a/public/js/components/Cis/Profil/StudentProfil.js
+++ b/public/js/components/Cis/Profil/StudentProfil.js
@@ -9,6 +9,7 @@ import ProfilInformation from "./ProfilComponents/ProfilInformation.js";
import FetchProfilUpdates from "./ProfilComponents/FetchProfilUpdates.js";
import EditProfil from "./ProfilModal/EditProfil.js";
import QuickLinks from "./ProfilComponents/QuickLinks.js";
+import CalendarSync from "./ProfilComponents/CalendarSync.js";
import ApiProfilUpdate from '../../../api/factory/profilUpdate.js';
import { dateFilter } from '../../../tabulator/filters/Dates.js';
@@ -26,6 +27,7 @@ export default {
FetchProfilUpdates,
EditProfil,
QuickLinks,
+ CalendarSync,
},
inject: ["sortProfilUpdates", "collapseFunction", "language","isEditable"],
data() {
@@ -102,6 +104,7 @@ export default {
props: {
data: Object,
editData: Object,
+ calendarSyncUrls: Array,
},
provide() {
return {
@@ -426,13 +429,18 @@ export default {
-
diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php
index d7e6aab68..c1633bd9c 100644
--- a/system/phrasesupdate.php
+++ b/system/phrasesupdate.php
@@ -29562,7 +29562,8 @@ array(
'insertvon' => 'system'
)
)
- ), array(
+ ),
+ array(
'app' => 'core',
'category' => 'profil',
'phrase' => 'sem_short',
@@ -29582,6 +29583,126 @@ array(
)
)
),
+ array(
+ 'app' => 'core',
+ 'category' => 'profil',
+ 'phrase' => 'calendar_sync',
+ 'insertvon' => 'system',
+ 'phrases' => array(
+ array(
+ 'sprache' => 'German',
+ 'text' => 'Persönlichen LV-Plan abonnieren',
+ 'description' => '',
+ 'insertvon' => 'system'
+ ),
+ array(
+ 'sprache' => 'English',
+ 'text' => 'Subscribe to personal schedule',
+ 'description' => '',
+ 'insertvon' => 'system'
+ )
+ )
+ ),
+ array(
+ 'app' => 'core',
+ 'category' => 'profil',
+ 'phrase' => 'calendar_sync_instructions',
+ 'insertvon' => 'system',
+ 'phrases' => array(
+ array(
+ 'sprache' => 'German',
+ 'text' => 'Anleitung LV-Plan Synchronisation',
+ 'description' => '',
+ 'insertvon' => 'system'
+ ),
+ array(
+ 'sprache' => 'English',
+ 'text' => 'Instructions for synchronizing your schedule',
+ 'description' => '',
+ 'insertvon' => 'system'
+ )
+ )
+ ),
+ array(
+ 'app' => 'core',
+ 'category' => 'profil',
+ 'phrase' => 'calendar_sync_cal_dav',
+ 'insertvon' => 'system',
+ 'phrases' => array(
+ array(
+ 'sprache' => 'German',
+ 'text' => 'CalDAV URL (Android, Thunderbird, CalDAV-Synchronizer)',
+ 'description' => '',
+ 'insertvon' => 'system'
+ ),
+ array(
+ 'sprache' => 'English',
+ 'text' => 'CalDAV URL (Android, Thunderbird, CalDAV-Synchronizer)',
+ 'description' => '',
+ 'insertvon' => 'system'
+ )
+ )
+ ),
+ array(
+ 'app' => 'core',
+ 'category' => 'profil',
+ 'phrase' => 'calendar_sync_cal_dav_principal',
+ 'insertvon' => 'system',
+ 'phrases' => array(
+ array(
+ 'sprache' => 'German',
+ 'text' => 'CalDAV Principal URL (MacOS, iOS)',
+ 'description' => '',
+ 'insertvon' => 'system'
+ ),
+ array(
+ 'sprache' => 'English',
+ 'text' => 'CalDAV Principal URL (MacOS, iOS)',
+ 'description' => '',
+ 'insertvon' => 'system'
+ )
+ )
+ ),
+ array(
+ 'app' => 'core',
+ 'category' => 'profil',
+ 'phrase' => 'calendar_sync_i_cal',
+ 'insertvon' => 'system',
+ 'phrases' => array(
+ array(
+ 'sprache' => 'German',
+ 'text' => 'iCAL URL (Google)',
+ 'description' => '',
+ 'insertvon' => 'system'
+ ),
+ array(
+ 'sprache' => 'English',
+ 'text' => 'iCAL URL (Google)',
+ 'description' => '',
+ 'insertvon' => 'system'
+ )
+ )
+ ),
+ array(
+ 'app' => 'core',
+ 'category' => 'profil',
+ 'phrase' => 'calendar_sync_clipboard_copy_confirmation',
+ 'insertvon' => 'system',
+ 'phrases' => array(
+ array(
+ 'sprache' => 'German',
+ 'text' => 'URL in die Zwischenablage kopiert.',
+ 'description' => '',
+ 'insertvon' => 'system'
+ ),
+ array(
+ 'sprache' => 'English',
+ 'text' => 'URL copied to clipboard.',
+ 'description' => '',
+ 'insertvon' => 'system'
+ )
+ )
+ ),
//Profil Phrasen ende
// LvPlan Phrasen start
array(
@@ -57420,6 +57541,28 @@ I have been informed that I am under no obligation to consent to the transmissio
)
),
// ### LvPlanStgOrg END ###
+ // DMS-Link Phrasen Start
+ array(
+ 'app' => 'core',
+ 'category' => 'DMS-Link',
+ 'phrase' => 'lvplanSyncFAQ',
+ 'insertvon' => 'system',
+ 'phrases' => array(
+ array(
+ 'sprache' => 'German',
+ 'text' => '7188',
+ 'description' => '',
+ 'insertvon' => 'system'
+ ),
+ array(
+ 'sprache' => 'English',
+ 'text' => '7188',
+ 'description' => '',
+ 'insertvon' => 'system'
+ )
+ )
+ ),
+ // DMS-Link Phrasen End
);