Merge pull request #8 from basti76/master

Use ical.js to parse recieved calendar data
This commit is contained in:
Torsten Kühnel
2018-11-11 10:42:21 +01:00
committed by GitHub
4 changed files with 286 additions and 212 deletions

3
.eslintrc.js Normal file
View File

@@ -0,0 +1,3 @@
module.exports = {
"extends": "standard"
};

View File

@@ -45,7 +45,9 @@
defaults: { defaults: {
nname: {value: ''}, nname: {value: ''},
server: {type: 'nextcloud-credentials', required: true}, server: {type: 'nextcloud-credentials', required: true},
calendar: {value: '', required: false} calendar: {value: '', required: false},
pastWeeks: { type: 'num', value: 0, required: true},
futureWeeks: { type: 'num', default: 4, required: true }
}, },
inputs: 1, inputs: 1,
outputs: 1, outputs: 1,
@@ -60,7 +62,7 @@
<script type="text/x-red" data-template-name="nextcloud-caldav"> <script type="text/x-red" data-template-name="nextcloud-caldav">
<div class="form-row"> <div class="form-row">
<label for="node-input-nname"><i class="fa fa-tag"></i> Name</label> <label for="node-input-nname"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-nname" placeholder="Name"> <input type="text" id="node-input-nname" placeholder="Name" style="width: 70%">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-server"><i class="fa fa-server"></i> Server</label> <label for="node-input-server"><i class="fa fa-server"></i> Server</label>
@@ -70,6 +72,14 @@
<label for="node-input-calendar"><i class="fa fa-calendar"></i> Calendar</label> <label for="node-input-calendar"><i class="fa fa-calendar"></i> Calendar</label>
<input type="text" id="node-input-calendar"> <input type="text" id="node-input-calendar">
</div> </div>
<div class="form-row">
<label for="node-input-pastWeeks"><i class="fa fa-check-square"></i> Past weeks to sync</label>
<span class="ui-spinner ui-widget ui-widget-content ui-corner-all"><input type="number" id="node-input-pastWeeks"></span>
</div>
<div class="form-row">
<label for="node-input-futureWeeks"><i class="fa fa-random"></i> Upcoming weeks to sync</label>
<span class="ui-spinner ui-widget ui-widget-content ui-corner-all"><input type="number" id="node-input-futureWeeks"></span>
</div>
</script> </script>
<script type="text/x-red" data-help-name="nextcloud-caldav"> <script type="text/x-red" data-help-name="nextcloud-caldav">

View File

@@ -1,11 +1,13 @@
module.exports = function (RED) { module.exports = function (RED) {
let dav = require('dav') const dav = require('dav')
let webdav = require('webdav') const webdav = require('webdav')
const fs = require('fs') const fs = require('fs')
const IcalExpander = require('ical-expander')
const moment = require('moment')
function NextcloudConfigNode(n) { function NextcloudConfigNode (config) {
RED.nodes.createNode(this, n) RED.nodes.createNode(this, config)
this.address = n.address this.address = config.address
} }
RED.nodes.registerType('nextcloud-credentials', NextcloudConfigNode, { RED.nodes.registerType('nextcloud-credentials', NextcloudConfigNode, {
credentials: { credentials: {
@@ -14,13 +16,33 @@ module.exports = function(RED) {
} }
}) })
function NextcloudCalDav(n) { function NextcloudCalDav (config) {
RED.nodes.createNode(this, n) RED.nodes.createNode(this, config)
this.server = RED.nodes.getNode(n.server) this.server = RED.nodes.getNode(config.server)
this.calendar = n.calendar this.calendar = config.calendar
let node = this this.pastWeeks = config.pastWeeks || 0
this.futureWeeks = config.futureWeeks || 4
const node = this
node.on('input', function(msg) { node.on('input', (msg) => {
let startDate = moment().startOf('day').subtract(this.pastWeeks, 'weeks')
let endDate = moment().endOf('day').add(this.futureWeeks, 'weeks')
const filters = [{
type: 'comp-filter',
attrs: { name: 'VCALENDAR' },
children: [{
type: 'comp-filter',
attrs: { name: 'VEVENT' },
children: [{
type: 'time-range',
attrs: {
start: startDate.format('YYYYMMDD[T]HHmmss[Z]'),
end: endDate.format('YYYYMMDD[T]HHmmss[Z]')
}
}]
}]
}]
// dav.debug.enabled = true;
const xhr = new dav.transport.Basic( const xhr = new dav.transport.Basic(
new dav.Credentials({ new dav.Credentials({
username: node.server.credentials.user, username: node.server.credentials.user,
@@ -31,7 +53,7 @@ module.exports = function(RED) {
let calDavUri = node.server.address + '/remote.php/dav/calendars/' let calDavUri = node.server.address + '/remote.php/dav/calendars/'
// User // User
calDavUri += node.server.credentials.user + '/' calDavUri += node.server.credentials.user + '/'
dav.createAccount({ server: calDavUri, xhr: xhr }) dav.createAccount({ server: calDavUri, xhr: xhr, loadCollections: true, loadObjects: true })
.then(function (account) { .then(function (account) {
if (!account.calendars) { if (!account.calendars) {
node.error('Nextcloud:CalDAV -> no calendars found.') node.error('Nextcloud:CalDAV -> no calendars found.')
@@ -40,21 +62,22 @@ module.exports = function(RED) {
// account instanceof dav.Account // account instanceof dav.Account
account.calendars.forEach(function (calendar) { account.calendars.forEach(function (calendar) {
// Wenn Kalender gesetzt ist, dann nur diesen abrufen // Wenn Kalender gesetzt ist, dann nur diesen abrufen
let c = msg.calendar || node.calendar let calName = msg.calendar || node.calendar
if (!c || !c.length || (c && c.length && c === calendar.displayName)) { if (!calName || !calName.length || (calName && calName.length && calName === calendar.displayName)) {
dav.listCalendarObjects(calendar, { xhr: xhr }) dav.listCalendarObjects(calendar, { xhr: xhr, filters: filters })
.then(function (calendarEntries) { .then(function (calendarEntries) {
let icsList = {'payload': {'name': calendar.displayName, 'data': []}} let msg = { 'payload': { 'name': calendar.displayName, 'data': [] } }
calendarEntries.forEach(function (calendarEntry) { calendarEntries.forEach(function (calendarEntry) {
const keyValue = calendarEntry.calendarData.split('\n') try {
let icsJson = {} const ics = calendarEntry.calendarData
for (let x = 0; x < keyValue.length; x++) { const icalExpander = new IcalExpander({ ics, maxIterations: 100 })
const temp = keyValue[x].split(':') const events = icalExpander.between(startDate.toDate(), endDate.toDate())
icsJson[temp[0]] = temp[1] msg.payload.data = msg.payload.data.concat(convertEvents(events))
} catch (error) {
node.error('Error parsing calendar data: ' + error)
} }
icsList.payload.data.push(icsJson)
}) })
node.send(icsList) node.send(msg)
}, function () { }, function () {
node.error('Nextcloud:CalDAV -> get ics went wrong.') node.error('Nextcloud:CalDAV -> get ics went wrong.')
}) })
@@ -64,17 +87,51 @@ module.exports = function(RED) {
node.error('Nextcloud:CalDAV -> get calendars went wrong.') node.error('Nextcloud:CalDAV -> get calendars went wrong.')
}) })
}) })
function convertEvents (events) {
const mappedEvents = events.events.map(_convertEvent)
const mappedOccurrences = events.occurrences.map(_convertEvent)
return [].concat(mappedEvents, mappedOccurrences)
}
function _convertEvent (e) {
if (e) {
let startDate = e.startDate.toString()
let endDate = e.endDate.toString()
if (e.item) {
e = e.item
}
if (e.duration.wrappedJSObject) {
delete e.duration.wrappedJSObject
}
return {
startDate: startDate,
endDate: endDate,
summary: e.summary || '',
description: e.description || '',
attendees: e.attendees,
duration: e.duration.toICALString(),
durationSeconds: e.duration.toSeconds(),
location: e.location || '',
organizer: e.organizer || '',
uid: e.uid || '',
isRecurring: false,
allDay: ((e.duration.toSeconds() % 86400) === 0)
}
}
}
} }
RED.nodes.registerType('nextcloud-caldav', NextcloudCalDav) RED.nodes.registerType('nextcloud-caldav', NextcloudCalDav)
function NextcloudCardDav (config) {
RED.nodes.createNode(this, config)
this.server = RED.nodes.getNode(config.server)
this.addressBook = config.addressBook
const node = this
function NextcloudCardDav(n) { node.on('input', (msg) => {
RED.nodes.createNode(this, n)
this.server = RED.nodes.getNode(n.server)
this.addressBook = n.addressBook
let node = this
node.on('input', function(msg) {
const xhr = new dav.transport.Basic( const xhr = new dav.transport.Basic(
new dav.Credentials({ new dav.Credentials({
username: node.server.credentials.user, username: node.server.credentials.user,
@@ -119,19 +176,17 @@ module.exports = function(RED) {
}, function () { }, function () {
node.error('Nextcloud:CardDAV -> get addressBooks went wrong.') node.error('Nextcloud:CardDAV -> get addressBooks went wrong.')
}) })
}) })
} }
RED.nodes.registerType('nextcloud-carddav', NextcloudCardDav) RED.nodes.registerType('nextcloud-carddav', NextcloudCardDav)
function NextcloudWebDavList (config) {
RED.nodes.createNode(this, config)
this.server = RED.nodes.getNode(config.server)
this.directory = config.directory
const node = this
function NextcloudWebDavList(n) { node.on('input', (msg) => {
RED.nodes.createNode(this, n)
this.server = RED.nodes.getNode(n.server)
this.directory = n.directory
let node = this
node.on('input', function(msg) {
const webDavUri = node.server.address + '/remote.php/webdav/' const webDavUri = node.server.address + '/remote.php/webdav/'
const client = webdav(webDavUri, node.server.credentials.user, node.server.credentials.pass) const client = webdav(webDavUri, node.server.credentials.user, node.server.credentials.pass)
let directory = '' let directory = ''
@@ -152,14 +207,13 @@ module.exports = function(RED) {
} }
RED.nodes.registerType('nextcloud-webdav-list', NextcloudWebDavList) RED.nodes.registerType('nextcloud-webdav-list', NextcloudWebDavList)
function NextcloudWebDavOut (config) {
RED.nodes.createNode(this, config)
this.server = RED.nodes.getNode(config.server)
this.filename = config.filename
const node = this
function NextcloudWebDavOut(n) { node.on('input', (msg) => {
RED.nodes.createNode(this, n)
this.server = RED.nodes.getNode(n.server)
this.filename = n.filename
let node = this
node.on('input', function(msg) {
const webDavUri = node.server.address + '/remote.php/webdav/' const webDavUri = node.server.address + '/remote.php/webdav/'
const client = webdav(webDavUri, node.server.credentials.user, node.server.credentials.pass) const client = webdav(webDavUri, node.server.credentials.user, node.server.credentials.pass)
let filename = '' let filename = ''
@@ -183,22 +237,21 @@ module.exports = function(RED) {
} }
RED.nodes.registerType('nextcloud-webdav-out', NextcloudWebDavOut) RED.nodes.registerType('nextcloud-webdav-out', NextcloudWebDavOut)
function NextcloudWebDavIn (config) {
RED.nodes.createNode(this, config)
this.server = RED.nodes.getNode(config.server)
this.directory = config.directory
this.filename = config.filename
const node = this
function NextcloudWebDavIn(n) { node.on('input', (msg) => {
RED.nodes.createNode(this, n)
this.server = RED.nodes.getNode(n.server)
this.directory = n.directory
this.filename = n.filename
let node = this
node.on('input', function(msg) {
// Read upload file // Read upload file
let filename = node.filename let filename = node.filename
if (msg.filename) { if (msg.filename) {
filename = msg.filename filename = msg.filename
} }
const name = filename.substr((filename.lastIndexOf('/') + 1), filename.length) const name = filename.substr((filename.lastIndexOf('/') + 1), filename.length)
const file = fs.readFileSync(filename); const file = fs.readFileSync(filename)
// Set upload directory // Set upload directory
let directory = '/' let directory = '/'
if (msg.directory) { if (msg.directory) {

View File

@@ -17,11 +17,19 @@
"carddav" "carddav"
], ],
"dependencies": { "dependencies": {
"dav": "^1.7.8", "dav": "^1.8.0",
"npm": "^5.8.0", "ical-expander": "^2.0.0",
"moment": "^2.22.2",
"webdav": "^1.5.2" "webdav": "^1.5.2"
}, },
"devDependencies": {}, "devDependencies": {
"eslint": "^5.6.0",
"eslint-config-standard": "^12.0.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-node": "^7.0.1",
"eslint-plugin-promise": "^4.0.1",
"eslint-plugin-standard": "^4.0.0"
},
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },