@jambonz/node-red-contrib-jambonz 2.2.73 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/examples/Authenticating sip devices.json +1 -0
- package/examples/Conference with LCC.json +1 -0
- package/{src/examples → examples}/Connecting to a dialogflow bot.json +0 -0
- package/examples/Create Call and Send DTMF.json +1 -0
- package/examples/Get Log Data.json +1 -0
- package/examples/Leave Queue.json +1 -0
- package/examples/SIP Responses.json +1 -0
- package/{src/examples → examples}/SIP trunking outbound call.json +0 -0
- package/examples/Simple IVR.json +1 -0
- package/examples/Simple Queue.json +1 -0
- package/examples/Using Redirect.json +1 -0
- package/examples/Voicemail using Listen into S3 bucket.json +130 -0
- package/examples/config.json +1 -0
- package/examples/gather.json +1 -0
- package/examples/lex.json +1 -0
- package/examples/messages.json +1 -0
- package/examples/rasa.json +1 -0
- package/examples/tag a call.json +1 -0
- package/package.json +52 -14
- package/resources/editor.js +414 -0
- package/src/data/recognizer.json +685 -1
- package/src/data/tts.json +2970 -1
- package/src/nodes/auth.html +108 -0
- package/src/nodes/auth.js +43 -0
- package/src/nodes/conference.html +121 -0
- package/src/nodes/conference.js +31 -0
- package/src/nodes/config.html +484 -0
- package/src/nodes/config.js +74 -0
- package/src/nodes/create_call.html +287 -0
- package/src/nodes/create_call.js +104 -0
- package/src/nodes/create_sms.html +106 -0
- package/src/nodes/create_sms.js +65 -0
- package/src/nodes/dequeue.html +102 -0
- package/src/nodes/dequeue.js +25 -0
- package/src/nodes/dial.html +619 -0
- package/src/nodes/dial.js +138 -0
- package/src/nodes/dialogflow.html +260 -0
- package/src/nodes/dialogflow.js +53 -0
- package/src/nodes/dtmf.html +74 -0
- package/src/nodes/dtmf.js +22 -0
- package/src/nodes/enqueue.html +90 -0
- package/src/nodes/enqueue.js +25 -0
- package/src/nodes/gather.html +322 -0
- package/src/nodes/gather.js +83 -0
- package/src/nodes/get_alerts.html +94 -0
- package/src/nodes/get_alerts.js +47 -0
- package/src/nodes/get_calls.html +59 -0
- package/src/nodes/get_calls.js +38 -0
- package/src/nodes/get_recent_calls.html +95 -0
- package/src/nodes/get_recent_calls.js +47 -0
- package/src/nodes/hangup.html +46 -0
- package/src/nodes/hangup.js +20 -0
- package/src/nodes/jambonz.html +63 -38
- package/src/nodes/lcc.html +256 -0
- package/src/nodes/lcc.js +102 -0
- package/src/nodes/leave.html +40 -0
- package/src/nodes/leave.js +21 -0
- package/src/nodes/lex.html +264 -0
- package/src/nodes/lex.js +75 -0
- package/src/nodes/libs.js +99 -0
- package/src/nodes/listen.html +341 -0
- package/src/nodes/listen.js +82 -0
- package/src/nodes/message.html +95 -0
- package/src/nodes/message.js +32 -0
- package/src/nodes/pause.html +62 -0
- package/src/nodes/pause.js +25 -0
- package/src/nodes/play.html +76 -0
- package/src/nodes/play.js +23 -0
- package/src/nodes/rasa.html +106 -0
- package/src/nodes/rasa.js +22 -0
- package/src/nodes/redirect.html +64 -0
- package/src/nodes/redirect.js +24 -0
- package/src/nodes/s3-upload.html +29 -14
- package/src/nodes/s3-upload.js +24 -9
- package/src/nodes/say.html +115 -0
- package/src/nodes/say.js +38 -0
- package/src/nodes/sip-decline.html +76 -0
- package/src/nodes/sip-decline.js +25 -0
- package/src/nodes/sip-refer.html +116 -0
- package/src/nodes/sip-refer.js +33 -0
- package/src/nodes/sip-request.html +96 -0
- package/src/nodes/sip-request.js +36 -0
- package/src/nodes/tag.html +60 -0
- package/src/nodes/tag.js +22 -0
- package/src/nodes/template.html +63 -0
- package/src/nodes/template.js +9 -0
- package/src/nodes/userauth.html +85 -0
- package/src/nodes/userauth.js +70 -0
- package/src/nodes/webhooks.js +0 -16
- package/src/utils/http-helpers.js +68 -0
- package/src/examples/Authenticating sip devices.json +0 -10
- package/src/nodes/http-helpers.js +0 -26
- package/src/nodes/jambonz.js +0 -1044
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
<!-- Javascript -->
|
|
2
|
+
<script type="text/javascript">
|
|
3
|
+
RED.nodes.registerType('create-call',{
|
|
4
|
+
category: 'jambonz',
|
|
5
|
+
color: '#aebfb9',
|
|
6
|
+
defaults: {
|
|
7
|
+
name: {value: ''},
|
|
8
|
+
server: {value: '', required: true, type: 'jambonz_auth'},
|
|
9
|
+
from: {value: '', required: true},
|
|
10
|
+
fromType: {value: ''},
|
|
11
|
+
to: {value: '', required: true},
|
|
12
|
+
toType: {value: ''},
|
|
13
|
+
dest: {value: 'phone', required: true},
|
|
14
|
+
timeout: {},
|
|
15
|
+
application: {value: ''},
|
|
16
|
+
appName: {},
|
|
17
|
+
mode: {value: 'app'},
|
|
18
|
+
call_hook_url : {},
|
|
19
|
+
call_hook_urlType : {value: 'str'},
|
|
20
|
+
call_hook_method : {value : 'GET'},
|
|
21
|
+
call_status_url : {},
|
|
22
|
+
call_status_urlType : {value: 'str'},
|
|
23
|
+
call_status_method : {value : 'GET'},
|
|
24
|
+
vendor: {value: 'default', validate : function (v) {
|
|
25
|
+
console.log(v)
|
|
26
|
+
if ( v == null && $('#node-input-mode').val() == 'url'){
|
|
27
|
+
return(false)
|
|
28
|
+
} else {
|
|
29
|
+
return(true)
|
|
30
|
+
}
|
|
31
|
+
}},
|
|
32
|
+
lang: {value: 'default'},
|
|
33
|
+
xlang: {},
|
|
34
|
+
voice: {value: 'default'},
|
|
35
|
+
xvoice: {},
|
|
36
|
+
transcriptionvendor: {value: 'default', validate : function (v) {
|
|
37
|
+
console.log(v)
|
|
38
|
+
if ( v == null && $('#node-input-mode').val() == 'url'){
|
|
39
|
+
return(false)
|
|
40
|
+
} else {
|
|
41
|
+
return(true)
|
|
42
|
+
}
|
|
43
|
+
}},
|
|
44
|
+
recognizerlang: {value: 'default'}
|
|
45
|
+
},
|
|
46
|
+
inputs:1,
|
|
47
|
+
outputs:1,
|
|
48
|
+
icon: "font-awesome/fa-cubes",
|
|
49
|
+
label: function() {
|
|
50
|
+
return this.name || 'create call';
|
|
51
|
+
},
|
|
52
|
+
oneditprepare: function() {
|
|
53
|
+
var node = this;
|
|
54
|
+
var destElem = $('#node-input-dest');
|
|
55
|
+
var serverElem = $('#node-input-server');
|
|
56
|
+
var applicationElem = $('#node-input-application');
|
|
57
|
+
prepareTtsControls(node);
|
|
58
|
+
prepareSttControls(node);
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
$('#node-input-from').typedInput({
|
|
62
|
+
default: $('#node-input-fromType').val(),
|
|
63
|
+
types: ['str','msg', 'flow', 'global', 'jsonata', 'env'],
|
|
64
|
+
typeField: $('#node-input-fromType')
|
|
65
|
+
});
|
|
66
|
+
$('#node-input-to').typedInput({
|
|
67
|
+
default: $('#node-input-toType').val(),
|
|
68
|
+
types: ['str','msg', 'flow', 'global', 'jsonata', 'env'],
|
|
69
|
+
typeField: $('#node-input-toType')
|
|
70
|
+
});
|
|
71
|
+
$('#node-input-call_hook_url').typedInput({
|
|
72
|
+
default: $('#node-input-call_hook_urlType').val(),
|
|
73
|
+
types: ['str','msg', 'flow', 'global', 'jsonata', 'env'],
|
|
74
|
+
typeField: $('#node-input-call_hook_urlType')
|
|
75
|
+
});
|
|
76
|
+
$('#node-input-call_status_url').typedInput({
|
|
77
|
+
default: $('#node-input-call_status_urlType').val(),
|
|
78
|
+
types: ['str','msg', 'flow', 'global', 'jsonata', 'env'],
|
|
79
|
+
typeField: $('#node-input-call_status_urlType')
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
var populateApplications = function() {
|
|
83
|
+
var serverId = $('#node-input-server option:selected').val();
|
|
84
|
+
$.ajax({
|
|
85
|
+
url: `_jambonz/applications/${serverId}`,
|
|
86
|
+
dataType: 'json',
|
|
87
|
+
timeout: 500,
|
|
88
|
+
error: (err) => {
|
|
89
|
+
console.log(err);
|
|
90
|
+
},
|
|
91
|
+
success: (res) => {
|
|
92
|
+
applicationElem.find('option').remove();
|
|
93
|
+
var options = '';
|
|
94
|
+
res.forEach((app) => {
|
|
95
|
+
if (node.application === app.application_sid) {
|
|
96
|
+
options += `<option value="${app.application_sid}" selected>${app.name}</option>`;
|
|
97
|
+
node.appName = app.name;
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
options += `<option value="${app.application_sid}">${app.name}</option>`;
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
if (options.length) applicationElem.append(options);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
serverElem.change(populateApplications);
|
|
108
|
+
applicationElem.change(() => {
|
|
109
|
+
node.appName = $('#node-input-application option:selected').text();
|
|
110
|
+
});
|
|
111
|
+
$('#url-options').hide();
|
|
112
|
+
$('#node-input-mode').change(function() {
|
|
113
|
+
const mode = $('#node-input-mode').val();
|
|
114
|
+
if (mode == 'app') {
|
|
115
|
+
$('#app-options').show();
|
|
116
|
+
$('#url-options').hide();
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
$('#app-options').hide();
|
|
120
|
+
$('#url-options').show();
|
|
121
|
+
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
</script>
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
<!-- HTML -->
|
|
130
|
+
<script type="text/html" data-template-name="create-call">
|
|
131
|
+
<div class="form-row">
|
|
132
|
+
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
|
133
|
+
<input type="text" id="node-input-name" placeholder="Name">
|
|
134
|
+
</div>
|
|
135
|
+
<div class="form-row">
|
|
136
|
+
<label for="node-input-server">Server</label>
|
|
137
|
+
<input type="text" id="node-input-server">
|
|
138
|
+
</div>
|
|
139
|
+
<div class="form-row">
|
|
140
|
+
<label for="node-input-from">From</label>
|
|
141
|
+
<input type="text" id="node-input-from" placeholder="calling party number">
|
|
142
|
+
<input type="hidden" id="node-input-fromType">
|
|
143
|
+
</div>
|
|
144
|
+
<div class="form-row">
|
|
145
|
+
<label for="node-input-to">To</label>
|
|
146
|
+
<input type="text" id="node-input-to" placeholder="called party info">
|
|
147
|
+
<input type="hidden" id="node-input-toType">
|
|
148
|
+
</div>
|
|
149
|
+
<div class="form-row">
|
|
150
|
+
<label for="node-input-dest">Call type</label>
|
|
151
|
+
<select id="node-input-dest">
|
|
152
|
+
<option value="phone">phone number</option>
|
|
153
|
+
<option value="user">registered sip device/user</option>
|
|
154
|
+
<option value="sip">sip endpoint</option>
|
|
155
|
+
<option value="ms-teams">Microsoft teams</option>
|
|
156
|
+
</select>
|
|
157
|
+
</div>
|
|
158
|
+
<div class="form-row">
|
|
159
|
+
<label for="node-input-timeout">Ring timeout</label>
|
|
160
|
+
<input type="text" id="node-input-timeout" placeholder="ring no answer timeout in secs (default: 60)">
|
|
161
|
+
<input type="hidden" id="node-input-timeoutType">
|
|
162
|
+
</div>
|
|
163
|
+
<div class="form-row">
|
|
164
|
+
<label for="node-input-application">Connect to</label>
|
|
165
|
+
<select id="node-input-mode">
|
|
166
|
+
<option value="app">Application</option>
|
|
167
|
+
<option value="url">Webhooks</option>
|
|
168
|
+
</select>
|
|
169
|
+
</div>
|
|
170
|
+
<div id="app-options">
|
|
171
|
+
<div class="form-row">
|
|
172
|
+
<label for="node-input-application">Application</label>
|
|
173
|
+
<select id="node-input-application">
|
|
174
|
+
</select>
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
<div id="url-options">
|
|
178
|
+
<fieldset>
|
|
179
|
+
<legend>Webhook options</legend>
|
|
180
|
+
<div class="form-row">
|
|
181
|
+
<label for="node-input-call_hook_url">Call Hook URL</label>
|
|
182
|
+
<input type="text" id="node-input-call_hook_url" placeholder="https://example.com/answer">
|
|
183
|
+
<input type="hidden" id="node-input-call_hook_urlType">
|
|
184
|
+
</div>
|
|
185
|
+
<div class="form-row">
|
|
186
|
+
<label for="node-input-call_hook_method">Method</label>
|
|
187
|
+
<select id="node-input-call_hook_method">
|
|
188
|
+
<option value="GET">GET</option>
|
|
189
|
+
<option value="POST">POST</option>
|
|
190
|
+
</select>
|
|
191
|
+
</div>
|
|
192
|
+
<div class="form-row">
|
|
193
|
+
<label for="node-input-call_status_url">Call Status URL</label>
|
|
194
|
+
<input type="text" id="node-input-call_status_url" placeholder="https://example.com/status">
|
|
195
|
+
<input type="hidden" id="node-input-call_status_urlType">
|
|
196
|
+
</div>
|
|
197
|
+
<div class="form-row">
|
|
198
|
+
<label for="node-input-call_status_method">Method</label>
|
|
199
|
+
<select id="node-input-call_status_method">
|
|
200
|
+
<option value="GET">GET</option>
|
|
201
|
+
<option value="POST">POST</option>
|
|
202
|
+
</select>
|
|
203
|
+
</div>
|
|
204
|
+
<fieldset>
|
|
205
|
+
<legend>Speech synthesis options</legend>
|
|
206
|
+
<div class="form-row">
|
|
207
|
+
<label for="node-input-vendor">Vendor</label>
|
|
208
|
+
<select id="node-input-vendor">
|
|
209
|
+
<option value="default" selected disabled>--Select Vendor--</option>
|
|
210
|
+
<option value="google">google</option>
|
|
211
|
+
<option value="aws">aws/polly</option>
|
|
212
|
+
<option value="microsoft">microsoft</option>
|
|
213
|
+
<option value="ibm">ibm</option>
|
|
214
|
+
<option value="nuance">nuance</option>
|
|
215
|
+
</select>
|
|
216
|
+
</div>
|
|
217
|
+
<div class="form-row" style="display: none;">
|
|
218
|
+
<label for="node-input-lang"> Lang</label>
|
|
219
|
+
<input type="text" id="node-input-lang">
|
|
220
|
+
</div>
|
|
221
|
+
<div class="form-row">
|
|
222
|
+
<label for="node-input-xlang">Language</label>
|
|
223
|
+
<select id="node-input-xlang">
|
|
224
|
+
</select>
|
|
225
|
+
</div>
|
|
226
|
+
<div class="form-row" style="display: none;">
|
|
227
|
+
<label for="node-input-voice"> Voice</label>
|
|
228
|
+
<input type="text" id="node-input-voice">
|
|
229
|
+
</div>
|
|
230
|
+
<div class="form-row">
|
|
231
|
+
<label for="node-input-xvoice">Voice</label>
|
|
232
|
+
<select id="node-input-xvoice">
|
|
233
|
+
</select>
|
|
234
|
+
</div>
|
|
235
|
+
<legend>Transcription options</legend>
|
|
236
|
+
<div id="speech-input-container">
|
|
237
|
+
<div class="form-row">
|
|
238
|
+
<label for="node-input-transcriptionvendor">Vendor</label>
|
|
239
|
+
<select id="node-input-transcriptionvendor">
|
|
240
|
+
<option value="default" selected disabled>--Select Vendor--</option>
|
|
241
|
+
<option value="google">Google</option>
|
|
242
|
+
<option value="aws">AWS</option>
|
|
243
|
+
<option value="deepgram">deepgram</option>
|
|
244
|
+
<option value="microsoft">microsoft</option>
|
|
245
|
+
<option value="ibm">ibm</option>
|
|
246
|
+
<option value="nuance">nuance</option>
|
|
247
|
+
|
|
248
|
+
</select>
|
|
249
|
+
</div>
|
|
250
|
+
<div class="form-row">
|
|
251
|
+
<label for="node-input-recognizerlang"><i class="icon-tag"></i> Language</label>
|
|
252
|
+
<select id="node-input-recognizerlang">
|
|
253
|
+
</select>
|
|
254
|
+
</div>
|
|
255
|
+
</fieldset>
|
|
256
|
+
</div>
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
</script>
|
|
260
|
+
|
|
261
|
+
<!-- Help Text -->
|
|
262
|
+
|
|
263
|
+
<script type="text/html" data-help-name="create-call">
|
|
264
|
+
<p>Create an outbound call</p>
|
|
265
|
+
<h3>Properties</h3>
|
|
266
|
+
<p><code>Server</code> -jambonz server to connect to</p>
|
|
267
|
+
<p><code>From</code> - Calling party phone number</p>
|
|
268
|
+
<p><code>To</code> - Called party phone number, or other identifier</p>
|
|
269
|
+
<p><code>Call type</code> - Type of destination: phone number, registered user, sip endpoint, or microsoft teams</p>
|
|
270
|
+
<p><code>Application</code> - Application to execute when call is answered</p>
|
|
271
|
+
|
|
272
|
+
<h3>Outputs</h3>
|
|
273
|
+
<dl class="message-properties">
|
|
274
|
+
<dt>statusCode<span class="property-type">int</span></dt>
|
|
275
|
+
<dd> <code>msg.statusCode</code> will contain the response code from Jambomnz to the createCall request</dd>
|
|
276
|
+
<dt>callSid<span class="property-type">string</span></dt>
|
|
277
|
+
<dd> <code>msg.callSid</code> will contain the SID of the call that was created</dd>
|
|
278
|
+
</dl>
|
|
279
|
+
|
|
280
|
+
<h3>Details</h3>
|
|
281
|
+
The create call command is used to generate a new outbound call.
|
|
282
|
+
When the call is answered the specified application's call hook will be invoked.
|
|
283
|
+
<h3>References</h3>
|
|
284
|
+
<ul>
|
|
285
|
+
<li><a href="https://docs.jambonz.org/rest/#create-a-call">Jambonz reference</a></li>
|
|
286
|
+
</ul>
|
|
287
|
+
</script>
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
var {createHash} = require('crypto');
|
|
2
|
+
var mustache = require('mustache');
|
|
3
|
+
const { toNamespacedPath } = require('path');
|
|
4
|
+
mustache.escape = function(text) {return text;};
|
|
5
|
+
var {v_resolve, doCreateCall, } = require('./libs')
|
|
6
|
+
|
|
7
|
+
module.exports = function(RED) {
|
|
8
|
+
/** Create call */
|
|
9
|
+
function create_call(config) {
|
|
10
|
+
RED.nodes.createNode(this, config);
|
|
11
|
+
var node = this;
|
|
12
|
+
const server = RED.nodes.getNode(config.server);
|
|
13
|
+
|
|
14
|
+
node.on('input', async(msg, send, done) => {
|
|
15
|
+
send = send || function() { node.send.apply(node, arguments);};
|
|
16
|
+
|
|
17
|
+
const {accountSid, apiToken} = server.credentials;
|
|
18
|
+
const url = server.url
|
|
19
|
+
if (!url || !accountSid || !apiToken) {
|
|
20
|
+
node.error(`invalid / missing credentials, skipping create-call node: ${JSON.stringify(server.credentials)}`);
|
|
21
|
+
send(msg);
|
|
22
|
+
if (done) done();
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var from = v_resolve(config.from, config.fromType, this.context(), msg);
|
|
27
|
+
var to = v_resolve(config.to, config.toType, this.context(), msg);
|
|
28
|
+
|
|
29
|
+
const opts = {
|
|
30
|
+
from,
|
|
31
|
+
to: {
|
|
32
|
+
type: config.dest
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
switch (config.mode) {
|
|
37
|
+
case 'app':
|
|
38
|
+
opts.application_sid = config.application
|
|
39
|
+
break
|
|
40
|
+
case 'url':
|
|
41
|
+
opts.call_hook = {
|
|
42
|
+
url: config.call_hook_url,
|
|
43
|
+
method: config.call_hook_method
|
|
44
|
+
}
|
|
45
|
+
opts.call_status_hook = {
|
|
46
|
+
url: config.call_status_url,
|
|
47
|
+
method: config.call_status_method
|
|
48
|
+
}
|
|
49
|
+
opts.speech_synthesis_vendor = config.vendor
|
|
50
|
+
opts.speech_synthesis_language = config.lang
|
|
51
|
+
opts.speech_synthesis_voice = config.voice
|
|
52
|
+
opts.speech_recognizer_vendor = config.transcriptionvendor
|
|
53
|
+
opts.speech_recognizer_language = config.recognizerlang
|
|
54
|
+
break
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (config.timeout) {
|
|
58
|
+
const timeout = parseInt(config.timeout);
|
|
59
|
+
if (timeout > 0) opts.timeout = timeout;
|
|
60
|
+
}
|
|
61
|
+
switch (config.dest) {
|
|
62
|
+
case 'phone':
|
|
63
|
+
opts.to.number = to;
|
|
64
|
+
break;
|
|
65
|
+
case 'user':
|
|
66
|
+
opts.to.name = to;
|
|
67
|
+
break;
|
|
68
|
+
case 'sip':
|
|
69
|
+
opts.to.sipUri = to;
|
|
70
|
+
break;
|
|
71
|
+
case 'ms-teams':
|
|
72
|
+
opts.to.user = to;
|
|
73
|
+
break;
|
|
74
|
+
default:
|
|
75
|
+
if (done) done(`unknown dest type ${config.dest}`);
|
|
76
|
+
else node.error(`unknown dest type ${config.dest}`, msg);
|
|
77
|
+
send(msg);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
node.log(JSON.stringify(opts))
|
|
81
|
+
try {
|
|
82
|
+
const res = await doCreateCall(url, accountSid, apiToken, opts);
|
|
83
|
+
msg.statusCode = 202;
|
|
84
|
+
msg.callSid = res.sid;
|
|
85
|
+
} catch (err) {
|
|
86
|
+
if (err.statusCode) {
|
|
87
|
+
console.log(JSON.stringify(err))
|
|
88
|
+
node.error(`create-call failed with ${err.statusCode}`);
|
|
89
|
+
msg.statusCode = err.statusCode;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
node.error(`Error sending create all ${JSON.stringify(err)}`);
|
|
93
|
+
if (done) done(err);
|
|
94
|
+
else node.error(err, msg);
|
|
95
|
+
send(msg);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
send(msg);
|
|
100
|
+
if (done) done();
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
RED.nodes.registerType('create-call', create_call);
|
|
104
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
<!-- Javascript -->
|
|
2
|
+
<script type="text/javascript">
|
|
3
|
+
RED.nodes.registerType('create-sms',{
|
|
4
|
+
category: 'jambonz',
|
|
5
|
+
color: '#aebfb9',
|
|
6
|
+
defaults: {
|
|
7
|
+
name: {value: ''},
|
|
8
|
+
server: {value: '', required: true, type: 'jambonz_auth'},
|
|
9
|
+
from: {value: '', required: true},
|
|
10
|
+
fromType: {value: ''},
|
|
11
|
+
to: {value: '', required: true},
|
|
12
|
+
toType: {value: ''},
|
|
13
|
+
text: {value: '', required: true},
|
|
14
|
+
textType: {value: ''},
|
|
15
|
+
provider: {value: ''},
|
|
16
|
+
providerType: {value: ''},
|
|
17
|
+
},
|
|
18
|
+
inputs:1,
|
|
19
|
+
outputs:1,
|
|
20
|
+
icon: "font-awesome/fa-cubes",
|
|
21
|
+
label: function() {
|
|
22
|
+
return this.name || 'create sms';
|
|
23
|
+
},
|
|
24
|
+
oneditprepare: function() {
|
|
25
|
+
var node = this;
|
|
26
|
+
|
|
27
|
+
$('#node-input-from').typedInput({
|
|
28
|
+
default: $('#node-input-fromType').val(),
|
|
29
|
+
types: ['str','msg', 'flow', 'global', 'jsonata', 'env'],
|
|
30
|
+
typeField: $('#node-input-fromType')
|
|
31
|
+
});
|
|
32
|
+
$('#node-input-to').typedInput({
|
|
33
|
+
default: $('#node-input-toType').val(),
|
|
34
|
+
types: ['str','msg', 'flow', 'global', 'jsonata', 'env'],
|
|
35
|
+
typeField: $('#node-input-toType')
|
|
36
|
+
});
|
|
37
|
+
$('#node-input-text').typedInput({
|
|
38
|
+
default: $('#node-input-textType').val(),
|
|
39
|
+
types: ['str','msg', 'flow', 'global', 'jsonata', 'env'],
|
|
40
|
+
typeField: $('#node-input-textType')
|
|
41
|
+
});
|
|
42
|
+
$('#node-input-provider').typedInput({
|
|
43
|
+
default: $('#node-input-providerType').val(),
|
|
44
|
+
types: ['str','msg', 'flow', 'global', 'jsonata', 'env'],
|
|
45
|
+
typeField: $('#node-input-providerType')
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
<!-- HTML -->
|
|
54
|
+
|
|
55
|
+
<script type="text/html" data-template-name="create-sms">
|
|
56
|
+
<div class="form-row">
|
|
57
|
+
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
|
58
|
+
<input type="text" id="node-input-name" placeholder="Name">
|
|
59
|
+
</div>
|
|
60
|
+
<div class="form-row">
|
|
61
|
+
<label for="node-input-server">Server</label>
|
|
62
|
+
<input type="text" id="node-input-server">
|
|
63
|
+
</div>
|
|
64
|
+
<div class="form-row">
|
|
65
|
+
<label for="node-input-from">From</label>
|
|
66
|
+
<input type="text" id="node-input-from" placeholder="sending number">
|
|
67
|
+
<input type="hidden" id="node-input-fromType">
|
|
68
|
+
</div>
|
|
69
|
+
<div class="form-row">
|
|
70
|
+
<label for="node-input-to">To</label>
|
|
71
|
+
<input type="text" id="node-input-to" placeholder="destination number">
|
|
72
|
+
<input type="hidden" id="node-input-toType">
|
|
73
|
+
</div>
|
|
74
|
+
<div class="form-row">
|
|
75
|
+
<label for="node-input-text">Text</label>
|
|
76
|
+
<input type="text" id="node-input-text" placeholder="Text">
|
|
77
|
+
<input type="hidden" id="node-input-textType">
|
|
78
|
+
</div>
|
|
79
|
+
<div class="form-row">
|
|
80
|
+
<label for="node-input-provider">SMS Provider</label>
|
|
81
|
+
<input type="text" id="node-input-provider">
|
|
82
|
+
<input type="hidden" id="node-input-providerType">
|
|
83
|
+
</div>
|
|
84
|
+
</script>
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
<!-- Help Text -->
|
|
88
|
+
|
|
89
|
+
<script type="text/html" data-help-name="create-sms">
|
|
90
|
+
<p>Send an SMS</p>
|
|
91
|
+
<h3>Properties</h3>
|
|
92
|
+
<p><code>Server</code> - jambonz server to connect to</p>
|
|
93
|
+
<p><code>From</code> - Sending party phone number</p>
|
|
94
|
+
<p><code>To</code> - Destination phone number</p>
|
|
95
|
+
<p><code>Text</code> - Text message</p>
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
<h3>Details</h3>
|
|
99
|
+
The create message command is used to send an SMS message.
|
|
100
|
+
<!--
|
|
101
|
+
<h3>References</h3>
|
|
102
|
+
<ul>
|
|
103
|
+
<li><a href="https://docs.jambonz.org/rest/#create-a-call">Jambonz reference</a></li>
|
|
104
|
+
</ul>
|
|
105
|
+
-->
|
|
106
|
+
</script>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
var {createHash} = require('crypto');
|
|
2
|
+
const bent = require('bent');
|
|
3
|
+
var mustache = require('mustache');
|
|
4
|
+
mustache.escape = function(text) {return text;};
|
|
5
|
+
var {v_resolve, doCreateMessage} = require('./libs')
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
module.exports = function(RED) {
|
|
9
|
+
/** Create sms */
|
|
10
|
+
function create_sms(config) {
|
|
11
|
+
RED.nodes.createNode(this, config);
|
|
12
|
+
var node = this;
|
|
13
|
+
const server = RED.nodes.getNode(config.server);
|
|
14
|
+
|
|
15
|
+
node.on('input', async(msg, send, done) => {
|
|
16
|
+
send = send || function() { node.send.apply(node, arguments);};
|
|
17
|
+
|
|
18
|
+
const {accountSid, apiToken} = server.credentials;
|
|
19
|
+
const url = server.url
|
|
20
|
+
if (!url || !accountSid || !apiToken) {
|
|
21
|
+
node.log(`invalid / missing credentials, skipping create-message node: ${JSON.stringify(server.credentials)}`);
|
|
22
|
+
send(msg);
|
|
23
|
+
if (done) done();
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
var from = v_resolve(config.from, config.fromType, this.context(), msg);
|
|
28
|
+
var to = v_resolve(config.to, config.toType, this.context(), msg);
|
|
29
|
+
var text = v_resolve(config.text, config.textType, this.context(), msg);
|
|
30
|
+
var provider = v_resolve(config.provider, config.providerType, this.context(), msg);
|
|
31
|
+
|
|
32
|
+
const opts = {
|
|
33
|
+
from,
|
|
34
|
+
to,
|
|
35
|
+
text,
|
|
36
|
+
provider
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
node.log(`sending create message ${JSON.stringify(opts)}`);
|
|
41
|
+
const res = await doCreateMessage(url, accountSid, apiToken, opts);
|
|
42
|
+
msg.statusCode = 202;
|
|
43
|
+
msg.messageSid = res.sid;
|
|
44
|
+
msg.providerResponse = res.providerResponse;
|
|
45
|
+
node.log(`successfully launched call with messageSid ${msg.messageSid}`);
|
|
46
|
+
} catch (err) {
|
|
47
|
+
if (err.statusCode) {
|
|
48
|
+
node.log(`create_message failed with ${err.statusCode}`);
|
|
49
|
+
msg.statusCode = err.statusCode;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
node.log(`Error sending create message ${JSON.stringify(err)}`);
|
|
53
|
+
if (done) done(err);
|
|
54
|
+
else node.error(err, msg);
|
|
55
|
+
send(msg);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
send(msg);
|
|
60
|
+
if (done) done();
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
RED.nodes.registerType('create-sms', create_sms);
|
|
64
|
+
|
|
65
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<!-- Javascript -->
|
|
2
|
+
<script type="text/javascript">
|
|
3
|
+
RED.nodes.registerType('dequeue',{
|
|
4
|
+
category: 'jambonz',
|
|
5
|
+
color: '#bbabaa',
|
|
6
|
+
defaults: {
|
|
7
|
+
name: {value: ''},
|
|
8
|
+
queue: {required: true, value: ''},
|
|
9
|
+
queueType: {value: 'str'},
|
|
10
|
+
actionHook: {},
|
|
11
|
+
actionHookType: {value: 'str'},
|
|
12
|
+
confirmHook: {},
|
|
13
|
+
confirmHookType: {value: 'str'},
|
|
14
|
+
beep: {value: false},
|
|
15
|
+
timeout: {},
|
|
16
|
+
timeoutType: {value: 'num'}
|
|
17
|
+
},
|
|
18
|
+
inputs:1,
|
|
19
|
+
outputs:1,
|
|
20
|
+
icon: "font-awesome/fa-cubes",
|
|
21
|
+
label: function() {
|
|
22
|
+
return this.name || 'dequeue';
|
|
23
|
+
},
|
|
24
|
+
oneditprepare: function() {
|
|
25
|
+
$('#node-input-queue').typedInput({
|
|
26
|
+
types: ['str', 'msg', 'flow', 'global', 'jsonata', 'env'],
|
|
27
|
+
typeField: $('#node-input-queueType')
|
|
28
|
+
});
|
|
29
|
+
$('#node-input-actionHook').typedInput({
|
|
30
|
+
types: ['str', 'msg', 'flow', 'global', 'jsonata', 'env'],
|
|
31
|
+
typeField: $('#node-input-actionHookType')
|
|
32
|
+
});
|
|
33
|
+
$('#node-input-confirmHook').typedInput({
|
|
34
|
+
types: ['str', 'msg', 'flow', 'global', 'jsonata', 'env'],
|
|
35
|
+
typeField: $('#node-input-confirmHookType')
|
|
36
|
+
});
|
|
37
|
+
$('#node-input-timeout').typedInput({
|
|
38
|
+
types: ['num', 'msg', 'flow', 'global', 'jsonata', 'env'],
|
|
39
|
+
typeField: $('#node-input-timeoutType')
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
<!-- HTML -->
|
|
47
|
+
<script type="text/html" data-template-name="dequeue">
|
|
48
|
+
<div class="form-row">
|
|
49
|
+
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
|
50
|
+
<input type="text" id="node-input-name" placeholder="Name">
|
|
51
|
+
</div>
|
|
52
|
+
<div class="form-row">
|
|
53
|
+
<label for="node-input-queue">Queue name</label>
|
|
54
|
+
<input type="text" id="node-input-queue" placeholder="name of queue to remove caller from">
|
|
55
|
+
<input type="hidden" id="node-input-queueType">
|
|
56
|
+
</div>
|
|
57
|
+
<div class="form-row">
|
|
58
|
+
<label for="node-input-beep">Play beep on connecting</label>
|
|
59
|
+
<input type="checkbox" id="node-input-beep">
|
|
60
|
+
</div>
|
|
61
|
+
<div class="form-row">
|
|
62
|
+
<label for="node-input-actionHook">Action hook</label>
|
|
63
|
+
<input type="text" id="node-input-actionHook" placeholder="webhook url">
|
|
64
|
+
<input type="hidden" id="node-input-actionHookType">
|
|
65
|
+
</div>
|
|
66
|
+
<div class="form-row">
|
|
67
|
+
<label for="node-input-confirmHook">Confirm hook</label>
|
|
68
|
+
<input type="text" id="node-input-confirmHook" placeholder="webhook url">
|
|
69
|
+
<input type="hidden" id="node-input-confirmHookType">
|
|
70
|
+
</div>
|
|
71
|
+
<div class="form-row">
|
|
72
|
+
<label for="node-input-timeout">Timeout</label>
|
|
73
|
+
<input type="text" id="node-input-timeout" placeholder="seconds to wait if queue is empty">
|
|
74
|
+
<input type="hidden" id="node-input-timeoutType">
|
|
75
|
+
</div>
|
|
76
|
+
</script>
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
<!-- Help Text -->
|
|
80
|
+
<script type="text/html" data-help-name="dequeue">
|
|
81
|
+
<p>removes the a call from the front of a queue and bridges that call to the current caller.</p>
|
|
82
|
+
<h3>Properties</h3>
|
|
83
|
+
<p><code>Queue name</code> - Name of the queue.</p>
|
|
84
|
+
<p><code>Play beep on connecting</code> - Play a beep tone to this caller only just prior to connecting the queued call.</p>
|
|
85
|
+
<p><code>Action hook</code> - A webhook invoke when call ends.</p>
|
|
86
|
+
<p><code>Confirm hook</code> - A webhook for an application to run on the callee's end before the call is bridged.</p>
|
|
87
|
+
<p><code>Timeout</code> - number of seconds to wait on an empty queue before returning.</p>
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
<h3>Outputs</h3>
|
|
91
|
+
<dl class="message-properties">
|
|
92
|
+
<dt>jambonz<span class="property-type">object</span></dt>
|
|
93
|
+
<dd> <code>msg.jambonz</code> will contain any previous actions provided to the input with the new <code>dequeue</code> action appended </dd>
|
|
94
|
+
</dl>
|
|
95
|
+
|
|
96
|
+
<h3>Details</h3>
|
|
97
|
+
The dequeue verb removes the a call from the front of a specified queue and bridges that call to the current caller.
|
|
98
|
+
<h3>References</h3>
|
|
99
|
+
<ul>
|
|
100
|
+
<li><a href="https://docs.jambonz.org/jambonz/#dequeue">Jambonz dequeue reference</a></li>
|
|
101
|
+
</ul>
|
|
102
|
+
</script>
|