Skip to content
This repository has been archived by the owner on Jun 12, 2018. It is now read-only.

Add dialogue action for sending over a different channel #1042

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions go/apps/dialogue/templates/dialogue/edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@
</div>

<div class="form-group">
<label>Channel type</label>

<select id="delivery-class" class="form-control">
{% for delivery_class, label in delivery_classes %}
<option value="{{ delivery_class }}" {% if delivery_class == current_delivery_class %} selected {% endif %}>
{{ label }}
{% for delivery_class in delivery_classes %}
<option value="{{ delivery_class.name }}" {% if delivery_class.name == current_delivery_class %} selected {% endif %}>
{{ delivery_class.label }}
</option>
{% endfor %}
</select>

<label>Channel type</label>
</div>
</div>

Expand Down
64 changes: 52 additions & 12 deletions go/apps/dialogue/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from go.apps.tests.view_helpers import AppViewsHelper
from go.base.tests.helpers import GoDjangoTestCase
from go.vumitools.api import VumiApiCommand
from go.vumitools.contact.models import DELIVERY_CLASSES


class TestDialogueViews(GoDjangoTestCase):
Expand Down Expand Up @@ -104,6 +105,40 @@ def test_show_running(self):
conv_helper.get_action_view_url('send_jsbox'))

def test_edit(self):
conv_helper = self.setup_conversation(name=u"myconv")
self.mock_rpc.set_response(result={"poll": {}})
response = self.client.get(conv_helper.get_view_url('edit'))

self.assertContains(response, u"myconv")
self.assertContains(response, 'diagram')

def test_edit_channel_types(self):
conv_helper = self.setup_conversation()
self.mock_rpc.set_response(result={"poll": {}})
response = self.client.get(conv_helper.get_view_url('edit'))

for d in DELIVERY_CLASSES.itervalues():
self.assertContains(response, d['label'])

def test_edit_model_data(self):
conv_helper = self.setup_conversation()
conversation = conv_helper.get_conversation()

poll = {}
self.mock_rpc.set_response(result={"poll": poll})
response = self.client.get(conv_helper.get_view_url('edit'))

expected = poll.copy()
expected.update({
'campaign_id': conversation.user_account.key,
'conversation_key': conversation.key,
'urls': {"show": conv_helper.get_view_url('show')}
})

model_data = response.context["model_data"]
self.assertEqual(json.loads(model_data), expected)

def test_edit_model_data_groups(self):
conv_helper = self.setup_conversation(
with_group=False, started=False, name=u"myconv")

Expand All @@ -118,24 +153,29 @@ def test_edit(self):
'name': 'foo'
}]
}

self.mock_rpc.set_response(result={"poll": poll})
response = self.client.get(conv_helper.get_view_url('edit'))
self.assertContains(response, u"myconv")
self.assertContains(response, 'diagram')

self.assertContains(response, 'USSD')
self.assertContains(response, 'SMS')
self.assertContains(response, 'Google Talk')
self.assertContains(response, 'Mxit')
self.assertContains(response, 'WeChat')
self.assertContains(response, 'Twitter')
expected = poll.copy()
expected.update({'groups': [group1.get_data(), group2.get_data()]})

model_data = response.context["model_data"]
self.assertEqual(json.loads(model_data), expected)

def test_edit_model_data_channel_types(self):
conv_helper = self.setup_conversation()

poll = {}
self.mock_rpc.set_response(result={"poll": poll})
response = self.client.get(conv_helper.get_view_url('edit'))

expected = poll.copy()
expected.update({
'campaign_id': conversation.user_account.key,
'conversation_key': conversation.key,
'urls': {"show": conv_helper.get_view_url('show')},
'groups': [group1.get_data(), group2.get_data()]
'channel_types': [{
'name': name,
'label': d['label']
} for name, d in DELIVERY_CLASSES.iteritems()]
})

model_data = response.context["model_data"]
Expand Down
8 changes: 6 additions & 2 deletions go/apps/dialogue/view_definition.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,17 @@ def get(self, request, conversation):
contact_store = conversation.user_api.contact_store
groups = contact_store.list_static_groups()

delivery_classes = [{
'name': d_name,
'label': d['label']
} for d_name, d in DELIVERY_CLASSES.iteritems()]

model_data = r.json['result']['poll']
model_data.update({
'campaign_id': request.user_api.user_account_key,
'conversation_key': conversation.key,
'groups': [g.get_data() for g in groups],
'channel_types': delivery_classes,
'urls': {
'show': self.get_view_url(
'show',
Expand All @@ -46,8 +52,6 @@ def get(self, request, conversation):

metadata = model_data.get('poll_metadata', {})
delivery_class = metadata.get('delivery_class', DEFAULT_DELIVERY_CLASS)
delivery_classes = [
(d_name, d['label']) for d_name, d in DELIVERY_CLASSES.iteritems()]

return self.render_to_response({
'current_delivery_class': delivery_class,
Expand Down
8 changes: 8 additions & 0 deletions go/base/static/css/conversations.less
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,14 @@
}
}
}

.send.state {
.preview.mode {
.channel-type {
font-weight: bold;
}
}
}
}
}

Expand Down
18 changes: 8 additions & 10 deletions go/base/static/css/vumigo.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ body {
}
a:link,
button {
-webkit-transition: color 0s, background 0s;
-moz-transition: color 0s, background 0s;
-o-transition: color 0s, background 0s;
-ms-transition: color 0s, background 0s;
transition: color 0s, background 0s;
-webkit-transition: color 0.1s, background 0.1s;
-moz-transition: color 0.1s, background 0.1s;
-o-transition: color 0.1s, background 0.1s;
-ms-transition: color 0.1s, background 0.1s;
transition: color 0.1s, background 0.1s;
}
.btn.disabled {
pointer-events: auto;
Expand Down Expand Up @@ -567,6 +567,9 @@ button {
.dialogue #diagram .choice.state .preview.mode .choices {
text-align: left;
}
.dialogue #diagram .send.state .preview.mode .channel-type {
font-weight: bold;
}
.conversation.groups .group-table th:first-child,
.conversation.groups .group-table td:first-child {
width: 20px;
Expand Down Expand Up @@ -843,8 +846,3 @@ table tbody.loading td {
padding: 6px;
font-size: 16px;
}

.logs-sandbox,
.logs-sandbox td {
word-break: break-all;
}
43 changes: 41 additions & 2 deletions go/base/static/js/src/apps/dialogue/models.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
GroupModel = contacts.GroupModel,
GroupCollection = contacts.GroupCollection;

var channel = go.channel.models,
ChannelTypeModel = channel.ChannelTypeModel,
ChannelTypeCollection = channel.ChannelTypeCollection;

var DialogueEndpointModel = EndpointModel.extend({
defaults: function() { return {uuid: uuid.v4()}; }
});
Expand All @@ -40,7 +44,8 @@
choice: 'go.apps.dialogue.models.ChoiceStateModel',
freetext: 'go.apps.dialogue.models.FreeTextStateModel',
end: 'go.apps.dialogue.models.EndStateModel',
group: 'go.apps.dialogue.models.GroupStateModel'
group: 'go.apps.dialogue.models.GroupStateModel',
send: 'go.apps.dialogue.models.SendStateModel'
},

defaults: function() {
Expand Down Expand Up @@ -150,6 +155,34 @@
}
});

var SendStateModel = DialogueStateModel.extend({
storableOnContact: false,

relations: [{
type: Backbone.HasOne,
key: 'channel_type',
includeInJSON: 'name',
relatedModel: ChannelTypeModel
}, {
type: Backbone.HasOne,
key: 'entry_endpoint',
relatedModel: DialogueEndpointModel
}, {
type: Backbone.HasOne,
key: 'exit_endpoint',
relatedModel: DialogueEndpointModel
}],

defaults: function() {
return _({
text: '',
channel_type: null,
entry_endpoint: {},
exit_endpoint: {}
}).defaults(GroupStateModel.__super__.defaults.call(this));
}
});

var EndStateModel = DialogueStateModel.extend({
storableOnContact: false,

Expand Down Expand Up @@ -214,6 +247,11 @@
key: 'groups',
relatedModel: GroupModel,
collectionType: GroupCollection
}, {
type: Backbone.HasMany,
key: 'channel_types',
relatedModel: ChannelTypeModel,
collectionType: ChannelTypeCollection
}, {
type: Backbone.HasOne,
key: 'poll_metadata',
Expand Down Expand Up @@ -260,6 +298,7 @@
ChoiceStateModel: ChoiceStateModel,
FreeTextStateModel: FreeTextStateModel,
EndStateModel: EndStateModel,
GroupStateModel: GroupStateModel
GroupStateModel: GroupStateModel,
SendStateModel: SendStateModel
});
})(go.apps.dialogue.models = {});
81 changes: 81 additions & 0 deletions go/base/static/js/src/apps/dialogue/states/send.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// go.apps.dialogue.states.send
// ============================
// Structures for send states: states that send a message the user over a
// different channel.

(function(exports) {
var states = go.apps.dialogue.states,
EntryEndpointView = states.EntryEndpointView,
ExitEndpointView = states.ExitEndpointView,
DialogueStateView = states.DialogueStateView,
DialogueStateEditView = states.DialogueStateEditView,
DialogueStatePreviewView = states.DialogueStatePreviewView;

var SendStateEditView = DialogueStateEditView.extend({
bodyOptions:{
jst: 'JST.apps_dialogue_states_send_edit'
},

data: function() {
var type = this.model.get('channel_type');
var d = SendStateEditView.__super__.data.call(this);
d.text = this.model.get('text');

d.typeName = null;
if (type) { d.typeName = type.get('name'); }
d.types = this.model.get('dialogue').get('channel_types');

return d;
},

events: _.extend({
'change .channel-type': function(e) {
var name = $(e.target).val();

if (name === 'unassigned') {
this.model.set('channel_type', null, {silent: true});
} else if (name !== 'none') {
this.model.set('channel_type', {name: name}, {silent: true});
}
},

'change .send-text': function(e) {
this.model.set('text', $(e.target).val(), {silent: true});
}
}, DialogueStateEditView.prototype.events)
});

var SendStatePreviewView = DialogueStatePreviewView.extend({
bodyOptions: {
jst: 'JST.apps_dialogue_states_send_preview'
},

data: function() {
var type = this.model.get('channel_type');
var d = SendStatePreviewView.__super__.data.call(this);
d.text = this.model.get('text');

d.typeLabel = null;
if (type) { d.typeLabel = type.get('label'); }

return d;
}
});

var SendStateView = DialogueStateView.extend({
typeName: 'send',

editModeType: SendStateEditView,
previewModeType: SendStatePreviewView,

endpointSchema: [
{attr: 'entry_endpoint', type: EntryEndpointView},
{attr: 'exit_endpoint', type: ExitEndpointView}]
});

_(exports).extend({
SendStateView: SendStateView,
SendStateEditView: SendStateEditView,
SendStatePreviewView: SendStatePreviewView
});
})(go.apps.dialogue.states.send = {});
3 changes: 2 additions & 1 deletion go/base/static/js/src/apps/dialogue/states/states.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,8 @@
choice: 'go.apps.dialogue.states.choice.ChoiceStateView',
freetext: 'go.apps.dialogue.states.freetext.FreeTextStateView',
end: 'go.apps.dialogue.states.end.EndStateView',
group: 'go.apps.dialogue.states.group.GroupStateView'
group: 'go.apps.dialogue.states.group.GroupStateView',
send: 'go.apps.dialogue.states.send.SendStateView'
},

events: {
Expand Down
20 changes: 20 additions & 0 deletions go/base/static/js/src/channel/models.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// go.channel.models
// =================

(function(exports) {
var Model = go.components.models.Model;

var ChannelTypeModel = Model.extend({
idAttribute: 'name'
});

var ChannelTypeCollection = Backbone.Collection.extend({
model: ChannelTypeModel,
comparator: 'name'
});

_.extend(exports, {
ChannelTypeModel: ChannelTypeModel,
ChannelTypeCollection: ChannelTypeCollection
});
})(go.channel.models = {});
Loading