|
17 | 17 | module.exports = function(RED) { |
18 | 18 | "use strict"; |
19 | 19 |
|
| 20 | + function GoogleCalendarQueryNode(n) { |
| 21 | + RED.nodes.createNode(this,n); |
| 22 | + this.google = RED.nodes.getNode(n.google); |
| 23 | + this.calendar = n.calendar || 'primary'; |
| 24 | + |
| 25 | + this.calendars = {}; |
| 26 | + if (!this.google || !this.google.credentials.accessToken) { |
| 27 | + this.warn("Missing google credentials"); |
| 28 | + return; |
| 29 | + } |
| 30 | + |
| 31 | + var node = this; |
| 32 | + node.status({fill:"blue",shape:"dot",text:"querying"}); |
| 33 | + this.google.request('https://www.googleapis.com/calendar/v3/users/me/calendarList', function(err, data) { |
| 34 | + if (err) { |
| 35 | + node.error("failed to fetch calendar list: " + err.toString()); |
| 36 | + node.status({fill:"red",shape:"ring",text:"failed"}); |
| 37 | + return; |
| 38 | + } |
| 39 | + if (data.error) { |
| 40 | + node.error("failed to fetch calendar list: " + |
| 41 | + data.error.message); |
| 42 | + node.status({fill:"red",shape:"ring",text:"failed"}); |
| 43 | + return; |
| 44 | + } |
| 45 | + for (var i = 0; i < data.items.length; i++) { |
| 46 | + var cal = data.items[i]; |
| 47 | + if (cal.primary) { |
| 48 | + node.calendars.primary = cal; |
| 49 | + } |
| 50 | + node.calendars[cal.id] = cal; |
| 51 | + } |
| 52 | + node.status({}); |
| 53 | + |
| 54 | + node.on('input', function(msg) { |
| 55 | + node.status({fill:"blue",shape:"dot",text:"querying"}); |
| 56 | + var cal = node.calendars[msg.calendar] || node.calendarByName(msg.calendar) || node.calendars[node.calendar] || node.calendarByName(node.calendar); |
| 57 | + if (!cal) { |
| 58 | + node.status({fill:"red",shape:"ring",text:"invalid calendar"}); |
| 59 | + return; |
| 60 | + } |
| 61 | + var request = { |
| 62 | + url: 'https://www.googleapis.com/calendar/v3/calendars/'+cal.id+'/events', |
| 63 | + }; |
| 64 | + var now = new Date(); |
| 65 | + request.qs = { |
| 66 | + maxResults: 10, |
| 67 | + orderBy: 'startTime', |
| 68 | + singleEvents: true, |
| 69 | + timeMin: now.toISOString() |
| 70 | + }; |
| 71 | + if (msg.payload) { |
| 72 | + request.qs.q = RED.util.ensureString(msg.payload); |
| 73 | + } |
| 74 | + node.google.request(request, function(err, data) { |
| 75 | + if (err) { |
| 76 | + node.error("Error: " + err.toString()); |
| 77 | + node.status({fill:"red",shape:"ring",text:"failed"}); |
| 78 | + } else if (data.error) { |
| 79 | + node.error("Error " + data.error.code + ": " + |
| 80 | + JSON.stringify(data.error.message)); |
| 81 | + node.status({fill:"red",shape:"ring",text:"failed"}); |
| 82 | + } else { |
| 83 | + var payload = msg.payload = {}; |
| 84 | + var ev; |
| 85 | + /* 0 - 10 events ending after now ordered by startTime |
| 86 | + * so we find the first that starts after now to |
| 87 | + * give us the "next" event |
| 88 | + */ |
| 89 | + for (var i = 0; i<data.items.length; i++) { |
| 90 | + ev = data.items[i]; |
| 91 | + var start = getEventDate(ev); |
| 92 | + if (start && start.getTime() > now.getTime()) { |
| 93 | + payload.start = start; |
| 94 | + break; |
| 95 | + } |
| 96 | + ev = undefined; |
| 97 | + } |
| 98 | + if (!ev) { |
| 99 | + delete msg.data; |
| 100 | + node.send(msg); |
| 101 | + node.status({fill:"red",shape:"ring",text:"no event"}); |
| 102 | + return; |
| 103 | + } |
| 104 | + if (ev.summary) { |
| 105 | + payload.title = msg.title = ev.summary; |
| 106 | + } |
| 107 | + if (ev.description) { |
| 108 | + payload.description = msg.description = ev.description; |
| 109 | + } else { |
| 110 | + delete msg.description; |
| 111 | + } |
| 112 | + if (ev.location) { |
| 113 | + /* intentionally the same object so that |
| 114 | + * if a node modifies msg.location (for |
| 115 | + * example by looking up |
| 116 | + * msg.location.description and adding |
| 117 | + * msg.location.{lat,lon} then both copies |
| 118 | + * will be updated. |
| 119 | + */ |
| 120 | + payload.location = msg.location = { |
| 121 | + description: ev.location |
| 122 | + }; |
| 123 | + } else { |
| 124 | + delete msg.location; |
| 125 | + } |
| 126 | + if (ev.start && ev.start.date) { |
| 127 | + payload.allDayEvent = true; |
| 128 | + } |
| 129 | + var end = getEventDate(ev, 'end'); |
| 130 | + if (end) { |
| 131 | + payload.end = end; |
| 132 | + } |
| 133 | + if (ev.creator) { |
| 134 | + payload.creator = { |
| 135 | + name: ev.creator.displayName, |
| 136 | + email: ev.creator.email, |
| 137 | + }; |
| 138 | + } |
| 139 | + if (ev.attendees) { |
| 140 | + payload.attendees = []; |
| 141 | + ev.attendees.forEach(function (a) { |
| 142 | + payload.attendees.push({ |
| 143 | + name: a.displayName, |
| 144 | + email: a.email |
| 145 | + }); |
| 146 | + }); |
| 147 | + } |
| 148 | + msg.data = ev; |
| 149 | + node.send(msg); |
| 150 | + node.status({}); |
| 151 | + } |
| 152 | + }); |
| 153 | + }); |
| 154 | + }); |
| 155 | + } |
| 156 | + RED.nodes.registerType("google calendar", GoogleCalendarQueryNode); |
| 157 | + |
| 158 | + function getEventDate(ev, type) { |
| 159 | + if (typeof type === 'undefined') { |
| 160 | + type = 'start'; |
| 161 | + } |
| 162 | + if (ev[type] && ev[type].dateTime) { |
| 163 | + return new Date(ev[type].dateTime); |
| 164 | + } else if (ev.start && ev.start.date) { |
| 165 | + return new Date(ev[type].date); |
| 166 | + } else { |
| 167 | + return null; |
| 168 | + } |
| 169 | + } |
| 170 | + |
| 171 | + GoogleCalendarQueryNode.prototype.calendarByName = function(name) { |
| 172 | + for (var cal in this.calendars) { |
| 173 | + if (this.calendars.hasOwnProperty(cal)) { |
| 174 | + if (this.calendars[cal].summary === name) { |
| 175 | + return this.calendars[cal]; |
| 176 | + } |
| 177 | + } |
| 178 | + } |
| 179 | + return; |
| 180 | + }; |
| 181 | + |
20 | 182 | function GoogleCalendarOutNode(n) { |
21 | 183 | RED.nodes.createNode(this,n); |
22 | 184 | this.google = RED.nodes.getNode(n.google); |
@@ -49,7 +211,6 @@ module.exports = function(RED) { |
49 | 211 | } |
50 | 212 | node.calendars[cal.id] = cal; |
51 | 213 | } |
52 | | - //console.log("Calendars: "+require('util').inspect(node.calendars)); |
53 | 214 | node.status({}); |
54 | 215 |
|
55 | 216 | node.on('input', function(msg) { |
|
0 commit comments