Skip to content
This repository was archived by the owner on Jan 28, 2019. It is now read-only.

Commit 0556822

Browse files
committed
Merge pull request #73 from medic/750-autoreply-deny-list
added support for outgoing_deny_list conf in default_response transit…
2 parents 45c4dc2 + a093a57 commit 0556822

File tree

6 files changed

+212
-57
lines changed

6 files changed

+212
-57
lines changed

lib/messages.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ function addMessage(opts) {
2020
try {
2121
utils.addMessage(doc, {
2222
phone: String(phone),
23-
message: template.render(opts.message, details)
23+
message: template.render(opts.message, details),
24+
state: opts.state
2425
});
2526
} catch(e) {
2627
utils.addError(doc, {

lib/utils.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ var addMessage = function(doc, options) {
147147
]
148148
});
149149

150-
setTaskState(task, 'pending');
150+
setTaskState(task, options.state || 'pending');
151151

152152
doc.tasks.push(task);
153153
};
@@ -508,6 +508,11 @@ module.exports = {
508508
/*
509509
* Return message from configured translations given key and locale.
510510
*
511+
* If translation is not found return the translation key. Otherwise
512+
* messages won't get added because of an empty message. Better to at
513+
* least surface something in the UI providing a clue that something is
514+
* misconfigured as opposed to broken.
515+
*
511516
* @param {String} key - translation key/identifier
512517
* @param {String} locale - short locale string
513518
*
@@ -516,7 +521,7 @@ module.exports = {
516521
translate: function(key, locale) {
517522

518523
var translations = config.get('translations'),
519-
msg;
524+
msg = key;
520525

521526
_.each(translations, function(t) {
522527
if (t.key === key) {
@@ -529,5 +534,8 @@ module.exports = {
529534

530535
return msg;
531536

537+
},
538+
escapeRegex: function(s) {
539+
return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
532540
}
533541
}

test/unit/default_responses.js

+139-42
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@ exports.tearDown = function(callback) {
2020
restore([
2121
transition.filter,
2222
transition._isMessageEmpty,
23+
transition._isMessageFromGateway,
2324
transition._isFormNotFound,
2425
transition._isConfigFormsOnlyMode,
2526
transition._isReportedAfterStartDate,
27+
transition._isResponseAllowed,
2628
transition._getConfig,
2729
transition._getLocale,
2830
transition._translate,
@@ -75,54 +77,96 @@ exports['when doc has errors still pass filter'] = function(test) {
7577
test.done();
7678
};
7779

78-
exports['do not pass filter when message is from gateway'] = function(test) {
79-
sinon.stub(transition, '_getConfig').returns('+774455558888');
80+
exports['filter passes when message is from gateway'] = function(test) {
81+
sinon.stub(transition, '_isMessageFromGateway').returns(true);
8082
test.equals(transition.filter({
81-
from: '+222',
82-
type: 'data_record',
83-
sms_message: {
84-
from: '+774455558888'
85-
}
86-
}), false);
83+
from: 'x',
84+
type: 'data_record'
85+
}), true);
8786
test.done();
8887
};
8988

90-
exports['do not pass filter when gateway config is missing country code'] = function(test) {
91-
sinon.stub(transition, '_getConfig').returns('446681800');
89+
exports['filter passes when message is not from gateway'] = function(test) {
90+
sinon.stub(transition, '_isMessageFromGateway').returns(false);
9291
test.equals(transition.filter({
93-
from: '+222',
94-
type: 'data_record',
95-
sms_message: {
96-
from: '+41446681800'
97-
}
98-
}), false);
92+
from: 'x',
93+
type: 'data_record'
94+
}), true);
95+
test.done();
96+
};
97+
98+
exports['describe _isMessageFromGateway'] = function(test) {
99+
var tests = [
100+
['+774455558888', '77-44-5555-8888', true],
101+
['+774455558889', '77-44-5555-8888', false],
102+
// missing country code matches
103+
['+41446681800', '446681800', true]
104+
];
105+
_.each(tests, function(t) {
106+
var s = sinon.stub(transition, '_getConfig');
107+
s.withArgs('gateway_number').returns(t[0]);
108+
test.equals(transition._isMessageFromGateway({from: t[1]}), t[2]);
109+
s.restore();
110+
});
99111
test.done();
100112
};
101113

102-
exports['do not pass filter when numbers are same but different formats'] = function(test) {
103-
sinon.stub(transition, '_getConfig').returns('77-44-5555-8888');
114+
exports['filter passes when response is allowed'] = function(test) {
115+
// Filter passes because message is added with a 'denied' state.
116+
sinon.stub(transition, '_isResponseAllowed').returns(true);
104117
test.equals(transition.filter({
105-
from: '+222',
106-
type: 'data_record',
107-
sms_message: {
108-
from: '+774455558888'
109-
}
110-
}), false);
118+
from: 'x',
119+
type: 'data_record'
120+
}), true);
111121
test.done();
112122
};
113123

114-
exports['pass filter when message is not from gateway'] = function(test) {
115-
sinon.stub(transition, '_getConfig').returns('+774455558889')
124+
exports['filter passes when response is not allowed'] = function(test) {
125+
// Filter passes because message is added with a 'denied' state.
126+
sinon.stub(transition, '_isResponseAllowed').returns(false);
116127
test.equals(transition.filter({
117-
from: '+222',
118-
type: 'data_record',
119-
sms_message: {
120-
from: '+774455558888'
121-
}
128+
from: 'x',
129+
type: 'data_record'
122130
}), true);
123131
test.done();
124132
};
125133

134+
exports['describe _isResponseAllowed'] = function(test) {
135+
/*
136+
* Support comma separated string config to match an outgoing phone number
137+
* or MNO (mobile network operator) defined string.
138+
*/
139+
var tests = [
140+
// denied
141+
['+123', '+123', false],
142+
['+123', '+123999999', false],
143+
['SAFARI', 'SAFARICOM', false],
144+
['Safari', 'SAFARICOM', false],
145+
['+123,+456,+789', '+456', false],
146+
['+123,+456,+789', '+4569999999', false],
147+
['SAFARI, ORANGE', 'ORANGE NET', false],
148+
['0', '0000123', false],
149+
['0', '0', false],
150+
// allowed
151+
['+123', '+999', true],
152+
['SAFARI, ORANGE NET', 'ORANGE', true],
153+
['VIVO', 'EM VIVO', true],
154+
['0', '-1', true],
155+
// allow falsey inputs
156+
['snarf', undefined, true],
157+
['snarf', null, true],
158+
['', '+123', true],
159+
['', '', true]
160+
];
161+
_.each(tests, function(t) {
162+
var s = sinon.stub(transition, '_getConfig');
163+
s.withArgs('outgoing_deny_list').returns(t[0]);
164+
test.equals(transition._isResponseAllowed({from: t[1]}), t[2]);
165+
s.restore();
166+
});
167+
test.done();
168+
};
169+
126170
exports['do nothing if reported date is not after config start date'] = function(test) {
127171
transition._isReportedAfterStartDate.restore();
128172
sinon.stub(transition, '_isReportedAfterStartDate').returns(false);
@@ -162,14 +206,14 @@ exports['when doc has no errors, form is not found returns false'] = function(te
162206

163207
exports['isReportedAfterStartDate returns false if config start date is whitespace'] = function(test) {
164208
transition._isReportedAfterStartDate.restore();
165-
sinon.stub(transition, '_getConfig').returns({ start_date: ' ' });
209+
sinon.stub(transition, '_getConfig').withArgs('default_responses').returns({ start_date: ' ' });
166210
test.equals(transition._isReportedAfterStartDate({}), false);
167211
test.done();
168212
};
169213

170214
exports['isReportedAfterStartDate returns true when reported date is after start date'] = function(test) {
171215
transition._isReportedAfterStartDate.restore();
172-
sinon.stub(transition, '_getConfig').returns({ start_date: '2014-01-01' });
216+
sinon.stub(transition, '_getConfig').withArgs('default_responses').returns({ start_date: '2014-01-01' });
173217
test.equals(transition._isReportedAfterStartDate({
174218
reported_date: 1412641215000
175219
}), true);
@@ -178,7 +222,7 @@ exports['isReportedAfterStartDate returns true when reported date is after start
178222

179223
exports['isReportedAfterStartDate returns false when reported date is before start date'] = function(test) {
180224
transition._isReportedAfterStartDate.restore();
181-
sinon.stub(transition, '_getConfig').returns({ start_date: '2014-12-01' });
225+
sinon.stub(transition, '_getConfig').withArgs('default_responses').returns({ start_date: '2014-12-01' });
182226
test.equals(transition._isReportedAfterStartDate({
183227
reported_date: 1412641215000
184228
}), false);
@@ -188,7 +232,7 @@ exports['isReportedAfterStartDate returns false when reported date is before sta
188232
exports['add response if unstructured message and setting enabled'] = function(test) {
189233

190234
sinon.stub(transition, '_isConfigFormsOnlyMode').returns(false);
191-
sinon.stub(config, 'get').returns([
235+
sinon.stub(config, 'get').withArgs('translations').returns([
192236
{
193237
'key': 'sms_received',
194238
'default': 'SMS rcvd, thx!'
@@ -218,8 +262,7 @@ exports['add response if unstructured message and setting enabled'] = function(t
218262
};
219263

220264
exports['add response if unstructured message (form prop is undefined)'] = function(test) {
221-
// stub the translations config
222-
sinon.stub(config, 'get').returns([
265+
sinon.stub(config, 'get').withArgs('translations').returns([
223266
{
224267
'key': 'sms_received',
225268
'default': 'SMS rcvd, thx!'
@@ -253,7 +296,7 @@ exports['do not add response if valid form'] = function(test) {
253296
* on different transition.
254297
*/
255298

256-
sinon.stub(config, 'get').returns([
299+
sinon.stub(config, 'get').withArgs('translations').returns([
257300
{
258301
'key': 'sms_received',
259302
'default': 'SMS rcvd, thx!'
@@ -278,7 +321,7 @@ exports['do not add response if valid form'] = function(test) {
278321
exports['add response if form not found'] = function(test) {
279322
sinon.stub(transition, '_isConfigFormsOnlyMode').returns(false);
280323
// stub the translations config
281-
sinon.stub(config, 'get').returns([
324+
sinon.stub(config, 'get').withArgs('translations').returns([
282325
{
283326
'key': 'sms_received',
284327
'default': 'SMS rcvd, thx!'
@@ -311,7 +354,7 @@ exports['add response if form not found'] = function(test) {
311354
exports['add response if form not found and forms_only_mode'] = function(test) {
312355
sinon.stub(transition, '_isConfigFormsOnlyMode').returns(true);
313356
// stub the translations config
314-
sinon.stub(config, 'get').returns([
357+
sinon.stub(config, 'get').withArgs('translations').returns([
315358
{
316359
'key': 'form_not_found',
317360
'default': 'Form was not recognized.'
@@ -345,7 +388,7 @@ exports['add response if form not found and respect locale'] = function(test) {
345388
sinon.stub(transition, '_isConfigFormsOnlyMode').returns(false);
346389
sinon.stub(transition, '_getLocale').returns('fr');
347390
// stub the translations config
348-
sinon.stub(config, 'get').returns([
391+
sinon.stub(config, 'get').withArgs('translations').returns([
349392
{
350393
key: 'sms_received',
351394
default: 'SMS message rcvd',
@@ -393,7 +436,7 @@ exports['add response if form not found and respect locale'] = function(test) {
393436
exports['add response to empty message'] = function (test) {
394437
sinon.stub(transition, '_isConfigFormsOnlyMode').returns(false);
395438
// stub the translations config
396-
sinon.stub(config, 'get').returns([
439+
sinon.stub(config, 'get').withArgs('translations').returns([
397440
{
398441
'key': 'empty',
399442
'default': 'SMS appears empty.'
@@ -423,3 +466,57 @@ exports['add response to empty message'] = function (test) {
423466
});
424467
};
425468

469+
exports['add response when recipient is allowed'] = function (test) {
470+
sinon.stub(transition, '_isResponseAllowed').returns(true);
471+
sinon.stub(config, 'get').withArgs('translations').returns([
472+
{
473+
'key': 'sms_received',
474+
'default': 'ahoy mate'
475+
}
476+
]);
477+
var messageFn = sinon.spy(messages, 'addMessage');
478+
test.expect(4);
479+
var doc = {
480+
from: 'x',
481+
type: 'data_record'
482+
};
483+
transition.onMatch({ doc: doc }, {}, {}, function(err, changed) {
484+
test.ok(messageFn.calledOnce);
485+
test.ok(messageFn.calledWith({
486+
doc: doc,
487+
phone: 'x',
488+
message: 'ahoy mate'
489+
}));
490+
test.equals(err, null);
491+
test.equals(changed, true);
492+
test.done();
493+
});
494+
};
495+
496+
exports['add response with denied state when recipient is denied'] = function (test) {
497+
sinon.stub(transition, '_isResponseAllowed').returns(false);
498+
sinon.stub(config, 'get').withArgs('translations').returns([
499+
{
500+
'key': 'sms_received',
501+
'default': 'ahoy mate'
502+
}
503+
]);
504+
var messageFn = sinon.spy(messages, 'addMessage');
505+
test.expect(4);
506+
var doc = {
507+
from: 'x',
508+
type: 'data_record'
509+
};
510+
transition.onMatch({ doc: doc }, {}, {}, function(err, changed) {
511+
test.ok(messageFn.calledOnce);
512+
test.ok(messageFn.calledWith({
513+
doc: doc,
514+
phone: 'x',
515+
message: 'ahoy mate',
516+
state: 'denied'
517+
}));
518+
test.equals(err, null);
519+
test.equals(changed, true);
520+
test.done();
521+
});
522+
};

test/unit/utils.js

+22-1
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@ process.env.TEST_ENV = 'hello'; // required for ../../db.js
33
var _ = require('underscore'),
44
db = require('../../db'),
55
sinon = require('sinon'),
6-
utils = require('../../lib/utils');
6+
utils = require('../../lib/utils'),
7+
config = require('../../config');
78

89
exports.tearDown = function(callback) {
910
if (db.view.restore) {
1011
db.view.restore();
1112
}
13+
if (config.get.restore) {
14+
config.get.restore();
15+
}
1216
callback();
1317
}
1418

@@ -412,3 +416,20 @@ exports['applyPhoneFilters performs replace'] = function(test) {
412416

413417
test.done();
414418
}
419+
420+
exports['translate returns message if key found in translations'] = function(test) {
421+
sinon.stub(config, 'get').withArgs('translations').returns([
422+
{
423+
key: 'sms_received',
424+
default: 'got it!'
425+
}
426+
]);
427+
test.equals(utils.translate('sms_received'), 'got it!');
428+
test.done();
429+
}
430+
431+
exports['translate returns key if translations not found'] = function(test) {
432+
sinon.stub(config, 'get').withArgs('translations').returns([]);
433+
test.equals(utils.translate('sms_received'), 'sms_received');
434+
test.done();
435+
}

0 commit comments

Comments
 (0)