Compare commits

...

113 Commits

Author SHA1 Message Date
42177aadeb
use latest commit from sarafu-api
Some checks are pending
release / docker (push) Waiting to run
2025-04-11 11:10:48 +03:00
fa9f1a72ef Merge pull request 'self pin reset' (#49) from self-pin-reset-node into master
Reviewed-on: #49
2025-04-11 09:26:11 +02:00
4ffb32f14a Merge branch 'master' into self-pin-reset-node 2025-04-11 10:25:35 +03:00
c41277db87 Merge pull request 'sms-upsell' (#55) from sms-upsell into master
Reviewed-on: #55
2025-04-11 09:24:35 +02:00
56cda36aa7
updated the description of DATA_SELF_PIN_RESET 2025-04-10 13:55:00 +03:00
c9170ca45a Merge branch 'master' into self-pin-reset-node 2025-04-09 23:43:10 +03:00
57a1645c03
remove the verify_new_pin functionality that managed the unused flag_valid_pin 2025-04-09 23:40:03 +03:00
7d9c3b66a9
remove unused function reset_valid_pin 2025-04-09 19:29:40 +03:00
aec1f4c4c1
use a single confirm_pin_change node 2025-04-09 19:23:46 +03:00
d680387ef1
use the same check for flag_invalid_pin to move to the invalid_pin node 2025-04-09 19:21:35 +03:00
0337c66f96
cleanup: remove extra space in all .vis files 2025-04-09 18:17:59 +03:00
6070792fe4
cleanup: remove extra space 2025-04-09 18:14:10 +03:00
69ae494b2c
update the order for the INCMP statement 2025-04-09 18:10:51 +03:00
b89abf3487
update the reset flags in TestCheckBlockedStatus 2025-04-09 18:06:24 +03:00
4ef8c47f8b
update the reset flags in TestConfirmPinChange 2025-04-09 18:01:40 +03:00
1076a9578e
use the correct flag_invalid_pin in TestSaveTemporaryPin 2025-04-09 17:57:54 +03:00
a27d44e561
updated the expected content for the alias in view profile 2025-04-09 17:52:58 +03:00
35a2732fe2
updated the menu flow for the admin reset others PIN in test 2025-04-09 17:52:18 +03:00
834f2ce629
remove code related to admins resetting a user's actual PIN 2025-04-09 17:39:41 +03:00
26353bdf6e
add a space 2025-04-09 17:34:24 +03:00
1f6bf2bbed
updated the flags set and reset in SaveTemporaryPin and VerifyCreatePin 2025-04-09 16:59:48 +03:00
0c1d9ab582
updated the description of the flag_incorrect_pin 2025-04-09 16:58:13 +03:00
29d94bb2e5
have the catch for create_pin above to catch accounts that do not have a PIN before the status on chain is checked 2025-04-09 16:57:22 +03:00
067c496244
use a single pin_mismatch node for a confirmed PIN that does not match the original PIN 2025-04-09 16:55:46 +03:00
f8c258a3b4
allow the user to quit and move to invalid_pin node if the given input is invalid 2025-04-09 16:49:04 +03:00
aec96ce9ba
move to the top node when one selects back 2025-04-09 15:19:23 +03:00
71ef950fff
use the confirm_self_pin_reset to confirm the new PIN 2025-04-09 15:12:51 +03:00
477f3a307a
use the self_reset_pin node to reset PINs for accounts with a flag_account_pin_reset 2025-04-09 15:11:51 +03:00
33c376c971
set the DATA_SELF_PIN_RESET as 0 and reset the flag_account_pin_reset 2025-04-09 15:10:12 +03:00
514f6ae05b
move back to the previous node if the admin user is not authorized 2025-04-08 16:26:21 +03:00
8a6659a98b
request the admin to authorize the PIN reset 2025-04-08 16:25:50 +03:00
d094af9c51
move to the authorize_reset_others_pin if the given number is valid and registered 2025-04-08 16:25:11 +03:00
f96f9c11e6
updated the ResetOthersPin and ValidateBlockedNumber for the updated reset other's PIN functionality 2025-04-08 16:23:21 +03:00
1d8b0ef951
Merge branch 'master' into sms-upsell 2025-04-07 11:45:29 +03:00
fb2dc003b8
check recipient before sending an sms 2025-04-07 11:38:52 +03:00
a11ca2a618
reset the flag_language_set and flag_account_created flags if the publicKey does not exist on the db
Some checks failed
release / docker (push) Has been cancelled
2025-04-04 12:05:04 +03:00
4268cc0589
build: logdebug mode
Some checks failed
release / docker (push) Has been cancelled
2025-04-03 15:45:41 +03:00
ae0672c7da
updated the vise version to pop the cache on a new session
Some checks failed
release / docker (push) Has been cancelled
2025-04-02 18:34:04 +03:00
2c671bc0d4
use the DATA_SELF_PIN_RESET to set the flag_account_pin_reset 2025-04-02 18:29:04 +03:00
c5673b339b
added a DATA_SELF_PIN_RESET to track when a user's PIN is reset by an admin 2025-04-02 18:24:34 +03:00
c3567313af Merge pull request 'manage vouchers in single function' (#42) from manage-vouchers-in-single-function into master
Reviewed-on: #42
2025-04-01 21:26:28 +02:00
f82b413e34 Merge branch 'master' into manage-vouchers-in-single-function 2025-04-01 21:26:16 +02:00
695bfed349
feat: send invites when a recipient
is not resolved
2025-04-01 16:30:08 +03:00
8bf48cb081
update sarafu-api dep 2025-04-01 16:25:59 +03:00
ea0fc4491d
removed debug related logs 2025-04-01 11:12:38 +03:00
2634790118 Merge pull request 'use a different key for the suggested aliases' (#47) from fix-double-alias-request into master
Some checks failed
release / docker (push) Has been cancelled
Reviewed-on: #47
2025-03-28 09:35:10 +01:00
272a7ac05f
chore: remove extra colon 2025-03-28 11:32:24 +03:00
39c0d31995
remove verbose logs 2025-03-28 11:26:32 +03:00
18acb53ead
add alias logs
Some checks failed
release / docker (push) Has been cancelled
2025-03-28 11:08:50 +03:00
43d91f84f6
use a different key for the suggested aliases 2025-03-28 10:49:31 +03:00
0914217769
increase the size limit for the manage_vouchers 2025-03-26 14:33:23 +03:00
ea117b7222
replace SetDefaultVoucher and CheckVouchers with ManageVouchers 2025-03-26 14:28:43 +03:00
39e1c84a45
added TestManageVouchers for ManageVouchers 2025-03-26 14:27:17 +03:00
20ee4dfb24
replace SetDefaultVoucher and CheckVouchers with ManageVouchers 2025-03-26 14:26:31 +03:00
0791eb1f11
ci/cd: build with log warn only
Some checks failed
release / docker (push) Has been cancelled
2025-03-25 09:52:37 +03:00
8ebd2bbbfa
remove alias updates from TestUpdateAllProfileItems
Some checks failed
release / docker (push) Has been cancelled
2025-03-24 20:06:07 +03:00
06c534cbb1
remove the subprefix db from TestViewVoucher 2025-03-24 20:03:20 +03:00
b8d53f82bb
remove the subprefix db from TestGetVoucherList 2025-03-24 20:01:44 +03:00
71c01e00cd
remove commented out code 2025-03-24 19:58:43 +03:00
419716a2b4
remove the subprefix db from TestCheckVouchers 2025-03-24 19:57:08 +03:00
54b2088842
Pass correct arguments in the TestGetVoucherData 2025-03-24 19:53:02 +03:00
b2208359d6 Add missing param to the GetVoucherData 2025-03-24 19:46:58 +03:00
0828b1eb10 Increase the limit for the max_amount output 2025-03-24 19:46:58 +03:00
c22f9edeca Merge pull request 'fix-multiple-alias-requests' (#38) from fix-multiple-alias-requests into master
Some checks failed
release / docker (push) Has been cancelled
Reviewed-on: #38
2025-03-24 15:47:26 +01:00
c81b17994a
remove redundant cast on sanitized input 2025-03-24 16:03:30 +03:00
64b42b92ec
Merge branch 'master' into fix-multiple-alias-requests 2025-03-24 16:00:20 +03:00
493f64157b
sanitize alias hint before request 2025-03-24 15:59:13 +03:00
f6c9d54a65
register check-account_created handler
Some checks failed
release / docker (push) Has been cancelled
2025-03-24 12:39:03 +03:00
74c82de472
add check for if public key exists,then explicitly set flag_account_created
Some checks failed
release / docker (push) Has been cancelled
2025-03-24 12:29:40 +03:00
ddb8c6e748
add lowercase balance text translation 2025-03-22 18:39:05 +03:00
87ebd0029b
chore: show default value when profile info is not set 2025-03-22 18:38:35 +03:00
b941cf2562
chore: match profile text prompt 2025-03-22 18:37:27 +03:00
1c8bda5ded
fix(alias): remove alias requests made when a profile item is edited,show a default value when an alias is not set 2025-03-22 09:49:19 +03:00
30cb800450
Added log lines for voucherlist
Some checks failed
release / docker (push) Has been cancelled
2025-03-21 13:58:30 +03:00
680a1e9681
Use userstore for the voucher data instead of subprefixdb
Some checks failed
release / docker (push) Has been cancelled
2025-03-21 13:46:13 +03:00
b327b569fb
fix failing test 2025-03-21 09:05:51 +03:00
445ca0d0ff
Add a default alias to remove bug in retrieving the data
Some checks failed
release / docker (push) Has been cancelled
2025-03-20 22:34:04 +03:00
e681c9cfca
Added debug logs
Some checks failed
release / docker (push) Has been cancelled
2025-03-20 15:23:36 +03:00
d504571014
Added debug logs
Some checks failed
release / docker (push) Has been cancelled
2025-03-20 15:07:02 +03:00
3b16e25ebd
Added debug logs
Some checks failed
release / docker (push) Has been cancelled
2025-03-20 14:54:06 +03:00
5f37856927
Added activeSym logs
Some checks failed
release / docker (push) Has been cancelled
2025-03-20 14:35:06 +03:00
e564f1328b
add fetched vouchers log
Some checks failed
release / docker (push) Has been cancelled
2025-03-20 13:48:34 +03:00
374f79388c
ci/cd: remove ssh binary from Docker builds
Some checks failed
release / docker (push) Has been cancelled
2025-03-18 17:48:55 +03:00
lash
30644d3535 Merge branch 'lash/more-edbug' 2025-03-15 03:12:05 +00:00
lash
e5e857e3cb
Upgrade deps 2025-03-15 03:02:25 +00:00
1af826e87f
dep: update sarafu-api dep
Some checks failed
release / docker (push) Has been cancelled
2025-03-10 12:41:16 +03:00
38ef3b623e
dep: update sarafu-api dep
Some checks failed
release / docker (push) Has been cancelled
2025-03-10 11:53:47 +03:00
f7e7f7bd1c
add for check back,add logs for the alias 2025-03-10 11:51:02 +03:00
bd0e7822ed
dep: upgrade sarafu-api dep
Some checks failed
release / docker (push) Has been cancelled
2025-03-07 16:13:23 +03:00
4dba5f2ab5
dep: upgrade sarafu-api dep
Some checks failed
release / docker (push) Has been cancelled
2025-03-07 09:48:30 +03:00
144398e18b Merge pull request 'ens' (#32) from ens into master
Reviewed-on: #32
Reviewed-by: lash <accounts-grassrootseconomics@holbrook.no>
2025-03-07 06:00:17 +01:00
e97d4be296
refactor: break down checkbalance function to avoild code redandancy,remove misplaced flag setting 2025-03-03 12:16:45 +03:00
c2a0b05c84
fix: update expected content in checkbalance function 2025-03-03 12:12:46 +03:00
20c8af582c
switch to use ens api endpoint for the aliases requests 2025-02-28 17:29:18 +03:00
101afd5ebd
update check balance test 2025-02-27 16:35:41 +03:00
830d867ac8
chore: remove alias tag,use lower case b for balance 2025-02-27 16:35:17 +03:00
0cbe391209
update test data file to include my alias menu option 2025-02-27 16:00:54 +03:00
226d1f5697
fix: update authorize test function 2025-02-27 13:21:42 +03:00
3e422f269f
feat: show alias if set on main node 2025-02-27 13:14:27 +03:00
7a6e5b094f
load current alias 2025-02-27 09:42:25 +03:00
5ed63cec39
reset invalid PIN flag 2025-02-27 09:41:02 +03:00
8f7d5ff66d
feat: add request for ens based names from user input 2025-02-26 16:34:00 +03:00
f922fb6d43
update authorize_account sink value 2025-02-26 15:48:25 +03:00
78af4d225f
add alias account template 2025-02-26 15:47:17 +03:00
b887c67e5d
add node to confirm your alias 2025-02-26 15:14:04 +03:00
0816190469
feat: add node to update your alias 2025-02-26 15:08:29 +03:00
28e734e0ba
feat: add my alias menu option 2025-02-26 15:02:28 +03:00
d92dc026f5
check for invalid PIN 2025-02-26 14:51:16 +03:00
939df35c8c
register new menu handlers 2025-02-26 14:48:19 +03:00
c09ce32010
feat: reset invalid pin flag,update template text 2025-02-26 14:46:09 +03:00
1f0e7c016e
add check for account alias data type 2025-02-26 14:40:17 +03:00
a984c9dd06
add invalid and account alias flags 2025-02-26 14:37:54 +03:00
e2d5546de1 Merge pull request 'fix-pin-reset-bug' (#26) from fix-pin-reset-bug into master
Some checks failed
release / docker (push) Has been cancelled
Reviewed-on: #26
2025-02-21 10:31:45 +01:00
75 changed files with 669 additions and 834 deletions

View File

@ -21,8 +21,7 @@ RUN make VISE_PATH=/build/go-vise -B
WORKDIR /build/sarafu-vise WORKDIR /build/sarafu-vise
RUN echo "Building on $BUILDPLATFORM, building for $TARGETPLATFORM" RUN echo "Building on $BUILDPLATFORM, building for $TARGETPLATFORM"
RUN go mod download RUN go mod download
RUN go build -tags logtrace,online -o sarafu-at -ldflags="-X main.build=${BUILD} -s -w" cmd/africastalking/main.go RUN go build -tags logdebug,online -o sarafu-at -ldflags="-X main.build=${BUILD} -s -w" cmd/africastalking/main.go
RUN go build -tags logtrace,online -o sarafu-ssh -ldflags="-X main.build=${BUILD} -s -w" cmd/ssh/main.go
FROM debian:bookworm-slim FROM debian:bookworm-slim
@ -37,7 +36,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
WORKDIR /service WORKDIR /service
COPY --from=build /build/sarafu-vise/sarafu-at . COPY --from=build /build/sarafu-vise/sarafu-at .
COPY --from=build /build/sarafu-vise/sarafu-ssh .
COPY --from=build /build/sarafu-vise/LICENSE . COPY --from=build /build/sarafu-vise/LICENSE .
COPY --from=build /build/sarafu-vise/README.md . COPY --from=build /build/sarafu-vise/README.md .
COPY --from=build /build/sarafu-vise/services ./services COPY --from=build /build/sarafu-vise/services ./services
@ -45,6 +43,5 @@ COPY --from=build /build/sarafu-vise/.env.example .
RUN mv .env.example .env RUN mv .env.example .env
EXPOSE 7123 EXPOSE 7123
EXPOSE 7122
CMD ["./sarafu-at"] CMD ["./sarafu-at"]

6
go.mod
View File

@ -3,10 +3,10 @@ module git.grassecon.net/grassrootseconomics/sarafu-vise
go 1.23.4 go 1.23.4
require ( require (
git.defalsify.org/vise.git v0.2.3-0.20250205173834-d1f6647211ac git.defalsify.org/vise.git v0.3.2-0.20250401123711-d481b04a6805
git.grassecon.net/grassrootseconomics/common v0.0.0-20250121134736-ba8cbbccea7d git.grassecon.net/grassrootseconomics/common v0.0.0-20250121134736-ba8cbbccea7d
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250206112944-31eb30de0f69 git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250411080608-34957e5b6ff8
git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.1.0.20250204132347-1eb0b1555244 git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2
git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694 git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694
github.com/alecthomas/assert/v2 v2.2.2 github.com/alecthomas/assert/v2 v2.2.2
github.com/gofrs/uuid v4.4.0+incompatible github.com/gofrs/uuid v4.4.0+incompatible

22
go.sum
View File

@ -1,11 +1,21 @@
git.defalsify.org/vise.git v0.2.3-0.20250205173834-d1f6647211ac h1:f/E0ZTclVfMEnD/3Alrzzbg+dOm138zGydV42jT0JPw= git.defalsify.org/vise.git v0.3.1 h1:A6FhMcur09ft/JzUPGXR+KpA17fltfeBnasyvLMZmq4=
git.defalsify.org/vise.git v0.2.3-0.20250205173834-d1f6647211ac/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck= git.defalsify.org/vise.git v0.3.1/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck=
git.defalsify.org/vise.git v0.3.2-0.20250401123711-d481b04a6805 h1:FnT39aqXcP5YWhwPDBABopSjCu2SlbPFoOVitSpAVxU=
git.defalsify.org/vise.git v0.3.2-0.20250401123711-d481b04a6805/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck=
git.grassecon.net/grassrootseconomics/common v0.0.0-20250121134736-ba8cbbccea7d h1:5mzLas+jxTUtusOKx4XvU+n2QvrV/mH17MnJRy46siQ= git.grassecon.net/grassrootseconomics/common v0.0.0-20250121134736-ba8cbbccea7d h1:5mzLas+jxTUtusOKx4XvU+n2QvrV/mH17MnJRy46siQ=
git.grassecon.net/grassrootseconomics/common v0.0.0-20250121134736-ba8cbbccea7d/go.mod h1:wgQJZGIS6QuNLHqDhcsvehsbn5PvgV7aziRebMnJi60= git.grassecon.net/grassrootseconomics/common v0.0.0-20250121134736-ba8cbbccea7d/go.mod h1:wgQJZGIS6QuNLHqDhcsvehsbn5PvgV7aziRebMnJi60=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250206112944-31eb30de0f69 h1:cbBpm9uNJak58MpFpNXJuvgCmz+A8kquXr9har4expg= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250310093912-8145b4bd004b h1:xiTpaqWWoF5qcnarY/9ZkT6aVdnKwqztb2gzIahJn4w=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250206112944-31eb30de0f69/go.mod h1:gOn89ipaDcDvmQXRMQYKUqcw/sJcwVOPVt2eC6Geip8= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250310093912-8145b4bd004b/go.mod h1:gOn89ipaDcDvmQXRMQYKUqcw/sJcwVOPVt2eC6Geip8=
git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.1.0.20250204132347-1eb0b1555244 h1:BXotWSKg04U97sf/xeWJuUTSVgKk2aEK+5BtBrnafXQ= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250401111804-2eed990921c5 h1:DwBZHP4sebfHxK8EU2nlA2CXU81+a7Kj/pnC5vDPcf4=
git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.1.0.20250204132347-1eb0b1555244/go.mod h1:6B6ByxXOiRY0NR7K02Bf3fEu7z+2c/6q8PFVNjC5G8w= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250401111804-2eed990921c5/go.mod h1:gOn89ipaDcDvmQXRMQYKUqcw/sJcwVOPVt2eC6Geip8=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250401115503-5b41c8dc6440 h1:eWrBZMM3pBMCFyRl4rO/aaR+OmOMFJxogNyFAFry+EM=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250401115503-5b41c8dc6440/go.mod h1:gOn89ipaDcDvmQXRMQYKUqcw/sJcwVOPVt2eC6Geip8=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250401122510-441e289854ad h1:tYjanaCf6mF+iXRtDx5gckQm5vhZYx9N/JlNIBZj1m0=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250401122510-441e289854ad/go.mod h1:gOn89ipaDcDvmQXRMQYKUqcw/sJcwVOPVt2eC6Geip8=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250411080608-34957e5b6ff8 h1:Emesd0rybSLhPwZwqdvLsk/P9ZsT+7CQwQV/mrjQp3o=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250411080608-34957e5b6ff8/go.mod h1:gOn89ipaDcDvmQXRMQYKUqcw/sJcwVOPVt2eC6Geip8=
git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2 h1:YFztSsexCUgFo6M0tbngRwYdgJd3LQV3RO/Jw09u3+k=
git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2/go.mod h1:6B6ByxXOiRY0NR7K02Bf3fEu7z+2c/6q8PFVNjC5G8w=
git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694 h1:DjJlBSz0S13acft5XZDWk7ZYnzElym0xLMYEVgyNJ+E= git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694 h1:DjJlBSz0S13acft5XZDWk7ZYnzElym0xLMYEVgyNJ+E=
git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694/go.mod h1:DpibtYpnT3nG4Kn556hRAkdu4+CtiI/6MbnQHal51mQ= git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694/go.mod h1:DpibtYpnT3nG4Kn556hRAkdu4+CtiI/6MbnQHal51mQ=
github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk= github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk=

View File

@ -1,11 +1,14 @@
package application package application
import ( import (
"bytes"
"context" "context"
"errors"
"fmt" "fmt"
"path" "path"
"strconv" "strconv"
"strings" "strings"
"unicode"
"gopkg.in/leonelquinteros/gotext.v1" "gopkg.in/leonelquinteros/gotext.v1"
@ -193,6 +196,7 @@ func (h *MenuHandlers) createAccountNoExist(ctx context.Context, sessionId strin
data := map[storedb.DataTyp]string{ data := map[storedb.DataTyp]string{
storedb.DATA_TRACKING_ID: trackingId, storedb.DATA_TRACKING_ID: trackingId,
storedb.DATA_PUBLIC_KEY: publicKey, storedb.DATA_PUBLIC_KEY: publicKey,
storedb.DATA_ACCOUNT_ALIAS: "",
} }
store := h.userdataStore store := h.userdataStore
for key, value := range data { for key, value := range data {
@ -239,26 +243,60 @@ func (h *MenuHandlers) CreateAccount(ctx context.Context, sym string, input []by
return res, nil return res, nil
} }
// ResetValidPin resets the flag_valid_pin flag. func (h *MenuHandlers) CheckAccountCreated(ctx context.Context, sym string, input []byte) (resource.Result, error) {
func (h *MenuHandlers) ResetValidPin(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
flag_valid_pin, _ := h.flagManager.GetFlag("flag_valid_pin") flag_language_set, _ := h.flagManager.GetFlag("flag_language_set")
res.FlagReset = append(res.FlagReset, flag_valid_pin) flag_account_created, _ := h.flagManager.GetFlag("flag_account_created")
store := h.userdataStore
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
_, err := store.ReadEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY)
if err != nil {
if db.IsNotFound(err) {
// reset major flags
res.FlagReset = append(res.FlagReset, flag_language_set)
res.FlagReset = append(res.FlagReset, flag_account_created)
return res, nil
}
return res, nil
}
res.FlagSet = append(res.FlagSet, flag_account_created)
return res, nil return res, nil
} }
// CheckBlockedStatus resets the account blocked flag if the PIN attempts have been reset by an admin. // CheckBlockedStatus:
// 1. Checks whether the DATA_SELF_PIN_RESET is 1 and sets the flag_account_pin_reset
// 2. resets the account blocked flag if the PIN attempts have been reset by an admin.
func (h *MenuHandlers) CheckBlockedStatus(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *MenuHandlers) CheckBlockedStatus(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
store := h.userdataStore store := h.userdataStore
flag_account_blocked, _ := h.flagManager.GetFlag("flag_account_blocked") flag_account_blocked, _ := h.flagManager.GetFlag("flag_account_blocked")
flag_account_pin_reset, _ := h.flagManager.GetFlag("flag_account_pin_reset")
sessionId, ok := ctx.Value("SessionId").(string) sessionId, ok := ctx.Value("SessionId").(string)
if !ok { if !ok {
return res, fmt.Errorf("missing session") return res, fmt.Errorf("missing session")
} }
res.FlagReset = append(res.FlagReset, flag_account_pin_reset)
selfPinReset, err := store.ReadEntry(ctx, sessionId, storedb.DATA_SELF_PIN_RESET)
if err == nil {
pinResetValue, _ := strconv.ParseUint(string(selfPinReset), 0, 64)
if pinResetValue == 1 {
res.FlagSet = append(res.FlagSet, flag_account_pin_reset)
}
}
currentWrongPinAttempts, err := store.ReadEntry(ctx, sessionId, storedb.DATA_INCORRECT_PIN_ATTEMPTS) currentWrongPinAttempts, err := store.ReadEntry(ctx, sessionId, storedb.DATA_INCORRECT_PIN_ATTEMPTS)
if err != nil { if err != nil {
if !db.IsNotFound(err) { if !db.IsNotFound(err) {
@ -267,7 +305,6 @@ func (h *MenuHandlers) CheckBlockedStatus(ctx context.Context, sym string, input
} }
pinAttemptsValue, _ := strconv.ParseUint(string(currentWrongPinAttempts), 0, 64) pinAttemptsValue, _ := strconv.ParseUint(string(currentWrongPinAttempts), 0, 64)
if pinAttemptsValue == 0 { if pinAttemptsValue == 0 {
res.FlagReset = append(res.FlagReset, flag_account_blocked) res.FlagReset = append(res.FlagReset, flag_account_blocked)
return res, nil return res, nil
@ -310,29 +347,6 @@ func (h *MenuHandlers) ResetIncorrectPin(ctx context.Context, sym string, input
return res, nil return res, nil
} }
// VerifyNewPin checks if a new PIN meets the required format criteria.
func (h *MenuHandlers) VerifyNewPin(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{}
_, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
flag_valid_pin, _ := h.flagManager.GetFlag("flag_valid_pin")
if string(input) != "0" {
pinInput := string(input)
// Validate that the PIN is a 4-digit number.
if pin.IsValidPIN(pinInput) {
res.FlagSet = append(res.FlagSet, flag_valid_pin)
} else {
res.FlagReset = append(res.FlagReset, flag_valid_pin)
}
} else {
res.FlagSet = append(res.FlagSet, flag_valid_pin)
}
return res, nil
}
// SaveTemporaryPin saves the valid PIN input to the DATA_TEMPORARY_VALUE, // SaveTemporaryPin saves the valid PIN input to the DATA_TEMPORARY_VALUE,
// during the account creation process // during the account creation process
// and during the change PIN process. // and during the change PIN process.
@ -345,15 +359,20 @@ func (h *MenuHandlers) SaveTemporaryPin(ctx context.Context, sym string, input [
return res, fmt.Errorf("missing session") return res, fmt.Errorf("missing session")
} }
flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin") flag_invalid_pin, _ := h.flagManager.GetFlag("flag_invalid_pin")
accountPIN := string(input)
// Validate that the PIN is a 4-digit number. if string(input) == "0" {
if !pin.IsValidPIN(accountPIN) {
res.FlagSet = append(res.FlagSet, flag_incorrect_pin)
return res, nil return res, nil
} }
res.FlagReset = append(res.FlagReset, flag_incorrect_pin)
accountPIN := string(input)
// Validate that the PIN has a valid format.
if !pin.IsValidPIN(accountPIN) {
res.FlagSet = append(res.FlagSet, flag_invalid_pin)
return res, nil
}
res.FlagReset = append(res.FlagReset, flag_invalid_pin)
// Hash the PIN // Hash the PIN
hashedPIN, err := pin.HashPIN(string(accountPIN)) hashedPIN, err := pin.HashPIN(string(accountPIN))
@ -372,84 +391,11 @@ func (h *MenuHandlers) SaveTemporaryPin(ctx context.Context, sym string, input [
return res, nil return res, nil
} }
// SaveOthersTemporaryPin allows authorized users to set temporary PINs for blocked numbers. // ResetInvalidPIN resets the invalid PIN flag
func (h *MenuHandlers) SaveOthersTemporaryPin(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *MenuHandlers) ResetInvalidPIN(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error flag_invalid_pin, _ := h.flagManager.GetFlag("flag_invalid_pin")
res.FlagReset = append(res.FlagReset, flag_invalid_pin)
store := h.userdataStore
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
temporaryPin := string(input)
// Validate that the input is a 4-digit number.
if !pin.IsValidPIN(temporaryPin) {
return res, nil
}
// Retrieve the blocked number associated with this session
blockedNumber, err := store.ReadEntry(ctx, sessionId, storedb.DATA_BLOCKED_NUMBER)
if err != nil {
logg.ErrorCtxf(ctx, "failed to read blockedNumber entry with", "key", storedb.DATA_BLOCKED_NUMBER, "error", err)
return res, err
}
// Hash the temporary PIN
hashedPIN, err := pin.HashPIN(string(temporaryPin))
if err != nil {
logg.ErrorCtxf(ctx, "failed to hash temporaryPin", "error", err)
return res, err
}
// Save the hashed temporary PIN for that blocked number
err = store.WriteEntry(ctx, string(blockedNumber), storedb.DATA_TEMPORARY_VALUE, []byte(hashedPIN))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write hashed temporaryPin entry with", "key", storedb.DATA_TEMPORARY_VALUE, "value", temporaryPin, "error", err)
return res, err
}
return res, nil
}
// CheckBlockedNumPinMisMatch checks if the provided PIN matches a temporary PIN stored for a blocked number.
func (h *MenuHandlers) CheckBlockedNumPinMisMatch(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{}
flag_pin_mismatch, _ := h.flagManager.GetFlag("flag_pin_mismatch")
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
if string(input) == "0" {
res.FlagReset = append(res.FlagReset, flag_pin_mismatch)
return res, nil
}
// Get blocked number from storage.
store := h.userdataStore
blockedNumber, err := store.ReadEntry(ctx, sessionId, storedb.DATA_BLOCKED_NUMBER)
if err != nil {
logg.ErrorCtxf(ctx, "failed to read blockedNumber entry with", "key", storedb.DATA_BLOCKED_NUMBER, "error", err)
return res, err
}
// Get Hashed temporary PIN for the blocked number.
hashedTemporaryPin, err := store.ReadEntry(ctx, string(blockedNumber), storedb.DATA_TEMPORARY_VALUE)
if err != nil {
logg.ErrorCtxf(ctx, "failed to read hashedTemporaryPin entry with", "key", storedb.DATA_TEMPORARY_VALUE, "error", err)
return res, err
}
if len(hashedTemporaryPin) == 0 {
logg.ErrorCtxf(ctx, "hashedTemporaryPin is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
if pin.VerifyPIN(string(hashedTemporaryPin), string(input)) {
res.FlagReset = append(res.FlagReset, flag_pin_mismatch)
} else {
res.FlagSet = append(res.FlagSet, flag_pin_mismatch)
}
return res, nil return res, nil
} }
@ -461,6 +407,7 @@ func (h *MenuHandlers) ConfirmPinChange(ctx context.Context, sym string, input [
return res, fmt.Errorf("missing session") return res, fmt.Errorf("missing session")
} }
flag_pin_mismatch, _ := h.flagManager.GetFlag("flag_pin_mismatch") flag_pin_mismatch, _ := h.flagManager.GetFlag("flag_pin_mismatch")
flag_account_pin_reset, _ := h.flagManager.GetFlag("flag_account_pin_reset")
if string(input) == "0" { if string(input) == "0" {
res.FlagReset = append(res.FlagReset, flag_pin_mismatch) res.FlagReset = append(res.FlagReset, flag_pin_mismatch)
@ -491,14 +438,68 @@ func (h *MenuHandlers) ConfirmPinChange(ctx context.Context, sym string, input [
logg.ErrorCtxf(ctx, "failed to write DATA_ACCOUNT_PIN entry with", "key", storedb.DATA_ACCOUNT_PIN, "hashedPIN value", hashedTemporaryPin, "error", err) logg.ErrorCtxf(ctx, "failed to write DATA_ACCOUNT_PIN entry with", "key", storedb.DATA_ACCOUNT_PIN, "hashedPIN value", hashedTemporaryPin, "error", err)
return res, err return res, err
} }
// set the DATA_SELF_PIN_RESET as 0
err = store.WriteEntry(ctx, sessionId, storedb.DATA_SELF_PIN_RESET, []byte("0"))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write DATA_SELF_PIN_RESET entry with", "key", storedb.DATA_SELF_PIN_RESET, "self PIN reset value", "0", "error", err)
return res, err
}
res.FlagReset = append(res.FlagReset, flag_account_pin_reset)
return res, nil
}
// ValidateBlockedNumber performs validation of phone numbers during the Reset other's PIN.
// It checks phone number format and verifies registration status.
// If valid, it writes the number under DATA_BLOCKED_NUMBER on the admin account
func (h *MenuHandlers) ValidateBlockedNumber(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
var err error
flag_unregistered_number, _ := h.flagManager.GetFlag("flag_unregistered_number")
store := h.userdataStore
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
if string(input) == "0" {
res.FlagReset = append(res.FlagReset, flag_unregistered_number)
return res, nil
}
blockedNumber := string(input)
formattedNumber, err := phone.FormatPhoneNumber(blockedNumber)
if err != nil {
res.FlagSet = append(res.FlagSet, flag_unregistered_number)
logg.ErrorCtxf(ctx, "Failed to format the phone number: %s", blockedNumber, "error", err)
return res, nil
}
_, err = store.ReadEntry(ctx, formattedNumber, storedb.DATA_PUBLIC_KEY)
if err != nil {
if db.IsNotFound(err) {
logg.InfoCtxf(ctx, "Invalid or unregistered number")
res.FlagSet = append(res.FlagSet, flag_unregistered_number)
return res, nil
} else {
logg.ErrorCtxf(ctx, "Error on ValidateBlockedNumber", "error", err)
return res, err
}
}
err = store.WriteEntry(ctx, sessionId, storedb.DATA_BLOCKED_NUMBER, []byte(formattedNumber))
if err != nil {
return res, nil
}
return res, nil return res, nil
} }
// ResetOthersPin handles the PIN reset process for other users' accounts by: // ResetOthersPin handles the PIN reset process for other users' accounts by:
// 1. Retrieving the blocked phone number from the session // 1. Retrieving the blocked phone number from the session
// 2. Fetching the hashed temporary PIN associated with that number // 2. Writing the DATA_SELF_PIN_RESET on the blocked phone number
// 3. Updating the account PIN with the temporary PIN // 3. Resetting the DATA_INCORRECT_PIN_ATTEMPTS to 0 for the blocked phone number
func (h *MenuHandlers) ResetOthersPin(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *MenuHandlers) ResetOthersPin(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
store := h.userdataStore store := h.userdataStore
@ -511,19 +512,11 @@ func (h *MenuHandlers) ResetOthersPin(ctx context.Context, sym string, input []b
logg.ErrorCtxf(ctx, "failed to read blockedPhonenumber entry with", "key", storedb.DATA_BLOCKED_NUMBER, "error", err) logg.ErrorCtxf(ctx, "failed to read blockedPhonenumber entry with", "key", storedb.DATA_BLOCKED_NUMBER, "error", err)
return res, err return res, err
} }
hashedTemporaryPin, err := store.ReadEntry(ctx, string(blockedPhonenumber), storedb.DATA_TEMPORARY_VALUE)
if err != nil {
logg.ErrorCtxf(ctx, "failed to read hashedTmporaryPin entry with", "key", storedb.DATA_TEMPORARY_VALUE, "error", err)
return res, err
}
if len(hashedTemporaryPin) == 0 {
logg.ErrorCtxf(ctx, "hashedTemporaryPin is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
err = store.WriteEntry(ctx, string(blockedPhonenumber), storedb.DATA_ACCOUNT_PIN, []byte(hashedTemporaryPin)) // set the DATA_SELF_PIN_RESET for the account
err = store.WriteEntry(ctx, string(blockedPhonenumber), storedb.DATA_SELF_PIN_RESET, []byte("1"))
if err != nil { if err != nil {
return res, err return res, nil
} }
err = store.WriteEntry(ctx, string(blockedPhonenumber), storedb.DATA_INCORRECT_PIN_ATTEMPTS, []byte(string("0"))) err = store.WriteEntry(ctx, string(blockedPhonenumber), storedb.DATA_INCORRECT_PIN_ATTEMPTS, []byte(string("0")))
@ -594,64 +587,26 @@ func (h *MenuHandlers) ResetUnregisteredNumber(ctx context.Context, sym string,
return res, nil return res, nil
} }
// ValidateBlockedNumber performs validation of phone numbers, specifically for blocked numbers in the system.
// It checks phone number format and verifies registration status.
func (h *MenuHandlers) ValidateBlockedNumber(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
var err error
flag_unregistered_number, _ := h.flagManager.GetFlag("flag_unregistered_number")
store := h.userdataStore
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
if string(input) == "0" {
res.FlagReset = append(res.FlagReset, flag_unregistered_number)
return res, nil
}
blockedNumber := string(input)
formattedNumber, err := phone.FormatPhoneNumber(blockedNumber)
if err != nil {
res.FlagSet = append(res.FlagSet, flag_unregistered_number)
logg.ErrorCtxf(ctx, "Failed to format the phone number: %s", blockedNumber, "error", err)
return res, nil
}
_, err = store.ReadEntry(ctx, formattedNumber, storedb.DATA_PUBLIC_KEY)
if err != nil {
if db.IsNotFound(err) {
logg.InfoCtxf(ctx, "Invalid or unregistered number")
res.FlagSet = append(res.FlagSet, flag_unregistered_number)
return res, nil
} else {
logg.ErrorCtxf(ctx, "Error on ValidateBlockedNumber", "error", err)
return res, err
}
}
err = store.WriteEntry(ctx, sessionId, storedb.DATA_BLOCKED_NUMBER, []byte(formattedNumber))
if err != nil {
return res, nil
}
return res, nil
}
// VerifyCreatePin checks whether the confirmation PIN is similar to the temporary PIN // VerifyCreatePin checks whether the confirmation PIN is similar to the temporary PIN
// If similar, it sets the USERFLAG_PIN_SET flag and writes the account PIN allowing the user // If similar, it sets the USERFLAG_PIN_SET flag and writes the account PIN allowing the user
// to access the main menu. // to access the main menu.
func (h *MenuHandlers) VerifyCreatePin(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *MenuHandlers) VerifyCreatePin(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
flag_valid_pin, _ := h.flagManager.GetFlag("flag_valid_pin")
flag_pin_mismatch, _ := h.flagManager.GetFlag("flag_pin_mismatch")
flag_pin_set, _ := h.flagManager.GetFlag("flag_pin_set")
sessionId, ok := ctx.Value("SessionId").(string) sessionId, ok := ctx.Value("SessionId").(string)
if !ok { if !ok {
return res, fmt.Errorf("missing session") return res, fmt.Errorf("missing session")
} }
flag_valid_pin, _ := h.flagManager.GetFlag("flag_valid_pin")
flag_pin_mismatch, _ := h.flagManager.GetFlag("flag_pin_mismatch")
flag_pin_set, _ := h.flagManager.GetFlag("flag_pin_set")
if string(input) == "0" {
res.FlagReset = append(res.FlagReset, flag_pin_mismatch)
return res, nil
}
store := h.userdataStore store := h.userdataStore
hashedTemporaryPin, err := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE) hashedTemporaryPin, err := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if err != nil { if err != nil {
@ -664,14 +619,15 @@ func (h *MenuHandlers) VerifyCreatePin(ctx context.Context, sym string, input []
} }
if pin.VerifyPIN(string(hashedTemporaryPin), string(input)) { if pin.VerifyPIN(string(hashedTemporaryPin), string(input)) {
res.FlagSet = []uint32{flag_valid_pin} res.FlagSet = append(res.FlagSet, flag_valid_pin)
res.FlagReset = []uint32{flag_pin_mismatch}
res.FlagSet = append(res.FlagSet, flag_pin_set) res.FlagSet = append(res.FlagSet, flag_pin_set)
res.FlagReset = append(res.FlagReset, flag_pin_mismatch)
} else { } else {
res.FlagSet = []uint32{flag_pin_mismatch} res.FlagSet = append(res.FlagSet, flag_pin_mismatch)
return res, nil return res, nil
} }
// save the hashed PIN as the new account PIN
err = store.WriteEntry(ctx, sessionId, storedb.DATA_ACCOUNT_PIN, []byte(hashedTemporaryPin)) err = store.WriteEntry(ctx, sessionId, storedb.DATA_ACCOUNT_PIN, []byte(hashedTemporaryPin))
if err != nil { if err != nil {
logg.ErrorCtxf(ctx, "failed to write DATA_ACCOUNT_PIN entry with", "key", storedb.DATA_ACCOUNT_PIN, "value", hashedTemporaryPin, "error", err) logg.ErrorCtxf(ctx, "failed to write DATA_ACCOUNT_PIN entry with", "key", storedb.DATA_ACCOUNT_PIN, "value", hashedTemporaryPin, "error", err)
@ -707,10 +663,6 @@ func (h *MenuHandlers) SaveFirstname(ctx context.Context, sym string, input []by
logg.ErrorCtxf(ctx, "failed to write firstName entry with", "key", storedb.DATA_FIRST_NAME, "value", temporaryFirstName, "error", err) logg.ErrorCtxf(ctx, "failed to write firstName entry with", "key", storedb.DATA_FIRST_NAME, "value", temporaryFirstName, "error", err)
return res, err return res, err
} }
err := h.constructAccountAlias(ctx)
if err != nil {
return res, err
}
res.FlagSet = append(res.FlagSet, flag_firstname_set) res.FlagSet = append(res.FlagSet, flag_firstname_set)
} else { } else {
if firstNameSet { if firstNameSet {
@ -1104,6 +1056,22 @@ func (h *MenuHandlers) GetCurrentProfileInfo(ctx context.Context, sym string, in
} }
res.FlagSet = append(res.FlagSet, flag_offerings_set) res.FlagSet = append(res.FlagSet, flag_offerings_set)
res.Content = string(profileInfo) res.Content = string(profileInfo)
case storedb.DATA_ACCOUNT_ALIAS:
profileInfo, err = store.ReadEntry(ctx, sessionId, storedb.DATA_ACCOUNT_ALIAS)
if err != nil {
if db.IsNotFound(err) {
res.Content = defaultValue
break
}
logg.ErrorCtxf(ctx, "Failed to read account alias entry with", "key", "error", storedb.DATA_ACCOUNT_ALIAS, err)
return res, err
}
alias := string(profileInfo)
if alias == "" {
res.Content = defaultValue
} else {
res.Content = alias
}
default: default:
break break
} }
@ -1147,8 +1115,10 @@ func (h *MenuHandlers) GetProfileInfo(ctx context.Context, sym string, input []b
offerings := getEntryOrDefault(store.ReadEntry(ctx, sessionId, storedb.DATA_OFFERINGS)) offerings := getEntryOrDefault(store.ReadEntry(ctx, sessionId, storedb.DATA_OFFERINGS))
alias := getEntryOrDefault(store.ReadEntry(ctx, sessionId, storedb.DATA_ACCOUNT_ALIAS)) alias := getEntryOrDefault(store.ReadEntry(ctx, sessionId, storedb.DATA_ACCOUNT_ALIAS))
if alias != defaultValue { if alias != defaultValue && alias != "" {
alias = strings.Split(alias, ".")[0] alias = strings.Split(alias, ".")[0]
} else {
alias = defaultValue
} }
// Construct the full name // Construct the full name
@ -1233,10 +1203,6 @@ func (h *MenuHandlers) UpdateAllProfileItems(ctx context.Context, sym string, in
if err != nil { if err != nil {
return res, err return res, err
} }
err = h.constructAccountAlias(ctx)
if err != nil {
return res, err
}
return res, nil return res, nil
} }
@ -1275,6 +1241,7 @@ func (h *MenuHandlers) Authorize(ctx context.Context, sym string, input []byte)
flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin") flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin")
flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized") flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized")
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
flag_invalid_pin, _ := h.flagManager.GetFlag("flag_invalid_pin")
store := h.userdataStore store := h.userdataStore
AccountPin, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACCOUNT_PIN) AccountPin, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACCOUNT_PIN)
@ -1311,6 +1278,9 @@ func (h *MenuHandlers) Authorize(ctx context.Context, sym string, input []byte)
return res, nil return res, nil
} }
} else { } else {
if string(input) != "0" {
res.FlagSet = append(res.FlagSet, flag_invalid_pin)
}
return res, nil return res, nil
} }
return res, nil return res, nil
@ -1411,53 +1381,83 @@ func (h *MenuHandlers) ShowBlockedAccount(ctx context.Context, sym string, input
return res, nil return res, nil
} }
// loadUserContent loads the main user content in the main menu: the alias,balance associated with active voucher
func loadUserContent(ctx context.Context, activeSym string, balance string, alias string) (string, error) {
var content string
code := codeFromCtx(ctx)
l := gotext.NewLocale(translationDir, code)
l.AddDomain("default")
balFloat, err := strconv.ParseFloat(balance, 64)
if err != nil {
//Only exclude ErrSyntax error to avoid returning an error if the active bal is not available yet
if !errors.Is(err, strconv.ErrSyntax) {
logg.ErrorCtxf(ctx, "failed to parse activeBal as float", "value", balance, "error", err)
return "", err
}
balFloat = 0.00
}
// Format to 2 decimal places
balStr := fmt.Sprintf("%.2f %s", balFloat, activeSym)
if alias != "" {
content = l.Get("%s balance: %s\n", alias, balStr)
} else {
content = l.Get("Balance: %s\n", balStr)
}
return content, nil
}
// CheckBalance retrieves the balance of the active voucher and sets // CheckBalance retrieves the balance of the active voucher and sets
// the balance as the result content. // the balance as the result content.
func (h *MenuHandlers) CheckBalance(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *MenuHandlers) CheckBalance(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var (
var err error res resource.Result
err error
alias string
content string
)
sessionId, ok := ctx.Value("SessionId").(string) sessionId, ok := ctx.Value("SessionId").(string)
if !ok { if !ok {
return res, fmt.Errorf("missing session") return res, fmt.Errorf("missing session")
} }
code := codeFromCtx(ctx)
l := gotext.NewLocale(translationDir, code)
l.AddDomain("default")
store := h.userdataStore store := h.userdataStore
// get the active sym and active balance // get the active sym and active balance
activeSym, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM) activeSym, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM)
if err != nil { if err != nil {
if db.IsNotFound(err) { logg.InfoCtxf(ctx, "could not find the activeSym in checkBalance:", "err", err)
balance := "0.00" if !db.IsNotFound(err) {
res.Content = l.Get("Balance: %s\n", balance)
return res, nil
}
logg.ErrorCtxf(ctx, "failed to read activeSym entry with", "key", storedb.DATA_ACTIVE_SYM, "error", err) logg.ErrorCtxf(ctx, "failed to read activeSym entry with", "key", storedb.DATA_ACTIVE_SYM, "error", err)
return res, err return res, err
} }
}
activeBal, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_BAL) activeBal, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_BAL)
if err != nil { if err != nil {
if !db.IsNotFound(err) {
logg.ErrorCtxf(ctx, "failed to read activeBal entry with", "key", storedb.DATA_ACTIVE_BAL, "error", err) logg.ErrorCtxf(ctx, "failed to read activeBal entry with", "key", storedb.DATA_ACTIVE_BAL, "error", err)
return res, err return res, err
} }
// Convert activeBal from []byte to float64
balFloat, err := strconv.ParseFloat(string(activeBal), 64)
if err != nil {
logg.ErrorCtxf(ctx, "failed to parse activeBal as float", "value", string(activeBal), "error", err)
return res, err
} }
// Format to 2 decimal places accAlias, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACCOUNT_ALIAS)
balStr := fmt.Sprintf("%.2f %s", balFloat, activeSym) if err != nil {
if !db.IsNotFound(err) {
logg.ErrorCtxf(ctx, "failed to read account alias entry with", "key", storedb.DATA_ACCOUNT_ALIAS, "error", err)
return res, err
}
} else {
alias = strings.Split(string(accAlias), ".")[0]
}
res.Content = l.Get("Balance: %s\n", balStr) content, err = loadUserContent(ctx, string(activeSym), string(activeBal), alias)
if err != nil {
return res, err
}
res.Content = content
return res, nil return res, nil
} }
@ -1561,6 +1561,7 @@ func (h *MenuHandlers) ValidateRecipient(ctx context.Context, sym string, input
//Perform a search for each search domain,break on first match //Perform a search for each search domain,break on first match
for _, domain := range config.SearchDomains() { for _, domain := range config.SearchDomains() {
fqdn := fmt.Sprintf("%s.%s", recipient, domain) fqdn := fmt.Sprintf("%s.%s", recipient, domain)
logg.InfoCtxf(ctx, "Resolving with fqdn alias", "alias", fqdn)
AliasAddress, err = h.accountService.CheckAliasAddress(ctx, fqdn) AliasAddress, err = h.accountService.CheckAliasAddress(ctx, fqdn)
if err == nil { if err == nil {
AliasAddressResult = AliasAddress.Address AliasAddressResult = AliasAddress.Address
@ -1630,19 +1631,24 @@ func (h *MenuHandlers) InviteValidRecipient(ctx context.Context, sym string, inp
l := gotext.NewLocale(translationDir, code) l := gotext.NewLocale(translationDir, code)
l.AddDomain("default") l.AddDomain("default")
recipient, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE) recipient, err := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if len(recipient) == 0 { if err != nil {
logg.ErrorCtxf(ctx, "recipient is empty", "key", storedb.DATA_TEMPORARY_VALUE) logg.ErrorCtxf(ctx, "Failed to read invalid recipient info", "error", err)
return res, fmt.Errorf("Data error encountered") return res, err
} }
// TODO if !phone.IsValidPhoneNumber(string(recipient)) {
// send an invitation SMS logg.InfoCtxf(ctx, "corrupted recipient", "key", storedb.DATA_TEMPORARY_VALUE, "recipient", recipient)
// if successful return res, nil
// res.Content = l.Get("Your invitation to %s to join Sarafu Network has been sent.", string(recipient)) }
_, err = h.accountService.SendUpsellSMS(ctx, sessionId, string(recipient))
if err != nil {
res.Content = l.Get("Your invite request for %s to Sarafu Network failed. Please try again later.", string(recipient)) res.Content = l.Get("Your invite request for %s to Sarafu Network failed. Please try again later.", string(recipient))
return res, nil return res, nil
}
res.Content = l.Get("Your invitation to %s to join Sarafu Network has been sent.", string(recipient))
return res, nil
} }
// ResetTransactionAmount resets the transaction amount and invalid flag. // ResetTransactionAmount resets the transaction amount and invalid flag.
@ -1867,11 +1873,12 @@ func (h *MenuHandlers) InitiateTransaction(ctx context.Context, sym string, inpu
return res, nil return res, nil
} }
// SetDefaultVoucher retrieves the current vouchers // ManageVouchers retrieves the token holdings from the API using the "PublicKey" and
// and sets the first as the default voucher, if no active voucher is set. // 1. sets the first as the default voucher if no active voucher is set.
func (h *MenuHandlers) SetDefaultVoucher(ctx context.Context, sym string, input []byte) (resource.Result, error) { // 2. Stores list of vouchers
// 3. updates the balance of the active voucher
func (h *MenuHandlers) ManageVouchers(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error
userStore := h.userdataStore userStore := h.userdataStore
sessionId, ok := ctx.Value("SessionId").(string) sessionId, ok := ctx.Value("SessionId").(string)
@ -1881,31 +1888,31 @@ func (h *MenuHandlers) SetDefaultVoucher(ctx context.Context, sym string, input
flag_no_active_voucher, _ := h.flagManager.GetFlag("flag_no_active_voucher") flag_no_active_voucher, _ := h.flagManager.GetFlag("flag_no_active_voucher")
// check if the user has an active sym
_, err = userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM)
if err != nil {
if db.IsNotFound(err) {
publicKey, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY) publicKey, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY)
if err != nil { if err != nil {
logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", storedb.DATA_PUBLIC_KEY, "error", err) logg.ErrorCtxf(ctx, "failed to read publicKey entry", "key", storedb.DATA_PUBLIC_KEY, "error", err)
return res, err return res, err
} }
// Fetch vouchers from the API using the public key // Fetch vouchers from API
vouchersResp, err := h.accountService.FetchVouchers(ctx, string(publicKey)) vouchersResp, err := h.accountService.FetchVouchers(ctx, string(publicKey))
if err != nil { if err != nil {
res.FlagSet = append(res.FlagSet, flag_no_active_voucher) res.FlagSet = append(res.FlagSet, flag_no_active_voucher)
return res, nil return res, nil
} }
// Return if there is no voucher
if len(vouchersResp) == 0 { if len(vouchersResp) == 0 {
res.FlagSet = append(res.FlagSet, flag_no_active_voucher) res.FlagSet = append(res.FlagSet, flag_no_active_voucher)
return res, nil return res, nil
} }
// Use only the first voucher res.FlagReset = append(res.FlagReset, flag_no_active_voucher)
// Check if user has an active voucher with proper error handling
activeSym, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM)
if err != nil {
if db.IsNotFound(err) {
// No active voucher, set the first one as default
firstVoucher := vouchersResp[0] firstVoucher := vouchersResp[0]
defaultSym := firstVoucher.TokenSymbol defaultSym := firstVoucher.TokenSymbol
defaultBal := firstVoucher.Balance defaultBal := firstVoucher.Balance
@ -1915,69 +1922,27 @@ func (h *MenuHandlers) SetDefaultVoucher(ctx context.Context, sym string, input
// Scale down the balance // Scale down the balance
scaledBalance := store.ScaleDownBalance(defaultBal, defaultDec) scaledBalance := store.ScaleDownBalance(defaultBal, defaultDec)
// TODO: implement atomic transaction firstVoucherMap := map[storedb.DataTyp]string{
// set the active symbol storedb.DATA_ACTIVE_SYM: defaultSym,
err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM, []byte(defaultSym)) storedb.DATA_ACTIVE_BAL: scaledBalance,
if err != nil { storedb.DATA_ACTIVE_DECIMAL: defaultDec,
logg.ErrorCtxf(ctx, "failed to write defaultSym entry with", "key", storedb.DATA_ACTIVE_SYM, "value", defaultSym, "error", err) storedb.DATA_ACTIVE_ADDRESS: defaultAddr,
return res, err
}
// set the active balance
err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_BAL, []byte(scaledBalance))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write defaultBal entry with", "key", storedb.DATA_ACTIVE_BAL, "value", scaledBalance, "error", err)
return res, err
}
// set the active decimals
err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_DECIMAL, []byte(defaultDec))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write defaultDec entry with", "key", storedb.DATA_ACTIVE_DECIMAL, "value", defaultDec, "error", err)
return res, err
}
// set the active contract address
err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_ADDRESS, []byte(defaultAddr))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write defaultAddr entry with", "key", storedb.DATA_ACTIVE_ADDRESS, "value", defaultAddr, "error", err)
return res, err
} }
return res, nil for key, value := range firstVoucherMap {
if err := userStore.WriteEntry(ctx, sessionId, key, []byte(value)); err != nil {
logg.ErrorCtxf(ctx, "Failed to write active voucher data", "key", key, "error", err)
return res, err
}
} }
logg.InfoCtxf(ctx, "Default voucher set", "symbol", defaultSym, "balance", defaultBal, "decimals", defaultDec, "address", defaultAddr)
} else {
logg.ErrorCtxf(ctx, "failed to read activeSym entry with", "key", storedb.DATA_ACTIVE_SYM, "error", err) logg.ErrorCtxf(ctx, "failed to read activeSym entry with", "key", storedb.DATA_ACTIVE_SYM, "error", err)
return res, err return res, err
} }
} else {
res.FlagReset = append(res.FlagReset, flag_no_active_voucher) // Update active voucher balance
return res, nil
}
// CheckVouchers retrieves the token holdings from the API using the "PublicKey" and stores
// them to gdbm.
func (h *MenuHandlers) CheckVouchers(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
userStore := h.userdataStore
publicKey, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY)
if err != nil {
logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", storedb.DATA_PUBLIC_KEY, "error", err)
return res, err
}
// Fetch vouchers from the API using the public key
vouchersResp, err := h.accountService.FetchVouchers(ctx, string(publicKey))
if err != nil {
return res, nil
}
// check the current active sym and update the data
activeSym, _ := userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM)
if activeSym != nil {
activeSymStr := string(activeSym) activeSymStr := string(activeSym)
// Find the matching voucher data // Find the matching voucher data
@ -2007,9 +1972,8 @@ func (h *MenuHandlers) CheckVouchers(ctx context.Context, sym string, input []by
} }
} }
data := store.ProcessVouchers(vouchersResp)
// Store all voucher data // Store all voucher data
data := store.ProcessVouchers(vouchersResp)
dataMap := map[storedb.DataTyp]string{ dataMap := map[storedb.DataTyp]string{
storedb.DATA_VOUCHER_SYMBOLS: data.Symbols, storedb.DATA_VOUCHER_SYMBOLS: data.Symbols,
storedb.DATA_VOUCHER_BALANCES: data.Balances, storedb.DATA_VOUCHER_BALANCES: data.Balances,
@ -2017,9 +1981,11 @@ func (h *MenuHandlers) CheckVouchers(ctx context.Context, sym string, input []by
storedb.DATA_VOUCHER_ADDRESSES: data.Addresses, storedb.DATA_VOUCHER_ADDRESSES: data.Addresses,
} }
// Write data entries
for key, value := range dataMap { for key, value := range dataMap {
if err := h.prefixDb.Put(ctx, []byte(storedb.ToBytes(key)), []byte(value)); err != nil { if err := userStore.WriteEntry(ctx, sessionId, key, []byte(value)); err != nil {
return res, nil logg.ErrorCtxf(ctx, "Failed to write data entry for sessionId: %s", sessionId, "key", key, "error", err)
continue
} }
} }
@ -2029,16 +1995,25 @@ func (h *MenuHandlers) CheckVouchers(ctx context.Context, sym string, input []by
// GetVoucherList fetches the list of vouchers and formats them. // GetVoucherList fetches the list of vouchers and formats them.
func (h *MenuHandlers) GetVoucherList(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *MenuHandlers) GetVoucherList(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
userStore := h.userdataStore
// Read vouchers from the store // Read vouchers from the store
voucherData, err := h.prefixDb.Get(ctx, storedb.ToBytes(storedb.DATA_VOUCHER_SYMBOLS)) voucherData, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_VOUCHER_SYMBOLS)
logg.InfoCtxf(ctx, "reading GetVoucherList entries for sessionId: %s", sessionId, "key", storedb.DATA_VOUCHER_SYMBOLS, "voucherData", voucherData)
if err != nil { if err != nil {
logg.ErrorCtxf(ctx, "Failed to read the voucherData from prefixDb", "error", err) logg.ErrorCtxf(ctx, "failed to read voucherData entires with", "key", storedb.DATA_VOUCHER_SYMBOLS, "error", err)
return res, err return res, err
} }
formattedData := h.ReplaceSeparatorFunc(string(voucherData)) formattedData := h.ReplaceSeparatorFunc(string(voucherData))
logg.InfoCtxf(ctx, "final output for sessionId: %s", sessionId, "key", storedb.DATA_VOUCHER_SYMBOLS, "formattedData", formattedData)
res.Content = string(formattedData) res.Content = string(formattedData)
return res, nil return res, nil
@ -2065,7 +2040,7 @@ func (h *MenuHandlers) ViewVoucher(ctx context.Context, sym string, input []byte
return res, nil return res, nil
} }
metadata, err := store.GetVoucherData(ctx, h.prefixDb, inputStr) metadata, err := store.GetVoucherData(ctx, h.userdataStore, sessionId, inputStr)
if err != nil { if err != nil {
return res, fmt.Errorf("failed to retrieve voucher data: %v", err) return res, fmt.Errorf("failed to retrieve voucher data: %v", err)
} }
@ -2394,6 +2369,110 @@ func (h *MenuHandlers) constructAccountAlias(ctx context.Context) error {
return nil return nil
} }
// RequestCustomAlias requests an ENS based alias name based on a user's input,then saves it as temporary value
func (h *MenuHandlers) RequestCustomAlias(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
if string(input) == "0" {
return res, nil
}
store := h.userdataStore
aliasHint, err := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if err != nil {
if db.IsNotFound(err) {
return res, nil
}
return res, err
}
//Ensures that the call doesn't happen twice for the same alias hint
if !bytes.Equal(aliasHint, input) {
err = store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(string(input)))
if err != nil {
return res, err
}
pubKey, err := store.ReadEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY)
if err != nil {
if db.IsNotFound(err) {
return res, nil
}
}
sanitizedInput := sanitizeAliasHint(string(input))
aliasResult, err := h.accountService.RequestAlias(ctx, string(pubKey), sanitizedInput)
if err != nil {
logg.ErrorCtxf(ctx, "failed to retrieve alias", "alias", string(aliasHint), "error_alias_request", err)
return res, fmt.Errorf("Failed to retrieve alias: %s", err.Error())
}
alias := aliasResult.Alias
logg.InfoCtxf(ctx, "Suggested alias ", "alias", alias)
//Store the returned alias,wait for user to confirm it as new account alias
err = store.WriteEntry(ctx, sessionId, storedb.DATA_SUGGESTED_ALIAS, []byte(alias))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write account alias", "key", storedb.DATA_TEMPORARY_VALUE, "value", alias, "error", err)
return res, err
}
}
return res, nil
}
func sanitizeAliasHint(input string) string {
for i, r := range input {
// Check if the character is a special character (non-alphanumeric)
if !unicode.IsLetter(r) && !unicode.IsNumber(r) {
return input[:i]
}
}
// If no special character is found, return the whole input
return input
}
// GetSuggestedAlias loads and displays the suggested alias name from the temporary value
func (h *MenuHandlers) GetSuggestedAlias(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
store := h.userdataStore
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
suggestedAlias, err := store.ReadEntry(ctx, sessionId, storedb.DATA_SUGGESTED_ALIAS)
if err != nil {
return res, nil
}
res.Content = string(suggestedAlias)
return res, nil
}
// ConfirmNewAlias reads the suggested alias from the [DATA_SUGGECTED_ALIAS] key and confirms it as the new account alias.
func (h *MenuHandlers) ConfirmNewAlias(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
store := h.userdataStore
flag_alias_set, _ := h.flagManager.GetFlag("flag_alias_set")
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
newAlias, err := store.ReadEntry(ctx, sessionId, storedb.DATA_SUGGESTED_ALIAS)
if err != nil {
return res, nil
}
logg.InfoCtxf(ctx, "Confirming new alias", "alias", string(newAlias))
err = store.WriteEntry(ctx, sessionId, storedb.DATA_ACCOUNT_ALIAS, []byte(string(newAlias)))
if err != nil {
logg.ErrorCtxf(ctx, "failed to clear DATA_ACCOUNT_ALIAS_VALUE entry with", "key", storedb.DATA_ACCOUNT_ALIAS, "value", "empty", "error", err)
return res, err
}
res.FlagSet = append(res.FlagSet, flag_alias_set)
return res, nil
}
// ClearTemporaryValue empties the DATA_TEMPORARY_VALUE at the main menu to prevent // ClearTemporaryValue empties the DATA_TEMPORARY_VALUE at the main menu to prevent
// previously stored data from being accessed // previously stored data from being accessed
func (h *MenuHandlers) ClearTemporaryValue(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *MenuHandlers) ClearTemporaryValue(ctx context.Context, sym string, input []byte) (resource.Result, error) {

View File

@ -566,7 +566,7 @@ func TestSaveTemporaryPin(t *testing.T) {
log.Fatal(err) log.Fatal(err)
} }
flag_incorrect_pin, _ := fm.GetFlag("flag_incorrect_pin") flag_invalid_pin, _ := fm.GetFlag("flag_invalid_pin")
// Create the MenuHandlers instance with the mock flag manager // Create the MenuHandlers instance with the mock flag manager
h := &MenuHandlers{ h := &MenuHandlers{
@ -584,14 +584,14 @@ func TestSaveTemporaryPin(t *testing.T) {
name: "Valid Pin entry", name: "Valid Pin entry",
input: []byte("1234"), input: []byte("1234"),
expectedResult: resource.Result{ expectedResult: resource.Result{
FlagReset: []uint32{flag_incorrect_pin}, FlagReset: []uint32{flag_invalid_pin},
}, },
}, },
{ {
name: "Invalid Pin entry", name: "Invalid Pin entry",
input: []byte("12343"), input: []byte("12343"),
expectedResult: resource.Result{ expectedResult: resource.Result{
FlagSet: []uint32{flag_incorrect_pin}, FlagSet: []uint32{flag_invalid_pin},
}, },
}, },
} }
@ -1037,6 +1037,7 @@ func TestAuthorize(t *testing.T) {
flag_incorrect_pin, _ := fm.GetFlag("flag_incorrect_pin") flag_incorrect_pin, _ := fm.GetFlag("flag_incorrect_pin")
flag_account_authorized, _ := fm.GetFlag("flag_account_authorized") flag_account_authorized, _ := fm.GetFlag("flag_account_authorized")
flag_allow_update, _ := fm.GetFlag("flag_allow_update") flag_allow_update, _ := fm.GetFlag("flag_allow_update")
flag_invalid_pin, _ := fm.GetFlag("flag_invalid_pin")
// Set 1234 is the correct account pin // Set 1234 is the correct account pin
accountPIN := "1234" accountPIN := "1234"
@ -1072,7 +1073,9 @@ func TestAuthorize(t *testing.T) {
{ {
name: "Test with pin that is not a 4 digit", name: "Test with pin that is not a 4 digit",
input: []byte("1235aqds"), input: []byte("1235aqds"),
expectedResult: resource.Result{}, expectedResult: resource.Result{
FlagSet: []uint32{flag_invalid_pin},
},
}, },
} }
@ -1840,53 +1843,7 @@ func TestGetProfile(t *testing.T) {
} }
} }
func TestVerifyNewPin(t *testing.T) { func TestConfirmPinChange(t *testing.T) {
sessionId := "session123"
fm, _ := NewFlagManager(flagsPath)
mockState := state.NewState(16)
flag_valid_pin, _ := fm.GetFlag("flag_valid_pin")
mockAccountService := new(mocks.MockAccountService)
h := &MenuHandlers{
flagManager: fm,
accountService: mockAccountService,
st: mockState,
}
ctx := context.WithValue(context.Background(), "SessionId", sessionId)
tests := []struct {
name string
input []byte
expectedResult resource.Result
}{
{
name: "Test with valid pin",
input: []byte("1234"),
expectedResult: resource.Result{
FlagSet: []uint32{flag_valid_pin},
},
},
{
name: "Test with invalid pin",
input: []byte("123"),
expectedResult: resource.Result{
FlagReset: []uint32{flag_valid_pin},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
//Call the function under test
res, _ := h.VerifyNewPin(ctx, "verify_new_pin", tt.input)
//Assert that the result set to content is what was expected
assert.Equal(t, res, tt.expectedResult, "Result should contain flags set according to user input")
})
}
}
func TestConfirmPin(t *testing.T) {
sessionId := "session123" sessionId := "session123"
mockState := state.NewState(16) mockState := state.NewState(16)
@ -1895,6 +1852,8 @@ func TestConfirmPin(t *testing.T) {
fm, _ := NewFlagManager(flagsPath) fm, _ := NewFlagManager(flagsPath)
flag_pin_mismatch, _ := fm.GetFlag("flag_pin_mismatch") flag_pin_mismatch, _ := fm.GetFlag("flag_pin_mismatch")
flag_account_pin_reset, _ := fm.GetFlag("flag_account_pin_reset")
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
@ -1914,7 +1873,7 @@ func TestConfirmPin(t *testing.T) {
input: []byte("1234"), input: []byte("1234"),
temporarypin: "1234", temporarypin: "1234",
expectedResult: resource.Result{ expectedResult: resource.Result{
FlagReset: []uint32{flag_pin_mismatch}, FlagReset: []uint32{flag_pin_mismatch, flag_account_pin_reset},
}, },
}, },
} }
@ -1987,36 +1946,46 @@ func TestFetchCommunityBalance(t *testing.T) {
} }
} }
func TestSetDefaultVoucher(t *testing.T) { func TestManageVouchers(t *testing.T) {
sessionId := "session123" sessionId := "session123"
publicKey := "0X13242618721"
ctx, store := InitializeTestStore(t) ctx, store := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
fm, err := NewFlagManager(flagsPath) fm, err := NewFlagManager(flagsPath)
if err != nil { if err != nil {
t.Logf(err.Error()) t.Fatal(err)
} }
flag_no_active_voucher, err := fm.GetFlag("flag_no_active_voucher") flag_no_active_voucher, err := fm.GetFlag("flag_no_active_voucher")
if err != nil { if err != nil {
t.Logf(err.Error()) t.Fatal(err)
} }
publicKey := "0X13242618721" err = store.WriteEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY, []byte(publicKey))
if err != nil {
t.Fatal(err)
}
tests := []struct { tests := []struct {
name string name string
vouchersResp []dataserviceapi.TokenHoldings vouchersResp []dataserviceapi.TokenHoldings
storedActiveVoucher string
expectedVoucherSymbols []byte
expectedUpdatedAddress []byte
expectedResult resource.Result expectedResult resource.Result
}{ }{
{ {
name: "Test no vouchers available", name: "No vouchers available",
vouchersResp: []dataserviceapi.TokenHoldings{}, vouchersResp: []dataserviceapi.TokenHoldings{},
expectedVoucherSymbols: []byte(""),
expectedUpdatedAddress: []byte(""),
expectedResult: resource.Result{ expectedResult: resource.Result{
FlagSet: []uint32{flag_no_active_voucher}, FlagSet: []uint32{flag_no_active_voucher},
}, },
}, },
{ {
name: "Test set default voucher when no active voucher is set", name: "Set default voucher when no active voucher is set",
vouchersResp: []dataserviceapi.TokenHoldings{ vouchersResp: []dataserviceapi.TokenHoldings{
{ {
ContractAddress: "0x123", ContractAddress: "0x123",
@ -2025,7 +1994,24 @@ func TestSetDefaultVoucher(t *testing.T) {
Balance: "100", Balance: "100",
}, },
}, },
expectedResult: resource.Result{}, expectedVoucherSymbols: []byte("1:TOKEN1"),
expectedUpdatedAddress: []byte("0x123"),
expectedResult: resource.Result{
FlagReset: []uint32{flag_no_active_voucher},
},
},
{
name: "Check and update active voucher balance",
vouchersResp: []dataserviceapi.TokenHoldings{
{ContractAddress: "0xd4c288865Ce", TokenSymbol: "SRF", TokenDecimals: "6", Balance: "100"},
{ContractAddress: "0x41c188d63Qa", TokenSymbol: "MILO", TokenDecimals: "4", Balance: "200"},
},
storedActiveVoucher: "SRF",
expectedVoucherSymbols: []byte("1:SRF\n2:MILO"),
expectedUpdatedAddress: []byte("0xd4c288865Ce"),
expectedResult: resource.Result{
FlagReset: []uint32{flag_no_active_voucher},
},
}, },
} }
@ -2039,51 +2025,11 @@ func TestSetDefaultVoucher(t *testing.T) {
flagManager: fm, flagManager: fm,
} }
err := store.WriteEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY, []byte(publicKey))
if err != nil {
t.Fatal(err)
}
mockAccountService.On("FetchVouchers", string(publicKey)).Return(tt.vouchersResp, nil) mockAccountService.On("FetchVouchers", string(publicKey)).Return(tt.vouchersResp, nil)
res, err := h.SetDefaultVoucher(ctx, "set_default_voucher", []byte("some-input")) // Store active voucher if needed
if tt.storedActiveVoucher != "" {
assert.NoError(t, err) err := store.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM, []byte(tt.storedActiveVoucher))
assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result")
mockAccountService.AssertExpectations(t)
})
}
}
func TestCheckVouchers(t *testing.T) {
mockAccountService := new(mocks.MockAccountService)
sessionId := "session123"
publicKey := "0X13242618721"
ctx, store := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId)
spdb := InitializeTestSubPrefixDb(t, ctx)
h := &MenuHandlers{
userdataStore: store,
accountService: mockAccountService,
prefixDb: spdb,
}
err := store.WriteEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY, []byte(publicKey))
if err != nil {
t.Fatal(err)
}
mockVouchersResponse := []dataserviceapi.TokenHoldings{
{ContractAddress: "0xd4c288865Ce", TokenSymbol: "SRF", TokenDecimals: "6", Balance: "100"},
{ContractAddress: "0x41c188d63Qa", TokenSymbol: "MILO", TokenDecimals: "4", Balance: "200"},
}
// store the default voucher data
err = store.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM, []byte("SRF"))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -2091,52 +2037,45 @@ func TestCheckVouchers(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
}
expectedSym := []byte("1:SRF\n2:MILO") res, err := h.ManageVouchers(ctx, "manage_vouchers", []byte(""))
expectedUpdatedAddress := []byte("0xd4c288865Ce")
mockAccountService.On("FetchVouchers", string(publicKey)).Return(mockVouchersResponse, nil)
_, err = h.CheckVouchers(ctx, "check_vouchers", []byte(""))
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, tt.expectedResult, res)
// Read voucher sym data from the store if tt.storedActiveVoucher != "" {
voucherData, err := spdb.Get(ctx, storedb.ToBytes(storedb.DATA_VOUCHER_SYMBOLS)) // Validate stored voucher symbols
if err != nil { voucherData, err := store.ReadEntry(ctx, sessionId, storedb.DATA_VOUCHER_SYMBOLS)
t.Fatal(err) assert.NoError(t, err)
} assert.Equal(t, tt.expectedVoucherSymbols, voucherData)
// Read active contract address from the store // Validate stored active contract address
updatedAddress, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_ADDRESS) updatedAddress, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_ADDRESS)
if err != nil { assert.NoError(t, err)
t.Fatal(err) assert.Equal(t, tt.expectedUpdatedAddress, updatedAddress)
}
// assert that the data is stored correctly
assert.Equal(t, expectedSym, voucherData)
// assert that the address is updated
assert.Equal(t, expectedUpdatedAddress, updatedAddress)
mockAccountService.AssertExpectations(t) mockAccountService.AssertExpectations(t)
}
})
}
} }
func TestGetVoucherList(t *testing.T) { func TestGetVoucherList(t *testing.T) {
sessionId := "session123" sessionId := "session123"
ctx := context.WithValue(context.Background(), "SessionId", sessionId) ctx, store := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId)
spdb := InitializeTestSubPrefixDb(t, ctx)
// Initialize MenuHandlers // Initialize MenuHandlers
h := &MenuHandlers{ h := &MenuHandlers{
prefixDb: spdb, userdataStore: store,
ReplaceSeparatorFunc: mockReplaceSeparator, ReplaceSeparatorFunc: mockReplaceSeparator,
} }
mockSyms := []byte("1:SRF\n2:MILO") mockSyms := []byte("1:SRF\n2:MILO")
// Put voucher sym data from the store // Put voucher sym data from the store
err := spdb.Put(ctx, storedb.ToBytes(storedb.DATA_VOUCHER_SYMBOLS), mockSyms) err := store.WriteEntry(ctx, sessionId, storedb.DATA_VOUCHER_SYMBOLS, mockSyms)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -2156,15 +2095,11 @@ func TestViewVoucher(t *testing.T) {
} }
ctx, store := InitializeTestStore(t) ctx, store := InitializeTestStore(t)
sessionId := "session123" sessionId := "session123"
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
spdb := InitializeTestSubPrefixDb(t, ctx)
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
flagManager: fm, flagManager: fm,
prefixDb: spdb,
} }
// Define mock voucher data // Define mock voucher data
@ -2177,7 +2112,7 @@ func TestViewVoucher(t *testing.T) {
// Put the data // Put the data
for key, value := range mockData { for key, value := range mockData {
err = spdb.Put(ctx, []byte(storedb.ToBytes(key)), []byte(value)) err := store.WriteEntry(ctx, sessionId, key, []byte(value))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -2357,10 +2292,8 @@ func TestCheckBlockedStatus(t *testing.T) {
if err != nil { if err != nil {
t.Logf(err.Error()) t.Logf(err.Error())
} }
flag_account_blocked, err := fm.GetFlag("flag_account_blocked") flag_account_blocked, _ := fm.GetFlag("flag_account_blocked")
if err != nil { flag_account_pin_reset, _ := fm.GetFlag("flag_account_pin_reset")
t.Logf(err.Error())
}
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
@ -2375,13 +2308,15 @@ func TestCheckBlockedStatus(t *testing.T) {
{ {
name: "Currently blocked account", name: "Currently blocked account",
currentWrongPinAttempts: "4", currentWrongPinAttempts: "4",
expectedResult: resource.Result{}, expectedResult: resource.Result{
FlagReset: []uint32{flag_account_pin_reset},
},
}, },
{ {
name: "Account with 0 wrong PIN attempts", name: "Account with 0 wrong PIN attempts",
currentWrongPinAttempts: "0", currentWrongPinAttempts: "0",
expectedResult: resource.Result{ expectedResult: resource.Result{
FlagReset: []uint32{flag_account_blocked}, FlagReset: []uint32{flag_account_pin_reset, flag_account_blocked},
}, },
}, },
} }
@ -2910,173 +2845,6 @@ func TestValidateBlockedNumber(t *testing.T) {
} }
} }
func TestSaveOthersTemporaryPin(t *testing.T) {
sessionId := "session123"
blockedNumber := "+254712345678"
testPin := "1234"
ctx, userStore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId)
h := &MenuHandlers{
userdataStore: userStore,
}
tests := []struct {
name string
sessionId string
blockedNumber string
testPin string
setup func() error // Setup function for each test case
expectedError bool
verifyResult func(t *testing.T) // Function to verify the result
}{
{
name: "Missing Session ID",
sessionId: "", // Empty session ID
blockedNumber: blockedNumber,
testPin: testPin,
setup: nil,
expectedError: true,
verifyResult: nil,
},
{
name: "Failed to Read Blocked Number",
sessionId: sessionId,
blockedNumber: blockedNumber,
testPin: testPin,
setup: func() error {
// Do not write the blocked number to simulate a read failure
return nil
},
expectedError: true,
verifyResult: nil,
},
{
name: "Successfully save hashed PIN",
sessionId: sessionId,
blockedNumber: blockedNumber,
testPin: testPin,
setup: func() error {
// Write the blocked number to the store
return userStore.WriteEntry(ctx, sessionId, storedb.DATA_BLOCKED_NUMBER, []byte(blockedNumber))
},
expectedError: false,
verifyResult: func(t *testing.T) {
// Read the stored hashed PIN
othersHashedPin, err := userStore.ReadEntry(ctx, blockedNumber, storedb.DATA_TEMPORARY_VALUE)
if err != nil {
t.Fatal(err)
}
// Verify that the stored hashed PIN matches the original PIN
if !pin.VerifyPIN(string(othersHashedPin), testPin) {
t.Fatal("stored hashed PIN does not match the original PIN")
}
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Set up the context with the session ID
ctx := context.WithValue(context.Background(), "SessionId", tt.sessionId)
// Run the setup function if provided
if tt.setup != nil {
err := tt.setup()
if err != nil {
t.Fatal(err)
}
}
// Call the function under test
_, err := h.SaveOthersTemporaryPin(ctx, "save_others_temporary_pin", []byte(tt.testPin))
// Assert the error
if tt.expectedError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
// Verify the result if a verification function is provided
if tt.verifyResult != nil {
tt.verifyResult(t)
}
})
}
}
func TestCheckBlockedNumPinMisMatch(t *testing.T) {
sessionId := "session123"
blockedNumber := "+254712345678"
testPin := "1234"
mockState := state.NewState(128)
ctx, userStore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId)
hashedPIN, err := pin.HashPIN(testPin)
if err != nil {
logg.ErrorCtxf(ctx, "failed to hash testPin", "error", err)
t.Fatal(err)
}
fm, err := NewFlagManager(flagsPath)
if err != nil {
t.Fatal(err)
}
flag_pin_mismatch, _ := fm.GetFlag("flag_pin_mismatch")
h := &MenuHandlers{
userdataStore: userStore,
st: mockState,
flagManager: fm,
}
// Write initial data to the store
err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_BLOCKED_NUMBER, []byte(blockedNumber))
if err != nil {
t.Fatal(err)
}
err = userStore.WriteEntry(ctx, blockedNumber, storedb.DATA_TEMPORARY_VALUE, []byte(hashedPIN))
if err != nil {
t.Fatal(err)
}
tests := []struct {
name string
input []byte
expectedResult resource.Result
}{
{
name: "Successful PIN match",
input: []byte(testPin),
expectedResult: resource.Result{
FlagReset: []uint32{flag_pin_mismatch},
},
},
{
name: "PIN mismatch",
input: []byte("1345"),
expectedResult: resource.Result{
FlagSet: []uint32{flag_pin_mismatch},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
res, err := h.CheckBlockedNumPinMisMatch(ctx, "sym", tt.input)
assert.NoError(t, err)
assert.Equal(t, tt.expectedResult, res)
})
}
}
func TestGetCurrentProfileInfo(t *testing.T) { func TestGetCurrentProfileInfo(t *testing.T) {
sessionId := "session123" sessionId := "session123"
ctx, store := InitializeTestStore(t) ctx, store := InitializeTestStore(t)
@ -3233,30 +3001,6 @@ func TestResetOthersPin(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
} }
func TestResetValidPin(t *testing.T) {
ctx := context.Background()
fm, err := NewFlagManager(flagsPath)
if err != nil {
t.Fatal(err)
}
flag_valid_pin, _ := fm.GetFlag("flag_valid_pin")
expectedResult := resource.Result{
FlagReset: []uint32{flag_valid_pin},
}
h := &MenuHandlers{
flagManager: fm,
}
res, err := h.ResetValidPin(ctx, "reset_valid_pin", []byte(""))
assert.NoError(t, err)
assert.Equal(t, expectedResult, res)
}
func TestResetUnregisteredNumber(t *testing.T) { func TestResetUnregisteredNumber(t *testing.T) {
ctx := context.Background() ctx := context.Background()
@ -3473,15 +3217,6 @@ func TestUpdateAllProfileItems(t *testing.T) {
err = store.WriteEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY, []byte(publicKey)) err = store.WriteEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY, []byte(publicKey))
require.NoError(t, err) require.NoError(t, err)
aliasInput := fmt.Sprintf("%s%s", profileItems[0], profileItems[1])
// Mock the account alias response
mockAccountService.On(
"RequestAlias",
publicKey,
aliasInput,
).Return(&models.RequestAliasResult{Alias: "JohnDoe"}, nil)
// Call the function under test // Call the function under test
res, err := h.UpdateAllProfileItems(ctx, "symbol", nil) res, err := h.UpdateAllProfileItems(ctx, "symbol", nil)
assert.NoError(t, err) assert.NoError(t, err)
@ -3493,10 +3228,6 @@ func TestUpdateAllProfileItems(t *testing.T) {
assert.Equal(t, profileItems[i], string(storedValue)) assert.Equal(t, profileItems[i], string(storedValue))
} }
// Validate alias storage
storedAlias, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACCOUNT_ALIAS)
assert.NoError(t, err)
assert.Equal(t, "JohnDoe", string(storedAlias))
assert.Equal(t, expectedResult, res) assert.Equal(t, expectedResult, res)
} }

View File

@ -49,9 +49,8 @@ func (eu *EventsUpdater) updateToken(ctx context.Context, identity identity.Iden
// set default token to given symbol. // set default token to given symbol.
func (eu *EventsUpdater) updateDefaultToken(ctx context.Context, identity identity.Identity, userStore *store.UserDataStore, activeSym string) error { func (eu *EventsUpdater) updateDefaultToken(ctx context.Context, identity identity.Identity, userStore *store.UserDataStore, activeSym string) error {
pfxDb := toPrefixDb(userStore, identity.SessionId)
// TODO: the activeSym input should instead be newline separated list? // TODO: the activeSym input should instead be newline separated list?
tokenData, err := store.GetVoucherData(ctx, pfxDb, activeSym) tokenData, err := store.GetVoucherData(ctx, userStore, identity.SessionId, activeSym)
if err != nil { if err != nil {
return err return err
} }

View File

@ -99,23 +99,18 @@ func (ls *LocalHandlerService) GetHandler(accountService remote.AccountService)
ls.DbRs.AddLocalFunc("verify_yob", appHandlers.VerifyYob) ls.DbRs.AddLocalFunc("verify_yob", appHandlers.VerifyYob)
ls.DbRs.AddLocalFunc("reset_incorrect_date_format", appHandlers.ResetIncorrectYob) ls.DbRs.AddLocalFunc("reset_incorrect_date_format", appHandlers.ResetIncorrectYob)
ls.DbRs.AddLocalFunc("initiate_transaction", appHandlers.InitiateTransaction) ls.DbRs.AddLocalFunc("initiate_transaction", appHandlers.InitiateTransaction)
ls.DbRs.AddLocalFunc("verify_new_pin", appHandlers.VerifyNewPin)
ls.DbRs.AddLocalFunc("confirm_pin_change", appHandlers.ConfirmPinChange) ls.DbRs.AddLocalFunc("confirm_pin_change", appHandlers.ConfirmPinChange)
ls.DbRs.AddLocalFunc("quit_with_help", appHandlers.QuitWithHelp) ls.DbRs.AddLocalFunc("quit_with_help", appHandlers.QuitWithHelp)
ls.DbRs.AddLocalFunc("fetch_community_balance", appHandlers.FetchCommunityBalance) ls.DbRs.AddLocalFunc("fetch_community_balance", appHandlers.FetchCommunityBalance)
ls.DbRs.AddLocalFunc("set_default_voucher", appHandlers.SetDefaultVoucher) ls.DbRs.AddLocalFunc("manage_vouchers", appHandlers.ManageVouchers)
ls.DbRs.AddLocalFunc("check_vouchers", appHandlers.CheckVouchers)
ls.DbRs.AddLocalFunc("get_vouchers", appHandlers.GetVoucherList) ls.DbRs.AddLocalFunc("get_vouchers", appHandlers.GetVoucherList)
ls.DbRs.AddLocalFunc("view_voucher", appHandlers.ViewVoucher) ls.DbRs.AddLocalFunc("view_voucher", appHandlers.ViewVoucher)
ls.DbRs.AddLocalFunc("set_voucher", appHandlers.SetVoucher) ls.DbRs.AddLocalFunc("set_voucher", appHandlers.SetVoucher)
ls.DbRs.AddLocalFunc("get_voucher_details", appHandlers.GetVoucherDetails) ls.DbRs.AddLocalFunc("get_voucher_details", appHandlers.GetVoucherDetails)
ls.DbRs.AddLocalFunc("reset_valid_pin", appHandlers.ResetValidPin)
ls.DbRs.AddLocalFunc("check_pin_mismatch", appHandlers.CheckBlockedNumPinMisMatch)
ls.DbRs.AddLocalFunc("validate_blocked_number", appHandlers.ValidateBlockedNumber) ls.DbRs.AddLocalFunc("validate_blocked_number", appHandlers.ValidateBlockedNumber)
ls.DbRs.AddLocalFunc("retrieve_blocked_number", appHandlers.RetrieveBlockedNumber) ls.DbRs.AddLocalFunc("retrieve_blocked_number", appHandlers.RetrieveBlockedNumber)
ls.DbRs.AddLocalFunc("reset_unregistered_number", appHandlers.ResetUnregisteredNumber) ls.DbRs.AddLocalFunc("reset_unregistered_number", appHandlers.ResetUnregisteredNumber)
ls.DbRs.AddLocalFunc("reset_others_pin", appHandlers.ResetOthersPin) ls.DbRs.AddLocalFunc("reset_others_pin", appHandlers.ResetOthersPin)
ls.DbRs.AddLocalFunc("save_others_temporary_pin", appHandlers.SaveOthersTemporaryPin)
ls.DbRs.AddLocalFunc("get_current_profile_info", appHandlers.GetCurrentProfileInfo) ls.DbRs.AddLocalFunc("get_current_profile_info", appHandlers.GetCurrentProfileInfo)
ls.DbRs.AddLocalFunc("check_transactions", appHandlers.CheckTransactions) ls.DbRs.AddLocalFunc("check_transactions", appHandlers.CheckTransactions)
ls.DbRs.AddLocalFunc("get_transactions", appHandlers.GetTransactionsList) ls.DbRs.AddLocalFunc("get_transactions", appHandlers.GetTransactionsList)
@ -124,6 +119,12 @@ func (ls *LocalHandlerService) GetHandler(accountService remote.AccountService)
ls.DbRs.AddLocalFunc("set_back", appHandlers.SetBack) ls.DbRs.AddLocalFunc("set_back", appHandlers.SetBack)
ls.DbRs.AddLocalFunc("show_blocked_account", appHandlers.ShowBlockedAccount) ls.DbRs.AddLocalFunc("show_blocked_account", appHandlers.ShowBlockedAccount)
ls.DbRs.AddLocalFunc("clear_temporary_value", appHandlers.ClearTemporaryValue) ls.DbRs.AddLocalFunc("clear_temporary_value", appHandlers.ClearTemporaryValue)
ls.DbRs.AddLocalFunc("reset_invalid_pin", appHandlers.ResetInvalidPIN)
ls.DbRs.AddLocalFunc("request_custom_alias", appHandlers.RequestCustomAlias)
ls.DbRs.AddLocalFunc("get_suggested_alias", appHandlers.GetSuggestedAlias)
ls.DbRs.AddLocalFunc("confirm_new_alias", appHandlers.ConfirmNewAlias)
ls.DbRs.AddLocalFunc("check_account_created", appHandlers.CheckAccountCreated)
ls.first = appHandlers.Init ls.first = appHandlers.Init
return appHandlers, nil return appHandlers, nil

View File

@ -71,7 +71,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "5", "input": "5",
@ -108,11 +108,11 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "", "input": "",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "2", "input": "2",
@ -149,7 +149,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "5", "input": "5",
@ -173,7 +173,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "0", "input": "0",
@ -190,7 +190,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "5", "input": "5",
@ -202,23 +202,7 @@
}, },
{ {
"input": "0700000000", "input": "0700000000",
"expectedContent": "Please enter new PIN for: {secondary_session_id}\n0:Back" "expectedContent": "{secondary_session_id} will get a PIN reset request.\nPlease enter your PIN to confirm:\n0:Back\n9:Quit"
},
{
"input": "11111",
"expectedContent": "The PIN you have entered is invalid.Please try a 4 digit number instead.\n1:Retry\n9:Quit"
},
{
"input": "1",
"expectedContent": "Please enter new PIN for: {secondary_session_id}\n0:Back"
},
{
"input": "1111",
"expectedContent": "Please confirm new PIN for: {secondary_session_id}\n0:Back"
},
{
"input": "1111",
"expectedContent": "Please enter your PIN:"
}, },
{ {
"input": "1234", "input": "1234",
@ -239,7 +223,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "5", "input": "5",
@ -264,7 +248,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "3", "input": "3",
@ -284,7 +268,7 @@
}, },
{ {
"input": "1234", "input": "1234",
"expectedContent": "Balance: {balance}\n\n0:Back\n9:Quit" "expectedContent": "{balance}\n\n0:Back\n9:Quit"
}, },
{ {
"input": "0", "input": "0",
@ -292,7 +276,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "0", "input": "0",
@ -309,7 +293,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "3", "input": "3",
@ -337,7 +321,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "0", "input": "0",
@ -354,7 +338,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "1", "input": "1",
@ -411,7 +395,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "1", "input": "1",
@ -448,7 +432,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "1", "input": "1",
@ -489,7 +473,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "1", "input": "1",
@ -526,7 +510,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "1", "input": "1",
@ -563,7 +547,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "1", "input": "1",
@ -600,7 +584,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "1", "input": "1",
@ -612,7 +596,7 @@
}, },
{ {
"input": "1234", "input": "1234",
"expectedContent": "My profile:\nName: foo bar\nGender: male\nAge: 80\nLocation: Kilifi\nYou provide: Bananas\nYour alias: \n\n0:Back\n9:Quit" "expectedContent": "My profile:\nName: foo bar\nGender: male\nAge: 80\nLocation: Kilifi\nYou provide: Bananas\nYour alias: Not Provided\n\n0:Back\n9:Quit"
}, },
{ {
"input": "0", "input": "0",
@ -633,7 +617,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "1", "input": "1",

View File

@ -9,7 +9,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "1", "input": "1",

View File

@ -9,7 +9,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "1", "input": "1",

View File

@ -9,7 +9,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "1", "input": "1",

View File

@ -9,7 +9,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "1", "input": "1",

View File

@ -9,7 +9,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "1", "input": "1",

View File

@ -9,7 +9,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "1", "input": "1",

View File

@ -9,7 +9,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "1", "input": "1",

View File

@ -116,7 +116,7 @@
}, },
{ {
"input": "3", "input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
"input": "6", "input": "6",

View File

@ -1,5 +1,5 @@
LOAD reset_transaction_amount 0 LOAD reset_transaction_amount 0
LOAD max_amount 10 LOAD max_amount 40
RELOAD max_amount RELOAD max_amount
MAP max_amount MAP max_amount
MOUT back 0 MOUT back 0

View File

@ -0,0 +1,2 @@
{{.retrieve_blocked_number}} will get a PIN reset request.
Please enter your PIN to confirm:

View File

@ -0,0 +1,12 @@
LOAD retrieve_blocked_number 0
RELOAD retrieve_blocked_number
MAP retrieve_blocked_number
MOUT back 0
MOUT quit 9
LOAD authorize_account 6
HALT
RELOAD authorize_account
CATCH incorrect_pin flag_incorrect_pin 1
INCMP _ 0
INCMP quit 9
INCMP pin_reset_result *

View File

@ -0,0 +1,2 @@
{{.retrieve_blocked_number}} atapokea ombi la kuweka upya PIN.
Tafadhali weka PIN yako kudhibitisha:

View File

@ -1,4 +1,7 @@
LOAD save_temporary_pin 6 MOUT back 0
HALT HALT
INCMP _ 0
LOAD verify_create_pin 8 LOAD verify_create_pin 8
RELOAD verify_create_pin
CATCH pin_mismatch flag_pin_mismatch 1
INCMP account_creation * INCMP account_creation *

View File

@ -0,0 +1,2 @@
Your full alias will be: {{.get_suggested_alias}}
Please enter your PIN to confirm:

View File

@ -0,0 +1,12 @@
LOAD reset_invalid_pin 6
RELOAD reset_invalid_pin
LOAD get_suggested_alias 0
RELOAD get_suggested_alias
MAP get_suggested_alias
MOUT back 0
HALT
INCMP _ 0
RELOAD authorize_account
CATCH incorrect_pin flag_incorrect_pin 1
CATCH invalid_pin flag_invalid_pin 1
CATCH update_alias flag_allow_update 1

View File

@ -0,0 +1,2 @@
Lakabu yako kamili itakuwa: {{.get_suggested_alias}}
Tafadhali weka PIN yako ili kuthibitisha:

View File

@ -1 +0,0 @@
Please confirm new PIN for: {{.retrieve_blocked_number}}

View File

@ -1,14 +0,0 @@
CATCH incorrect_pin flag_incorrect_pin 1
RELOAD retrieve_blocked_number
MAP retrieve_blocked_number
CATCH invalid_others_pin flag_valid_pin 0
CATCH pin_reset_result flag_account_authorized 1
LOAD save_others_temporary_pin 6
RELOAD save_others_temporary_pin
MOUT back 0
HALT
INCMP _ 0
LOAD check_pin_mismatch 6
RELOAD check_pin_mismatch
CATCH others_pin_mismatch flag_pin_mismatch 1
INCMP pin_entry *

View File

@ -1 +0,0 @@
Tafadhali thibitisha PIN mpya ya: {{.retrieve_blocked_number}}

View File

@ -1,7 +1,7 @@
LOAD confirm_pin_change 0
MOUT back 0 MOUT back 0
HALT HALT
INCMP _ 0 INCMP _ 0
LOAD confirm_pin_change 0
RELOAD confirm_pin_change RELOAD confirm_pin_change
CATCH pin_reset_mismatch flag_pin_mismatch 1 CATCH pin_mismatch flag_pin_mismatch 1
INCMP * pin_reset_success INCMP pin_reset_success *

View File

@ -2,8 +2,8 @@ LOAD create_account 0
CATCH account_creation_failed flag_account_creation_failed 1 CATCH account_creation_failed flag_account_creation_failed 1
MOUT exit 0 MOUT exit 0
HALT HALT
INCMP quit 0
LOAD save_temporary_pin 6 LOAD save_temporary_pin 6
RELOAD save_temporary_pin RELOAD save_temporary_pin
CATCH . flag_incorrect_pin 1 CATCH invalid_pin flag_invalid_pin 1
INCMP quit 0
INCMP confirm_create_pin * INCMP confirm_create_pin *

View File

@ -1,5 +0,0 @@
MOUT retry 1
MOUT quit 9
HALT
INCMP confirm_create_pin 1
INCMP quit 9

View File

@ -7,4 +7,4 @@ INCMP _ 0
LOAD validate_blocked_number 6 LOAD validate_blocked_number 6
RELOAD validate_blocked_number RELOAD validate_blocked_number
CATCH unregistered_number flag_unregistered_number 1 CATCH unregistered_number flag_unregistered_number 1
INCMP enter_others_new_pin * INCMP authorize_reset_others_pin *

View File

@ -1 +0,0 @@
Please enter new PIN for: {{.retrieve_blocked_number}}

View File

@ -1,9 +0,0 @@
LOAD retrieve_blocked_number 0
RELOAD retrieve_blocked_number
MAP retrieve_blocked_number
MOUT back 0
HALT
LOAD verify_new_pin 6
RELOAD verify_new_pin
INCMP _ 0
INCMP * confirm_others_new_pin

View File

@ -1 +0,0 @@
Tafadhali weka PIN mpya ya: {{.retrieve_blocked_number}}

View File

@ -1 +0,0 @@
The PIN you have entered is invalid.Please try a 4 digit number instead.

View File

@ -1,5 +0,0 @@
MOUT retry 1
MOUT quit 9
HALT
INCMP enter_others_new_pin 1
INCMP quit 9

View File

@ -1 +1 @@
The PIN you entered is invalid.The PIN must be different from your current PIN.For help call +254757628885 The PIN you entered is invalid. The PIN must be a 4 digit number.

View File

@ -1,3 +1,8 @@
MOUT back 0 LOAD reset_invalid_pin 6
RELOAD reset_invalid_pin
MOUT retry 1
MOUT quit 9
HALT HALT
INCMP _ 0 INCMP _ 1
INCMP quit 9
INCMP . *

View File

@ -1 +1 @@
PIN mpya na udhibitisho wa PIN mpya hazilingani.Tafadhali jaribu tena.Kwa usaidizi piga simu +254757628885. PIN uliyoweka si sahihi. PIN lazima iwe nambari 4.

View File

@ -30,3 +30,7 @@ msgstr "Salio la Kikundi: 0.00"
msgid "Symbol: %s\nBalance: %s" msgid "Symbol: %s\nBalance: %s"
msgstr "Sarafu: %s\nSalio: %s" msgstr "Sarafu: %s\nSalio: %s"
msgid "%s balance: %s\n"
msgstr "%s salio: %s\n"

View File

@ -1,9 +1,7 @@
LOAD clear_temporary_value 2 LOAD clear_temporary_value 2
RELOAD clear_temporary_value RELOAD clear_temporary_value
LOAD set_default_voucher 8 LOAD manage_vouchers 160
RELOAD set_default_voucher RELOAD manage_vouchers
LOAD check_vouchers 10
RELOAD check_vouchers
LOAD check_balance 128 LOAD check_balance 128
RELOAD check_balance RELOAD check_balance
CATCH api_failure flag_api_call_error 1 CATCH api_failure flag_api_call_error 1

View File

@ -1,3 +1,4 @@
LOAD authorize_account 16
LOAD reset_allow_update 0 LOAD reset_allow_update 0
MOUT profile 1 MOUT profile 1
MOUT change_language 2 MOUT change_language 2
@ -5,13 +6,15 @@ MOUT check_balance 3
MOUT check_statement 4 MOUT check_statement 4
MOUT pin_options 5 MOUT pin_options 5
MOUT my_address 6 MOUT my_address 6
MOUT my_account_alias 7
MOUT back 0 MOUT back 0
HALT HALT
INCMP main 0 INCMP ^ 0
INCMP edit_profile 1 INCMP edit_profile 1
INCMP change_language 2 INCMP change_language 2
INCMP balances 3 INCMP balances 3
INCMP check_statement 4 INCMP check_statement 4
INCMP pin_management 5 INCMP pin_management 5
INCMP address 6 INCMP address 6
INCMP my_account_alias 7
INCMP . * INCMP . *

View File

@ -0,0 +1,2 @@
Current alias: {{.get_current_profile_info}}
Enter your preferred alias:

View File

@ -0,0 +1,8 @@
LOAD get_current_profile_info 0
MAP get_current_profile_info
MOUT back 0
HALT
INCMP _ 0
LOAD request_custom_alias 0
RELOAD request_custom_alias
INCMP confirm_new_alias *

View File

@ -0,0 +1 @@
My Alias

View File

@ -0,0 +1 @@
Lakabu yangu

View File

@ -0,0 +1,2 @@
Lakabu ya sasa: {{.get_current_profile_info}}
Weka lakabu unalopendelea:

View File

@ -2,6 +2,5 @@ MOUT back 0
HALT HALT
INCMP _ 0 INCMP _ 0
RELOAD save_temporary_pin RELOAD save_temporary_pin
RELOAD verify_new_pin CATCH invalid_pin flag_invalid_pin 1
CATCH invalid_pin flag_valid_pin 0 INCMP confirm_pin_change *
INCMP * confirm_pin_change

View File

@ -1,8 +1,8 @@
RELOAD reset_allow_update RELOAD reset_incorrect
MOUT back 0 MOUT back 0
HALT HALT
INCMP _ 0 INCMP _ 0
RELOAD authorize_account RELOAD authorize_account
CATCH incorrect_pin flag_incorrect_pin 1 CATCH incorrect_pin flag_incorrect_pin 1
CATCH _ flag_allow_update 0 CATCH invalid_pin flag_invalid_pin 1
INCMP new_pin * INCMP new_pin *

View File

@ -1 +0,0 @@
The PIN you have entered is not a match

View File

@ -1 +0,0 @@
PIN uliyoweka hailingani.Jaribu tena.

View File

@ -1,9 +1,9 @@
LOAD set_back 6 LOAD set_back 6
LOAD authorize_account 5 LOAD authorize_account 16
LOAD reset_allow_update 4 LOAD reset_allow_update 4
LOAD verify_new_pin 2
LOAD save_temporary_pin 1 LOAD save_temporary_pin 1
LOAD reset_incorrect 0 LOAD reset_incorrect 0
LOAD reset_invalid_pin 6
MOUT change_pin 1 MOUT change_pin 1
MOUT reset_pin 2 MOUT reset_pin 2
MOUT back 0 MOUT back 0

View File

@ -1 +0,0 @@
The PIN is not a match. Try again

View File

@ -1,6 +0,0 @@
MOUT retry 1
MOUT quit 9
HALT
INCMP _ 1
INCMP quit 9
INCMP . *

View File

@ -1 +0,0 @@
PIN uliyoweka hailingani.Jaribu tena.

View File

@ -1,3 +1,4 @@
CATCH _ flag_account_authorized 0
LOAD retrieve_blocked_number 0 LOAD retrieve_blocked_number 0
MAP retrieve_blocked_number MAP retrieve_blocked_number
LOAD reset_others_pin 6 LOAD reset_others_pin 6

View File

@ -1,6 +1,6 @@
MOUT back 0 MOUT back 0
MOUT quit 9 MOUT quit 9
HALT HALT
INCMP main 0 INCMP ^ 0
INCMP quit 9 INCMP quit 9
INCMP . * INCMP . *

View File

@ -9,7 +9,7 @@ flag,flag_account_authorized,15,this is set to allow a user access guarded nodes
flag,flag_invalid_recipient,16,this is set when the transaction recipient is invalid flag,flag_invalid_recipient,16,this is set when the transaction recipient is invalid
flag,flag_invalid_recipient_with_invite,17,this is set when the transaction recipient is valid but not on the platform flag,flag_invalid_recipient_with_invite,17,this is set when the transaction recipient is valid but not on the platform
flag,flag_invalid_amount,18,this is set when the given transaction amount is invalid flag,flag_invalid_amount,18,this is set when the given transaction amount is invalid
flag,flag_incorrect_pin,19,this is set when the provided PIN is invalid or does not match the current account's PIN flag,flag_incorrect_pin,19,this is set when the provided PIN does not match the current account's PIN
flag,flag_valid_pin,20,this is set when the given PIN is valid flag,flag_valid_pin,20,this is set when the given PIN is valid
flag,flag_allow_update,21,this is set to allow a user to update their profile data flag,flag_allow_update,21,this is set to allow a user to update their profile data
flag,flag_single_edit,22,this is set to allow a user to edit a single profile item such as year of birth flag,flag_single_edit,22,this is set to allow a user to edit a single profile item such as year of birth
@ -29,4 +29,6 @@ flag,flag_location_set,35,this is set when the location of the profile is set
flag,flag_offerings_set,36,this is set when the offerings of the profile is set flag,flag_offerings_set,36,this is set when the offerings of the profile is set
flag,flag_back_set,37,this is set when it is a back navigation flag,flag_back_set,37,this is set when it is a back navigation
flag,flag_account_blocked,38,this is set when an account has been blocked after the allowed incorrect PIN attempts have been exceeded flag,flag_account_blocked,38,this is set when an account has been blocked after the allowed incorrect PIN attempts have been exceeded
flag,flag_invalid_pin,39,this is set when the given PIN is invalid(is less than or more than 4 digits)
flag,flag_alias_set,40,this is set when an account alias has been assigned to a user
flag,flag_account_pin_reset,41,this is set on an account when an admin triggers a PIN reset for them

1 flag flag_language_set 8 checks whether the user has set their prefered language
9 flag flag_invalid_recipient 16 this is set when the transaction recipient is invalid
10 flag flag_invalid_recipient_with_invite 17 this is set when the transaction recipient is valid but not on the platform
11 flag flag_invalid_amount 18 this is set when the given transaction amount is invalid
12 flag flag_incorrect_pin 19 this is set when the provided PIN is invalid or does not match the current account's PIN this is set when the provided PIN does not match the current account's PIN
13 flag flag_valid_pin 20 this is set when the given PIN is valid
14 flag flag_allow_update 21 this is set to allow a user to update their profile data
15 flag flag_single_edit 22 this is set to allow a user to edit a single profile item such as year of birth
29 flag flag_offerings_set 36 this is set when the offerings of the profile is set
30 flag flag_back_set 37 this is set when it is a back navigation
31 flag flag_account_blocked 38 this is set when an account has been blocked after the allowed incorrect PIN attempts have been exceeded
32 flag flag_invalid_pin 39 this is set when the given PIN is invalid(is less than or more than 4 digits)
33 flag flag_alias_set 40 this is set when an account alias has been assigned to a user
34 flag flag_account_pin_reset 41 this is set on an account when an admin triggers a PIN reset for them

View File

@ -1,12 +1,15 @@
LOAD check_blocked_status 1 LOAD check_blocked_status 1
RELOAD check_blocked_status RELOAD check_blocked_status
LOAD check_account_created 2
RELOAD check_account_created
CATCH self_reset_pin flag_account_pin_reset 1
CATCH blocked_account flag_account_blocked 1 CATCH blocked_account flag_account_blocked 1
CATCH select_language flag_language_set 0 CATCH select_language flag_language_set 0
CATCH terms flag_account_created 0 CATCH terms flag_account_created 0
CATCH create_pin flag_pin_set 0
LOAD check_account_status 0 LOAD check_account_status 0
RELOAD check_account_status RELOAD check_account_status
CATCH api_failure flag_api_call_error 1 CATCH api_failure flag_api_call_error 1
CATCH account_pending flag_account_pending 1 CATCH account_pending flag_account_pending 1
CATCH create_pin flag_pin_set 0
CATCH main flag_account_success 1 CATCH main flag_account_success 1
HALT HALT

View File

@ -0,0 +1,2 @@
A PIN reset has been done on your account.
Please enter a new four number PIN:

View File

@ -0,0 +1,6 @@
LOAD reset_invalid_pin 6
HALT
LOAD save_temporary_pin 1
RELOAD save_temporary_pin
CATCH invalid_pin flag_invalid_pin 1
INCMP confirm_pin_change *

View File

@ -0,0 +1,2 @@
Uwekaji upya wa PIN umefanyika kwenye akaunti yako.
Tafadhali weka PIN mpya ya nambari nne:

View File

@ -0,0 +1 @@
Your alias has been updated successfully

View File

@ -0,0 +1,7 @@
LOAD confirm_new_alias 0
RELOAD confirm_new_alias
MOUT back 0
MOUT quit 9
HALT
INCMP ^ 0
INCMP quit 9

View File

@ -0,0 +1 @@
Ombi lako la kubadilisha lakabu limefanikiwa.

View File

@ -14,6 +14,6 @@ import (
func New(ctx context.Context, storageService storage.StorageService) remote.AccountService { func New(ctx context.Context, storageService storage.StorageService) remote.AccountService {
return &httpremote.HTTPAccountService{ return &httpremote.HTTPAccountService{
SS: storageService, SS: storageService,
UseApi: false, UseApi: true,
} }
} }

View File

@ -63,6 +63,10 @@ const (
DATA_INITIAL_LANGUAGE_CODE DATA_INITIAL_LANGUAGE_CODE
//Fully qualified account alias string //Fully qualified account alias string
DATA_ACCOUNT_ALIAS DATA_ACCOUNT_ALIAS
//currently suggested alias by the api awaiting user's confirmation as accepted account alias
DATA_SUGGESTED_ALIAS
//Key used to store a value of 1 for a user to reset their own PIN once they access the menu.
DATA_SELF_PIN_RESET
) )
const ( const (
@ -130,7 +134,8 @@ func StringToDataTyp(str string) (DataTyp, error) {
return DATA_GENDER, nil return DATA_GENDER, nil
case "DATA_OFFERINGS": case "DATA_OFFERINGS":
return DATA_OFFERINGS, nil return DATA_OFFERINGS, nil
case "DATA_ACCOUNT_ALIAS":
return DATA_ACCOUNT_ALIAS, nil
default: default:
return 0, errors.New("invalid DataTyp string") return 0, errors.New("invalid DataTyp string")
} }

View File

@ -33,11 +33,14 @@ func (s *SubPrefixDb) toKey(k []byte) []byte {
func (s *SubPrefixDb) Get(ctx context.Context, key []byte) ([]byte, error) { func (s *SubPrefixDb) Get(ctx context.Context, key []byte) ([]byte, error) {
s.store.SetPrefix(db.DATATYPE_USERDATA) s.store.SetPrefix(db.DATATYPE_USERDATA)
key = s.toKey(key) key = s.toKey(key)
logg.InfoCtxf(ctx, "SubPrefixDb Get log", "key", string(key))
return s.store.Get(ctx, key) return s.store.Get(ctx, key)
} }
func (s *SubPrefixDb) Put(ctx context.Context, key []byte, val []byte) error { func (s *SubPrefixDb) Put(ctx context.Context, key []byte, val []byte) error {
s.store.SetPrefix(db.DATATYPE_USERDATA) s.store.SetPrefix(db.DATATYPE_USERDATA)
key = s.toKey(key) key = s.toKey(key)
logg.InfoCtxf(ctx, "SubPrefixDb Put log", "key", string(key))
return s.store.Put(ctx, key, val) return s.store.Put(ctx, key, val)
} }

View File

@ -68,7 +68,7 @@ func ScaleDownBalance(balance, decimals string) string {
} }
// GetVoucherData retrieves and matches voucher data // GetVoucherData retrieves and matches voucher data
func GetVoucherData(ctx context.Context, db storedb.PrefixDb, input string) (*dataserviceapi.TokenHoldings, error) { func GetVoucherData(ctx context.Context, store DataStore, sessionId string, input string) (*dataserviceapi.TokenHoldings, error) {
keys := []storedb.DataTyp{ keys := []storedb.DataTyp{
storedb.DATA_VOUCHER_SYMBOLS, storedb.DATA_VOUCHER_SYMBOLS,
storedb.DATA_VOUCHER_BALANCES, storedb.DATA_VOUCHER_BALANCES,
@ -78,9 +78,9 @@ func GetVoucherData(ctx context.Context, db storedb.PrefixDb, input string) (*da
data := make(map[storedb.DataTyp]string) data := make(map[storedb.DataTyp]string)
for _, key := range keys { for _, key := range keys {
value, err := db.Get(ctx, storedb.ToBytes(key)) value, err := store.ReadEntry(ctx, sessionId, key)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get prefix key %x: %v", storedb.ToBytes(key), err) return nil, fmt.Errorf("failed to get data key %x: %v", key, err)
} }
data[key] = string(value) data[key] = string(value)
} }

View File

@ -8,7 +8,6 @@ import (
"github.com/alecthomas/assert/v2" "github.com/alecthomas/assert/v2"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
visedb "git.defalsify.org/vise.git/db"
memdb "git.defalsify.org/vise.git/db/mem" memdb "git.defalsify.org/vise.git/db/mem"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
@ -77,16 +76,8 @@ func TestProcessVouchers(t *testing.T) {
} }
func TestGetVoucherData(t *testing.T) { func TestGetVoucherData(t *testing.T) {
ctx := context.Background() ctx, store := InitializeTestDb(t)
sessionId := "session123"
db := memdb.NewMemDb()
err := db.Connect(ctx, "")
if err != nil {
t.Fatal(err)
}
prefix := storedb.ToBytes(visedb.DATATYPE_USERDATA)
spdb := storedb.NewSubPrefixDb(db, prefix)
// Test voucher data // Test voucher data
mockData := map[storedb.DataTyp][]byte{ mockData := map[storedb.DataTyp][]byte{
@ -98,13 +89,13 @@ func TestGetVoucherData(t *testing.T) {
// Put the data // Put the data
for key, value := range mockData { for key, value := range mockData {
err = spdb.Put(ctx, []byte(storedb.ToBytes(key)), []byte(value)) err := store.WriteEntry(ctx, sessionId, key, []byte(value))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
result, err := GetVoucherData(ctx, spdb, "1") result, err := GetVoucherData(ctx, store, sessionId, "1")
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, "SRF", result.TokenSymbol) assert.Equal(t, "SRF", result.TokenSymbol)