Added back africastalking executable, vise-code

This commit is contained in:
lash 2025-01-11 15:21:40 +00:00
parent d98341bb69
commit 5f261c642d
Signed by: lash
GPG Key ID: 21D2E7BB88C2A746
384 changed files with 1909 additions and 95 deletions

20
.env.example Normal file
View File

@ -0,0 +1,20 @@
#Serve Http
PORT=7123
HOST=127.0.0.1
#AfricasTalking USSD POST endpoint
AT_ENDPOINT=/ussd/africastalking
#PostgreSQL
DB_CONN=postgres://postgres:strongpass@localhost:5432/urdt_ussd
#DB_TIMEZONE=Africa/Nairobi
#DB_SCHEMA=vise
#External API Calls
CUSTODIAL_URL_BASE=http://localhost:5003
BEARER_TOKEN=eyJeSIsInRcCI6IkpXVCJ.yJwdWJsaWNLZXkiOiIwrrrrrr
DATA_URL_BASE=http://localhost:5006
#Language
DEFAULT_LANGUAGE=eng
LANGUAGES=eng, swa

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
**/*.env
covprofile
go.work*
**/*/*.bin
**/*/.state/
cmd/.state/
id_*
*.gdbm
*.log

177
cmd/africastalking/main.go Normal file
View File

@ -0,0 +1,177 @@
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/logging"
"git.defalsify.org/vise.git/lang"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/visedriver/config"
"git.grassecon.net/grassrootseconomics/visedriver/initializers"
"git.grassecon.net/grassrootseconomics/visedriver/remote"
"git.grassecon.net/grassrootseconomics/visedriver/common"
"git.grassecon.net/grassrootseconomics/visedriver/session"
at "git.grassecon.net/grassrootseconomics/visedriver-africastalking/africastalking"
"git.grassecon.net/grassrootseconomics/visedriver-africastalking/args"
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers"
)
var (
logg = logging.NewVanilla().WithDomain("AfricasTalking").WithContextKey("at-session-id")
scriptDir = path.Join("services", "registration")
build = "dev"
menuSeparator = ": "
)
func init() {
initializers.LoadEnvVariables()
}
func main() {
config.LoadConfig()
var connStr string
var resourceDir string
var size uint
var database string
var engineDebug bool
var host string
var port uint
var err error
var gettextDir string
var langs args.LangVar
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
flag.StringVar(&connStr, "c", "", "connection string")
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
flag.UintVar(&size, "s", 160, "max size of output")
flag.StringVar(&host, "h", initializers.GetEnv("HOST", "127.0.0.1"), "http host")
flag.UintVar(&port, "p", initializers.GetEnvUint("PORT", 7123), "http port")
flag.StringVar(&gettextDir, "gettext", "", "use gettext translations from given directory")
flag.Var(&langs, "language", "add symbol resolution for language")
flag.Parse()
if connStr == "" {
connStr = config.DbConn
}
connData, err := common.ToConnData(config.DbConn)
if err != nil {
fmt.Fprintf(os.Stderr, "connstr err: %v", err)
os.Exit(1)
}
logg.Infof("start command", "build", build, "conn", connData, "resourcedir", resourceDir, "outputsize", size)
ctx := context.Background()
ctx = context.WithValue(ctx, "Database", database)
ln, err := lang.LanguageFromCode(config.DefaultLanguage)
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,
}
if engineDebug {
cfg.EngineDebug = true
}
menuStorageService, err := common.NewStorageService(connData)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
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)
}
defer userdataStore.Close()
dbResource, ok := rs.(*resource.DbResource)
if !ok {
os.Exit(1)
}
lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
lhs.SetDataStore(&userdataStore)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
accountService := remote.AccountService{}
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)
}
defer stateStore.Close()
rp := &at.ATRequestParser{}
bsh := session.NewBaseSessionHandler(cfg, rs, stateStore, userdataStore, rp, hl)
sh := at.NewATSessionHandler(bsh)
mux := http.NewServeMux()
mux.Handle(initializers.GetEnv("AT_ENDPOINT", "/"), sh)
s := &http.Server{
Addr: fmt.Sprintf("%s:%s", host, strconv.Itoa(int(port))),
Handler: mux,
}
s.RegisterOnShutdown(sh.Shutdown)
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)
}
}

199
cmd/async/main.go Normal file
View File

@ -0,0 +1,199 @@
package main
import (
"context"
"flag"
"fmt"
"os"
"os/signal"
"path"
"syscall"
"git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/lang"
"git.defalsify.org/vise.git/logging"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/visedriver/config"
"git.grassecon.net/grassrootseconomics/visedriver/initializers"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
"git.grassecon.net/grassrootseconomics/visedriver/session"
"git.grassecon.net/grassrootseconomics/visedriver/remote"
"git.grassecon.net/grassrootseconomics/visedriver/request"
"git.grassecon.net/grassrootseconomics/sarafu-vise/args"
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers"
)
var (
logg = logging.NewVanilla()
scriptDir = path.Join("services", "registration")
menuSeparator = ": "
)
func init() {
initializers.LoadEnvVariables()
}
type asyncRequestParser struct {
sessionId string
input []byte
}
func (p *asyncRequestParser) GetSessionId(ctx context.Context, r any) (string, error) {
return p.sessionId, nil
}
func (p *asyncRequestParser) GetInput(r any) ([]byte, error) {
return p.input, nil
}
func main() {
config.LoadConfig()
var connStr string
var sessionId string
var resourceDir string
var size uint
var engineDebug bool
var host string
var port uint
var err error
var gettextDir string
var langs args.LangVar
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
flag.StringVar(&connStr, "c", "", "connection string")
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
flag.UintVar(&size, "s", 160, "max size of output")
flag.StringVar(&host, "h", initializers.GetEnv("HOST", "127.0.0.1"), "http host")
flag.UintVar(&port, "p", initializers.GetEnvUint("PORT", 7123), "http port")
flag.StringVar(&gettextDir, "gettext", "", "use gettext translations from given directory")
flag.Var(&langs, "language", "add symbol resolution for language")
flag.Parse()
if connStr == "" {
connStr = config.DbConn
}
connData, err := storage.ToConnData(connStr)
if err != nil {
fmt.Fprintf(os.Stderr, "connstr err: %v", err)
os.Exit(1)
}
logg.Infof("start command", "conn", connData, "resourcedir", resourceDir, "outputsize", size, "sessionId", sessionId)
ctx := context.Background()
ln, err := lang.LanguageFromCode(config.DefaultLanguage)
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,
}
if engineDebug {
cfg.EngineDebug = true
}
menuStorageService := storage.NewMenuStorageService(connData, resourceDir)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
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)
}
defer userdataStore.Close()
dbResource, ok := rs.(*resource.DbResource)
if !ok {
os.Exit(1)
}
lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs)
lhs.SetDataStore(&userdataStore)
accountService := remote.AccountService{}
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)
}
defer stateStore.Close()
rp := &asyncRequestParser{
sessionId: sessionId,
}
sh := session.NewBaseSessionHandler(cfg, rs, stateStore, userdataStore, rp, hl)
cfg.SessionId = sessionId
rqs := request.RequestSession{
Ctx: ctx,
Writer: os.Stdout,
Config: cfg,
}
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:
}
sh.Shutdown()
}()
for true {
rqs, err = sh.Process(rqs)
if err != nil {
logg.ErrorCtxf(ctx, "error in process: %v", "err", err)
fmt.Errorf("error in process: %v", err)
os.Exit(1)
}
rqs, err = sh.Output(rqs)
if err != nil {
logg.ErrorCtxf(ctx, "error in output: %v", "err", err)
fmt.Errorf("error in output: %v", err)
os.Exit(1)
}
rqs, err = sh.Reset(rqs)
if err != nil {
logg.ErrorCtxf(ctx, "error in reset: %v", "err", err)
fmt.Errorf("error in reset: %v", err)
os.Exit(1)
}
fmt.Println("")
_, err = fmt.Scanln(&rqs.Input)
if err != nil {
logg.ErrorCtxf(ctx, "error in input", "err", err)
fmt.Errorf("error in input: %v", err)
os.Exit(1)
}
}
}

162
cmd/http/main.go Normal file
View File

@ -0,0 +1,162 @@
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/visedriver/config"
"git.grassecon.net/grassrootseconomics/visedriver/initializers"
httpsession "git.grassecon.net/grassrootseconomics/visedriver/session/http"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
"git.grassecon.net/grassrootseconomics/visedriver/session"
"git.grassecon.net/grassrootseconomics/visedriver/remote"
"git.grassecon.net/grassrootseconomics/sarafu-vise/args"
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers"
)
var (
logg = logging.NewVanilla()
scriptDir = path.Join("services", "registration")
menuSeparator = ": "
)
func init() {
initializers.LoadEnvVariables()
}
func main() {
config.LoadConfig()
var connStr string
var resourceDir string
var size uint
var engineDebug bool
var host string
var port uint
var err error
var gettextDir string
var langs args.LangVar
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
flag.StringVar(&connStr, "c", "", "connection string")
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
flag.UintVar(&size, "s", 160, "max size of output")
flag.StringVar(&host, "h", initializers.GetEnv("HOST", "127.0.0.1"), "http host")
flag.UintVar(&port, "p", initializers.GetEnvUint("PORT", 7123), "http port")
flag.StringVar(&gettextDir, "gettext", "", "use gettext translations from given directory")
flag.Var(&langs, "language", "add symbol resolution for language")
flag.Parse()
if connStr == "" {
connStr = config.DbConn
}
connData, err := storage.ToConnData(connStr)
if err != nil {
fmt.Fprintf(os.Stderr, "connstr err: %v", err)
os.Exit(1)
}
logg.Infof("start command", "conn", connData, "resourcedir", resourceDir, "outputsize", size)
ctx := context.Background()
ln, err := lang.LanguageFromCode(config.DefaultLanguage)
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,
}
if engineDebug {
cfg.EngineDebug = true
}
menuStorageService := storage.NewMenuStorageService(connData, resourceDir)
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)
}
defer userdataStore.Close()
dbResource, ok := rs.(*resource.DbResource)
if !ok {
os.Exit(1)
}
lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs)
lhs.SetDataStore(&userdataStore)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
accountService := remote.AccountService{}
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)
}
defer stateStore.Close()
rp := &httpsession.DefaultRequestParser{}
bsh := session.NewBaseSessionHandler(cfg, rs, stateStore, userdataStore, rp, hl)
sh := httpsession.NewHTTPSessionHandler(bsh)
s := &http.Server{
Addr: fmt.Sprintf("%s:%s", host, strconv.Itoa(int(port))),
Handler: sh,
}
s.RegisterOnShutdown(sh.Shutdown)
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)
}
}

34
cmd/ssh/README.md Normal file
View File

@ -0,0 +1,34 @@
# 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>
```

144
cmd/ssh/main.go Normal file
View File

@ -0,0 +1,144 @@
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/visedriver/config"
"git.grassecon.net/grassrootseconomics/visedriver/initializers"
"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 init() {
initializers.LoadEnvVariables()
}
func main() {
config.LoadConfig()
var connStr string
var authConnStr string
var resourceDir string
var size uint
var engineDebug bool
var stateDebug bool
var host string
var port uint
flag.StringVar(&connStr, "c", "", "connection string")
flag.StringVar(&authConnStr, "authdb", "", "auth connection string")
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
flag.UintVar(&size, "s", 160, "max size of output")
flag.StringVar(&host, "h", "127.0.0.1", "socket host")
flag.UintVar(&port, "p", 7122, "socket port")
flag.Parse()
if connStr == "" {
connStr = config.DbConn
}
if authConnStr == "" {
authConnStr = connStr
}
connData, err := storage.ToConnData(connStr)
if err != nil {
fmt.Fprintf(os.Stderr, "connstr err: %v", 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", connData, "authconn", authConnData, "resourcedir", resourceDir, "outputsize", size, "keyfile", sshKeyFile, "host", host, "port", port)
pfp := path.Join(scriptDir, "pp.csv")
cfg := engine.Config{
Root: "root",
OutputSize: uint32(size),
FlagCount: uint32(16),
}
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()
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: connData,
ResourceDir: resourceDir,
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)
}

44
cmd/ssh/sshkey/main.go Normal file
View File

@ -0,0 +1,44 @@
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()
err = store.AddFromFile(ctx, sshKeyFile, sessionId)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
}
}

4
go.mod
View File

@ -4,8 +4,8 @@ go 1.23.4
require ( require (
git.defalsify.org/vise.git v0.2.3-0.20250103172917-3e190a44568d git.defalsify.org/vise.git v0.2.3-0.20250103172917-3e190a44568d
git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250110203936-8387644019e6 git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250111151614-46bf21b7b8bd
git.grassecon.net/urdt/ussd v0.8.0-beta.11 git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250111150203-fd8301144509
github.com/alecthomas/assert/v2 v2.2.2 github.com/alecthomas/assert/v2 v2.2.2
github.com/gofrs/uuid v4.4.0+incompatible github.com/gofrs/uuid v4.4.0+incompatible
github.com/grassrootseconomics/ussd-data-service v1.2.0-beta github.com/grassrootseconomics/ussd-data-service v1.2.0-beta

8
go.sum
View File

@ -1,9 +1,9 @@
git.defalsify.org/vise.git v0.2.3-0.20250103172917-3e190a44568d h1:bPAOVZOX4frSGhfOdcj7kc555f8dc9DmMd2YAyC2AMw= git.defalsify.org/vise.git v0.2.3-0.20250103172917-3e190a44568d h1:bPAOVZOX4frSGhfOdcj7kc555f8dc9DmMd2YAyC2AMw=
git.defalsify.org/vise.git v0.2.3-0.20250103172917-3e190a44568d/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck= git.defalsify.org/vise.git v0.2.3-0.20250103172917-3e190a44568d/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck=
git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250110203936-8387644019e6 h1:KvcNmeY9EpvsVtcwYW48FxTb7cTdDY1aX0Jcwd649c0= git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250111151614-46bf21b7b8bd h1:mKCov8udBJBQuMF3aFg38SkClL8OvAUZmtArNzgIPak=
git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250110203936-8387644019e6/go.mod h1:E6W7ZOa7ZvVr0Bc5ot0LNSwpSPYq4hXlAIvEPy3AJ7U= git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250111151614-46bf21b7b8bd/go.mod h1:E6W7ZOa7ZvVr0Bc5ot0LNSwpSPYq4hXlAIvEPy3AJ7U=
git.grassecon.net/urdt/ussd v0.8.0-beta.11 h1:lAKH5DI21cD+YlS9J+69h5OR45LyYo7dQkufol926FI= git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250111150203-fd8301144509 h1:xlX2FAJkjn1/VS/1z8A9eSGnKWDUmBJy+GtEEDRmggc=
git.grassecon.net/urdt/ussd v0.8.0-beta.11/go.mod h1:Xct45L7FUE4pYtLN4gmhkMCoafUNpcOJ7horP9kPDAc= git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250111150203-fd8301144509/go.mod h1:FwJ9MQtaKlDThtL0ovxZXBIDJoDNgiSeSAxeZNriQJk=
github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk= github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk=
github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
github.com/alecthomas/participle/v2 v2.0.0 h1:Fgrq+MbuSsJwIkw3fEj9h75vDP0Er5JzepJ0/HNHv0g= github.com/alecthomas/participle/v2 v2.0.0 h1:Fgrq+MbuSsJwIkw3fEj9h75vDP0Er5JzepJ0/HNHv0g=

View File

@ -21,7 +21,6 @@ import (
"git.grassecon.net/grassrootseconomics/visedriver/utils" "git.grassecon.net/grassrootseconomics/visedriver/utils"
"git.grassecon.net/grassrootseconomics/visedriver/models" "git.grassecon.net/grassrootseconomics/visedriver/models"
"git.grassecon.net/grassrootseconomics/visedriver/remote" "git.grassecon.net/grassrootseconomics/visedriver/remote"
"git.grassecon.net/grassrootseconomics/visedriver/handlers"
"gopkg.in/leonelquinteros/gotext.v1" "gopkg.in/leonelquinteros/gotext.v1"
dbstorage "git.grassecon.net/grassrootseconomics/visedriver/storage/db" dbstorage "git.grassecon.net/grassrootseconomics/visedriver/storage/db"
@ -39,10 +38,6 @@ type FlagManager struct {
parser *asm.FlagParser parser *asm.FlagParser
} }
type MenuHandlers struct {
*handlers.Handlers
}
// NewFlagManager creates a new FlagManager instance // NewFlagManager creates a new FlagManager instance
func NewFlagManager(csvPath string) (*FlagManager, error) { func NewFlagManager(csvPath string) (*FlagManager, error) {
parser := asm.NewFlagParser() parser := asm.NewFlagParser()
@ -61,11 +56,54 @@ func (fm *FlagManager) GetFlag(label string) (uint32, error) {
return fm.parser.GetFlag(label) return fm.parser.GetFlag(label)
} }
func ToMenuHandlers(h *handlers.Handlers) *MenuHandlers { type MenuHandlers struct {
return &MenuHandlers{ pe *persist.Persister
Handlers: h, st *state.State
ca cache.Memory
userdataStore common.DataStore
adminstore *utils.AdminStore
flagManager *asm.FlagParser
accountService remote.AccountServiceInterface
prefixDb dbstorage.PrefixDb
profile *models.Profile
ReplaceSeparatorFunc func(string) string
} }
// NewHandlers creates a new instance of the Handlers struct with the provided dependencies.
func NewMenuHandlers(appFlags *asm.FlagParser, userdataStore db.Db, adminstore *utils.AdminStore, accountService remote.AccountServiceInterface, replaceSeparatorFunc func(string) string) (*MenuHandlers, error) {
if userdataStore == nil {
return nil, fmt.Errorf("cannot create handler with nil userdata store")
} }
userDb := &common.UserDataStore{
Db: userdataStore,
}
// Instantiate the SubPrefixDb with "DATATYPE_USERDATA" prefix
prefix := common.ToBytes(db.DATATYPE_USERDATA)
prefixDb := dbstorage.NewSubPrefixDb(userdataStore, prefix)
h := &MenuHandlers{
userdataStore: userDb,
flagManager: appFlags,
adminstore: adminstore,
accountService: accountService,
prefixDb: prefixDb,
profile: &models.Profile{Max: 6},
ReplaceSeparatorFunc: replaceSeparatorFunc,
}
return h, nil
}
// WithPersister sets persister instance to the handlers.
//func (h *MenuHandlers) WithPersister(pe *persist.Persister) *MenuHandlers {
func (h *MenuHandlers) SetPersister(pe *persist.Persister) {
if h.pe != nil {
panic("persister already set")
}
h.pe = pe
//return h
}
// Init initializes the handler for a new session. // Init initializes the handler for a new session.
func (h *MenuHandlers) Init(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *MenuHandlers) Init(ctx context.Context, sym string, input []byte) (resource.Result, error) {
@ -121,6 +159,7 @@ func (h *MenuHandlers) SetLanguage(ctx context.Context, sym string, input []byte
symbol, _ := h.st.Where() symbol, _ := h.st.Where()
code := strings.Split(symbol, "_")[1] code := strings.Split(symbol, "_")[1]
// TODO: Use defaultlanguage from config
if !utils.IsValidISO639(code) { if !utils.IsValidISO639(code) {
//Fallback to english instead? //Fallback to english instead?
code = "eng" code = "eng"

View File

@ -72,7 +72,7 @@ func InitializeTestSubPrefixDb(t *testing.T, ctx context.Context) *dbstorage.Sub
return spdb return spdb
} }
func TestNewHandlers(t *testing.T) { func TestNewMenuHandlers(t *testing.T) {
_, store := InitializeTestStore(t) _, store := InitializeTestStore(t)
fm, err := NewFlagManager(flagsPath) fm, err := NewFlagManager(flagsPath)
@ -84,7 +84,7 @@ func TestNewHandlers(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 := NewHandlers(fm.parser, store, nil, &accountService, mockReplaceSeparator) handlers, err := NewMenuHandlers(fm.parser, store, nil, &accountService, mockReplaceSeparator)
if err != nil { if err != nil {
t.Fatalf("expected no error, got %v", err) t.Fatalf("expected no error, got %v", err)
} }
@ -108,7 +108,7 @@ func TestNewHandlers(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 := NewHandlers(fm.parser, nil, nil, &accountService, mockReplaceSeparator) handlers, err := NewMenuHandlers(fm.parser, nil, nil, &accountService, mockReplaceSeparator)
if err == nil { if err == nil {
t.Fatal("expected an error, got none") t.Fatal("expected an error, got none")
} }
@ -144,23 +144,23 @@ func TestInit(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
setup func() (*Handlers, context.Context) setup func() (*MenuHandlers, context.Context)
input []byte input []byte
expectedResult resource.Result expectedResult resource.Result
}{ }{
{ {
name: "Handler not ready", name: "Handler not ready",
setup: func() (*Handlers, context.Context) { setup: func() (*MenuHandlers, context.Context) {
return &Handlers{}, ctx return &MenuHandlers{}, ctx
}, },
input: []byte("1"), input: []byte("1"),
expectedResult: resource.Result{}, expectedResult: resource.Result{},
}, },
{ {
name: "State and memory initialization", name: "State and memory initialization",
setup: func() (*Handlers, context.Context) { setup: func() (*MenuHandlers, context.Context) {
pe := persist.NewPersister(store).WithSession(sessionId).WithContent(st, ca) pe := persist.NewPersister(store).WithSession(sessionId).WithContent(st, ca)
h := &Handlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm.parser,
adminstore: adminstore, adminstore: adminstore,
pe: pe, pe: pe,
@ -174,9 +174,9 @@ func TestInit(t *testing.T) {
}, },
{ {
name: "Non-admin session initialization", name: "Non-admin session initialization",
setup: func() (*Handlers, context.Context) { setup: func() (*MenuHandlers, context.Context) {
pe := persist.NewPersister(store).WithSession("0712345678").WithContent(st, ca) pe := persist.NewPersister(store).WithSession("0712345678").WithContent(st, ca)
h := &Handlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm.parser,
adminstore: adminstore, adminstore: adminstore,
pe: pe, pe: pe,
@ -190,9 +190,9 @@ func TestInit(t *testing.T) {
}, },
{ {
name: "Move to top node on empty input", name: "Move to top node on empty input",
setup: func() (*Handlers, context.Context) { setup: func() (*MenuHandlers, context.Context) {
pe := persist.NewPersister(store).WithSession(sessionId).WithContent(st, ca) pe := persist.NewPersister(store).WithSession(sessionId).WithContent(st, ca)
h := &Handlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm.parser,
adminstore: adminstore, adminstore: adminstore,
pe: pe, pe: pe,
@ -253,7 +253,7 @@ func TestCreateAccount(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm.parser,
@ -275,20 +275,20 @@ func TestCreateAccount(t *testing.T) {
func TestWithPersister(t *testing.T) { func TestWithPersister(t *testing.T) {
// Test case: Setting a persister // Test case: Setting a persister
h := &Handlers{} h := &MenuHandlers{}
p := &persist.Persister{} p := &persist.Persister{}
result := h.WithPersister(p) h.SetPersister(p)
assert.Equal(t, p, h.pe, "The persister should be set correctly.") assert.Equal(t, p, h.pe, "The persister should be set correctly.")
assert.Equal(t, h, result, "The returned handler should be the same instance.") //assert.Equal(t, h, result, "The returned handler should be the same instance.")
} }
func TestWithPersister_PanicWhenAlreadySet(t *testing.T) { func TestWithPersister_PanicWhenAlreadySet(t *testing.T) {
// Test case: Panic on multiple calls // Test case: Panic on multiple calls
h := &Handlers{pe: &persist.Persister{}} h := &MenuHandlers{pe: &persist.Persister{}}
require.Panics(t, func() { require.Panics(t, func() {
h.WithPersister(&persist.Persister{}) h.SetPersister(&persist.Persister{})
}, "Should panic when trying to set a persister again.") }, "Should panic when trying to set a persister again.")
} }
@ -317,8 +317,8 @@ func TestSaveFirstname(t *testing.T) {
expectedResult.FlagSet = []uint32{flag_firstname_set} expectedResult.FlagSet = []uint32{flag_firstname_set}
// Create the Handlers instance with the mock store // Create the MenuHandlers instance with the mock store
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
flagManager: fm.parser, flagManager: fm.parser,
st: mockState, st: mockState,
@ -361,8 +361,8 @@ func TestSaveFamilyname(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
// Create the Handlers instance with the mock store // Create the MenuHandlers instance with the mock store
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
st: mockState, st: mockState,
flagManager: fm.parser, flagManager: fm.parser,
@ -405,8 +405,8 @@ func TestSaveYoB(t *testing.T) {
expectedResult.FlagSet = []uint32{flag_yob_set} expectedResult.FlagSet = []uint32{flag_yob_set}
// Create the Handlers instance with the mock store // Create the MenuHandlers instance with the mock store
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
flagManager: fm.parser, flagManager: fm.parser,
st: mockState, st: mockState,
@ -449,8 +449,8 @@ func TestSaveLocation(t *testing.T) {
expectedResult.FlagSet = []uint32{flag_location_set} expectedResult.FlagSet = []uint32{flag_location_set}
// Create the Handlers instance with the mock store // Create the MenuHandlers instance with the mock store
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
flagManager: fm.parser, flagManager: fm.parser,
st: mockState, st: mockState,
@ -493,8 +493,8 @@ func TestSaveOfferings(t *testing.T) {
expectedResult.FlagSet = []uint32{flag_offerings_set} expectedResult.FlagSet = []uint32{flag_offerings_set}
// Create the Handlers instance with the mock store // Create the MenuHandlers instance with the mock store
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
flagManager: fm.parser, flagManager: fm.parser,
st: mockState, st: mockState,
@ -560,8 +560,8 @@ func TestSaveGender(t *testing.T) {
} }
mockState.ExecPath = append(mockState.ExecPath, tt.executingSymbol) mockState.ExecPath = append(mockState.ExecPath, tt.executingSymbol)
// Create the Handlers instance with the mock store // Create the MenuHandlers instance with the mock store
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
st: mockState, st: mockState,
flagManager: fm.parser, flagManager: fm.parser,
@ -597,8 +597,8 @@ func TestSaveTemporaryPin(t *testing.T) {
flag_incorrect_pin, _ := fm.parser.GetFlag("flag_incorrect_pin") flag_incorrect_pin, _ := fm.parser.GetFlag("flag_incorrect_pin")
// Create the Handlers instance with the mock flag manager // Create the MenuHandlers instance with the mock flag manager
h := &Handlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm.parser,
userdataStore: store, userdataStore: store,
} }
@ -668,8 +668,8 @@ func TestCheckIdentifier(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
// Create the Handlers instance with the mock store // Create the MenuHandlers instance with the mock store
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
} }
@ -688,8 +688,8 @@ func TestGetSender(t *testing.T) {
ctx, _ := InitializeTestStore(t) ctx, _ := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
// Create the Handlers instance // Create the MenuHandlers instance
h := &Handlers{} h := &MenuHandlers{}
// Call the method // Call the method
res, _ := h.GetSender(ctx, "get_sender", []byte("")) res, _ := h.GetSender(ctx, "get_sender", []byte(""))
@ -717,8 +717,8 @@ func TestGetAmount(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
// Create the Handlers instance with the mock store // Create the MenuHandlers instance with the mock store
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
} }
@ -743,8 +743,8 @@ func TestGetRecipient(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
// Create the Handlers instance with the mock store // Create the MenuHandlers instance with the mock store
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
} }
@ -810,8 +810,8 @@ func TestSetLanguage(t *testing.T) {
// Set the ExecPath // Set the ExecPath
mockState.ExecPath = tt.execPath mockState.ExecPath = tt.execPath
// Create the Handlers instance with the mock flag manager // Create the MenuHandlers instance with the mock flag manager
h := &Handlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm.parser,
userdataStore: store, userdataStore: store,
st: mockState, st: mockState,
@ -854,8 +854,8 @@ func TestResetAllowUpdate(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
// Create the Handlers instance with the mock flag manager // Create the MenuHandlers instance with the mock flag manager
h := &Handlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm.parser,
} }
@ -896,8 +896,8 @@ func TestResetAccountAuthorized(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
// Create the Handlers instance with the mock flag manager // Create the MenuHandlers instance with the mock flag manager
h := &Handlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm.parser,
} }
@ -979,8 +979,8 @@ func TestIncorrectPinReset(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
// Create the Handlers instance with the mock flag manager // Create the MenuHandlers instance with the mock flag manager
h := &Handlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm.parser,
userdataStore: store, userdataStore: store,
} }
@ -1022,8 +1022,8 @@ func TestResetIncorrectYob(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
// Create the Handlers instance with the mock flag manager // Create the MenuHandlers instance with the mock flag manager
h := &Handlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm.parser,
} }
@ -1059,7 +1059,7 @@ func TestAuthorize(t *testing.T) {
// Set 1234 is the correct account pin // Set 1234 is the correct account pin
accountPIN := "1234" accountPIN := "1234"
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm.parser,
@ -1133,7 +1133,7 @@ func TestVerifyYob(t *testing.T) {
flag_incorrect_date_format, _ := fm.parser.GetFlag("flag_incorrect_date_format") flag_incorrect_date_format, _ := fm.parser.GetFlag("flag_incorrect_date_format")
ctx := context.WithValue(context.Background(), "SessionId", sessionId) ctx := context.WithValue(context.Background(), "SessionId", sessionId)
h := &Handlers{ h := &MenuHandlers{
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm.parser,
st: mockState, st: mockState,
@ -1199,7 +1199,7 @@ func TestVerifyCreatePin(t *testing.T) {
flag_pin_mismatch, _ := fm.parser.GetFlag("flag_pin_mismatch") flag_pin_mismatch, _ := fm.parser.GetFlag("flag_pin_mismatch")
flag_pin_set, _ := fm.parser.GetFlag("flag_pin_set") flag_pin_set, _ := fm.parser.GetFlag("flag_pin_set")
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm.parser,
@ -1293,7 +1293,7 @@ func TestCheckAccountStatus(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm.parser,
@ -1333,7 +1333,7 @@ func TestTransactionReset(t *testing.T) {
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm.parser,
@ -1380,7 +1380,7 @@ func TestResetTransactionAmount(t *testing.T) {
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm.parser,
@ -1424,7 +1424,7 @@ func TestInitiateTransaction(t *testing.T) {
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm.parser,
@ -1521,7 +1521,7 @@ func TestQuit(t *testing.T) {
ctx := context.WithValue(context.Background(), "SessionId", sessionId) ctx := context.WithValue(context.Background(), "SessionId", sessionId)
h := &Handlers{ h := &MenuHandlers{
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm.parser,
} }
@ -1570,7 +1570,7 @@ func TestValidateAmount(t *testing.T) {
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm.parser,
@ -1691,8 +1691,8 @@ func TestValidateRecipient(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
// Create the Handlers instance // Create the MenuHandlers instance
h := &Handlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm.parser,
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
@ -1745,7 +1745,7 @@ func TestCheckBalance(t *testing.T) {
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
ctx := context.WithValue(ctx, "SessionId", tt.sessionId) ctx := context.WithValue(ctx, "SessionId", tt.sessionId)
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
} }
@ -1780,7 +1780,7 @@ func TestGetProfile(t *testing.T) {
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
mockState := state.NewState(16) mockState := state.NewState(16)
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
st: mockState, st: mockState,
@ -1858,7 +1858,7 @@ func TestVerifyNewPin(t *testing.T) {
flag_valid_pin, _ := fm.parser.GetFlag("flag_valid_pin") flag_valid_pin, _ := fm.parser.GetFlag("flag_valid_pin")
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
h := &Handlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm.parser,
accountService: mockAccountService, accountService: mockAccountService,
} }
@ -1904,7 +1904,7 @@ func TestConfirmPin(t *testing.T) {
fm, _ := NewFlagManager(flagsPath) fm, _ := NewFlagManager(flagsPath)
flag_pin_mismatch, _ := fm.parser.GetFlag("flag_pin_mismatch") flag_pin_mismatch, _ := fm.parser.GetFlag("flag_pin_mismatch")
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
flagManager: fm.parser, flagManager: fm.parser,
accountService: mockAccountService, accountService: mockAccountService,
@ -1968,7 +1968,7 @@ func TestFetchCommunityBalance(t *testing.T) {
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
mockState := state.NewState(16) mockState := state.NewState(16)
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
st: mockState, st: mockState,
accountService: mockAccountService, accountService: mockAccountService,
@ -2033,7 +2033,7 @@ func TestSetDefaultVoucher(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm.parser,
@ -2066,7 +2066,7 @@ func TestCheckVouchers(t *testing.T) {
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
spdb := InitializeTestSubPrefixDb(t, ctx) spdb := InitializeTestSubPrefixDb(t, ctx)
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
prefixDb: spdb, prefixDb: spdb,
@ -2108,8 +2108,8 @@ func TestGetVoucherList(t *testing.T) {
spdb := InitializeTestSubPrefixDb(t, ctx) spdb := InitializeTestSubPrefixDb(t, ctx)
// Initialize Handlers // Initialize MenuHandlers
h := &Handlers{ h := &MenuHandlers{
prefixDb: spdb, prefixDb: spdb,
ReplaceSeparatorFunc: mockReplaceSeparator, ReplaceSeparatorFunc: mockReplaceSeparator,
} }
@ -2142,7 +2142,7 @@ func TestViewVoucher(t *testing.T) {
spdb := InitializeTestSubPrefixDb(t, ctx) spdb := InitializeTestSubPrefixDb(t, ctx)
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
flagManager: fm.parser, flagManager: fm.parser,
prefixDb: spdb, prefixDb: spdb,
@ -2175,7 +2175,7 @@ func TestSetVoucher(t *testing.T) {
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
} }
@ -2215,7 +2215,7 @@ func TestGetVoucherDetails(t *testing.T) {
tokA_AAddress := "0x0000000000000000000000000000000000000000" tokA_AAddress := "0x0000000000000000000000000000000000000000"
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
flagManager: fm.parser, flagManager: fm.parser,
accountService: mockAccountService, accountService: mockAccountService,
@ -2246,7 +2246,7 @@ func TestCountIncorrectPINAttempts(t *testing.T) {
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
attempts := uint8(2) attempts := uint8(2)
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
} }
err := store.WriteEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS, []byte(strconv.Itoa(int(attempts)))) err := store.WriteEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS, []byte(strconv.Itoa(int(attempts))))
@ -2279,7 +2279,7 @@ func TestResetIncorrectPINAttempts(t *testing.T) {
t.Logf(err.Error()) t.Logf(err.Error())
} }
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
} }
h.resetIncorrectPINAttempts(ctx, sessionId) h.resetIncorrectPINAttempts(ctx, sessionId)
@ -2298,7 +2298,7 @@ func TestPersistLanguageCode(t *testing.T) {
sessionId := "session123" sessionId := "session123"
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
h := &Handlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
} }
tests := []struct { tests := []struct {

View File

@ -16,7 +16,7 @@ import (
) )
type HandlerService interface { type HandlerService interface {
GetHandler() (*application.Handlers, error) GetHandler() (*application.MenuHandlers, error)
} }
func getParser(fp string, debug bool) (*asm.FlagParser, error) { func getParser(fp string, debug bool) (*asm.FlagParser, error) {
@ -64,16 +64,17 @@ func (ls *LocalHandlerService) SetDataStore(db *db.Db) {
ls.UserdataStore = db ls.UserdataStore = db
} }
func (ls *LocalHandlerService) GetHandler(accountService remote.AccountServiceInterface) (*application.Handlers, error) { func (ls *LocalHandlerService) GetHandler(accountService remote.AccountServiceInterface) (*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.NewHandlers(ls.Parser, *ls.UserdataStore, ls.AdminStore, accountService, replaceSeparatorFunc) appHandlers, err := application.NewMenuHandlers(ls.Parser, *ls.UserdataStore, ls.AdminStore, accountService, replaceSeparatorFunc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
appHandlers = appHandlers.WithPersister(ls.Pe) //appHandlers = appHandlers.WithPersister(ls.Pe)
appHandlers.SetPersister(ls.Pe)
ls.DbRs.AddLocalFunc("set_language", appHandlers.SetLanguage) ls.DbRs.AddLocalFunc("set_language", appHandlers.SetLanguage)
ls.DbRs.AddLocalFunc("create_account", appHandlers.CreateAccount) ls.DbRs.AddLocalFunc("create_account", appHandlers.CreateAccount)
ls.DbRs.AddLocalFunc("save_temporary_pin", appHandlers.SaveTemporaryPin) ls.DbRs.AddLocalFunc("save_temporary_pin", appHandlers.SaveTemporaryPin)

View File

@ -0,0 +1,23 @@
# Variables to match files in the current directory
INPUTS = $(wildcard ./*.vis)
TXTS = $(wildcard ./*.txt.orig)
VISE_PATH := ../../go-vise
# Rule to build .bin files from .vis files
%.vis:
go run $(VISE_PATH)/dev/asm/main.go -f pp.csv $(basename $@).vis > $(basename $@).bin
@echo "Built $(basename $@).bin from $(basename $@).vis"
# Rule to copy .orig files to .txt
%.txt.orig:
cp -v $(basename $@).orig $(basename $@)
@echo "Copied $(basename $@).orig to $(basename $@)"
# 'all' target depends on all .vis and .txt.orig files
all: $(INPUTS) $(TXTS)
@echo "Running all: $(INPUTS) $(TXTS)"
clean:
rm -vf *.bin
.PHONY: clean

View File

@ -0,0 +1 @@
Something went wrong.Please try again

Binary file not shown.

View File

@ -0,0 +1 @@
HALT

View File

@ -0,0 +1 @@
Tatizo la kimtambo limetokea,tafadhali jaribu tena baadaye.

View File

@ -0,0 +1 @@
Your account is being created...

Binary file not shown.

View File

@ -0,0 +1,4 @@
RELOAD verify_create_pin
CATCH create_pin_mismatch flag_pin_mismatch 1
LOAD quit 0
HALT

View File

@ -0,0 +1 @@
Your account creation request failed. Please try again later.

Binary file not shown.

View File

@ -0,0 +1,3 @@
MOUT quit 9
HALT
INCMP quit 9

View File

@ -0,0 +1 @@
Ombi lako la kusajiliwa haliwezi kukamilishwa. Tafadhali jaribu tena baadaye.

View File

@ -0,0 +1 @@
Akaunti yako inatengenezwa...

View File

@ -0,0 +1 @@
My Account

View File

@ -0,0 +1 @@
Akaunti yangu

View File

@ -0,0 +1 @@
Your account is still being created.

Binary file not shown.

View File

@ -0,0 +1,3 @@
RELOAD check_account_status
CATCH main flag_account_success 1
HALT

View File

@ -0,0 +1 @@
Akaunti yako bado inatengenezwa

View File

@ -0,0 +1 @@
Address: {{.check_identifier}}

Binary file not shown.

View File

@ -0,0 +1,8 @@
LOAD check_identifier 0
RELOAD check_identifier
MAP check_identifier
MOUT back 0
MOUT quit 9
HALT
INCMP _ 0
INCMP quit 9

View File

@ -0,0 +1 @@
Anwani:{{.check_identifier}}

View File

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

Binary file not shown.

View File

@ -0,0 +1,15 @@
LOAD reset_transaction_amount 0
LOAD max_amount 10
RELOAD max_amount
MAP max_amount
MOUT back 0
HALT
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,2 @@
Kiwango cha juu: {{.max_amount}}
Weka kiwango:

View File

@ -0,0 +1 @@
Failed to connect to the custodial service.Please try again.

Binary file not shown.

View File

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

View File

@ -0,0 +1 @@
Back

View File

@ -0,0 +1 @@
Rudi

View File

@ -0,0 +1 @@
Balances:

Binary file not shown.

View File

@ -0,0 +1,10 @@
LOAD reset_account_authorized 0
RELOAD reset_account_authorized
MOUT my_balance 1
MOUT community_balance 2
MOUT back 0
HALT
INCMP _ 0
INCMP my_balance 1
INCMP community_balance 2
INCMP . *

View File

@ -0,0 +1 @@
Salio:

Binary file not shown.

View File

@ -0,0 +1,2 @@
LOAD show_blocked_account 0
HALT

View File

@ -0,0 +1 @@
Select language:

Binary file not shown.

View File

@ -0,0 +1,10 @@
LOAD reset_account_authorized 0
LOAD reset_incorrect 0
CATCH incorrect_pin flag_incorrect_pin 1
CATCH pin_entry flag_account_authorized 0
MOUT english 1
MOUT kiswahili 2
HALT
INCMP set_eng 1
INCMP set_swa 2
INCMP . *

View File

@ -0,0 +1 @@
Change language

View File

@ -0,0 +1 @@
Badili lugha

View File

@ -0,0 +1 @@
Chagua lugha:

View File

@ -0,0 +1 @@
Change PIN

View File

@ -0,0 +1 @@
Badili PIN

View File

@ -0,0 +1 @@
Check balances

View File

@ -0,0 +1 @@
Angalia salio

View File

@ -0,0 +1 @@
Please enter your PIN to view statement:

Binary file not shown.

View File

@ -0,0 +1,12 @@
LOAD check_transactions 0
RELOAD check_transactions
CATCH no_transfers flag_no_transfers 1
LOAD authorize_account 6
MOUT back 0
MOUT quit 9
HALT
RELOAD authorize_account
CATCH incorrect_pin flag_incorrect_pin 1
INCMP _ 0
INCMP quit 9
INCMP transactions *

View File

@ -0,0 +1 @@
Check statement

View File

@ -0,0 +1 @@
Taarifa ya matumizi

View File

@ -0,0 +1 @@
Tafadhali weka PIN yako kuona taarifa ya matumizi:

View File

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

View File

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

Binary file not shown.

View File

@ -0,0 +1,12 @@
LOAD reset_incorrect 6
LOAD fetch_community_balance 0
CATCH api_failure flag_api_call_error 1
MAP fetch_community_balance
CATCH incorrect_pin flag_incorrect_pin 1
CATCH pin_entry flag_account_authorized 0
MOUT back 0
MOUT quit 9
HALT
INCMP _ 0
INCMP quit 9
INCMP . *

View File

@ -0,0 +1 @@
Community balance

View File

@ -0,0 +1 @@
Salio la kikundi

View File

@ -0,0 +1 @@
Enter your four number PIN again:

Binary file not shown.

View File

@ -0,0 +1,4 @@
LOAD save_temporary_pin 6
HALT
LOAD verify_create_pin 8
INCMP account_creation *

View File

@ -0,0 +1 @@
Weka PIN yako tena:

View File

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

Binary file not shown.

View File

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

View File

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

View File

@ -0,0 +1 @@
Confirm your new PIN:

Binary file not shown.

View File

@ -0,0 +1,5 @@
CATCH invalid_pin flag_valid_pin 0
MOUT back 0
HALT
INCMP _ 0
INCMP * pin_reset_success

View File

@ -0,0 +1 @@
Thibitisha PIN yako mpya:

View File

@ -0,0 +1 @@
Please enter a new four number PIN for your account:

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

View File

@ -0,0 +1 @@
Tafadhali weka PIN mpya yenye nambari nne kwa akaunti yako:

View File

@ -0,0 +1,5 @@
Wasifu wangu
Name: Not provided
Gender: Not provided
Age: Not provided
Location: Not provided

Binary file not shown.

View File

@ -0,0 +1,3 @@
MOUT back 0
HALT
INCMP _ 0

View File

@ -0,0 +1,2 @@
Current family name: {{.get_current_profile_info}}
Enter family name:

Binary file not shown.

View File

@ -0,0 +1,18 @@
CATCH incorrect_pin flag_incorrect_pin 1
CATCH update_familyname flag_allow_update 1
LOAD get_current_profile_info 0
RELOAD get_current_profile_info
MAP get_current_profile_info
MOUT back 0
HALT
RELOAD set_back
CATCH _ flag_back_set 1
LOAD save_familyname 64
RELOAD save_familyname
CATCH pin_entry flag_familyname_set 1
CATCH select_gender flag_gender_set 0
CATCH edit_yob flag_yob_set 0
CATCH edit_location flag_location_set 0
CATCH edit_offerings flag_offerings_set 0
CATCH pin_entry flag_familyname_set 0
INCMP select_gender *

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