mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-10-12 15:04:04 +00:00
implemented coodle ical comp and corresponding endpoint
This commit is contained in:
@@ -71,6 +71,8 @@ $route['Cis/StgOrgLvPlan/.*'] = 'Cis/StgOrgLvPlan/index/$1';
|
||||
$route['Cis/Coodle'] = 'Cis/Coodle';
|
||||
|
||||
$route['CoodleFreeBusy/(:any)'] = 'api/frontend/v1/coodle/FreeBusy/getCoodleFreeBusy/$1';
|
||||
$route['CoodleIcal/encrypted/(:any)'] = 'api/frontend/v1/coodle/CoodleSurvey/getCoodleIcalEncrypted/$1';
|
||||
$route['CoodleIcal/(:any)'] = 'api/frontend/v1/coodle/CoodleSurvey/getCoodleIcal/$1';
|
||||
|
||||
$route['Abgabetool/Assistenz'] = 'Cis/Abgabetool/Assistenz';
|
||||
$route['Abgabetool/Assistenz/(:any)'] = 'Cis/Abgabetool/Assistenz/$1';
|
||||
|
||||
@@ -23,6 +23,8 @@ class CoodleSurvey extends FHCAPI_Controller
|
||||
{
|
||||
|
||||
protected $coodlePageUrl;
|
||||
protected $coodleIcalUrl;
|
||||
protected $coodleIcalUrlWithEncryptedUid;
|
||||
|
||||
/**
|
||||
* Object initialization
|
||||
@@ -40,9 +42,13 @@ class CoodleSurvey extends FHCAPI_Controller
|
||||
'cancelSurvey' => self::PERM_LOGGED,
|
||||
'completeSurvey' => self::PERM_LOGGED,
|
||||
'sendVotingReminders' => self::PERM_LOGGED,
|
||||
'getCoodleIcalUrl' => self::PERM_LOGGED,
|
||||
'getCoodleIcal' => self::PERM_ANONYMOUS,
|
||||
'getCoodleIcalEncrypted' => self::PERM_ANONYMOUS,
|
||||
]);
|
||||
|
||||
$this->load->library('form_validation');
|
||||
$this->load->library('CryptLib');
|
||||
$this->load->model('person/Person_model', 'PersonModel');
|
||||
$this->load->model('ressource/CoodleSurvey_model', 'CoodleSurveyModel');
|
||||
$this->load->model('ressource/CoodleSurveyTimeslot_model', 'CoodleSurveyTimeslotModel');
|
||||
@@ -51,6 +57,8 @@ class CoodleSurvey extends FHCAPI_Controller
|
||||
$this->load->helper('hlp_sancho_helper');
|
||||
|
||||
$this->coodlePageUrl = APP_ROOT . "cis.php/Cis/Coodle";
|
||||
$this->coodleIcalUrl = APP_ROOT . "cis.php/CoodleIcal/{uid}";
|
||||
$this->coodleIcalUrlWithEncryptedUid = APP_ROOT . "cis.php/CoodleIcal/encrypted/{encryptedUid}";
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
@@ -726,6 +734,44 @@ class CoodleSurvey extends FHCAPI_Controller
|
||||
$this->terminateWithSuccess();
|
||||
}
|
||||
|
||||
public function getCoodleIcalUrl()
|
||||
{
|
||||
$uid = getAuthUID();
|
||||
|
||||
$encryptedUid = $this->cryptlib->RIJNDAEL_256_ECB(str_pad($uid, 32, chr(0)), LVPLAN_CYPHER_KEY, true);
|
||||
$encryptedUid = base64_encode($encryptedUid);
|
||||
$encryptedUid = str_replace(array('+', '/', '='), array('-', '_', ''), $encryptedUid);
|
||||
$encryptedUid = trim($encryptedUid);
|
||||
|
||||
$unencryptedUrl = str_replace("{uid}", $uid, $this->coodleIcalUrl);
|
||||
$encryptedUrl = str_replace("{encryptedUid}", $encryptedUid, $this->coodleIcalUrlWithEncryptedUid);
|
||||
|
||||
$this->terminateWithSuccess([
|
||||
"unencryptedUrl" => $unencryptedUrl,
|
||||
"encryptedUrl" => $encryptedUrl,
|
||||
]);
|
||||
}
|
||||
|
||||
public function getCoodleIcal($uid)
|
||||
{
|
||||
$coodleIcalFilePath = $this->_getCoodleIcal($uid, false);
|
||||
$this->terminateWithFileOutput("text/calendar", file_get_contents($coodleIcalFilePath), "coodle_ical.ics");
|
||||
}
|
||||
|
||||
public function getCoodleIcalEncrypted($encryptedUid)
|
||||
{
|
||||
$data = str_replace(array('-', '_'), array('+', '/'), $encryptedUid);
|
||||
$mod4 = strlen($data) % 4;
|
||||
if ($mod4) {
|
||||
$data .= substr('====', $mod4);
|
||||
}
|
||||
$decodedData = base64_decode($data);
|
||||
|
||||
$uid = trim($this->cryptlib->RIJNDAEL_256_ECB_DECRYPT($decodedData, LVPLAN_CYPHER_KEY, true));
|
||||
|
||||
$coodleIcalFilePath = $this->_getCoodleIcal($uid, true);
|
||||
$this->terminateWithFileOutput("text/calendar", file_get_contents($coodleIcalFilePath), "coodle_ical.ics");
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// Private methods
|
||||
@@ -865,4 +911,68 @@ class CoodleSurvey extends FHCAPI_Controller
|
||||
fwrite($calendarFile, "END:VEVENT" . PHP_EOL);
|
||||
fwrite($calendarFile, "END:VCALENDAR");
|
||||
}
|
||||
|
||||
private function _getCoodleIcal($uid, $shouldIncludeIdentifyingInformation)
|
||||
{
|
||||
$activeParticipantEntries = $this->CoodleSurveyParticipantModel->getActiveParticipantEntriesByUid($uid);
|
||||
$selectedTimeslotIds = [];
|
||||
foreach ($activeParticipantEntries as $participantEntry) {
|
||||
if ($participantEntry->selection === null)
|
||||
continue;
|
||||
|
||||
$selectedTimeslotIds = array_merge($selectedTimeslotIds, json_decode($participantEntry->selection));
|
||||
}
|
||||
|
||||
$events = [];
|
||||
$localTimezone = new DateTimeZone("Europe/Vienna");
|
||||
$utcTimezone = new DateTimeZone("UTC");
|
||||
foreach ($selectedTimeslotIds as $timeslotId) {
|
||||
$timeslot = $this->CoodleSurveyTimeslotModel->getTimeslot($timeslotId);
|
||||
if (!$timeslot)
|
||||
continue;
|
||||
|
||||
$survey = $this->CoodleSurveyModel->getSurvey($timeslot->survey_id);
|
||||
|
||||
$startTime = new DateTime($timeslot->starts_at, $localTimezone);
|
||||
$endTime = new DateTime($timeslot->starts_at, $localTimezone);
|
||||
$endTime->modify("+$survey->timeslot_duration minutes");
|
||||
|
||||
$startTime->setTimezone($utcTimezone);
|
||||
$endTime->setTimezone($utcTimezone);
|
||||
|
||||
$surveyCreatorFullName = getData($this->PersonModel->getFullName($survey->creator_uid));
|
||||
|
||||
$formattedStartTime = $startTime->format("Ymd\THis\Z");
|
||||
$formattedEndTime = $endTime->format("Ymd\THis\Z");
|
||||
$events[] = [
|
||||
"id" => "coodle_termin_option_" . $survey->id . "_" . $formattedStartTime . "_" . $formattedEndTime,
|
||||
"summary" => "Coodle Terminoption" . ($shouldIncludeIdentifyingInformation ? " $survey->title" : ""),
|
||||
"description" => $shouldIncludeIdentifyingInformation ? "Erstellt von " . $surveyCreatorFullName : "",
|
||||
"start" => $formattedStartTime,
|
||||
"end" => $formattedEndTime,
|
||||
];
|
||||
}
|
||||
|
||||
$coodleIcalFilePath = tempnam(sys_get_temp_dir(), "coodle_ical_");
|
||||
|
||||
$coodleIcalFile = fopen($coodleIcalFilePath, "w");
|
||||
fwrite($coodleIcalFile, "BEGIN:VCALENDAR" . PHP_EOL);
|
||||
fwrite($coodleIcalFile, "VERSION:2.0" . PHP_EOL);
|
||||
fwrite($coodleIcalFile, "PRDODID:" . CAMPUS_NAME . PHP_EOL);
|
||||
|
||||
foreach ($events as $event) {
|
||||
fwrite($coodleIcalFile, "BEGIN:VEVENT" . PHP_EOL);
|
||||
fwrite($coodleIcalFile, "UID:" . $event["id"] . PHP_EOL);
|
||||
fwrite($coodleIcalFile, "SUMMARY:" . $event["summary"] . PHP_EOL);
|
||||
fwrite($coodleIcalFile, "DESCRIPTION:" . $event["description"] . PHP_EOL);
|
||||
fwrite($coodleIcalFile, "DTSTART:" . $event["start"] . PHP_EOL);
|
||||
fwrite($coodleIcalFile, "DTNED:" . $event["end"] . PHP_EOL);
|
||||
fwrite($coodleIcalFile, "TRANS:OPAQUE" . PHP_EOL);
|
||||
fwrite($coodleIcalFile, "END:VEVENT" . PHP_EOL);
|
||||
}
|
||||
|
||||
fwrite($coodleIcalFile, "END:VCALENDAR");
|
||||
|
||||
return $coodleIcalFilePath;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,4 +25,17 @@ class CryptLib
|
||||
|
||||
return $cipher->encrypt($value);
|
||||
}
|
||||
}
|
||||
|
||||
public static function RIJNDAEL_256_ECB_DECRYPT($value, $key, $paddingDisabled = false)
|
||||
{
|
||||
if (isEmptyString($value) || isEmptyString($key)) return null;
|
||||
|
||||
$cipher = new Rijndael(Rijndael::MODE_ECB);
|
||||
$cipher->setBlockLength(256);
|
||||
$cipher->setKey($key);
|
||||
|
||||
if ($paddingDisabled === true) $cipher->disablePadding();
|
||||
|
||||
return $cipher->decrypt($value);
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,20 @@ class CoodleSurveyParticipant_model extends DB_Model
|
||||
return $this->execQuery($query)->retval;
|
||||
}
|
||||
|
||||
public function getActiveParticipantEntriesByUid($uid)
|
||||
{
|
||||
$query = "SELECT
|
||||
surveyParticipant.survey_id as survey_id,
|
||||
surveyParticipant.participant_uid as participant_uid,
|
||||
surveyParticipant.selection as selection
|
||||
FROM $this->dbTable surveyParticipant
|
||||
JOIN campus.tbl_coodle_surveys survey ON(survey.id = surveyParticipant.survey_id)
|
||||
WHERE surveyParticipant.participant_uid = '$uid'
|
||||
AND survey.completed_at IS NULL
|
||||
AND survey.canceled_at IS NULL";
|
||||
return $this->execQuery($query)->retval;
|
||||
}
|
||||
|
||||
public function updateParticipants($surveyId, $participants, $timeslots)
|
||||
{
|
||||
$participantUids = array_map(function ($participant) {
|
||||
|
||||
@@ -108,4 +108,10 @@ export default {
|
||||
},
|
||||
};
|
||||
},
|
||||
getCoodleIcalLink() {
|
||||
return {
|
||||
method: "get",
|
||||
url: "/api/frontend/v1/coodle/CoodleSurvey/getCoodleIcalUrl",
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import CoodleApi from "../../../../api/factory/coodle.js";
|
||||
|
||||
export default {
|
||||
name: "CoodleIcal",
|
||||
props: {
|
||||
authUid: String | null,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
icalLink: "",
|
||||
encryptedIcalLink: "",
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isDarkMode() {
|
||||
return this.$theme.theme_name.value == "dark";
|
||||
},
|
||||
link() {
|
||||
return this.icalLink;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async getIcalLink() {
|
||||
const icalLinkResponse = await this.$api.call(CoodleApi.getCoodleIcalLink());
|
||||
if (icalLinkResponse.meta.status === "success") {
|
||||
this.icalLink = icalLinkResponse.data.unencryptedUrl;
|
||||
this.encryptedIcalLink = icalLinkResponse.data.encryptedUrl;
|
||||
console.log(icalLinkResponse);
|
||||
console.log(this.icalLink);
|
||||
console.log(this.encryptedIcalLink);
|
||||
}
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
await this.getIcalLink();
|
||||
console.log(this.icalLink);
|
||||
console.log(this.encryptedIcalLink);
|
||||
},
|
||||
template: /*html*/ `
|
||||
<div class="card" style="min-height:100%">
|
||||
<div class="card-body">
|
||||
<div class="d-flex flex-column gap-3">
|
||||
<span>
|
||||
{{ "You can integrate your selections from active Coodle surveys into your preferred calendar application. To do so, import the .ics file from one of the following links." }}
|
||||
</span>
|
||||
<span>
|
||||
{{ "To exclude identifiable survey data: " }}
|
||||
<a v-if="icalLink?.length" :href="icalLink" target="_blank">{{ icalLink }}</a>
|
||||
</span>
|
||||
<span>
|
||||
{{ "To include identifiable survey data: " }}
|
||||
<a v-if="encryptedIcalLink?.length" :href="encryptedIcalLink" target="_blank">{{ encryptedIcalLink }}</a>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
@@ -371,7 +371,6 @@ export default {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<coodle-survey-basic-info
|
||||
v-model:surveyFormDataModelValue="surveyFormData"
|
||||
:survey="$props.survey"
|
||||
|
||||
@@ -2,6 +2,7 @@ import ActiveCoodleSurveys from "./Components/ActiveCoodleSurveys.js";
|
||||
import InactiveCoodleSurveys from "./Components/InactiveCoodleSurveys.js";
|
||||
import CoodleSurvey from "./Components/CoodleSurvey.js";
|
||||
import CoodleFreeBusy from "./Components/CoodleFreeBusy.js";
|
||||
import CoodleIcal from "./Components/CoodleIcal.js";
|
||||
|
||||
import ApiAuthinfo from "../../../api/factory/authinfo.js";
|
||||
import CoodleApi from "../../../api/factory/coodle.js";
|
||||
@@ -13,6 +14,7 @@ export default {
|
||||
InactiveCoodleSurveys,
|
||||
CoodleSurvey,
|
||||
CoodleFreeBusy,
|
||||
CoodleIcal,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -141,6 +143,16 @@ export default {
|
||||
</div>
|
||||
<span class="text-nowrap">{{ "FreeBusy Settings" }}</span>
|
||||
</div>
|
||||
<div
|
||||
@click="switchToTab('ical')"
|
||||
:class="getTabStylingClass(view === 'ical')"
|
||||
class="btn d-flex flex-row gap-2 align-items-center py-2"
|
||||
>
|
||||
<div>
|
||||
<i class="fa-solid fa-calendar fa-lg"></i>
|
||||
</div>
|
||||
<span class="text-nowrap">{{ "Coodle iCal" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow-1 mt-1">
|
||||
@@ -161,6 +173,7 @@ export default {
|
||||
:authInfo="authInfo"
|
||||
/>
|
||||
<coodle-free-busy v-else-if="view === 'freeBusySettings'" :authUid="authInfo?.uid" />
|
||||
<coodle-ical v-else-if="view === 'ical'" :authUid="authInfo?.uid" />
|
||||
</div>
|
||||
</div>`,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user