Skip to content

Commit 490d780

Browse files
committed
Merge pull request #18 from hindessm/google-calendar
Google Calendar
2 parents 8098f7b + 10d8b57 commit 490d780

File tree

5 files changed

+549
-1
lines changed

5 files changed

+549
-1
lines changed

google/calendar.html

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<!--
2+
Copyright 2014 IBM Corp.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
-->
16+
17+
<script type="text/x-red" data-template-name="google calendar out">
18+
<div class="form-row">
19+
<label for="node-input-google"><i class="fa fa-user"></i> Google</label>
20+
<input type="text" id="node-input-google">
21+
</div>
22+
<div class="form-row">
23+
<label for="node-input-calendar"><i class="fa fa-tag"></i> Calendar</label>
24+
<input type="text" id="node-input-calendar">
25+
</div>
26+
<div class="form-row">
27+
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
28+
<input type="text" id="node-input-name">
29+
</div>
30+
</script>
31+
32+
<script type="text/x-red" data-help-name="google calendar out">
33+
<p>Create an entry in a <a href="https://www.google.com/calendar">Google Calendar</a>.</p>
34+
<p>The incoming message can provide the following properties:
35+
<ul>
36+
<li><b>payload</b> - either a string to describe the event using <a href="https://support.google.com/calendar/answer/36604?hl=en">quick add format</a> or an object representing the request body for an <a href="https://developers.google.com/google-apps/calendar/v3/reference/events/insert">insert request</a></li>
37+
<li><b>calendar</b> - the calendar to add the event to (optional, defaults to the node calendar property or the users primary calendar)</li>
38+
<li><b>sendNotifications</b> - a boolean to determine if notifications should be sent to attendees (optional, defaults to false)</li>
39+
</ul>
40+
</p>
41+
</script>
42+
43+
<script type="text/javascript">
44+
RED.nodes.registerType('google calendar out',{
45+
category: 'social',
46+
color:"#C0DEED",
47+
defaults: {
48+
google: {type:"google-credentials",required:true},
49+
name: {value:""},
50+
calendar: {value:""}
51+
},
52+
inputs:1,
53+
outputs:0,
54+
icon: "google-calendar.png",
55+
align: "right",
56+
label: function() {
57+
return this.name||"Google Calendar";
58+
}
59+
});
60+
</script>

google/calendar.js

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/**
2+
* Copyright 2014 IBM Corp.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
**/
16+
17+
module.exports = function(RED) {
18+
"use strict";
19+
20+
function GoogleCalendarOutNode(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+
//console.log("Calendars: "+require('util').inspect(node.calendars));
53+
node.status({});
54+
55+
node.on('input', function(msg) {
56+
node.status({fill:"blue",shape:"dot",text:"creating"});
57+
var cal = node.calendars[msg.calendar] || node.calendarByName(msg.calendar) || node.calendars[node.calendar];
58+
if (!cal) {
59+
node.status({fill:"red",shape:"ring",text:"invalid calendar"});
60+
return;
61+
}
62+
var request = {
63+
method: 'POST',
64+
};
65+
if (typeof msg.payload === 'object') {
66+
request.url = 'https://www.googleapis.com/calendar/v3/calendars/'+cal.id+'/events';
67+
request.body = msg.payload;
68+
} else {
69+
request.url = 'https://www.googleapis.com/calendar/v3/calendars/'+cal.id+'/events/quickAdd';
70+
request.form = {
71+
text: RED.util.ensureString(msg.payload)
72+
};
73+
}
74+
if (node.sendNotifications || msg.sendNotifications) {
75+
request.query = {
76+
sendNotifications: true
77+
};
78+
}
79+
node.google.request(request, function(err, data) {
80+
if (err) {
81+
node.error(err.toString());
82+
node.status({fill:"red",shape:"ring",text:"failed"});
83+
} else if (data.error) {
84+
node.error(data.error.message);
85+
node.status({fill:"red",shape:"ring",text:"failed"});
86+
} else {
87+
node.status({});
88+
}
89+
});
90+
});
91+
});
92+
}
93+
RED.nodes.registerType("google calendar out", GoogleCalendarOutNode);
94+
95+
GoogleCalendarOutNode.prototype.calendarByName = function(name) {
96+
for (var cal in this.calendars) {
97+
if (this.calendars.hasOwnProperty(cal)) {
98+
if (this.calendars[cal].summary === name) {
99+
return this.calendars[cal];
100+
}
101+
}
102+
}
103+
return;
104+
};
105+
}

google/google.html

+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
<!--
2+
Copyright 2014 IBM Corp.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
-->
16+
17+
<script type="text/x-red" data-template-name="google-credentials">
18+
<div id="node-config-google-client-keys">
19+
<div class="form-row">
20+
<p style="margin-top: 10px;"><b>1.</b> Create your own project by following these <a href="https://developers.google.com/api-client-library/javascript/start/start-js#Getkeysforyourapplication" target="_blank" style="text-decoration:underline;">instructions</a></p>
21+
</div>
22+
<div class="form-tips" id="node-config-google-tooltip">
23+
</div>
24+
<div class="form-row">
25+
<p style="margin-top: 10px;"><b>2.</b> Copy the project credentials here:</p>
26+
</div>
27+
<div class="form-row">
28+
<label style="margin-left: 10px; margin-right: -10px;" for="node-config-input-clientId"><i class="fa fa-user"></i> Client Id</label>
29+
<input type="password" id="node-config-input-clientId">
30+
</div>
31+
<div class="form-row">
32+
<label style="margin-left: 10px; margin-right: -10px;" for="node-config-input-clientSecret"><i class="fa fa-key"></i> Secret</label>
33+
<input type="password" id="node-config-input-clientSecret">
34+
</div>
35+
<div class="form-row">
36+
<label>&nbsp;</label>
37+
<a class="btn" id="node-config-start-auth" href="#" target="_blank">Authenticate with Google</a>
38+
</div>
39+
</div>
40+
<div id="node-config-google">
41+
<div class="form-row">
42+
<label><i class="fa fa-user"></i> Google User</label><span id="node-config-google-displayName" class="input-xlarge uneditable-input"></span>
43+
</div>
44+
<input type="hidden" id="node-config-input-displayName">
45+
</div>
46+
</script>
47+
48+
<script type="text/javascript">
49+
(function() {
50+
RED.nodes.registerType('google-credentials',{
51+
category: 'config',
52+
defaults: {
53+
displayName: {value:""}
54+
},
55+
credentials: {
56+
displayName: {type:"text"},
57+
clientId: { type: "password"},
58+
clientSecret: { type: "password"}
59+
},
60+
label: function() {
61+
return this.displayName || 'Google'; // TODO: fix this
62+
},
63+
exportable: false,
64+
oneditprepare: function() {
65+
var id = this.id;
66+
var pathname = document.location.pathname;
67+
if (pathname.slice(-1) != "/") {
68+
pathname += "/";
69+
}
70+
var callback = location.protocol + "//" +
71+
location.hostname + ":" + location.port +
72+
pathname + "google-credentials/auth/callback";
73+
$("#node-config-google-tooltip").html("<p>Please configure the authorized <b>Redirect URIs</b> of your app to include the following url:</p>\n<code>"+callback+"</code>");
74+
75+
function updateGoogleAuthButton() {
76+
var v1 = $("#node-config-input-clientId").val();
77+
var v2 = $("#node-config-input-clientSecret").val();
78+
$("#node-config-start-auth").toggleClass("disabled",(v1.length === 0 || v2.length === 0));
79+
}
80+
$("#node-config-input-clientId").on('change keydown paste input',updateGoogleAuthButton);
81+
$("#node-config-input-clientSecret").on('change keydown paste input',updateGoogleAuthButton);
82+
83+
function updateGoogleDisplayName(dn) {
84+
$("#node-config-google-client-keys").hide();
85+
$("#node-config-google").show();
86+
$("#node-config-input-displayName").val(dn);
87+
$("#node-config-google-displayName").html(dn);
88+
}
89+
90+
function pollGoogleCredentials() {
91+
$.getJSON('credentials/google-credentials/'+id,function(data) {
92+
if (data.displayName) {
93+
$("#node-config-dialog-ok").button("enable");
94+
updateGoogleDisplayName(data.displayName);
95+
delete window.googleConfigNodeIntervalId;
96+
} else {
97+
window.googleConfigNodeIntervalId = window.setTimeout(pollGoogleCredentials,2000);
98+
}
99+
});
100+
}
101+
102+
updateGoogleAuthButton();
103+
104+
if (this.displayName) {
105+
updateGoogleDisplayName(this.displayName);
106+
} else {
107+
$("#node-config-google-client-keys").show();
108+
$("#node-config-google").hide();
109+
$("#node-config-dialog-ok").button("disable");
110+
}
111+
112+
$("#node-config-start-auth").mousedown(function() {
113+
var clientId = $("#node-config-input-clientId").val();
114+
var clientSecret = $("#node-config-input-clientSecret").val();
115+
var url = 'google-credentials/auth?id='+id+'&clientId='+clientId+"&clientSecret="+clientSecret+"&callback="+encodeURIComponent(callback);
116+
$(this).attr("href",url);
117+
window.googleConfigNodeIntervalId = window.setTimeout(pollGoogleCredentials,2000);
118+
});
119+
$("#node-config-start-auth").click(function(e) {
120+
var clientId = $("#node-config-input-clientId").val();
121+
var clientSecret = $("#node-config-input-clientSecret").val();
122+
if (clientId === "" || clientSecret === "") {
123+
e.preventDefault();
124+
}
125+
});
126+
},
127+
oneditsave: function() {
128+
if (window.googleConfigNodeIntervalId) {
129+
window.clearTimeout(window.googleConfigNodeIntervalId);
130+
delete window.googleConfigNodeIntervalId;
131+
}
132+
},
133+
oneditcancel: function() {
134+
if (window.googleConfigNodeIntervalId) {
135+
window.clearTimeout(window.googleConfigNodeIntervalId);
136+
delete window.googleConfigNodeIntervalId;
137+
}
138+
}
139+
});
140+
})();
141+
</script>

0 commit comments

Comments
 (0)