Compare commits

...

158 Commits

Author SHA1 Message Date
e2d5546de1 Merge pull request 'fix-pin-reset-bug' (#26) from fix-pin-reset-bug into master
Some checks are pending
release / docker (push) Waiting to run
Reviewed-on: #26
2025-02-21 10:31:45 +01:00
95089875bf
remove extra spacing 2025-02-21 12:30:28 +03:00
4db25055ad
Added a fix for invalid PIN in PIN reset 2025-02-21 12:29:28 +03:00
e8e6f0e371
Added a fix to only hash valid PINs in SaveOthersTemporaryPin 2025-02-21 11:49:51 +03:00
91c4967efa
check for back 2025-02-21 11:01:42 +03:00
7b1824f18c
go back if account not unlocked 2025-02-21 11:01:31 +03:00
04c3f5ce65
repeat same node on invalid input 2025-02-21 11:01:14 +03:00
e646658f40
repeat same node on invalid input 2025-02-21 10:56:12 +03:00
c4cab444ad
repeat same node on invalid input 2025-02-20 21:26:53 +03:00
b5ade9112e
catch incorrect pin when resetting for others 2025-02-20 21:21:20 +03:00
3b9184e852
check for back 2025-02-20 21:20:41 +03:00
07b85768d1 Merge branch 'master' into fix-pin-reset-bug 2025-02-20 20:00:21 +03:00
c9678df152
reset the PIN using the formattedNumber 2025-02-20 19:59:52 +03:00
c37fee5e54
have the secondarySessionId as a formatted phone number 2025-02-20 19:58:12 +03:00
98b2a31655
remove extra space 2025-02-20 19:56:48 +03:00
d4fcf40b8d Merge pull request 'remove the sessionId from the ctx' (#25) from remove-session-id-from-ctx into master
Reviewed-on: #25
2025-02-20 17:28:54 +01:00
83a10efcd9
remove the sessionId from the ctx to prevent double sessionId key (<sessionId>.<sessionId>) 2025-02-20 15:10:18 +03:00
0089d6f125 Merge pull request 'tests-menu-traversal' (#16) from tests-menu-traversal into master
Reviewed-on: #16
2025-02-13 10:00:42 +01:00
a7d13dc7c4 Merge branch 'master' into tests-menu-traversal 2025-02-13 09:59:11 +01:00
bed7f58e81 Merge pull request 'alfred/test-updates' (#15) from alfred/test-updates into master
Reviewed-on: #15
2025-02-13 09:58:45 +01:00
07fd1110ed
added documentation lines 2025-02-11 13:22:32 +03:00
2f1dbb9147
added TestClearTemporaryValue 2025-02-11 13:10:56 +03:00
93f1897321
Merge branch 'master' into tests-menu-traversal 2025-02-11 13:07:07 +03:00
c324e29aea
added test case to the TestCheckVouchers 2025-02-11 13:00:23 +03:00
f91056cca2 Merge branch 'master' into alfred/test-updates 2025-02-11 12:53:41 +03:00
7d11377ffd
test empty input. 2025-02-11 12:45:52 +03:00
9a63234470
set and reset admin flag using persister's state 2025-02-10 15:45:15 +03:00
fe74dbb848
add test for menu select voucher 2025-02-10 15:37:05 +03:00
278edc7049
test reset other's pin with registred and unregistred phone number 2025-02-10 13:31:18 +03:00
3b03d40279
return the persister and flag parser 2025-02-10 12:52:01 +03:00
4d46133194
chore: add some spacing 2025-02-10 12:10:17 +03:00
fd84f6ae98 Merge pull request 'debug-errors-with-temporary-value' (#22) from debug-errors-with-temporary-value into master
Some checks failed
release / docker (push) Has been cancelled
Reviewed-on: #22
2025-02-06 14:43:59 +01:00
1e8d5b1b83
Remove left over code comment 2025-02-06 16:42:39 +03:00
628a57ea10
Only clear the temporary data once at main.vis 2025-02-06 16:42:07 +03:00
a37908323f
Remove early LOAD statement 2025-02-06 16:32:03 +03:00
lash
9c27be3a9d
Update sarafu-api dep 2025-02-06 12:24:35 +00:00
1190c5b6f2 Merge branch 'master' into alfred/test-updates 2025-02-06 15:19:40 +03:00
b95452ae5f Merge pull request 'clear-temporary-valua-after-use' (#21) from clear-temporary-valua-after-use into master
Reviewed-on: #21
2025-02-06 13:18:41 +01:00
14df16098c
Updated tests to include the mockState 2025-02-06 15:10:15 +03:00
1cdd5a37ae Merge branch 'master' into alfred/test-updates 2025-02-06 15:02:18 +03:00
6b3b8ffabe
add alias request and resolve logs 2025-02-06 14:57:29 +03:00
6647416115
Return an error if the temporary value is empty 2025-02-06 14:38:11 +03:00
4155b267ee
Clear the temporary value after use 2025-02-06 14:23:42 +03:00
0f2d6def23 Merge pull request 'lash/custom-engin' (#20) from lash/custom-engin into master
Some checks failed
release / docker (push) Has been cancelled
Reviewed-on: #20
2025-02-06 11:11:48 +01:00
lash
c13768d782
Remove custom engine 2025-02-05 17:56:08 +00:00
lash
af4b075df3
Add reset on empty to ssh 2025-02-05 17:45:31 +00:00
lash
1d7027905d
Use simplified reset on empty input solution 2025-02-05 17:44:29 +00:00
lash
6c77d04284 Merge branch 'lash/async-inputs' into lash/custom-engin 2025-02-05 16:27:10 +00:00
lash
12acd508b1
Allow empty input in async cmd 2025-02-05 16:26:17 +00:00
f88e253486
Call the engine Reset 2025-02-05 19:16:25 +03:00
68597ea7cc
Return the Sarafu Engine in GetEngine 2025-02-05 19:08:36 +03:00
3d9eeddab8
Remove the Move to top node on empty input test case 2025-02-05 19:07:35 +03:00
df58f69032
Remove input length check on menuhandler Init 2025-02-05 19:02:23 +03:00
8b999a09a2
add test cases 2025-02-05 18:04:29 +03:00
lash
fdde1bb979
Add missing services import in ssh 2025-02-05 10:28:20 +00:00
lash
23cadc6178
Reinstate loading handlerfuncs in cmd, ssh clients 2025-02-05 10:21:21 +00:00
0821241427
repeat same node on invalid option 2025-02-05 10:23:31 +03:00
ca71062528
Merge branch 'master' into tests-menu-traversal 2025-02-05 09:11:16 +03:00
1918ea37d5 Merge pull request 'Bug fixes and menu improvement' (#19) from minor-bug-fixes into master
Reviewed-on: #19
Reviewed-by: lash <accounts-grassrootseconomics@holbrook.no>
2025-02-04 14:36:20 +01:00
lash
422b651097
Add missing file 2025-02-04 13:33:44 +00:00
lash
861d04dbfd
WIP Implement custom engine 2025-02-04 13:25:17 +00:00
c78081fb84
added TestInsertOrShift 2025-02-04 11:42:14 +03:00
ff3c597158
added TestUpdateAllProfileItems 2025-02-04 11:03:23 +03:00
09c5f3a14c
added TestInsertProfileItems 2025-02-04 10:30:39 +03:00
f7873bfef7
add mock state to failing tests 2025-02-04 10:16:12 +03:00
815e3b2a25
remove unused handler 2025-02-04 09:46:33 +03:00
f9a9a9b4a6
preload all common functions 2025-02-04 08:44:10 +03:00
04429ab74c
fix: wrong pin count by load and reload handlers 2025-02-04 08:43:55 +03:00
d3f1a14e71
replace back with retry option 2025-02-04 08:41:55 +03:00
5722d4f8dd
reset flags on back navigation,process only numeric pin entries 2025-02-04 08:41:06 +03:00
cad18c9e64 Merge pull request 'use the latest changes from grassrootseconomics/visedriver-africastalking' (#17) from update-dependency into master
Some checks failed
release / docker (push) Has been cancelled
Reviewed-on: #17
2025-01-29 09:18:49 +01:00
fbff584bb4
use the latest changes from grassrootseconomics/visedriver-africastalking 2025-01-29 10:14:01 +03:00
4169419442
add test for reset without privileges 2025-01-28 09:28:40 +03:00
bef62b97e7
extract remaining pin attempts 2025-01-27 14:00:42 +03:00
56d0baad6e
test block account 2025-01-27 14:00:18 +03:00
5a586eb67a
added TestConstructAccountAlias 2025-01-27 13:31:00 +03:00
6a945f8f20
added TestResetUnregisteredNumber 2025-01-27 12:53:02 +03:00
39f8c86e8b
added TestResetValidPin 2025-01-27 12:50:46 +03:00
73b501c8aa
removed left over commented code 2025-01-27 12:42:48 +03:00
a6cd4b5fca
added TestResetOthersPin 2025-01-27 12:36:04 +03:00
d47bc6c241 Merge branch 'master' into alfred/test-updates 2025-01-27 12:23:13 +03:00
dd55906e70
added TestGetCurrentProfileInfo 2025-01-27 11:35:05 +03:00
6fdf3735d0
added TestCheckBlockedNumPinMisMatch 2025-01-27 10:52:43 +03:00
b492421851
enhanced the TestSaveOthersTemporaryPin 2025-01-27 10:40:35 +03:00
128c0162d2
added TestSaveOthersTemporaryPin 2025-01-27 02:13:53 +03:00
ebe94c705f
added TestValidateBlockedNumber 2025-01-27 01:46:14 +03:00
df0c1b3429
added TestQuitWithHelp and TestShowBlockedAccount 2025-01-27 01:25:01 +03:00
d66fd894bc
added TestMaxAmount 2025-01-27 01:17:44 +03:00
28185fc2c5
added TestRetrieveBlockedNumber 2025-01-27 01:05:32 +03:00
d2f75c693a Merge pull request 'alias-fqdn' (#9) from alias-fqdn into master
Reviewed-on: #9
2025-01-25 13:46:29 +01:00
363c35efed
update test data file 2025-01-25 09:55:39 +03:00
64a87231ca
removed redundant type from array 2025-01-24 15:43:42 +03:00
0f361a065b Merge branch 'master' into alias-fqdn 2025-01-24 13:08:29 +01:00
lash
4d1045a9f9
Adapt override to non-pointer values 2025-01-24 15:03:47 +03:00
lash
f3a6485bb3
Avoid overwrite of env configs 2025-01-24 15:02:31 +03:00
cd37adc288
update test 2025-01-24 15:02:30 +03:00
6f0994d692
feat: show alias as part of the profile information 2025-01-24 15:02:30 +03:00
lash
fbaba15776
Adapt override to non-pointer values 2025-01-24 10:15:37 +00:00
lash
9a094f440f
Avoid overwrite of env configs 2025-01-24 08:47:23 +00:00
6c77ff58ab Merge branch 'master' into alias-fqdn 2025-01-24 09:44:50 +01:00
c8ddafcf66
run go mod tidy 2025-01-24 11:41:25 +03:00
5f1a659789
request alias on initial profile setup 2025-01-24 11:41:00 +03:00
0d4be0f7fc
return nil when error is key not found 2025-01-24 10:12:28 +03:00
b6161da749
fix failing test 2025-01-24 09:32:21 +03:00
f1c4d5f1f9
docker: change bin name -> sarafu-at 2025-01-24 09:26:00 +03:00
73b876dbdd
ci/cd: add Dockerfile and GH builds 2025-01-24 09:25:09 +03:00
18e865ba26
set UseApi and storageservice to HttpAccountService 2025-01-24 07:59:33 +03:00
d7c909f028
update sarafu-api dep 2025-01-24 07:58:03 +03:00
908a52cda6
Merge branch 'master' into alias-fqdn 2025-01-24 07:41:33 +03:00
0e480e3d55
enhanced the TestViewTransactionStatement 2025-01-23 16:08:04 +03:00
ffea1a0b96
added TestViewTransactionStatement 2025-01-23 15:54:50 +03:00
be5bd16616
added TestGetTransactionsList 2025-01-23 15:06:12 +03:00
93723616f6
added TestCheckTransactions 2025-01-23 13:42:17 +03:00
c9257ba0d6
added TestPersistInitialLanguageCode 2025-01-23 11:47:12 +03:00
caabf4f8af
updated the structure of TestPersistLanguageCode 2025-01-23 11:30:25 +03:00
f884b19012
added TestCheckBlockedStatus 2025-01-23 11:29:57 +03:00
526dc822fb Merge pull request 'remove unused New conn argument' (#14) from fix-remote-new-args into master
Reviewed-on: #14
2025-01-23 09:29:25 +01:00
1249e45d54
remove unused New conn argument 2025-01-23 11:22:34 +03:00
lash
99d03e3bc9
Fix signal handling for termination, proper engine cleanup 2025-01-22 19:08:57 +00:00
lash
1e495763f5
Fmt 2025-01-22 18:37:27 +00:00
lash
5e83c89e03
Correct override handling for mode 2025-01-22 16:40:32 +00:00
lash
1909b60bf4
Reinstate resource-dir switch 2025-01-22 09:42:39 +00:00
lash
49335a290f
Gofmt, remove commented code 2025-01-21 15:43:26 +00:00
lash
2c8e60e1bb
Add gdbmdb testutil 2025-01-21 15:02:32 +00:00
lash
4baacb325d Merge branch 'master' into lash/dbtx 2025-01-21 14:26:48 +00:00
lash
c243edd4c4
Make override constructor for args population 2025-01-21 14:25:55 +00:00
44846c5950 Merge pull request 'Add transactional vise db ability' (#11) from lash/dbtx into master
Reviewed-on: #11
2025-01-21 15:15:15 +01:00
lash
592c57b72d
Update deps, unique fsdbs in testfsdb 2025-01-21 14:14:52 +00:00
lash
341f0b9cc8 Merge branch 'master' into lash/dbtx 2025-01-21 13:45:33 +00:00
lash
1c911ee73f Merge branch 'master' into lash/dbtx 2025-01-21 13:44:56 +00:00
lash
00b9079a55
Clean up spaces 2025-01-21 13:44:32 +00:00
ec6b078de3
fix: import config and model packages 2025-01-21 15:23:21 +03:00
0b4fde9d1e
Merge branch 'master' into alias-fqdn 2025-01-21 12:53:50 +03:00
66be350ad1
remove accountservice implementation check 2025-01-21 12:48:17 +03:00
lash
156511e499
Build vise-asm binary in makefile 2025-01-21 08:17:23 +00:00
lash
8b68130ed4
Remove bin files 2025-01-21 08:11:26 +00:00
lash
7ab8eef623 Merge branch 'reset-account-blocked-flag' into lash/dbtx 2025-01-21 08:02:56 +00:00
7d513ac2a7 Merge pull request 'reset account blocked flag' (#13) from reset-account-blocked-flag into master
Reviewed-on: #13
2025-01-21 07:47:33 +01:00
lash
b31011b390
Update deps 2025-01-20 12:37:02 +00:00
lash
358567e52e Merge remote-tracking branch 'origin/master' into lash/dbtx 2025-01-20 12:01:35 +00:00
lash
933943636e
Implement conns in testutil 2025-01-20 10:28:42 +00:00
1e69f2167a
Merge branch 'master' into alias-fqdn 2025-01-20 12:32:29 +03:00
lash
20feef4103
WIP integrate multiple conns, menutraversal now panics 2025-01-19 18:27:47 +00:00
lash
8d5d3f1dc8
WIP implement multi connstr config 2025-01-19 16:32:55 +00:00
lash
0f54ab4b4a
Update deps, fix connbusy error in postgres get 2025-01-19 11:11:34 +00:00
lash
be47c999ca
Integrate tx enabled vise db 2025-01-19 09:46:37 +00:00
lash
c719db8b92
Update dep 2025-01-18 19:35:48 +00:00
lash
16cb2846b7
Update govise dep; removes hardcoded datatype 2025-01-18 09:00:44 +00:00
lash
bc2abc2464
Update govise dep, dump keys fix 2025-01-18 08:23:40 +00:00
f435046385
Merge branch 'master' into alias-fqdn 2025-01-18 08:01:58 +03:00
efaf0ab22e
feat: construct an account alias 2025-01-18 07:53:42 +03:00
e29bcb5b27
define and parse alias search domains 2025-01-18 07:52:08 +03:00
cdb22f8cbb
add key for the account alias 2025-01-18 07:50:55 +03:00
lash
9cb9e02442 Merge branch 'master' into lash/update-dump 2025-01-17 18:56:43 +00:00
6aa4bd8906
add alias search domains 2025-01-17 15:02:58 +03:00
lash
ab03e6d529
Rehabilitate debug db tets, improve dump format 2025-01-17 11:09:30 +00:00
lash
9b66146ef1
Remove generate tool (use devapi main instead) 2025-01-17 10:36:29 +00:00
lash
825c06c3bb
Rehabilitate dump tool 2025-01-17 10:36:02 +00:00
149 changed files with 2525 additions and 684 deletions

16
.dockerignore Normal file
View File

@ -0,0 +1,16 @@
/**
!/args
!/cmd/africastalking
!/cmd/ssh
!/config
!/debug
!/handlers
!/internal
!/profile
!/services
!/ssh
!/store
!/LICENSE
!/README.md
!/go.*
!/.env.example

View File

@ -18,3 +18,6 @@ DATA_URL_BASE=http://localhost:5006
#Language
DEFAULT_LANGUAGE=eng
LANGUAGES=eng, swa
#Alias search domains
ALIAS_SEARCH_DOMAINS=sarafu.local, sarafu.eth

56
.github/workflows/docker.yaml vendored Normal file
View File

@ -0,0 +1,56 @@
name: release
on:
push:
tags:
- "v*"
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Check out repo
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache Docker layers
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Login to GHCR Docker registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set outputs
run: |
echo "RELEASE_TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV \
&& echo "RELEASE_SHORT_COMMIT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
- name: Build and push image
uses: docker/build-push-action@v2
with:
context: ./
file: ./Dockerfile
platforms: linux/amd64
push: true
build-args: |
BUILD=${{ env.RELEASE_SHORT_COMMIT }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache
tags: |
ghcr.io/grassrootseconomics/sarafu-vise:latest
ghcr.io/grassrootseconomics/sarafu-vise:${{ env.RELEASE_TAG }}

50
Dockerfile Normal file
View File

@ -0,0 +1,50 @@
FROM golang:1.23.4-bookworm AS build
ENV CGO_ENABLED=1
ARG BUILDPLATFORM
ARG TARGETPLATFORM
ARG BUILD=dev
WORKDIR /build
RUN apt-get update && apt-get install -y --no-install-recommends \
libgdbm-dev \
git \
&& rm -rf /var/lib/apt/lists/*
RUN git clone https://git.defalsify.org/vise.git go-vise
COPY . ./sarafu-vise
WORKDIR /build/sarafu-vise/services/registration
RUN echo "Compiling go-vise files"
RUN make VISE_PATH=/build/go-vise -B
WORKDIR /build/sarafu-vise
RUN echo "Building on $BUILDPLATFORM, building for $TARGETPLATFORM"
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 logtrace,online -o sarafu-ssh -ldflags="-X main.build=${BUILD} -s -w" cmd/ssh/main.go
FROM debian:bookworm-slim
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
libgdbm-dev \
ca-certificates \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /service
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/README.md .
COPY --from=build /build/sarafu-vise/services ./services
COPY --from=build /build/sarafu-vise/.env.example .
RUN mv .env.example .env
EXPOSE 7123
EXPOSE 7122
CMD ["./sarafu-at"]

View File

@ -10,7 +10,7 @@ type LangVar struct {
v []lang.Language
}
func(lv *LangVar) Set(s string) error {
func (lv *LangVar) Set(s string) error {
v, err := lang.LanguageFromCode(s)
if err != nil {
return err
@ -19,16 +19,14 @@ func(lv *LangVar) Set(s string) error {
return err
}
func(lv *LangVar) String() string {
func (lv *LangVar) String() string {
var s []string
for _, v := range(lv.v) {
for _, v := range lv.v {
s = append(s, v.Code)
}
return strings.Join(s, ",")
}
func(lv *LangVar) Langs() []lang.Language {
func (lv *LangVar) Langs() []lang.Language {
return lv.v
}

View File

@ -12,18 +12,18 @@ import (
"syscall"
"git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/logging"
"git.defalsify.org/vise.git/lang"
"git.defalsify.org/vise.git/logging"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
"git.grassecon.net/grassrootseconomics/visedriver/request"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
at "git.grassecon.net/grassrootseconomics/visedriver-africastalking/africastalking"
"git.grassecon.net/grassrootseconomics/sarafu-vise/args"
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers"
"git.grassecon.net/grassrootseconomics/sarafu-vise/services"
at "git.grassecon.net/grassrootseconomics/visedriver-africastalking/africastalking"
)
var (
@ -36,8 +36,7 @@ var (
func main() {
config.LoadConfig()
var connStr string
var resourceDir string
override := config.NewOverride()
var size uint
var engineDebug bool
var host string
@ -46,10 +45,11 @@ func main() {
var gettextDir string
var langs args.LangVar
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
flag.StringVar(&connStr, "c", "", "connection string")
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(&override.UserConn, "userdata", "?", "userdata store connection string")
flag.StringVar(&override.ResourceConn, "resource", "?", "resource data directory")
flag.StringVar(&override.StateConn, "state", "?", "state store connection string")
flag.UintVar(&size, "s", 160, "max size of output")
flag.StringVar(&host, "h", config.Host(), "http host")
flag.UintVar(&port, "p", config.Port(), "http port")
@ -57,16 +57,14 @@ func main() {
flag.Var(&langs, "language", "add symbol resolution for language")
flag.Parse()
if connStr == "" {
connStr = config.DbConn()
}
connData, err := storage.ToConnData(connStr)
config.Apply(override)
conns, err := config.GetConns()
if err != nil {
fmt.Fprintf(os.Stderr, "connstr err: %v", err)
fmt.Fprintf(os.Stderr, "conn specification error: %v\n", err)
os.Exit(1)
}
logg.Infof("start command", "build", build, "conn", connData, "resourcedir", resourceDir, "outputsize", size)
logg.Infof("start command", "build", build, "conn", conns, "outputsize", size)
ctx := context.Background()
ln, err := lang.LanguageFromCode(config.Language())
@ -83,13 +81,14 @@ func main() {
OutputSize: uint32(size),
FlagCount: uint32(128),
MenuSeparator: menuSeparator,
ResetOnEmptyInput: true,
}
if engineDebug {
cfg.EngineDebug = true
}
menuStorageService := storage.NewMenuStorageService(connData, resourceDir)
menuStorageService := storage.NewMenuStorageService(conns)
rs, err := menuStorageService.GetResource(ctx)
if err != nil {
fmt.Fprintf(os.Stderr, "menustorageservice: %v\n", err)
@ -101,7 +100,6 @@ func main() {
fmt.Fprintf(os.Stderr, "userdatadb: %v\n", err)
os.Exit(1)
}
defer userdataStore.Close()
dbResource, ok := rs.(*resource.DbResource)
if !ok {
@ -120,7 +118,7 @@ func main() {
os.Exit(1)
}
accountService := services.New(ctx, menuStorageService, connData)
accountService := services.New(ctx, menuStorageService)
hl, err := lhs.GetHandler(accountService)
if err != nil {
@ -133,10 +131,10 @@ func main() {
fmt.Fprintf(os.Stderr, "getstatestore: %v\n", err)
os.Exit(1)
}
defer stateStore.Close()
rp := &at.ATRequestParser{}
bsh := request.NewBaseRequestHandler(cfg, rs, stateStore, userdataStore, rp, hl)
bsh = bsh.WithEngineFunc(lhs.GetEngine)
sh := at.NewATRequestHandler(bsh)
mux := http.NewServeMux()
@ -146,7 +144,10 @@ func main() {
Addr: fmt.Sprintf("%s:%s", host, strconv.Itoa(int(port))),
Handler: mux,
}
s.RegisterOnShutdown(sh.Shutdown)
shutdownFunc := func() {
sh.Shutdown(ctx)
}
s.RegisterOnShutdown(shutdownFunc)
cint := make(chan os.Signal)
cterm := make(chan os.Signal)

View File

@ -1,12 +1,15 @@
package main
import (
"bufio"
"context"
"flag"
"fmt"
"io"
"os"
"os/signal"
"path"
"strings"
"syscall"
"git.defalsify.org/vise.git/engine"
@ -14,12 +17,12 @@ import (
"git.defalsify.org/vise.git/logging"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
"git.grassecon.net/grassrootseconomics/visedriver/request"
"git.grassecon.net/grassrootseconomics/sarafu-vise/services"
"git.grassecon.net/grassrootseconomics/sarafu-vise/args"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config"
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers"
"git.grassecon.net/grassrootseconomics/sarafu-vise/services"
"git.grassecon.net/grassrootseconomics/visedriver/request"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
)
var (
@ -44,9 +47,8 @@ func (p *asyncRequestParser) GetInput(r any) ([]byte, error) {
func main() {
config.LoadConfig()
var connStr string
override := config.NewOverride()
var sessionId string
var resourceDir string
var size uint
var engineDebug bool
var host string
@ -56,8 +58,11 @@ func main() {
var langs args.LangVar
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
flag.StringVar(&connStr, "c", "", "connection string")
flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(&override.ResourceConn, "resource", "?", "resource data directory")
flag.StringVar(&override.UserConn, "userdata", "?", "userdata store connection string")
flag.StringVar(&override.StateConn, "state", "?", "state store connection string")
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
flag.UintVar(&size, "s", 160, "max size of output")
flag.StringVar(&host, "h", config.Host(), "http host")
@ -66,16 +71,14 @@ func main() {
flag.Var(&langs, "language", "add symbol resolution for language")
flag.Parse()
if connStr == "" {
connStr = config.DbConn()
}
connData, err := storage.ToConnData(connStr)
config.Apply(override)
conns, err := config.GetConns()
if err != nil {
fmt.Fprintf(os.Stderr, "connstr err: %v", err)
fmt.Fprintf(os.Stderr, "conn specification error: %v\n", err)
os.Exit(1)
}
logg.Infof("start command", "conn", connData, "resourcedir", resourceDir, "outputsize", size, "sessionId", sessionId)
logg.Infof("start command", "conn", conns, "outputsize", size, "sessionId", sessionId)
ctx := context.Background()
@ -93,13 +96,14 @@ func main() {
OutputSize: uint32(size),
FlagCount: uint32(128),
MenuSeparator: menuSeparator,
ResetOnEmptyInput: true,
}
if engineDebug {
cfg.EngineDebug = true
}
menuStorageService := storage.NewMenuStorageService(connData, resourceDir)
menuStorageService := storage.NewMenuStorageService(conns)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
@ -116,7 +120,7 @@ func main() {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
defer userdataStore.Close()
//defer userdataStore.Close(ctx)
dbResource, ok := rs.(*resource.DbResource)
if !ok {
@ -126,8 +130,7 @@ func main() {
lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs)
lhs.SetDataStore(&userdataStore)
accountService := services.New(ctx, menuStorageService, connData)
accountService := services.New(ctx, menuStorageService)
hl, err := lhs.GetHandler(accountService)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
@ -139,12 +142,14 @@ func main() {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
defer stateStore.Close()
//defer stateStore.Close(ctx)
rp := &asyncRequestParser{
sessionId: sessionId,
}
sh := request.NewBaseRequestHandler(cfg, rs, stateStore, userdataStore, rp, hl)
sh = sh.WithEngineFunc(lhs.GetEngine)
cfg.SessionId = sessionId
rqs := request.RequestSession{
Ctx: ctx,
@ -161,7 +166,7 @@ func main() {
case _ = <-cint:
case _ = <-cterm:
}
sh.Shutdown()
sh.Shutdown(ctx)
}()
for true {
@ -177,18 +182,26 @@ func main() {
fmt.Errorf("error in output: %v", err)
os.Exit(1)
}
rqs, err = sh.Reset(rqs)
rqs, err = sh.Reset(ctx, rqs)
if err != nil {
logg.ErrorCtxf(ctx, "error in reset: %v", "err", err)
fmt.Errorf("error in reset: %v", err)
os.Exit(1)
}
fmt.Println("")
_, err = fmt.Scanln(&rqs.Input)
in := bufio.NewReader(os.Stdin)
s, err := in.ReadString('\n')
if err != nil {
if err == io.EOF {
logg.DebugCtxf(ctx, "have EOF, bailing")
break
}
logg.ErrorCtxf(ctx, "error in input", "err", err)
fmt.Errorf("error in input: %v", err)
os.Exit(1)
}
rqs.Input = []byte{}
s = strings.TrimSpace(s)
rqs.Input = []byte(s)
}
}

View File

@ -17,13 +17,13 @@ import (
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config"
httprequest "git.grassecon.net/grassrootseconomics/visedriver/request/http"
"git.grassecon.net/grassrootseconomics/visedriver/request"
httprequest "git.grassecon.net/grassrootseconomics/visedriver/request/http"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
"git.grassecon.net/grassrootseconomics/sarafu-vise/services"
"git.grassecon.net/grassrootseconomics/sarafu-vise/args"
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers"
"git.grassecon.net/grassrootseconomics/sarafu-vise/services"
)
var (
@ -35,8 +35,7 @@ var (
func main() {
config.LoadConfig()
var connStr string
var resourceDir string
override := config.NewOverride()
var size uint
var engineDebug bool
var host string
@ -45,8 +44,11 @@ func main() {
var gettextDir string
var langs args.LangVar
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
flag.StringVar(&connStr, "c", "", "connection string")
flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(&override.UserConn, "userdata", "?", "userdata store connection string")
flag.StringVar(&override.ResourceConn, "resource", "?", "resource data directory")
flag.StringVar(&override.StateConn, "state", "?", "state store connection string")
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
flag.UintVar(&size, "s", 160, "max size of output")
flag.StringVar(&host, "h", config.Host(), "http host")
@ -55,16 +57,14 @@ func main() {
flag.Var(&langs, "language", "add symbol resolution for language")
flag.Parse()
if connStr == "" {
connStr = config.DbConn()
}
connData, err := storage.ToConnData(connStr)
config.Apply(override)
conns, err := config.GetConns()
if err != nil {
fmt.Fprintf(os.Stderr, "connstr err: %v", err)
fmt.Fprintf(os.Stderr, "conn specification error: %v\n", err)
os.Exit(1)
}
logg.Infof("start command", "conn", connData, "resourcedir", resourceDir, "outputsize", size)
logg.Infof("start command", "conn", conns, "outputsize", size)
ctx := context.Background()
@ -82,13 +82,14 @@ func main() {
OutputSize: uint32(size),
FlagCount: uint32(128),
MenuSeparator: menuSeparator,
ResetOnEmptyInput: true,
}
if engineDebug {
cfg.EngineDebug = true
}
menuStorageService := storage.NewMenuStorageService(connData, resourceDir)
menuStorageService := storage.NewMenuStorageService(conns)
rs, err := menuStorageService.GetResource(ctx)
if err != nil {
@ -101,7 +102,6 @@ func main() {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
defer userdataStore.Close()
dbResource, ok := rs.(*resource.DbResource)
if !ok {
@ -116,7 +116,7 @@ func main() {
os.Exit(1)
}
accountService := services.New(ctx, menuStorageService, connData)
accountService := services.New(ctx, menuStorageService)
hl, err := lhs.GetHandler(accountService)
if err != nil {
@ -129,18 +129,21 @@ func main() {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
defer stateStore.Close()
//accountService := services.New(ctx, menuStorageService, connData)
rp := &httprequest.DefaultRequestParser{}
bsh := request.NewBaseRequestHandler(cfg, rs, stateStore, userdataStore, rp, hl)
bsh = bsh.WithEngineFunc(lhs.GetEngine)
sh := httprequest.NewHTTPRequestHandler(bsh)
s := &http.Server{
Addr: fmt.Sprintf("%s:%s", host, strconv.Itoa(int(port))),
Handler: sh,
}
s.RegisterOnShutdown(sh.Shutdown)
shutdownFunc := func() {
sh.Shutdown(ctx)
}
s.RegisterOnShutdown(shutdownFunc)
cint := make(chan os.Signal)
cterm := make(chan os.Signal)

View File

@ -5,17 +5,19 @@ import (
"flag"
"fmt"
"os"
"os/signal"
"path"
"syscall"
"git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/lang"
"git.defalsify.org/vise.git/logging"
"git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/lang"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
"git.grassecon.net/grassrootseconomics/sarafu-vise/services"
"git.grassecon.net/grassrootseconomics/sarafu-vise/args"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config"
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers"
"git.grassecon.net/grassrootseconomics/sarafu-vise/services"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
)
var (
@ -27,41 +29,39 @@ var (
func main() {
config.LoadConfig()
var connStr string
override := config.NewOverride()
var size uint
var sessionId string
var engineDebug bool
var resourceDir string
var err error
var gettextDir string
var langs args.LangVar
flag.StringVar(&resourceDir, "resourcedir", scriptDir, "resource dir")
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
flag.StringVar(&connStr, "c", "", "connection string")
flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(&override.ResourceConn, "resource", "?", "resource data directory")
flag.StringVar(&override.UserConn, "userdata", "?", "userdata store connection string")
flag.StringVar(&override.StateConn, "state", "?", "state store connection string")
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
flag.UintVar(&size, "s", 160, "max size of output")
flag.StringVar(&gettextDir, "gettext", "", "use gettext translations from given directory")
flag.Var(&langs, "language", "add symbol resolution for language")
flag.Parse()
if connStr == "" {
connStr = config.DbConn()
}
connData, err := storage.ToConnData(connStr)
config.Apply(override)
conns, err := config.GetConns()
if err != nil {
fmt.Fprintf(os.Stderr, "connstr err: %v\n", err)
fmt.Fprintf(os.Stderr, "conn specification error: %v\n", err)
os.Exit(1)
}
logg.Infof("start command", "conn", connData, "outputsize", size)
logg.Infof("start command", "conn", conns, "outputsize", size)
if len(langs.Langs()) == 0 {
langs.Set(config.Language())
}
ctx := context.Background()
ctx = context.WithValue(ctx, "SessionId", sessionId)
ln, err := lang.LanguageFromCode(config.Language())
if err != nil {
@ -78,9 +78,11 @@ func main() {
OutputSize: uint32(size),
FlagCount: uint32(128),
MenuSeparator: menuSeparator,
EngineDebug: engineDebug,
ResetOnEmptyInput: true,
}
menuStorageService := storage.NewMenuStorageService(connData, resourceDir)
menuStorageService := storage.NewMenuStorageService(conns)
if err != nil {
fmt.Fprintf(os.Stderr, "menu storage service error: %v\n", err)
os.Exit(1)
@ -122,18 +124,28 @@ func main() {
os.Exit(1)
}
accountService := services.New(ctx, menuStorageService, connData)
hl, err := lhs.GetHandler(accountService)
accountService := services.New(ctx, menuStorageService)
_, err = lhs.GetHandler(accountService)
if err != nil {
fmt.Fprintf(os.Stderr, "get accounts service handler: %v\n", err)
os.Exit(1)
}
en := lhs.GetEngine(cfg, rs, pe)
en := lhs.GetEngine()
en = en.WithFirst(hl.Init)
if engineDebug {
en = en.WithDebug(nil)
cint := make(chan os.Signal)
cterm := make(chan os.Signal)
signal.Notify(cint, os.Interrupt, syscall.SIGINT)
signal.Notify(cterm, os.Interrupt, syscall.SIGTERM)
go func() {
var s os.Signal
select {
case s = <-cterm:
case s = <-cint:
}
logg.InfoCtxf(ctx, "stopping on signal", "sig", s)
en.Finish(ctx)
os.Exit(0)
}()
err = engine.Loop(ctx, en, os.Stdin, os.Stdout, nil)
if err != nil {

View File

@ -31,34 +31,31 @@ var (
func main() {
config.LoadConfig()
var connStr string
override := config.NewOverride()
var authConnStr string
var resourceDir string
var size uint
var engineDebug bool
var stateDebug bool
var host string
var port uint
flag.StringVar(&connStr, "c", "", "connection string")
flag.StringVar(&authConnStr, "authdb", "", "auth connection string")
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(&override.ResourceConn, "resource", "?", "resource connection string")
flag.StringVar(&override.UserConn, "userdata", "?", "userdata store connection string")
flag.StringVar(&override.StateConn, "state", "?", "state store connection string")
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
flag.UintVar(&size, "s", 160, "max size of output")
flag.StringVar(&host, "h", config.HostSSH(), "socket host")
flag.UintVar(&port, "p", config.PortSSH(), "socket port")
flag.Parse()
if connStr == "" {
connStr = config.DbConn()
}
if authConnStr == "" {
authConnStr = connStr
}
connData, err := storage.ToConnData(connStr)
config.Apply(override)
conns, err := config.GetConns()
if err != nil {
fmt.Fprintf(os.Stderr, "connstr err: %v", err)
fmt.Fprintf(os.Stderr, "conn specification error: %v\n", err)
os.Exit(1)
}
authConnData, err := storage.ToConnData(authConnStr)
if err != nil {
fmt.Fprintf(os.Stderr, "auth connstr err: %v", err)
@ -79,7 +76,7 @@ func main() {
logg.WarnCtxf(ctx, "!!!!! Do not expose to internet and only use with tunnel!")
logg.WarnCtxf(ctx, "!!!!! (See ssh -L <...>)")
logg.Infof("start command", "conn", connData, "authconn", authConnData, "resourcedir", resourceDir, "outputsize", size, "keyfile", sshKeyFile, "host", host, "port", port)
logg.Infof("start command", "conn", conns, "authconn", authConnData, "outputsize", size, "keyfile", sshKeyFile, "host", host, "port", port)
pfp := path.Join(scriptDir, "pp.csv")
@ -87,6 +84,7 @@ func main() {
Root: "root",
OutputSize: uint32(size),
FlagCount: uint32(128),
ResetOnEmptyInput: true,
}
if stateDebug {
cfg.StateDebug = true
@ -102,7 +100,7 @@ func main() {
}
defer func() {
logg.TraceCtxf(ctx, "shutdown auth key store reached")
err = authKeyStore.Close()
err = authKeyStore.Close(ctx)
if err != nil {
logg.ErrorCtxf(ctx, "keystore close error", "err", err)
}
@ -117,8 +115,7 @@ func main() {
Cfg: cfg,
Debug: engineDebug,
FlagFile: pfp,
Conn: connData,
ResourceDir: resourceDir,
Conn: conns,
SrvKeyFile: sshKeyFile,
Host: host,
Port: port,

View File

@ -34,7 +34,7 @@ func main() {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
}
defer store.Close()
defer store.Close(ctx)
err = store.AddFromFile(ctx, sshKeyFile, sessionId)
if err != nil {

20
config/args.go Normal file
View File

@ -0,0 +1,20 @@
package config
import (
viseconfig "git.grassecon.net/grassrootseconomics/visedriver/config"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
)
func NewOverride() *viseconfig.Override {
o := &viseconfig.Override{
StateConnMode: storage.DBMODE_TEXT,
ResourceConnMode: storage.DBMODE_TEXT,
UserConnMode: storage.DBMODE_BINARY,
}
return o
}
func Apply(o *viseconfig.Override) error {
viseconfig.ApplyConn(o)
return nil
}

View File

@ -1,13 +1,24 @@
package config
import (
"git.grassecon.net/grassrootseconomics/visedriver/env"
viseconfig "git.grassecon.net/grassrootseconomics/visedriver/config"
"strings"
apiconfig "git.grassecon.net/grassrootseconomics/sarafu-api/config"
viseconfig "git.grassecon.net/grassrootseconomics/visedriver/config"
"git.grassecon.net/grassrootseconomics/visedriver/env"
)
func init() {
var (
GetConns = viseconfig.GetConns
EnvPath string
)
func loadEnv() {
if EnvPath == "" {
env.LoadEnvVariables()
} else {
env.LoadEnvVariablesPath(EnvPath)
}
}
const (
@ -15,10 +26,11 @@ const (
defaultSSHPort uint = 7122
defaultHTTPHost string = "127.0.0.1"
defaultHTTPPort uint = 7123
defaultDomain = "sarafu.local"
)
func LoadConfig() error {
loadEnv()
err := viseconfig.LoadConfig()
if err != nil {
return err
@ -30,10 +42,17 @@ func LoadConfig() error {
return nil
}
func DbConn() string {
return viseconfig.DbConn
func SearchDomains() []string {
var ParsedDomains []string
SearchDomains := env.GetEnv("ALIAS_SEARCH_DOMAINS", defaultDomain)
SearchDomainList := strings.Split(env.GetEnv("ALIAS_SEARCH_DOMAINS", SearchDomains), ",")
for _, domain := range SearchDomainList {
ParsedDomains = append(ParsedDomains, strings.ReplaceAll(domain, " ", ""))
}
return ParsedDomains
}
func Language() string {
return viseconfig.DefaultLanguage
}

View File

@ -1,11 +1,11 @@
package debug
import (
"fmt"
"encoding/binary"
"fmt"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
visedb "git.defalsify.org/vise.git/db"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
)
var (
@ -32,18 +32,10 @@ func (k KeyInfo) String() string {
func ToKeyInfo(k []byte, sessionId string) (KeyInfo, error) {
o := KeyInfo{}
b := []byte(sessionId)
if len(k) <= len(b) {
return o, fmt.Errorf("storage key missing")
}
o.SessionId = sessionId
o.Typ = uint8(k[0])
k = k[1:]
o.SessionId = string(k[:len(b)])
k = k[len(b):]
if o.Typ == visedb.DATATYPE_USERDATA {
if len(k) == 0 {
@ -53,30 +45,19 @@ func ToKeyInfo(k []byte, sessionId string) (KeyInfo, error) {
o.SubTyp = storedb.DataTyp(v)
o.Label = subTypToString(o.SubTyp)
k = k[2:]
if len(k) != 0 {
return o, fmt.Errorf("excess key information: %x", k)
}
} else {
o.Label = typToString(o.Typ)
}
if len(k) != 0 {
return o, fmt.Errorf("excess key information")
k = k[2:]
}
return o, nil
}
func FromKey(k []byte) (KeyInfo, error) {
o := KeyInfo{}
if len(k) < 4 {
return o, fmt.Errorf("insufficient key length")
}
sessionIdBytes := k[1:len(k)-2]
return ToKeyInfo(k, string(sessionIdBytes))
}
func subTypToString(v storedb.DataTyp) string {
return dbTypStr[v + visedb.DATATYPE_USERDATA + 1]
return dbTypStr[v+visedb.DATATYPE_USERDATA+1]
}
func typToString(v uint8) string {

View File

@ -1,3 +1,4 @@
//go:build debugdb
// +build debugdb
package debug
@ -11,34 +12,37 @@ import (
func init() {
DebugCap |= 1
dbTypStr[db.DATATYPE_STATE] = "internal state"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_TRACKING_ID] = "tracking id"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_PUBLIC_KEY] = "public key"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_ACCOUNT_PIN] = "account pin"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_FIRST_NAME] = "first name"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_FAMILY_NAME] = "family name"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_YOB] = "year of birth"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_LOCATION] = "location"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_GENDER] = "gender"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_OFFERINGS] = "offerings"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_RECIPIENT] = "recipient"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_AMOUNT] = "amount"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_TEMPORARY_VALUE] = "temporary value"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_ACTIVE_SYM] = "active sym"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_ACTIVE_BAL] = "active bal"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_BLOCKED_NUMBER] = "blocked number"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_PUBLIC_KEY_REVERSE] = "public_key_reverse"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_ACTIVE_DECIMAL] = "active decimal"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_ACTIVE_ADDRESS] = "active address"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_VOUCHER_SYMBOLS] = "voucher symbols"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_VOUCHER_BALANCES] = "voucher balances"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_VOUCHER_DECIMALS] = "voucher decimals"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_VOUCHER_ADDRESSES] = "voucher addresses"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_TX_SENDERS] = "tx senders"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_TX_RECIPIENTS] = "tx recipients"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_TX_VALUES] = "tx values"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_TX_ADDRESSES] = "tx addresses"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_TX_HASHES] = "tx hashes"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_TX_DATES] = "tx dates"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_TX_SYMBOLS] = "tx symbols"
dbTypStr[db.DATATYPE_USERDATA + 1 + storedb.DATA_TX_DECIMALS] = "tx decimals"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_TRACKING_ID] = "tracking id"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_PUBLIC_KEY] = "public key"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_ACCOUNT_PIN] = "account pin"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_FIRST_NAME] = "first name"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_FAMILY_NAME] = "family name"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_YOB] = "year of birth"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_LOCATION] = "location"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_GENDER] = "gender"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_OFFERINGS] = "offerings"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_RECIPIENT] = "recipient"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_AMOUNT] = "amount"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_TEMPORARY_VALUE] = "temporary value"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_ACTIVE_SYM] = "active sym"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_ACTIVE_BAL] = "active bal"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_BLOCKED_NUMBER] = "blocked number"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_PUBLIC_KEY_REVERSE] = "public_key_reverse"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_ACTIVE_DECIMAL] = "active decimal"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_ACTIVE_ADDRESS] = "active address"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_INCORRECT_PIN_ATTEMPTS] = "incorrect pin attempts"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_SELECTED_LANGUAGE_CODE] = "selected language"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_INITIAL_LANGUAGE_CODE] = "initial language"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_VOUCHER_SYMBOLS] = "voucher symbols"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_VOUCHER_BALANCES] = "voucher balances"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_VOUCHER_DECIMALS] = "voucher decimals"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_VOUCHER_ADDRESSES] = "voucher addresses"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_TX_SENDERS] = "tx senders"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_TX_RECIPIENTS] = "tx recipients"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_TX_VALUES] = "tx values"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_TX_ADDRESSES] = "tx addresses"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_TX_HASHES] = "tx hashes"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_TX_DATES] = "tx dates"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_TX_SYMBOLS] = "tx symbols"
dbTypStr[db.DATATYPE_USERDATA+1+storedb.DATA_TX_DECIMALS] = "tx decimals"
}

View File

@ -3,14 +3,13 @@ package debug
import (
"testing"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
visedb "git.defalsify.org/vise.git/db"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
)
func TestDebugDbSubKeyInfo(t *testing.T) {
s := "foo"
b := []byte{0x20}
b = append(b, []byte(s)...)
b = append(b, []byte{0x00, 0x02}...)
r, err := ToKeyInfo(b, s)
if err != nil {
@ -25,7 +24,7 @@ func TestDebugDbSubKeyInfo(t *testing.T) {
if r.SubTyp != 2 {
t.Fatalf("expected 2, got %d", r.SubTyp)
}
if DebugCap & 1 > 0 {
if DebugCap&1 > 0 {
if r.Label != "tracking id" {
t.Fatalf("expected 'tracking id', got '%s'", r.Label)
}
@ -46,7 +45,7 @@ func TestDebugDbKeyInfo(t *testing.T) {
if r.Typ != 16 {
t.Fatalf("expected 16, got %d", r.Typ)
}
if DebugCap & 1 > 0 {
if DebugCap&1 > 0 {
if r.Label != "internal state" {
t.Fatalf("expected 'internal_state', got '%s'", r.Label)
}
@ -56,7 +55,6 @@ func TestDebugDbKeyInfo(t *testing.T) {
func TestDebugDbKeyInfoRestore(t *testing.T) {
s := "bar"
b := []byte{visedb.DATATYPE_USERDATA}
b = append(b, []byte(s)...)
k := storedb.ToBytes(storedb.DATA_ACTIVE_SYM)
b = append(b, k...)
@ -70,7 +68,7 @@ func TestDebugDbKeyInfoRestore(t *testing.T) {
if r.Typ != 32 {
t.Fatalf("expected 32, got %d", r.Typ)
}
if DebugCap & 1 > 0 {
if DebugCap&1 > 0 {
if r.Label != "active sym" {
t.Fatalf("expected 'active sym', got '%s'", r.Label)
}

View File

@ -10,9 +10,9 @@ import (
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
"git.grassecon.net/grassrootseconomics/sarafu-vise/internal/cmd"
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers/application"
"git.grassecon.net/grassrootseconomics/sarafu-vise/internal/cmd"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
)
var (
@ -23,24 +23,25 @@ var (
func main() {
config.LoadConfig()
override := config.NewOverride()
var sessionId string
var connStr string
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
flag.StringVar(&connStr, "c", "", "connection string")
flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(&override.ResourceConn, "resource", "?", "resource data directory")
flag.StringVar(&override.UserConn, "userdata", "?", "userdata store connection string")
flag.StringVar(&override.StateConn, "state", "?", "state store connection string")
flag.Parse()
if connStr == "" {
connStr = config.DbConn()
}
connData, err := storage.ToConnData(connStr)
config.Apply(override)
conns, err := config.GetConns()
if err != nil {
fmt.Fprintf(os.Stderr, "connstr err: %v\n", err)
fmt.Fprintf(os.Stderr, "conn specification error: %v\n", err)
os.Exit(1)
}
ctx := context.Background()
ctx = context.WithValue(ctx, "SessionId", sessionId)
pfp := path.Join(scriptDir, "pp.csv")
flagParser, err := application.NewFlagManager(pfp)
@ -49,16 +50,16 @@ func main() {
os.Exit(1)
}
x := cmd.NewCmd(connData, sessionId, flagParser)
x := cmd.NewCmd(sessionId, flagParser)
err = x.Parse(flag.Args())
if err != nil {
fmt.Fprintf(os.Stderr, "cmd parse fail: %v\n", err)
os.Exit(1)
}
logg.Infof("start command", "conn", connData, "subcmd", x)
logg.Infof("start command", "conn", conns, "subcmd", x)
menuStorageService := storage.NewMenuStorageService(connData, "")
menuStorageService := storage.NewMenuStorageService(conns)
if err != nil {
fmt.Fprintf(os.Stderr, "menu storage service error: %v\n", err)
os.Exit(1)

View File

@ -8,13 +8,12 @@ import (
"path"
"strings"
"git.defalsify.org/vise.git/logging"
"git.defalsify.org/vise.git/lang"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/visedriver/config"
)
const (
changeHeadSrc = `LOAD reset_account_authorized 0
LOAD reset_incorrect 0
CATCH incorrect_pin flag_incorrect_pin 1
@ -63,7 +62,7 @@ func main() {
}
logg.Tracef("using languages", "lang", config.Languages)
for i, v := range(config.Languages) {
for i, v := range config.Languages {
ln, err := lang.LanguageFromCode(v)
if err != nil {
fmt.Fprintf(os.Stderr, "error parsing language: %s\n", v)
@ -76,7 +75,7 @@ func main() {
incmps += fmt.Sprintf("INCMP %s %v\n", v, n)
p := path.Join(srcDir, v)
w, err := os.OpenFile(p, os.O_WRONLY | os.O_CREATE | os.O_EXCL, 0600)
w, err := os.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
if err != nil {
fmt.Fprintf(os.Stderr, "failed open language set template output: %v\n", err)
os.Exit(1)
@ -93,7 +92,7 @@ func main() {
src += "INCMP . *\n"
p := path.Join(srcDir, "select_language.vis")
w, err := os.OpenFile(p, os.O_WRONLY | os.O_CREATE | os.O_EXCL, 0600)
w, err := os.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
if err != nil {
fmt.Fprintf(os.Stderr, "failed open select language vis output: %v\n", err)
os.Exit(1)
@ -107,7 +106,7 @@ func main() {
src = changeHeadSrc + src
p = path.Join(srcDir, "change_language.vis")
w, err = os.OpenFile(p, os.O_WRONLY | os.O_CREATE | os.O_EXCL, 0600)
w, err = os.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
if err != nil {
fmt.Fprintf(os.Stderr, "failed open select language vis output: %v\n", err)
os.Exit(1)

View File

@ -7,11 +7,11 @@ import (
"os"
"path"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
"git.grassecon.net/grassrootseconomics/sarafu-vise/debug"
"git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config"
"git.grassecon.net/grassrootseconomics/sarafu-vise/debug"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
)
var (
@ -19,55 +19,58 @@ var (
scriptDir = path.Join("services", "registration")
)
func formatItem(k []byte, v []byte) (string, error) {
o, err := debug.FromKey(k)
func formatItem(k []byte, v []byte, sessionId string) (string, error) {
o, err := debug.ToKeyInfo(k, sessionId)
if err != nil {
return "", err
}
s := fmt.Sprintf("%vValue: %v\n\n", o, string(v))
s := fmt.Sprintf("%v\t%v\n", o.Label, string(v))
return s, nil
}
func main() {
config.LoadConfig()
var connStr string
override := config.NewOverride()
var sessionId string
var database string
var engineDebug bool
var err error
var first bool
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
flag.StringVar(&connStr, "c", ".state", "connection string")
flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(&override.ResourceConn, "resource", "?", "resource data directory")
flag.StringVar(&override.UserConn, "userdata", "?", "userdata store connection string")
flag.StringVar(&override.StateConn, "state", "?", "state store connection string")
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
flag.Parse()
if connStr != "" {
connStr = config.DbConn()
}
connData, err := storage.ToConnData(connStr)
config.Apply(override)
conns, err := config.GetConns()
if err != nil {
fmt.Fprintf(os.Stderr, "connstr err: %v", err)
fmt.Fprintf(os.Stderr, "conn specification error: %v\n", err)
os.Exit(1)
}
logg.Infof("start command", "conn", connData)
logg.Infof("start command", "conn", conns)
ctx := context.Background()
ctx = context.WithValue(ctx, "SessionId", sessionId)
ctx = context.WithValue(ctx, "Database", database)
resourceDir := scriptDir
menuStorageService := storage.NewMenuStorageService(connData, resourceDir)
menuStorageService := storage.NewMenuStorageService(conns)
store, err := menuStorageService.GetUserdataDb(ctx)
if err != nil {
fmt.Fprintf(os.Stderr, "get userdata db: %v\n", err.Error())
os.Exit(1)
}
store.SetSession(sessionId)
store.SetPrefix(db.DATATYPE_USERDATA)
d, err := store.Dump(ctx, []byte(sessionId))
d, err := store.Dump(ctx, []byte(""))
if err != nil {
fmt.Fprintf(os.Stderr, "store dump fail: %v\n", err.Error())
os.Exit(1)
@ -78,15 +81,19 @@ func main() {
if k == nil {
break
}
r, err := formatItem(k, v)
if !first {
fmt.Printf("Session ID: %s\n---\n", sessionId)
first = true
}
r, err := formatItem(append([]byte{db.DATATYPE_USERDATA}, k...), v, sessionId)
if err != nil {
fmt.Fprintf(os.Stderr, "format db item error: %v", err)
fmt.Fprintf(os.Stderr, "format db item error: %v\n", err)
os.Exit(1)
}
fmt.Printf(r)
}
err = store.Close()
err = store.Close(ctx)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)

View File

@ -1,86 +0,0 @@
package main
import (
"context"
"crypto/sha1"
"flag"
"fmt"
"os"
"path"
testdataloader "github.com/peteole/testdata-loader"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
)
var (
logg = logging.NewVanilla()
baseDir = testdataloader.GetBasePath()
scriptDir = path.Join("services", "registration")
)
func main() {
config.LoadConfig()
var connStr string
var sessionId string
var database string
var engineDebug bool
var err error
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
flag.StringVar(&connStr, "c", "", "connection string")
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
flag.Parse()
if connStr != "" {
connStr = config.DbConn()
}
connData, err := storage.ToConnData(connStr)
if err != nil {
fmt.Fprintf(os.Stderr, "connstr err: %v", err)
os.Exit(1)
}
logg.Infof("start command", "conn", connData)
ctx := context.Background()
ctx = context.WithValue(ctx, "SessionId", sessionId)
ctx = context.WithValue(ctx, "Database", database)
resourceDir := scriptDir
menuStorageService := storage.NewMenuStorageService(connData, resourceDir)
userDb, err := menuStorageService.GetUserdataDb(ctx)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
userStore := store.UserDataStore{userDb}
h := sha1.New()
h.Write([]byte(sessionId))
address := h.Sum(nil)
addressString := fmt.Sprintf("%x", address)
err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY, []byte(addressString))
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
err = userStore.WriteEntry(ctx, addressString, storedb.DATA_PUBLIC_KEY_REVERSE, []byte(sessionId))
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
err = userDb.Close()
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
}

10
go.mod
View File

@ -3,11 +3,11 @@ module git.grassecon.net/grassrootseconomics/sarafu-vise
go 1.23.4
require (
git.defalsify.org/vise.git v0.2.3-0.20250115000535-e2d329b3f739
git.grassecon.net/grassrootseconomics/common v0.0.0-20250113174703-6afccefd1f05
git.grassecon.net/grassrootseconomics/sarafu-api v0.0.0-20250115072214-bca7c5de969f
git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250115003256-c0534ede1b63
git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250113103030-f0b2056fd87d
git.defalsify.org/vise.git v0.2.3-0.20250205173834-d1f6647211ac
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/visedriver v0.9.0-beta.1.0.20250204132347-1eb0b1555244
git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694
github.com/alecthomas/assert/v2 v2.2.2
github.com/gofrs/uuid v4.4.0+incompatible
github.com/grassrootseconomics/ussd-data-service v1.2.0-beta

20
go.sum
View File

@ -1,13 +1,13 @@
git.defalsify.org/vise.git v0.2.3-0.20250115000535-e2d329b3f739 h1:w7pj1oh7jXrfajahVYU7m7AfHst4C6jNVzDVoaqJ7e8=
git.defalsify.org/vise.git v0.2.3-0.20250115000535-e2d329b3f739/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck=
git.grassecon.net/grassrootseconomics/common v0.0.0-20250113174703-6afccefd1f05 h1:BenzGx6aDHKDwE23/mWIFD2InYIXyzHroZWV3MF5WUk=
git.grassecon.net/grassrootseconomics/common v0.0.0-20250113174703-6afccefd1f05/go.mod h1:wgQJZGIS6QuNLHqDhcsvehsbn5PvgV7aziRebMnJi60=
git.grassecon.net/grassrootseconomics/sarafu-api v0.0.0-20250115072214-bca7c5de969f h1:FgccQi8vipX6dUt+GRiRDYHMR3UqC+plz73vw7y3fyU=
git.grassecon.net/grassrootseconomics/sarafu-api v0.0.0-20250115072214-bca7c5de969f/go.mod h1:tbA4whUGMUIDgQVdIW0sxWPuuXOvZRSny5zeku5hX4k=
git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250115003256-c0534ede1b63 h1:bX7klKZpX+ZZu1LKbtOXDAhV/KK0YwExehiIi0jusAM=
git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250115003256-c0534ede1b63/go.mod h1:Syw9TZyigPAM7t9FvicOm36iUnidt45f0SxzT2JniQ8=
git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250113103030-f0b2056fd87d h1:q/NO1rEgK3pia32D/tCq5hXfEuJp84COZRwceFvy/MM=
git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250113103030-f0b2056fd87d/go.mod h1:AH15xABcvaJr1TCGlih3oGSuwWC0E5IdbHQwuu+E1KI=
git.defalsify.org/vise.git v0.2.3-0.20250205173834-d1f6647211ac h1:f/E0ZTclVfMEnD/3Alrzzbg+dOm138zGydV42jT0JPw=
git.defalsify.org/vise.git v0.2.3-0.20250205173834-d1f6647211ac/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/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.20250206112944-31eb30de0f69/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/visedriver v0.9.0-beta.1.0.20250204132347-1eb0b1555244/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/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/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
github.com/alecthomas/participle/v2 v2.0.0 h1:Fgrq+MbuSsJwIkw3fEj9h75vDP0Er5JzepJ0/HNHv0g=

View File

@ -23,7 +23,9 @@ import (
"git.grassecon.net/grassrootseconomics/common/person"
"git.grassecon.net/grassrootseconomics/common/phone"
"git.grassecon.net/grassrootseconomics/common/pin"
"git.grassecon.net/grassrootseconomics/sarafu-api/models"
"git.grassecon.net/grassrootseconomics/sarafu-api/remote"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config"
"git.grassecon.net/grassrootseconomics/sarafu-vise/profile"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
@ -100,14 +102,12 @@ func NewMenuHandlers(appFlags *FlagManager, userdataStore db.Db, accountService
return h, nil
}
// WithPersister sets persister instance to the handlers.
// func (h *MenuHandlers) WithPersister(pe *persist.Persister) *MenuHandlers {
// SetPersister sets persister instance to the handlers.
func (h *MenuHandlers) SetPersister(pe *persist.Persister) {
if h.pe != nil {
panic("persister already set")
}
h.pe = pe
//return h
}
// Init initializes the handler for a new session.
@ -123,12 +123,6 @@ func (h *MenuHandlers) Init(ctx context.Context, sym string, input []byte) (reso
h.st = h.pe.GetState()
h.ca = h.pe.GetMemory()
if len(input) == 0 {
// move to the top node
h.st.Code = []byte{}
}
sessionId, ok := ctx.Value("SessionId").(string)
if ok {
ctx = context.WithValue(ctx, "SessionId", sessionId)
@ -324,6 +318,7 @@ func (h *MenuHandlers) VerifyNewPin(ctx context.Context, sym string, input []byt
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) {
@ -331,6 +326,9 @@ func (h *MenuHandlers) VerifyNewPin(ctx context.Context, sym string, input []byt
} else {
res.FlagReset = append(res.FlagReset, flag_valid_pin)
}
} else {
res.FlagSet = append(res.FlagSet, flag_valid_pin)
}
return res, nil
}
@ -386,6 +384,12 @@ func (h *MenuHandlers) SaveOthersTemporaryPin(ctx context.Context, sym string, i
}
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 {
@ -418,6 +422,11 @@ func (h *MenuHandlers) CheckBlockedNumPinMisMatch(ctx context.Context, sym strin
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)
@ -431,6 +440,11 @@ func (h *MenuHandlers) CheckBlockedNumPinMisMatch(ctx context.Context, sym strin
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 {
@ -448,12 +462,21 @@ func (h *MenuHandlers) ConfirmPinChange(ctx context.Context, sym string, input [
}
flag_pin_mismatch, _ := h.flagManager.GetFlag("flag_pin_mismatch")
if string(input) == "0" {
res.FlagReset = append(res.FlagReset, flag_pin_mismatch)
return res, nil
}
store := h.userdataStore
hashedTemporaryPin, err := store.ReadEntry(ctx, sessionId, 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)
@ -488,13 +511,17 @@ 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)
return res, err
}
hashedTmporaryPin, err := store.ReadEntry(ctx, string(blockedPhonenumber), storedb.DATA_TEMPORARY_VALUE)
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(hashedTmporaryPin))
err = store.WriteEntry(ctx, string(blockedPhonenumber), storedb.DATA_ACCOUNT_PIN, []byte(hashedTemporaryPin))
if err != nil {
return res, err
}
@ -579,12 +606,21 @@ func (h *MenuHandlers) ValidateBlockedNumber(ctx context.Context, sym string, in
if !ok {
return res, fmt.Errorf("missing session")
}
blockedNumber := string(input)
_, err = store.ReadEntry(ctx, blockedNumber, storedb.DATA_PUBLIC_KEY)
if !phone.IsValidPhoneNumber(blockedNumber) {
res.FlagSet = append(res.FlagSet, flag_unregistered_number)
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")
@ -595,7 +631,7 @@ func (h *MenuHandlers) ValidateBlockedNumber(ctx context.Context, sym string, in
return res, err
}
}
err = store.WriteEntry(ctx, sessionId, storedb.DATA_BLOCKED_NUMBER, []byte(blockedNumber))
err = store.WriteEntry(ctx, sessionId, storedb.DATA_BLOCKED_NUMBER, []byte(formattedNumber))
if err != nil {
return res, nil
}
@ -622,6 +658,11 @@ func (h *MenuHandlers) VerifyCreatePin(ctx context.Context, sym string, input []
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.FlagSet = []uint32{flag_valid_pin}
res.FlagReset = []uint32{flag_pin_mismatch}
@ -657,11 +698,19 @@ func (h *MenuHandlers) SaveFirstname(ctx context.Context, sym string, input []by
firstNameSet := h.st.MatchFlag(flag_firstname_set, true)
if allowUpdate {
temporaryFirstName, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if len(temporaryFirstName) == 0 {
logg.ErrorCtxf(ctx, "temporaryFirstName is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
err = store.WriteEntry(ctx, sessionId, storedb.DATA_FIRST_NAME, []byte(temporaryFirstName))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write firstName entry with", "key", storedb.DATA_FIRST_NAME, "value", temporaryFirstName, "error", err)
return res, err
}
err := h.constructAccountAlias(ctx)
if err != nil {
return res, err
}
res.FlagSet = append(res.FlagSet, flag_firstname_set)
} else {
if firstNameSet {
@ -697,6 +746,10 @@ func (h *MenuHandlers) SaveFamilyname(ctx context.Context, sym string, input []b
if allowUpdate {
temporaryFamilyName, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if len(temporaryFamilyName) == 0 {
logg.ErrorCtxf(ctx, "temporaryFamilyName is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
err = store.WriteEntry(ctx, sessionId, storedb.DATA_FAMILY_NAME, []byte(temporaryFamilyName))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write familyName entry with", "key", storedb.DATA_FAMILY_NAME, "value", temporaryFamilyName, "error", err)
@ -767,6 +820,10 @@ func (h *MenuHandlers) SaveYob(ctx context.Context, sym string, input []byte) (r
if allowUpdate {
temporaryYob, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if len(temporaryYob) == 0 {
logg.ErrorCtxf(ctx, "temporaryYob is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
err = store.WriteEntry(ctx, sessionId, storedb.DATA_YOB, []byte(temporaryYob))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write yob entry with", "key", storedb.DATA_TEMPORARY_VALUE, "value", temporaryYob, "error", err)
@ -806,6 +863,10 @@ func (h *MenuHandlers) SaveLocation(ctx context.Context, sym string, input []byt
if allowUpdate {
temporaryLocation, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if len(temporaryLocation) == 0 {
logg.ErrorCtxf(ctx, "temporaryLocation is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
err = store.WriteEntry(ctx, sessionId, storedb.DATA_LOCATION, []byte(temporaryLocation))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write location entry with", "key", storedb.DATA_LOCATION, "value", temporaryLocation, "error", err)
@ -847,6 +908,10 @@ func (h *MenuHandlers) SaveGender(ctx context.Context, sym string, input []byte)
if allowUpdate {
temporaryGender, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if len(temporaryGender) == 0 {
logg.ErrorCtxf(ctx, "temporaryGender is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
err = store.WriteEntry(ctx, sessionId, storedb.DATA_GENDER, []byte(temporaryGender))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write gender entry with", "key", storedb.DATA_GENDER, "value", gender, "error", err)
@ -888,6 +953,10 @@ func (h *MenuHandlers) SaveOfferings(ctx context.Context, sym string, input []by
if allowUpdate {
temporaryOfferings, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if len(temporaryOfferings) == 0 {
logg.ErrorCtxf(ctx, "temporaryOfferings is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
err = store.WriteEntry(ctx, sessionId, storedb.DATA_OFFERINGS, []byte(temporaryOfferings))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write offerings entry with", "key", storedb.DATA_TEMPORARY_VALUE, "value", offerings, "error", err)
@ -1076,6 +1145,11 @@ func (h *MenuHandlers) GetProfileInfo(ctx context.Context, sym string, input []b
gender := getEntryOrDefault(store.ReadEntry(ctx, sessionId, storedb.DATA_GENDER))
location := getEntryOrDefault(store.ReadEntry(ctx, sessionId, storedb.DATA_LOCATION))
offerings := getEntryOrDefault(store.ReadEntry(ctx, sessionId, storedb.DATA_OFFERINGS))
alias := getEntryOrDefault(store.ReadEntry(ctx, sessionId, storedb.DATA_ACCOUNT_ALIAS))
if alias != defaultValue {
alias = strings.Split(alias, ".")[0]
}
// Construct the full name
name := person.ConstructName(firstName, familyName, defaultValue)
@ -1092,18 +1166,18 @@ func (h *MenuHandlers) GetProfileInfo(ctx context.Context, sym string, input []b
switch language.Code {
case "eng":
res.Content = fmt.Sprintf(
"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n",
name, gender, age, location, offerings,
"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\nYour alias: %s\n",
name, gender, age, location, offerings, alias,
)
case "swa":
res.Content = fmt.Sprintf(
"Jina: %s\nJinsia: %s\nUmri: %s\nEneo: %s\nUnauza: %s\n",
name, gender, age, location, offerings,
"Jina: %s\nJinsia: %s\nUmri: %s\nEneo: %s\nUnauza: %s\nLakabu yako: %s\n",
name, gender, age, location, offerings, alias,
)
default:
res.Content = fmt.Sprintf(
"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n",
name, gender, age, location, offerings,
"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\nYour alias: %s\n",
name, gender, age, location, offerings, alias,
)
}
@ -1159,6 +1233,10 @@ func (h *MenuHandlers) UpdateAllProfileItems(ctx context.Context, sym string, in
if err != nil {
return res, err
}
err = h.constructAccountAlias(ctx)
if err != nil {
return res, err
}
return res, nil
}
@ -1204,7 +1282,9 @@ func (h *MenuHandlers) Authorize(ctx context.Context, sym string, input []byte)
logg.ErrorCtxf(ctx, "failed to read AccountPin entry with", "key", storedb.DATA_ACCOUNT_PIN, "error", err)
return res, err
}
if len(input) == 4 {
str := string(input)
_, err = strconv.Atoi(str)
if len(input) == 4 && err == nil {
if pin.VerifyPIN(string(AccountPin), string(input)) {
if h.st.MatchFlag(flag_account_authorized, false) {
res.FlagReset = append(res.FlagReset, flag_incorrect_pin)
@ -1222,7 +1302,7 @@ func (h *MenuHandlers) Authorize(ctx context.Context, sym string, input []byte)
}
}
} else {
err := h.incrementIncorrectPINAttempts(ctx, sessionId)
err = h.incrementIncorrectPINAttempts(ctx, sessionId)
if err != nil {
return res, err
}
@ -1239,11 +1319,13 @@ func (h *MenuHandlers) Authorize(ctx context.Context, sym string, input []byte)
// Setback sets the flag_back_set flag when the navigation is back.
func (h *MenuHandlers) SetBack(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
flag_back_set, _ := h.flagManager.GetFlag("flag_back_set")
//TODO:
//Add check if the navigation is lateral nav instead of checking the input.
if string(input) == "0" {
flag_back_set, _ := h.flagManager.GetFlag("flag_back_set")
res.FlagSet = append(res.FlagSet, flag_back_set)
} else {
res.FlagReset = append(res.FlagReset, flag_back_set)
}
return res, nil
}
@ -1399,16 +1481,16 @@ func (h *MenuHandlers) FetchCommunityBalance(ctx context.Context, sym string, in
// TODO: split up functino
func (h *MenuHandlers) ValidateRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
var AliasAddressResult string
var AliasAddress *models.AliasAddress
store := h.userdataStore
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
flag_invalid_recipient, _ := h.flagManager.GetFlag("flag_invalid_recipient")
flag_invalid_recipient_with_invite, _ := h.flagManager.GetFlag("flag_invalid_recipient_with_invite")
flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error")
recipient := string(input)
@ -1468,21 +1550,36 @@ func (h *MenuHandlers) ValidateRecipient(ctx context.Context, sym string, input
}
case "alias":
// Call the API to validate and retrieve the address for the alias
r, aliasErr := h.accountService.CheckAliasAddress(ctx, recipient)
if aliasErr != nil {
res.FlagSet = append(res.FlagSet, flag_api_error)
if strings.Contains(recipient, ".") {
AliasAddress, err = h.accountService.CheckAliasAddress(ctx, recipient)
if err == nil {
AliasAddressResult = AliasAddress.Address
} else {
logg.ErrorCtxf(ctx, "failed to resolve alias", "alias", recipient, "error_alias_check", err)
}
} else {
//Perform a search for each search domain,break on first match
for _, domain := range config.SearchDomains() {
fqdn := fmt.Sprintf("%s.%s", recipient, domain)
AliasAddress, err = h.accountService.CheckAliasAddress(ctx, fqdn)
if err == nil {
AliasAddressResult = AliasAddress.Address
continue
} else {
logg.ErrorCtxf(ctx, "failed to resolve alias", "alias", recipient, "error_alias_check", err)
}
}
}
if AliasAddressResult == "" {
res.Content = recipient
logg.ErrorCtxf(ctx, "failed on CheckAliasAddress", "error", aliasErr)
res.FlagSet = append(res.FlagSet, flag_invalid_recipient)
return res, nil
} else {
err = store.WriteEntry(ctx, sessionId, storedb.DATA_RECIPIENT, []byte(AliasAddressResult))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write recipient entry with", "key", storedb.DATA_RECIPIENT, "value", AliasAddressResult, "error", err)
return res, err
}
// Alias validation succeeded, save the Ethereum address
err = store.WriteEntry(ctx, sessionId, storedb.DATA_RECIPIENT, []byte(r.Address))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write recipient entry with", "key", storedb.DATA_RECIPIENT, "value", r.Address, "error", err)
return res, err
}
}
}
@ -1534,6 +1631,10 @@ func (h *MenuHandlers) InviteValidRecipient(ctx context.Context, sym string, inp
l.AddDomain("default")
recipient, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if len(recipient) == 0 {
logg.ErrorCtxf(ctx, "recipient is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
// TODO
// send an invitation SMS
@ -1652,6 +1753,10 @@ func (h *MenuHandlers) GetRecipient(ctx context.Context, sym string, input []byt
}
store := h.userdataStore
recipient, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if len(recipient) == 0 {
logg.ErrorCtxf(ctx, "recipient is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
res.Content = string(recipient)
@ -2015,7 +2120,6 @@ func (h *MenuHandlers) GetVoucherDetails(ctx context.Context, sym string, input
if !ok {
return res, fmt.Errorf("missing session")
}
flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error")
// get the active address
@ -2211,6 +2315,7 @@ func (h *MenuHandlers) ViewTransactionStatement(ctx context.Context, sym string,
return res, nil
}
// persistInitialLanguageCode receives an initial language code and persists it to the store
func (h *MenuHandlers) persistInitialLanguageCode(ctx context.Context, sessionId string, code string) error {
store := h.userdataStore
_, err := store.ReadEntry(ctx, sessionId, storedb.DATA_INITIAL_LANGUAGE_CODE)
@ -2242,3 +2347,68 @@ func (h *MenuHandlers) persistLanguageCode(ctx context.Context, code string) err
}
return h.persistInitialLanguageCode(ctx, sessionId, code)
}
// constructAccountAlias retrieves and alias based on the first and family name
// and writes the result in DATA_ACCOUNT_ALIAS
func (h *MenuHandlers) constructAccountAlias(ctx context.Context) error {
var alias string
store := h.userdataStore
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return fmt.Errorf("missing session")
}
firstName, err := store.ReadEntry(ctx, sessionId, storedb.DATA_FIRST_NAME)
if err != nil {
if db.IsNotFound(err) {
return nil
}
return err
}
familyName, err := store.ReadEntry(ctx, sessionId, storedb.DATA_FAMILY_NAME)
if err != nil {
if db.IsNotFound(err) {
return nil
}
return err
}
pubKey, err := store.ReadEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY)
if err != nil {
if db.IsNotFound(err) {
return nil
}
return err
}
aliasInput := fmt.Sprintf("%s%s", firstName, familyName)
aliasResult, err := h.accountService.RequestAlias(ctx, string(pubKey), aliasInput)
if err != nil {
logg.ErrorCtxf(ctx, "failed to retrieve alias", "alias", aliasInput, "error_alias_request", err)
return fmt.Errorf("Failed to retrieve alias: %s", err.Error())
}
alias = aliasResult.Alias
//Store the alias
err = store.WriteEntry(ctx, sessionId, storedb.DATA_ACCOUNT_ALIAS, []byte(alias))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write account alias", "key", storedb.DATA_ACCOUNT_ALIAS, "value", alias, "error", err)
return err
}
return nil
}
// ClearTemporaryValue empties the DATA_TEMPORARY_VALUE at the main menu to prevent
// previously stored data from being accessed
func (h *MenuHandlers) ClearTemporaryValue(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
// clear the temporary value at the start
err := userStore.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(""))
if err != nil {
logg.ErrorCtxf(ctx, "failed to clear DATA_TEMPORARY_VALUE entry with", "key", storedb.DATA_TEMPORARY_VALUE, "value", "empty", "error", err)
return res, err
}
return res, nil
}

File diff suppressed because it is too large Load Diff

View File

@ -35,13 +35,6 @@ func (eu *EventsUpdater) HandleCustodialRegistration(ctx context.Context, ev *ap
if err != nil {
return err
}
// err = pe.Load(identity.SessionId)
// if err != nil {
// return err
// }
// st := pe.GetState()
// st.SetFlag(accountCreatedFlag)
// return pe.Save(identity.SessionId)
logg.DebugCtxf(ctx, "received custodial registration event", "identity", identity)
return nil
}

View File

@ -4,12 +4,12 @@ import (
"context"
"fmt"
"git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store"
"git.grassecon.net/grassrootseconomics/sarafu-api/remote"
"git.defalsify.org/vise.git/persist"
apievent "git.grassecon.net/grassrootseconomics/sarafu-api/event"
"git.grassecon.net/grassrootseconomics/sarafu-api/remote"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
)
var (

View File

@ -6,10 +6,10 @@ import (
"strings"
"git.defalsify.org/vise.git/db"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"git.grassecon.net/grassrootseconomics/common/identity"
apievent "git.grassecon.net/grassrootseconomics/sarafu-api/event"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
)
// execute all
@ -47,7 +47,6 @@ func (eu *EventsUpdater) updateToken(ctx context.Context, identity identity.Iden
return nil
}
// set default token to given symbol.
func (eu *EventsUpdater) updateDefaultToken(ctx context.Context, identity identity.Identity, userStore *store.UserDataStore, activeSym string) error {
pfxDb := toPrefixDb(userStore, identity.SessionId)
@ -59,7 +58,6 @@ func (eu *EventsUpdater) updateDefaultToken(ctx context.Context, identity identi
return store.UpdateVoucherData(ctx, userStore, identity.SessionId, tokenData)
}
// handle token transfer.
//
// if from and to are NOT the same, handle code will be executed once for each side of the transfer.
@ -189,7 +187,7 @@ func (eu *EventsUpdater) updateTokenTransferList(ctx context.Context, identity i
return err
}
for i, tx := range(txs) {
for i, tx := range txs {
r = append(r, eu.formatFunc(apievent.EventTokenTransferTag, i, tx))
}

View File

@ -6,6 +6,7 @@ import (
"git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/logging"
"git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/resource"
@ -13,6 +14,10 @@ import (
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers/application"
)
var (
logg = logging.NewVanilla().WithDomain("sarafu-vise.engine")
)
type HandlerService interface {
GetHandler() (*application.MenuHandlers, error)
}
@ -24,6 +29,7 @@ type LocalHandlerService struct {
UserdataStore *db.Db
Cfg engine.Config
Rs resource.Resource
first resource.EntryFunc
}
func NewLocalHandlerService(ctx context.Context, fp string, debug bool, dbResource *resource.DbResource, cfg engine.Config, rs resource.Resource) (*LocalHandlerService, error) {
@ -60,7 +66,6 @@ func (ls *LocalHandlerService) GetHandler(accountService remote.AccountService)
if err != nil {
return nil, err
}
//appHandlers = appHandlers.WithPersister(ls.Pe)
appHandlers.SetPersister(ls.Pe)
ls.DbRs.AddLocalFunc("check_blocked_status", appHandlers.CheckBlockedStatus)
ls.DbRs.AddLocalFunc("set_language", appHandlers.SetLanguage)
@ -118,13 +123,20 @@ func (ls *LocalHandlerService) GetHandler(accountService remote.AccountService)
ls.DbRs.AddLocalFunc("update_all_profile_items", appHandlers.UpdateAllProfileItems)
ls.DbRs.AddLocalFunc("set_back", appHandlers.SetBack)
ls.DbRs.AddLocalFunc("show_blocked_account", appHandlers.ShowBlockedAccount)
ls.DbRs.AddLocalFunc("clear_temporary_value", appHandlers.ClearTemporaryValue)
ls.first = appHandlers.Init
return appHandlers, nil
}
// TODO: enable setting of sessionId on engine init time
func (ls *LocalHandlerService) GetEngine() *engine.DefaultEngine {
en := engine.NewEngine(ls.Cfg, ls.Rs)
en = en.WithPersister(ls.Pe)
func (ls *LocalHandlerService) GetEngine(cfg engine.Config, rs resource.Resource, pr *persist.Persister) engine.Engine {
en := engine.NewEngine(cfg, rs)
if ls.first != nil {
en = en.WithFirst(ls.first)
}
en = en.WithPersister(pr)
if cfg.EngineDebug {
en = en.WithDebug(nil)
}
return en
}

View File

@ -5,8 +5,8 @@ import (
"fmt"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers/application"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
)
var (
@ -22,9 +22,8 @@ type Cmd struct {
exec func(ctx context.Context, ss storage.StorageService) error
}
func NewCmd(conn storage.ConnData, sessionId string, flagParser *application.FlagManager) *Cmd {
func NewCmd(sessionId string, flagParser *application.FlagManager) *Cmd {
return &Cmd{
conn: conn,
sessionId: sessionId,
flagParser: flagParser,
}
@ -95,5 +94,3 @@ func (c *Cmd) Parse(args []string) error {
return fmt.Errorf("unknown subcommand: %s", cmd)
}

View File

@ -1,5 +1,67 @@
{
"groups": [
{
"name": "main_my_vouchers_select_voucher_using_index",
"steps": [
{
"input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
},
{
"input": "2",
"expectedContent": "My vouchers\n1:Select voucher\n2:Voucher details\n0:Back"
},
{
"input": "1",
"expectedContent": "Select number or symbol from your vouchers:\n1SRF\n0:Back\n99:Quit"
},
{
"input": "",
"expectedContent": "Select number or symbol from your vouchers:\n1SRF\n0:Back\n99:Quit"
},
{
"input": "1",
"expectedContent": "Enter PIN to confirm selection:\nSymbol: SRF\nBalance: 2.745987\n0:Back\n9:Quit"
},
{
"input": "1234",
"expectedContent": "Success! SRF is now your active voucher.\n0:Back\n9:Quit"
},
{
"input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
}
]
},
{
"name": "main_my_vouchers_select_voucher_using_symbol",
"steps": [
{
"input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
},
{
"input": "2",
"expectedContent": "My vouchers\n1:Select voucher\n2:Voucher details\n0:Back"
},
{
"input": "1",
"expectedContent": "Select number or symbol from your vouchers:\n1SRF\n0:Back\n99:Quit"
},
{
"input": "SRF",
"expectedContent": "Enter PIN to confirm selection:\nSymbol: SRF\nBalance: 2.745987\n0:Back\n9:Quit"
},
{
"input": "1234",
"expectedContent": "Success! SRF is now your active voucher.\n0:Back\n9:Quit"
},
{
"input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
}
]
},
{
"name": "my_account_change_pin",
"steps": [
@ -48,13 +110,17 @@
"input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back"
},
{
"input": "",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back"
},
{
"input": "2",
"expectedContent": "Please enter your PIN:"
},
{
"input": "1235",
"expectedContent": "Incorrect PIN. You have: 2 remaining attempt(s).\n1:Retry\n9:Quit"
"expectedContent": "Incorrect PIN. You have: {attempts} remaining attempt(s).\n1:Retry\n9:Quit"
},
{
"input": "1",
@ -74,6 +140,121 @@
}
]
},
{
"name": "menu_my_account_reset_others_pin_with_unregistered_number",
"steps": [
{
"input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
},
{
"input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back"
},
{
"input": "5",
"expectedContent": "PIN Management\n1:Change PIN\n2:Reset other's PIN\n0:Back"
},
{
"input": "2",
"expectedContent": "Enter other's phone number:\n0:Back"
},
{
"input": "0700000001",
"expectedContent": "The number you have entered is either not registered with Sarafu or is invalid.\n1:Retry\n9:Quit"
},
{
"input": "1",
"expectedContent": "Enter other's phone number:\n0:Back"
},
{
"input": "0",
"expectedContent": "PIN Management\n1:Change PIN\n2:Reset other's PIN\n0:Back"
},
{
"input": "0",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back"
},
{
"input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
}
]
},
{
"name": "menu_my_account_reset_others_pin_with_registered_number",
"steps": [
{
"input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
},
{
"input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back"
},
{
"input": "5",
"expectedContent": "PIN Management\n1:Change PIN\n2:Reset other's PIN\n0:Back"
},
{
"input": "2",
"expectedContent": "Enter other's phone number:\n0:Back"
},
{
"input": "0700000000",
"expectedContent": "Please enter new PIN for: {secondary_session_id}\n0:Back"
},
{
"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",
"expectedContent": "PIN reset request for {secondary_session_id} was successful\n0:Back\n9:Quit"
},
{
"input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
}
]
},
{
"name": "menu_my_account_reset_others_pin_with_no_privileges",
"steps": [
{
"input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
},
{
"input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back"
},
{
"input": "5",
"expectedContent": "PIN Management\n1:Change PIN\n2:Reset other's PIN\n0:Back"
},
{
"input": "2",
"expectedContent": "You do not have privileges to perform this action\n\n9:Quit\n0:Back"
},
{
"input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
}
]
},
{
"name": "menu_my_account_check_my_balance",
"steps": [
@ -95,7 +276,7 @@
},
{
"input": "1235",
"expectedContent": "Incorrect PIN. You have: 2 remaining attempt(s).\n1:Retry\n9:Quit"
"expectedContent": "Incorrect PIN. You have: {attempts} remaining attempt(s).\n1:Retry\n9:Quit"
},
{
"input": "1",
@ -140,7 +321,7 @@
},
{
"input": "1235",
"expectedContent": "Incorrect PIN. You have: 2 remaining attempt(s).\n1:Retry\n9:Quit"
"expectedContent": "Incorrect PIN. You have: {attempts} remaining attempt(s).\n1:Retry\n9:Quit"
},
{
"input": "1",
@ -277,6 +458,10 @@
"input": "3",
"expectedContent": "Select gender: \n1:Male\n2:Female\n3:Unspecified\n0:Back"
},
{
"input": "",
"expectedContent": "Select gender: \n1:Male\n2:Female\n3:Unspecified\n0:Back"
},
{
"input": "1",
"expectedContent": "Please enter your PIN:"
@ -427,7 +612,7 @@
},
{
"input": "1234",
"expectedContent": "My profile:\nName: foo bar\nGender: male\nAge: 80\nLocation: Kilifi\nYou provide: Bananas\n\n0:Back\n9:Quit"
"expectedContent": "My profile:\nName: foo bar\nGender: male\nAge: 80\nLocation: Kilifi\nYou provide: Bananas\nYour alias: \n\n0:Back\n9:Quit"
},
{
"input": "0",
@ -438,6 +623,47 @@
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
}
]
},
{
"name": "menu_block_account_via_view_profile",
"steps": [
{
"input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
},
{
"input": "3",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back"
},
{
"input": "1",
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
},
{
"input": "7",
"expectedContent": "Please enter your PIN:"
},
{
"input": "1254",
"expectedContent": "Incorrect PIN. You have: {attempts} remaining attempt(s).\n1:Retry\n9:Quit"
},
{
"input": "1",
"expectedContent": "Please enter your PIN:"
},
{
"input": "1254",
"expectedContent": "Incorrect PIN. You have: {attempts} remaining attempt(s).\n1:Retry\n9:Quit"
},
{
"input": "1",
"expectedContent": "Please enter your PIN:"
},
{
"input": "1254",
"expectedContent": "Your account has been locked. For help on how to unblock your account, contact support at: 0757628885"
}
]
}
]
}

View File

@ -9,22 +9,22 @@ import (
"regexp"
"testing"
"github.com/gofrs/uuid"
"git.grassecon.net/grassrootseconomics/visedriver/testutil/driver"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/sarafu-vise/testutil"
"git.grassecon.net/grassrootseconomics/visedriver/testutil/driver"
"github.com/gofrs/uuid"
)
var (
logg = logging.NewVanilla().WithDomain("menutraversaltest")
testData = driver.ReadData()
sessionID string
src = rand.NewSource(42)
g = rand.New(src)
secondarySessionId = "+254700000000"
)
var groupTestFile = flag.String("test-file", "group_test.json", "The test file to use for running the group tests")
var database = flag.String("db", "gdbm", "Specify the database (gdbm or postgres)")
var connStr = flag.String("conn", ".test_state", "connection string")
var dbSchema = flag.String("schema", "test", "Specify the database schema (default test)")
func GenerateSessionId() string {
uu := uuid.NewGenWithOptions(uuid.WithRandomReader(g))
@ -68,6 +68,16 @@ func extractMaxAmount(response []byte) string {
return ""
}
func extractRemainingAttempts(response []byte) string {
// Regex to match "You have: <number> remaining attempt(s)"
re := regexp.MustCompile(`(?m)You have:\s+(\d+)\s+remaining attempt\(s\)`)
match := re.FindSubmatch(response)
if match != nil {
return string(match[1]) // "<number>" of remaining attempts
}
return ""
}
// Extracts the send amount value from the engine response.
func extractSendAmount(response []byte) string {
// Regex to match the pattern "will receive X.XX SYM from"
@ -80,12 +90,7 @@ func extractSendAmount(response []byte) string {
}
func TestMain(m *testing.M) {
// Parse the flags
flag.Parse()
sessionID = GenerateSessionId()
// set the db
testutil.SetDatabase(*database, *connStr, *dbSchema)
// Cleanup the db after tests
defer testutil.CleanDatabase()
@ -93,14 +98,51 @@ func TestMain(m *testing.M) {
}
func TestAccountCreationSuccessful(t *testing.T) {
en, fn, eventChannel := testutil.TestEngine(sessionID)
en, fn, eventChannel, _, _ := testutil.TestEngine(sessionID)
defer fn()
ctx := context.Background()
sessions := testData
for _, session := range sessions {
groups := driver.FilterGroupsByName(session.Groups, "account_creation_successful")
for _, group := range groups {
for _, step := range group.Steps {
for i, step := range group.Steps {
logg.TraceCtxf(ctx, "executing step", "i", i, "step", step)
cont, err := en.Exec(ctx, []byte(step.Input))
if err != nil {
t.Fatalf("Test case '%s' failed at input '%s': %v", group.Name, step.Input, err)
}
if !cont {
break
}
w := bytes.NewBuffer(nil)
_, err = en.Flush(ctx, w)
if err != nil {
t.Fatalf("Test case '%s' failed during Flush: %v", group.Name, err)
}
b := w.Bytes()
match, err := step.MatchesExpectedContent(b)
if err != nil {
t.Fatalf("Error compiling regex for step '%s': %v", step.Input, err)
}
if !match {
t.Fatalf("expected:\n\t%s\ngot:\n\t%s\n", step.ExpectedContent, b)
}
}
}
}
<-eventChannel
}
func TestSecondaryAccount(t *testing.T) {
en, fn, eventChannel, _, _ := testutil.TestEngine(secondarySessionId)
defer fn()
ctx := context.Background()
sessions := testData
for _, session := range sessions {
groups := driver.FilterGroupsByName(session.Groups, "account_creation_successful")
for _, group := range groups {
for i, step := range group.Steps {
logg.TraceCtxf(ctx, "executing step", "i", i, "step", step)
cont, err := en.Exec(ctx, []byte(step.Input))
if err != nil {
t.Fatalf("Test case '%s' failed at input '%s': %v", group.Name, step.Input, err)
@ -135,14 +177,15 @@ func TestAccountRegistrationRejectTerms(t *testing.T) {
t.Fail()
}
edgeCaseSessionID := v.String()
en, fn, _ := testutil.TestEngine(edgeCaseSessionID)
en, fn, _, _, _ := testutil.TestEngine(edgeCaseSessionID)
defer fn()
ctx := context.Background()
sessions := testData
for _, session := range sessions {
groups := driver.FilterGroupsByName(session.Groups, "account_creation_reject_terms")
for _, group := range groups {
for _, step := range group.Steps {
for i, step := range group.Steps {
logg.TraceCtxf(ctx, "executing step", "i", i, "step", step)
cont, err := en.Exec(ctx, []byte(step.Input))
if err != nil {
t.Fatalf("Test case '%s' failed at input '%s': %v", group.Name, step.Input, err)
@ -170,14 +213,15 @@ func TestAccountRegistrationRejectTerms(t *testing.T) {
}
func TestMainMenuHelp(t *testing.T) {
en, fn, _ := testutil.TestEngine(sessionID)
en, fn, _, _, _ := testutil.TestEngine(sessionID)
defer fn()
ctx := context.Background()
sessions := testData
for _, session := range sessions {
groups := driver.FilterGroupsByName(session.Groups, "main_menu_help")
for _, group := range groups {
for _, step := range group.Steps {
for i, step := range group.Steps {
logg.TraceCtxf(ctx, "executing step", "i", i, "step", step)
cont, err := en.Exec(ctx, []byte(step.Input))
if err != nil {
t.Fatalf("Test case '%s' failed at input '%s': %v", group.Name, step.Input, err)
@ -211,7 +255,7 @@ func TestMainMenuHelp(t *testing.T) {
}
func TestMainMenuQuit(t *testing.T) {
en, fn, _ := testutil.TestEngine(sessionID)
en, fn, _, _, _ := testutil.TestEngine(sessionID)
defer fn()
ctx := context.Background()
sessions := testData
@ -252,7 +296,7 @@ func TestMainMenuQuit(t *testing.T) {
}
func TestMyAccount_MyAddress(t *testing.T) {
en, fn, _ := testutil.TestEngine(sessionID)
en, fn, _, _, _ := testutil.TestEngine(sessionID)
defer fn()
ctx := context.Background()
sessions := testData
@ -296,7 +340,7 @@ func TestMyAccount_MyAddress(t *testing.T) {
}
func TestMainMenuSend(t *testing.T) {
en, fn, _ := testutil.TestEngine(sessionID)
en, fn, _, _, _ := testutil.TestEngine(sessionID)
defer fn()
ctx := context.Background()
sessions := testData
@ -347,9 +391,12 @@ func TestGroups(t *testing.T) {
if err != nil {
log.Fatalf("Failed to load test groups: %v", err)
}
en, fn, _ := testutil.TestEngine(sessionID)
en, fn, _, pe, flagParser := testutil.TestEngine(sessionID)
defer fn()
ctx := context.Background()
flag_admin_privilege, _ := flagParser.GetFlag("flag_admin_privilege")
// Create test cases from loaded groups
tests := driver.CreateTestCases(groups)
for _, tt := range tests {
@ -368,9 +415,21 @@ func TestGroups(t *testing.T) {
}
b := w.Bytes()
balance := extractBalance(b)
attempts := extractRemainingAttempts(b)
st := pe.GetState()
if st != nil {
st.SetFlag(flag_admin_privilege)
if tt.Name == "menu_my_account_reset_others_pin_with_no_privileges" {
st.ResetFlag(flag_admin_privilege)
}
}
expectedContent := []byte(tt.ExpectedContent)
expectedContent = bytes.Replace(expectedContent, []byte("{balance}"), []byte(balance), -1)
expectedContent = bytes.Replace(expectedContent, []byte("{attempts}"), []byte(attempts), -1)
expectedContent = bytes.Replace(expectedContent, []byte("{secondary_session_id}"), []byte(secondarySessionId), -1)
tt.ExpectedContent = string(expectedContent)

42
profile/profile_test.go Normal file
View File

@ -0,0 +1,42 @@
package profile
import (
"testing"
"github.com/alecthomas/assert/v2"
"github.com/stretchr/testify/require"
)
func TestInsertOrShift(t *testing.T) {
tests := []struct {
name string
profile Profile
index int
value string
expected []string
}{
{
name: "Insert within range",
profile: Profile{ProfileItems: []string{"A", "B", "C"}, Max: 5},
index: 1,
value: "X",
expected: []string{"A", "X"},
},
{
name: "Insert beyond range",
profile: Profile{ProfileItems: []string{"A"}, Max: 5},
index: 3,
value: "Y",
expected: []string{"A", "0", "0", "Y"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
p := tt.profile
p.InsertOrShift(tt.index, tt.value)
require.NotNil(t, p.ProfileItems)
assert.Equal(t, tt.expected, p.ProfileItems)
})
}
}

View File

@ -1,16 +1,17 @@
//go:build !online
// +build !online
package services
import (
"fmt"
"context"
"fmt"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
devremote "git.grassecon.net/grassrootseconomics/sarafu-api/dev"
"git.grassecon.net/grassrootseconomics/sarafu-api/remote"
apievent "git.grassecon.net/grassrootseconomics/sarafu-api/event"
"git.grassecon.net/grassrootseconomics/sarafu-api/remote"
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers/event"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
)
type localEmitter struct {
@ -37,7 +38,7 @@ func (d *localEmitter) emit(ctx context.Context, msg apievent.Msg) error {
return err
}
func New(ctx context.Context, storageService storage.StorageService, conn storage.ConnData) remote.AccountService {
func New(ctx context.Context, storageService storage.StorageService) remote.AccountService {
svc := devremote.NewDevAccountService(ctx, storageService)
svc = svc.WithAutoVoucher(ctx, "FOO", 42)
eu := event.NewEventsUpdater(svc, storageService)

View File

@ -4,8 +4,8 @@ TXTS = $(wildcard ./*.txt.orig)
VISE_PATH := ../../go-vise
# Rule to build .bin files from .vis files
%.vis:
go run $(VISE_PATH)/dev/asm/main.go -f pp.csv $(basename $@).vis > $(basename $@).bin
%.vis: buildasm
./vise-asm -f pp.csv $(basename $@).vis > $(basename $@).bin
@echo "Built $(basename $@).bin from $(basename $@).vis"
# Rule to copy .orig files to .txt
@ -19,5 +19,10 @@ all: $(INPUTS) $(TXTS)
clean:
rm -vf *.bin
rm -vf ./vise-asm
buildasm:
go build -v -o ./vise-asm $(VISE_PATH)/dev/asm/main.go
.PHONY: clean

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

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

View File

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

View File

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

Binary file not shown.

Binary file not shown.

View File

@ -4,4 +4,7 @@ RELOAD reset_account_authorized
MOUT back 0
HALT
INCMP _ 0
LOAD validate_blocked_number 6
RELOAD validate_blocked_number
CATCH unregistered_number flag_unregistered_number 1
INCMP enter_others_new_pin *

View File

@ -1,6 +1,3 @@
LOAD validate_blocked_number 6
RELOAD validate_blocked_number
CATCH unregistered_number flag_unregistered_number 1
LOAD retrieve_blocked_number 0
RELOAD retrieve_blocked_number
MAP retrieve_blocked_number

Binary file not shown.

Binary file not shown.

View File

@ -7,3 +7,4 @@ MOUT quit 9
HALT
INCMP _ 1
INCMP quit 9
INCMP . *

Binary file not shown.

View File

@ -1,3 +1,5 @@
LOAD clear_temporary_value 2
RELOAD clear_temporary_value
LOAD set_default_voucher 8
RELOAD set_default_voucher
LOAD check_vouchers 10

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,13 +1,7 @@
LOAD authorize_account 12
RELOAD authorize_account
CATCH incorrect_pin flag_incorrect_pin 1
CATCH old_pin flag_allow_update 0
MOUT back 0
HALT
INCMP _ 0
LOAD save_temporary_pin 6
LOAD verify_new_pin 0
RELOAD save_temporary_pin
RELOAD verify_new_pin
CATCH invalid_pin flag_valid_pin 0
INCMP * confirm_pin_change

View File

@ -1,5 +1,5 @@
MOUT quit 9
MOUT back 0
HALT
INCMP pin_management 0
INCMP ^ 0
INCMP quit 9

Binary file not shown.

Binary file not shown.

View File

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

View File

@ -3,3 +3,4 @@ MOUT quit 9
HALT
INCMP _ 1
INCMP quit 9
INCMP . *

Binary file not shown.

View File

@ -1,8 +1,14 @@
LOAD set_back 6
LOAD authorize_account 5
LOAD reset_allow_update 4
LOAD verify_new_pin 2
LOAD save_temporary_pin 1
LOAD reset_incorrect 0
MOUT change_pin 1
MOUT reset_pin 2
MOUT back 0
HALT
INCMP my_account 0
INCMP _ 0
INCMP old_pin 1
INCMP enter_other_number 2
INCMP . *

View File

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

View File

@ -4,5 +4,5 @@ LOAD reset_others_pin 6
MOUT back 0
MOUT quit 9
HALT
INCMP pin_management 0
INCMP ^ 0
INCMP quit 9

Some files were not shown because too many files have changed in this diff Show More