Compare commits

..

78 Commits

Author SHA1 Message Date
Alfred Kamanda
0fd4545a75 updated the golang version to 1.24
Some checks failed
release / docker (push) Has been cancelled
2025-11-18 16:06:49 +03:00
Alfred Kamanda
666faf3db2 removed unused code from ssh and http
Some checks failed
release / docker (push) Has been cancelled
2025-11-18 15:39:44 +03:00
Alfred Kamanda
978bc61f5f use the updated sarafu-api package 2025-11-18 15:30:54 +03:00
Alfred Kamanda
2038c5e99c import the correct go-vise package 2025-11-18 11:10:15 +03:00
Alfred Kamanda
e694e6e1bd use the correct packages 2025-11-18 11:09:46 +03:00
Alfred Kamanda
a7f9847f3a Merge branch 'master' into update-go-vise 2025-11-18 10:56:17 +03:00
c18d40286e Merge pull request 'credit-send-hotfix' (#109) from credit-send-hotfix into master
Reviewed-on: #109
2025-11-18 08:52:21 +01:00
Alfred Kamanda
c2cf8e91e5 removed the print debug statements
Some checks failed
release / docker (push) Has been cancelled
2025-11-14 10:55:54 +03:00
Alfred Kamanda
20cfb47940 updated the size outputs 2025-11-14 10:49:11 +03:00
Alfred Kamanda
03d6cbd429 added a debug for the returned content 2025-11-14 10:46:22 +03:00
Alfred Kamanda
ee41f73347 added a debug log 2025-11-14 10:41:34 +03:00
Alfred Kamanda
bafe3cc04e added the swap menu swahili version 2025-11-13 17:13:34 +03:00
Alfred Kamanda
308dc93a91 return nil to CATCH the flag_api_call_error 2025-11-13 17:09:30 +03:00
Alfred Kamanda
8d29c364c3 updated the swahili message for output length error 2025-11-13 17:07:57 +03:00
Alfred Kamanda
d52d6c478f added a CATCH for the api_call_error flag
Some checks failed
release / docker (push) Has been cancelled
2025-11-13 01:46:36 +03:00
Alfred Kamanda
208eac5a3c use the correct 'flag_api_call_error' 2025-11-13 01:44:50 +03:00
fc2ca0f546 Merge pull request 'send with swap' (#102) from send-with-swap into master
Some checks failed
release / docker (push) Has been cancelled
Reviewed-on: #102
2025-11-12 08:54:05 +01:00
Alfred Kamanda
724bc1bcf3 Merge branch 'master' into send-with-swap
Some checks failed
release / docker (push) Has been cancelled
2025-11-05 15:32:35 +03:00
6e8c0fbcb3 Merge pull request 'Fix get_pools being skipped' (#108) from pool-debug into master
Some checks failed
release / docker (push) Has been cancelled
Reviewed-on: #108
2025-11-05 12:12:14 +01:00
Alfred Kamanda
9f8cf95e0f remove print debug statements 2025-11-05 11:20:55 +03:00
Alfred Kamanda
97be6e943c add a reload for the get_pools 2025-11-05 11:16:52 +03:00
Alfred Kamanda
ba93bd9152 add debug logs for the pool data entry 2025-11-05 11:03:45 +03:00
Alfred Kamanda
5fac27d00e add debug logs for the pool keys 2025-11-04 15:27:15 +03:00
Alfred Kamanda
348185ef96 use l.Get for the language change
Some checks failed
release / docker (push) Has been cancelled
2025-10-30 12:36:11 +03:00
Alfred Kamanda
f51f577e2a added the swahili translations 2025-10-30 12:35:46 +03:00
Alfred Kamanda
582f349be3 handle normal send transactions based on the sym 2025-10-30 11:12:16 +03:00
Alfred Kamanda
8ce17a8d1e add a sym for the credit_max_amount 2025-10-30 11:11:39 +03:00
Alfred Kamanda
4092437d21 add a node for the credit-send amount 2025-10-30 11:11:12 +03:00
Alfred Kamanda
37f4b60679 removed the credit-swap related code 2025-10-30 11:08:57 +03:00
Alfred Kamanda
878b5d0aa5 added the credit_send top-level menu 2025-10-30 11:08:18 +03:00
Alfred Kamanda
d2b934feda use the same translation from the english menu 2025-10-30 10:07:05 +03:00
Alfred Kamanda
4c80606b56 properly handle formatting, preventing rounding errors for the case of 2.1 -> 2.09
Some checks failed
release / docker (push) Has been cancelled
2025-10-29 10:55:42 +03:00
Alfred Kamanda
38ab1ecdd1 added an edge-case test for precision 2025-10-29 10:53:11 +03:00
Alfred Kamanda
a49257657e switch the order to match the TokenHoldings struct
Some checks failed
release / docker (push) Has been cancelled
2025-10-28 17:20:31 +03:00
Alfred Kamanda
95b48371ce CATCH invalid credit-swap amounts 2025-10-28 17:19:40 +03:00
Alfred Kamanda
9da2f8a6ac have a node for invalid credit send amounts 2025-10-28 17:17:22 +03:00
Alfred Kamanda
3194508e51 increase the output sizes 2025-10-28 17:16:54 +03:00
Alfred Kamanda
41f08c5c9b display the max_amount directly from the function 2025-10-28 17:16:25 +03:00
Alfred Kamanda
de539dc300 update the credit-send functionality to display the RAT data 2025-10-28 17:15:39 +03:00
Alfred Kamanda
8af2ccd36f added text translations for the amounts (for normal and credit-send transactions) 2025-10-28 17:09:46 +03:00
Alfred Kamanda
d9c49ee119 upgraded sarafu-api to make use of the credit-send API 2025-10-28 12:21:42 +03:00
Alfred Kamanda
5cfdd949ff use the correct amount when initiating the transfer (the amount that has been swapped)
Some checks failed
release / docker (push) Has been cancelled
2025-10-22 17:32:35 +03:00
Alfred Kamanda
865dae4b7f correctly format amounts to 2 decimal places using TruncateDecimalString 2025-10-22 16:16:05 +03:00
Alfred Kamanda
0af41ea1f1 Merge branch 'master' into send-with-swap 2025-10-22 14:40:21 +03:00
37a1906ed1 Merge pull request 'handle-error-codes' (#105) from handle-error-codes into master
Some checks failed
release / docker (push) Has been cancelled
Reviewed-on: #105
2025-10-22 13:35:13 +02:00
Alfred Kamanda
ba9a23946f added ClearTransactionTypeFlag when a user goes back
Some checks failed
release / docker (push) Has been cancelled
2025-10-09 15:08:51 +03:00
Alfred Kamanda
34271cba23 Merge branch 'master' into send-with-swap
Some checks failed
release / docker (push) Has been cancelled
2025-10-09 14:32:31 +03:00
Alfred Kamanda
e029a8cdc7 improved the tests by updating the menu 2025-10-09 14:19:03 +03:00
Alfred Kamanda
9878745861 fixed the TestCheckBalance by adjusting the expected result 2025-10-09 13:39:30 +03:00
Alfred Kamanda
606a551f60 use the correct data keys on the test 2025-10-09 13:31:55 +03:00
Alfred Kamanda
ed780659d3 removed the debug statements 2025-10-09 13:20:58 +03:00
Alfred Kamanda
764431ee58 added some debug statements 2025-10-09 13:08:22 +03:00
Alfred Kamanda
fb5eb3f24f added the determineAndSaveTransactionType heper for shared logic on the transaction type 2025-10-09 12:45:16 +03:00
Alfred Kamanda
27fdb20974 handle the transaction type for a swap when using an alias 2025-10-09 12:27:51 +03:00
Alfred Kamanda
f7859fb72a handle the transaction type for a swap when using an address 2025-10-09 12:15:56 +03:00
Alfred Kamanda
7973ecdfd9 Merge branch 'master' into send-with-swap
Some checks failed
release / docker (push) Has been cancelled
2025-08-26 12:22:50 +03:00
Alfred Kamanda
c90d3cd731 added the handler functions 2025-08-25 17:28:11 +03:00
Alfred Kamanda
cda2d49f3e added TransactionInitiateSwap functionality that performs a swap followed by a send 2025-08-25 17:27:20 +03:00
Alfred Kamanda
4492f8087a added TransactionSwapPreview functionality 2025-08-25 17:25:59 +03:00
Alfred Kamanda
0f8c2f9270 use the recipient's phone number to read swap related data 2025-08-25 17:24:58 +03:00
Alfred Kamanda
5a09d33be0 removed unused DATA_RECIPIENT_ACTIVE_TOKEN key 2025-08-25 17:21:23 +03:00
Alfred Kamanda
0c67efedea added the transaction_swap_initiated node 2025-08-25 17:20:34 +03:00
Alfred Kamanda
14d493475e catch the flag_swap_transaction and move to the transaction_swap node 2025-08-25 17:20:07 +03:00
Alfred Kamanda
0e4dfe1baf added the flag_swap_transaction when a swap needs to be performed in the send node 2025-08-25 17:19:11 +03:00
Alfred Kamanda
7e1042c6a9 update the MaxAmount logic to check the swap capability for swap transactions 2025-08-25 12:46:16 +03:00
Alfred Kamanda
e274967c8e update the handlePhoneNumber logic to cover new users or those without an active voucher 2025-08-25 10:52:22 +03:00
Alfred Kamanda
16e2bbb409 use updated visedriver-africastalking to correctly log the incoming request 2025-08-20 16:12:35 +03:00
Alfred Kamanda
5fd3102852 update the repository to be used on build and the README 2025-08-20 09:37:15 +03:00
Alfred Kamanda
790f50e5e1 use updated visedriver-africastalking 2025-08-19 17:35:42 +03:00
Alfred Kamanda
77721e7ef6 replace the go-vise package and remove logdb 2025-08-19 15:58:07 +03:00
Alfred Kamanda
b8e939c899 use the updated go-vise package, along with visedriver and sarafu-api 2025-08-19 15:54:40 +03:00
Alfred Kamanda
43904491ae added the grassrootseconomics/go-vise package 2025-08-18 16:34:16 +03:00
Alfred Kamanda
83ea123d56 added missing env variables
Signed-off-by: Alfred Kamanda <alfredmwaik@gmail.com>
2025-08-18 16:19:22 +03:00
Alfred Kamanda
5b82afa768 added the DATA_RECIPIENT_PHONE_NUMBER to store the formatted phone number 2025-08-04 13:50:21 +03:00
Alfred Kamanda
b6de057cc4 add a reset for the DATA_RECIPIENT_ACTIVE_TOKEN key 2025-08-04 11:21:14 +03:00
Alfred Kamanda
758463ee8c add transaction data keys 2025-08-04 11:19:22 +03:00
Alfred Kamanda
f441b3b2af split the ValidateRecipient and check the transaction type 2025-08-04 11:18:45 +03:00
Alfred Kamanda
4d687cac2e updated the MaxAmount description comment 2025-07-30 11:46:22 +03:00
100 changed files with 1078 additions and 1399 deletions

View File

@@ -7,6 +7,7 @@ AT_ENDPOINT=/ussd/africastalking
#PostgreSQL #PostgreSQL
DB_CONN=postgres://postgres:strongpass@localhost:5432/urdt_ussd?search_path=vise DB_CONN=postgres://postgres:strongpass@localhost:5432/urdt_ussd?search_path=vise
DB_CONN_RESOURCE=services/registration
#DB_TIMEZONE=Africa/Nairobi #DB_TIMEZONE=Africa/Nairobi
#DB_SCHEMA=vise #DB_SCHEMA=vise
@@ -14,6 +15,7 @@ DB_CONN=postgres://postgres:strongpass@localhost:5432/urdt_ussd?search_path=vise
CUSTODIAL_URL_BASE=http://localhost:5003 CUSTODIAL_URL_BASE=http://localhost:5003
BEARER_TOKEN=eyJeSIsInRcCI6IkpXVCJ.yJwdWJsaWNLZXkiOiIwrrrrrr BEARER_TOKEN=eyJeSIsInRcCI6IkpXVCJ.yJwdWJsaWNLZXkiOiIwrrrrrr
DATA_URL_BASE=http://localhost:5006 DATA_URL_BASE=http://localhost:5006
ALIAS_ENS_BASE=http://localhost:5015
#Language #Language
DEFAULT_LANGUAGE=eng DEFAULT_LANGUAGE=eng

View File

@@ -1,4 +1,4 @@
FROM golang:1.23.4-bookworm AS build FROM golang:1.24-bookworm AS build
ENV CGO_ENABLED=1 ENV CGO_ENABLED=1
@@ -11,7 +11,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
libgdbm-dev \ libgdbm-dev \
git \ git \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
RUN git clone https://git.defalsify.org/vise.git go-vise RUN git clone https://github.com/grassrootseconomics/go-vise go-vise
COPY . ./sarafu-vise COPY . ./sarafu-vise
WORKDIR /build/sarafu-vise/services/registration WORKDIR /build/sarafu-vise/services/registration

View File

@@ -7,9 +7,9 @@ This is a USSD service built using the [go-vise](https://github.com/nolash/go-vi
## Prerequisites ## Prerequisites
### 1. [go-vise](https://github.com/nolash/go-vise) ### 1. [go-vise](https://github.com/nolash/go-vise)
Set up `go-vise` by cloning the repository into a separate directory. The main upstream repository is hosted at: `https://git.defalsify.org/vise.git` Set up `go-vise` by cloning the repository into a separate directory. The main upstream repository is hosted at: `https://github.com/grassrootseconomics/go-vise`
``` ```
git clone https://git.defalsify.org/vise.git git clone https://github.com/grassrootseconomics/go-vise
``` ```
## Setup ## Setup

View File

@@ -3,7 +3,7 @@ package args
import ( import (
"strings" "strings"
"git.defalsify.org/vise.git/lang" "github.com/grassrootseconomics/go-vise/lang"
) )
type LangVar struct { type LangVar struct {

View File

@@ -11,10 +11,10 @@ import (
"strconv" "strconv"
"syscall" "syscall"
"git.defalsify.org/vise.git/engine" "github.com/grassrootseconomics/go-vise/engine"
"git.defalsify.org/vise.git/lang" "github.com/grassrootseconomics/go-vise/lang"
"git.defalsify.org/vise.git/logging" "github.com/grassrootseconomics/go-vise/resource"
"git.defalsify.org/vise.git/resource" slogging "github.com/grassrootseconomics/go-vise/slog"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config" "git.grassecon.net/grassrootseconomics/sarafu-vise/config"
"git.grassecon.net/grassrootseconomics/visedriver/request" "git.grassecon.net/grassrootseconomics/visedriver/request"
@@ -27,7 +27,7 @@ import (
) )
var ( var (
logg = logging.NewVanilla().WithDomain("AfricasTalking").WithContextKey("at-session-id") logg = slogging.Get().With("component", "AfricasTalking")
scriptDir = path.Join("services", "registration") scriptDir = path.Join("services", "registration")
build = "dev" build = "dev"
menuSeparator = ": " menuSeparator = ": "
@@ -79,10 +79,10 @@ func main() {
pfp := path.Join(scriptDir, "pp.csv") pfp := path.Join(scriptDir, "pp.csv")
cfg := engine.Config{ cfg := engine.Config{
Root: "root", Root: "root",
OutputSize: uint32(size), OutputSize: uint32(size),
FlagCount: uint32(128), FlagCount: uint32(128),
MenuSeparator: menuSeparator, MenuSeparator: menuSeparator,
ResetOnEmptyInput: true, ResetOnEmptyInput: true,
} }
@@ -102,11 +102,6 @@ func main() {
fmt.Fprintf(os.Stderr, "userdatadb: %v\n", err) fmt.Fprintf(os.Stderr, "userdatadb: %v\n", err)
os.Exit(1) os.Exit(1)
} }
logdb, err := menuStorageService.GetLogDb(ctx, userdataStore, logDbConnStr, "user-data")
if err != nil {
fmt.Fprintf(os.Stderr, "get log db error: %v\n", err)
os.Exit(1)
}
dbResource, ok := rs.(*resource.DbResource) dbResource, ok := rs.(*resource.DbResource)
if !ok { if !ok {
@@ -120,7 +115,6 @@ func main() {
os.Exit(1) os.Exit(1)
} }
lhs.SetDataStore(&userdataStore) lhs.SetDataStore(&userdataStore)
lhs.SetLogDb(&logdb)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "setdatastore: %v\n", err) fmt.Fprintf(os.Stderr, "setdatastore: %v\n", err)
os.Exit(1) os.Exit(1)

View File

@@ -12,10 +12,10 @@ import (
"strings" "strings"
"syscall" "syscall"
"git.defalsify.org/vise.git/engine" "github.com/grassrootseconomics/go-vise/engine"
"git.defalsify.org/vise.git/lang" "github.com/grassrootseconomics/go-vise/lang"
"git.defalsify.org/vise.git/logging" "github.com/grassrootseconomics/go-vise/resource"
"git.defalsify.org/vise.git/resource" slogging "github.com/grassrootseconomics/go-vise/slog"
"git.grassecon.net/grassrootseconomics/sarafu-vise/args" "git.grassecon.net/grassrootseconomics/sarafu-vise/args"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config" "git.grassecon.net/grassrootseconomics/sarafu-vise/config"
@@ -26,7 +26,7 @@ import (
) )
var ( var (
logg = logging.NewVanilla() logg = slogging.Get().With("component", "Async")
scriptDir = path.Join("services", "registration") scriptDir = path.Join("services", "registration")
menuSeparator = ": " menuSeparator = ": "
) )
@@ -94,10 +94,10 @@ func main() {
pfp := path.Join(scriptDir, "pp.csv") pfp := path.Join(scriptDir, "pp.csv")
cfg := engine.Config{ cfg := engine.Config{
Root: "root", Root: "root",
OutputSize: uint32(size), OutputSize: uint32(size),
FlagCount: uint32(128), FlagCount: uint32(128),
MenuSeparator: menuSeparator, MenuSeparator: menuSeparator,
ResetOnEmptyInput: true, ResetOnEmptyInput: true,
} }
@@ -122,12 +122,6 @@ func main() {
fmt.Fprintf(os.Stderr, err.Error()) fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1) os.Exit(1)
} }
logdb, err := menuStorageService.GetLogDb(ctx, userdataStore, logDbConnStr, "user-data")
if err != nil {
fmt.Fprintf(os.Stderr, "get log db error: %v\n", err)
os.Exit(1)
}
//defer userdataStore.Close(ctx) //defer userdataStore.Close(ctx)
dbResource, ok := rs.(*resource.DbResource) dbResource, ok := rs.(*resource.DbResource)
@@ -137,7 +131,6 @@ func main() {
lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs) lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs)
lhs.SetDataStore(&userdataStore) lhs.SetDataStore(&userdataStore)
lhs.SetLogDb(&logdb)
accountService := services.New(ctx, menuStorageService) accountService := services.New(ctx, menuStorageService)
hl, err := lhs.GetHandler(accountService) hl, err := lhs.GetHandler(accountService)

View File

@@ -1,172 +0,0 @@
package main
import (
"context"
"flag"
"fmt"
"net/http"
"os"
"os/signal"
"path"
"strconv"
"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.grassecon.net/grassrootseconomics/sarafu-vise/config"
"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/args"
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers"
"git.grassecon.net/grassrootseconomics/sarafu-vise/services"
)
var (
logg = logging.NewVanilla()
scriptDir = path.Join("services", "registration")
menuSeparator = ": "
)
func main() {
config.LoadConfig()
override := config.NewOverride()
var size uint
var engineDebug bool
var host string
var port uint
var err error
var gettextDir string
var langs args.LangVar
var logDbConnStr 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")
flag.UintVar(&port, "p", config.Port(), "http port")
flag.StringVar(&gettextDir, "gettext", "", "use gettext translations from given directory")
flag.Var(&langs, "language", "add symbol resolution for language")
flag.StringVar(&logDbConnStr, "log-c", "db-logs", "log db connection string")
flag.Parse()
config.Apply(override)
conns, err := config.GetConns()
if err != nil {
fmt.Fprintf(os.Stderr, "conn specification error: %v\n", err)
os.Exit(1)
}
logg.Infof("start command", "conn", conns, "outputsize", size)
ctx := context.Background()
ln, err := lang.LanguageFromCode(config.Language())
if err != nil {
fmt.Fprintf(os.Stderr, "default language set error: %v", err)
os.Exit(1)
}
ctx = context.WithValue(ctx, "Language", ln)
pfp := path.Join(scriptDir, "pp.csv")
cfg := engine.Config{
Root: "root",
OutputSize: uint32(size),
FlagCount: uint32(128),
MenuSeparator: menuSeparator,
ResetOnEmptyInput: true,
}
if engineDebug {
cfg.EngineDebug = true
}
menuStorageService := storage.NewMenuStorageService(conns)
rs, err := menuStorageService.GetResource(ctx)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
userdataStore, err := menuStorageService.GetUserdataDb(ctx)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
logdb, err := menuStorageService.GetLogDb(ctx, userdataStore, logDbConnStr, "user-data")
if err != nil {
fmt.Fprintf(os.Stderr, "get log db error: %v\n", err)
os.Exit(1)
}
dbResource, ok := rs.(*resource.DbResource)
if !ok {
os.Exit(1)
}
lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs)
lhs.SetDataStore(&userdataStore)
lhs.SetLogDb(&logdb)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
accountService := services.New(ctx, menuStorageService)
hl, err := lhs.GetHandler(accountService)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
stateStore, err := menuStorageService.GetStateStore(ctx)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
//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,
}
shutdownFunc := func() {
sh.Shutdown(ctx)
}
s.RegisterOnShutdown(shutdownFunc)
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() {
select {
case _ = <-cint:
case _ = <-cterm:
}
s.Shutdown(ctx)
}()
err = s.ListenAndServe()
if err != nil {
logg.Infof("Server closed with error", "err", err)
}
}

View File

@@ -9,19 +9,19 @@ import (
"path" "path"
"syscall" "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.grassecon.net/grassrootseconomics/sarafu-vise/args" "git.grassecon.net/grassrootseconomics/sarafu-vise/args"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config" "git.grassecon.net/grassrootseconomics/sarafu-vise/config"
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers" "git.grassecon.net/grassrootseconomics/sarafu-vise/handlers"
"git.grassecon.net/grassrootseconomics/sarafu-vise/services" "git.grassecon.net/grassrootseconomics/sarafu-vise/services"
"git.grassecon.net/grassrootseconomics/visedriver/storage" "git.grassecon.net/grassrootseconomics/visedriver/storage"
"github.com/grassrootseconomics/go-vise/engine"
"github.com/grassrootseconomics/go-vise/lang"
"github.com/grassrootseconomics/go-vise/resource"
slogging "github.com/grassrootseconomics/go-vise/slog"
) )
var ( var (
logg = logging.NewVanilla() logg = slogging.Get().With("component", "Main CLI")
scriptDir = path.Join("services", "registration") scriptDir = path.Join("services", "registration")
menuSeparator = ": " menuSeparator = ": "
) )
@@ -112,11 +112,11 @@ func main() {
os.Exit(1) os.Exit(1)
} }
logdb, err := menuStorageService.GetLogDb(ctx, userdatastore, logDbConnStr, "user-data") // logdb, err := menuStorageService.GetLogDb(ctx, userdatastore, logDbConnStr, "user-data")
if err != nil { // if err != nil {
fmt.Fprintf(os.Stderr, "get log db error: %v\n", err) // fmt.Fprintf(os.Stderr, "get log db error: %v\n", err)
os.Exit(1) // os.Exit(1)
} // }
dbResource, ok := rs.(*resource.DbResource) dbResource, ok := rs.(*resource.DbResource)
if !ok { if !ok {
@@ -126,7 +126,7 @@ func main() {
lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs) lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs)
lhs.SetDataStore(&userdatastore) lhs.SetDataStore(&userdatastore)
lhs.SetLogDb(&logdb) // lhs.SetLogDb(&logdb)
lhs.SetPersister(pe) lhs.SetPersister(pe)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "localhandler service error: %v\n", err) fmt.Fprintf(os.Stderr, "localhandler service error: %v\n", err)

View File

@@ -1,34 +0,0 @@
# URDT-USSD SSH server
An SSH server entry point for the vise engine.
## Adding public keys for access
Map your (client) public key to a session identifier (e.g. phone number)
```
go run -v -tags logtrace ./cmd/ssh/sshkey/main.go -i <session_id> [--dbdir <dbpath>] <client_publickey_filepath>
```
## Create a private key for the server
```
ssh-keygen -N "" -f <server_privatekey_filepath>
```
## Run the server
```
go run -v -tags logtrace ./cmd/ssh/main.go -h <host> -p <port> [--dbdir <dbpath>] <server_privatekey_filepath>
```
## Connect to the server
```
ssh [-v] -T -p <port> -i <client_publickey_filepath> <host>
```

View File

@@ -1,136 +0,0 @@
package main
import (
"context"
"flag"
"fmt"
"os"
"os/signal"
"path"
"sync"
"syscall"
"git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config"
"git.grassecon.net/grassrootseconomics/sarafu-vise/ssh"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
)
var (
wg sync.WaitGroup
keyStore db.Db
logg = logging.NewVanilla()
scriptDir = path.Join("services", "registration")
build = "dev"
)
func main() {
config.LoadConfig()
override := config.NewOverride()
var authConnStr string
var size uint
var engineDebug bool
var stateDebug bool
var host string
var port uint
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()
config.Apply(override)
conns, err := config.GetConns()
if err != nil {
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)
os.Exit(1)
}
sshKeyFile := flag.Arg(0)
_, err = os.Stat(sshKeyFile)
if err != nil {
fmt.Fprintf(os.Stderr, "cannot open ssh server private key file: %v\n", err)
os.Exit(1)
}
ctx := context.Background()
logg.WarnCtxf(ctx, "!!!!! WARNING WARNING WARNING")
logg.WarnCtxf(ctx, "!!!!! =======================")
logg.WarnCtxf(ctx, "!!!!! This is not a production ready server!")
logg.WarnCtxf(ctx, "!!!!! Do not expose to internet and only use with tunnel!")
logg.WarnCtxf(ctx, "!!!!! (See ssh -L <...>)")
logg.Infof("start command", "conn", conns, "authconn", authConnData, "outputsize", size, "keyfile", sshKeyFile, "host", host, "port", port)
pfp := path.Join(scriptDir, "pp.csv")
cfg := engine.Config{
Root: "root",
OutputSize: uint32(size),
FlagCount: uint32(128),
ResetOnEmptyInput: true,
}
if stateDebug {
cfg.StateDebug = true
}
if engineDebug {
cfg.EngineDebug = true
}
authKeyStore, err := ssh.NewSshKeyStore(ctx, authConnData.String())
if err != nil {
fmt.Fprintf(os.Stderr, "keystore file open error: %v", err)
os.Exit(1)
}
defer func() {
logg.TraceCtxf(ctx, "shutdown auth key store reached")
err = authKeyStore.Close(ctx)
if err != nil {
logg.ErrorCtxf(ctx, "keystore close error", "err", err)
}
}()
cint := make(chan os.Signal)
cterm := make(chan os.Signal)
signal.Notify(cint, os.Interrupt, syscall.SIGINT)
signal.Notify(cterm, os.Interrupt, syscall.SIGTERM)
runner := &ssh.SshRunner{
Cfg: cfg,
Debug: engineDebug,
FlagFile: pfp,
Conn: conns,
SrvKeyFile: sshKeyFile,
Host: host,
Port: port,
}
go func() {
select {
case _ = <-cint:
case _ = <-cterm:
}
logg.TraceCtxf(ctx, "shutdown runner reached")
err := runner.Stop()
if err != nil {
logg.ErrorCtxf(ctx, "runner stop error", "err", err)
}
}()
runner.Run(ctx, authKeyStore)
}

View File

@@ -1,44 +0,0 @@
package main
import (
"context"
"flag"
"fmt"
"os"
"git.grassecon.net/grassrootseconomics/sarafu-vise/ssh"
)
func main() {
var dbDir string
var sessionId string
flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from")
flag.StringVar(&sessionId, "i", "", "session id")
flag.Parse()
if sessionId == "" {
fmt.Fprintf(os.Stderr, "empty session id\n")
os.Exit(1)
}
ctx := context.Background()
sshKeyFile := flag.Arg(0)
if sshKeyFile == "" {
fmt.Fprintf(os.Stderr, "missing key file argument\n")
os.Exit(1)
}
store, err := ssh.NewSshKeyStore(ctx, dbDir)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
}
defer store.Close(ctx)
err = store.AddFromFile(ctx, sshKeyFile, sessionId)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
}
}

View File

@@ -4,8 +4,8 @@ import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
visedb "git.defalsify.org/vise.git/db"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
visedb "github.com/grassrootseconomics/go-vise/db"
) )
var ( var (

View File

@@ -4,7 +4,7 @@
package debug package debug
import ( import (
"git.defalsify.org/vise.git/db" "github.com/grassrootseconomics/go-vise/db"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
) )

View File

@@ -3,8 +3,8 @@ package debug
import ( import (
"testing" "testing"
visedb "git.defalsify.org/vise.git/db"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
visedb "github.com/grassrootseconomics/go-vise/db"
) )
func TestDebugDbSubKeyInfo(t *testing.T) { func TestDebugDbSubKeyInfo(t *testing.T) {

View File

@@ -7,16 +7,15 @@ import (
"os" "os"
"path" "path"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config" "git.grassecon.net/grassrootseconomics/sarafu-vise/config"
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers/application" "git.grassecon.net/grassrootseconomics/sarafu-vise/handlers/application"
"git.grassecon.net/grassrootseconomics/sarafu-vise/internal/cmd" "git.grassecon.net/grassrootseconomics/sarafu-vise/internal/cmd"
"git.grassecon.net/grassrootseconomics/visedriver/storage" "git.grassecon.net/grassrootseconomics/visedriver/storage"
slogging "github.com/grassrootseconomics/go-vise/slog"
) )
var ( var (
logg = logging.NewVanilla().WithContextKey("SessionId") logg = slogging.Get().With("component", "admin devtool")
scriptDir = path.Join("services", "registration") scriptDir = path.Join("services", "registration")
) )

View File

@@ -8,9 +8,9 @@ import (
"path" "path"
"strings" "strings"
"git.defalsify.org/vise.git/lang"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/visedriver/config" "git.grassecon.net/grassrootseconomics/visedriver/config"
"github.com/grassrootseconomics/go-vise/lang"
slogging "github.com/grassrootseconomics/go-vise/slog"
) )
const ( const (
@@ -28,7 +28,7 @@ MOVE language_changed
) )
var ( var (
logg = logging.NewVanilla() logg = slogging.Get()
mouts string mouts string
incmps string incmps string
) )

View File

@@ -7,15 +7,15 @@ import (
"os" "os"
"path" "path"
"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/config"
"git.grassecon.net/grassrootseconomics/sarafu-vise/debug" "git.grassecon.net/grassrootseconomics/sarafu-vise/debug"
"git.grassecon.net/grassrootseconomics/visedriver/storage" "git.grassecon.net/grassrootseconomics/visedriver/storage"
"github.com/grassrootseconomics/go-vise/db"
slogging "github.com/grassrootseconomics/go-vise/slog"
) )
var ( var (
logg = logging.NewVanilla() logg = slogging.Get()
scriptDir = path.Join("services", "registration") scriptDir = path.Join("services", "registration")
) )

30
go.mod
View File

@@ -1,29 +1,32 @@
module git.grassecon.net/grassrootseconomics/sarafu-vise module git.grassecon.net/grassrootseconomics/sarafu-vise
go 1.23.4 go 1.24
toolchain go1.24.6
require ( require (
git.defalsify.org/vise.git v0.3.2-0.20250528124150-03bf7bfc1b66 git.defalsify.org/vise.git v0.3.2-0.20250407143413-e55cf9bcb7d2
git.grassecon.net/grassrootseconomics/common v0.9.0-beta.1.0.20250417111317-2953f4c2f32e git.grassecon.net/grassrootseconomics/common v0.9.0-beta.1.0.20250417111317-2953f4c2f32e
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20251022084613-532547899f63 git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20251118101154-74e5fb016c2e
git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250408094335-e2d1f65bb306 git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250819084006-5a9c82207578
git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694 git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694
github.com/alecthomas/assert/v2 v2.2.2 github.com/alecthomas/assert/v2 v2.11.0
github.com/gofrs/uuid v4.4.0+incompatible github.com/gofrs/uuid v4.4.0+incompatible
github.com/grassrootseconomics/ethutils v1.3.1 github.com/grassrootseconomics/ethutils v1.3.1
github.com/grassrootseconomics/go-vise v0.5.0
github.com/grassrootseconomics/ussd-data-service v1.6.0-beta github.com/grassrootseconomics/ussd-data-service v1.6.0-beta
github.com/jackc/pgx/v5 v5.7.1 github.com/jackc/pgx/v5 v5.7.5
github.com/peteole/testdata-loader v0.3.0 github.com/peteole/testdata-loader v0.3.0
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.9.0
golang.org/x/crypto v0.32.0 golang.org/x/crypto v0.40.0
gopkg.in/leonelquinteros/gotext.v1 v1.3.1 gopkg.in/leonelquinteros/gotext.v1 v1.3.1
) )
require ( require (
github.com/Microsoft/go-winio v0.6.2 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/StackExchange/wmi v1.2.1 // indirect github.com/StackExchange/wmi v1.2.1 // indirect
github.com/alecthomas/participle/v2 v2.0.0 // indirect github.com/alecthomas/participle/v2 v2.1.4 // indirect
github.com/alecthomas/repr v0.2.0 // indirect github.com/alecthomas/repr v0.4.0 // indirect
github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c // indirect github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c // indirect
github.com/bits-and-blooms/bitset v1.14.3 // indirect github.com/bits-and-blooms/bitset v1.14.3 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect
@@ -37,7 +40,7 @@ require (
github.com/ethereum/c-kzg-4844 v1.0.0 // indirect github.com/ethereum/c-kzg-4844 v1.0.0 // indirect
github.com/ethereum/go-ethereum v1.14.9 // indirect github.com/ethereum/go-ethereum v1.14.9 // indirect
github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 // indirect github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 // indirect
github.com/fxamacker/cbor/v2 v2.4.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect
github.com/grassrootseconomics/eth-custodial v1.3.0-beta // indirect github.com/grassrootseconomics/eth-custodial v1.3.0-beta // indirect
@@ -48,6 +51,7 @@ require (
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/joho/godotenv v1.5.1 // indirect github.com/joho/godotenv v1.5.1 // indirect
github.com/leonelquinteros/gotext v1.7.2 // indirect
github.com/lmittmann/w3 v0.17.1 // indirect github.com/lmittmann/w3 v0.17.1 // indirect
github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a // indirect github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect
@@ -59,9 +63,9 @@ require (
github.com/tklauser/numcpus v0.6.1 // indirect github.com/tklauser/numcpus v0.6.1 // indirect
github.com/x448/float16 v0.8.4 // indirect github.com/x448/float16 v0.8.4 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/sync v0.10.0 // indirect golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.29.0 // indirect golang.org/x/sys v0.34.0 // indirect
golang.org/x/text v0.21.0 // indirect golang.org/x/text v0.27.0 // indirect
golang.org/x/time v0.7.0 // indirect golang.org/x/time v0.7.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
rsc.io/tmplfunc v0.0.3 // indirect rsc.io/tmplfunc v0.0.3 // indirect

86
go.sum
View File

@@ -1,31 +1,13 @@
git.defalsify.org/vise.git v0.3.2-0.20250528124150-03bf7bfc1b66 h1:hmtb2Q3lHxq+SXqG+Gn43pKhTRYx+sw5j1LpgBfXN1o= git.defalsify.org/vise.git v0.3.2-0.20250407143413-e55cf9bcb7d2 h1:kbiDZtvphEKsTAnebrB6QxRbB7zdoTHSmzzumXrJ4hw=
git.defalsify.org/vise.git v0.3.2-0.20250528124150-03bf7bfc1b66/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck= git.defalsify.org/vise.git v0.3.2-0.20250407143413-e55cf9bcb7d2/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck=
git.grassecon.net/grassrootseconomics/common v0.9.0-beta.1.0.20250417111317-2953f4c2f32e h1:DcC9qkNl9ny3hxQmsMK6W81+5R/j4ZwYUbvewMI/rlc= git.grassecon.net/grassrootseconomics/common v0.9.0-beta.1.0.20250417111317-2953f4c2f32e h1:DcC9qkNl9ny3hxQmsMK6W81+5R/j4ZwYUbvewMI/rlc=
git.grassecon.net/grassrootseconomics/common v0.9.0-beta.1.0.20250417111317-2953f4c2f32e/go.mod h1:wgQJZGIS6QuNLHqDhcsvehsbn5PvgV7aziRebMnJi60= git.grassecon.net/grassrootseconomics/common v0.9.0-beta.1.0.20250417111317-2953f4c2f32e/go.mod h1:wgQJZGIS6QuNLHqDhcsvehsbn5PvgV7aziRebMnJi60=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250623063234-c1797e7a32b5 h1:VnRe01kHkZUBK/QjE7iV6gElSqSwQnAkWV3yCHtuYrI= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20251028083421-fe897cca84f2 h1:wf//obTSLW5VZ0gM25l0U5oV/d+TBXX+1ClSMkEU7Uc=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250623063234-c1797e7a32b5/go.mod h1:H97hR+VOnZvR5BiGVb0ScCPwH/IoKBOlKM+yrQNVpq0= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20251028083421-fe897cca84f2/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250623070026-d945964b0b46 h1:0+XkSRe7XSHa9WHXKpGPuC0myDszjchr4syH006lQ28= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20251118101154-74e5fb016c2e h1:Yyiz9qqpFi/nZOvJIMTxlZkdhWlBYSc7Ke1rZp8C8xI=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250623070026-d945964b0b46/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20251118101154-74e5fb016c2e/go.mod h1:LJF/8GtEP/XU2+Z1KzN6//nFyqJbn17oledIn6Gtmmc=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250623075057-7b42d509e6d4 h1:W+8CC7x5eCPylkGy2TEoOpfJuiIlqzEzyYTzCLlY/u8= git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250819084006-5a9c82207578 h1:GKhBMVbjGBus3eAp2tw3M66irOnEWWg0QEKVn0bBS8E=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250623075057-7b42d509e6d4/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8= git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250819084006-5a9c82207578/go.mod h1:hx6mjSyxKv5oxiJxB6EevJrMJIYjVoYxFEzBtpD+29c=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250624074830-5aa032400c12 h1:vD8biQmN36eouuE+TdxgXQjKisRf5cTGu/tMPv3afs0=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250624074830-5aa032400c12/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250624090744-339ba854c997 h1:8bCKyYoV4YiVBvCZlRclc3aQlBYpWhgtM35mvniDFD8=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250624090744-339ba854c997/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250626065419-57ee409f9629 h1:ew3vCFrLS/7/8uULTTPCbsHzFntQ6X68SScnBEy3pl0=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250626065419-57ee409f9629/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630213135-50ee455e7069 h1:re+hdr5NAC6JqhyvjMCkgX17fFi0u3Mawc6RBnBJW8I=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630213135-50ee455e7069/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630213606-12940bb5f284 h1:2zMU9jPd6xEO6oY9oxr84sdT9G3d09eyAkjVBAz9eco=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630213606-12940bb5f284/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630214912-814bef2b209a h1:KuhJ/WY4RCGmrXUA680ciaponM4vM5zBOJfnCpUo2fc=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630214912-814bef2b209a/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20251021120522-6f7802b58cf5 h1:bQglHVxMilciZ9M2PGuLgA+Wkvqo8OqQh6TFYwjtuSE=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20251021120522-6f7802b58cf5/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20251022084613-532547899f63 h1:yznaUXeAy+qiZb2nCxosYXE5HyCPpynIoplEuYV/zQM=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20251022084613-532547899f63/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8=
git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250408094335-e2d1f65bb306 h1:Jo+yWysWw/N5BJQtAyEMN8ePVvAyPHv+JG4lQti+1N4=
git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250408094335-e2d1f65bb306/go.mod h1:FdLwYtzsjOIcDiW4uDgDYnB4Wdzq12uJUe0QHSSPbSo=
git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694 h1:DjJlBSz0S13acft5XZDWk7ZYnzElym0xLMYEVgyNJ+E= git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694 h1:DjJlBSz0S13acft5XZDWk7ZYnzElym0xLMYEVgyNJ+E=
git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694/go.mod h1:DpibtYpnT3nG4Kn556hRAkdu4+CtiI/6MbnQHal51mQ= git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694/go.mod h1:DpibtYpnT3nG4Kn556hRAkdu4+CtiI/6MbnQHal51mQ=
github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
@@ -36,12 +18,12 @@ github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDO
github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI=
github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI=
github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/participle/v2 v2.0.0 h1:Fgrq+MbuSsJwIkw3fEj9h75vDP0Er5JzepJ0/HNHv0g= github.com/alecthomas/participle/v2 v2.1.4 h1:W/H79S8Sat/krZ3el6sQMvMaahJ+XcM9WSI2naI7w2U=
github.com/alecthomas/participle/v2 v2.0.0/go.mod h1:rAKZdJldHu8084ojcWevWAL8KmEU+AT+Olodb+WoN2Y= github.com/alecthomas/participle/v2 v2.1.4/go.mod h1:8tqVbpTX20Ru4NfYQgZf4mP18eXPTBViyMWiArNEgGI=
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c h1:H9Nm+I7Cg/YVPpEV1RzU3Wq2pjamPc/UtHDgItcb7lE= github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c h1:H9Nm+I7Cg/YVPpEV1RzU3Wq2pjamPc/UtHDgItcb7lE=
github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c/go.mod h1:rGod7o6KPeJ+hyBpHfhi4v7blx9sf+QsHsA7KAsdN6U= github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c/go.mod h1:rGod7o6KPeJ+hyBpHfhi4v7blx9sf+QsHsA7KAsdN6U=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@@ -89,8 +71,8 @@ github.com/ethereum/go-ethereum v1.14.9 h1:J7iwXDrtUyE9FUjUYbd4c9tyzwMh6dTJsKzo9
github.com/ethereum/go-ethereum v1.14.9/go.mod h1:QeW+MtTpRdBEm2pUFoonByee8zfHv7kGp0wK0odvU1I= github.com/ethereum/go-ethereum v1.14.9/go.mod h1:QeW+MtTpRdBEm2pUFoonByee8zfHv7kGp0wK0odvU1I=
github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 h1:8NfxH2iXvJ60YRB8ChToFTUzl8awsc3cJ8CbLjGIl/A= github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 h1:8NfxH2iXvJ60YRB8ChToFTUzl8awsc3cJ8CbLjGIl/A=
github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk=
github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps=
github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
@@ -117,8 +99,8 @@ github.com/grassrootseconomics/eth-custodial v1.3.0-beta h1:twrMBhl89GqDUL9PlkzQ
github.com/grassrootseconomics/eth-custodial v1.3.0-beta/go.mod h1:7uhRcdnJplX4t6GKCEFkbeDhhjlcaGJeJqevbcvGLZo= github.com/grassrootseconomics/eth-custodial v1.3.0-beta/go.mod h1:7uhRcdnJplX4t6GKCEFkbeDhhjlcaGJeJqevbcvGLZo=
github.com/grassrootseconomics/ethutils v1.3.1 h1:LlQO90HjJkl7ejC8fv6jP7RJUrAm1j4VMMCYfsoIrhU= github.com/grassrootseconomics/ethutils v1.3.1 h1:LlQO90HjJkl7ejC8fv6jP7RJUrAm1j4VMMCYfsoIrhU=
github.com/grassrootseconomics/ethutils v1.3.1/go.mod h1:Wuv1VEZrkLIXqTSEYI3Nh9HG/ZHOUQ+U+xvWJ8QtjgQ= github.com/grassrootseconomics/ethutils v1.3.1/go.mod h1:Wuv1VEZrkLIXqTSEYI3Nh9HG/ZHOUQ+U+xvWJ8QtjgQ=
github.com/grassrootseconomics/ussd-data-service v1.5.0-beta h1:BSSQL/yPEvTVku9ja/ENZyZdwZkEaiTzzOUfg72bTy4= github.com/grassrootseconomics/go-vise v0.5.0 h1:FRg2de55Eb5SisrgTBeFWfWX+sXwp5q9r7YWtKWDwsk=
github.com/grassrootseconomics/ussd-data-service v1.5.0-beta/go.mod h1:9sGnorpKaK76FmOGXoh/xv7x5siSFNYdXxQo9BKW4DI= github.com/grassrootseconomics/go-vise v0.5.0/go.mod h1:b2/q4jfTu2i1wyUwYUu7FYq4m2f1AZv8MpiDM3ZcoGo=
github.com/grassrootseconomics/ussd-data-service v1.6.0-beta h1:pY6zns6ifXyClRxP+JJaWrged3oRE7tTS2xaftF9clA= github.com/grassrootseconomics/ussd-data-service v1.6.0-beta h1:pY6zns6ifXyClRxP+JJaWrged3oRE7tTS2xaftF9clA=
github.com/grassrootseconomics/ussd-data-service v1.6.0-beta/go.mod h1:9sGnorpKaK76FmOGXoh/xv7x5siSFNYdXxQo9BKW4DI= github.com/grassrootseconomics/ussd-data-service v1.6.0-beta/go.mod h1:9sGnorpKaK76FmOGXoh/xv7x5siSFNYdXxQo9BKW4DI=
github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 h1:U4kkNYryi/qfbBF8gh7Vsbuz+cVmhf5kt6pE9bYYyLo= github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 h1:U4kkNYryi/qfbBF8gh7Vsbuz+cVmhf5kt6pE9bYYyLo=
@@ -133,8 +115,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= github.com/jackc/pgx/v5 v5.7.5 h1:JHGfMnQY+IEtGM63d+NGMjoRpysB2JBwDr5fsngwmJs=
github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= github.com/jackc/pgx/v5 v5.7.5/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
@@ -149,6 +131,10 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
github.com/leonelquinteros/gotext v1.7.2 h1:bDPndU8nt+/kRo1m4l/1OXiiy2v7Z7dfPQ9+YP7G1Mc=
github.com/leonelquinteros/gotext v1.7.2/go.mod h1:9/haCkm5P7Jay1sxKDGJ5WIg4zkz8oZKw4ekNpALob8=
github.com/lmittmann/tint v1.1.2 h1:2CQzrL6rslrsyjqLDwD11bZ5OpLBPU+g3G/r5LSfS8w=
github.com/lmittmann/tint v1.1.2/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
github.com/lmittmann/w3 v0.17.1 h1:zdXIimmNmYfqOFur+Jqc9Yqwtq6jwnsQufbTOnSAtW4= github.com/lmittmann/w3 v0.17.1 h1:zdXIimmNmYfqOFur+Jqc9Yqwtq6jwnsQufbTOnSAtW4=
github.com/lmittmann/w3 v0.17.1/go.mod h1:WVUGMbL83WYBu4Sge3SVlW3qIG4VaHe+S8+UUnwz9Eg= github.com/lmittmann/w3 v0.17.1/go.mod h1:WVUGMbL83WYBu4Sge3SVlW3qIG4VaHe+S8+UUnwz9Eg=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
@@ -162,8 +148,8 @@ github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqky
github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pashagolub/pgxmock/v4 v4.3.0 h1:DqT7fk0OCK6H0GvqtcMsLpv8cIwWqdxWgfZNLeHCb/s= github.com/pashagolub/pgxmock/v4 v4.7.0 h1:de2ORuFYyjwOQR7NBm57+321RnZxpYiuUjsmqRiqgh8=
github.com/pashagolub/pgxmock/v4 v4.3.0/go.mod h1:9VoVHXwS3XR/yPtKGzwQvwZX1kzGB9sM8SviDcHDa3A= github.com/pashagolub/pgxmock/v4 v4.7.0/go.mod h1:9L57pC193h2aKRHVyiiE817avasIPZnPwPlw3JczWvM=
github.com/peteole/testdata-loader v0.3.0 h1:8jckE9KcyNHgyv/VPoaljvKZE0Rqr8+dPVYH6rfNr9I= github.com/peteole/testdata-loader v0.3.0 h1:8jckE9KcyNHgyv/VPoaljvKZE0Rqr8+dPVYH6rfNr9I=
github.com/peteole/testdata-loader v0.3.0/go.mod h1:Mt0ZbRtb56u8SLJpNP+BnQbENljMorYBpqlvt3cS83U= github.com/peteole/testdata-loader v0.3.0/go.mod h1:Mt0ZbRtb56u8SLJpNP+BnQbENljMorYBpqlvt3cS83U=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -202,22 +188,22 @@ github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+F
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=

View File

@@ -5,9 +5,9 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/resource"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/grassrootseconomics/go-vise/db"
"github.com/grassrootseconomics/go-vise/resource"
) )
// CheckAccountStatus queries the API using the TrackingId and sets flags // CheckAccountStatus queries the API using the TrackingId and sets flags

View File

@@ -4,12 +4,12 @@ import (
"context" "context"
"testing" "testing"
"git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/state"
"git.grassecon.net/grassrootseconomics/sarafu-api/models" "git.grassecon.net/grassrootseconomics/sarafu-api/models"
"git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks" "git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/alecthomas/assert/v2" "github.com/alecthomas/assert/v2"
"github.com/grassrootseconomics/go-vise/resource"
"github.com/grassrootseconomics/go-vise/state"
) )
func TestCheckAccountStatus(t *testing.T) { func TestCheckAccountStatus(t *testing.T) {

View File

@@ -6,8 +6,8 @@ import (
"fmt" "fmt"
"unicode" "unicode"
"git.defalsify.org/vise.git/db" "github.com/grassrootseconomics/go-vise/db"
"git.defalsify.org/vise.git/resource" "github.com/grassrootseconomics/go-vise/resource"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
) )

View File

@@ -4,9 +4,9 @@ import (
"context" "context"
"fmt" "fmt"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/common/pin" "git.grassecon.net/grassrootseconomics/common/pin"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/grassrootseconomics/go-vise/resource"
) )
// Authorize attempts to unlock the next sequential nodes by verifying the provided PIN against the already set PIN. // Authorize attempts to unlock the next sequential nodes by verifying the provided PIN against the already set PIN.

View File

@@ -5,12 +5,12 @@ import (
"log" "log"
"testing" "testing"
"git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/state"
"git.grassecon.net/grassrootseconomics/common/pin" "git.grassecon.net/grassrootseconomics/common/pin"
"git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks" "git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/alecthomas/assert/v2" "github.com/alecthomas/assert/v2"
"github.com/grassrootseconomics/go-vise/resource"
"github.com/grassrootseconomics/go-vise/state"
) )
func TestAuthorize(t *testing.T) { func TestAuthorize(t *testing.T) {

View File

@@ -4,10 +4,10 @@ import (
"context" "context"
"fmt" "fmt"
"git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store" "git.grassecon.net/grassrootseconomics/sarafu-vise/store"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/grassrootseconomics/go-vise/db"
"github.com/grassrootseconomics/go-vise/resource"
"gopkg.in/leonelquinteros/gotext.v1" "gopkg.in/leonelquinteros/gotext.v1"
) )

View File

@@ -4,12 +4,12 @@ import (
"context" "context"
"testing" "testing"
"git.defalsify.org/vise.git/lang"
"git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/state"
"git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks" "git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/alecthomas/assert/v2" "github.com/alecthomas/assert/v2"
"github.com/grassrootseconomics/go-vise/lang"
"github.com/grassrootseconomics/go-vise/resource"
"github.com/grassrootseconomics/go-vise/state"
) )
func TestCheckBalance(t *testing.T) { func TestCheckBalance(t *testing.T) {
@@ -52,7 +52,7 @@ func TestCheckBalance(t *testing.T) {
alias: "user72", alias: "user72",
activeSym: "SRF", activeSym: "SRF",
activeBal: "10.967", activeBal: "10.967",
expectedResult: resource.Result{Content: "user72 balance: 10.96 SRF\n"}, expectedResult: resource.Result{Content: "user72\nBalance: 10.96 SRF\n"},
expectError: false, expectError: false,
}, },
} }

View File

@@ -5,11 +5,11 @@ import (
"fmt" "fmt"
"strings" "strings"
"git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/state"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
commonlang "git.grassecon.net/grassrootseconomics/common/lang" commonlang "git.grassecon.net/grassrootseconomics/common/lang"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/grassrootseconomics/go-vise/db"
"github.com/grassrootseconomics/go-vise/resource"
"github.com/grassrootseconomics/go-vise/state"
) )
// SetLanguage sets the language across the menu. // SetLanguage sets the language across the menu.

View File

@@ -5,10 +5,10 @@ import (
"log" "log"
"testing" "testing"
"git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/state"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/alecthomas/assert/v2" "github.com/alecthomas/assert/v2"
"github.com/grassrootseconomics/go-vise/resource"
"github.com/grassrootseconomics/go-vise/state"
) )
func TestSetLanguage(t *testing.T) { func TestSetLanguage(t *testing.T) {

View File

@@ -7,23 +7,23 @@ import (
"gopkg.in/leonelquinteros/gotext.v1" "gopkg.in/leonelquinteros/gotext.v1"
"git.defalsify.org/vise.git/asm"
"git.defalsify.org/vise.git/cache"
"git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/lang"
"git.defalsify.org/vise.git/logging"
"git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/state"
"git.grassecon.net/grassrootseconomics/sarafu-api/remote" "git.grassecon.net/grassrootseconomics/sarafu-api/remote"
"git.grassecon.net/grassrootseconomics/sarafu-vise/internal/sms" "git.grassecon.net/grassrootseconomics/sarafu-vise/internal/sms"
"git.grassecon.net/grassrootseconomics/sarafu-vise/profile" "git.grassecon.net/grassrootseconomics/sarafu-vise/profile"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store" "git.grassecon.net/grassrootseconomics/sarafu-vise/store"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/grassrootseconomics/go-vise/asm"
"github.com/grassrootseconomics/go-vise/cache"
"github.com/grassrootseconomics/go-vise/db"
"github.com/grassrootseconomics/go-vise/lang"
"github.com/grassrootseconomics/go-vise/persist"
"github.com/grassrootseconomics/go-vise/resource"
slogging "github.com/grassrootseconomics/go-vise/slog"
"github.com/grassrootseconomics/go-vise/state"
) )
var ( var (
logg = logging.NewVanilla().WithDomain("ussdmenuhandler").WithContextKey("SessionId") logg = slogging.Get().With("component", "ussdmenuhandler")
scriptDir = path.Join("services", "registration") scriptDir = path.Join("services", "registration")
translationDir = path.Join(scriptDir, "locale") translationDir = path.Join(scriptDir, "locale")
) )
@@ -65,13 +65,13 @@ type MenuHandlers struct {
accountService remote.AccountService accountService remote.AccountService
prefixDb storedb.PrefixDb prefixDb storedb.PrefixDb
smsService sms.SmsService smsService sms.SmsService
logDb store.LogDb // logDb store.LogDb
profile *profile.Profile profile *profile.Profile
ReplaceSeparatorFunc func(string) string ReplaceSeparatorFunc func(string) string
} }
// NewHandlers creates a new instance of the Handlers struct with the provided dependencies. // NewHandlers creates a new instance of the Handlers struct with the provided dependencies.
func NewMenuHandlers(appFlags *FlagManager, userdataStore db.Db, logdb db.Db, accountService remote.AccountService, replaceSeparatorFunc func(string) string) (*MenuHandlers, error) { func NewMenuHandlers(appFlags *FlagManager, userdataStore db.Db, accountService remote.AccountService, replaceSeparatorFunc func(string) string) (*MenuHandlers, error) {
if userdataStore == nil { if userdataStore == nil {
return nil, fmt.Errorf("cannot create handler with nil userdata store") return nil, fmt.Errorf("cannot create handler with nil userdata store")
} }
@@ -83,9 +83,9 @@ func NewMenuHandlers(appFlags *FlagManager, userdataStore db.Db, logdb db.Db, ac
Userdatastore: *userDb, Userdatastore: *userDb,
} }
logDb := store.LogDb{ // logDb := store.LogDb{
Db: logdb, // Db: logdb,
} // }
// Instantiate the SubPrefixDb with "DATATYPE_USERDATA" prefix // Instantiate the SubPrefixDb with "DATATYPE_USERDATA" prefix
prefix := storedb.ToBytes(db.DATATYPE_USERDATA) prefix := storedb.ToBytes(db.DATATYPE_USERDATA)
@@ -97,7 +97,7 @@ func NewMenuHandlers(appFlags *FlagManager, userdataStore db.Db, logdb db.Db, ac
accountService: accountService, accountService: accountService,
smsService: smsservice, smsService: smsservice,
prefixDb: prefixDb, prefixDb: prefixDb,
logDb: logDb, // logDb: logDb,
profile: &profile.Profile{Max: 6}, profile: &profile.Profile{Max: 6},
ReplaceSeparatorFunc: replaceSeparatorFunc, ReplaceSeparatorFunc: replaceSeparatorFunc,
} }

View File

@@ -8,23 +8,23 @@ import (
"strings" "strings"
"testing" "testing"
"git.defalsify.org/vise.git/cache"
"git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/state"
"git.grassecon.net/grassrootseconomics/common/pin" "git.grassecon.net/grassrootseconomics/common/pin"
"git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks" "git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks"
"git.grassecon.net/grassrootseconomics/sarafu-api/testutil/testservice" "git.grassecon.net/grassrootseconomics/sarafu-api/testutil/testservice"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store" "git.grassecon.net/grassrootseconomics/sarafu-vise/store"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/grassrootseconomics/go-vise/cache"
"github.com/grassrootseconomics/go-vise/persist"
"github.com/grassrootseconomics/go-vise/resource"
"github.com/grassrootseconomics/go-vise/state"
"github.com/alecthomas/assert/v2" "github.com/alecthomas/assert/v2"
testdataloader "github.com/peteole/testdata-loader" testdataloader "github.com/peteole/testdata-loader"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
visedb "git.defalsify.org/vise.git/db" visedb "github.com/grassrootseconomics/go-vise/db"
memdb "git.defalsify.org/vise.git/db/mem" memdb "github.com/grassrootseconomics/go-vise/db/mem"
) )
var ( var (
@@ -56,25 +56,6 @@ func InitializeTestStore(t *testing.T) (context.Context, *store.UserDataStore) {
return ctx, store return ctx, store
} }
// InitializeTestLogdbStore sets up and returns an in-memory database and logdb store.
func InitializeTestLogdbStore(t *testing.T) (context.Context, *store.UserDataStore) {
ctx := context.Background()
// Initialize memDb
db := memdb.NewMemDb()
err := db.Connect(ctx, "")
require.NoError(t, err, "Failed to connect to memDb")
// Create UserDataStore with memDb
logdb := &store.UserDataStore{Db: db}
t.Cleanup(func() {
db.Close(ctx) // Ensure the DB is closed after each test
})
return ctx, logdb
}
func InitializeTestSubPrefixDb(t *testing.T, ctx context.Context) *storedb.SubPrefixDb { func InitializeTestSubPrefixDb(t *testing.T, ctx context.Context) *storedb.SubPrefixDb {
db := memdb.NewMemDb() db := memdb.NewMemDb()
err := db.Connect(ctx, "") err := db.Connect(ctx, "")
@@ -89,7 +70,6 @@ func InitializeTestSubPrefixDb(t *testing.T, ctx context.Context) *storedb.SubPr
func TestNewMenuHandlers(t *testing.T) { func TestNewMenuHandlers(t *testing.T) {
_, store := InitializeTestStore(t) _, store := InitializeTestStore(t)
_, logdb := InitializeTestLogdbStore(t)
fm, err := NewFlagManager(flagsPath) fm, err := NewFlagManager(flagsPath)
if err != nil { if err != nil {
@@ -100,7 +80,7 @@ func TestNewMenuHandlers(t *testing.T) {
// Test case for valid UserDataStore // Test case for valid UserDataStore
t.Run("Valid UserDataStore", func(t *testing.T) { t.Run("Valid UserDataStore", func(t *testing.T) {
handlers, err := NewMenuHandlers(fm, store, logdb, &accountService, mockReplaceSeparator) handlers, err := NewMenuHandlers(fm, store, &accountService, mockReplaceSeparator)
if err != nil { if err != nil {
t.Fatalf("expected no error, got %v", err) t.Fatalf("expected no error, got %v", err)
} }
@@ -124,7 +104,7 @@ func TestNewMenuHandlers(t *testing.T) {
// Test case for nil UserDataStore // Test case for nil UserDataStore
t.Run("Nil UserDataStore", func(t *testing.T) { t.Run("Nil UserDataStore", func(t *testing.T) {
handlers, err := NewMenuHandlers(fm, nil, logdb, &accountService, mockReplaceSeparator) handlers, err := NewMenuHandlers(fm, nil, &accountService, mockReplaceSeparator)
if err == nil { if err == nil {
t.Fatal("expected an error, got none") t.Fatal("expected an error, got none")
} }
@@ -227,12 +207,6 @@ func TestCheckIdentifier(t *testing.T) {
ctx, userdatastore := InitializeTestStore(t) ctx, userdatastore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
// Define test cases // Define test cases
tests := []struct { tests := []struct {
name string name string
@@ -260,7 +234,6 @@ func TestCheckIdentifier(t *testing.T) {
// Create the MenuHandlers instance with the mock store // Create the MenuHandlers instance with the mock store
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: userdatastore, userdataStore: userdatastore,
logDb: logDb,
} }
// Call the method // Call the method

View File

@@ -5,11 +5,11 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/common/phone" "git.grassecon.net/grassrootseconomics/common/phone"
"git.grassecon.net/grassrootseconomics/common/pin" "git.grassecon.net/grassrootseconomics/common/pin"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/grassrootseconomics/go-vise/db"
"github.com/grassrootseconomics/go-vise/resource"
) )
// ResetIncorrectPin resets the incorrect pin flag after a new PIN attempt. // ResetIncorrectPin resets the incorrect pin flag after a new PIN attempt.
@@ -81,7 +81,6 @@ func (h *MenuHandlers) SaveTemporaryPin(ctx context.Context, sym string, input [
} }
store := h.userdataStore store := h.userdataStore
logdb := h.logDb
err = store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(hashedPIN)) err = store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(hashedPIN))
if err != nil { if err != nil {
@@ -89,11 +88,6 @@ func (h *MenuHandlers) SaveTemporaryPin(ctx context.Context, sym string, input [
return res, err return res, err
} }
err = logdb.WriteLogEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(hashedPIN))
if err != nil {
logg.DebugCtxf(ctx, "Failed to write temporaryAccountPIN log entry", "key", storedb.DATA_TEMPORARY_VALUE, "value", accountPIN, "error", err)
}
return res, nil return res, nil
} }
@@ -121,7 +115,6 @@ func (h *MenuHandlers) ConfirmPinChange(ctx context.Context, sym string, input [
} }
store := h.userdataStore store := h.userdataStore
logdb := h.logDb
hashedTemporaryPin, err := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE) hashedTemporaryPin, err := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if err != nil { if err != nil {
logg.ErrorCtxf(ctx, "failed to read hashedTemporaryPin entry with", "key", storedb.DATA_TEMPORARY_VALUE, "error", err) logg.ErrorCtxf(ctx, "failed to read hashedTemporaryPin entry with", "key", storedb.DATA_TEMPORARY_VALUE, "error", err)
@@ -146,11 +139,6 @@ func (h *MenuHandlers) ConfirmPinChange(ctx context.Context, sym string, input [
return res, err return res, err
} }
err = logdb.WriteLogEntry(ctx, sessionId, storedb.DATA_ACCOUNT_PIN, []byte(hashedTemporaryPin))
if err != nil {
logg.DebugCtxf(ctx, "Failed to write AccountPIN log entry", "key", storedb.DATA_ACCOUNT_PIN, "value", hashedTemporaryPin, "error", err)
}
// set the DATA_SELF_PIN_RESET as 0 // set the DATA_SELF_PIN_RESET as 0
err = store.WriteEntry(ctx, sessionId, storedb.DATA_SELF_PIN_RESET, []byte("0")) err = store.WriteEntry(ctx, sessionId, storedb.DATA_SELF_PIN_RESET, []byte("0"))
if err != nil { if err != nil {
@@ -171,7 +159,6 @@ func (h *MenuHandlers) ValidateBlockedNumber(ctx context.Context, sym string, in
flag_unregistered_number, _ := h.flagManager.GetFlag("flag_unregistered_number") flag_unregistered_number, _ := h.flagManager.GetFlag("flag_unregistered_number")
store := h.userdataStore store := h.userdataStore
logdb := h.logDb
sessionId, ok := ctx.Value("SessionId").(string) sessionId, ok := ctx.Value("SessionId").(string)
if !ok { if !ok {
return res, fmt.Errorf("missing session") return res, fmt.Errorf("missing session")
@@ -207,11 +194,6 @@ func (h *MenuHandlers) ValidateBlockedNumber(ctx context.Context, sym string, in
return res, nil return res, nil
} }
err = logdb.WriteLogEntry(ctx, sessionId, storedb.DATA_BLOCKED_NUMBER, []byte(formattedNumber))
if err != nil {
logg.DebugCtxf(ctx, "Failed to write blocked number log entry", "key", storedb.DATA_BLOCKED_NUMBER, "value", formattedNumber, "error", err)
}
return res, nil return res, nil
} }
@@ -319,7 +301,6 @@ func (h *MenuHandlers) VerifyCreatePin(ctx context.Context, sym string, input []
} }
store := h.userdataStore store := h.userdataStore
logdb := h.logDb
hashedTemporaryPin, err := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE) hashedTemporaryPin, err := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if err != nil { if err != nil {
@@ -347,11 +328,6 @@ func (h *MenuHandlers) VerifyCreatePin(ctx context.Context, sym string, input []
return res, err return res, err
} }
err = logdb.WriteLogEntry(ctx, sessionId, storedb.DATA_ACCOUNT_PIN, []byte(hashedTemporaryPin))
if err != nil {
logg.DebugCtxf(ctx, "Failed to write DATA_ACCOUNT_PIN log entry", "key", storedb.DATA_ACCOUNT_PIN, "value", hashedTemporaryPin, "error", err)
}
return res, nil return res, nil
} }

View File

@@ -6,13 +6,12 @@ import (
"strconv" "strconv"
"testing" "testing"
"git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/state"
"git.grassecon.net/grassrootseconomics/common/pin" "git.grassecon.net/grassrootseconomics/common/pin"
"git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks" "git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/alecthomas/assert/v2" "github.com/alecthomas/assert/v2"
"github.com/grassrootseconomics/go-vise/resource"
"github.com/grassrootseconomics/go-vise/state"
) )
func TestCountIncorrectPINAttempts(t *testing.T) { func TestCountIncorrectPINAttempts(t *testing.T) {
@@ -71,11 +70,6 @@ func TestSaveTemporaryPin(t *testing.T) {
ctx, userdatastore := InitializeTestStore(t) ctx, userdatastore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
fm, err := NewFlagManager(flagsPath) fm, err := NewFlagManager(flagsPath)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@@ -87,7 +81,6 @@ func TestSaveTemporaryPin(t *testing.T) {
h := &MenuHandlers{ h := &MenuHandlers{
flagManager: fm, flagManager: fm,
userdataStore: userdatastore, userdataStore: userdatastore,
logDb: logDb,
} }
// Define test cases // Define test cases

View File

@@ -4,11 +4,11 @@ import (
"context" "context"
"fmt" "fmt"
"git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config" "git.grassecon.net/grassrootseconomics/sarafu-vise/config"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store" "git.grassecon.net/grassrootseconomics/sarafu-vise/store"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/grassrootseconomics/go-vise/db"
"github.com/grassrootseconomics/go-vise/resource"
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
"gopkg.in/leonelquinteros/gotext.v1" "gopkg.in/leonelquinteros/gotext.v1"
) )
@@ -22,12 +22,12 @@ func (h *MenuHandlers) GetPools(ctx context.Context, sym string, input []byte) (
} }
userStore := h.userdataStore userStore := h.userdataStore
flag_api_error, _ := h.flagManager.GetFlag("flag_api_error") flag_api_call_error, _ := h.flagManager.GetFlag("flag_api_call_error")
// call the api to get a list of top 5 pools sorted by swaps // call the api to get a list of top 5 pools sorted by swaps
topPools, err := h.accountService.FetchTopPools(ctx) topPools, err := h.accountService.FetchTopPools(ctx)
if err != nil { if err != nil {
res.FlagSet = append(res.FlagSet, flag_api_error) res.FlagSet = append(res.FlagSet, flag_api_call_error)
logg.ErrorCtxf(ctx, "failed on FetchTransactions", "error", err) logg.ErrorCtxf(ctx, "failed on FetchTransactions", "error", err)
return res, err return res, err
} }
@@ -129,12 +129,12 @@ func (h *MenuHandlers) ViewPool(ctx context.Context, sym string, input []byte) (
} }
if poolData == nil { if poolData == nil {
flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") flag_api_call_error, _ := h.flagManager.GetFlag("flag_api_call_error")
// no match found. Call the API using the inputStr as the symbol // no match found. Call the API using the inputStr as the symbol
poolResp, err := h.accountService.RetrievePoolDetails(ctx, inputStr) poolResp, err := h.accountService.RetrievePoolDetails(ctx, inputStr)
if err != nil { if err != nil {
res.FlagSet = append(res.FlagSet, flag_api_error) res.FlagSet = append(res.FlagSet, flag_api_call_error)
return res, nil return res, nil
} }

View File

@@ -5,11 +5,11 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config" "git.grassecon.net/grassrootseconomics/sarafu-vise/config"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store" "git.grassecon.net/grassrootseconomics/sarafu-vise/store"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/grassrootseconomics/go-vise/db"
"github.com/grassrootseconomics/go-vise/resource"
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
"gopkg.in/leonelquinteros/gotext.v1" "gopkg.in/leonelquinteros/gotext.v1"
) )
@@ -41,7 +41,7 @@ func (h *MenuHandlers) LoadSwapToList(ctx context.Context, sym string, input []b
l.AddDomain("default") l.AddDomain("default")
flag_incorrect_voucher, _ := h.flagManager.GetFlag("flag_incorrect_voucher") flag_incorrect_voucher, _ := h.flagManager.GetFlag("flag_incorrect_voucher")
flag_api_error, _ := h.flagManager.GetFlag("flag_api_error") flag_api_call_error, _ := h.flagManager.GetFlag("flag_api_call_error")
inputStr := string(input) inputStr := string(input)
if inputStr == "0" { if inputStr == "0" {
@@ -88,7 +88,7 @@ func (h *MenuHandlers) LoadSwapToList(ctx context.Context, sym string, input []b
// call the api using the ActivePoolAddress and ActiveVoucherAddress to check if it is part of the pool // call the api using the ActivePoolAddress and ActiveVoucherAddress to check if it is part of the pool
r, err := h.accountService.CheckTokenInPool(ctx, string(activePoolAddress), string(activeAddress)) r, err := h.accountService.CheckTokenInPool(ctx, string(activePoolAddress), string(activeAddress))
if err != nil { if err != nil {
res.FlagSet = append(res.FlagSet, flag_api_error) res.FlagSet = append(res.FlagSet, flag_api_call_error)
logg.ErrorCtxf(ctx, "failed on CheckTokenInPool", "error", err) logg.ErrorCtxf(ctx, "failed on CheckTokenInPool", "error", err)
return res, err return res, err
} }
@@ -110,7 +110,7 @@ func (h *MenuHandlers) LoadSwapToList(ctx context.Context, sym string, input []b
// call the api using the activePoolAddress to get a list of SwapToSymbolsData // call the api using the activePoolAddress to get a list of SwapToSymbolsData
swapToList, err := h.accountService.GetPoolSwappableVouchers(ctx, string(activePoolAddress)) swapToList, err := h.accountService.GetPoolSwappableVouchers(ctx, string(activePoolAddress))
if err != nil { if err != nil {
res.FlagSet = append(res.FlagSet, flag_api_error) res.FlagSet = append(res.FlagSet, flag_api_call_error)
logg.ErrorCtxf(ctx, "failed on FetchTransactions", "error", err) logg.ErrorCtxf(ctx, "failed on FetchTransactions", "error", err)
return res, err return res, err
} }
@@ -165,7 +165,7 @@ func (h *MenuHandlers) SwapMaxLimit(ctx context.Context, sym string, input []byt
} }
flag_incorrect_voucher, _ := h.flagManager.GetFlag("flag_incorrect_voucher") flag_incorrect_voucher, _ := h.flagManager.GetFlag("flag_incorrect_voucher")
flag_api_error, _ := h.flagManager.GetFlag("flag_api_error") flag_api_call_error, _ := h.flagManager.GetFlag("flag_api_call_error")
flag_low_swap_amount, _ := h.flagManager.GetFlag("flag_low_swap_amount") flag_low_swap_amount, _ := h.flagManager.GetFlag("flag_low_swap_amount")
res.FlagReset = append(res.FlagReset, flag_incorrect_voucher, flag_low_swap_amount) res.FlagReset = append(res.FlagReset, flag_incorrect_voucher, flag_low_swap_amount)
@@ -202,9 +202,9 @@ func (h *MenuHandlers) SwapMaxLimit(ctx context.Context, sym string, input []byt
logg.InfoCtxf(ctx, "Call GetSwapFromTokenMaxLimit with:", "ActivePoolAddress", swapData.ActivePoolAddress, "ActiveSwapFromAddress", swapData.ActiveSwapFromAddress, "ActiveSwapToAddress", swapData.ActiveSwapToAddress, "publicKey", swapData.PublicKey) logg.InfoCtxf(ctx, "Call GetSwapFromTokenMaxLimit with:", "ActivePoolAddress", swapData.ActivePoolAddress, "ActiveSwapFromAddress", swapData.ActiveSwapFromAddress, "ActiveSwapToAddress", swapData.ActiveSwapToAddress, "publicKey", swapData.PublicKey)
r, err := h.accountService.GetSwapFromTokenMaxLimit(ctx, swapData.ActivePoolAddress, swapData.ActiveSwapFromAddress, swapData.ActiveSwapToAddress, swapData.PublicKey) r, err := h.accountService.GetSwapFromTokenMaxLimit(ctx, swapData.ActivePoolAddress, swapData.ActiveSwapFromAddress, swapData.ActiveSwapToAddress, swapData.PublicKey)
if err != nil { if err != nil {
res.FlagSet = append(res.FlagSet, flag_api_error) res.FlagSet = append(res.FlagSet, flag_api_call_error)
logg.ErrorCtxf(ctx, "failed on GetSwapFromTokenMaxLimit", "error", err) logg.ErrorCtxf(ctx, "failed on GetSwapFromTokenMaxLimit", "error", err)
return res, err return res, nil
} }
// Scale down the amount // Scale down the amount
@@ -220,7 +220,7 @@ func (h *MenuHandlers) SwapMaxLimit(ctx context.Context, sym string, input []byt
} }
// Format to 2 decimal places // Format to 2 decimal places
maxStr := fmt.Sprintf("%.2f", maxAmountFloat) maxStr, _ := store.TruncateDecimalString(string(maxAmountStr), 2)
if maxAmountFloat < 0.1 { if maxAmountFloat < 0.1 {
// return with low amount flag // return with low amount flag
@@ -310,8 +310,8 @@ func (h *MenuHandlers) SwapPreview(ctx context.Context, sym string, input []byte
// call the API to get the quote // call the API to get the quote
r, err := h.accountService.GetPoolSwapQuote(ctx, finalAmountStr, swapData.PublicKey, swapData.ActiveSwapFromAddress, swapData.ActivePoolAddress, swapData.ActiveSwapToAddress) r, err := h.accountService.GetPoolSwapQuote(ctx, finalAmountStr, swapData.PublicKey, swapData.ActiveSwapFromAddress, swapData.ActivePoolAddress, swapData.ActiveSwapToAddress)
if err != nil { if err != nil {
flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") flag_api_call_error, _ := h.flagManager.GetFlag("flag_api_call_error")
res.FlagSet = append(res.FlagSet, flag_api_error) res.FlagSet = append(res.FlagSet, flag_api_call_error)
res.Content = l.Get("Your request failed. Please try again later.") res.Content = l.Get("Your request failed. Please try again later.")
logg.ErrorCtxf(ctx, "failed on poolSwap", "error", err) logg.ErrorCtxf(ctx, "failed on poolSwap", "error", err)
return res, nil return res, nil
@@ -319,14 +319,9 @@ func (h *MenuHandlers) SwapPreview(ctx context.Context, sym string, input []byte
// Scale down the quoted amount // Scale down the quoted amount
quoteAmountStr := store.ScaleDownBalance(r.OutValue, swapData.ActiveSwapToDecimal) quoteAmountStr := store.ScaleDownBalance(r.OutValue, swapData.ActiveSwapToDecimal)
qouteAmount, err := strconv.ParseFloat(quoteAmountStr, 64)
if err != nil {
logg.ErrorCtxf(ctx, "failed to parse quoteAmountStr as float", "value", quoteAmountStr, "error", err)
return res, err
}
// Format to 2 decimal places // Format to 2 decimal places
qouteStr := fmt.Sprintf("%.2f", qouteAmount) qouteStr, _ := store.TruncateDecimalString(string(quoteAmountStr), 2)
res.Content = fmt.Sprintf( res.Content = fmt.Sprintf(
"You will swap:\n%s %s for %s %s:", "You will swap:\n%s %s for %s %s:",
@@ -369,8 +364,8 @@ func (h *MenuHandlers) InitiateSwap(ctx context.Context, sym string, input []byt
// Call the poolSwap API // Call the poolSwap API
r, err := h.accountService.PoolSwap(ctx, swapAmountStr, swapData.PublicKey, swapData.ActiveSwapFromAddress, swapData.ActivePoolAddress, swapData.ActiveSwapToAddress) r, err := h.accountService.PoolSwap(ctx, swapAmountStr, swapData.PublicKey, swapData.ActiveSwapFromAddress, swapData.ActivePoolAddress, swapData.ActiveSwapToAddress)
if err != nil { if err != nil {
flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") flag_api_call_error, _ := h.flagManager.GetFlag("flag_api_call_error")
res.FlagSet = append(res.FlagSet, flag_api_error) res.FlagSet = append(res.FlagSet, flag_api_call_error)
res.Content = l.Get("Your request failed. Please try again later.") res.Content = l.Get("Your request failed. Please try again later.")
logg.ErrorCtxf(ctx, "failed on poolSwap", "error", err) logg.ErrorCtxf(ctx, "failed on poolSwap", "error", err)
return res, nil return res, nil

View File

@@ -6,11 +6,11 @@ import (
"strconv" "strconv"
"strings" "strings"
"git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/lang"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/common/person" "git.grassecon.net/grassrootseconomics/common/person"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/grassrootseconomics/go-vise/db"
"github.com/grassrootseconomics/go-vise/lang"
"github.com/grassrootseconomics/go-vise/resource"
) )
// SaveFirstname updates the first name in the gdbm with the provided input. // SaveFirstname updates the first name in the gdbm with the provided input.
@@ -24,7 +24,6 @@ func (h *MenuHandlers) SaveFirstname(ctx context.Context, sym string, input []by
firstName := string(input) firstName := string(input)
store := h.userdataStore store := h.userdataStore
logdb := h.logDb
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
flag_firstname_set, _ := h.flagManager.GetFlag("flag_firstname_set") flag_firstname_set, _ := h.flagManager.GetFlag("flag_firstname_set")
@@ -44,10 +43,6 @@ func (h *MenuHandlers) SaveFirstname(ctx context.Context, sym string, input []by
} }
res.FlagSet = append(res.FlagSet, flag_firstname_set) res.FlagSet = append(res.FlagSet, flag_firstname_set)
err = logdb.WriteLogEntry(ctx, sessionId, storedb.DATA_FIRST_NAME, []byte(temporaryFirstName))
if err != nil {
logg.DebugCtxf(ctx, "Failed to write firtname db log entry", "key", storedb.DATA_FIRST_NAME, "value", temporaryFirstName)
}
} else { } else {
if firstNameSet { if firstNameSet {
err = store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(firstName)) err = store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(firstName))
@@ -73,7 +68,6 @@ func (h *MenuHandlers) SaveFamilyname(ctx context.Context, sym string, input []b
} }
store := h.userdataStore store := h.userdataStore
logdb := h.logDb
familyName := string(input) familyName := string(input)
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
@@ -94,10 +88,6 @@ func (h *MenuHandlers) SaveFamilyname(ctx context.Context, sym string, input []b
} }
res.FlagSet = append(res.FlagSet, flag_familyname_set) res.FlagSet = append(res.FlagSet, flag_familyname_set)
err = logdb.WriteLogEntry(ctx, sessionId, storedb.DATA_FAMILY_NAME, []byte(temporaryFamilyName))
if err != nil {
logg.DebugCtxf(ctx, "Failed to write firtname db log entry", "key", storedb.DATA_FAMILY_NAME, "value", temporaryFamilyName)
}
} else { } else {
if familyNameSet { if familyNameSet {
err = store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(familyName)) err = store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(familyName))
@@ -154,7 +144,6 @@ func (h *MenuHandlers) SaveYob(ctx context.Context, sym string, input []byte) (r
} }
yob := string(input) yob := string(input)
store := h.userdataStore store := h.userdataStore
logdb := h.logDb
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
flag_yob_set, _ := h.flagManager.GetFlag("flag_yob_set") flag_yob_set, _ := h.flagManager.GetFlag("flag_yob_set")
@@ -175,10 +164,6 @@ func (h *MenuHandlers) SaveYob(ctx context.Context, sym string, input []byte) (r
} }
res.FlagSet = append(res.FlagSet, flag_yob_set) res.FlagSet = append(res.FlagSet, flag_yob_set)
err = logdb.WriteLogEntry(ctx, sessionId, storedb.DATA_YOB, []byte(temporaryYob))
if err != nil {
logg.DebugCtxf(ctx, "Failed to write yob db log entry", "key", storedb.DATA_YOB, "value", temporaryYob)
}
} else { } else {
if yobSet { if yobSet {
err = store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(yob)) err = store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(yob))
@@ -204,7 +189,6 @@ func (h *MenuHandlers) SaveLocation(ctx context.Context, sym string, input []byt
} }
location := string(input) location := string(input)
store := h.userdataStore store := h.userdataStore
logdb := h.logDb
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
flag_location_set, _ := h.flagManager.GetFlag("flag_location_set") flag_location_set, _ := h.flagManager.GetFlag("flag_location_set")
@@ -224,10 +208,6 @@ func (h *MenuHandlers) SaveLocation(ctx context.Context, sym string, input []byt
} }
res.FlagSet = append(res.FlagSet, flag_location_set) res.FlagSet = append(res.FlagSet, flag_location_set)
err = logdb.WriteLogEntry(ctx, sessionId, storedb.DATA_LOCATION, []byte(temporaryLocation))
if err != nil {
logg.DebugCtxf(ctx, "Failed to write location db log entry", "key", storedb.DATA_LOCATION, "value", temporaryLocation)
}
} else { } else {
if locationSet { if locationSet {
err = store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(location)) err = store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(location))
@@ -255,7 +235,6 @@ func (h *MenuHandlers) SaveGender(ctx context.Context, sym string, input []byte)
} }
gender := strings.Split(symbol, "_")[1] gender := strings.Split(symbol, "_")[1]
store := h.userdataStore store := h.userdataStore
logdb := h.logDb
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
flag_gender_set, _ := h.flagManager.GetFlag("flag_gender_set") flag_gender_set, _ := h.flagManager.GetFlag("flag_gender_set")
@@ -275,11 +254,6 @@ func (h *MenuHandlers) SaveGender(ctx context.Context, sym string, input []byte)
} }
res.FlagSet = append(res.FlagSet, flag_gender_set) res.FlagSet = append(res.FlagSet, flag_gender_set)
err = logdb.WriteLogEntry(ctx, sessionId, storedb.DATA_GENDER, []byte(temporaryGender))
if err != nil {
logg.DebugCtxf(ctx, "Failed to write gender db log entry", "key", storedb.DATA_TEMPORARY_VALUE, "value", temporaryGender)
}
} else { } else {
if genderSet { if genderSet {
err = store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(gender)) err = store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(gender))
@@ -306,7 +280,6 @@ func (h *MenuHandlers) SaveOfferings(ctx context.Context, sym string, input []by
offerings := string(input) offerings := string(input)
store := h.userdataStore store := h.userdataStore
logdb := h.logDb
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
flag_offerings_set, _ := h.flagManager.GetFlag("flag_offerings_set") flag_offerings_set, _ := h.flagManager.GetFlag("flag_offerings_set")
@@ -326,11 +299,6 @@ func (h *MenuHandlers) SaveOfferings(ctx context.Context, sym string, input []by
return res, err return res, err
} }
res.FlagSet = append(res.FlagSet, flag_offerings_set) res.FlagSet = append(res.FlagSet, flag_offerings_set)
err = logdb.WriteLogEntry(ctx, sessionId, storedb.DATA_FIRST_NAME, []byte(temporaryOfferings))
if err != nil {
logg.DebugCtxf(ctx, "Failed to write offerings db log entry", "key", storedb.DATA_OFFERINGS, "value", offerings)
}
} else { } else {
if offeringsSet { if offeringsSet {
err = store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(offerings)) err = store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(offerings))

View File

@@ -6,14 +6,13 @@ import (
"log" "log"
"testing" "testing"
"git.defalsify.org/vise.git/lang"
"git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/state"
"git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks" "git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks"
"git.grassecon.net/grassrootseconomics/sarafu-vise/profile" "git.grassecon.net/grassrootseconomics/sarafu-vise/profile"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/alecthomas/assert/v2" "github.com/alecthomas/assert/v2"
"github.com/grassrootseconomics/go-vise/lang"
"github.com/grassrootseconomics/go-vise/resource"
"github.com/grassrootseconomics/go-vise/state"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -21,11 +20,6 @@ func TestSaveFirstname(t *testing.T) {
sessionId := "session123" sessionId := "session123"
ctx, userStore := InitializeTestStore(t) ctx, userStore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
fm, _ := NewFlagManager(flagsPath) fm, _ := NewFlagManager(flagsPath)
@@ -52,7 +46,6 @@ func TestSaveFirstname(t *testing.T) {
userdataStore: userStore, userdataStore: userStore,
flagManager: fm, flagManager: fm,
st: mockState, st: mockState,
logDb: logDb,
} }
// Call the method // Call the method
@@ -71,11 +64,6 @@ func TestSaveFamilyname(t *testing.T) {
sessionId := "session123" sessionId := "session123"
ctx, userStore := InitializeTestStore(t) ctx, userStore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
fm, _ := NewFlagManager(flagsPath) fm, _ := NewFlagManager(flagsPath)
@@ -102,7 +90,6 @@ func TestSaveFamilyname(t *testing.T) {
userdataStore: userStore, userdataStore: userStore,
st: mockState, st: mockState,
flagManager: fm, flagManager: fm,
logDb: logDb,
} }
// Call the method // Call the method
@@ -224,11 +211,6 @@ func TestSaveYob(t *testing.T) {
sessionId := "session123" sessionId := "session123"
ctx, userStore := InitializeTestStore(t) ctx, userStore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
fm, _ := NewFlagManager(flagsPath) fm, _ := NewFlagManager(flagsPath)
@@ -255,7 +237,6 @@ func TestSaveYob(t *testing.T) {
userdataStore: userStore, userdataStore: userStore,
flagManager: fm, flagManager: fm,
st: mockState, st: mockState,
logDb: logDb,
} }
// Call the method // Call the method
@@ -274,11 +255,6 @@ func TestSaveLocation(t *testing.T) {
sessionId := "session123" sessionId := "session123"
ctx, userStore := InitializeTestStore(t) ctx, userStore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
fm, _ := NewFlagManager(flagsPath) fm, _ := NewFlagManager(flagsPath)
@@ -305,7 +281,6 @@ func TestSaveLocation(t *testing.T) {
userdataStore: userStore, userdataStore: userStore,
flagManager: fm, flagManager: fm,
st: mockState, st: mockState,
logDb: logDb,
} }
// Call the method // Call the method
@@ -324,11 +299,6 @@ func TestSaveGender(t *testing.T) {
sessionId := "session123" sessionId := "session123"
ctx, userStore := InitializeTestStore(t) ctx, userStore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
fm, _ := NewFlagManager(flagsPath) fm, _ := NewFlagManager(flagsPath)
@@ -378,7 +348,6 @@ func TestSaveGender(t *testing.T) {
userdataStore: userStore, userdataStore: userStore,
st: mockState, st: mockState,
flagManager: fm, flagManager: fm,
logDb: logDb,
} }
expectedResult := resource.Result{} expectedResult := resource.Result{}
@@ -403,11 +372,6 @@ func TestSaveOfferings(t *testing.T) {
sessionId := "session123" sessionId := "session123"
ctx, userStore := InitializeTestStore(t) ctx, userStore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
fm, _ := NewFlagManager(flagsPath) fm, _ := NewFlagManager(flagsPath)
@@ -434,7 +398,6 @@ func TestSaveOfferings(t *testing.T) {
userdataStore: userStore, userdataStore: userStore,
flagManager: fm, flagManager: fm,
st: mockState, st: mockState,
logDb: logDb,
} }
// Call the method // Call the method

View File

@@ -4,8 +4,8 @@ import (
"context" "context"
"fmt" "fmt"
"git.defalsify.org/vise.git/db" "github.com/grassrootseconomics/go-vise/db"
"git.defalsify.org/vise.git/resource" "github.com/grassrootseconomics/go-vise/resource"
"git.grassecon.net/grassrootseconomics/common/hex" "git.grassecon.net/grassrootseconomics/common/hex"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
@@ -33,16 +33,11 @@ func (h *MenuHandlers) createAccountNoExist(ctx context.Context, sessionId strin
storedb.DATA_ACCOUNT_ALIAS: "", storedb.DATA_ACCOUNT_ALIAS: "",
} }
store := h.userdataStore store := h.userdataStore
logdb := h.logDb
for key, value := range data { for key, value := range data {
err = store.WriteEntry(ctx, sessionId, key, []byte(value)) err = store.WriteEntry(ctx, sessionId, key, []byte(value))
if err != nil { if err != nil {
return err return err
} }
err = logdb.WriteLogEntry(ctx, sessionId, key, []byte(value))
if err != nil {
logg.DebugCtxf(ctx, "Failed to write log entry", "key", key, "value", value)
}
} }
publicKeyNormalized, err := hex.NormalizeHex(publicKey) publicKeyNormalized, err := hex.NormalizeHex(publicKey)
if err != nil { if err != nil {
@@ -53,11 +48,6 @@ func (h *MenuHandlers) createAccountNoExist(ctx context.Context, sessionId strin
return err return err
} }
err = logdb.WriteLogEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY_REVERSE, []byte(sessionId))
if err != nil {
logg.DebugCtxf(ctx, "Failed to write log entry", "key", storedb.DATA_PUBLIC_KEY_REVERSE, "value", sessionId)
}
res.FlagSet = append(res.FlagSet, flag_account_created) res.FlagSet = append(res.FlagSet, flag_account_created)
return nil return nil
} }

View File

@@ -4,22 +4,16 @@ import (
"context" "context"
"testing" "testing"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/sarafu-api/models" "git.grassecon.net/grassrootseconomics/sarafu-api/models"
"git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks" "git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store"
"github.com/alecthomas/assert/v2" "github.com/alecthomas/assert/v2"
"github.com/grassrootseconomics/go-vise/resource"
) )
func TestCreateAccount(t *testing.T) { func TestCreateAccount(t *testing.T) {
sessionId := "session123" sessionId := "session123"
ctx, userStore := InitializeTestStore(t) ctx, userStore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
fm, err := NewFlagManager(flagsPath) fm, err := NewFlagManager(flagsPath)
if err != nil { if err != nil {
@@ -57,7 +51,6 @@ func TestCreateAccount(t *testing.T) {
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: userStore, userdataStore: userStore,
accountService: mockAccountService, accountService: mockAccountService,
logDb: logDb,
flagManager: fm, flagManager: fm,
} }

View File

@@ -7,137 +7,241 @@ import (
"strconv" "strconv"
"strings" "strings"
"git.defalsify.org/vise.git/db" "git.grassecon.net/grassrootseconomics/common/hex"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/common/identity" "git.grassecon.net/grassrootseconomics/common/identity"
"git.grassecon.net/grassrootseconomics/common/phone" "git.grassecon.net/grassrootseconomics/common/phone"
"git.grassecon.net/grassrootseconomics/sarafu-api/models"
"git.grassecon.net/grassrootseconomics/sarafu-api/remote/http" "git.grassecon.net/grassrootseconomics/sarafu-api/remote/http"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config" "git.grassecon.net/grassrootseconomics/sarafu-vise/config"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store" "git.grassecon.net/grassrootseconomics/sarafu-vise/store"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/grassrootseconomics/ethutils" "github.com/grassrootseconomics/ethutils"
"github.com/grassrootseconomics/go-vise/db"
"github.com/grassrootseconomics/go-vise/resource"
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
"gopkg.in/leonelquinteros/gotext.v1" "gopkg.in/leonelquinteros/gotext.v1"
) )
// ValidateRecipient validates that the given input is valid. // ValidateRecipient validates that the given input is valid.
//
// TODO: split up functino
func (h *MenuHandlers) ValidateRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *MenuHandlers) ValidateRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var AliasAddressResult string
var AliasAddress *models.AliasAddress
store := h.userdataStore store := h.userdataStore
flag_invalid_recipient, _ := h.flagManager.GetFlag("flag_invalid_recipient")
sessionId, ok := ctx.Value("SessionId").(string) sessionId, ok := ctx.Value("SessionId").(string)
if !ok { if !ok {
return res, fmt.Errorf("missing session") return res, fmt.Errorf("missing session")
} }
flag_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")
// remove white spaces // remove white spaces
recipient := strings.ReplaceAll(string(input), " ", "") recipient := strings.ReplaceAll(string(input), " ", "")
if recipient == "0" {
return res, nil
}
if recipient != "0" { recipientType, err := identity.CheckRecipient(recipient)
recipientType, err := identity.CheckRecipient(recipient) if err != nil {
if err != nil { // Invalid recipient format (not a phone number, address, or valid alias format)
// Invalid recipient format (not a phone number, address, or valid alias format) res.FlagSet = append(res.FlagSet, flag_invalid_recipient)
res.FlagSet = append(res.FlagSet, flag_invalid_recipient) res.Content = recipient
return res, nil
}
// save the recipient as the temporaryRecipient
err = store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(recipient))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write temporaryRecipient entry with", "key", storedb.DATA_TEMPORARY_VALUE, "value", recipient, "error", err)
return res, err
}
switch recipientType {
case "phone number":
return h.handlePhoneNumber(ctx, sessionId, recipient, &res)
case "address":
return h.handleAddress(ctx, sessionId, recipient, &res)
case "alias":
return h.handleAlias(ctx, sessionId, recipient, &res)
}
return res, nil
}
func (h *MenuHandlers) handlePhoneNumber(ctx context.Context, sessionId, recipient string, res *resource.Result) (resource.Result, error) {
store := h.userdataStore
flag_invalid_recipient_with_invite, _ := h.flagManager.GetFlag("flag_invalid_recipient_with_invite")
formattedNumber, err := phone.FormatPhoneNumber(recipient)
if err != nil {
logg.ErrorCtxf(ctx, "Failed to format phone number", "recipient", recipient, "error", err)
return *res, err
}
publicKey, err := store.ReadEntry(ctx, formattedNumber, storedb.DATA_PUBLIC_KEY)
if err != nil {
if db.IsNotFound(err) {
logg.InfoCtxf(ctx, "Unregistered phone number", "recipient", recipient)
res.FlagSet = append(res.FlagSet, flag_invalid_recipient_with_invite)
res.Content = recipient res.Content = recipient
return *res, nil
return res, nil
} }
logg.ErrorCtxf(ctx, "Failed to read publicKey", "error", err)
return *res, err
}
// save the recipient as the temporaryRecipient if err := store.WriteEntry(ctx, sessionId, storedb.DATA_RECIPIENT, publicKey); err != nil {
err = store.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(recipient)) logg.ErrorCtxf(ctx, "Failed to write recipient", "value", string(publicKey), "error", err)
if err != nil { return *res, err
logg.ErrorCtxf(ctx, "failed to write temporaryRecipient entry with", "key", storedb.DATA_TEMPORARY_VALUE, "value", recipient, "error", err) }
return res, err
// Delegate to shared logic
if err := h.determineAndSaveTransactionType(ctx, sessionId, publicKey, []byte(formattedNumber)); err != nil {
return *res, err
}
return *res, nil
}
func (h *MenuHandlers) handleAddress(ctx context.Context, sessionId, recipient string, res *resource.Result) (resource.Result, error) {
store := h.userdataStore
address := ethutils.ChecksumAddress(recipient)
if err := store.WriteEntry(ctx, sessionId, storedb.DATA_RECIPIENT, []byte(address)); err != nil {
logg.ErrorCtxf(ctx, "Failed to write recipient address", "error", err)
return *res, err
}
// normalize the address to fetch the recipient's phone number
publicKeyNormalized, err := hex.NormalizeHex(address)
if err != nil {
return *res, err
}
// get the recipient's phone number from the address
recipientPhoneNumber, err := store.ReadEntry(ctx, publicKeyNormalized, storedb.DATA_PUBLIC_KEY_REVERSE)
if err != nil || len(recipientPhoneNumber) == 0 {
logg.WarnCtxf(ctx, "Recipient address not registered, switching to normal transaction", "address", address)
recipientPhoneNumber = nil
}
if err := h.determineAndSaveTransactionType(ctx, sessionId, []byte(address), recipientPhoneNumber); err != nil {
return *res, err
}
return *res, nil
}
func (h *MenuHandlers) handleAlias(ctx context.Context, sessionId, recipient string, res *resource.Result) (resource.Result, error) {
store := h.userdataStore
flag_invalid_recipient, _ := h.flagManager.GetFlag("flag_invalid_recipient")
flag_api_call_error, _ := h.flagManager.GetFlag("flag_api_call_error")
var aliasAddressResult string
if strings.Contains(recipient, ".") {
alias, err := h.accountService.CheckAliasAddress(ctx, recipient)
if err == nil {
aliasAddressResult = alias.Address
} else {
logg.ErrorCtxf(ctx, "Failed to resolve alias", "alias", recipient, "error", err)
} }
} else {
for _, domain := range config.SearchDomains() {
fqdn := fmt.Sprintf("%s.%s", recipient, domain)
logg.InfoCtxf(ctx, "Trying alias", "fqdn", fqdn)
switch recipientType { alias, err := h.accountService.CheckAliasAddress(ctx, fqdn)
case "phone number": if err == nil {
// format the phone number res.FlagReset = append(res.FlagReset, flag_api_call_error)
formattedNumber, err := phone.FormatPhoneNumber(recipient) aliasAddressResult = alias.Address
if err != nil { break
logg.ErrorCtxf(ctx, "Failed to format the phone number: %s", recipient, "error", err)
return res, err
}
// Check if the phone number is registered
publicKey, err := store.ReadEntry(ctx, formattedNumber, storedb.DATA_PUBLIC_KEY)
if err != nil {
if db.IsNotFound(err) {
logg.InfoCtxf(ctx, "Unregistered phone number: %s", recipient)
res.FlagSet = append(res.FlagSet, flag_invalid_recipient_with_invite)
res.Content = recipient
return res, nil
}
logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", storedb.DATA_PUBLIC_KEY, "error", err)
return res, err
}
// Save the publicKey as the recipient
err = store.WriteEntry(ctx, sessionId, storedb.DATA_RECIPIENT, publicKey)
if err != nil {
logg.ErrorCtxf(ctx, "failed to write recipient entry with", "key", storedb.DATA_RECIPIENT, "value", string(publicKey), "error", err)
return res, err
}
case "address":
// checksum the address
address := ethutils.ChecksumAddress(recipient)
// Save the valid Ethereum address as the recipient
err = store.WriteEntry(ctx, sessionId, storedb.DATA_RECIPIENT, []byte(address))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write recipient entry with", "key", storedb.DATA_RECIPIENT, "value", recipient, "error", err)
return res, err
}
case "alias":
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 { } else {
//Perform a search for each search domain,break on first match res.FlagSet = append(res.FlagSet, flag_api_call_error)
for _, domain := range config.SearchDomains() { logg.ErrorCtxf(ctx, "Alias resolution failed", "alias", fqdn, "error", err)
fqdn := fmt.Sprintf("%s.%s", recipient, domain) return *res, nil
logg.InfoCtxf(ctx, "Resolving with fqdn alias", "alias", fqdn)
AliasAddress, err = h.accountService.CheckAliasAddress(ctx, fqdn)
if err == nil {
res.FlagReset = append(res.FlagReset, flag_api_error)
AliasAddressResult = AliasAddress.Address
continue
} else {
res.FlagSet = append(res.FlagSet, flag_api_error)
logg.ErrorCtxf(ctx, "failed to resolve alias", "alias", recipient, "error_alias_check", err)
return res, nil
}
}
}
if AliasAddressResult == "" {
res.Content = recipient
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
}
} }
} }
} }
return res, nil if aliasAddressResult == "" {
res.FlagSet = append(res.FlagSet, flag_invalid_recipient)
res.Content = recipient
return *res, nil
}
if err := store.WriteEntry(ctx, sessionId, storedb.DATA_RECIPIENT, []byte(aliasAddressResult)); err != nil {
logg.ErrorCtxf(ctx, "Failed to store alias recipient", "error", err)
return *res, err
}
// Normalize the alias address to fetch the recipient's phone number
publicKeyNormalized, err := hex.NormalizeHex(aliasAddressResult)
if err != nil {
logg.ErrorCtxf(ctx, "Failed to normalize alias address", "address", aliasAddressResult, "error", err)
return *res, err
}
// get the recipient's phone number from the address
recipientPhoneNumber, err := store.ReadEntry(ctx, publicKeyNormalized, storedb.DATA_PUBLIC_KEY_REVERSE)
if err != nil || len(recipientPhoneNumber) == 0 {
logg.WarnCtxf(ctx, "Alias address not registered, switching to normal transaction", "address", aliasAddressResult)
recipientPhoneNumber = nil
}
if err := h.determineAndSaveTransactionType(ctx, sessionId, []byte(aliasAddressResult), recipientPhoneNumber); err != nil {
return *res, err
}
return *res, nil
}
// determineAndSaveTransactionType centralizes transaction-type logic and recipient info persistence.
// It expects the session to already have the recipient's public key (address) written.
func (h *MenuHandlers) determineAndSaveTransactionType(
ctx context.Context,
sessionId string,
publicKey []byte,
recipientPhoneNumber []byte,
) error {
store := h.userdataStore
txType := "swap"
// Read sender's active address
senderActiveAddress, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_ADDRESS)
if err != nil {
logg.ErrorCtxf(ctx, "Failed to read sender active address", "error", err)
return err
}
var recipientActiveAddress []byte
if recipientPhoneNumber != nil {
recipientActiveAddress, _ = store.ReadEntry(ctx, string(recipientPhoneNumber), storedb.DATA_ACTIVE_ADDRESS)
}
// recipient has no active token → normal transaction
if recipientActiveAddress == nil {
txType = "normal"
} else if senderActiveAddress != nil && string(senderActiveAddress) == string(recipientActiveAddress) {
// recipient has active token same as sender → normal transaction
txType = "normal"
}
// Save the transaction type
if err := store.WriteEntry(ctx, sessionId, storedb.DATA_SEND_TRANSACTION_TYPE, []byte(txType)); err != nil {
logg.ErrorCtxf(ctx, "Failed to write transaction type", "type", txType, "error", err)
return err
}
// Save the recipient's phone number only if it exists
if recipientPhoneNumber != nil {
if err := store.WriteEntry(ctx, sessionId, storedb.DATA_RECIPIENT_PHONE_NUMBER, recipientPhoneNumber); err != nil {
logg.ErrorCtxf(ctx, "Failed to write recipient phone number", "type", txType, "error", err)
return err
}
} else {
logg.InfoCtxf(ctx, "No recipient phone number found for public key", "publicKey", string(publicKey))
}
return nil
} }
// TransactionReset resets the previous transaction data (Recipient and Amount) // TransactionReset resets the previous transaction data (Recipient and Amount)
@@ -164,6 +268,16 @@ func (h *MenuHandlers) TransactionReset(ctx context.Context, sym string, input [
return res, nil return res, nil
} }
err = store.WriteEntry(ctx, sessionId, storedb.DATA_SEND_TRANSACTION_TYPE, []byte(""))
if err != nil {
return res, nil
}
err = store.WriteEntry(ctx, sessionId, storedb.DATA_RECIPIENT_PHONE_NUMBER, []byte(""))
if err != nil {
return res, nil
}
res.FlagReset = append(res.FlagReset, flag_invalid_recipient, flag_invalid_recipient_with_invite) res.FlagReset = append(res.FlagReset, flag_invalid_recipient, flag_invalid_recipient_with_invite)
return res, nil return res, nil
@@ -180,40 +294,226 @@ func (h *MenuHandlers) ResetTransactionAmount(ctx context.Context, sym string, i
} }
flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount") flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount")
flag_swap_transaction, _ := h.flagManager.GetFlag("flag_swap_transaction")
store := h.userdataStore store := h.userdataStore
err = store.WriteEntry(ctx, sessionId, storedb.DATA_AMOUNT, []byte("")) err = store.WriteEntry(ctx, sessionId, storedb.DATA_AMOUNT, []byte(""))
if err != nil { if err != nil {
return res, nil return res, nil
} }
res.FlagReset = append(res.FlagReset, flag_invalid_amount) res.FlagReset = append(res.FlagReset, flag_invalid_amount, flag_swap_transaction)
return res, nil return res, nil
} }
// MaxAmount gets the current balance from the API and sets it as // MaxAmount checks the transaction type to determine the displayed max amount.
// If the transaction type is "swap", it checks the max swappable amount and sets this as the content.
// If the transaction type is "normal", gets the current sender's balance from the store and sets it as
// the result content. // the result content.
func (h *MenuHandlers) MaxAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *MenuHandlers) MaxAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error
sessionId, ok := ctx.Value("SessionId").(string) sessionId, ok := ctx.Value("SessionId").(string)
if !ok { if !ok {
return res, fmt.Errorf("missing session") return res, fmt.Errorf("missing session")
} }
store := h.userdataStore
activeBal, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_BAL) flag_api_call_error, _ := h.flagManager.GetFlag("flag_api_call_error")
flag_swap_transaction, _ := h.flagManager.GetFlag("flag_swap_transaction")
userStore := h.userdataStore
code := codeFromCtx(ctx)
l := gotext.NewLocale(translationDir, code)
l.AddDomain("default")
// Fetch session data
transactionType, activeBal, activeSym, activeAddress, publicKey, activeDecimal, err := h.getSessionData(ctx, sessionId)
if err != nil { if err != nil {
logg.ErrorCtxf(ctx, "failed to read activeBal entry with", "key", storedb.DATA_ACTIVE_BAL, "error", err)
return res, err return res, err
} }
res.Content = string(activeBal) // Format the active balance amount to 2 decimal places
formattedBalance, _ := store.TruncateDecimalString(string(activeBal), 2)
// If normal transaction, or if the sym is max_amount, return balance
if string(transactionType) == "normal" || sym == "max_amount" {
res.FlagReset = append(res.FlagReset, flag_swap_transaction)
res.Content = l.Get("Maximum amount: %s %s\nEnter amount:", formattedBalance, string(activeSym))
return res, nil
}
res.FlagSet = append(res.FlagSet, flag_swap_transaction)
// Get the recipient's phone number to read other data items
recipientPhoneNumber, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_RECIPIENT_PHONE_NUMBER)
if err != nil {
// invalid state
return res, err
}
recipientActiveSym, recipientActiveAddress, recipientActiveDecimal, err := h.getRecipientData(ctx, string(recipientPhoneNumber))
if err != nil {
return res, err
}
// Resolve active pool address
activePoolAddress, err := h.resolveActivePoolAddress(ctx, sessionId)
if err != nil {
return res, err
}
// Check if sender token is swappable
canSwap, err := h.accountService.CheckTokenInPool(ctx, string(activePoolAddress), string(activeAddress))
if err != nil || !canSwap.CanSwapFrom {
if err != nil {
res.FlagSet = append(res.FlagSet, flag_api_call_error)
logg.ErrorCtxf(ctx, "failed on CheckTokenInPool", "error", err)
return res, nil
}
res.FlagReset = append(res.FlagReset, flag_swap_transaction)
res.Content = l.Get("Maximum amount: %s %s\nEnter amount:", formattedBalance, string(activeSym))
return res, nil
}
// retrieve the max credit send amounts
maxSAT, maxRAT, err := h.calculateSendCreditLimits(ctx, activePoolAddress, activeAddress, recipientActiveAddress, publicKey, activeDecimal, recipientActiveDecimal)
if err != nil {
res.FlagSet = append(res.FlagSet, flag_api_call_error)
logg.ErrorCtxf(ctx, "failed on calculateSendCreditLimits", "error", err)
return res, nil
}
// Fallback if below minimum
maxFloat, _ := strconv.ParseFloat(maxSAT, 64)
if maxFloat < 0.1 {
res.FlagReset = append(res.FlagReset, flag_swap_transaction)
res.Content = l.Get("Maximum amount: %s %s\nEnter amount:", formattedBalance, string(activeSym))
return res, nil
}
// Save max RAT amount to be used in validating the user's input
err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_SWAP_MAX_AMOUNT, []byte(maxRAT))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write swap max amount (maxRAT)", "value", maxRAT, "error", err)
return res, err
}
// save swap related data for the swap preview
metadata := &dataserviceapi.TokenHoldings{
TokenAddress: string(recipientActiveAddress),
TokenSymbol: string(recipientActiveSym),
TokenDecimals: string(recipientActiveDecimal),
}
// Store the active swap_to data
if err := store.UpdateSwapToVoucherData(ctx, userStore, sessionId, metadata); err != nil {
logg.ErrorCtxf(ctx, "failed on UpdateSwapToVoucherData", "error", err)
return res, err
}
res.Content = l.Get(
"Credit Available: %s %s\n(You can swap up to %s %s -> %s %s).\nEnter %s amount:",
maxRAT,
string(recipientActiveSym),
maxSAT,
string(activeSym),
maxRAT,
string(recipientActiveSym),
string(recipientActiveSym),
)
return res, nil return res, nil
} }
func (h *MenuHandlers) getSessionData(ctx context.Context, sessionId string) (transactionType, activeBal, activeSym, activeAddress, publicKey, activeDecimal []byte, err error) {
store := h.userdataStore
transactionType, err = store.ReadEntry(ctx, sessionId, storedb.DATA_SEND_TRANSACTION_TYPE)
if err != nil {
return
}
activeBal, err = store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_BAL)
if err != nil {
return
}
activeAddress, err = store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_ADDRESS)
if err != nil {
return
}
activeSym, err = store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM)
if err != nil {
return
}
publicKey, err = store.ReadEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY)
if err != nil {
return
}
activeDecimal, err = store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_DECIMAL)
if err != nil {
return
}
return
}
func (h *MenuHandlers) getRecipientData(ctx context.Context, sessionId string) (recipientActiveSym, recipientActiveAddress, recipientActiveDecimal []byte, err error) {
store := h.userdataStore
recipientActiveSym, err = store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_SYM)
if err != nil {
return
}
recipientActiveAddress, err = store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_ADDRESS)
if err != nil {
return
}
recipientActiveDecimal, err = store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_DECIMAL)
if err != nil {
return
}
return
}
func (h *MenuHandlers) resolveActivePoolAddress(ctx context.Context, sessionId string) ([]byte, error) {
store := h.userdataStore
addr, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_POOL_ADDRESS)
if err == nil {
return addr, nil
}
if db.IsNotFound(err) {
defaultAddr := []byte(config.DefaultPoolAddress())
if err := store.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_POOL_ADDRESS, defaultAddr); err != nil {
logg.ErrorCtxf(ctx, "failed to write default pool address", "error", err)
return nil, err
}
return defaultAddr, nil
}
logg.ErrorCtxf(ctx, "failed to read active pool address", "error", err)
return nil, err
}
func (h *MenuHandlers) calculateSendCreditLimits(ctx context.Context, poolAddress, fromAddress, toAddress, publicKey, fromDecimal, toDecimal []byte) (string, string, error) {
creditSendMaxLimits, err := h.accountService.GetCreditSendMaxLimit(
ctx,
string(poolAddress),
string(fromAddress),
string(toAddress),
string(publicKey),
)
if err != nil {
logg.ErrorCtxf(ctx, "failed on GetCreditSendMaxLimit", "error", err)
return "", "", err
}
scaledSAT := store.ScaleDownBalance(creditSendMaxLimits.MaxSAT, string(fromDecimal))
formattedSAT, _ := store.TruncateDecimalString(string(scaledSAT), 2)
scaledRAT := store.ScaleDownBalance(creditSendMaxLimits.MaxRAT, string(toDecimal))
formattedRAT, _ := store.TruncateDecimalString(string(scaledRAT), 2)
return formattedSAT, formattedRAT, nil
}
// ValidateAmount ensures that the given input is a valid amount and that // ValidateAmount ensures that the given input is a valid amount and that
// it is not more than the current balance. // it is not more than the current balance.
func (h *MenuHandlers) ValidateAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *MenuHandlers) ValidateAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) {
@@ -285,7 +585,7 @@ func (h *MenuHandlers) GetRecipient(ctx context.Context, sym string, input []byt
recipient, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE) recipient, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if len(recipient) == 0 { if len(recipient) == 0 {
logg.ErrorCtxf(ctx, "recipient is empty", "key", storedb.DATA_TEMPORARY_VALUE) logg.ErrorCtxf(ctx, "recipient is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered") return res, fmt.Errorf("data error encountered")
} }
res.Content = string(recipient) res.Content = string(recipient)
@@ -307,7 +607,7 @@ func (h *MenuHandlers) GetSender(ctx context.Context, sym string, input []byte)
return res, nil return res, nil
} }
// GetAmount retrieves the amount from teh Gdbm Db. // GetAmount retrieves the transaction amount from the store.
func (h *MenuHandlers) GetAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *MenuHandlers) GetAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
@@ -371,8 +671,8 @@ func (h *MenuHandlers) InitiateTransaction(ctx context.Context, sym string, inpu
res.Content = l.Get("An unexpected error occurred. Please try again later.") res.Content = l.Get("An unexpected error occurred. Please try again later.")
} }
flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") flag_api_call_error, _ := h.flagManager.GetFlag("flag_api_call_error")
res.FlagSet = append(res.FlagSet, flag_api_error) res.FlagSet = append(res.FlagSet, flag_api_call_error)
logg.ErrorCtxf(ctx, "failed on TokenTransfer", "error", err) logg.ErrorCtxf(ctx, "failed on TokenTransfer", "error", err)
return res, nil return res, nil
} }
@@ -391,3 +691,214 @@ func (h *MenuHandlers) InitiateTransaction(ctx context.Context, sym string, inpu
res.FlagReset = append(res.FlagReset, flag_account_authorized) res.FlagReset = append(res.FlagReset, flag_account_authorized)
return res, nil return res, nil
} }
// TransactionSwapPreview displays the send swap preview and estimates
func (h *MenuHandlers) TransactionSwapPreview(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")
}
// Input in RAT
inputStr := string(input)
if inputStr == "0" {
return res, nil
}
flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount")
code := codeFromCtx(ctx)
l := gotext.NewLocale(translationDir, code)
l.AddDomain("default")
userStore := h.userdataStore
recipientPhoneNumber, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_RECIPIENT_PHONE_NUMBER)
if err != nil {
// invalid state
return res, err
}
swapData, err := store.ReadSwapPreviewData(ctx, userStore, sessionId)
if err != nil {
return res, err
}
// use the stored max RAT
maxRATValue, err := strconv.ParseFloat(swapData.ActiveSwapMaxAmount, 64)
if err != nil {
logg.ErrorCtxf(ctx, "Failed to convert the swapMaxAmount to a float", "error", err)
return res, err
}
inputAmount, err := strconv.ParseFloat(inputStr, 64)
if err != nil || inputAmount > maxRATValue {
res.FlagSet = append(res.FlagSet, flag_invalid_amount)
res.Content = inputStr
return res, nil
}
// Format the amount to 2 decimal places
formattedAmount, err := store.TruncateDecimalString(inputStr, 2)
if err != nil {
res.FlagSet = append(res.FlagSet, flag_invalid_amount)
res.Content = inputStr
return res, nil
}
finalAmountStr, err := store.ParseAndScaleAmount(formattedAmount, swapData.ActiveSwapToDecimal)
if err != nil {
return res, err
}
// call the credit send API to get the reverse quote
r, err := h.accountService.GetCreditSendReverseQuote(ctx, swapData.ActivePoolAddress, swapData.ActiveSwapFromAddress, swapData.ActiveSwapToAddress, finalAmountStr)
if err != nil {
flag_api_call_error, _ := h.flagManager.GetFlag("flag_api_call_error")
res.FlagSet = append(res.FlagSet, flag_api_call_error)
res.Content = l.Get("Your request failed. Please try again later.")
logg.ErrorCtxf(ctx, "failed GetCreditSendReverseQuote poolSwap", "error", err)
return res, nil
}
sendInputAmount := r.InputAmount // amount of SAT that should be swapped
sendOutputAmount := r.OutputAmount // amount of RAT that will be received
// store the sendOutputAmount as the final amount (that will be sent)
err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_AMOUNT, []byte(sendOutputAmount))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write output amount value entry with", "key", storedb.DATA_AMOUNT, "value", sendOutputAmount, "error", err)
return res, err
}
// Scale down the quoted output amount
quoteAmountStr := store.ScaleDownBalance(sendOutputAmount, swapData.ActiveSwapToDecimal)
// Format the qouteAmount amount to 2 decimal places
qouteAmount, _ := store.TruncateDecimalString(quoteAmountStr, 2)
// store the qouteAmount in the temporary value
err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(qouteAmount))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write temporary qouteAmount entry with", "key", storedb.DATA_TEMPORARY_VALUE, "value", qouteAmount, "error", err)
return res, err
}
// store the sendInputAmount as the swap amount
err = userStore.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_SWAP_AMOUNT, []byte(sendInputAmount))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write swap amount entry with", "key", storedb.DATA_ACTIVE_SWAP_AMOUNT, "value", sendInputAmount, "error", err)
return res, err
}
res.Content = l.Get(
"%s will receive %s %s",
string(recipientPhoneNumber), qouteAmount, swapData.ActiveSwapToSym,
)
return res, nil
}
// TransactionInitiateSwap calls the poolSwap and returns a confirmation based on the result.
func (h *MenuHandlers) TransactionInitiateSwap(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized")
flag_swap_transaction, _ := h.flagManager.GetFlag("flag_swap_transaction")
code := codeFromCtx(ctx)
l := gotext.NewLocale(translationDir, code)
l.AddDomain("default")
userStore := h.userdataStore
swapData, err := store.ReadSwapPreviewData(ctx, userStore, sessionId)
if err != nil {
return res, err
}
swapAmount, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_ACTIVE_SWAP_AMOUNT)
if err != nil {
logg.ErrorCtxf(ctx, "failed to read swapAmount entry with", "key", storedb.DATA_ACTIVE_SWAP_AMOUNT, "error", err)
return res, err
}
swapAmountStr := string(swapAmount)
// Call the poolSwap API
poolSwap, err := h.accountService.PoolSwap(ctx, swapAmountStr, swapData.PublicKey, swapData.ActiveSwapFromAddress, swapData.ActivePoolAddress, swapData.ActiveSwapToAddress)
if err != nil {
flag_api_call_error, _ := h.flagManager.GetFlag("flag_api_call_error")
res.FlagSet = append(res.FlagSet, flag_api_call_error)
res.Content = l.Get("Your request failed. Please try again later.")
logg.ErrorCtxf(ctx, "failed on poolSwap", "error", err)
return res, nil
}
swapTrackingId := poolSwap.TrackingId
logg.InfoCtxf(ctx, "poolSwap", "swapTrackingId", swapTrackingId)
// Initiate a send
recipientPublicKey, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_RECIPIENT)
if err != nil {
logg.ErrorCtxf(ctx, "failed to read swapAmount entry with", "key", storedb.DATA_ACTIVE_SWAP_AMOUNT, "error", err)
return res, err
}
recipientPhoneNumber, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_RECIPIENT_PHONE_NUMBER)
if err != nil {
// invalid state
return res, err
}
// read the amount that should be sent
amount, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_AMOUNT)
if err != nil {
// invalid state
return res, err
}
// Call TokenTransfer with the expected swap amount
tokenTransfer, err := h.accountService.TokenTransfer(ctx, string(amount), swapData.PublicKey, string(recipientPublicKey), swapData.ActiveSwapToAddress)
if err != nil {
flag_api_call_error, _ := h.flagManager.GetFlag("flag_api_call_error")
res.FlagSet = append(res.FlagSet, flag_api_call_error)
res.Content = l.Get("Your request failed. Please try again later.")
logg.ErrorCtxf(ctx, "failed on TokenTransfer", "error", err)
return res, nil
}
trackingId := tokenTransfer.TrackingId
logg.InfoCtxf(ctx, "TokenTransfer", "trackingId", trackingId)
res.Content = l.Get(
"Your request has been sent. %s will receive %s %s from %s.",
string(recipientPhoneNumber),
swapData.TemporaryValue,
swapData.ActiveSwapToSym,
sessionId,
)
res.FlagReset = append(res.FlagReset, flag_account_authorized, flag_swap_transaction)
return res, nil
}
// ClearTransactionTypeFlag resets the flag when a user goes back.
func (h *MenuHandlers) ClearTransactionTypeFlag(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
flag_swap_transaction, _ := h.flagManager.GetFlag("flag_swap_transaction")
inputStr := string(input)
if inputStr == "0" {
res.FlagReset = append(res.FlagReset, flag_swap_transaction)
return res, nil
}
return res, nil
}

View File

@@ -6,11 +6,11 @@ import (
"log" "log"
"testing" "testing"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/sarafu-api/models" "git.grassecon.net/grassrootseconomics/sarafu-api/models"
"git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks" "git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/alecthomas/assert/v2" "github.com/alecthomas/assert/v2"
"github.com/grassrootseconomics/go-vise/resource"
) )
func TestValidateRecipient(t *testing.T) { func TestValidateRecipient(t *testing.T) {

View File

@@ -6,9 +6,9 @@ import (
"strconv" "strconv"
"strings" "strings"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store" "git.grassecon.net/grassrootseconomics/sarafu-vise/store"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/grassrootseconomics/go-vise/resource"
) )
// CheckTransactions retrieves the transactions from the API using the "PublicKey" and stores to prefixDb. // CheckTransactions retrieves the transactions from the API using the "PublicKey" and stores to prefixDb.
@@ -20,10 +20,9 @@ func (h *MenuHandlers) CheckTransactions(ctx context.Context, sym string, input
} }
flag_no_transfers, _ := h.flagManager.GetFlag("flag_no_transfers") flag_no_transfers, _ := h.flagManager.GetFlag("flag_no_transfers")
flag_api_error, _ := h.flagManager.GetFlag("flag_api_error") flag_api_call_error, _ := h.flagManager.GetFlag("flag_api_call_error")
userStore := h.userdataStore userStore := h.userdataStore
logdb := h.logDb
publicKey, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY) publicKey, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY)
if err != nil { if err != nil {
logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", storedb.DATA_PUBLIC_KEY, "error", err) logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", storedb.DATA_PUBLIC_KEY, "error", err)
@@ -33,11 +32,11 @@ func (h *MenuHandlers) CheckTransactions(ctx context.Context, sym string, input
// Fetch transactions from the API using the public key // Fetch transactions from the API using the public key
transactionsResp, err := h.accountService.FetchTransactions(ctx, string(publicKey)) transactionsResp, err := h.accountService.FetchTransactions(ctx, string(publicKey))
if err != nil { if err != nil {
res.FlagSet = append(res.FlagSet, flag_api_error) res.FlagSet = append(res.FlagSet, flag_api_call_error)
logg.ErrorCtxf(ctx, "failed on FetchTransactions", "error", err) logg.ErrorCtxf(ctx, "failed on FetchTransactions", "error", err)
return res, err return res, err
} }
res.FlagReset = append(res.FlagReset, flag_api_error) res.FlagReset = append(res.FlagReset, flag_api_call_error)
// Return if there are no transactions // Return if there are no transactions
if len(transactionsResp) == 0 { if len(transactionsResp) == 0 {
@@ -64,10 +63,6 @@ func (h *MenuHandlers) CheckTransactions(ctx context.Context, sym string, input
logg.ErrorCtxf(ctx, "failed to write to prefixDb", "error", err) logg.ErrorCtxf(ctx, "failed to write to prefixDb", "error", err)
return res, err return res, err
} }
err = logdb.WriteLogEntry(ctx, sessionId, key, []byte(value))
if err != nil {
logg.DebugCtxf(ctx, "Failed to write tx db log entry", "key", key, "value", value)
}
} }
res.FlagReset = append(res.FlagReset, flag_no_transfers) res.FlagReset = append(res.FlagReset, flag_no_transfers)

View File

@@ -6,11 +6,11 @@ import (
"testing" "testing"
"time" "time"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks" "git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store" "git.grassecon.net/grassrootseconomics/sarafu-vise/store"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/alecthomas/assert/v2" "github.com/alecthomas/assert/v2"
"github.com/grassrootseconomics/go-vise/resource"
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
) )
@@ -21,11 +21,6 @@ func TestCheckTransactions(t *testing.T) {
ctx, userStore := InitializeTestStore(t) ctx, userStore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
spdb := InitializeTestSubPrefixDb(t, ctx) spdb := InitializeTestSubPrefixDb(t, ctx)
@@ -38,7 +33,6 @@ func TestCheckTransactions(t *testing.T) {
userdataStore: userStore, userdataStore: userStore,
accountService: mockAccountService, accountService: mockAccountService,
prefixDb: spdb, prefixDb: spdb,
logDb: logDb,
flagManager: fm, flagManager: fm,
} }

View File

@@ -4,9 +4,9 @@ import (
"context" "context"
"fmt" "fmt"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/common/phone" "git.grassecon.net/grassrootseconomics/common/phone"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/grassrootseconomics/go-vise/resource"
"gopkg.in/leonelquinteros/gotext.v1" "gopkg.in/leonelquinteros/gotext.v1"
) )

View File

@@ -5,10 +5,10 @@ import (
"fmt" "fmt"
"strings" "strings"
"git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store" "git.grassecon.net/grassrootseconomics/sarafu-vise/store"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/grassrootseconomics/go-vise/db"
"github.com/grassrootseconomics/go-vise/resource"
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
"gopkg.in/leonelquinteros/gotext.v1" "gopkg.in/leonelquinteros/gotext.v1"
) )
@@ -20,7 +20,6 @@ import (
func (h *MenuHandlers) ManageVouchers(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *MenuHandlers) ManageVouchers(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
userStore := h.userdataStore userStore := h.userdataStore
logdb := h.logDb
sessionId, ok := ctx.Value("SessionId").(string) sessionId, ok := ctx.Value("SessionId").(string)
if !ok { if !ok {
@@ -82,10 +81,6 @@ func (h *MenuHandlers) ManageVouchers(ctx context.Context, sym string, input []b
logg.ErrorCtxf(ctx, "Failed to write active voucher data", "key", key, "error", err) logg.ErrorCtxf(ctx, "Failed to write active voucher data", "key", key, "error", err)
return res, err return res, err
} }
err = logdb.WriteLogEntry(ctx, sessionId, key, []byte(value))
if err != nil {
logg.DebugCtxf(ctx, "Failed to write voucher db log entry", "key", key, "value", value)
}
} }
logg.InfoCtxf(ctx, "Default voucher set", "symbol", defaultSym, "balance", defaultBal, "decimals", defaultDec, "address", defaultAddr) logg.InfoCtxf(ctx, "Default voucher set", "symbol", defaultSym, "balance", defaultBal, "decimals", defaultDec, "address", defaultAddr)

View File

@@ -5,12 +5,11 @@ import (
"fmt" "fmt"
"testing" "testing"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/sarafu-api/models" "git.grassecon.net/grassrootseconomics/sarafu-api/models"
"git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks" "git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/alecthomas/assert/v2" "github.com/alecthomas/assert/v2"
"github.com/grassrootseconomics/go-vise/resource"
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
) )
@@ -20,11 +19,6 @@ func TestManageVouchers(t *testing.T) {
ctx, userStore := InitializeTestStore(t) ctx, userStore := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
_, logdb := InitializeTestLogdbStore(t)
logDb := store.LogDb{
Db: logdb,
}
fm, err := NewFlagManager(flagsPath) fm, err := NewFlagManager(flagsPath)
if err != nil { if err != nil {
@@ -102,7 +96,6 @@ func TestManageVouchers(t *testing.T) {
userdataStore: userStore, userdataStore: userStore,
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm, flagManager: fm,
logDb: logDb,
} }
mockAccountService.On("FetchVouchers", string(publicKey)).Return(tt.vouchersResp, nil) mockAccountService.On("FetchVouchers", string(publicKey)).Return(tt.vouchersResp, nil)

View File

@@ -4,16 +4,16 @@ import (
"context" "context"
"fmt" "fmt"
"git.defalsify.org/vise.git/logging"
"git.defalsify.org/vise.git/persist"
apievent "git.grassecon.net/grassrootseconomics/sarafu-api/event" apievent "git.grassecon.net/grassrootseconomics/sarafu-api/event"
"git.grassecon.net/grassrootseconomics/sarafu-api/remote" "git.grassecon.net/grassrootseconomics/sarafu-api/remote"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store" "git.grassecon.net/grassrootseconomics/sarafu-vise/store"
"git.grassecon.net/grassrootseconomics/visedriver/storage" "git.grassecon.net/grassrootseconomics/visedriver/storage"
"github.com/grassrootseconomics/go-vise/persist"
slogging "github.com/grassrootseconomics/go-vise/slog"
) )
var ( var (
logg = logging.NewVanilla().WithDomain("sarafu-vise.handlers.event") logg = slogging.Get().With("component", "sarafu-vise.handlers.event")
) )
type EventsUpdater struct { type EventsUpdater struct {

View File

@@ -5,11 +5,11 @@ import (
"fmt" "fmt"
"strings" "strings"
"git.defalsify.org/vise.git/db"
"git.grassecon.net/grassrootseconomics/common/identity" "git.grassecon.net/grassrootseconomics/common/identity"
apievent "git.grassecon.net/grassrootseconomics/sarafu-api/event" apievent "git.grassecon.net/grassrootseconomics/sarafu-api/event"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store" "git.grassecon.net/grassrootseconomics/sarafu-vise/store"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/grassrootseconomics/go-vise/db"
) )
// execute all // execute all

View File

@@ -4,20 +4,15 @@ import (
"context" "context"
"strings" "strings"
"git.defalsify.org/vise.git/db" "github.com/grassrootseconomics/go-vise/db"
"git.defalsify.org/vise.git/engine" "github.com/grassrootseconomics/go-vise/engine"
"git.defalsify.org/vise.git/logging" "github.com/grassrootseconomics/go-vise/persist"
"git.defalsify.org/vise.git/persist" "github.com/grassrootseconomics/go-vise/resource"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/sarafu-api/remote" "git.grassecon.net/grassrootseconomics/sarafu-api/remote"
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers/application" "git.grassecon.net/grassrootseconomics/sarafu-vise/handlers/application"
) )
var (
logg = logging.NewVanilla().WithDomain("sarafu-vise.engine")
)
type HandlerService interface { type HandlerService interface {
GetHandler() (*application.MenuHandlers, error) GetHandler() (*application.MenuHandlers, error)
} }
@@ -27,7 +22,6 @@ type LocalHandlerService struct {
DbRs *resource.DbResource DbRs *resource.DbResource
Pe *persist.Persister Pe *persist.Persister
UserdataStore *db.Db UserdataStore *db.Db
LogDb *db.Db
Cfg engine.Config Cfg engine.Config
Rs resource.Resource Rs resource.Resource
first resource.EntryFunc first resource.EntryFunc
@@ -58,16 +52,12 @@ func (ls *LocalHandlerService) SetDataStore(db *db.Db) {
ls.UserdataStore = db ls.UserdataStore = db
} }
func (ls *LocalHandlerService) SetLogDb(db *db.Db) {
ls.LogDb = db
}
func (ls *LocalHandlerService) GetHandler(accountService remote.AccountService) (*application.MenuHandlers, error) { func (ls *LocalHandlerService) GetHandler(accountService remote.AccountService) (*application.MenuHandlers, error) {
replaceSeparatorFunc := func(input string) string { replaceSeparatorFunc := func(input string) string {
return strings.ReplaceAll(input, ":", ls.Cfg.MenuSeparator) return strings.ReplaceAll(input, ":", ls.Cfg.MenuSeparator)
} }
appHandlers, err := application.NewMenuHandlers(ls.Parser, *ls.UserdataStore, *ls.LogDb, accountService, replaceSeparatorFunc) appHandlers, err := application.NewMenuHandlers(ls.Parser, *ls.UserdataStore, accountService, replaceSeparatorFunc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -86,6 +76,7 @@ func (ls *LocalHandlerService) GetHandler(accountService remote.AccountService)
ls.DbRs.AddLocalFunc("transaction_reset", appHandlers.TransactionReset) ls.DbRs.AddLocalFunc("transaction_reset", appHandlers.TransactionReset)
ls.DbRs.AddLocalFunc("invite_valid_recipient", appHandlers.InviteValidRecipient) ls.DbRs.AddLocalFunc("invite_valid_recipient", appHandlers.InviteValidRecipient)
ls.DbRs.AddLocalFunc("max_amount", appHandlers.MaxAmount) ls.DbRs.AddLocalFunc("max_amount", appHandlers.MaxAmount)
ls.DbRs.AddLocalFunc("credit_max_amount", appHandlers.MaxAmount)
ls.DbRs.AddLocalFunc("validate_amount", appHandlers.ValidateAmount) ls.DbRs.AddLocalFunc("validate_amount", appHandlers.ValidateAmount)
ls.DbRs.AddLocalFunc("reset_transaction_amount", appHandlers.ResetTransactionAmount) ls.DbRs.AddLocalFunc("reset_transaction_amount", appHandlers.ResetTransactionAmount)
ls.DbRs.AddLocalFunc("get_recipient", appHandlers.GetRecipient) ls.DbRs.AddLocalFunc("get_recipient", appHandlers.GetRecipient)
@@ -136,6 +127,10 @@ func (ls *LocalHandlerService) GetHandler(accountService remote.AccountService)
ls.DbRs.AddLocalFunc("swap_max_limit", appHandlers.SwapMaxLimit) ls.DbRs.AddLocalFunc("swap_max_limit", appHandlers.SwapMaxLimit)
ls.DbRs.AddLocalFunc("swap_preview", appHandlers.SwapPreview) ls.DbRs.AddLocalFunc("swap_preview", appHandlers.SwapPreview)
ls.DbRs.AddLocalFunc("initiate_swap", appHandlers.InitiateSwap) ls.DbRs.AddLocalFunc("initiate_swap", appHandlers.InitiateSwap)
ls.DbRs.AddLocalFunc("transaction_swap_preview", appHandlers.TransactionSwapPreview)
ls.DbRs.AddLocalFunc("transaction_initiate_swap", appHandlers.TransactionInitiateSwap)
ls.DbRs.AddLocalFunc("clear_trans_type_flag", appHandlers.ClearTransactionTypeFlag)
ls.first = appHandlers.Init ls.first = appHandlers.Init
return appHandlers, nil return appHandlers, nil

View File

@@ -4,13 +4,13 @@ import (
"context" "context"
"fmt" "fmt"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers/application" "git.grassecon.net/grassrootseconomics/sarafu-vise/handlers/application"
"git.grassecon.net/grassrootseconomics/visedriver/storage" "git.grassecon.net/grassrootseconomics/visedriver/storage"
slogging "github.com/grassrootseconomics/go-vise/slog"
) )
var ( var (
logg = logging.NewVanilla().WithDomain("cmd").WithContextKey("SessionId") logg = slogging.Get().With("component", "cmd")
) )
type Cmd struct { type Cmd struct {

View File

@@ -4,15 +4,15 @@ import (
"context" "context"
"fmt" "fmt"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/common/phone" "git.grassecon.net/grassrootseconomics/common/phone"
"git.grassecon.net/grassrootseconomics/sarafu-api/remote" "git.grassecon.net/grassrootseconomics/sarafu-api/remote"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store" "git.grassecon.net/grassrootseconomics/sarafu-vise/store"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
slogging "github.com/grassrootseconomics/go-vise/slog"
) )
var ( var (
logg = logging.NewVanilla().WithDomain("smsservice") logg = slogging.Get().With("component", "smsservice")
) )
type SmsService struct { type SmsService struct {

View File

@@ -5,19 +5,19 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "2", "input": "3",
"expectedContent": "My vouchers\n1:Select voucher\n2:Voucher details\n0:Back" "expectedContent": "My vouchers\n1:Select voucher\n2:Voucher details\n0:Back"
}, },
{ {
"input": "1", "input": "1",
"expectedContent": "Select number or symbol from your vouchers:\n1SRF\n0:Back\n99:Quit" "expectedContent": "Select number or symbol from your vouchers:\n1:SRF\n0:Back\n99:Quit"
}, },
{ {
"input": "", "input": "",
"expectedContent": "Select number or symbol from your vouchers:\n1SRF\n0:Back\n99:Quit" "expectedContent": "Select number or symbol from your vouchers:\n1:SRF\n0:Back\n99:Quit"
}, },
{ {
"input": "1", "input": "1",
@@ -29,7 +29,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
}, },
@@ -38,15 +38,15 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "2", "input": "3",
"expectedContent": "My vouchers\n1:Select voucher\n2:Voucher details\n0:Back" "expectedContent": "My vouchers\n1:Select voucher\n2:Voucher details\n0:Back"
}, },
{ {
"input": "1", "input": "1",
"expectedContent": "Select number or symbol from your vouchers:\n1SRF\n0:Back\n99:Quit" "expectedContent": "Select number or symbol from your vouchers:\n1:SRF\n0:Back\n99:Quit"
}, },
{ {
"input": "SRF", "input": "SRF",
@@ -58,7 +58,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
}, },
@@ -67,10 +67,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
@@ -95,7 +95,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
}, },
@@ -104,10 +104,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
@@ -136,7 +136,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
}, },
@@ -145,10 +145,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
@@ -177,7 +177,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
}, },
@@ -186,10 +186,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
@@ -210,7 +210,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
}, },
@@ -219,10 +219,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
@@ -235,7 +235,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
}, },
@@ -244,10 +244,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
@@ -280,7 +280,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
}, },
@@ -289,10 +289,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
@@ -325,7 +325,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
}, },
@@ -334,10 +334,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
@@ -382,7 +382,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
}, },
@@ -391,10 +391,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
@@ -419,7 +419,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
}, },
@@ -428,10 +428,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
@@ -460,7 +460,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
}, },
@@ -469,10 +469,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
@@ -497,7 +497,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
}, },
@@ -506,10 +506,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
@@ -534,7 +534,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
}, },
@@ -543,10 +543,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
@@ -571,7 +571,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
}, },
@@ -580,10 +580,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
@@ -604,7 +604,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
}, },
@@ -613,10 +613,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {

View File

@@ -9,14 +9,14 @@ import (
"regexp" "regexp"
"testing" "testing"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/sarafu-vise/testutil" "git.grassecon.net/grassrootseconomics/sarafu-vise/testutil"
"git.grassecon.net/grassrootseconomics/visedriver/testutil/driver" "git.grassecon.net/grassrootseconomics/visedriver/testutil/driver"
"github.com/gofrs/uuid" "github.com/gofrs/uuid"
slogging "github.com/grassrootseconomics/go-vise/slog"
) )
var ( var (
logg = logging.NewVanilla().WithDomain("menutraversaltest") logg = slogging.Get().With("component", "menutraversaltest")
testData = driver.ReadData() testData = driver.ReadData()
sessionID string sessionID string
src = rand.NewSource(42) src = rand.NewSource(42)

View File

@@ -5,10 +5,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
@@ -49,7 +49,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
} }

View File

@@ -5,10 +5,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
@@ -53,7 +53,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
} }

View File

@@ -5,10 +5,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
@@ -45,7 +45,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
} }

View File

@@ -5,10 +5,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
@@ -37,7 +37,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
} }

View File

@@ -5,10 +5,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
@@ -33,7 +33,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
} }

View File

@@ -5,10 +5,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
@@ -41,7 +41,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
} }

View File

@@ -5,10 +5,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {
@@ -61,7 +61,7 @@
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
} }
] ]
} }

View File

@@ -57,7 +57,7 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "1", "input": "1",
@@ -86,10 +86,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "4", "input": "6",
"expectedContent": "For more help,please call: 0757628885" "expectedContent": "For more help,please call: 0757628885"
} }
] ]
@@ -99,7 +99,7 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "9", "input": "9",
@@ -112,10 +112,10 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" "expectedContent": "{balance}\n\n1:Send\n2:Swap\n3:My Vouchers\n4:Select pool\n5:My Account\n6:Help\n9:Quit"
}, },
{ {
"input": "3", "input": "5",
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back" "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n7:My Alias\n0:Back"
}, },
{ {

View File

@@ -1,2 +1 @@
Maximum amount: {{.max_amount}} {{.max_amount}}
Enter amount:

View File

@@ -1,5 +1,6 @@
LOAD reset_transaction_amount 0 LOAD reset_transaction_amount 10
LOAD max_amount 40 RELOAD reset_transaction_amount
LOAD max_amount 0
RELOAD max_amount RELOAD max_amount
MAP max_amount MAP max_amount
MOUT back 0 MOUT back 0
@@ -9,7 +10,7 @@ RELOAD validate_amount
CATCH api_failure flag_api_call_error 1 CATCH api_failure flag_api_call_error 1
CATCH invalid_amount flag_invalid_amount 1 CATCH invalid_amount flag_invalid_amount 1
INCMP _ 0 INCMP _ 0
LOAD get_recipient 0 LOAD get_recipient 100
LOAD get_sender 64 LOAD get_sender 64
LOAD get_amount 32 LOAD get_amount 32
INCMP transaction_pin * INCMP transaction_pin *

View File

@@ -1,2 +1 @@
Kiwango cha juu: {{.max_amount}} {{.max_amount}}
Weka kiwango:

View File

@@ -0,0 +1 @@
{{.credit_max_amount}}

View File

@@ -0,0 +1,19 @@
LOAD reset_transaction_amount 10
LOAD credit_max_amount 160
RELOAD credit_max_amount
CATCH api_failure flag_api_call_error 1
MAP credit_max_amount
MOUT back 0
HALT
LOAD clear_trans_type_flag 6
RELOAD clear_trans_type_flag
CATCH transaction_swap flag_swap_transaction 1
LOAD validate_amount 64
RELOAD validate_amount
CATCH api_failure flag_api_call_error 1
CATCH invalid_amount flag_invalid_amount 1
INCMP _ 0
LOAD get_recipient 0
LOAD get_sender 64
LOAD get_amount 32
INCMP transaction_pin *

View File

@@ -0,0 +1 @@
{{.credit_max_amount}}

View File

@@ -0,0 +1 @@
Enter recipient's phone number/address/alias:

View File

@@ -0,0 +1,12 @@
LOAD transaction_reset 0
RELOAD transaction_reset
CATCH no_voucher flag_no_active_voucher 1
MOUT back 0
HALT
LOAD validate_recipient 50
RELOAD validate_recipient
CATCH api_failure flag_api_call_error 1
CATCH invalid_recipient flag_invalid_recipient 1
CATCH invite_recipient flag_invalid_recipient_with_invite 1
INCMP _ 0
INCMP credit_amount *

View File

@@ -0,0 +1 @@
Credit-Send

View File

@@ -0,0 +1 @@
Tuma-Mkopo

View File

@@ -0,0 +1 @@
Weka nambari ya simu/anwani/lakabu:

View File

@@ -0,0 +1 @@
Amount {{.transaction_swap_preview}} is invalid, please try again:

View File

@@ -0,0 +1,7 @@
MAP transaction_swap_preview
RELOAD reset_transaction_amount
MOUT retry 1
MOUT quit 9
HALT
INCMP ^ 1
INCMP quit 9

View File

@@ -0,0 +1 @@
Kiwango {{.transaction_swap_preview}} sio sahihi, tafadhali weka tena:

View File

@@ -45,3 +45,12 @@ msgstr "Jina: %s\nSarafu: %s"
msgid "Only USD vouchers are allowed to mpesa.sarafu.eth." msgid "Only USD vouchers are allowed to mpesa.sarafu.eth."
msgstr "Ni sarafu za USD pekee zinazoruhusiwa kwa mpesa.sarafu.eth." msgstr "Ni sarafu za USD pekee zinazoruhusiwa kwa mpesa.sarafu.eth."
msgid "Maximum amount: %s %s\nEnter amount:"
msgstr "Kiwango cha juu: %s %s\nWeka kiwango:"
msgid "Credit Available: %s %s\n(You can swap up to %s %s -> %s %s).\nEnter %s amount:"
msgstr "Kiwango kinachopatikana: %s %s\n(Unaweza kubadilisha hadi %s %s -> %s %s)\nWeka kiwango cha %s:"
msgid "%s will receive %s %s"
msgstr "%s atapokea %s %s"

View File

@@ -7,18 +7,20 @@ LOAD check_balance 128
RELOAD check_balance RELOAD check_balance
MAP check_balance MAP check_balance
MOUT send 1 MOUT send 1
MOUT swap 2 MOUT credit_send 2
MOUT vouchers 3 MOUT swap 3
MOUT select_pool 4 MOUT vouchers 4
MOUT account 5 MOUT select_pool 5
MOUT help 6 MOUT account 6
MOUT help 7
MOUT quit 9 MOUT quit 9
HALT HALT
INCMP send 1 INCMP send 1
INCMP swap_to_list 2 INCMP credit_send 2
INCMP my_vouchers 3 INCMP swap_to_list 3
INCMP select_pool 4 INCMP my_vouchers 4
INCMP my_account 5 INCMP select_pool 5
INCMP help 6 INCMP my_account 6
INCMP help 7
INCMP quit 9 INCMP quit 9
INCMP . * INCMP . *

View File

@@ -35,3 +35,4 @@ flag,flag_account_pin_reset,41,this is set on an account when an admin triggers
flag,flag_incorrect_pool,42,this is set when the user selects an invalid pool flag,flag_incorrect_pool,42,this is set when the user selects an invalid pool
flag,flag_low_swap_amount,43,this is set when the swap max limit is less than 0.1 flag,flag_low_swap_amount,43,this is set when the swap max limit is less than 0.1
flag,flag_alias_unavailable,44,this is set when the preferred alias is not available flag,flag_alias_unavailable,44,this is set when the preferred alias is not available
flag,flag_swap_transaction,45,this is set when the transaction will involve performing a swap
1 flag flag_language_set 8 checks whether the user has set their prefered language
35 flag flag_incorrect_pool 42 this is set when the user selects an invalid pool
36 flag flag_low_swap_amount 43 this is set when the swap max limit is less than 0.1
37 flag flag_alias_unavailable 44 this is set when the preferred alias is not available
38 flag flag_swap_transaction 45 this is set when the transaction will involve performing a swap

View File

@@ -1,5 +1,6 @@
CATCH no_voucher flag_no_active_voucher 1 CATCH no_voucher flag_no_active_voucher 1
LOAD get_pools 0 LOAD get_pools 0
RELOAD get_pools
MAP get_pools MAP get_pools
LOAD get_default_pool 20 LOAD get_default_pool 20
RELOAD get_default_pool RELOAD get_default_pool

View File

@@ -1 +1 @@
Weka nambari ya simu: Weka nambari ya simu/Anwani/Lakabu:

View File

@@ -0,0 +1 @@
Badilisha

View File

@@ -1,2 +1,2 @@
Chagua nambari au ishara ya sarafu kubadilisha KWENDA: Chagua nambari au ishara ya sarafu unayotaka kupokea.
{{.swap_to_list}} {{.swap_to_list}}

View File

@@ -0,0 +1,3 @@
{{.transaction_swap_preview}}
Please enter your PIN to confirm:

View File

@@ -0,0 +1,13 @@
LOAD transaction_swap_preview 0
MAP transaction_swap_preview
CATCH api_failure flag_api_call_error 1
CATCH invalid_credit_send_amount flag_invalid_amount 1
MOUT back 0
MOUT quit 9
LOAD authorize_account 6
HALT
RELOAD authorize_account
CATCH incorrect_pin flag_incorrect_pin 1
INCMP _ 0
INCMP quit 9
INCMP transaction_swap_initiated *

View File

@@ -0,0 +1,4 @@
LOAD reset_incorrect_pin 6
CATCH _ flag_account_authorized 0
LOAD transaction_initiate_swap 0
HALT

View File

@@ -0,0 +1,3 @@
{{.transaction_swap_preview}}
Tafadhali weka PIN yako kudhibitisha:

View File

@@ -1,68 +0,0 @@
package ssh
import (
"context"
"fmt"
"os"
"path"
"golang.org/x/crypto/ssh"
"git.defalsify.org/vise.git/db"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
dbstorage "git.grassecon.net/grassrootseconomics/visedriver/storage/db/gdbm"
)
type SshKeyStore struct {
store db.Db
}
func NewSshKeyStore(ctx context.Context, dbDir string) (*SshKeyStore, error) {
keyStore := &SshKeyStore{}
keyStoreFile := path.Join(dbDir, "ssh_authorized_keys.gdbm")
keyStore.store = dbstorage.NewThreadGdbmDb()
err := keyStore.store.Connect(ctx, keyStoreFile)
if err != nil {
return nil, err
}
return keyStore, nil
}
func (s *SshKeyStore) AddFromFile(ctx context.Context, fp string, sessionId string) error {
_, err := os.Stat(fp)
if err != nil {
return fmt.Errorf("cannot open ssh server public key file: %v\n", err)
}
publicBytes, err := os.ReadFile(fp)
if err != nil {
return fmt.Errorf("Failed to load public key: %v", err)
}
pubKey, _, _, _, err := ssh.ParseAuthorizedKey(publicBytes)
if err != nil {
return fmt.Errorf("Failed to parse public key: %v", err)
}
k := append([]byte{0x01}, pubKey.Marshal()...)
s.store.SetLanguage(nil)
s.store.SetSession("")
s.store.SetPrefix(storage.DATATYPE_EXTEND)
logg.Infof("Added key", "sessionId", sessionId, "public key", string(publicBytes))
return s.store.Put(ctx, k, []byte(sessionId))
}
func (s *SshKeyStore) Get(ctx context.Context, pubKey ssh.PublicKey) (string, error) {
s.store.SetLanguage(nil)
s.store.SetSession("")
s.store.SetPrefix(storage.DATATYPE_EXTEND)
k := append([]byte{0x01}, pubKey.Marshal()...)
v, err := s.store.Get(ctx, k)
if err != nil {
return "", err
}
return string(v), nil
}
func (s *SshKeyStore) Close(ctx context.Context) error {
return s.store.Close(ctx)
}

View File

@@ -1,276 +0,0 @@
package ssh
import (
"context"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"net"
"os"
"sync"
"golang.org/x/crypto/ssh"
"git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/logging"
"git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/state"
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers"
"git.grassecon.net/grassrootseconomics/sarafu-vise/services"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
)
var (
logg = logging.NewVanilla().WithDomain("ssh")
)
type auther struct {
Ctx context.Context
keyStore *SshKeyStore
auth map[string]string
}
func NewAuther(ctx context.Context, keyStore *SshKeyStore) *auther {
return &auther{
Ctx: ctx,
keyStore: keyStore,
auth: make(map[string]string),
}
}
func (a *auther) Check(conn ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
logg.TraceCtxf(a.Ctx, "looking for publickey", "pubkey", fmt.Sprintf("%x", pubKey))
va, err := a.keyStore.Get(a.Ctx, pubKey)
if err != nil {
return nil, err
}
ka := hex.EncodeToString(conn.SessionID())
a.auth[ka] = va
fmt.Fprintf(os.Stderr, "connect: %s -> %s\n", ka, va)
return nil, nil
}
func (a *auther) FromConn(c *ssh.ServerConn) (string, error) {
if c == nil {
return "", errors.New("nil server conn")
}
if c.Conn == nil {
return "", errors.New("nil underlying conn")
}
return a.Get(c.Conn.SessionID())
}
func (a *auther) Get(k []byte) (string, error) {
ka := hex.EncodeToString(k)
v, ok := a.auth[ka]
if !ok {
return "", errors.New("not found")
}
return v, nil
}
type SshRunner struct {
Ctx context.Context
Cfg engine.Config
FlagFile string
Conn storage.Conns
Debug bool
SrvKeyFile string
Host string
Port uint
wg sync.WaitGroup
lst net.Listener
}
func (s *SshRunner) serve(ctx context.Context, sessionId string, ch ssh.NewChannel, en engine.Engine) error {
if ch == nil {
return errors.New("nil channel")
}
if ch.ChannelType() != "session" {
ch.Reject(ssh.UnknownChannelType, "that is not the channel you are looking for")
return errors.New("not a session")
}
channel, requests, err := ch.Accept()
if err != nil {
panic(err)
}
defer channel.Close()
s.wg.Add(1)
go func(reqIn <-chan *ssh.Request) {
defer s.wg.Done()
for req := range reqIn {
req.Reply(req.Type == "shell", nil)
}
_ = requests
}(requests)
cont, err := en.Exec(ctx, []byte{})
if err != nil {
return fmt.Errorf("initial engine exec err: %v", err)
}
var input [state.INPUT_LIMIT]byte
for cont {
c, err := en.Flush(ctx, channel)
if err != nil {
return fmt.Errorf("flush err: %v", err)
}
_, err = channel.Write([]byte{0x0a})
if err != nil {
return fmt.Errorf("newline err: %v", err)
}
c, err = channel.Read(input[:])
if err != nil {
return fmt.Errorf("read input fail: %v", err)
}
logg.TraceCtxf(ctx, "input read", "c", c, "input", input[:c-1])
cont, err = en.Exec(ctx, input[:c-1])
if err != nil {
return fmt.Errorf("engine exec err: %v", err)
}
logg.TraceCtxf(ctx, "exec cont", "cont", cont, "en", en)
_ = c
}
c, err := en.Flush(ctx, channel)
if err != nil {
return fmt.Errorf("last flush err: %v", err)
}
_ = c
return nil
}
func (s *SshRunner) Stop() error {
return s.lst.Close()
}
func (s *SshRunner) GetEngine(sessionId string) (engine.Engine, func(), error) {
ctx := s.Ctx
menuStorageService := storage.NewMenuStorageService(s.Conn)
rs, err := menuStorageService.GetResource(ctx)
if err != nil {
return nil, nil, err
}
pe, err := menuStorageService.GetPersister(ctx)
if err != nil {
return nil, nil, err
}
userdatastore, err := menuStorageService.GetUserdataDb(ctx)
if err != nil {
return nil, nil, err
}
dbResource, ok := rs.(*resource.DbResource)
if !ok {
return nil, nil, err
}
lhs, err := handlers.NewLocalHandlerService(ctx, s.FlagFile, true, dbResource, s.Cfg, rs)
lhs.SetDataStore(&userdatastore)
lhs.SetPersister(pe)
lhs.Cfg.SessionId = sessionId
if err != nil {
return nil, nil, err
}
// TODO: this is getting very hacky!
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(lhs.Cfg, rs, pe)
closer := func() {
err := menuStorageService.Close(ctx)
if err != nil {
logg.ErrorCtxf(ctx, "menu storage service cleanup fail", "err", err)
}
}
return en, closer, nil
}
// adapted example from crypto/ssh package, NewServerConn doc
func (s *SshRunner) Run(ctx context.Context, keyStore *SshKeyStore) {
s.Ctx = ctx
running := true
// TODO: waitgroup should probably not be global
defer s.wg.Wait()
auth := NewAuther(ctx, keyStore)
cfg := ssh.ServerConfig{
PublicKeyCallback: auth.Check,
}
privateBytes, err := os.ReadFile(s.SrvKeyFile)
if err != nil {
logg.ErrorCtxf(ctx, "Failed to load private key", "err", err)
}
private, err := ssh.ParsePrivateKey(privateBytes)
if err != nil {
logg.ErrorCtxf(ctx, "Failed to parse private key", "err", err)
}
srvPub := private.PublicKey()
srvPubStr := base64.StdEncoding.EncodeToString(srvPub.Marshal())
logg.InfoCtxf(ctx, "have server key", "type", srvPub.Type(), "public", srvPubStr)
cfg.AddHostKey(private)
s.lst, err = net.Listen("tcp", fmt.Sprintf("%s:%d", s.Host, s.Port))
if err != nil {
panic(err)
}
for running {
conn, err := s.lst.Accept()
if err != nil {
logg.ErrorCtxf(ctx, "ssh accept error", "err", err)
running = false
continue
}
go func(conn net.Conn) {
defer conn.Close()
for true {
srvConn, nC, rC, err := ssh.NewServerConn(conn, &cfg)
if err != nil {
logg.InfoCtxf(ctx, "rejected client", "err", err)
return
}
logg.DebugCtxf(ctx, "ssh client connected", "conn", srvConn)
s.wg.Add(1)
go func() {
ssh.DiscardRequests(rC)
s.wg.Done()
}()
sessionId, err := auth.FromConn(srvConn)
if err != nil {
logg.ErrorCtxf(ctx, "Cannot find authentication")
return
}
en, closer, err := s.GetEngine(sessionId)
if err != nil {
logg.ErrorCtxf(ctx, "engine won't start", "err", err)
return
}
defer func() {
err := en.Finish(ctx)
if err != nil {
logg.ErrorCtxf(ctx, "engine won't stop", "err", err)
}
closer()
}()
for ch := range nC {
err = s.serve(ctx, sessionId, ch, en)
logg.ErrorCtxf(ctx, "ssh server finish", "err", err)
}
}
}(conn)
}
}

View File

@@ -4,7 +4,7 @@ import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"git.defalsify.org/vise.git/logging" slogging "github.com/grassrootseconomics/go-vise/slog"
) )
// DataType is a subprefix value used in association with vise/db.DATATYPE_USERDATA. // DataType is a subprefix value used in association with vise/db.DATATYPE_USERDATA.
@@ -65,7 +65,7 @@ const (
DATA_ACCOUNT_ALIAS DATA_ACCOUNT_ALIAS
//currently suggested alias by the api awaiting user's confirmation as accepted account alias //currently suggested alias by the api awaiting user's confirmation as accepted account alias
DATA_SUGGESTED_ALIAS DATA_SUGGESTED_ALIAS
//Key used to store a value of 1 for a user to reset their own PIN once they access the menu. //Key used to store a value of 1 for a user to reset their own PIN once they access the menu.
DATA_SELF_PIN_RESET DATA_SELF_PIN_RESET
// Holds the active pool contract address for the swap // Holds the active pool contract address for the swap
DATA_ACTIVE_POOL_ADDRESS DATA_ACTIVE_POOL_ADDRESS
@@ -89,6 +89,10 @@ const (
DATA_ACTIVE_POOL_NAME DATA_ACTIVE_POOL_NAME
// Holds the active pool symbol for the swap // Holds the active pool symbol for the swap
DATA_ACTIVE_POOL_SYM DATA_ACTIVE_POOL_SYM
// Holds the send transaction type
DATA_SEND_TRANSACTION_TYPE
// Holds the recipient formatted phone number
DATA_RECIPIENT_PHONE_NUMBER
) )
const ( const (
@@ -153,7 +157,7 @@ const (
) )
var ( var (
logg = logging.NewVanilla().WithDomain("urdt-common") logg = slogging.Get().With("component", "urdt-common")
) )
func typToBytes(typ DataTyp) []byte { func typToBytes(typ DataTyp) []byte {

View File

@@ -3,7 +3,7 @@ package db
import ( import (
"context" "context"
"git.defalsify.org/vise.git/db" "github.com/grassrootseconomics/go-vise/db"
) )
// PrefixDb interface abstracts the database operations. // PrefixDb interface abstracts the database operations.

View File

@@ -5,7 +5,7 @@ import (
"context" "context"
"testing" "testing"
memdb "git.defalsify.org/vise.git/db/mem" memdb "github.com/grassrootseconomics/go-vise/db/mem"
) )
func TestSubPrefix(t *testing.T) { func TestSubPrefix(t *testing.T) {

View File

@@ -3,9 +3,9 @@ package store
import ( import (
"context" "context"
visedb "git.defalsify.org/vise.git/db"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
visedb "github.com/grassrootseconomics/go-vise/db"
) )
type LogDb struct { type LogDb struct {

View File

@@ -173,9 +173,9 @@ func UpdateSwapToVoucherData(ctx context.Context, store DataStore, sessionId str
logg.InfoCtxf(ctx, "UpdateSwapToVoucherData", "data", data) logg.InfoCtxf(ctx, "UpdateSwapToVoucherData", "data", data)
// Active swap to voucher data entries // Active swap to voucher data entries
activeEntries := map[storedb.DataTyp][]byte{ activeEntries := map[storedb.DataTyp][]byte{
storedb.DATA_ACTIVE_SWAP_TO_ADDRESS: []byte(data.TokenAddress),
storedb.DATA_ACTIVE_SWAP_TO_SYM: []byte(data.TokenSymbol), storedb.DATA_ACTIVE_SWAP_TO_SYM: []byte(data.TokenSymbol),
storedb.DATA_ACTIVE_SWAP_TO_DECIMAL: []byte(data.TokenDecimals), storedb.DATA_ACTIVE_SWAP_TO_DECIMAL: []byte(data.TokenDecimals),
storedb.DATA_ACTIVE_SWAP_TO_ADDRESS: []byte(data.TokenAddress),
} }
// Write active data // Write active data

View File

@@ -14,13 +14,13 @@ func TestReadSwapData(t *testing.T) {
// Test swap data // Test swap data
swapData := map[storedb.DataTyp]string{ swapData := map[storedb.DataTyp]string{
storedb.DATA_PUBLIC_KEY: publicKey, storedb.DATA_PUBLIC_KEY: publicKey,
storedb.DATA_ACTIVE_POOL_ADDRESS: "0x48a953cA5cf5298bc6f6Af3C608351f537AAcb9e", storedb.DATA_ACTIVE_POOL_ADDRESS: "0x48a953cA5cf5298bc6f6Af3C608351f537AAcb9e",
storedb.DATA_ACTIVE_SWAP_FROM_SYM: "AMANI", storedb.DATA_ACTIVE_SYM: "AMANI",
storedb.DATA_ACTIVE_SWAP_FROM_DECIMAL: "6", storedb.DATA_ACTIVE_DECIMAL: "6",
storedb.DATA_ACTIVE_SWAP_FROM_ADDRESS: "0xc7B78Ac9ACB9E025C8234621FC515bC58179dEAe", storedb.DATA_ACTIVE_ADDRESS: "0xc7B78Ac9ACB9E025C8234621FC515bC58179dEAe",
storedb.DATA_ACTIVE_SWAP_TO_SYM: "cUSD", storedb.DATA_ACTIVE_SWAP_TO_SYM: "cUSD",
storedb.DATA_ACTIVE_SWAP_TO_ADDRESS: "0x765DE816845861e75A25fCA122bb6898B8B1282a", storedb.DATA_ACTIVE_SWAP_TO_ADDRESS: "0x765DE816845861e75A25fCA122bb6898B8B1282a",
} }
// Store the data // Store the data
@@ -53,15 +53,16 @@ func TestReadSwapPreviewData(t *testing.T) {
// Test swap preview data // Test swap preview data
swapPreviewData := map[storedb.DataTyp]string{ swapPreviewData := map[storedb.DataTyp]string{
storedb.DATA_PUBLIC_KEY: publicKey, storedb.DATA_TEMPORARY_VALUE: "temp",
storedb.DATA_ACTIVE_SWAP_MAX_AMOUNT: "1339482", storedb.DATA_PUBLIC_KEY: publicKey,
storedb.DATA_ACTIVE_SWAP_FROM_DECIMAL: "6", storedb.DATA_ACTIVE_SWAP_MAX_AMOUNT: "1339482",
storedb.DATA_ACTIVE_POOL_ADDRESS: "0x48a953cA5cf5298bc6f6Af3C608351f537AAcb9e", storedb.DATA_ACTIVE_DECIMAL: "6",
storedb.DATA_ACTIVE_SWAP_FROM_ADDRESS: "0xc7B78Ac9ACB9E025C8234621FC515bC58179dEAe", storedb.DATA_ACTIVE_POOL_ADDRESS: "0x48a953cA5cf5298bc6f6Af3C608351f537AAcb9e",
storedb.DATA_ACTIVE_SWAP_FROM_SYM: "AMANI", storedb.DATA_ACTIVE_ADDRESS: "0xc7B78Ac9ACB9E025C8234621FC515bC58179dEAe",
storedb.DATA_ACTIVE_SWAP_TO_ADDRESS: "0x765DE816845861e75A25fCA122bb6898B8B1282a", storedb.DATA_ACTIVE_SYM: "AMANI",
storedb.DATA_ACTIVE_SWAP_TO_SYM: "cUSD", storedb.DATA_ACTIVE_SWAP_TO_ADDRESS: "0x765DE816845861e75A25fCA122bb6898B8B1282a",
storedb.DATA_ACTIVE_SWAP_TO_DECIMAL: "18", storedb.DATA_ACTIVE_SWAP_TO_SYM: "cUSD",
storedb.DATA_ACTIVE_SWAP_TO_DECIMAL: "18",
} }
// Store the data // Store the data
@@ -72,6 +73,7 @@ func TestReadSwapPreviewData(t *testing.T) {
} }
expectedResult := SwapPreviewData{ expectedResult := SwapPreviewData{
TemporaryValue: "temp",
PublicKey: "0X13242618721", PublicKey: "0X13242618721",
ActiveSwapMaxAmount: "1339482", ActiveSwapMaxAmount: "1339482",
ActiveSwapFromDecimal: "6", ActiveSwapFromDecimal: "6",

View File

@@ -7,6 +7,7 @@ import (
"math/big" "math/big"
"reflect" "reflect"
"strconv" "strconv"
"strings"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
) )
@@ -21,25 +22,34 @@ type TransactionData struct {
ActiveAddress string ActiveAddress string
} }
// TruncateDecimalString safely truncates the input amount to the specified decimal places // TruncateDecimalString safely truncates (not rounds) a number string to the specified decimal places
func TruncateDecimalString(input string, decimalPlaces int) (string, error) { func TruncateDecimalString(input string, decimalPlaces int) (string, error) {
num, ok := new(big.Float).SetString(input) if _, err := strconv.ParseFloat(input, 64); err != nil {
if !ok {
return "", fmt.Errorf("invalid input") return "", fmt.Errorf("invalid input")
} }
// Multiply by 10^decimalPlaces // Split input into integer and fractional parts
scale := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimalPlaces)), nil)) parts := strings.SplitN(input, ".", 2)
scaled := new(big.Float).Mul(num, scale) intPart := parts[0]
var fracPart string
// Truncate by converting to int (chops off decimals) if len(parts) == 2 {
intPart, _ := scaled.Int(nil) fracPart = parts[1]
}
// Divide back to get truncated float // Truncate or pad fractional part
truncated := new(big.Float).Quo(new(big.Float).SetInt(intPart), scale) if len(fracPart) > decimalPlaces {
fracPart = fracPart[:decimalPlaces]
} else {
fracPart = fracPart + strings.Repeat("0", decimalPlaces-len(fracPart))
}
// Format with fixed decimals // Handle zero decimal places
return truncated.Text('f', decimalPlaces), nil if decimalPlaces == 0 {
return intPart, nil
}
return fmt.Sprintf("%s.%s", intPart, fracPart), nil
} }
func ParseAndScaleAmount(storedAmount, activeDecimal string) (string, error) { func ParseAndScaleAmount(storedAmount, activeDecimal string) (string, error) {

View File

@@ -22,6 +22,13 @@ func TestTruncateDecimalString(t *testing.T) {
want: "4.00", want: "4.00",
expectError: false, expectError: false,
}, },
{
name: "precision test",
input: "2.1",
decimalPlaces: 2,
want: "2.10",
expectError: false,
},
{ {
name: "single decimal", name: "single decimal",
input: "4.1", input: "4.1",

View File

@@ -3,11 +3,11 @@ package store
import ( import (
"context" "context"
visedb "git.defalsify.org/vise.git/db"
"git.grassecon.net/grassrootseconomics/common/hex" "git.grassecon.net/grassrootseconomics/common/hex"
"git.grassecon.net/grassrootseconomics/common/identity" "git.grassecon.net/grassrootseconomics/common/identity"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
visedb "github.com/grassrootseconomics/go-vise/db"
) )
// TODO: Rename interface, "datastore" is redundant naming and too general // TODO: Rename interface, "datastore" is redundant naming and too general

View File

@@ -6,13 +6,13 @@ import (
"math/big" "math/big"
"strings" "strings"
"git.defalsify.org/vise.git/logging"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
slogging "github.com/grassrootseconomics/go-vise/slog"
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
) )
var ( var (
logg = logging.NewVanilla().WithDomain("vouchers").WithContextKey("SessionId") logg = slogging.Get().With("component", "vouchers")
) )
// symbolReplacements holds mappings of invalid symbols → valid ones // symbolReplacements holds mappings of invalid symbols → valid ones

View File

@@ -8,8 +8,8 @@ import (
"github.com/alecthomas/assert/v2" "github.com/alecthomas/assert/v2"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
memdb "git.defalsify.org/vise.git/db/mem"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
memdb "github.com/grassrootseconomics/go-vise/db/mem"
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
) )

View File

@@ -9,10 +9,6 @@ import (
"path/filepath" "path/filepath"
"time" "time"
"git.defalsify.org/vise.git/asm"
"git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/sarafu-api/remote" "git.grassecon.net/grassrootseconomics/sarafu-api/remote"
httpremote "git.grassecon.net/grassrootseconomics/sarafu-api/remote/http" httpremote "git.grassecon.net/grassrootseconomics/sarafu-api/remote/http"
"git.grassecon.net/grassrootseconomics/sarafu-api/testutil/testservice" "git.grassecon.net/grassrootseconomics/sarafu-api/testutil/testservice"
@@ -20,6 +16,10 @@ import (
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers" "git.grassecon.net/grassrootseconomics/sarafu-vise/handlers"
"git.grassecon.net/grassrootseconomics/sarafu-vise/testutil/testtag" "git.grassecon.net/grassrootseconomics/sarafu-vise/testutil/testtag"
"git.grassecon.net/grassrootseconomics/visedriver/storage" "git.grassecon.net/grassrootseconomics/visedriver/storage"
"github.com/grassrootseconomics/go-vise/asm"
"github.com/grassrootseconomics/go-vise/engine"
"github.com/grassrootseconomics/go-vise/persist"
"github.com/grassrootseconomics/go-vise/resource"
"github.com/jackc/pgx/v5/pgxpool" "github.com/jackc/pgx/v5/pgxpool"
) )
@@ -113,12 +113,6 @@ func TestEngine(sessionId string) (engine.Engine, func(), chan bool, *persist.Pe
os.Exit(1) os.Exit(1)
} }
logdb, err := menuStorageService.GetLogDb(ctx, userDataStore, "test-db-logs", "user-data")
if err != nil {
fmt.Fprintf(os.Stderr, "get log db error: %v\n", err)
os.Exit(1)
}
dbResource, ok := rs.(*resource.DbResource) dbResource, ok := rs.(*resource.DbResource)
if !ok { if !ok {
fmt.Fprintf(os.Stderr, "dbresource cast error") fmt.Fprintf(os.Stderr, "dbresource cast error")
@@ -127,7 +121,6 @@ func TestEngine(sessionId string) (engine.Engine, func(), chan bool, *persist.Pe
lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs) lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs)
lhs.SetDataStore(&userDataStore) lhs.SetDataStore(&userDataStore)
lhs.SetLogDb(&logdb)
lhs.SetPersister(pe) lhs.SetPersister(pe)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, err.Error()) fmt.Fprintf(os.Stderr, err.Error())
@@ -161,7 +154,6 @@ func TestEngine(sessionId string) (engine.Engine, func(), chan bool, *persist.Pe
en := lhs.GetEngine(lhs.Cfg, rs, pe) en := lhs.GetEngine(lhs.Cfg, rs, pe)
cleanFn := func() { cleanFn := func() {
logdb.Close(ctx)
err := en.Finish(ctx) err := en.Finish(ctx)
if err != nil { if err != nil {
logg.Errorf(err.Error()) logg.Errorf(err.Error())

View File

@@ -4,16 +4,16 @@ import (
"context" "context"
"path" "path"
"git.defalsify.org/vise.git/db"
fsdb "git.defalsify.org/vise.git/db/fs"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config" "git.grassecon.net/grassrootseconomics/sarafu-vise/config"
"git.grassecon.net/grassrootseconomics/visedriver/storage" "git.grassecon.net/grassrootseconomics/visedriver/storage"
"github.com/grassrootseconomics/go-vise/db"
fsdb "github.com/grassrootseconomics/go-vise/db/fs"
slogging "github.com/grassrootseconomics/go-vise/slog"
testdataloader "github.com/peteole/testdata-loader" testdataloader "github.com/peteole/testdata-loader"
) )
var ( var (
logg = logging.NewVanilla().WithDomain("sarafu-vise.testutil").WithContextKey("SessionId") logg = slogging.Get().With("component", "sarafu-vise.testutil")
conns storage.Conns conns storage.Conns
resourceDb db.Db resourceDb db.Db
baseDir = testdataloader.GetBasePath() baseDir = testdataloader.GetBasePath()