Skip to content

Commit

Permalink
Use response tuple (#41)
Browse files Browse the repository at this point in the history
* feat: take response tuple

* chore: update readme

* chore: fix error

* chore: update readme
  • Loading branch information
lenileiro authored Jan 1, 2022
1 parent 44eb278 commit 1fd05dc
Show file tree
Hide file tree
Showing 8 changed files with 346 additions and 220 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,8 @@
## v1.0.0 - 2021-10-02

- Add support for Zero Based menu list

# v1.1.0 - 2022-01-01

- Deplicate set `error` on ExUssd.set/2 function
- use response tuple
36 changes: 21 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ by adding `ex_ussd` to your list of dependencies in `mix.exs`:
```elixir
defp deps do
[
{:ex_ussd, "~> 1.0.2"}
{:ex_ussd, "~> 1.1.0"}
]
end
```
Expand Down Expand Up @@ -63,31 +63,37 @@ defmodule ApiWeb.HomeResolver do
use ExUssd

def ussd_init(menu, _payload) do
ExUssd.set(menu, title: "Enter your PIN")
{:ok, ExUssd.set(menu, title: "Enter your PIN")}
end

def ussd_callback(menu, payload, %{attempt: %{count: count}}) do
if payload.text == "5555" do
menu
|> ExUssd.set(data: %{name: "John"}) # use payload `phone_number` to fetch the user from DB
|> ExUssd.set(resolve: &home_rc/2)
menu =
menu
|> ExUssd.set(data: %{name: "John"}) # use payload `phone_number` to fetch the user from DB
|> ExUssd.set(resolve: &home_rc/2)
{:ok, menu}
else
ExUssd.set(menu, error: "Wrong PIN, #{2 - count} attempt left\n")
{:error, "Wrong PIN, #{2 - count} attempt left"}
end
end

def ussd_after_callback(%{error: true} = menu, _payload, %{attempt: %{count: 3}}) do
menu
|> ExUssd.set(title: "Account is locked, Dial *234# to reset your account")
|> ExUssd.set(should_close: true)
menu =
menu
|> ExUssd.set(title: "Account is locked, Dial *234# to reset your account")
|> ExUssd.set(should_close: true)
{:ok, menu}
end

def home_rc(%ExUssd{data: %{name: name}} = menu, _) do
menu
|> ExUssd.set(title: "Welcome #{name}!")
|> ExUssd.add(ExUssd.new(name: "option 1"))
|> ExUssd.add(ExUssd.new(name: "option 2"))
|> ExUssd.set(show_navigation: false) # hide navigation options
menu =
menu
|> ExUssd.set(title: "Welcome #{name}!")
|> ExUssd.add(ExUssd.new(name: "option 1"))
|> ExUssd.add(ExUssd.new(name: "option 2"))
|> ExUssd.set(show_navigation: false) # hide navigation options
{:ok, menu}
end
end
```
Expand All @@ -110,4 +116,4 @@ Auto-populated from:

## Licence

ExUssd is released under [Apache License 2.0](./LICENSE).
ExUssd is released under [Apache License 2.0](LICENSE).
291 changes: 166 additions & 125 deletions lib/ex_ussd.ex

Large diffs are not rendered by default.

128 changes: 100 additions & 28 deletions lib/ex_ussd/executer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,23 @@ defmodule ExUssd.Executer do
def execute_navigate(%ExUssd{navigate: navigate} = menu, payload)
when is_function(navigate) do
case apply(navigate, [menu, payload]) do
%ExUssd{} = menu -> %{menu | navigate: nil}
_ -> menu
%ExUssd{} = menu ->
%{menu | navigate: nil}

{:ok, menu} ->
menu

{:error, message} when is_binary(message) ->
{:ok, %{menu | error: IO.iodata_to_binary([message, "\n"])}}

{:error, message} ->
raise ArgumentError, "Expected a string, found #{inspect(message)}"

nil ->
nil

_ ->
menu
end
end

Expand All @@ -30,7 +45,22 @@ defmodule ExUssd.Executer do
def execute_init_callback(%ExUssd{resolve: resolve} = menu, payload)
when is_function(resolve) do
if is_function(resolve, 2) do
with %ExUssd{} = menu <- apply(resolve, [menu, payload]), do: {:ok, menu}
case apply(resolve, [menu, payload]) do
{:ok, %ExUssd{} = menu} ->
{:ok, menu}

{:ok, menu} ->
raise ArgumentError, "Expected ExUssd struct, found #{inspect(menu)}"

{:error, message} when is_binary(message) ->
{:ok, %{menu | error: IO.iodata_to_binary([message, "\n"])}}

{:error, message} ->
raise ArgumentError, "Expected a string, found #{inspect(message)}"

nil ->
nil
end
else
raise %BadArityError{function: resolve, args: [menu, payload]}
end
Expand All @@ -39,8 +69,22 @@ defmodule ExUssd.Executer do
def execute_init_callback(%ExUssd{name: name, resolve: resolve} = menu, payload)
when is_atom(resolve) do
if function_exported?(resolve, :ussd_init, 2) do
with %ExUssd{} = menu <- apply(resolve, :ussd_init, [menu, payload]),
do: {:ok, menu}
case apply(resolve, :ussd_init, [menu, payload]) do
{:ok, %ExUssd{} = menu} ->
{:ok, menu}

{:ok, menu} ->
raise ArgumentError, "Expected ExUssd struct, found #{inspect(menu)}"

{:error, message} when is_binary(message) ->
{:ok, %{menu | error: IO.iodata_to_binary([message, "\n"])}}

{:error, message} ->
raise ArgumentError, "Expected a string, found #{inspect(message)}"

nil ->
nil
end
else
raise %ArgumentError{message: "resolve module for #{name} does not export ussd_init/2"}
end
Expand Down Expand Up @@ -94,24 +138,38 @@ defmodule ExUssd.Executer do
)

try do
with %ExUssd{error: error} = current_menu <-
apply(resolve, :ussd_callback, [
%{menu | resolve: nil, menu_list: []},
payload,
metadata
]) do
if is_bitstring(error) do
case apply(resolve, :ussd_callback, [
%{menu | resolve: nil, menu_list: []},
payload,
metadata
]) do
{:ok, %ExUssd{} = response_menu} ->
build_response_menu(:ok, %{response_menu | error: nil}, menu, payload, opts)
|> get_next_menu(menu, payload, opts)

{:ok, menu} ->
raise ArgumentError, "Expected ExUssd struct, found #{inspect(menu)}"

{:error, message} when is_binary(message) ->
if Keyword.get(opts, :state) do
ExUssd.Registry.add_attempt(payload[:session_id], payload[:text])
end

if Enum.empty?(menu_list) do
build_response_menu(:halt, current_menu, menu, payload, opts)
build_response_menu(
:halt,
%{menu | error: IO.iodata_to_binary([message, "\n"])},
menu,
payload,
opts
)
end
else
build_response_menu(:ok, current_menu, menu, payload, opts)
|> get_next_menu(menu, payload, opts)
end

{:error, message} ->
raise ArgumentError, "Expected a string, found #{inspect(message)}"

nil ->
nil
end
rescue
FunctionClauseError ->
Expand Down Expand Up @@ -161,18 +219,32 @@ defmodule ExUssd.Executer do
)

try do
with %ExUssd{error: error} = current_menu <-
apply(resolve, :ussd_after_callback, [
%{menu | resolve: nil, menu_list: [], error: error_state},
payload,
metadata
]) do
if is_bitstring(error) do
build_response_menu(:halt, current_menu, menu, payload, opts)
else
build_response_menu(:ok, current_menu, menu, payload, opts)
case apply(resolve, :ussd_after_callback, [
%{menu | resolve: nil, menu_list: [], error: error_state},
payload,
metadata
]) do
{:ok, %ExUssd{} = response_menu} ->
build_response_menu(:ok, %{response_menu | error: nil}, menu, payload, opts)
|> get_next_menu(menu, payload, opts)
end

{:ok, menu} ->
raise ArgumentError, "Expected ExUssd struct, found #{inspect(menu)}"

{:error, message} when is_binary(message) ->
build_response_menu(
:halt,
%{menu | error: IO.iodata_to_binary([message, "\n"])},
menu,
payload,
opts
)

{:error, message} ->
raise ArgumentError, "Expected a string, found #{inspect(message)}"

nil ->
nil
end
rescue
FunctionClauseError ->
Expand Down
1 change: 0 additions & 1 deletion lib/ex_ussd/op.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ defmodule ExUssd.Op do
alias ExUssd.{Display, Utils}

@allowed_fields [
:error,
:title,
:next,
:previous,
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule ExUssd.MixProject do
use Mix.Project

@source_url "https://github.com/beamkenya/ex_ussd.git"
@version "1.0.1"
@version "1.1.0"

def project do
[
Expand Down
4 changes: 2 additions & 2 deletions test/ex_ussd/executer_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ defmodule ExUssd.ExecuterTest do
menu =
ExUssd.new(
name: Faker.Company.name(),
resolve: fn menu, _payload -> menu |> ExUssd.set(title: "Welcome") end
resolve: fn menu, _payload -> {:ok, ExUssd.set(menu, title: "Welcome")} end
)

title = "Welcome"
Expand All @@ -19,7 +19,7 @@ defmodule ExUssd.ExecuterTest do
menu =
ExUssd.new(
name: Faker.Company.name(),
resolve: fn menu, _payload, _metadata -> menu |> ExUssd.set(title: "Welcome") end
resolve: fn menu, _payload, _metadata -> {:ok, ExUssd.set(menu, title: "Welcome")} end
)

assert_raise BadArityError, fn -> Executer.execute_init_callback(menu, Map.new()) end
Expand Down
Loading

0 comments on commit 1fd05dc

Please sign in to comment.