bianchi 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +45 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +2 -0
- data/.vscode/settings.json +5 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +14 -10
- data/README.md +174 -21
- data/bianchi.gemspec +2 -1
- data/lib/bianchi/cli/main.rb +5 -5
- data/lib/bianchi/cli/templates/page.erb +2 -4
- data/lib/bianchi/ussd/engine.rb +1 -4
- data/lib/bianchi/ussd/{errors.rb → exceptions.rb} +2 -0
- data/lib/bianchi/ussd/page.rb +16 -2
- data/lib/bianchi/ussd/page_delegators.rb +2 -0
- data/lib/bianchi/ussd/provider_configurations.rb +7 -23
- data/lib/bianchi/ussd/provider_parsers/africastalking.rb +30 -0
- data/lib/bianchi/ussd/provider_parsers/appsnmobile.rb +51 -0
- data/lib/bianchi/ussd/store.rb +7 -1
- data/lib/bianchi/version.rb +1 -1
- data/lib/bianchi.rb +3 -1
- data/ussd/engine.rb +2 -1
- data/ussd/main_menu/page_1.rb +5 -5
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a8d03b012d92b96f021d80a4ce43c668d75f7003978feb81b189cdcb71952be
|
4
|
+
data.tar.gz: b1c13d1ead41b898177e6915f06d134a0a762fb367b95cadbbb688d031c4767a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5178fa0c0e7a8b65829b004d348b73dc74a0305789e03edbdb0af2fe9ac1236281dd31835052281791289b7a48912b918ec536969aa27de484d16a383a8edcf3
|
7
|
+
data.tar.gz: 7b961616077c63d17997d26837b1207bfd3718f5abc27e34a4fdb15ebbea3ec0b7754c846d0cbc1e77ba2984f974bff259e7100716dcf50b1af12f8e2d34346c
|
@@ -0,0 +1,45 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- '*'
|
7
|
+
pull_request:
|
8
|
+
branches:
|
9
|
+
- main
|
10
|
+
|
11
|
+
jobs:
|
12
|
+
rubocop:
|
13
|
+
runs-on: ubuntu-latest
|
14
|
+
|
15
|
+
services:
|
16
|
+
redis:
|
17
|
+
image: redis
|
18
|
+
ports:
|
19
|
+
- 6379:6379
|
20
|
+
options: --entrypoint redis-server
|
21
|
+
|
22
|
+
steps:
|
23
|
+
- name: Checkout code
|
24
|
+
uses: actions/checkout@v4.1.1
|
25
|
+
|
26
|
+
- name: Set up Ruby
|
27
|
+
uses: ruby/setup-ruby@v1.171.0
|
28
|
+
with:
|
29
|
+
ruby-version: 3.0
|
30
|
+
|
31
|
+
- name: Install dependencies
|
32
|
+
run: |
|
33
|
+
gem install bundler
|
34
|
+
bundle install
|
35
|
+
|
36
|
+
- name: Run RuboCop
|
37
|
+
run: bundle exec rubocop
|
38
|
+
|
39
|
+
- name: Start Redis
|
40
|
+
run: docker ps -a
|
41
|
+
|
42
|
+
- name: Run RSpec tests
|
43
|
+
env:
|
44
|
+
REDIS_URL: redis://localhost:6379
|
45
|
+
run: bundle exec rspec
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
bianchi (0.1.
|
4
|
+
bianchi (0.1.2)
|
5
5
|
activesupport
|
6
6
|
json
|
7
7
|
redis
|
@@ -32,10 +32,11 @@ GEM
|
|
32
32
|
i18n (1.14.1)
|
33
33
|
concurrent-ruby (~> 1.0)
|
34
34
|
json (2.7.1)
|
35
|
+
language_server-protocol (3.17.0.3)
|
35
36
|
minitest (5.21.2)
|
36
37
|
mutex_m (0.2.0)
|
37
38
|
parallel (1.24.0)
|
38
|
-
parser (3.3.0.
|
39
|
+
parser (3.3.0.5)
|
39
40
|
ast (~> 2.4.1)
|
40
41
|
racc
|
41
42
|
racc (1.7.3)
|
@@ -60,15 +61,17 @@ GEM
|
|
60
61
|
diff-lcs (>= 1.2.0, < 2.0)
|
61
62
|
rspec-support (~> 3.12.0)
|
62
63
|
rspec-support (3.12.1)
|
63
|
-
rubocop (
|
64
|
+
rubocop (1.60.2)
|
65
|
+
json (~> 2.3)
|
66
|
+
language_server-protocol (>= 3.17.0)
|
64
67
|
parallel (~> 1.10)
|
65
|
-
parser (>=
|
68
|
+
parser (>= 3.3.0.2)
|
66
69
|
rainbow (>= 2.2.2, < 4.0)
|
67
|
-
regexp_parser (>= 1.8)
|
68
|
-
rexml
|
69
|
-
rubocop-ast (>=
|
70
|
+
regexp_parser (>= 1.8, < 3.0)
|
71
|
+
rexml (>= 3.2.5, < 4.0)
|
72
|
+
rubocop-ast (>= 1.30.0, < 2.0)
|
70
73
|
ruby-progressbar (~> 1.7)
|
71
|
-
unicode-display_width (>=
|
74
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
72
75
|
rubocop-ast (1.30.0)
|
73
76
|
parser (>= 3.2.1.0)
|
74
77
|
ruby-progressbar (1.13.0)
|
@@ -76,9 +79,10 @@ GEM
|
|
76
79
|
thor (1.3.0)
|
77
80
|
tzinfo (2.0.6)
|
78
81
|
concurrent-ruby (~> 1.0)
|
79
|
-
unicode-display_width (
|
82
|
+
unicode-display_width (2.5.0)
|
80
83
|
|
81
84
|
PLATFORMS
|
85
|
+
arm64-darwin-22
|
82
86
|
x86_64-darwin-23
|
83
87
|
|
84
88
|
DEPENDENCIES
|
@@ -86,7 +90,7 @@ DEPENDENCIES
|
|
86
90
|
byebug
|
87
91
|
rake (~> 13.0)
|
88
92
|
rspec (~> 3.0)
|
89
|
-
rubocop (~>
|
93
|
+
rubocop (~> 1.60, >= 1.60.2)
|
90
94
|
|
91
95
|
BUNDLED WITH
|
92
96
|
2.2.3
|
data/README.md
CHANGED
@@ -1,43 +1,196 @@
|
|
1
|
-
#
|
1
|
+
# Bianchi
|
2
|
+
A DSL (Domain-Specific Language) and a minimalist framework in Ruby, tailored for USSD development. Structured around a menu page approach, Bianchi offers a comprehensive suite of methods and generators, streamlining the process of building USSD applications efficiently and easily.
|
3
|
+
A basic test run with bianchi can be found here https://github.com/SydDaps/sinatra_bianchi_example
|
2
4
|
|
3
|
-
|
5
|
+
## Installation
|
6
|
+
Add `gem 'bianchi', '~> 0.1.1'` to your gem file and run `bundle install`
|
4
7
|
|
5
|
-
|
8
|
+
Bianchi relies on Redis and requires the `REDIS_URL` environment variable to be set, pointing to your Redis instance. Ensure Redis is installed, and running, and that REDIS_URL is correctly configured before using Bianchi.
|
6
9
|
|
7
|
-
##
|
10
|
+
## Getting Started
|
11
|
+
|
12
|
+
To initialize a new USSD project, generate a project directory using Bianchi's command-line interface. Use the following Ruby command:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
bundle exec bianchi setup -p provider_name
|
16
|
+
```
|
17
|
+
|
18
|
+
Replace `provider_name` with your desired provider. Currently supported providers include: africastalking.
|
19
|
+
|
20
|
+
This command creates a `ussd/engine.rb` file in the project root directory. Here's a sample content of `ussd/engine.rb`:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
module USSD
|
24
|
+
class Engine
|
25
|
+
def self.start(params)
|
26
|
+
Bianchi::USSD::Engine.start(params, provider: :africastalking) do
|
27
|
+
# e.g menu :main, options
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
34
|
+
To define menus for your USSD applications' engine instance, use the following command:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
menu :menu_name, options
|
38
|
+
```
|
39
|
+
|
40
|
+
For example, let's define our first menu, which serves as the initial menu of the application, and let's call this the main menu:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
menu :main, initial: true
|
44
|
+
```
|
45
|
+
now that we have the initial menu up let's generate our pages for that menu using Bianchi's command-line interface. Use the following Ruby command:
|
46
|
+
```ruby
|
47
|
+
command: bundle exec bianchi g menu menu_name page page_number
|
48
|
+
example: bianchi g menu main page 1
|
49
|
+
```
|
50
|
+
This creates a `ussd/main_menu/page_1` file in the project root directory. Here's a sample content of the file:
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
module USSD
|
54
|
+
module MainMenu
|
55
|
+
class Page1 < Bianchi::USSD::Page
|
56
|
+
def request; end
|
57
|
+
|
58
|
+
def response; end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
```
|
8
63
|
|
9
|
-
|
64
|
+
In the `ussd/main_menu/page_1` file, the main application code goes into the `request` and `response` methods. Here's a sample code to illustrate the usage:
|
10
65
|
|
11
66
|
```ruby
|
12
|
-
|
67
|
+
module USSD
|
68
|
+
module MainMenu
|
69
|
+
class Page1 < Bianchi::USSD::Page
|
70
|
+
def request
|
71
|
+
render_and_await(request_body)
|
72
|
+
end
|
73
|
+
|
74
|
+
def response
|
75
|
+
case session_input_body
|
76
|
+
when "1"
|
77
|
+
redirect_to_greetings_menu_page_1
|
78
|
+
when "2"
|
79
|
+
redirect_to_repeat_menu_page_1
|
80
|
+
else
|
81
|
+
render_and_await("invalid input \n" + request_body)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def request_body
|
88
|
+
<<~MSG
|
89
|
+
Welcome
|
90
|
+
1. Greetings
|
91
|
+
2. Repeat my name
|
92
|
+
MSG
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
13
97
|
```
|
14
98
|
|
15
|
-
|
99
|
+
In this example, when a page is requested, you send some information, and the end user submits data for that request. The `response` method processes the response data and can move to a new page request, end the session, or send a response from there.
|
100
|
+
### Page Renders
|
16
101
|
|
17
|
-
|
102
|
+
In Bianchi USSD applications, any method that starts with `render` sends data back to the user. Typically, we either send data and expect a response or send data and terminate the session. Here are the two main methods for rendering pages:
|
18
103
|
|
19
|
-
|
104
|
+
- `render_and_await(string)`: Responds to the user and expects the user to respond.
|
20
105
|
|
21
|
-
|
106
|
+
- `render_and_end(string)`: Responds to the user and terminates the session.
|
22
107
|
|
23
|
-
|
108
|
+
Here's how you can use these methods in Ruby:
|
109
|
+
```ruby
|
110
|
+
render_and_await("Please select an option:")
|
111
|
+
```
|
112
|
+
This method sends the message "Please select an option:" to the user and awaits their response.
|
113
|
+
```ruby
|
114
|
+
render_and_end("Thank you for using our service. Goodbye!")
|
115
|
+
```
|
116
|
+
This method sends the message "Thank you for using our service. Goodbye!" to the user and terminates the session.
|
117
|
+
|
118
|
+
### Page Session
|
119
|
+
|
120
|
+
In Bianchi USSD applications, the `session` serves as an information tracker between all the pages and records all interactions between the user and the application. It contains valuable information necessary for the USSD application to function properly.
|
121
|
+
|
122
|
+
Here are the methods available within the page session:
|
123
|
+
|
124
|
+
- `session_params`: Returns a hash containing all the data the provider sent.
|
125
|
+
- `session_input_body`: Retrieves the user's current input.
|
126
|
+
- `session_mobile_number`: Returns the current user's phone number dialing the code.
|
127
|
+
- `session_session_id`: Provides the session's ID.
|
128
|
+
- `session.store`: Accesses the current session's cache. Further details about this will be discussed later.
|
129
|
+
|
130
|
+
### Page Store
|
131
|
+
|
132
|
+
In Bianchi USSD applications, the `session.store` serves as the main application cache, where data can be stored and accessed across all pages.
|
133
|
+
|
134
|
+
Here are the methods available within the page store:
|
135
|
+
|
136
|
+
- `session.store.set(key, value)`: Stores a key-value pair in the cache.
|
137
|
+
- `session.store.get(key)`: Retrieves the value associated with a given key from the cache.
|
138
|
+
- `session.store.all`: Returns the entire cache as a hash.
|
24
139
|
|
25
|
-
|
140
|
+
Here's how you can use these methods to manage your application's cache:
|
26
141
|
|
27
|
-
|
142
|
+
```ruby
|
143
|
+
# Storing data in the cache
|
144
|
+
session.store.set('user_id', 123)
|
145
|
+
|
146
|
+
# Retrieving data from the cache
|
147
|
+
user_id = session.store.get('user_id')
|
148
|
+
|
149
|
+
# Retrieving the entire cache
|
150
|
+
all_data = session.store.all
|
151
|
+
```
|
152
|
+
|
153
|
+
### Page Redirects
|
154
|
+
|
155
|
+
In Bianchi USSD applications, any method that starts with `redirect_to` initiates another page request to be sent to the user. An example use case is when you want to transition to another menu page after processing the user's response.
|
28
156
|
|
29
|
-
|
157
|
+
For instance, in the snippet of the main menu page provided earlier, we use `redirect_to_greetings_menu_page_1` when the user selects "1". This directs the application to the greetings menu page 1's request.
|
30
158
|
|
31
|
-
|
159
|
+
Here are the methods available within the page redirects:
|
32
160
|
|
33
|
-
|
161
|
+
- `redirect_to_menu_[menu_name]_page_[page_number]`: Redirects to a specified menu using the `menu_name` and loads the page specified by `page_number`.
|
162
|
+
- `redirect_to_[next|previous]_page`: Redirects to the next or previous page within the same menu.
|
34
163
|
|
35
|
-
|
164
|
+
Here's how you can use these methods within your Bianchi USSD application:
|
36
165
|
|
37
|
-
|
166
|
+
```ruby
|
167
|
+
# Redirecting to a specific menu page
|
168
|
+
redirect_to_menu_greetings_page_1
|
169
|
+
|
170
|
+
# Redirecting to the next or previous page in the same menu
|
171
|
+
redirect_to_next_page
|
172
|
+
redirect_to_previous_page
|
173
|
+
```
|
38
174
|
|
39
|
-
|
175
|
+
## Responding to the Provider
|
40
176
|
|
41
|
-
|
177
|
+
Once all processes are completed, the next step is to prepare the response to send to the provider. The provider prompt data is accessible via the engine instance's `prompt_data` attribute.
|
42
178
|
|
43
|
-
|
179
|
+
Here's an example of how you can retrieve the provider prompt data in your USSD application:
|
180
|
+
|
181
|
+
```ruby
|
182
|
+
module USSD
|
183
|
+
class Engine
|
184
|
+
def self.start(params)
|
185
|
+
Bianchi::USSD::Engine.start(params, provider: :africastalking) do
|
186
|
+
menu :main, options
|
187
|
+
menu :greetings
|
188
|
+
menu :repeat
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# Retrieving provider prompt data
|
195
|
+
provider_data = USSD::Engine.new(provider_params).prompt_data
|
196
|
+
```
|
data/bianchi.gemspec
CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |spec|
|
|
6
6
|
spec.name = "bianchi"
|
7
7
|
spec.version = Bianchi::VERSION
|
8
8
|
spec.authors = ["Dapilah Sydney"]
|
9
|
-
spec.email = [
|
9
|
+
spec.email = ["dapilah.sydney@gmail.com"]
|
10
10
|
|
11
11
|
spec.summary = "Write a short summary, because RubyGems requires one."
|
12
12
|
spec.homepage = "https://github.com/SydDaps/Bianchi"
|
@@ -34,4 +34,5 @@ Gem::Specification.new do |spec|
|
|
34
34
|
spec.add_dependency "json"
|
35
35
|
spec.add_dependency "redis"
|
36
36
|
spec.add_dependency "thor"
|
37
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
37
38
|
end
|
data/lib/bianchi/cli/main.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# rubocop:disable
|
3
|
+
# rubocop:disable Metrics/ParameterLists
|
4
4
|
module Bianchi
|
5
5
|
module Cli
|
6
6
|
class Main < Thor
|
@@ -20,15 +20,15 @@ module Bianchi
|
|
20
20
|
desc "setup", "sets up a new ussd project"
|
21
21
|
long_desc <<-LONG_DESC
|
22
22
|
Usage: bianchi setup optional(-p|--provider)
|
23
|
-
\x5 Providers: [:africa_is_talking]
|
23
|
+
\x5 Providers: [:africa_is_talking, :appsnmobile]
|
24
24
|
\x5 Example: `bianchi setup`
|
25
25
|
\x5 Example: `bianchi setup -p :africa_is_talking`
|
26
26
|
|
27
27
|
LONG_DESC
|
28
|
-
method_option :provider, :
|
28
|
+
method_option :provider, aliases: "-p", type: :string, desc: "Set up ussd project for provider"
|
29
29
|
def setup
|
30
30
|
@provider = options[:provider]
|
31
|
-
unless [
|
31
|
+
unless %w[africastalking none appsnmobile].include? @provider
|
32
32
|
say("Error: provider #{@provider} is not yet configured.", :yellow)
|
33
33
|
exit(1)
|
34
34
|
end
|
@@ -63,4 +63,4 @@ module Bianchi
|
|
63
63
|
end
|
64
64
|
end
|
65
65
|
end
|
66
|
-
# rubocop:enable
|
66
|
+
# rubocop:enable Metrics/ParameterLists
|
data/lib/bianchi/ussd/engine.rb
CHANGED
@@ -110,10 +110,7 @@ module Bianchi
|
|
110
110
|
"#{constant_name} is supposed to be defined to process #{session.menu.name} menu #{page_number}"
|
111
111
|
end
|
112
112
|
|
113
|
-
page.
|
114
|
-
p.ensure_methods_defined(%i[request response])
|
115
|
-
p.send(action)
|
116
|
-
end
|
113
|
+
page.call(session, action)
|
117
114
|
end
|
118
115
|
end
|
119
116
|
end
|
data/lib/bianchi/ussd/page.rb
CHANGED
@@ -11,6 +11,15 @@ module Bianchi
|
|
11
11
|
@session = session
|
12
12
|
end
|
13
13
|
|
14
|
+
def self.call(session, action)
|
15
|
+
new(session).tap do |p|
|
16
|
+
p.ensure_methods_defined(%i[request response])
|
17
|
+
p.send(action)
|
18
|
+
rescue DispatchRenderException
|
19
|
+
p
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
14
23
|
def render(body, options = {})
|
15
24
|
raise ArgumentError, "render body expected to be a string" unless body.is_a? String
|
16
25
|
|
@@ -22,6 +31,8 @@ module Bianchi
|
|
22
31
|
s.page_number = self.class.name.split("::").last
|
23
32
|
s.store.track_session
|
24
33
|
end
|
34
|
+
|
35
|
+
raise DispatchRenderException
|
25
36
|
end
|
26
37
|
|
27
38
|
def load_page(page_number, menu_name)
|
@@ -29,8 +40,11 @@ module Bianchi
|
|
29
40
|
page = constant_name.safe_constantize
|
30
41
|
|
31
42
|
unless page
|
32
|
-
raise PageLoadError,
|
33
|
-
|
43
|
+
raise PageLoadError, <<~MSG
|
44
|
+
\n
|
45
|
+
#{constant_name} is supposed to be defined to process #{menu_name} menu #{page_number}.
|
46
|
+
generate menu page with `bianchi g menu #{menu_name} page #{page_number[4..]}`
|
47
|
+
MSG
|
34
48
|
end
|
35
49
|
|
36
50
|
session.menu = Menu.new(menu_name)
|
@@ -3,10 +3,14 @@
|
|
3
3
|
module Bianchi
|
4
4
|
module USSD
|
5
5
|
module ProviderConfigurations
|
6
|
+
include ProviderParsers::Africastalking
|
7
|
+
include ProviderParsers::Appsnmobile
|
8
|
+
|
6
9
|
def parse_params(params)
|
7
10
|
provider_parsers = {
|
8
11
|
none: proc { params },
|
9
|
-
|
12
|
+
africastalking: proc { africastalking_params_parser(params) },
|
13
|
+
appsnmobile: proc { appsnmobile_params_parser(params) }
|
10
14
|
}.with_indifferent_access
|
11
15
|
|
12
16
|
parser = provider_parsers[@provider]
|
@@ -16,27 +20,11 @@ module Bianchi
|
|
16
20
|
parser.call
|
17
21
|
end
|
18
22
|
|
19
|
-
def africa_is_talking_params_parser(params)
|
20
|
-
required_params = %w[sessionId phoneNumber text serviceCode]
|
21
|
-
left_required_params = required_params - params.keys.map(&:to_s)
|
22
|
-
|
23
|
-
unless left_required_params.empty?
|
24
|
-
raise ArgumentError, "#{left_required_params} required in params to start engine for provider #{@provider}"
|
25
|
-
end
|
26
|
-
|
27
|
-
{
|
28
|
-
session_id: params["sessionId"],
|
29
|
-
mobile_number: params["phoneNumber"],
|
30
|
-
activity_state: params["text"] && params["text"].empty? ? "initial" : "subsequent",
|
31
|
-
input_body: params["text"],
|
32
|
-
service_code: params["serviceCode"]
|
33
|
-
}
|
34
|
-
end
|
35
|
-
|
36
23
|
def parser_prompt_data(prompt_data)
|
37
24
|
provider_parsers = {
|
38
25
|
none: proc { prompt_data },
|
39
|
-
|
26
|
+
africastalking: proc { africastalking_prompt_data_parser(prompt_data) },
|
27
|
+
appsnmobile: proc { appsnmobile_prompt_data_parser(prompt_data) }
|
40
28
|
}.with_indifferent_access
|
41
29
|
|
42
30
|
parser = provider_parsers[@provider]
|
@@ -45,10 +33,6 @@ module Bianchi
|
|
45
33
|
|
46
34
|
parser.call
|
47
35
|
end
|
48
|
-
|
49
|
-
def africa_is_talking_prompt_data_parser(prompt_data)
|
50
|
-
prompt_data["activity_state"] == :await ? "CON #{prompt_data['body']}" : "END #{prompt_data['body']}"
|
51
|
-
end
|
52
36
|
end
|
53
37
|
end
|
54
38
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bianchi
|
4
|
+
module USSD
|
5
|
+
module ProviderParsers
|
6
|
+
module Africastalking
|
7
|
+
def africastalking_params_parser(params)
|
8
|
+
required_params = %w[sessionId phoneNumber text serviceCode]
|
9
|
+
left_required_params = required_params - params.keys.map(&:to_s)
|
10
|
+
|
11
|
+
unless left_required_params.empty?
|
12
|
+
raise ArgumentError, "#{left_required_params} required in params to start engine for provider #{@provider}"
|
13
|
+
end
|
14
|
+
|
15
|
+
{
|
16
|
+
session_id: params["sessionId"],
|
17
|
+
mobile_number: params["phoneNumber"],
|
18
|
+
activity_state: params["text"] && params["text"].empty? ? "initial" : "subsequent",
|
19
|
+
input_body: params["text"].split("*").last,
|
20
|
+
service_code: params["serviceCode"]
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def africastalking_prompt_data_parser(prompt_data)
|
25
|
+
prompt_data["activity_state"] == :await ? "CON #{prompt_data['body']}" : "END #{prompt_data['body']}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bianchi
|
4
|
+
module USSD
|
5
|
+
module ProviderParsers
|
6
|
+
module Appsnmobile
|
7
|
+
def appsnmobile_params_parser(params)
|
8
|
+
required_params = %w[session_id msisdn msg_type ussd_body nw_code service_code]
|
9
|
+
left_required_params = required_params - params.keys.map(&:to_s)
|
10
|
+
|
11
|
+
unless left_required_params.empty?
|
12
|
+
raise ArgumentError, "#{left_required_params} required in params to start engine for provider #{@provider}"
|
13
|
+
end
|
14
|
+
|
15
|
+
{
|
16
|
+
session_id: params["session_id"],
|
17
|
+
mobile_number: params["msisdn"],
|
18
|
+
activity_state: return_activity_state(params["msg_type"]),
|
19
|
+
input_body: params["ussd_body"],
|
20
|
+
nw_code: params["nw_code"],
|
21
|
+
service_code: params["service_code"]
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def appsnmobile_prompt_data_parser(prompt_data)
|
26
|
+
msg_type = prompt_data["activity_state"] == :await ? "1" : "2"
|
27
|
+
|
28
|
+
{
|
29
|
+
session_id: prompt_data["session_id"],
|
30
|
+
msisdn: prompt_data["mobile_number"],
|
31
|
+
msg_type: msg_type,
|
32
|
+
ussd_body: prompt_data["body"],
|
33
|
+
nw_code: prompt_data["nw_code"],
|
34
|
+
service_code: prompt_data["service_code"]
|
35
|
+
}.to_json
|
36
|
+
end
|
37
|
+
|
38
|
+
def return_activity_state(msg_type)
|
39
|
+
case msg_type
|
40
|
+
when "0"
|
41
|
+
"initial"
|
42
|
+
when "1"
|
43
|
+
"subsequent"
|
44
|
+
else
|
45
|
+
raise ArgumentError, "#{@provider} sent in an unknown message type or msg_type"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/bianchi/ussd/store.rb
CHANGED
@@ -6,7 +6,13 @@ module Bianchi
|
|
6
6
|
attr_reader :session
|
7
7
|
|
8
8
|
def initialize(session)
|
9
|
-
|
9
|
+
redis_url = ENV.fetch("REDIS_URL", nil)
|
10
|
+
unless redis_url.present?
|
11
|
+
raise ArgumentError,
|
12
|
+
"environment variable REDIS_URL required to track engine session."
|
13
|
+
end
|
14
|
+
|
15
|
+
@redis = Redis.new(url: redis_url)
|
10
16
|
@session = session
|
11
17
|
end
|
12
18
|
|
data/lib/bianchi/version.rb
CHANGED
data/lib/bianchi.rb
CHANGED
@@ -6,6 +6,8 @@ require "json"
|
|
6
6
|
require "thor"
|
7
7
|
|
8
8
|
require_relative "bianchi/version"
|
9
|
+
require_relative "bianchi/ussd/provider_parsers/africastalking"
|
10
|
+
require_relative "bianchi/ussd/provider_parsers/appsnmobile"
|
9
11
|
require_relative "bianchi/ussd/provider_configurations"
|
10
12
|
require_relative "bianchi/ussd/engine"
|
11
13
|
require_relative "bianchi/ussd/menu"
|
@@ -13,7 +15,7 @@ require_relative "bianchi/ussd/session"
|
|
13
15
|
require_relative "bianchi/ussd/page_delegators"
|
14
16
|
require_relative "bianchi/ussd/page"
|
15
17
|
require_relative "bianchi/ussd/store"
|
16
|
-
require_relative "bianchi/ussd/
|
18
|
+
require_relative "bianchi/ussd/exceptions"
|
17
19
|
|
18
20
|
# cli
|
19
21
|
require "bianchi/cli/main"
|
data/ussd/engine.rb
CHANGED
data/ussd/main_menu/page_1.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bianchi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dapilah Sydney
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-02-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -74,9 +74,11 @@ executables:
|
|
74
74
|
extensions: []
|
75
75
|
extra_rdoc_files: []
|
76
76
|
files:
|
77
|
+
- ".github/workflows/ci.yml"
|
77
78
|
- ".gitignore"
|
78
79
|
- ".rspec"
|
79
80
|
- ".rubocop.yml"
|
81
|
+
- ".vscode/settings.json"
|
80
82
|
- CODE_OF_CONDUCT.md
|
81
83
|
- Gemfile
|
82
84
|
- Gemfile.lock
|
@@ -93,11 +95,13 @@ files:
|
|
93
95
|
- lib/bianchi/cli/templates/engine.erb
|
94
96
|
- lib/bianchi/cli/templates/page.erb
|
95
97
|
- lib/bianchi/ussd/engine.rb
|
96
|
-
- lib/bianchi/ussd/
|
98
|
+
- lib/bianchi/ussd/exceptions.rb
|
97
99
|
- lib/bianchi/ussd/menu.rb
|
98
100
|
- lib/bianchi/ussd/page.rb
|
99
101
|
- lib/bianchi/ussd/page_delegators.rb
|
100
102
|
- lib/bianchi/ussd/provider_configurations.rb
|
103
|
+
- lib/bianchi/ussd/provider_parsers/africastalking.rb
|
104
|
+
- lib/bianchi/ussd/provider_parsers/appsnmobile.rb
|
101
105
|
- lib/bianchi/ussd/session.rb
|
102
106
|
- lib/bianchi/ussd/store.rb
|
103
107
|
- lib/bianchi/version.rb
|
@@ -111,6 +115,7 @@ metadata:
|
|
111
115
|
homepage_uri: https://github.com/SydDaps/Bianchi
|
112
116
|
source_code_uri: https://github.com/SydDaps/Bianchi
|
113
117
|
changelog_uri: https://rubygems.org/
|
118
|
+
rubygems_mfa_required: 'true'
|
114
119
|
post_install_message:
|
115
120
|
rdoc_options: []
|
116
121
|
require_paths:
|