Created
November 27, 2017 16:45
-
-
Save YoungElPaso/07b698c8eeee6b0b7b1a005e47c715c9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
// node-ews for Exchange Web Services API calls. | |
const EWS = require("node-ews"); | |
// map-json for mapping JSON to something simpler. | |
const MP = require("map-json"); | |
// require lodash. | |
const _ = require("lodash"); | |
// use dedent-js for template indentation issues. | |
const DD = require("dedent-js"); | |
// JS datetime stuff. | |
const moment = require("moment"); | |
// Hack, needed to bump sequence, probably a better method! | |
const replace = require("replace-in-file"); | |
let sequence = 0; | |
const repOptions = { | |
files: "beancounter.txt", | |
from: /sequence:*.*/, | |
to: match => { | |
sequence = eval(match.split(":")[1]) + 1; | |
match = "sequence:" + sequence; | |
return match; | |
} | |
}; | |
replace(repOptions).then(changes => { | |
doEverything(); | |
}); | |
function doEverything() { | |
// EWS config object. | |
const ewsConfig = { | |
username: "[email protected]", | |
password: "xxxxxx", | |
host: "https://outlook.office365.com", | |
auth: "basic" | |
}; | |
// Instantiate new EWS. | |
const ews = new EWS(ewsConfig); | |
// Basic funtion to get stuff. | |
const ewsFunction = "FindItem"; | |
// Args for finding stuff. | |
const ewsArgs = { | |
attributes: { | |
Traversal: "Shallow" | |
}, | |
ItemShape: { | |
BaseShape: "Default" | |
}, | |
CalendarView: { | |
attributes: { | |
MaxEntriesReturned: "1000", | |
// Broad range, who cares, if I need this in two years, revisit then. | |
StartDate: " 2017-10-10T12:00:00Z", | |
EndDate: " 2019-01-01T12:00:00Z" | |
} | |
}, | |
ParentFolderIds: { | |
DistinguishedFolderId: { | |
attributes: { | |
Id: "calendar" | |
} | |
} | |
} | |
}; | |
// Go get the stuff. | |
ews | |
.run(ewsFunction, ewsArgs) | |
.then(result => { | |
let res = | |
result.ResponseMessages.FindItemResponseMessage.RootFolder.Items; | |
// Does some recursive mapping of old keys to new. | |
let mappingObj = { | |
CalendarItems: { | |
_source: "*", | |
_transform: { | |
"@toObjectArray": [ | |
{ | |
SUMMARY: { | |
_source: "CalendarItem.*.Subject", | |
_transformEach: { toUpperCase: [] } | |
}, | |
UID: { | |
_source: "CalendarItem.*.Start", | |
_transformEach: { createUID: [] } | |
}, | |
DTSTART: { | |
_source: "CalendarItem.*.Start", | |
_transformEach: { dtIt: [] } | |
}, | |
DTEND: { | |
_source: "CalendarItem.*.End", | |
_transformEach: { dtIt: [] } | |
}, | |
// TENTATIVE|CONFIRMED|CANCELED | |
STATUS: { | |
_source: "CalendarItem.*.LegacyFreeBusyStatus", | |
_transformEach: { | |
reMapStatus: [], | |
toUpperCase: [] | |
} | |
} | |
} | |
] | |
} | |
} | |
}; | |
let transFunctions = | |
// Transform / condition functions | |
{ | |
createUID: string => { | |
let s = | |
_.replace(string, /-|:/g, "") + "someone@123fakestreet"; | |
return s; | |
}, | |
reMapStatus: string => { | |
// TODO make sure the map is correct! | |
// Meh, probably wrong api so leaving this in. Status not really important, this is read-only | |
if (string == "Busy" || string == "Free") { | |
string = "CONFIRMED"; | |
} else { | |
string = "TENTATIVE"; | |
} | |
let s = string; | |
return s; | |
}, | |
dtStmp: string => { | |
// Annoying datetime format required for ical. | |
let d = _replace(new Date.toISOString(), /-|:/g, ""); | |
return d; | |
}, | |
dtIt: string => { | |
let s = _.replace(string, /-|:/g, ""); | |
return s; | |
}, | |
toUpperCase: value => value.toUpperCase(), | |
substr: (string, from, length) => string.substr(from, length), | |
toObjectArray: inputObject => { | |
// Uses lodash | |
const createObjectByIndex = index => | |
_.mapValues(inputObject, array => array[index]); | |
const firstObjectValues = _.values(inputObject)[0] || []; | |
return _.times(firstObjectValues.length, createObjectByIndex); | |
} | |
}; | |
// Map the old JSON to a more clear structure. Could be skipped. | |
let mapped = MP.map(res, mappingObj, transFunctions); | |
// Blank template. | |
let eventsTpl = ""; | |
// Create an .ics file using a template. | |
_.each(mapped.CalendarItems, function(e, i) { | |
eventsTpl += ` | |
BEGIN:VEVENT | |
SUMMARY:${e.SUMMARY} | |
UID:${e.UID} | |
DTSTAMP:${// Brutal hack required for datetime (split on seconds) | |
_.replace( | |
moment() | |
.seconds(0) | |
.milliseconds(0) | |
.toISOString() | |
.split(":")[0] + "1500Z", | |
/-|:|\./g, | |
"" | |
)} | |
DTSTART:${e.DTSTART} | |
DTEND:${e.DTEND} | |
STATUS:${e.STATUS} | |
END:VEVENT`; | |
}); | |
// Put the template together w/ the wrapping ics strings. | |
// Sequence is CRUCIAL to getting updates (if it doesn't bump, Google wont reimport!!!) | |
let icalTpl = ` | |
BEGIN:VCALENDAR | |
VERSION: 2.0 | |
SEQUENCE:${sequence} | |
PRODID:-//someone//ews-api-ical//EN | |
${DD(eventsTpl)} | |
END:VCALENDAR | |
`; | |
console.log(DD(icalTpl)); | |
}) | |
.catch(err => { | |
console.log(err); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment