Updated pushbullet node with all push types, added new "pushbullet in" that emits pushes. Added unit tests.

This commit is contained in:
dsundberg
2015-01-27 08:08:54 +01:00
parent 5982da8495
commit 425858d94d
6 changed files with 1872 additions and 180 deletions

View File

@@ -1,5 +1,5 @@
<!--
Copyright 2013 IBM Corp.
Copyright 2013,2015 IBM Corp.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,94 +14,353 @@
limitations under the License.
-->
<!-- PUSHBULLET CONFIG -->
<script type="text/x-red" data-template-name="pushbullet-config">
<div class="form-row">
<label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-config-input-name" placeholder="Name">
</div>
<div class="form-row">
<label for="node-config-input-apikey"><i class="fa fa-lock"></i> API-key</label>
<input type="password" id="node-config-input-apikey">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType('pushbullet-config', {
category: 'config',
color: "rgb(218, 196, 180)",
defaults: {
name: {value: ""}
},
credentials: {
apikey: {type: "password"}
},
label: function() {
return this.name || "Pushbullet config";
}
});
</script>
<!-- PUSHBULLET OUT -->
<script type="text/x-red" data-template-name="pushbullet">
<div class="form-row">
<label for="node-input-title"><i class="fa fa-flag"></i> Title</label>
<input type="text" id="node-input-title" placeholder="Node-RED">
<label for="node-input-config"><i class="fa fa-user"></i> Config</label>
<input type="text" id="node-input-config">
</div>
<div class="form-row">
<label for="node-input-deviceid"><i class="fa fa-mobile"></i> Device ID</label>
<select id="node-input-deviceid">
<option value="">All</option>
<option value="_msg_">- set from msg.deviceid -</option>
</select>
</div>
<div class="form-row">
<label for="node-input-chan"><i class="fa fa-random"></i> Channel</label>
<input type="text" id="node-input-chan" placeholder="channel name">
</div>
<div class="form-row">
<label for="node-config-input-deviceid"><i class="fa fa-user"></i> Device ID</label>
<input type="text" id="node-config-input-deviceid">
<label for="node-input-pushtype"><i class="fa fa-dot-circle-o"></i> Type</label>
<select id="node-input-pushtype">
<optgroup label="Push types">
<option value="address">Address</option>
<option value="file">File</option>
<option value="link">Link</option>
<option value="list">List</option>
<option value="note">Note</option>
<option value="">- set from msg.pushtype -</option>
</optgroup>
<optgroup label="Actions">
<option value="delete">Delete push</option>
<option value="dismissal">Dismiss push</option>
<option value="updatelist">Update list</option>
</optgroup>
</select>
</div>
<div class="form-row">
<label for="node-config-input-pushkey"><i class="fa fa-lock"></i> API Key</label>
<input type="password" id="node-config-input-pushkey">
<label for="node-input-title"><i class="fa fa-random"></i> Title</label>
<input type="text" id="node-input-title" placeholder="Node-RED">
</div>
<br/>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-tips" id="node-tip"><b>Note:</b> Using credentials from global pushkey.js file.</div>
<div class="form-tips" id="pushbullet-migration-info" style="display: none;">
<p><i class="fa fa-random"></i> Configuration node has been migrated, please click Ok and then re-deploy flow to save settings.</p>
</div>
</script>
<script type="text/x-red" data-help-name="pushbullet">
<p>Uses PushBullet to push the <b>msg.payload</b> to a device that has the PushBullet app installed.</p>
<p>Optionally uses <b>msg.topic</b> to set the title, if not already set in the properties.</p>
<p>You need to configure both your <i>API key</i> and the target <i>device ID</i>.
The device ID may be passed in as <b>msg.deviceid</b>.</p>
<p>You can also push to any channels that you own either configured or via <b>msg.channel</b>.</p>
The old method of storing your credentials in the pushkey.js file in the directory <b>above</b> /node-red is deprecated.</p>
<p>The deviceid can be found by clicking on your required device on the <a href="https://www.pushbullet.com/">PushBullet website</a>, once you have logged in.</p>
<p>Uses PushBullet to push <code>msg.payload</code> to a device that has the PushBullet app installed.</p>
<p>Optionally uses <code>msg.topic</code> to set the title, if not already set in the properties.</p>
<p>Optionally uses <code>msg.pushtype</code> to set the type of the push, if not already set in the properties.</p>
<p>Optionally uses <code>msg.deviceid</code> to set the device ID, if not already set in the properties.</p>
<p>You can also push to any channels that you own either configured or via <code>msg.channel</code>.</p>
<p>The node can also <i>dismiss</i> and <i>delete</i> and <i>update</i> items in a pushed list. In this case <code>msg.data.iden</code> must be set to a valid push id, if <code>msg</code> originates from the Pushbullet input node this value is already set.</p>
<p>The old method of storing your credentials in the pushkey.js file in the directory above /node-red is deprecated.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('pushbullet',{
category: 'output',
category: 'social-output',
defaults: {
config: {type: "pushbullet-config", required: true},
pushtype: {value:"note"},
title: {value:""},
chan: {value:"" },
name: {value:""}
},
credentials: {
deviceid: {value: ""},
pushkey: {value: ""}
},
color:"#a7c9a0",
inputs:1,
outputs:0,
icon: "bullet.png",
align: "right",
label: function() {
return this.name||this.title||"pushbullet";
var self = this;
function getName(deviceid) {
if(!self.devicename && deviceid && self.config) {
$.getJSON('pushbullet/'+self.config+'/devices', function(data) {
for(var i=0; i<data.length; i++) {
if(data[i].iden === deviceid) {
self.devicename = data[i].nickname;
self.dirty = true;
RED.view.redraw();
return;
}
}
});
}
}
try {
getName(this.credentials.deviceid);
}
catch(err) {
$.getJSON('credentials/pushbullet/'+this.id, function(data) {
getName(data.deviceid);
});
}
return this.name||this.devicename||this.title||"pushbullet";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditsave: function() {
this.devicename = undefined;
if(this.migrationData) {
$.ajax('pushbullet/'+this.id+'/migrate?save=true');
}
},
oneditprepare: function() {
var node = this, ddConfig = $('#node-input-config'), ddDevice = $('#node-input-deviceid'), ddPushtype = $('#node-input-pushtype');
function updateDeviceList() {
if(!ddConfig.val()) {
ddDevice.children().remove();
ddDevice.append('<option value="">All</option>')
ddDevice.append('<option value="_msg_">- set from msg.deviceid -</option>')
var currentDevice;
if(node.credentials) {
currentDevice = node.credentials.deviceid;
}
if(currentDevice && currentDevice !== "_msg_") {
ddDevice.append('<option value="'+currentDevice+'">'+currentDevice+'</option>');
ddDevice.val(currentDevice);
}
}
else {
var config = RED.nodes.node(ddConfig.val()),
url = 'pushbullet/'+ddConfig.val()+'/devices';
if(config && config.credentials && config.credentials.apikey) {
url += '?apikey='+config.credentials.apikey;
}
$.getJSON(url, function(data) {
ddDevice.children().remove();
ddDevice.append('<option value="">All</option>')
ddDevice.append('<option value="_msg_">- set from msg.deviceid -</option>')
var currentDevice, addCurrent = true;
if(node.credentials) {
currentDevice = node.credentials.deviceid;
}
for(var i=0; i<data.length; i++) {
var dev = data[i];
ddDevice.append('<option value="'+dev.iden+'">'+dev.nickname+' ('+dev.kind+')</option>');
if(dev.iden === currentDevice) {
addCurrent = false;
}
}
if(currentDevice) {
if(addCurrent && currentDevice !== "_msg_") {
ddDevice.append('<option value="'+currentDevice+'">'+currentDevice+'</option>');
}
ddDevice.val(currentDevice);
}
});
}
}
function checkMigration(cb) {
$.getJSON('pushbullet/'+node.id+'/migrate', function(data) {
var showMigration = false;
node.migrationData = data.config;
if(data.migrated) {
if(data.config) {
var configId = data.config;
var configType = 'pushbullet-config';
var configTypeDef = RED.nodes.getType(configType);
RED.nodes.add({
type: configType,
id: configId,
name: "Imported",
users: [node.id],
label: configTypeDef.label,
_def: configTypeDef,
});
}
if(node.credentials) {
if(node.credentials.pushkey) {
if(ddConfig.find('option[value="'+data.config+'"]').length === 0) {
ddConfig.append('<option value="'+data.config+'">Imported</option>');
}
ddConfig.val(data.config);
showMigration = true;
}
else {
ddConfig.val("_ADD_");
}
if(node.credentials.deviceid) {
ddDevice.append('<option value="'+node.credentials.deviceid+'">Imported</option>');
ddDevice.val(node.credentials.deviceid);
showMigration = true;
}
else {
ddDevice.val("");
}
}
}
if(showMigration) {
ddPushtype.val("note");
node.dirty = true;
$('#pushbullet-migration-info').show();
}
if(cb) {
cb(showMigration);
}
});
}
checkMigration(function(migrated) {
if(!migrated) {
ddConfig.change(function() {
if(ddConfig.val() && ddConfig.val() !== "_ADD_") {
updateDeviceList();
}
});
}
});
}
});
</script>
<!-- PUSHBULLET IN -->
<script type="text/x-red" data-template-name="pushbullet in">
<div class="form-row">
<label for="node-input-config"><i class="fa fa-user"></i> Config</label>
<input type="text" id="node-input-config" placeholder="Node-RED">
</div>
<div class="form-row">
<label for="node-input-filters"><i class="fa fa-mobile"></i> Device filter</label>
<select id="node-input-filters" style="width: 60%;" multiple="multiple"></select>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-tips">
<i class="fa fa-mobile"></i> Device filter list is multi-selectable. No selections means no filtering, i.e. all pushes are emitted.
</div>
</script>
<script type="text/x-red" data-help-name="pushbullet in">
<p>Receives Pushbullets from all devices. Messages contain the following data:</p>
<p><code>msg.pushtype</code>: type of message</p>
<p><code>msg.topic</code>: topic information from the push</p>
<p><code>msg.payload</code>: main content of the push</p>
<p><code>msg.data</code>: original object from the pushbullet API containing e.g. sender, receiver and message ids.</p>
<p>Pushes of type <i>link</i> and <i>file</i> will also have <code>msg.message</code> containing the message associated with the push.</p>
<p>For further details of see <a href="https://docs.pushbullet.com/stream/">Pushbullet Stream API</a> and <a href="https://docs.pushbullet.com/v2/pushes/">Pushbullet Push API</a>.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('pushbullet in',{
category: 'social-input',
defaults: {
config: {type: "pushbullet-config", required: true},
name: {value:""}
},
credentials: {
filters: {value: []}
},
color:"#a7c9a0",
inputs:0,
outputs:1,
icon: "bullet.png",
label: function() {
return this.name||"pushbullet";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
$.getJSON('pushbullet/'+this.id,function(data) {
if (data.deviceid) {
$('#node-config-input-deviceid').val(data.deviceid);
var node = this, ddConfig = $('#node-input-config'), ddDevice = $('#node-input-filters');
function updateDeviceList() {
var config = RED.nodes.node(ddConfig.val()),
url = 'pushbullet/'+ddConfig.val()+'/devices';
if(config && config.credentials && config.credentials.apikey) {
url += '?apikey='+config.credentials.apikey;
}
if (data.hasPassword) {
$('#node-config-input-pushkey').val('__PWRD__');
} else {
$('#node-config-input-pushkey').val('');
}
if (data.global) $('#node-tip').show();
else $('#node-tip').hide();
});
},
oneditsave: function() {
var newUser = $('#node-config-input-deviceid').val();
var newPass = $('#node-config-input-pushkey').val();
var credentials = {};
credentials.deviceid = newUser;
if (newPass != '__PWRD__') {
credentials.pushkey = newPass;
$.getJSON(url, function(data) {
var currentDevices = [], addDevices = [];
if(node.credentials && node.credentials.filters) {
currentDevices = node.credentials.filters;
addDevices = node.credentials.filters.splice();
}
var idx;
ddDevice.children().remove();
for(var i=0; i<data.length; i++) {
var dev = data[i];
ddDevice.append('<option value="'+dev.iden+'">'+dev.nickname+' ('+dev.kind+')</option>');
idx = addDevices.indexOf(dev.iden);
if (idx > -1) {
addDevices.splice(idx, 1);
}
}
for(var j=0;j<addDevices.length;j++) {
ddDevice.append('<option value="'+addDevices[j]+'">'+addDevices[j]+'</option>');
}
ddDevice.val(currentDevices);
});
}
$.ajax({
url: 'pushbullet/'+this.id,
type: 'POST',
data: credentials,
success:function(result){}
});
},
ondelete: function() {
$.ajax({
url: 'pushbullet/'+this.id,
type: 'DELETE',
success: function(result) {}
ddConfig.change(function() {
if(ddConfig.val() && ddConfig.val() !== "_ADD_") {
updateDeviceList();
}
});
}
});