flow_chat 0.4.0 → 0.4.1
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.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/README.md +408 -102
- data/examples/media_prompts_examples.rb +28 -0
- data/examples/multi_tenant_whatsapp_controller.rb +4 -8
- data/examples/whatsapp_controller.rb +1 -2
- data/examples/whatsapp_media_examples.rb +406 -0
- data/examples/whatsapp_message_job.rb +111 -0
- data/lib/flow_chat/base_processor.rb +7 -3
- data/lib/flow_chat/config.rb +36 -0
- data/lib/flow_chat/simulator/controller.rb +78 -0
- data/lib/flow_chat/simulator/views/simulator.html.erb +1707 -0
- data/lib/flow_chat/ussd/processor.rb +0 -1
- data/lib/flow_chat/ussd/prompt.rb +39 -5
- data/lib/flow_chat/version.rb +1 -1
- data/lib/flow_chat/whatsapp/app.rb +7 -1
- data/lib/flow_chat/whatsapp/client.rb +439 -0
- data/lib/flow_chat/whatsapp/configuration.rb +41 -3
- data/lib/flow_chat/whatsapp/gateway/cloud_api.rb +114 -114
- data/lib/flow_chat/whatsapp/processor.rb +0 -10
- data/lib/flow_chat/whatsapp/prompt.rb +118 -73
- data/lib/flow_chat/whatsapp/send_job_support.rb +79 -0
- metadata +8 -3
- data/lib/flow_chat/ussd/simulator/controller.rb +0 -51
- data/lib/flow_chat/ussd/simulator/views/simulator.html.erb +0 -239
@@ -1,51 +0,0 @@
|
|
1
|
-
module FlowChat
|
2
|
-
module Ussd
|
3
|
-
module Simulator
|
4
|
-
module Controller
|
5
|
-
def ussd_simulator
|
6
|
-
respond_to do |format|
|
7
|
-
format.html do
|
8
|
-
render inline: simulator_view_template, layout: false, locals: simulator_locals
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
protected
|
14
|
-
|
15
|
-
def show_options
|
16
|
-
true
|
17
|
-
end
|
18
|
-
|
19
|
-
def default_msisdn
|
20
|
-
"233200123456"
|
21
|
-
end
|
22
|
-
|
23
|
-
def default_endpoint
|
24
|
-
"/ussd"
|
25
|
-
end
|
26
|
-
|
27
|
-
def default_provider
|
28
|
-
:nalo
|
29
|
-
end
|
30
|
-
|
31
|
-
def simulator_view_template
|
32
|
-
File.read simulator_view_path
|
33
|
-
end
|
34
|
-
|
35
|
-
def simulator_view_path
|
36
|
-
File.join FlowChat.root.join("flow_chat", "ussd", "simulator", "views", "simulator.html.erb")
|
37
|
-
end
|
38
|
-
|
39
|
-
def simulator_locals
|
40
|
-
{
|
41
|
-
pagesize: FlowChat::Config.ussd.pagination_page_size,
|
42
|
-
show_options: show_options,
|
43
|
-
default_msisdn: default_msisdn,
|
44
|
-
default_endpoint: default_endpoint,
|
45
|
-
default_provider: default_provider
|
46
|
-
}
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
@@ -1,239 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html>
|
3
|
-
<head>
|
4
|
-
<title>FlowChat Ussd Simulator</title>
|
5
|
-
<style>
|
6
|
-
.content {
|
7
|
-
width: 320px;
|
8
|
-
margin: 100px auto;
|
9
|
-
}
|
10
|
-
.label {
|
11
|
-
display: inline-block;
|
12
|
-
width: 80px;
|
13
|
-
font-weight: bold;
|
14
|
-
}
|
15
|
-
.value {
|
16
|
-
display: inline;
|
17
|
-
}
|
18
|
-
.value select, input {
|
19
|
-
width: 200px;
|
20
|
-
}
|
21
|
-
.field {
|
22
|
-
margin: 5px;
|
23
|
-
}
|
24
|
-
#screen {
|
25
|
-
border: 1px black solid;
|
26
|
-
height:400px;
|
27
|
-
width:300px;
|
28
|
-
margin-top: 10px;
|
29
|
-
margin-bottom: 10px;
|
30
|
-
padding: 10px 5px;
|
31
|
-
}
|
32
|
-
#char-count {
|
33
|
-
text-align: center;
|
34
|
-
font-size: 10px;
|
35
|
-
}
|
36
|
-
.hidden {
|
37
|
-
display: none;
|
38
|
-
}
|
39
|
-
</style>
|
40
|
-
</head>
|
41
|
-
<body>
|
42
|
-
<div class="content">
|
43
|
-
<div class="field <%= show_options ? '' : 'hidden' %>">
|
44
|
-
<div class="label">Provider </div>
|
45
|
-
<div class="value">
|
46
|
-
<select id="provider">
|
47
|
-
<option <%= default_provider == :nalo ? 'selected' : '' %> value="nalo">Nalo</option>
|
48
|
-
<option <%= default_provider == :nsano ? 'selected' : '' %> value="nsano">Nsano</option>
|
49
|
-
</select>
|
50
|
-
</div>
|
51
|
-
</div>
|
52
|
-
<div class="field <%= show_options ? '' : 'hidden' %>">
|
53
|
-
<div class="label">Endpoint </div>
|
54
|
-
<div class="value">
|
55
|
-
<input id="endpoint" value="<%= default_endpoint %>" />
|
56
|
-
</div>
|
57
|
-
</div>
|
58
|
-
<div class="field <%= show_options ? '' : 'hidden' %>">
|
59
|
-
<div class="label">MSISDN </div>
|
60
|
-
<div class="value">
|
61
|
-
<input id="msisdn" value="<%= default_msisdn %>" />
|
62
|
-
</div>
|
63
|
-
</div>
|
64
|
-
<div id="screen"></div>
|
65
|
-
<div id="char-count"></div>
|
66
|
-
<div class="field">
|
67
|
-
<input id="data" disabled> <button id="respond" disabled>Respond</button>
|
68
|
-
</div>
|
69
|
-
<div class="field">
|
70
|
-
<button id="initiate" disabled>Initiate</button>
|
71
|
-
<button id="reset" disabled>Reset</button>
|
72
|
-
</div>
|
73
|
-
</div>
|
74
|
-
<script>
|
75
|
-
// Config
|
76
|
-
const pagesize = <%= pagesize %>
|
77
|
-
|
78
|
-
// View
|
79
|
-
const $screen = document.getElementById('screen')
|
80
|
-
const $charCount = document.getElementById('char-count')
|
81
|
-
|
82
|
-
const $provider = document.getElementById('provider')
|
83
|
-
const $endpoint = document.getElementById('endpoint')
|
84
|
-
const $msisdn = document.getElementById('msisdn')
|
85
|
-
|
86
|
-
const $data = document.getElementById('data')
|
87
|
-
const $respondBtn = document.getElementById('respond')
|
88
|
-
const $initiateBtn = document.getElementById('initiate')
|
89
|
-
const $resetBtn = document.getElementById('reset')
|
90
|
-
|
91
|
-
$provider.addEventListener('change', function (e) {
|
92
|
-
state.provider = $provider.value
|
93
|
-
render()
|
94
|
-
}, false)
|
95
|
-
|
96
|
-
$endpoint.addEventListener('keyup', function (e) {
|
97
|
-
state.endpoint = $endpoint.value
|
98
|
-
render()
|
99
|
-
}, false)
|
100
|
-
|
101
|
-
$msisdn.addEventListener('keyup', function (e) {
|
102
|
-
state.msisdn = $msisdn.value
|
103
|
-
render()
|
104
|
-
}, false)
|
105
|
-
|
106
|
-
$initiateBtn.addEventListener('click', function (e) {
|
107
|
-
makeRequest()
|
108
|
-
}, false)
|
109
|
-
|
110
|
-
$resetBtn.addEventListener('click',function(e){
|
111
|
-
reset()
|
112
|
-
}, false)
|
113
|
-
|
114
|
-
$respondBtn.addEventListener('click', function (e) {
|
115
|
-
makeRequest()
|
116
|
-
}, false)
|
117
|
-
|
118
|
-
function disableInputs() {
|
119
|
-
$data.disabled = 'disabled'
|
120
|
-
$respondBtn.disabled = 'disabled'
|
121
|
-
$initiateBtn.disabled = 'disabled'
|
122
|
-
$resetBtn.disabled = 'disabled'
|
123
|
-
$data.disabled = 'disabled'
|
124
|
-
}
|
125
|
-
|
126
|
-
function enableResponse() {
|
127
|
-
$data.disabled = false
|
128
|
-
$respondBtn.disabled = false
|
129
|
-
$resetBtn.disabled = false
|
130
|
-
}
|
131
|
-
|
132
|
-
function display(text) {
|
133
|
-
$screen.innerText = text.substr(0, pagesize)
|
134
|
-
if(text.length > 0)
|
135
|
-
$charCount.innerText = `${text.length} chars`
|
136
|
-
else
|
137
|
-
$charCount.innerText = ''
|
138
|
-
}
|
139
|
-
|
140
|
-
function render() {
|
141
|
-
disableInputs()
|
142
|
-
|
143
|
-
if(!state.isRunning){
|
144
|
-
if(state.provider && state.endpoint && state.msisdn)
|
145
|
-
$initiateBtn.disabled = false
|
146
|
-
else
|
147
|
-
$initiateBtn.disabled = 'disabled'
|
148
|
-
}
|
149
|
-
else {
|
150
|
-
enableResponse()
|
151
|
-
}
|
152
|
-
}
|
153
|
-
|
154
|
-
// State
|
155
|
-
const state = {}
|
156
|
-
|
157
|
-
function reset(shouldRender) {
|
158
|
-
state.isRunning = false
|
159
|
-
state.request_id = btoa(Math.random().toString()).substr(10, 10)
|
160
|
-
state.provider = $provider.value
|
161
|
-
state.endpoint = $endpoint.value
|
162
|
-
state.msisdn = $msisdn.value
|
163
|
-
|
164
|
-
$data.value = null
|
165
|
-
|
166
|
-
display("")
|
167
|
-
if(shouldRender !== false) render()
|
168
|
-
}
|
169
|
-
|
170
|
-
|
171
|
-
// API
|
172
|
-
|
173
|
-
function makeRequest() {
|
174
|
-
var data = {}
|
175
|
-
|
176
|
-
switch (state.provider) {
|
177
|
-
case "nalo":
|
178
|
-
data = {
|
179
|
-
USERID: state.request_id,
|
180
|
-
MSISDN: state.msisdn,
|
181
|
-
USERDATA: $data.value,
|
182
|
-
MSGTYPE: !state.isRunning,
|
183
|
-
}
|
184
|
-
break;
|
185
|
-
case "nsano":
|
186
|
-
data = {
|
187
|
-
network: 'MTN',
|
188
|
-
msisdn: state.msisdn,
|
189
|
-
msg: $data.value,
|
190
|
-
UserSessionID: state.request_id,
|
191
|
-
}
|
192
|
-
break;
|
193
|
-
|
194
|
-
default:
|
195
|
-
alert(`Unhandled provider request: ${state.provider}`)
|
196
|
-
return
|
197
|
-
}
|
198
|
-
|
199
|
-
disableInputs()
|
200
|
-
fetch(state.endpoint, {
|
201
|
-
method: 'POST',
|
202
|
-
headers: {
|
203
|
-
'Content-Type': 'application/json'
|
204
|
-
},
|
205
|
-
redirect: 'error',
|
206
|
-
body: JSON.stringify(data)
|
207
|
-
})
|
208
|
-
.then(response => {
|
209
|
-
if (!response.ok) {
|
210
|
-
throw Error(`${response.status}: ${response.statusText}`);
|
211
|
-
}
|
212
|
-
return response.json()
|
213
|
-
})
|
214
|
-
.then(data => {
|
215
|
-
switch (state.provider) {
|
216
|
-
case "nalo":
|
217
|
-
display(data.MSG)
|
218
|
-
state.isRunning = data.MSGTYPE
|
219
|
-
break;
|
220
|
-
case "nsano":
|
221
|
-
display(data.USSDResp.title)
|
222
|
-
state.isRunning = data.USSDResp.action == "input"
|
223
|
-
break;
|
224
|
-
|
225
|
-
default:
|
226
|
-
alert(`Unhandled provider response: ${state.provider}`)
|
227
|
-
return
|
228
|
-
}
|
229
|
-
$data.value = null
|
230
|
-
})
|
231
|
-
.catch(error => alert(error.message))
|
232
|
-
.finally(render);
|
233
|
-
}
|
234
|
-
|
235
|
-
// run the app
|
236
|
-
reset()
|
237
|
-
</script>
|
238
|
-
</body>
|
239
|
-
</html>
|