533 lines
27 KiB
JavaScript
533 lines
27 KiB
JavaScript
/*
|
|
$Revision$
|
|
$Id$
|
|
|
|
File: exchange_graph.js
|
|
|
|
Description: Exchange MS Graph koppeling
|
|
Dit bestand maakt voor een ruimte-mailbox Arguments(0) de csv
|
|
met calenderitems aan sinds de laatste sync-actie, Arguments(1)
|
|
|
|
Result: Errorlevel 10 betekent alles goed
|
|
Errorlevel 1 betekent dat we een foutsituatie hebben ontdekt
|
|
Errorlevel 0 betekent dat er iets is fout gegaan wat we niet hebben onderkend
|
|
|
|
Parameters (0) e-mail adres van de zaal
|
|
(1) "EXCHFULL" calendarview-import (in de toekomst tot config.fullfuture)
|
|
alle andere waarden: synchronisatie-import (voorheen werd hier de syncstate in meegegeven)
|
|
*/
|
|
|
|
/* GLOBALS */
|
|
var fso = new ActiveXObject("Scripting.FileSystemObject");
|
|
|
|
/*////////////////////////////////
|
|
// //
|
|
// Main functions //
|
|
// //
|
|
////////////////////////////////*/
|
|
|
|
/*
|
|
In zaalemail res_ruimte_extern_id
|
|
import_app_code EXCHFULL of EXCHANGE(default)
|
|
as_stream teruggeven als fileStream, of wegschrijven naar een .csv bestand
|
|
Out Pre-processed import in csv formaat
|
|
*/
|
|
function generateCalendarImport(zaalemail, import_app_code, as_stream)
|
|
{
|
|
var deltatoken;
|
|
|
|
// Determine files wild card
|
|
var import_app_files = "sync_*.csv";
|
|
var import_app_files_pre = "sync_";
|
|
var sql = "SELECT i.fac_import_app_files "
|
|
+ " FROM fac_import_app i"
|
|
+ " WHERE i.fac_import_app_code = " + safe.quoted_sql(String(import_app_code));
|
|
var oRs = Oracle.Execute(sql);
|
|
if (!oRs.EOF)
|
|
{
|
|
import_app_files = oRs("fac_import_app_files").Value;
|
|
import_app_files_pre = import_app_files.split("*")[0].split(".")[0];
|
|
}
|
|
oRs.Close();
|
|
|
|
__Log("\n\n==== Room: " + zaalemail);
|
|
if (import_app_code != "EXCHFULL") {
|
|
deltatoken = getSyncToken(zaalemail);
|
|
} else {
|
|
// No skiptoken and no deltatoken means retrieve all events
|
|
}
|
|
|
|
var csvname = config.xmlfolder + import_app_files_pre + safefilename(zaalemail) + ".csv";
|
|
// Verwijderen: het verwijderen van onze oude sync_*.csv
|
|
try {
|
|
fso.DeleteFile(csvname);
|
|
__Log("Oude syncfile is verwijderd.");
|
|
} catch(e) {
|
|
// Neem aan dat -gelukkig- geen files zijn gevonden
|
|
}
|
|
|
|
__Log("Connecting to MS Graph API");
|
|
var response = getCalendarItems(zaalemail, null, deltatoken);
|
|
if (response && response.value)
|
|
{
|
|
var results = response.value;
|
|
while (response.skiptoken) {
|
|
response = getCalendarItems(zaalemail, response.skiptoken, null);
|
|
for (var index = 0; index < response.value.length; index++) {
|
|
results.push(response.value[index]);
|
|
}
|
|
}
|
|
if (!("deltatoken" in response)) {
|
|
// Het laatste antwoord bevatte geen deltatoken, dat hoort er altijd te zijn, waarschijnlijk een MS Graph fout.
|
|
return _handleMsGraphFailure(null, response);
|
|
}
|
|
|
|
// deltatoken needs to be saved (asap) to retrieve only changes during a future run
|
|
upsertSyncToken(zaalemail, response.deltatoken);
|
|
|
|
// De pre-processed data
|
|
var csvFileText = graphToImport(results, zaalemail);
|
|
|
|
// save the CSV file to disc here
|
|
fileStream = new ActiveXObject("ADODB.Stream");
|
|
fileStream.Type = 2; // adTypeBinary eerst nog
|
|
fileStream.Open();
|
|
fileStream.CharSet = "utf-8";
|
|
// save only if records are found
|
|
if (!!csvFileText) {
|
|
fileStream.WriteText(csvFileText);
|
|
if (as_stream) {
|
|
// Leveren we die zo op en gaat die rechtstreeks impReadStream in
|
|
} else {
|
|
fileStream.SaveToFile(csvname, 2); // overwrite
|
|
}
|
|
}
|
|
|
|
// Als we hier komen is alles goed
|
|
return fileStream;
|
|
}
|
|
}
|
|
|
|
/*////////////////////////////////
|
|
// //
|
|
// Helper functions //
|
|
// //
|
|
////////////////////////////////*/
|
|
|
|
/* De volgende 2 functies zoeken in de data (Array) die de calendarItems bevat */
|
|
function getSeriesMaster(data, seriesMasterId) {
|
|
var result = {};
|
|
for (var i = 0; i < data.length; i++) {
|
|
if (data[i].id == seriesMasterId) {
|
|
result = data[i];
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function getOccurrencesBySeriesMasterId(data, seriesMasterId) {
|
|
var result = [];
|
|
for (var i = 0; i < data.length; i++) {
|
|
if (data[i].seriesMasterId == seriesMasterId) {
|
|
result.push(data[i]);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/* Deze functie zoekt in de Facilitor DB */
|
|
function getReserveringByEvent(event, zaalemail)
|
|
{
|
|
// res_rsv_ruimte_externnr bestaat uit 2 delen, gescheiden door een '|'-teken;
|
|
// 1. Het hoofd-id; COALESCE(seriesMasterId, (eigen) id)
|
|
// 2. Als het event onderdeel is van een series, dan is het 2de deel het (eigen) id, anders leeg
|
|
//
|
|
// LET OP deze id's kunnen een '_' bevatten
|
|
var externnr;
|
|
var compareExternnrSql = "";
|
|
switch (event.type) {
|
|
case "occurrence":
|
|
case "exception":
|
|
compareExternnrSql = "rr.res_rsv_ruimte_externnr = " + safe.quoted_sql(event.seriesMasterId + "|" + event.id); // Exact
|
|
break;
|
|
case "singleInstance":
|
|
compareExternnrSql = "rr.res_rsv_ruimte_externnr = " + safe.quoted_sql(event.id + "|"); // Exact
|
|
break;
|
|
case "seriesMaster":
|
|
externnr = event.id.replace(/_/g, '\\_'); // Escape de underscore
|
|
compareExternnrSql = "rr.res_rsv_ruimte_externnr LIKE " + safe.quoted_sql(externnr + '|_%') + " ESCAPE '\\'"; // LIKE (de laatste underscore niet escapen)
|
|
break;
|
|
default: /* Een 'deleted' notificatie heeft geen type, dan kan het een occurrence zijn of niet, test met het event.id op beiden */
|
|
externnr = event.id.replace(/_/g, '\\_'); // Escape de underscore
|
|
compareExternnrSql = "rr.res_rsv_ruimte_externnr LIKE " + safe.quoted_sql("%" + externnr + "%") + " ESCAPE '\\'"; // LIKE
|
|
break;
|
|
}
|
|
if ("iCalUId" in event) { // Vanaf 2024.1 (met rich notifications) altijd zo
|
|
compareExternnrSql = "(" + compareExternnrSql + " OR rr.res_rsv_ruimte_externnr = " + safe.quoted_sql("##iCalUId##" + event.iCalUId + "|") + ")";
|
|
}
|
|
var eventSql = "SELECT rr.res_rsv_ruimte_key"
|
|
+ " , rr.res_rsv_ruimte_omschrijving"
|
|
+ " , rr.res_rsv_ruimte_van"
|
|
+ " , rr.res_rsv_ruimte_tot"
|
|
+ " , rr.res_rsv_ruimte_externnr"
|
|
+ " , rr.res_rsv_ruimte_externnr2"
|
|
+ " , p_host.prs_perslid_email"
|
|
+ " FROM res_rsv_ruimte rr,"
|
|
+ " res_ruimte_opstelling ro,"
|
|
+ " res_ruimte r,"
|
|
+ " prs_perslid p_host"
|
|
+ " WHERE rr.res_rsv_ruimte_externnr IS NOT NULL"
|
|
+ " AND " + compareExternnrSql
|
|
+ " AND rr.res_rsv_ruimte_verwijder IS NULL"
|
|
+ " AND ro.res_ruimte_opstel_key = rr.res_ruimte_opstel_key"
|
|
+ " AND r.res_ruimte_key = ro.res_ruimte_key"
|
|
+ " AND r.res_ruimte_verwijder IS NULL"
|
|
+ " AND rr.res_rsv_ruimte_host_key = p_host.prs_perslid_key"
|
|
+ " AND UPPER(r.res_ruimte_extern_id) = " + safe.quoted_sql_upper(zaalemail);
|
|
var eventoRs = Oracle.Execute(eventSql);
|
|
var result = [];
|
|
while (!eventoRs.eof) {
|
|
result.push({
|
|
"key": eventoRs("res_rsv_ruimte_key").Value,
|
|
"description": eventoRs("res_rsv_ruimte_omschrijving").Value,
|
|
"van": eventoRs("res_rsv_ruimte_van").Value,
|
|
"tot": eventoRs("res_rsv_ruimte_tot").Value,
|
|
"externnr": eventoRs("res_rsv_ruimte_externnr").Value || "",
|
|
"organisatorId":eventoRs("res_rsv_ruimte_externnr2").Value || "",
|
|
"host_mail": eventoRs("prs_perslid_email").Value || ""
|
|
});
|
|
if (result[result.length - 1].externnr.slice(0, 11) === "##iCalUId##") { // Werk het FCLT-record direct bij zodat de import hem straks ook kan vinden
|
|
updateFcltRecord(result[result.length - 1].key, event, result[result.length - 1].organisatorId);
|
|
}
|
|
eventoRs.moveNext();
|
|
}
|
|
eventoRs.Close();
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
In Array van calendarItems
|
|
Out Pre-processed import in csv formaat
|
|
*/
|
|
function graphToImport(data, zaalemail)
|
|
{
|
|
var trs = [];
|
|
var tds = [];
|
|
var index;
|
|
var masterEvent;
|
|
var curDate = new Date();
|
|
var seqNbr = curDate.getTime();
|
|
var millisPerDay = 24 * 60 * 60 * 1000;
|
|
var maxPastMS = curDate.setHours(0, 0, 0, 0) - (config.fullpast * millisPerDay);
|
|
var maxFutureMS = curDate.setHours(23, 59, 59, 999) + (config.fullfuture * millisPerDay);
|
|
var SUBJECT_MAX_LENGTH = 60;
|
|
|
|
var _roomFallbackEmail;
|
|
var _unknownFallbackEmail;
|
|
var lcl_res_rsv_private = "";
|
|
if (data.length) {
|
|
var sql = "SELECT prs_perslid_email FROM prs_v_aanwezigperslid WHERE prs_perslid_oslogin = " + safe.quoted_sql_upper("_MSGRAPH_FALLBACK_ROOMS");
|
|
var oRs = Oracle.Execute(sql);
|
|
if (!oRs.EoF) {
|
|
_roomFallbackEmail = oRs("prs_perslid_email").Value;
|
|
}
|
|
oRs.Close();
|
|
|
|
sql = "SELECT prs_perslid_email FROM prs_v_aanwezigperslid WHERE prs_perslid_oslogin = " + safe.quoted_sql_upper("_MSGRAPH_FALLBACK_UNKNOWN");
|
|
oRs = Oracle.Execute(sql);
|
|
if (!oRs.EoF) {
|
|
_unknownFallbackEmail = oRs("prs_perslid_email").Value;
|
|
}
|
|
oRs.Close();
|
|
|
|
sql = "SELECT lcl.l('lcl_res_rsv_private') lcl_res_rsv_private FROM DUAL";
|
|
oRs = Oracle.Execute(sql);
|
|
if (!oRs.EoF) {
|
|
lcl_res_rsv_private = oRs("lcl_res_rsv_private").Value;
|
|
}
|
|
oRs.Close();
|
|
}
|
|
|
|
// Past de organizer.emailAddress.address aan van het meegegeven event indien nodig
|
|
function validateOrganizer(event, occurrence) {
|
|
// Als de organisator niet als prs_perslid in Facilitor bekend is, kennen we 2 fallback-accounts;
|
|
// 1) De organisator is een ruimte; externe software boekt vaak direct in de agenda vd ruimte, zoals Yealink, maar ook Facilitor zelf (bij msgraph_sync_level & 2)
|
|
// 2) De organisator is onbekend; technisch/funcioneel account, of gewoon onbekend in Facilitor
|
|
// Als de relevante fallback-account niet (juist) is geconfigureerd, returnen we een falsy value en wordt de regel niet geimporteerd
|
|
if ((event.organizer.emailAddress.address || "").slice(-2) === "##") {
|
|
// Deze hebben we al aangepast
|
|
} else if (event.isOrganizer) { // Ruimte = organizer (Yealink)
|
|
event.organizer.emailAddress.address = _roomFallbackEmail;
|
|
} else { // Try to find host by email
|
|
sql = "SELECT COUNT (*) aantal FROM prs_v_aanwezigperslid WHERE UPPER(prs_perslid_email) = " + safe.quoted_sql_upper(event.organizer.emailAddress.address);
|
|
oRs = Oracle.Execute(sql);
|
|
if (oRs("aantal").Value !== 1) { // Unknown or non-unique organizer
|
|
if (_unknownFallbackEmail) { // _unknownFallbackEmail is gedefinieerd en dus geconfigureerd
|
|
event.organizer.emailAddress.address = "##" + event.organizer.emailAddress.address + "##"; // Deze pakt de package op
|
|
} else {
|
|
event.organizer.emailAddress.address = null;
|
|
}
|
|
}
|
|
oRs.Close();
|
|
}
|
|
if (typeof occurrence != "undefined" && occurrence.type === "exception") { // Dan staat hier de(zelfde) organisator
|
|
occurrence.organizer.emailAddress.address = event.organizer.emailAddress.address;
|
|
}
|
|
return event.organizer.emailAddress.address;
|
|
}
|
|
|
|
// Header
|
|
var headerRow = [
|
|
"Subject",
|
|
"StartTime",
|
|
"EndTime",
|
|
"Organizer",
|
|
"Email",
|
|
"Name",
|
|
"Modifier",
|
|
"ApptId",
|
|
"RecurId",
|
|
"SeqNr"
|
|
].join(";");
|
|
// rows in data
|
|
/* types description
|
|
=============== ===============================
|
|
singleInstance: stand alone event
|
|
seriesMaster: definition of a repeating event
|
|
occurrence: repeating event occurrence
|
|
exception: changed repeating occurrence
|
|
*/
|
|
for (index = 0; index < data.length; index++)
|
|
{
|
|
var thisEvent = data[index];
|
|
|
|
// Eerst wat uitzonderingen eruit filteren
|
|
if ((getMSGraphSyncLevel() & 4) && "responseStatus" in thisEvent && thisEvent.responseStatus.response == "notResponded")
|
|
{ /*
|
|
Bij S("msgraph_sync_level") & 2 is dit "organizer" [Deze is vanuit Facilitor, direct op ruimte in Outlook geboekt]
|
|
Bij Yealink ad-hoc reserveringen is dit ook "organizer" [Deze is vanuit Yealink, direct op ruimte in Outlook geboekt]
|
|
Bij S("msgraph_sync_level") & 4 is dit de eerste keer "notResponded", en direct daarna "accepted"
|
|
*/
|
|
continue; // Hier doen we (nog) niets mee
|
|
}
|
|
|
|
var reserveringenFacilitor = getReserveringByEvent(thisEvent, zaalemail) || []; // Dit levert meerdere records op bij type = seriesMaster
|
|
if (( (getMSGraphSyncLevel() & 2) == 2 && // Als wij zelf afspraken op naam van de ruimte boeken, willen we zulke events nooit importeren
|
|
( (reserveringenFacilitor.length > 0 && reserveringenFacilitor[0].organisatorId == thisEvent.id) || // Deze is bekend in Facilitor en de ruimte is de organisator
|
|
(reserveringenFacilitor.length === 0 && /* Ooit; !_roomFallbackEmail && // Als je de fallback-user gebruikt dan is dit supported, anders niet */
|
|
(thisEvent.isOrganizer || // Deze is niet bekend in Facilitor en de ruimte is de organisator
|
|
inArray(thisEvent.type, ["occurrence", "exception"]) &&
|
|
(getSeriesMaster(data, thisEvent.seriesMasterId) || {}).isOrganizer))))) { // idem, maar dan bij de seriesMaster
|
|
// Deze slaan we over
|
|
continue;
|
|
}
|
|
|
|
// Facilitor-initiated reserveringen beginnen met alleen het externnr2 gevuld, update voor zover mogelijk hier het externnr
|
|
if (getMSGraphSyncLevel() & 4 && reserveringenFacilitor.length === 0) { // ReadWrite
|
|
var updateResult = updateExternnr(zaalemail, thisEvent.id);
|
|
if (updateResult == -1) { // De reservering is niet gevonden in Facilitor, en ook is de reservering niet geaccepteerd; dan hoeven we hier dus (nog) niets mee
|
|
continue; // Errorcode; skip record (Ruimte heeft nog niet geaccepteerd)
|
|
} else if (updateResult) {
|
|
reserveringenFacilitor = getReserveringByEvent(thisEvent, zaalemail) || []; // Probeer nog eens
|
|
}
|
|
}
|
|
|
|
// [D]eleted events
|
|
if (thisEvent["@removed"] || thisEvent.isCancelled || (("responseStatus" in thisEvent) && thisEvent.responseStatus.response == "declined"))
|
|
{
|
|
if (thisEvent.type == "seriesMaster") {
|
|
continue; // We krijgen per occurrence ook een event binnen en verwijderen die dan
|
|
}
|
|
|
|
// Op dit moment kan het nog steeds een "@removed" seriesMaster zijn, dan moeten we direct de hele serie deleten want we krijgen geen losse notificaties van de occurrences
|
|
for (var f in reserveringenFacilitor) {
|
|
if (new Date(reserveringenFacilitor[f].tot).getTime() >= maxPastMS &&
|
|
new Date(reserveringenFacilitor[f].van).getTime() <= maxFutureMS) {
|
|
if (("type" in thisEvent) && thisEvent.type === "singleInstance") { // Sla dan het iCalUId op zodat we deze sneller kunnen terugvinden bij een evt. ruimte-wissel
|
|
updateFcltRecord(reserveringenFacilitor[f].key, thisEvent, null, { "iCalUId": true, "force": false });
|
|
var sql = "SELECT res_rsv_ruimte_externnr FROM res_rsv_ruimte WHERE res_rsv_ruimte_key = " + reserveringenFacilitor[f].key;
|
|
var oRs = Oracle.Execute(sql);
|
|
var newExternnr = oRs.EoF
|
|
? reserveringenFacilitor[f].externnr
|
|
: oRs("res_rsv_ruimte_externnr").Value;
|
|
oRs.Close();
|
|
var eventId = newExternnr.split("|")[0];
|
|
var occurrenceId = newExternnr.split("|")[1] || "";
|
|
if (eventId.slice(0, 11) === "##iCalUId##") {
|
|
// Verwijder de id's van de oude verwijderde 'backups', die zijn niet meer nodig
|
|
var sql = "UPDATE res_rsv_ruimte"
|
|
+ " SET res_rsv_ruimte_externnr = NULL"
|
|
+ " WHERE res_rsv_ruimte_externnr = " + safe.quoted_sql(eventId + "|")
|
|
+ " AND res_rsv_ruimte_verwijder IS NOT NULL";
|
|
Oracle.Execute(sql);
|
|
}
|
|
} else {
|
|
var eventId = reserveringenFacilitor[f].externnr.split("|")[0];
|
|
var occurrenceId = reserveringenFacilitor[f].externnr.split("|")[1] || "";
|
|
}
|
|
tds = [
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"D", // [D]elete
|
|
safe.csv(eventId),
|
|
safe.csv(occurrenceId),
|
|
++seqNbr
|
|
];
|
|
trs.push(tds.join(";"));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var _startDate = parseISOString(thisEvent.start.dateTime);
|
|
var _endDate = parseISOString(thisEvent.end.dateTime);
|
|
if (_endDate.getTime() >= maxPastMS && _startDate.getTime() <= maxFutureMS)
|
|
{
|
|
{
|
|
var modifier = reserveringenFacilitor.length === 0 ? "C" : "U"; // [U]pdate of [C]reate
|
|
if (thisEvent.type == "singleInstance") // Simpel, single event
|
|
{
|
|
if (!validateOrganizer(thisEvent)) {
|
|
continue;
|
|
}
|
|
if (!eventReadyForProcessing(zaalemail, thisEvent)) {
|
|
continue;
|
|
}
|
|
var visibility = thisEvent.sensitivity === "normal" ? 1 : 0; // sensitivity IN ["normal", "personal", "private", "confidential"], we interpreteren die laatste 3 hetzelfde
|
|
tds = [
|
|
safe.csv((visibility ? thisEvent.subject : lcl_res_rsv_private).slice(0, SUBJECT_MAX_LENGTH)),
|
|
_startDate.toISOString(),
|
|
_endDate.toISOString(),
|
|
safe.csv(thisEvent.organizer.emailAddress.address),
|
|
"",
|
|
"",
|
|
safe.csv(visibility),
|
|
modifier,
|
|
safe.csv(thisEvent.id),
|
|
"",
|
|
++seqNbr
|
|
];
|
|
}
|
|
else if (inArray(thisEvent.type, ["occurrence", "exception"])) // Part of event-series (recurring)
|
|
{
|
|
masterEvent = getSeriesMaster(data, thisEvent.seriesMasterId) || {};
|
|
if (masterEvent.isCancelled) {
|
|
tds = [
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"D", // cancelled or deleted
|
|
safe.csv(thisEvent.seriesMasterId),
|
|
safe.csv(thisEvent.id),
|
|
++seqNbr
|
|
];
|
|
trs.push(tds.join(";"));
|
|
continue;
|
|
} else {
|
|
if (!validateOrganizer(masterEvent, thisEvent)) {
|
|
continue;
|
|
}
|
|
if (!eventReadyForProcessing(zaalemail, masterEvent)) {
|
|
continue;
|
|
}
|
|
var visibility = masterEvent.sensitivity === "normal" ? 1 : 0; // Gebruik de gegevens van de seriesMaster
|
|
tds = [
|
|
safe.csv((visibility ? masterEvent.subject : lcl_res_rsv_private).slice(0, SUBJECT_MAX_LENGTH)),
|
|
_startDate.toISOString(),
|
|
_endDate.toISOString(),
|
|
safe.csv(masterEvent.organizer.emailAddress.address),
|
|
"",
|
|
"",
|
|
safe.csv(visibility),
|
|
modifier,
|
|
safe.csv(thisEvent.seriesMasterId),
|
|
safe.csv(thisEvent.id),
|
|
++seqNbr
|
|
];
|
|
}
|
|
}
|
|
else if (thisEvent.type === "seriesMaster")
|
|
{ // Voer een (import) delete uit op alle occurrences van de seriesMaster die in Facilitor voorkomen maar niet in MS Graph
|
|
// Creates en Updates gaan vanzelf goed omdat dan de occurrence in de calendarView-response (=data) is meegegeven
|
|
// Bij deletes is dat niet het geval
|
|
// Deze calendarView/delta omvat de gehele serie, dus als een occurrence hier niet in staat, bestaat die niet (meer)
|
|
var reserveringenOutlook = getOccurrencesBySeriesMasterId(data, thisEvent.id);
|
|
for (var f in reserveringenFacilitor) {
|
|
var found = false;
|
|
for (var o in reserveringenOutlook) {
|
|
if (reserveringenOutlook[o].seriesMasterId === reserveringenFacilitor[f].externnr.split("|")[0] && // Match op seriesMasterId
|
|
reserveringenOutlook[o].id === reserveringenFacilitor[f].externnr.split("|")[1]) { // en op het id vd occurrence
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
tds = [
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"D", // [D]eleted
|
|
safe.csv(reserveringenFacilitor[f].externnr.split("|")[0]),
|
|
safe.csv(reserveringenFacilitor[f].externnr.split("|")[1]),
|
|
++seqNbr
|
|
];
|
|
trs.push(tds.join(";"));
|
|
}
|
|
}
|
|
continue; // Klaar
|
|
}
|
|
|
|
trs.push(tds.join(";"));
|
|
|
|
if ( thisEvent.type === "occurrence" && "attendees" in masterEvent // Deelnemers van occurrences staan bij de seriesMaster geregistreerd
|
|
|| "attendees" in thisEvent)
|
|
{ // Volgens mij zijn exceptions hier nooit relevant; ze zijn nooit nieuw (want ze begonnen als occurrence) en dus registreren we geen bezoeker-mutaties
|
|
var eventId = inArray(thisEvent.type, ["occurrence", "exception"]) ? thisEvent.seriesMasterId : thisEvent.id;
|
|
var occurrenceId = inArray(thisEvent.type, ["occurrence", "exception"]) ? thisEvent.id : "";
|
|
var thisEvent = ("attendees" in thisEvent) ? thisEvent : masterEvent; // Gebruik bij occurrence de gegevens van de seriesMaster
|
|
var visibility = thisEvent.sensitivity === "normal" ? 1 : 0;
|
|
for (var attendee in thisEvent.attendees) {
|
|
if (thisEvent.attendees[attendee].emailAddress &&
|
|
thisEvent.attendees[attendee].emailAddress.address &&
|
|
thisEvent.attendees[attendee].emailAddress.address !== thisEvent.organizer.emailAddress.address && // Organisator hoeft niet
|
|
thisEvent.attendees[attendee].emailAddress.address.toUpperCase() !== zaalemail.toUpperCase()) { // Ruimte ook niet
|
|
tds = [
|
|
safe.csv((visibility ? thisEvent.subject : lcl_res_rsv_private).slice(0, SUBJECT_MAX_LENGTH)),
|
|
_startDate.toISOString(),
|
|
_endDate.toISOString(),
|
|
safe.csv(thisEvent.organizer.emailAddress.address),
|
|
safe.csv(thisEvent.attendees[attendee].emailAddress.address),
|
|
safe.csv(thisEvent.attendees[attendee].emailAddress.name),
|
|
safe.csv(visibility),
|
|
modifier,
|
|
safe.csv(eventId),
|
|
safe.csv(occurrenceId),
|
|
seqNbr
|
|
];
|
|
trs.push(tds.join(";"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (trs.length)
|
|
trs = [headerRow].concat(trs);
|
|
return trs.join("\r\n");
|
|
}
|