Compare commits
2 Commits
c77812d857
...
92904f00eb
| Author | SHA1 | Date | |
|---|---|---|---|
| 92904f00eb | |||
| 0ed1e74080 |
231
_index.js
Normal file
231
_index.js
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
module.exports = function(RED) {
|
||||||
|
//require('https').globalAgent.options.ca = require('ssl-root-cas/latest').create();
|
||||||
|
|
||||||
|
let dav = require('dav')
|
||||||
|
let webdav = require('webdav')
|
||||||
|
const fs = require('fs')
|
||||||
|
const https = require('https');
|
||||||
|
const httpsAgent = new https.Agent({rejectUnauthorized: false});
|
||||||
|
|
||||||
|
function NextcloudConfigNode(n) {
|
||||||
|
RED.nodes.createNode(this, n)
|
||||||
|
this.address = n.address
|
||||||
|
}
|
||||||
|
RED.nodes.registerType('nextcloud-credentials', NextcloudConfigNode, {
|
||||||
|
credentials: {
|
||||||
|
user: {type: 'text'},
|
||||||
|
pass: {type: 'password'}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function NextcloudCalDav(n) {
|
||||||
|
RED.nodes.createNode(this, n)
|
||||||
|
this.server = RED.nodes.getNode(n.server)
|
||||||
|
this.calendar = n.calendar
|
||||||
|
let node = this
|
||||||
|
|
||||||
|
node.on('input', function(msg) {
|
||||||
|
const xhr = new dav.transport.Basic (
|
||||||
|
new dav.Credentials({
|
||||||
|
username: node.server.credentials.user,
|
||||||
|
password: node.server.credentials.pass
|
||||||
|
})
|
||||||
|
)
|
||||||
|
// Server + Basepath
|
||||||
|
let calDavUri = node.server.address + '/remote.php/dav/calendars/'
|
||||||
|
// User
|
||||||
|
calDavUri += node.server.credentials.user + '/'
|
||||||
|
dav.createAccount({ server: calDavUri, xhr: xhr })
|
||||||
|
.then(function(account) {
|
||||||
|
if (!account.calendars) {
|
||||||
|
node.error('Nextcloud:CalDAV -> no calendars found.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// account instanceof dav.Account
|
||||||
|
account.calendars.forEach(function(calendar) {
|
||||||
|
// Wenn Kalender gesetzt ist, dann nur diesen abrufen
|
||||||
|
let c = msg.calendar || node.calendar
|
||||||
|
if (!c || !c.length || (c && c.length && c === calendar.displayName)) {
|
||||||
|
dav.listCalendarObjects(calendar, { xhr: xhr })
|
||||||
|
.then(function(calendarEntries) {
|
||||||
|
let icsList = {'payload': {'name': calendar.displayName, 'data': []}}
|
||||||
|
calendarEntries.forEach(function(calendarEntry) {
|
||||||
|
const keyValue = calendarEntry.calendarData.split('\n')
|
||||||
|
let icsJson = {}
|
||||||
|
for (let x = 0; x < keyValue.length; x++) {
|
||||||
|
const temp = keyValue[x].split(':')
|
||||||
|
icsJson[temp[0]] = temp[1]
|
||||||
|
}
|
||||||
|
icsList.payload.data.push(icsJson)
|
||||||
|
})
|
||||||
|
node.send(icsList)
|
||||||
|
}, function(){
|
||||||
|
node.error('Nextcloud:CalDAV -> get ics went wrong.')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, function(){
|
||||||
|
node.error('Nextcloud:CalDAV -> get calendars went wrong.')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
RED.nodes.registerType('nextcloud-caldav', NextcloudCalDav)
|
||||||
|
|
||||||
|
|
||||||
|
function NextcloudCardDav(n) {
|
||||||
|
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 (
|
||||||
|
new dav.Credentials({
|
||||||
|
username: node.server.credentials.user,
|
||||||
|
password: node.server.credentials.pass
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
// Server + Basepath
|
||||||
|
let cardDavUri = node.server.address + '/remote.php/dav/addressbooks/users/'
|
||||||
|
// User
|
||||||
|
cardDavUri += node.server.credentials.user + '/'
|
||||||
|
// ToDo Filter ?
|
||||||
|
dav.createAccount({ server: cardDavUri, xhr: xhr, accountType: 'carddav' })
|
||||||
|
.then(function(account) {
|
||||||
|
if (!account.addressBooks) {
|
||||||
|
node.error('Nextcloud:CardDAV -> no addressbooks found.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// account instanceof dav.Account
|
||||||
|
account.addressBooks.forEach(function(addressBook) {
|
||||||
|
// Wenn Adressbuch gesetzt ist, dann nur diesen abrufen
|
||||||
|
let c = msg.addressBook || node.addressBook
|
||||||
|
if (!c || !c.length || (c && c.length && c === addressBook.displayName)) {
|
||||||
|
dav.listVCards(addressBook, { xhr: xhr })
|
||||||
|
.then(function(addressBookEntries) {
|
||||||
|
let vcfList = {'payload': {'name': addressBook.displayName, 'data': []}}
|
||||||
|
addressBookEntries.forEach(function(addressBookEntry) {
|
||||||
|
const keyValue = addressBookEntry.addressData.split('\n')
|
||||||
|
let vcfJson = {}
|
||||||
|
for (let x = 0; x < keyValue.length; x++) {
|
||||||
|
const temp = keyValue[x].split(':')
|
||||||
|
vcfJson[temp[0]] = temp[1]
|
||||||
|
}
|
||||||
|
vcfList.payload.data.push(vcfJson)
|
||||||
|
})
|
||||||
|
node.send(vcfList)
|
||||||
|
}, function(){
|
||||||
|
node.error('Nextcloud:CardDAV -> get cards went wrong.')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, function(){
|
||||||
|
node.error('Nextcloud:CardDAV -> get addressBooks went wrong.')
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
RED.nodes.registerType('nextcloud-carddav', NextcloudCardDav)
|
||||||
|
|
||||||
|
|
||||||
|
function NextcloudWebDavList(n) {
|
||||||
|
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 client = webdav(webDavUri, node.server.credentials.user, node.server.credentials.pass, httpsAgent)
|
||||||
|
let directory = ''
|
||||||
|
if (msg.directory) {
|
||||||
|
directory = '/' + msg.directory
|
||||||
|
} else if (node.directory && node.directory.length) {
|
||||||
|
directory = '/' + node.directory
|
||||||
|
}
|
||||||
|
directory = directory.replace('//', '/')
|
||||||
|
|
||||||
|
client.getDirectoryContents(directory)
|
||||||
|
.then(function (contents) {
|
||||||
|
node.send({'payload': contents})
|
||||||
|
}, function (error) {
|
||||||
|
node.error('Nextcloud:WebDAV -> get directory content went wrong.' + JSON.stringify(error))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
RED.nodes.registerType('nextcloud-webdav-list', NextcloudWebDavList)
|
||||||
|
|
||||||
|
|
||||||
|
function NextcloudWebDavOut(n) {
|
||||||
|
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 client = webdav(webDavUri, node.server.credentials.user, node.server.credentials.pass)
|
||||||
|
let filename = ''
|
||||||
|
if (msg.filename) {
|
||||||
|
filename = '/' + msg.filename
|
||||||
|
} else if (node.filename && node.filename.length) {
|
||||||
|
filename = '/' + node.filename
|
||||||
|
} else {
|
||||||
|
node.error('Nextcloud:WebDAV -> no filename specified.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
filename = filename.replace('//', '/')
|
||||||
|
node.warn(filename)
|
||||||
|
client.getFileContents(filename)
|
||||||
|
.then(function (contents) {
|
||||||
|
node.send({'payload': contents})
|
||||||
|
}, function (error) {
|
||||||
|
node.error('Nextcloud:WebDAV -> get file went wrong.' + JSON.stringify(error))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
RED.nodes.registerType('nextcloud-webdav-out', NextcloudWebDavOut)
|
||||||
|
|
||||||
|
|
||||||
|
function NextcloudWebDavIn(n) {
|
||||||
|
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
|
||||||
|
let filename = node.filename
|
||||||
|
if (msg.filename) {
|
||||||
|
filename = msg.filename
|
||||||
|
}
|
||||||
|
const name = filename.substr((filename.lastIndexOf('/') + 1), filename.length)
|
||||||
|
const file = fs.readFileSync(filename);
|
||||||
|
// Set upload directory
|
||||||
|
let directory = '/'
|
||||||
|
if (msg.directory) {
|
||||||
|
directory += msg.directory + '/'
|
||||||
|
} else if (node.directory && node.directory.length) {
|
||||||
|
directory += node.directory + '/'
|
||||||
|
}
|
||||||
|
directory = directory.replace('//', '/')
|
||||||
|
|
||||||
|
|
||||||
|
const webDavUri = node.server.address + '/remote.php/webdav/'
|
||||||
|
// https://nextcloud.jkoschke.me/remote.php/dav/files/jan/
|
||||||
|
const client = webdav(webDavUri, node.server.credentials.user, node.server.credentials.pass, httpsAgent);
|
||||||
|
|
||||||
|
client.putFileContents(directory + name, file, { format: 'binary' })
|
||||||
|
.then(function(contents) {
|
||||||
|
console.log(contents)
|
||||||
|
node.send({'payload': JSON.parse(contents)})
|
||||||
|
}, function(e) {
|
||||||
|
console.log(e);
|
||||||
|
node.error('Nextcloud:WebDAV -> send file went wrong.')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
RED.nodes.registerType('nextcloud-webdav-in', NextcloudWebDavIn)
|
||||||
|
}
|
||||||
72
nextcloud-cal.html
Normal file
72
nextcloud-cal.html
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<script type="text/javascript">
|
||||||
|
RED.nodes.registerType('nextcloud-caldav', {
|
||||||
|
category: 'nextcloud',
|
||||||
|
color: '#0082c9',
|
||||||
|
paletteLabel: 'CalDAV',
|
||||||
|
defaults: {
|
||||||
|
nname: {value: ''},
|
||||||
|
server: {type: 'nextcloud-credentials', required: true},
|
||||||
|
calendar: {value: '', required: false},
|
||||||
|
pastWeeks: { type: 'num', value: 0, required: true},
|
||||||
|
futureWeeks: { type: 'num', default: 4, required: true }
|
||||||
|
},
|
||||||
|
inputs: 1,
|
||||||
|
outputs: 1,
|
||||||
|
outputLabels: ['stdout'],
|
||||||
|
icon: 'nextcloud.png',
|
||||||
|
label: function() {
|
||||||
|
return this.nname || 'Nextcloud CalDAV'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/x-red" data-template-name="nextcloud-caldav">
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-nname"><i class="fa fa-tag"></i> Name</label>
|
||||||
|
<input type="text" id="node-input-nname" placeholder="Name" style="width: 70%">
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-server"><i class="fa fa-server"></i> Server</label>
|
||||||
|
<input type="text" id="node-input-server">
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-calendar"><i class="fa fa-calendar"></i> Calendar</label>
|
||||||
|
<input type="text" id="node-input-calendar">
|
||||||
|
</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 type="text/x-red" data-help-name="nextcloud-caldav">
|
||||||
|
<p>Connects to a Nextcloud server and downloads calendar entries (ics)</p>
|
||||||
|
|
||||||
|
<h3>Inputs</h3>
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>payload
|
||||||
|
<span class="property-type">any</span>
|
||||||
|
</dt>
|
||||||
|
<dd> Incoming message triggers download of calendar items. Any payload is possible. </dd>
|
||||||
|
<dt class="optional">calendar <span class="property-type">string</span></dt>
|
||||||
|
<dd> Calendar can be specified on incoming message or in nodes properties (expects displayname
|
||||||
|
of calendar - the name of the calendar as shown in nextcloud calendar app). Downloads
|
||||||
|
calendar items from all calendars if not set.</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h3>Outputs</h3>
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>payload
|
||||||
|
<span class="property-type">Object</span>
|
||||||
|
</dt>
|
||||||
|
<dd> Outputs one message for each calendar. Output payload is an object with two keys:</dd>
|
||||||
|
<dt class="optional">name <span class="property-type">string</span></dt>
|
||||||
|
<dd> The name of the calendar</dd>
|
||||||
|
<dt class="optional">data <span class="property-type">Array of objects</span></dt>
|
||||||
|
<dd> Each calendar entry is an ics parsed to a JSON object</dd>
|
||||||
|
</dl>
|
||||||
|
</script>
|
||||||
115
nextcloud-cal.js
Normal file
115
nextcloud-cal.js
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
module.exports = function(RED){
|
||||||
|
const dav = require('dav')
|
||||||
|
const IcalExpander = require('ical-expander')
|
||||||
|
const moment = require('moment')
|
||||||
|
const https = require('https')
|
||||||
|
|
||||||
|
function NextcloudCalDav (config) {
|
||||||
|
RED.nodes.createNode(this, config)
|
||||||
|
this.server = RED.nodes.getNode(config.server)
|
||||||
|
this.calendar = config.calendar
|
||||||
|
this.pastWeeks = config.pastWeeks || 0
|
||||||
|
this.futureWeeks = config.futureWeeks || 4
|
||||||
|
const node = this
|
||||||
|
|
||||||
|
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(
|
||||||
|
new dav.Credentials({
|
||||||
|
username: node.server.credentials.user,
|
||||||
|
password: node.server.credentials.pass
|
||||||
|
})
|
||||||
|
)
|
||||||
|
// Server + Basepath
|
||||||
|
let calDavUri = node.server.address + '/remote.php/dav/calendars/'
|
||||||
|
// User
|
||||||
|
calDavUri += node.server.credentials.user + '/'
|
||||||
|
dav.createAccount({ server: calDavUri, xhr: xhr, loadCollections: true, loadObjects: true })
|
||||||
|
.then(function (account) {
|
||||||
|
if (!account.calendars) {
|
||||||
|
node.error('Nextcloud:CalDAV -> no calendars found.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// account instanceof dav.Account
|
||||||
|
account.calendars.forEach(function (calendar) {
|
||||||
|
// Wenn Kalender gesetzt ist, dann nur diesen abrufen
|
||||||
|
let calName = msg.calendar || node.calendar
|
||||||
|
if (!calName || !calName.length || (calName && calName.length && calName === calendar.displayName)) {
|
||||||
|
dav.listCalendarObjects(calendar, { xhr: xhr, filters: filters })
|
||||||
|
.then(function (calendarEntries) {
|
||||||
|
let msg = { 'payload': { 'name': calendar.displayName, 'data': [] } }
|
||||||
|
calendarEntries.forEach(function (calendarEntry) {
|
||||||
|
try {
|
||||||
|
const ics = calendarEntry.calendarData
|
||||||
|
const icalExpander = new IcalExpander({ ics, maxIterations: 100 })
|
||||||
|
const events = icalExpander.between(startDate.toDate(), endDate.toDate())
|
||||||
|
msg.payload.data = msg.payload.data.concat(convertEvents(events))
|
||||||
|
} catch (error) {
|
||||||
|
node.error('Error parsing calendar data: ' + error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
node.send(msg)
|
||||||
|
}, function () {
|
||||||
|
node.error('Nextcloud:CalDAV -> get ics went wrong.')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, function () {
|
||||||
|
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)
|
||||||
|
}
|
||||||
62
nextcloud-card.html
Normal file
62
nextcloud-card.html
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<script type="text/javascript">
|
||||||
|
RED.nodes.registerType('nextcloud-carddav', {
|
||||||
|
category: 'nextcloud',
|
||||||
|
color: '#0082c9',
|
||||||
|
paletteLabel: 'CardDAV',
|
||||||
|
defaults: {
|
||||||
|
rname: {value: ''},
|
||||||
|
server: {type: 'nextcloud-credentials', required: true},
|
||||||
|
addressBook: {value: '', required: false}
|
||||||
|
},
|
||||||
|
inputs: 1,
|
||||||
|
outputs: 1,
|
||||||
|
outputLabels: ['stdout'],
|
||||||
|
icon: 'nextcloud.png',
|
||||||
|
label: function() {
|
||||||
|
return this.rname || 'Nextcloud CardDAV'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/x-red" data-template-name="nextcloud-carddav">
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-rname"><i class="fa fa-tag"></i> Name</label>
|
||||||
|
<input type="text" id="node-input-rname" placeholder="Name">
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-server"><i class="fa fa-server"></i> Server</label>
|
||||||
|
<input type="text" id="node-input-server">
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-addressBook"><i class="fa fa-address-book"></i> Address Book</label>
|
||||||
|
<input type="text" id="node-input-addressBook">
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/x-red" data-help-name="nextcloud-carddav">
|
||||||
|
<p>Connects to a Nextcloud server and downloads addressbook entries (vcf)</p>
|
||||||
|
|
||||||
|
<h3>Inputs</h3>
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>payload
|
||||||
|
<span class="property-type">any</span>
|
||||||
|
</dt>
|
||||||
|
<dd> Incoming message triggers download of addressbook items. Any payload is possible. </dd>
|
||||||
|
<dt class="optional">calendar <span class="property-type">string</span></dt>
|
||||||
|
<dd> Adressbook can be specified on incoming message or in nodes properties (expects displayname
|
||||||
|
of addressbook - the name of the addressbook as shown in nextcloud contacts app). Downloads
|
||||||
|
addressbook items from all addressbooks if not set.</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h3>Outputs</h3>
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>payload
|
||||||
|
<span class="property-type">Object</span>
|
||||||
|
</dt>
|
||||||
|
<dd> Outputs one message for each addressbook. Output payload is an object with two keys:</dd>
|
||||||
|
<dt class="optional">name <span class="property-type">string</span></dt>
|
||||||
|
<dd> The name of the addressbook</dd>
|
||||||
|
<dt class="optional">data <span class="property-type">Array of objects</span></dt>
|
||||||
|
<dd> Each addressbook entry is an vcf parsed to a JSON object</dd>
|
||||||
|
</dl>
|
||||||
|
</script>
|
||||||
60
nextcloud-card.js
Normal file
60
nextcloud-card.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
module.exports = function(RED){
|
||||||
|
|
||||||
|
const dav = require('dav')
|
||||||
|
const https = require('https')
|
||||||
|
|
||||||
|
function NextcloudCardDav (config) {
|
||||||
|
RED.nodes.createNode(this, config)
|
||||||
|
this.server = RED.nodes.getNode(config.server)
|
||||||
|
this.addressBook = config.addressBook
|
||||||
|
const node = this
|
||||||
|
|
||||||
|
node.on('input', (msg) => {
|
||||||
|
const xhr = new dav.transport.Basic(
|
||||||
|
new dav.Credentials({
|
||||||
|
username: node.server.credentials.user,
|
||||||
|
password: node.server.credentials.pass
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
// Server + Basepath
|
||||||
|
let cardDavUri = node.server.address + '/remote.php/dav/addressbooks/users/'
|
||||||
|
// User
|
||||||
|
cardDavUri += node.server.credentials.user + '/'
|
||||||
|
// ToDo Filter ?
|
||||||
|
dav.createAccount({ server: cardDavUri, xhr: xhr, accountType: 'carddav' })
|
||||||
|
.then(function (account) {
|
||||||
|
if (!account.addressBooks) {
|
||||||
|
node.error('Nextcloud:CardDAV -> no addressbooks found.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// account instanceof dav.Account
|
||||||
|
account.addressBooks.forEach(function (addressBook) {
|
||||||
|
// Wenn Adressbuch gesetzt ist, dann nur diesen abrufen
|
||||||
|
let c = msg.addressBook || node.addressBook
|
||||||
|
if (!c || !c.length || (c && c.length && c === addressBook.displayName)) {
|
||||||
|
dav.listVCards(addressBook, { xhr: xhr })
|
||||||
|
.then(function (addressBookEntries) {
|
||||||
|
let vcfList = { 'payload': { 'name': addressBook.displayName, 'data': [] } }
|
||||||
|
addressBookEntries.forEach(function (addressBookEntry) {
|
||||||
|
const keyValue = addressBookEntry.addressData.split('\n')
|
||||||
|
let vcfJson = {}
|
||||||
|
for (let x = 0; x < keyValue.length; x++) {
|
||||||
|
const temp = keyValue[x].split(':')
|
||||||
|
vcfJson[temp[0]] = temp[1]
|
||||||
|
}
|
||||||
|
vcfList.payload.data.push(vcfJson)
|
||||||
|
})
|
||||||
|
node.send(vcfList)
|
||||||
|
}, function () {
|
||||||
|
node.error('Nextcloud:CardDAV -> get cards went wrong.')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, function () {
|
||||||
|
node.error('Nextcloud:CardDAV -> get addressBooks went wrong.')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
RED.nodes.registerType('nextcloud-carddav', NextcloudCardDav)
|
||||||
|
}
|
||||||
45
nextcloud-config.html
Normal file
45
nextcloud-config.html
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<script type="text/javascript">
|
||||||
|
RED.nodes.registerType('nextcloud-credentials', {
|
||||||
|
category: 'config',
|
||||||
|
defaults: {
|
||||||
|
cname: {value: '', required: false},
|
||||||
|
address: {value: '', required: true},
|
||||||
|
insecure: {value: '', required: false}
|
||||||
|
},
|
||||||
|
credentials: {
|
||||||
|
user: {type:'text'},
|
||||||
|
pass: {type:'password'}
|
||||||
|
},
|
||||||
|
label: function() {
|
||||||
|
if (this.cname.length) {
|
||||||
|
return this.cname + ' (' + this.address + ')'
|
||||||
|
}
|
||||||
|
return this.address
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/x-red" data-template-name="nextcloud-credentials">
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-config-input-cname"><i class="fa fa-tag"></i> Name</label>
|
||||||
|
<input type="text" id="node-config-input-cname">
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-config-input-address"><i class="fa fa-server"></i> Server</label>
|
||||||
|
<input type="text" id="node-config-input-address" placeholder="https://your.server.com">
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-config-input-insecure"><i class="fa fa-server"></i> Security</label>
|
||||||
|
<input type="checkbox" value="1" id="node-config-input-insecure"
|
||||||
|
style="display: inline-block; width: auto; vertical-align: top">
|
||||||
|
<span style="width: 70%">Accept self signed certificates</span>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-config-input-user"><i class="fa fa-server"></i> Username</label>
|
||||||
|
<input type="text" id="node-config-input-user">
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-config-input-pass"><i class="fa fa-key"></i> Password</label>
|
||||||
|
<input type="password" id="node-config-input-pass">
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
13
nextcloud-config.js
Normal file
13
nextcloud-config.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
module.exports = function (RED) {
|
||||||
|
function NextcloudConfigNode(n) {
|
||||||
|
RED.nodes.createNode(this, n)
|
||||||
|
this.address = n.address;
|
||||||
|
this.insecure = n.insecure;
|
||||||
|
}
|
||||||
|
RED.nodes.registerType('nextcloud-credentials', NextcloudConfigNode, {
|
||||||
|
credentials: {
|
||||||
|
user: { type: 'text' },
|
||||||
|
pass: { type: 'password' }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
200
nextcloud.html
200
nextcloud.html
@ -1,188 +1,3 @@
|
|||||||
<script type="text/javascript">
|
|
||||||
RED.nodes.registerType('nextcloud-credentials', {
|
|
||||||
category: 'config',
|
|
||||||
defaults: {
|
|
||||||
cname: {value: '', required: false},
|
|
||||||
address: {value: 'https://your.server.com', required: true},
|
|
||||||
insecure: {value: '', required: false}
|
|
||||||
},
|
|
||||||
credentials: {
|
|
||||||
user: {type:'text'},
|
|
||||||
pass: {type:'password'}
|
|
||||||
},
|
|
||||||
label: function() {
|
|
||||||
if (this.cname.length) {
|
|
||||||
return this.cname + ' (' + this.address + ')'
|
|
||||||
}
|
|
||||||
return this.address
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script type="text/x-red" data-template-name="nextcloud-credentials">
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-config-input-cname"><i class="fa fa-tag"></i> Name</label>
|
|
||||||
<input type="text" id="node-config-input-cname">
|
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-config-input-address"><i class="fa fa-server"></i> Server</label>
|
|
||||||
<input type="text" id="node-config-input-address">
|
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-config-input-insecure"><i class="fa fa-server"></i> Security</label>
|
|
||||||
<input type="checkbox" value="1" id="node-config-input-insecure"
|
|
||||||
style="display: inline-block; width: auto; vertical-align: top">
|
|
||||||
<span style="width: 70%">Accept self signed certificates</span>
|
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-config-input-user"><i class="fa fa-server"></i> Username</label>
|
|
||||||
<input type="text" id="node-config-input-user">
|
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-config-input-pass"><i class="fa fa-key"></i> Password</label>
|
|
||||||
<input type="password" id="node-config-input-pass">
|
|
||||||
</div>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
RED.nodes.registerType('nextcloud-caldav', {
|
|
||||||
category: 'nextcloud',
|
|
||||||
color: '#0082c9',
|
|
||||||
paletteLabel: 'CalDAV',
|
|
||||||
defaults: {
|
|
||||||
nname: {value: ''},
|
|
||||||
server: {type: 'nextcloud-credentials', required: true},
|
|
||||||
calendar: {value: '', required: false},
|
|
||||||
pastWeeks: { type: 'num', value: 0, required: true},
|
|
||||||
futureWeeks: { type: 'num', default: 4, required: true }
|
|
||||||
},
|
|
||||||
inputs: 1,
|
|
||||||
outputs: 1,
|
|
||||||
outputLabels: ['stdout'],
|
|
||||||
icon: 'nextcloud.png',
|
|
||||||
label: function() {
|
|
||||||
return this.nname || 'Nextcloud CalDAV'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script type="text/x-red" data-template-name="nextcloud-caldav">
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-input-nname"><i class="fa fa-tag"></i> Name</label>
|
|
||||||
<input type="text" id="node-input-nname" placeholder="Name" style="width: 70%">
|
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-input-server"><i class="fa fa-server"></i> Server</label>
|
|
||||||
<input type="text" id="node-input-server">
|
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-input-calendar"><i class="fa fa-calendar"></i> Calendar</label>
|
|
||||||
<input type="text" id="node-input-calendar">
|
|
||||||
</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 type="text/x-red" data-help-name="nextcloud-caldav">
|
|
||||||
<p>Connects to a Nextcloud server and downloads calendar entries (ics)</p>
|
|
||||||
|
|
||||||
<h3>Inputs</h3>
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>payload
|
|
||||||
<span class="property-type">any</span>
|
|
||||||
</dt>
|
|
||||||
<dd> Incoming message triggers download of calendar items. Any payload is possible. </dd>
|
|
||||||
<dt class="optional">calendar <span class="property-type">string</span></dt>
|
|
||||||
<dd> Calendar can be specified on incoming message or in nodes properties (expects displayname
|
|
||||||
of calendar - the name of the calendar as shown in nextcloud calendar app). Downloads
|
|
||||||
calendar items from all calendars if not set.</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<h3>Outputs</h3>
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>payload
|
|
||||||
<span class="property-type">Object</span>
|
|
||||||
</dt>
|
|
||||||
<dd> Outputs one message for each calendar. Output payload is an object with two keys:</dd>
|
|
||||||
<dt class="optional">name <span class="property-type">string</span></dt>
|
|
||||||
<dd> The name of the calendar</dd>
|
|
||||||
<dt class="optional">data <span class="property-type">Array of objects</span></dt>
|
|
||||||
<dd> Each calendar entry is an ics parsed to a JSON object</dd>
|
|
||||||
</dl>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
RED.nodes.registerType('nextcloud-carddav', {
|
|
||||||
category: 'nextcloud',
|
|
||||||
color: '#0082c9',
|
|
||||||
paletteLabel: 'CardDAV',
|
|
||||||
defaults: {
|
|
||||||
rname: {value: ''},
|
|
||||||
server: {type: 'nextcloud-credentials', required: true},
|
|
||||||
addressBook: {value: '', required: false}
|
|
||||||
},
|
|
||||||
inputs: 1,
|
|
||||||
outputs: 1,
|
|
||||||
outputLabels: ['stdout'],
|
|
||||||
icon: 'nextcloud.png',
|
|
||||||
label: function() {
|
|
||||||
return this.rname || 'Nextcloud CardDAV'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script type="text/x-red" data-template-name="nextcloud-carddav">
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-input-rname"><i class="fa fa-tag"></i> Name</label>
|
|
||||||
<input type="text" id="node-input-rname" placeholder="Name">
|
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-input-server"><i class="fa fa-server"></i> Server</label>
|
|
||||||
<input type="text" id="node-input-server">
|
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-input-addressBook"><i class="fa fa-address-book"></i> Address Book</label>
|
|
||||||
<input type="text" id="node-input-addressBook">
|
|
||||||
</div>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script type="text/x-red" data-help-name="nextcloud-carddav">
|
|
||||||
<p>Connects to a Nextcloud server and downloads addressbook entries (vcf)</p>
|
|
||||||
|
|
||||||
<h3>Inputs</h3>
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>payload
|
|
||||||
<span class="property-type">any</span>
|
|
||||||
</dt>
|
|
||||||
<dd> Incoming message triggers download of addressbook items. Any payload is possible. </dd>
|
|
||||||
<dt class="optional">calendar <span class="property-type">string</span></dt>
|
|
||||||
<dd> Adressbook can be specified on incoming message or in nodes properties (expects displayname
|
|
||||||
of addressbook - the name of the addressbook as shown in nextcloud contacts app). Downloads
|
|
||||||
addressbook items from all addressbooks if not set.</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<h3>Outputs</h3>
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>payload
|
|
||||||
<span class="property-type">Object</span>
|
|
||||||
</dt>
|
|
||||||
<dd> Outputs one message for each addressbook. Output payload is an object with two keys:</dd>
|
|
||||||
<dt class="optional">name <span class="property-type">string</span></dt>
|
|
||||||
<dd> The name of the addressbook</dd>
|
|
||||||
<dt class="optional">data <span class="property-type">Array of objects</span></dt>
|
|
||||||
<dd> Each addressbook entry is an vcf parsed to a JSON object</dd>
|
|
||||||
</dl>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
RED.nodes.registerType('nextcloud-webdav-list', {
|
RED.nodes.registerType('nextcloud-webdav-list', {
|
||||||
category: 'nextcloud',
|
category: 'nextcloud',
|
||||||
@ -219,7 +34,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/x-red" data-help-name="nextcloud-webdav-list">
|
<script type="text/x-red" data-help-name="nextcloud-webdav-list">
|
||||||
<p>Connects to a Nextcloud server and lists directory content of a given path)</p>
|
<p>Connects to a Nextcloud/WebDav server and lists directory content of a given path)</p>
|
||||||
|
|
||||||
<h3>Inputs</h3>
|
<h3>Inputs</h3>
|
||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
@ -291,7 +106,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/x-red" data-help-name="nextcloud-webdav-out">
|
<script type="text/x-red" data-help-name="nextcloud-webdav-out">
|
||||||
<p>Connects to a Nextcloud server and downloads a file and sends it to the output</p>
|
<p>Connects to a Nextcloud/WebDav server and downloads a file and sends it to the output</p>
|
||||||
|
|
||||||
<h3>Inputs</h3>
|
<h3>Inputs</h3>
|
||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
@ -358,18 +173,17 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/x-red" data-help-name="nextcloud-webdav-in">
|
<script type="text/x-red" data-help-name="nextcloud-webdav-in">
|
||||||
<p>Connects to a Nextcloud server and uploads a file to a given directory</p>
|
<p>Connects to a Nextcloud/WebDav server and uploads a file to a given directory</p>
|
||||||
|
|
||||||
<h3>Inputs</h3>
|
<h3>Inputs</h3>
|
||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
<dt>payload
|
<dt>payload
|
||||||
<span class="property-type">any</span>
|
<span class="property-type">Binary buffer</span>
|
||||||
</dt>
|
</dt>
|
||||||
<dd> Incoming message triggers receiving a list containing a directory content. Any payload
|
<dd> The payload should contain the file which should be uploaded in a binary buffer </dd>
|
||||||
is possible. </dd>
|
|
||||||
<dt class="optional">filename <span class="property-type">string</span></dt>
|
<dt class="optional">filename <span class="property-type">string</span></dt>
|
||||||
<dd> The filename should be an absolute path, otherwise it will be relative to the working
|
<dd> A filename can be specified on incoming message or in nodes properties.
|
||||||
directory of the Node-RED process.</dd>
|
Saves the uploaded file with the given name. The property should also include the file extension.</dd>
|
||||||
<dt class="optional">directory <span class="property-type">string</span></dt>
|
<dt class="optional">directory <span class="property-type">string</span></dt>
|
||||||
<dd> A directory can be specified on incoming message or in nodes properties. Uploads the
|
<dd> A directory can be specified on incoming message or in nodes properties. Uploads the
|
||||||
file to the users root directory if not set.</dd>
|
file to the users root directory if not set.</dd>
|
||||||
|
|||||||
200
nextcloud.js
200
nextcloud.js
@ -2,187 +2,14 @@ module.exports = function (RED) {
|
|||||||
const dav = require('dav')
|
const dav = require('dav')
|
||||||
const webdav = require('webdav')
|
const webdav = require('webdav')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const IcalExpander = require('ical-expander')
|
|
||||||
const moment = require('moment')
|
|
||||||
const https = require('https')
|
const https = require('https')
|
||||||
|
const rootCas = require('ssl-root-cas').create();
|
||||||
|
|
||||||
function NextcloudConfigNode (config) {
|
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
|
||||||
RED.nodes.createNode(this, config)
|
|
||||||
this.address = config.address
|
|
||||||
this.insecure = config.insecure
|
|
||||||
}
|
|
||||||
RED.nodes.registerType('nextcloud-credentials', NextcloudConfigNode, {
|
|
||||||
credentials: {
|
|
||||||
user: { type: 'text' },
|
|
||||||
pass: { type: 'password' }
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
function NextcloudCalDav (config) {
|
|
||||||
RED.nodes.createNode(this, config)
|
|
||||||
this.server = RED.nodes.getNode(config.server)
|
|
||||||
this.calendar = config.calendar
|
|
||||||
this.pastWeeks = config.pastWeeks || 0
|
|
||||||
this.futureWeeks = config.futureWeeks || 4
|
|
||||||
const node = this
|
|
||||||
|
|
||||||
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(
|
|
||||||
new dav.Credentials({
|
|
||||||
username: node.server.credentials.user,
|
|
||||||
password: node.server.credentials.pass
|
|
||||||
})
|
|
||||||
)
|
|
||||||
// Server + Basepath
|
|
||||||
let calDavUri = node.server.address + '/remote.php/dav/calendars/'
|
|
||||||
// User
|
|
||||||
calDavUri += node.server.credentials.user + '/'
|
|
||||||
dav.createAccount({ server: calDavUri, xhr: xhr, loadCollections: true, loadObjects: true })
|
|
||||||
.then(function (account) {
|
|
||||||
if (!account.calendars) {
|
|
||||||
node.error('Nextcloud:CalDAV -> no calendars found.')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// account instanceof dav.Account
|
|
||||||
account.calendars.forEach(function (calendar) {
|
|
||||||
// Wenn Kalender gesetzt ist, dann nur diesen abrufen
|
|
||||||
let calName = msg.calendar || node.calendar
|
|
||||||
if (!calName || !calName.length || (calName && calName.length && calName === calendar.displayName)) {
|
|
||||||
dav.listCalendarObjects(calendar, { xhr: xhr, filters: filters })
|
|
||||||
.then(function (calendarEntries) {
|
|
||||||
let msg = { 'payload': { 'name': calendar.displayName, 'data': [] } }
|
|
||||||
calendarEntries.forEach(function (calendarEntry) {
|
|
||||||
try {
|
|
||||||
const ics = calendarEntry.calendarData
|
|
||||||
const icalExpander = new IcalExpander({ ics, maxIterations: 100 })
|
|
||||||
const events = icalExpander.between(startDate.toDate(), endDate.toDate())
|
|
||||||
msg.payload.data = msg.payload.data.concat(convertEvents(events))
|
|
||||||
} catch (error) {
|
|
||||||
node.error('Error parsing calendar data: ' + error)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
node.send(msg)
|
|
||||||
}, function () {
|
|
||||||
node.error('Nextcloud:CalDAV -> get ics went wrong.')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}, function () {
|
|
||||||
node.error('Nextcloud:CalDAV -> get calendars went wrong.')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
function convertEvents (events) {
|
function NextcloudWebDavList(config) {
|
||||||
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)
|
|
||||||
|
|
||||||
function NextcloudCardDav (config) {
|
|
||||||
RED.nodes.createNode(this, config)
|
|
||||||
this.server = RED.nodes.getNode(config.server)
|
|
||||||
this.addressBook = config.addressBook
|
|
||||||
const node = this
|
|
||||||
|
|
||||||
node.on('input', (msg) => {
|
|
||||||
const xhr = new dav.transport.Basic(
|
|
||||||
new dav.Credentials({
|
|
||||||
username: node.server.credentials.user,
|
|
||||||
password: node.server.credentials.pass
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
// Server + Basepath
|
|
||||||
let cardDavUri = node.server.address + '/remote.php/dav/addressbooks/users/'
|
|
||||||
// User
|
|
||||||
cardDavUri += node.server.credentials.user + '/'
|
|
||||||
// ToDo Filter ?
|
|
||||||
dav.createAccount({ server: cardDavUri, xhr: xhr, accountType: 'carddav' })
|
|
||||||
.then(function (account) {
|
|
||||||
if (!account.addressBooks) {
|
|
||||||
node.error('Nextcloud:CardDAV -> no addressbooks found.')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// account instanceof dav.Account
|
|
||||||
account.addressBooks.forEach(function (addressBook) {
|
|
||||||
// Wenn Adressbuch gesetzt ist, dann nur diesen abrufen
|
|
||||||
let c = msg.addressBook || node.addressBook
|
|
||||||
if (!c || !c.length || (c && c.length && c === addressBook.displayName)) {
|
|
||||||
dav.listVCards(addressBook, { xhr: xhr })
|
|
||||||
.then(function (addressBookEntries) {
|
|
||||||
let vcfList = { 'payload': { 'name': addressBook.displayName, 'data': [] } }
|
|
||||||
addressBookEntries.forEach(function (addressBookEntry) {
|
|
||||||
const keyValue = addressBookEntry.addressData.split('\n')
|
|
||||||
let vcfJson = {}
|
|
||||||
for (let x = 0; x < keyValue.length; x++) {
|
|
||||||
const temp = keyValue[x].split(':')
|
|
||||||
vcfJson[temp[0]] = temp[1]
|
|
||||||
}
|
|
||||||
vcfList.payload.data.push(vcfJson)
|
|
||||||
})
|
|
||||||
node.send(vcfList)
|
|
||||||
}, function () {
|
|
||||||
node.error('Nextcloud:CardDAV -> get cards went wrong.')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}, function () {
|
|
||||||
node.error('Nextcloud:CardDAV -> get addressBooks went wrong.')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
RED.nodes.registerType('nextcloud-carddav', NextcloudCardDav)
|
|
||||||
|
|
||||||
function NextcloudWebDavList (config) {
|
|
||||||
RED.nodes.createNode(this, config)
|
RED.nodes.createNode(this, config)
|
||||||
this.server = RED.nodes.getNode(config.server)
|
this.server = RED.nodes.getNode(config.server)
|
||||||
this.directory = config.directory
|
this.directory = config.directory
|
||||||
@ -214,7 +41,7 @@ module.exports = function (RED) {
|
|||||||
}
|
}
|
||||||
RED.nodes.registerType('nextcloud-webdav-list', NextcloudWebDavList)
|
RED.nodes.registerType('nextcloud-webdav-list', NextcloudWebDavList)
|
||||||
|
|
||||||
function NextcloudWebDavOut (config) {
|
function NextcloudWebDavOut(config) {
|
||||||
RED.nodes.createNode(this, config)
|
RED.nodes.createNode(this, config)
|
||||||
this.server = RED.nodes.getNode(config.server)
|
this.server = RED.nodes.getNode(config.server)
|
||||||
this.filename = config.filename
|
this.filename = config.filename
|
||||||
@ -249,7 +76,7 @@ module.exports = function (RED) {
|
|||||||
}
|
}
|
||||||
RED.nodes.registerType('nextcloud-webdav-out', NextcloudWebDavOut)
|
RED.nodes.registerType('nextcloud-webdav-out', NextcloudWebDavOut)
|
||||||
|
|
||||||
function NextcloudWebDavIn (config) {
|
function NextcloudWebDavIn(config) {
|
||||||
RED.nodes.createNode(this, config)
|
RED.nodes.createNode(this, config)
|
||||||
this.server = RED.nodes.getNode(config.server)
|
this.server = RED.nodes.getNode(config.server)
|
||||||
this.directory = config.directory
|
this.directory = config.directory
|
||||||
@ -257,14 +84,16 @@ module.exports = function (RED) {
|
|||||||
const node = this
|
const node = this
|
||||||
|
|
||||||
node.on('input', (msg) => {
|
node.on('input', (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 = msg.payload;
|
||||||
// Set upload directory
|
// Set upload directory
|
||||||
|
|
||||||
let directory = '/'
|
let directory = '/'
|
||||||
if (msg.directory) {
|
if (msg.directory) {
|
||||||
directory += msg.directory + '/'
|
directory += msg.directory + '/'
|
||||||
@ -273,20 +102,23 @@ module.exports = function (RED) {
|
|||||||
}
|
}
|
||||||
directory = directory.replace('//', '/')
|
directory = directory.replace('//', '/')
|
||||||
|
|
||||||
const webDavUri = node.server.address + '/remote.php/webdav/'
|
|
||||||
const client = webdav(webDavUri, node.server.credentials.user, node.server.credentials.pass)
|
|
||||||
|
|
||||||
// check option for self signed certs
|
// check option for self signed certs
|
||||||
const option = {}
|
const option = {}
|
||||||
if (node.server.insecure) {
|
if (node.server.insecure) {
|
||||||
option.agent = new https.Agent({ rejectUnauthorized: false })
|
option.agent = new https.Agent({ rejectUnauthorized: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const webDavUri = node.server.address + '/remote.php/webdav/'
|
||||||
|
const client = webdav(webDavUri, node.server.credentials.user, node.server.credentials.pass)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
client.putFileContents(directory + name, file, { format: 'binary' }, option)
|
client.putFileContents(directory + name, file, { format: 'binary' }, option)
|
||||||
.then(function (contents) {
|
.then(function (contents) {
|
||||||
console.log(contents)
|
console.log(contents)
|
||||||
node.send({ 'payload': JSON.parse(contents) })
|
node.send({ 'payload': JSON.parse(contents) })
|
||||||
}, function () {
|
}, function (e) {
|
||||||
|
console.error(e);
|
||||||
node.error('Nextcloud:WebDAV -> send file went wrong.')
|
node.error('Nextcloud:WebDAV -> send file went wrong.')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,11 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "node-red-contrib-nextcloud",
|
"name": "node-red-contrib-nextcloud-plus",
|
||||||
"version": "0.1.3",
|
"version": "0.1.3",
|
||||||
"description": "Collection of node-red nodes to download Calendars (CalDAV) and Contacts (CardDAV) and up- / download / list files (WebDAV) from / to nextcloud",
|
"description": "Collection of node-red nodes to download Calendars (CalDAV) and Contacts (CardDAV) and up- / download / list files (WebDAV) from / to nextcloud",
|
||||||
"main": "nextcloud.js",
|
"main": "nextcloud.js",
|
||||||
"node-red": {
|
"node-red": {
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"Nextcloud": "nextcloud.js"
|
"Nextcloud": "nextcloud.js",
|
||||||
|
"NexccloudCal": "nextcloud-cal.js",
|
||||||
|
"NextcloudConfig": "nextcloud-config.js",
|
||||||
|
"NextcloudCard": "nextcloud-card.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@ -20,6 +23,7 @@
|
|||||||
"dav": "^1.8.0",
|
"dav": "^1.8.0",
|
||||||
"ical-expander": "^2.0.0",
|
"ical-expander": "^2.0.0",
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.24.0",
|
||||||
|
"ssl-root-cas": "^1.3.1",
|
||||||
"webdav": "^1.6.1"
|
"webdav": "^1.6.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
Reference in New Issue
Block a user