diff --git a/devtools/admin/admin_numbers.json b/cmd/admin/admin_numbers.json similarity index 100% rename from devtools/admin/admin_numbers.json rename to cmd/admin/admin_numbers.json diff --git a/devtools/admin/commands/seed.go b/cmd/admin/commands/seed.go similarity index 93% rename from devtools/admin/commands/seed.go rename to cmd/admin/commands/seed.go index e76c83d..41d105a 100644 --- a/devtools/admin/commands/seed.go +++ b/cmd/admin/commands/seed.go @@ -6,7 +6,7 @@ import ( "os" "git.defalsify.org/vise.git/logging" - "git.grassecon.net/urdt/ussd/internal/utils" + "git.grassecon.net/grassrootseconomics/visedriver/utils" ) var ( diff --git a/devtools/admin/main.go b/cmd/admin/main.go similarity index 74% rename from devtools/admin/main.go rename to cmd/admin/main.go index 9a527f3..40c1247 100644 --- a/devtools/admin/main.go +++ b/cmd/admin/main.go @@ -4,7 +4,7 @@ import ( "context" "log" - "git.grassecon.net/urdt/ussd/devtools/admin/commands" + "git.grassecon.net/grassrootseconomics/visedriver/cmd/admin/commands" ) func main() { diff --git a/cmd/africastalking/main.go b/cmd/africastalking/main.go deleted file mode 100644 index 24812a1..0000000 --- a/cmd/africastalking/main.go +++ /dev/null @@ -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/urdt/ussd/config" - "git.grassecon.net/urdt/ussd/initializers" - "git.grassecon.net/urdt/ussd/internal/args" - "git.grassecon.net/urdt/ussd/internal/handlers" - "git.grassecon.net/urdt/ussd/internal/http/at" - "git.grassecon.net/urdt/ussd/internal/storage" - "git.grassecon.net/urdt/ussd/remote" -) - -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 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", "build", build, "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) - 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 := handlers.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) - } -} diff --git a/cmd/async/main.go b/cmd/async/main.go deleted file mode 100644 index 27db453..0000000 --- a/cmd/async/main.go +++ /dev/null @@ -1,197 +0,0 @@ -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/urdt/ussd/config" - "git.grassecon.net/urdt/ussd/initializers" - "git.grassecon.net/urdt/ussd/internal/args" - "git.grassecon.net/urdt/ussd/internal/handlers" - "git.grassecon.net/urdt/ussd/internal/storage" - "git.grassecon.net/urdt/ussd/remote" -) - -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 := handlers.NewBaseSessionHandler(cfg, rs, stateStore, userdataStore, rp, hl) - cfg.SessionId = sessionId - rqs := handlers.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) - } - } -} diff --git a/cmd/http/main.go b/cmd/http/main.go deleted file mode 100644 index 6617ca5..0000000 --- a/cmd/http/main.go +++ /dev/null @@ -1,160 +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/urdt/ussd/config" - "git.grassecon.net/urdt/ussd/initializers" - "git.grassecon.net/urdt/ussd/internal/args" - "git.grassecon.net/urdt/ussd/internal/handlers" - httpserver "git.grassecon.net/urdt/ussd/internal/http" - "git.grassecon.net/urdt/ussd/internal/storage" - "git.grassecon.net/urdt/ussd/remote" -) - -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 := &httpserver.DefaultRequestParser{} - bsh := handlers.NewBaseSessionHandler(cfg, rs, stateStore, userdataStore, rp, hl) - sh := httpserver.ToSessionHandler(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) - } -} diff --git a/devtools/lang/main.go b/cmd/lang/main.go similarity index 95% rename from devtools/lang/main.go rename to cmd/lang/main.go index 83c68b3..b82771b 100644 --- a/devtools/lang/main.go +++ b/cmd/lang/main.go @@ -10,8 +10,8 @@ import ( "git.defalsify.org/vise.git/logging" "git.defalsify.org/vise.git/lang" - "git.grassecon.net/urdt/ussd/config" - "git.grassecon.net/urdt/ussd/initializers" + "git.grassecon.net/grassrootseconomics/visedriver/config" + "git.grassecon.net/grassrootseconomics/visedriver/initializers" ) const ( diff --git a/cmd/main.go b/cmd/main.go deleted file mode 100644 index d2fe0ba..0000000 --- a/cmd/main.go +++ /dev/null @@ -1,146 +0,0 @@ -package main - -import ( - "context" - "flag" - "fmt" - "os" - "path" - - "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/urdt/ussd/config" - "git.grassecon.net/urdt/ussd/initializers" - "git.grassecon.net/urdt/ussd/internal/args" - "git.grassecon.net/urdt/ussd/internal/handlers" - "git.grassecon.net/urdt/ussd/internal/storage" - "git.grassecon.net/urdt/ussd/remote" -) - -var ( - logg = logging.NewVanilla() - scriptDir = path.Join("services", "registration") - menuSeparator = ": " -) - -func init() { - initializers.LoadEnvVariables() -} - -// TODO: external script automatically generate language handler list from select language vise code OR consider dynamic menu generation script possibility -func main() { - config.LoadConfig() - - var connStr string - var size uint - var sessionId string - var engineDebug bool - var resourceDir string - var err error - var gettextDir string - var langs args.LangVar - - flag.StringVar(&resourceDir, "resourcedir", scriptDir, "resource dir") - flag.StringVar(&sessionId, "session-id", "075xx2123", "session id") - flag.StringVar(&connStr, "c", "", "connection string") - flag.BoolVar(&engineDebug, "d", false, "use engine debug output") - flag.UintVar(&size, "s", 160, "max size of output") - flag.StringVar(&gettextDir, "gettext", "", "use gettext translations from given directory") - flag.Var(&langs, "language", "add symbol resolution for language") - flag.Parse() - - if connStr == "" { - connStr = config.DbConn - } - connData, err := storage.ToConnData(connStr) - if err != nil { - fmt.Fprintf(os.Stderr, "connstr err: %v", err) - os.Exit(1) - } - - logg.Infof("start command", "conn", connData, "outputsize", size) - - if len(langs.Langs()) == 0 { - langs.Set(config.DefaultLanguage) - } - - ctx := context.Background() - ctx = context.WithValue(ctx, "SessionId", sessionId) - - 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", - SessionId: sessionId, - OutputSize: uint32(size), - FlagCount: uint32(128), - MenuSeparator: menuSeparator, - } - - menuStorageService := storage.NewMenuStorageService(connData, resourceDir) - - if gettextDir != "" { - menuStorageService = menuStorageService.WithGettext(gettextDir, langs.Langs()) - } - - rs, err := menuStorageService.GetResource(ctx) - if err != nil { - fmt.Fprintf(os.Stderr, err.Error()) - os.Exit(1) - } - - pe, err := menuStorageService.GetPersister(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) - } - - dbResource, ok := rs.(*resource.DbResource) - if !ok { - fmt.Fprintf(os.Stderr, err.Error()) - os.Exit(1) - } - - lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs) - lhs.SetDataStore(&userdatastore) - lhs.SetPersister(pe) - - 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) - } - - en := lhs.GetEngine() - en = en.WithFirst(hl.Init) - if engineDebug { - en = en.WithDebug(nil) - } - - err = engine.Loop(ctx, en, os.Stdin, os.Stdout, nil) - if err != nil { - fmt.Fprintf(os.Stderr, "loop exited with error: %v\n", err) - os.Exit(1) - } -} diff --git a/cmd/ssh/README.md b/cmd/ssh/README.md deleted file mode 100644 index ff325d7..0000000 --- a/cmd/ssh/README.md +++ /dev/null @@ -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 [--dbdir ] -``` - - -## Create a private key for the server - -``` -ssh-keygen -N "" -f -``` - - -## Run the server - - -``` -go run -v -tags logtrace ./cmd/ssh/main.go -h -p [--dbdir ] -``` - - -## Connect to the server - -``` -ssh [-v] -T -p -i -``` diff --git a/cmd/ssh/main.go b/cmd/ssh/main.go deleted file mode 100644 index 51023e5..0000000 --- a/cmd/ssh/main.go +++ /dev/null @@ -1,144 +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/urdt/ussd/config" - "git.grassecon.net/urdt/ussd/initializers" - "git.grassecon.net/urdt/ussd/internal/ssh" - "git.grassecon.net/urdt/ussd/internal/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) -} diff --git a/cmd/ssh/sshkey/main.go b/cmd/ssh/sshkey/main.go deleted file mode 100644 index 87b89a3..0000000 --- a/cmd/ssh/sshkey/main.go +++ /dev/null @@ -1,44 +0,0 @@ -package main - -import ( - "context" - "flag" - "fmt" - "os" - - "git.grassecon.net/urdt/ussd/internal/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) - } -} diff --git a/devtools/store/dump/main.go b/cmd/store/dump/main.go similarity index 88% rename from devtools/store/dump/main.go rename to cmd/store/dump/main.go index c84a134..b28170c 100644 --- a/devtools/store/dump/main.go +++ b/cmd/store/dump/main.go @@ -7,10 +7,10 @@ import ( "os" "path" - "git.grassecon.net/urdt/ussd/config" - "git.grassecon.net/urdt/ussd/initializers" - "git.grassecon.net/urdt/ussd/internal/storage" - "git.grassecon.net/urdt/ussd/debug" + "git.grassecon.net/grassrootseconomics/visedriver/config" + "git.grassecon.net/grassrootseconomics/visedriver/initializers" + "git.grassecon.net/grassrootseconomics/visedriver/storage" + "git.grassecon.net/grassrootseconomics/visedriver/debug" "git.defalsify.org/vise.git/db" "git.defalsify.org/vise.git/logging" ) diff --git a/devtools/store/generate/main.go b/cmd/store/generate/main.go similarity index 88% rename from devtools/store/generate/main.go rename to cmd/store/generate/main.go index c421d1a..a1b9a84 100644 --- a/devtools/store/generate/main.go +++ b/cmd/store/generate/main.go @@ -8,12 +8,12 @@ import ( "os" "path" - "git.defalsify.org/vise.git/logging" - "git.grassecon.net/urdt/ussd/common" - "git.grassecon.net/urdt/ussd/config" - "git.grassecon.net/urdt/ussd/initializers" - "git.grassecon.net/urdt/ussd/internal/storage" testdataloader "github.com/peteole/testdata-loader" + "git.defalsify.org/vise.git/logging" + "git.grassecon.net/grassrootseconomics/visedriver/config" + "git.grassecon.net/grassrootseconomics/visedriver/storage" + "git.grassecon.net/grassrootseconomics/visedriver/initializers" + "git.grassecon.net/grassrootseconomics/visedriver/common" ) var ( diff --git a/common/storage.go b/common/storage.go index 2960578..4887d0f 100644 --- a/common/storage.go +++ b/common/storage.go @@ -7,8 +7,13 @@ import ( "git.defalsify.org/vise.git/db" "git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/persist" - "git.grassecon.net/urdt/ussd/internal/storage" - dbstorage "git.grassecon.net/urdt/ussd/internal/storage/db" + "git.defalsify.org/vise.git/lang" + "git.grassecon.net/grassrootseconomics/visedriver/storage" + dbstorage "git.grassecon.net/grassrootseconomics/visedriver/storage/db" +) + +var ( + ToConnData = storage.ToConnData ) func StoreToDb(store *UserDataStore) db.Db { @@ -36,6 +41,17 @@ func NewStorageService(conn storage.ConnData) (*StorageService, error) { return svc, nil } +func (ss *StorageService) WithGettext(path string, lns []lang.Language) *StorageService { + ss.svc = ss.svc.WithGettext(path, lns) + return ss +} + +// TODO: simplify enable poresource, conndata instead +func(ss *StorageService) SetResourceDir(resourceDir string) error { + ss.svc = ss.svc.WithResourceDir(resourceDir) + return nil +} + func(ss *StorageService) GetPersister(ctx context.Context) (*persist.Persister, error) { return ss.svc.GetPersister(ctx) } @@ -47,3 +63,7 @@ func(ss *StorageService) GetUserdataDb(ctx context.Context) (db.Db, error) { func(ss *StorageService) GetResource(ctx context.Context) (resource.Resource, error) { return nil, errors.New("not implemented") } + +func(ss *StorageService) GetStateStore(ctx context.Context) (db.Db, error) { + return ss.svc.GetStateStore(ctx) +} diff --git a/common/transfer_statements.go b/common/transfer_statements.go index e97437f..1f2ff42 100644 --- a/common/transfer_statements.go +++ b/common/transfer_statements.go @@ -6,7 +6,7 @@ import ( "strings" "time" - dbstorage "git.grassecon.net/urdt/ussd/internal/storage/db" + dbstorage "git.grassecon.net/grassrootseconomics/visedriver/storage/db" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" ) diff --git a/common/vouchers.go b/common/vouchers.go index 5dbdb71..cab32d0 100644 --- a/common/vouchers.go +++ b/common/vouchers.go @@ -6,7 +6,7 @@ import ( "math/big" "strings" - dbstorage "git.grassecon.net/urdt/ussd/internal/storage/db" + dbstorage "git.grassecon.net/grassrootseconomics/visedriver/storage/db" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" ) diff --git a/common/vouchers_test.go b/common/vouchers_test.go index 8b04e4a..89510ac 100644 --- a/common/vouchers_test.go +++ b/common/vouchers_test.go @@ -10,7 +10,7 @@ import ( visedb "git.defalsify.org/vise.git/db" memdb "git.defalsify.org/vise.git/db/mem" - dbstorage "git.grassecon.net/urdt/ussd/internal/storage/db" + dbstorage "git.grassecon.net/grassrootseconomics/visedriver/storage/db" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" ) diff --git a/config/config.go b/config/config.go index 4b43b42..7c17cef 100644 --- a/config/config.go +++ b/config/config.go @@ -4,7 +4,7 @@ import ( "net/url" "strings" - "git.grassecon.net/urdt/ussd/initializers" + "git.grassecon.net/grassrootseconomics/visedriver/initializers" ) const ( diff --git a/debug/db.go b/debug/db.go index ec9e58f..85efd1a 100644 --- a/debug/db.go +++ b/debug/db.go @@ -4,7 +4,7 @@ import ( "fmt" "encoding/binary" - "git.grassecon.net/urdt/ussd/common" + "git.grassecon.net/grassrootseconomics/visedriver/common" "git.defalsify.org/vise.git/db" ) diff --git a/debug/db_debug.go b/debug/db_debug.go index 05a238b..0ce276e 100644 --- a/debug/db_debug.go +++ b/debug/db_debug.go @@ -5,7 +5,7 @@ package debug import ( "git.defalsify.org/vise.git/db" - "git.grassecon.net/urdt/ussd/common" + "git.grassecon.net/grassrootseconomics/visedriver/common" ) func init() { diff --git a/debug/db_test.go b/debug/db_test.go index 25f781d..d55d47c 100644 --- a/debug/db_test.go +++ b/debug/db_test.go @@ -3,7 +3,7 @@ package debug import ( "testing" - "git.grassecon.net/urdt/ussd/common" + "git.grassecon.net/grassrootseconomics/visedriver/common" "git.defalsify.org/vise.git/db" ) diff --git a/entry/handlers.go b/entry/handlers.go new file mode 100644 index 0000000..ef85be4 --- /dev/null +++ b/entry/handlers.go @@ -0,0 +1,13 @@ +package entry + +import ( + "context" + "git.defalsify.org/vise.git/resource" + "git.defalsify.org/vise.git/persist" +) + +type EntryHandler interface { + Init(context.Context, string, []byte) (resource.Result, error) // HandlerFunc + Exit() + SetPersister(*persist.Persister) +} diff --git a/errors/errors.go b/errors/errors.go new file mode 100644 index 0000000..40974b1 --- /dev/null +++ b/errors/errors.go @@ -0,0 +1,15 @@ +package errors + +import ( + "git.grassecon.net/grassrootseconomics/visedriver/internal/handlers" +) + +var ( + ErrInvalidRequest = handlers.ErrInvalidRequest + ErrSessionMissing = handlers.ErrSessionMissing + ErrInvalidInput = handlers.ErrInvalidInput + ErrStorage = handlers.ErrStorage + ErrEngineType = handlers.ErrEngineType + ErrEngineInit = handlers.ErrEngineInit + ErrEngineExec = handlers.ErrEngineExec +) diff --git a/go.mod b/go.mod index 41c6700..b121a0d 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module git.grassecon.net/urdt/ussd +module git.grassecon.net/grassrootseconomics/visedriver go 1.23.0 @@ -8,15 +8,14 @@ require ( github.com/gofrs/uuid v4.4.0+incompatible github.com/grassrootseconomics/eth-custodial v1.3.0-beta github.com/grassrootseconomics/ussd-data-service v1.2.0-beta + github.com/jackc/pgx/v5 v5.7.1 github.com/joho/godotenv v1.5.1 github.com/peteole/testdata-loader v0.3.0 github.com/stretchr/testify v1.9.0 golang.org/x/crypto v0.27.0 - gopkg.in/leonelquinteros/gotext.v1 v1.3.1 ) require ( - github.com/alecthomas/participle/v2 v2.0.0 // indirect github.com/alecthomas/repr v0.2.0 // indirect github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -25,7 +24,6 @@ require ( github.com/hexops/gotextdiff v1.0.3 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect - github.com/jackc/pgx/v5 v5.7.1 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/kr/text v0.2.0 // indirect github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a // indirect @@ -34,6 +32,8 @@ require ( github.com/stretchr/objx v0.5.2 // indirect github.com/x448/float16 v0.8.4 // indirect golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.25.0 // indirect golang.org/x/text v0.18.0 // indirect + gopkg.in/leonelquinteros/gotext.v1 v1.3.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 6bef621..0456122 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,6 @@ git.defalsify.org/vise.git v0.2.3-0.20250103172917-3e190a44568d h1:bPAOVZOX4frSG git.defalsify.org/vise.git v0.2.3-0.20250103172917-3e190a44568d/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck= github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk= github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= -github.com/alecthomas/participle/v2 v2.0.0 h1:Fgrq+MbuSsJwIkw3fEj9h75vDP0Er5JzepJ0/HNHv0g= -github.com/alecthomas/participle/v2 v2.0.0/go.mod h1:rAKZdJldHu8084ojcWevWAL8KmEU+AT+Olodb+WoN2Y= github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk= github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c h1:H9Nm+I7Cg/YVPpEV1RzU3Wq2pjamPc/UtHDgItcb7lE= @@ -62,6 +60,10 @@ golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/args/lang.go b/internal/args/lang.go deleted file mode 100644 index f9afdc9..0000000 --- a/internal/args/lang.go +++ /dev/null @@ -1,34 +0,0 @@ -package args - -import ( - "strings" - - "git.defalsify.org/vise.git/lang" -) - -type LangVar struct { - v []lang.Language -} - -func(lv *LangVar) Set(s string) error { - v, err := lang.LanguageFromCode(s) - if err != nil { - return err - } - lv.v = append(lv.v, v) - return err -} - -func(lv *LangVar) String() string { - var s []string - for _, v := range(lv.v) { - s = append(s, v.Code) - } - return strings.Join(s, ",") -} - -func(lv *LangVar) Langs() []lang.Language { - return lv.v -} - - diff --git a/internal/handlers/application/menu_handler.go b/internal/handlers/application/menu_handler.go deleted file mode 100644 index 193f7fe..0000000 --- a/internal/handlers/application/menu_handler.go +++ /dev/null @@ -1,2193 +0,0 @@ -package application - -import ( - "bytes" - "context" - "fmt" - "path" - "strconv" - "strings" - - "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/urdt/ussd/common" - "git.grassecon.net/urdt/ussd/internal/utils" - "git.grassecon.net/urdt/ussd/models" - "git.grassecon.net/urdt/ussd/remote" - "gopkg.in/leonelquinteros/gotext.v1" - - dbstorage "git.grassecon.net/urdt/ussd/internal/storage/db" - dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" -) - -var ( - logg = logging.NewVanilla().WithDomain("ussdmenuhandler").WithContextKey("SessionId") - scriptDir = path.Join("services", "registration") - translationDir = path.Join(scriptDir, "locale") -) - -// FlagManager handles centralized flag management -type FlagManager struct { - parser *asm.FlagParser -} - -// NewFlagManager creates a new FlagManager instance -func NewFlagManager(csvPath string) (*FlagManager, error) { - parser := asm.NewFlagParser() - _, err := parser.Load(csvPath) - if err != nil { - return nil, fmt.Errorf("failed to load flag parser: %v", err) - } - - return &FlagManager{ - parser: parser, - }, nil -} - -// GetFlag retrieves a flag value by its label -func (fm *FlagManager) GetFlag(label string) (uint32, error) { - return fm.parser.GetFlag(label) -} - -type Handlers struct { - pe *persist.Persister - 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 NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db, adminstore *utils.AdminStore, accountService remote.AccountServiceInterface, replaceSeparatorFunc func(string) string) (*Handlers, 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 := &Handlers{ - 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 *Handlers) WithPersister(pe *persist.Persister) *Handlers { - if h.pe != nil { - panic("persister already set") - } - h.pe = pe - return h -} - -// Init initializes the handler for a new session. -func (h *Handlers) Init(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var r resource.Result - if h.pe == nil { - logg.WarnCtxf(ctx, "handler init called before it is ready or more than once", "state", h.st, "cache", h.ca) - return r, nil - } - defer func() { - h.Exit() - }() - - h.st = h.pe.GetState() - h.ca = h.pe.GetMemory() - - if len(input) == 0 { - // move to the top node - h.st.Code = []byte{} - } - - sessionId, ok := ctx.Value("SessionId").(string) - if ok { - ctx = context.WithValue(ctx, "SessionId", sessionId) - } - - flag_admin_privilege, _ := h.flagManager.GetFlag("flag_admin_privilege") - isAdmin, _ := h.adminstore.IsAdmin(sessionId) - - if isAdmin { - r.FlagSet = append(r.FlagSet, flag_admin_privilege) - } else { - r.FlagReset = append(r.FlagReset, flag_admin_privilege) - } - - if h.st == nil || h.ca == nil { - logg.ErrorCtxf(ctx, "perister fail in handler", "state", h.st, "cache", h.ca) - return r, fmt.Errorf("cannot get state and memory for handler") - } - - logg.DebugCtxf(ctx, "handler has been initialized", "state", h.st, "cache", h.ca) - - return r, nil -} - -func (h *Handlers) Exit() { - h.pe = nil -} - -// SetLanguage sets the language across the menu. -func (h *Handlers) SetLanguage(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - - symbol, _ := h.st.Where() - code := strings.Split(symbol, "_")[1] - - if !utils.IsValidISO639(code) { - //Fallback to english instead? - code = "eng" - } - err := h.persistLanguageCode(ctx, code) - if err != nil { - return res, err - } - res.Content = code - res.FlagSet = append(res.FlagSet, state.FLAG_LANG) - languageSetFlag, err := h.flagManager.GetFlag("flag_language_set") - if err != nil { - logg.ErrorCtxf(ctx, "Error setting the languageSetFlag", "error", err) - return res, err - } - res.FlagSet = append(res.FlagSet, languageSetFlag) - - return res, nil -} - -// handles the account creation when no existing account is present for the session and stores associated data in the user data store. -func (h *Handlers) createAccountNoExist(ctx context.Context, sessionId string, res *resource.Result) error { - flag_account_created, _ := h.flagManager.GetFlag("flag_account_created") - r, err := h.accountService.CreateAccount(ctx) - if err != nil { - return err - } - trackingId := r.TrackingId - publicKey := r.PublicKey - - data := map[common.DataTyp]string{ - common.DATA_TRACKING_ID: trackingId, - common.DATA_PUBLIC_KEY: publicKey, - } - store := h.userdataStore - for key, value := range data { - err = store.WriteEntry(ctx, sessionId, key, []byte(value)) - if err != nil { - return err - } - } - publicKeyNormalized, err := common.NormalizeHex(publicKey) - if err != nil { - return err - } - err = store.WriteEntry(ctx, publicKeyNormalized, common.DATA_PUBLIC_KEY_REVERSE, []byte(sessionId)) - if err != nil { - return err - } - res.FlagSet = append(res.FlagSet, flag_account_created) - return nil -} - -// CreateAccount checks if any account exists on the JSON data file, and if not, -// creates an account on the API, -// sets the default values and flags. -func (h *Handlers) CreateAccount(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") - } - store := h.userdataStore - _, err = store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) - if err != nil { - if db.IsNotFound(err) { - logg.InfoCtxf(ctx, "Creating an account because it doesn't exist") - err = h.createAccountNoExist(ctx, sessionId, &res) - if err != nil { - logg.ErrorCtxf(ctx, "failed on createAccountNoExist", "error", err) - return res, err - } - } - } - - return res, nil -} - -// CheckBlockedNumPinMisMatch checks if the provided PIN matches a temporary PIN stored for a blocked number. -func (h *Handlers) CheckBlockedNumPinMisMatch(ctx context.Context, sym string, input []byte) (resource.Result, error) { - res := resource.Result{} - flag_pin_mismatch, _ := h.flagManager.GetFlag("flag_pin_mismatch") - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - // Get blocked number from storage. - store := h.userdataStore - blockedNumber, err := store.ReadEntry(ctx, sessionId, common.DATA_BLOCKED_NUMBER) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read blockedNumber entry with", "key", common.DATA_BLOCKED_NUMBER, "error", err) - return res, err - } - // Get temporary PIN for the blocked number. - temporaryPin, err := store.ReadEntry(ctx, string(blockedNumber), common.DATA_TEMPORARY_VALUE) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read temporaryPin entry with", "key", common.DATA_TEMPORARY_VALUE, "error", err) - return res, err - } - if bytes.Equal(temporaryPin, input) { - res.FlagReset = append(res.FlagReset, flag_pin_mismatch) - } else { - res.FlagSet = append(res.FlagSet, flag_pin_mismatch) - } - return res, nil -} - -// VerifyNewPin checks if a new PIN meets the required format criteria. -func (h *Handlers) VerifyNewPin(ctx context.Context, sym string, input []byte) (resource.Result, error) { - res := resource.Result{} - _, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - flag_valid_pin, _ := h.flagManager.GetFlag("flag_valid_pin") - pinInput := string(input) - // Validate that the PIN is a 4-digit number. - if common.IsValidPIN(pinInput) { - res.FlagSet = append(res.FlagSet, flag_valid_pin) - } else { - res.FlagReset = append(res.FlagReset, flag_valid_pin) - } - - return res, nil -} - -// SaveTemporaryPin saves the valid PIN input to the DATA_TEMPORARY_VALUE, -// during the account creation process -// and during the change PIN process. -func (h *Handlers) SaveTemporaryPin(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_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin") - accountPIN := string(input) - - // Validate that the PIN is a 4-digit number. - if !common.IsValidPIN(accountPIN) { - res.FlagSet = append(res.FlagSet, flag_incorrect_pin) - return res, nil - } - res.FlagReset = append(res.FlagReset, flag_incorrect_pin) - store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(accountPIN)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write temporaryAccountPIN entry with", "key", common.DATA_TEMPORARY_VALUE, "value", accountPIN, "error", err) - return res, err - } - - return res, nil -} - -// SaveOthersTemporaryPin allows authorized users to set temporary PINs for blocked numbers. -func (h *Handlers) SaveOthersTemporaryPin(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - var err error - - store := h.userdataStore - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - temporaryPin := string(input) - // First, we retrieve the blocked number associated with this session - blockedNumber, err := store.ReadEntry(ctx, sessionId, common.DATA_BLOCKED_NUMBER) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read blockedNumber entry with", "key", common.DATA_BLOCKED_NUMBER, "error", err) - return res, err - } - - // Then we save the temporary PIN for that blocked number - err = store.WriteEntry(ctx, string(blockedNumber), common.DATA_TEMPORARY_VALUE, []byte(temporaryPin)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write temporaryPin entry with", "key", common.DATA_TEMPORARY_VALUE, "value", temporaryPin, "error", err) - return res, err - } - - return res, nil -} - -// ConfirmPinChange validates user's new PIN. If input matches the temporary PIN, saves it as the new account PIN. -func (h *Handlers) ConfirmPinChange(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") - } - flag_pin_mismatch, _ := h.flagManager.GetFlag("flag_pin_mismatch") - - store := h.userdataStore - temporaryPin, err := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read temporaryPin entry with", "key", common.DATA_TEMPORARY_VALUE, "error", err) - return res, err - } - if bytes.Equal(temporaryPin, input) { - res.FlagReset = append(res.FlagReset, flag_pin_mismatch) - } else { - res.FlagSet = append(res.FlagSet, flag_pin_mismatch) - return res, nil - } - - // Hash the PIN - hashedPIN, err := common.HashPIN(string(temporaryPin)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to hash temporaryPin", "error", err) - return res, err - } - - // save the hashed PIN as the new account PIN - err = store.WriteEntry(ctx, sessionId, common.DATA_ACCOUNT_PIN, []byte(hashedPIN)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write DATA_ACCOUNT_PIN entry with", "key", common.DATA_ACCOUNT_PIN, "hashedPIN value", hashedPIN, "error", err) - return res, err - } - return res, nil -} - -// VerifyCreatePin checks whether the confirmation PIN is similar to the temporary PIN -// If similar, it sets the USERFLAG_PIN_SET flag and writes the account PIN allowing the user -// to access the main menu. -func (h *Handlers) VerifyCreatePin(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - - flag_valid_pin, _ := h.flagManager.GetFlag("flag_valid_pin") - flag_pin_mismatch, _ := h.flagManager.GetFlag("flag_pin_mismatch") - flag_pin_set, _ := h.flagManager.GetFlag("flag_pin_set") - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - store := h.userdataStore - temporaryPin, err := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read temporaryPin entry with", "key", common.DATA_TEMPORARY_VALUE, "error", err) - return res, err - } - if bytes.Equal(input, temporaryPin) { - res.FlagSet = []uint32{flag_valid_pin} - res.FlagReset = []uint32{flag_pin_mismatch} - res.FlagSet = append(res.FlagSet, flag_pin_set) - } else { - res.FlagSet = []uint32{flag_pin_mismatch} - return res, nil - } - - // Hash the PIN - hashedPIN, err := common.HashPIN(string(temporaryPin)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to hash temporaryPin", "error", err) - return res, err - } - - err = store.WriteEntry(ctx, sessionId, common.DATA_ACCOUNT_PIN, []byte(hashedPIN)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write DATA_ACCOUNT_PIN entry with", "key", common.DATA_ACCOUNT_PIN, "value", hashedPIN, "error", err) - return res, err - } - - return res, nil -} - -// retrieves language codes from the context that can be used for handling translations. -func codeFromCtx(ctx context.Context) string { - var code string - if ctx.Value("Language") != nil { - lang := ctx.Value("Language").(lang.Language) - code = lang.Code - } - return code -} - -// SaveFirstname updates the first name in the gdbm with the provided input. -func (h *Handlers) SaveFirstname(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") - } - firstName := string(input) - store := h.userdataStore - flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") - flag_firstname_set, _ := h.flagManager.GetFlag("flag_firstname_set") - - allowUpdate := h.st.MatchFlag(flag_allow_update, true) - firstNameSet := h.st.MatchFlag(flag_firstname_set, true) - if allowUpdate { - temporaryFirstName, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) - err = store.WriteEntry(ctx, sessionId, common.DATA_FIRST_NAME, []byte(temporaryFirstName)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write firstName entry with", "key", common.DATA_FIRST_NAME, "value", temporaryFirstName, "error", err) - return res, err - } - res.FlagSet = append(res.FlagSet, flag_firstname_set) - } else { - if firstNameSet { - err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(firstName)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write temporaryFirstName entry with", "key", common.DATA_TEMPORARY_VALUE, "value", firstName, "error", err) - return res, err - } - } else { - h.profile.InsertOrShift(0, firstName) - } - } - - return res, nil -} - -// SaveFamilyname updates the family name in the gdbm with the provided input. -func (h *Handlers) SaveFamilyname(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") - } - - store := h.userdataStore - familyName := string(input) - - flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") - flag_familyname_set, _ := h.flagManager.GetFlag("flag_familyname_set") - allowUpdate := h.st.MatchFlag(flag_allow_update, true) - familyNameSet := h.st.MatchFlag(flag_familyname_set, true) - - if allowUpdate { - temporaryFamilyName, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) - err = store.WriteEntry(ctx, sessionId, common.DATA_FAMILY_NAME, []byte(temporaryFamilyName)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write familyName entry with", "key", common.DATA_FAMILY_NAME, "value", temporaryFamilyName, "error", err) - return res, err - } - res.FlagSet = append(res.FlagSet, flag_familyname_set) - } else { - if familyNameSet { - err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(familyName)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write temporaryFamilyName entry with", "key", common.DATA_TEMPORARY_VALUE, "value", familyName, "error", err) - return res, err - } - } else { - h.profile.InsertOrShift(1, familyName) - } - } - - return res, nil -} - -// SaveYOB updates the Year of Birth(YOB) in the gdbm with the provided input. -func (h *Handlers) SaveYob(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") - } - yob := string(input) - store := h.userdataStore - flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") - flag_yob_set, _ := h.flagManager.GetFlag("flag_yob_set") - - allowUpdate := h.st.MatchFlag(flag_allow_update, true) - yobSet := h.st.MatchFlag(flag_yob_set, true) - - if allowUpdate { - temporaryYob, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) - err = store.WriteEntry(ctx, sessionId, common.DATA_YOB, []byte(temporaryYob)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write yob entry with", "key", common.DATA_TEMPORARY_VALUE, "value", temporaryYob, "error", err) - return res, err - } - res.FlagSet = append(res.FlagSet, flag_yob_set) - } else { - if yobSet { - err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(yob)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write temporaryYob entry with", "key", common.DATA_TEMPORARY_VALUE, "value", yob, "error", err) - return res, err - } - } else { - h.profile.InsertOrShift(3, yob) - } - } - - return res, nil -} - -// SaveLocation updates the location in the gdbm with the provided input. -func (h *Handlers) SaveLocation(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") - } - location := string(input) - store := h.userdataStore - - flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") - flag_location_set, _ := h.flagManager.GetFlag("flag_location_set") - allowUpdate := h.st.MatchFlag(flag_allow_update, true) - locationSet := h.st.MatchFlag(flag_location_set, true) - - if allowUpdate { - temporaryLocation, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) - err = store.WriteEntry(ctx, sessionId, common.DATA_LOCATION, []byte(temporaryLocation)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write location entry with", "key", common.DATA_LOCATION, "value", temporaryLocation, "error", err) - return res, err - } - res.FlagSet = append(res.FlagSet, flag_location_set) - } else { - if locationSet { - err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(location)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write temporaryLocation entry with", "key", common.DATA_TEMPORARY_VALUE, "value", location, "error", err) - return res, err - } - res.FlagSet = append(res.FlagSet, flag_location_set) - } else { - h.profile.InsertOrShift(4, location) - } - } - - return res, nil -} - -// SaveGender updates the gender in the gdbm with the provided input. -func (h *Handlers) SaveGender(ctx context.Context, sym string, input []byte) (resource.Result, error) { - symbol, _ := h.st.Where() - var res resource.Result - var err error - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - gender := strings.Split(symbol, "_")[1] - store := h.userdataStore - flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") - flag_gender_set, _ := h.flagManager.GetFlag("flag_gender_set") - - allowUpdate := h.st.MatchFlag(flag_allow_update, true) - genderSet := h.st.MatchFlag(flag_gender_set, true) - - if allowUpdate { - temporaryGender, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) - err = store.WriteEntry(ctx, sessionId, common.DATA_GENDER, []byte(temporaryGender)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write gender entry with", "key", common.DATA_GENDER, "value", gender, "error", err) - return res, err - } - res.FlagSet = append(res.FlagSet, flag_gender_set) - } else { - if genderSet { - err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(gender)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write temporaryGender entry with", "key", common.DATA_TEMPORARY_VALUE, "value", gender, "error", err) - return res, err - } - } else { - h.profile.InsertOrShift(2, gender) - } - } - - return res, nil -} - -// SaveOfferings updates the offerings(goods and services provided by the user) in the gdbm with the provided input. -func (h *Handlers) SaveOfferings(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") - } - - offerings := string(input) - store := h.userdataStore - - flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") - flag_offerings_set, _ := h.flagManager.GetFlag("flag_offerings_set") - - allowUpdate := h.st.MatchFlag(flag_allow_update, true) - offeringsSet := h.st.MatchFlag(flag_offerings_set, true) - - if allowUpdate { - temporaryOfferings, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) - err = store.WriteEntry(ctx, sessionId, common.DATA_OFFERINGS, []byte(temporaryOfferings)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write offerings entry with", "key", common.DATA_TEMPORARY_VALUE, "value", offerings, "error", err) - return res, err - } - res.FlagSet = append(res.FlagSet, flag_offerings_set) - } else { - if offeringsSet { - err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(offerings)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write temporaryOfferings entry with", "key", common.DATA_TEMPORARY_VALUE, "value", offerings, "error", err) - return res, err - } - } else { - h.profile.InsertOrShift(5, offerings) - } - } - - return res, nil -} - -// ResetAllowUpdate resets the allowupdate flag that allows a user to update profile data. -func (h *Handlers) ResetAllowUpdate(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") - res.FlagReset = append(res.FlagReset, flag_allow_update) - return res, nil -} - -// ResetAllowUpdate resets the allowupdate flag that allows a user to update profile data. -func (h *Handlers) ResetValidPin(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - flag_valid_pin, _ := h.flagManager.GetFlag("flag_valid_pin") - res.FlagReset = append(res.FlagReset, flag_valid_pin) - return res, nil -} - -// ResetAccountAuthorized resets the account authorization flag after a successful PIN entry. -func (h *Handlers) ResetAccountAuthorized(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized") - res.FlagReset = append(res.FlagReset, flag_account_authorized) - return res, nil -} - -// CheckIdentifier retrieves the PublicKey from the JSON data file. -func (h *Handlers) CheckIdentifier(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") - } - store := h.userdataStore - publicKey, _ := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) - - res.Content = string(publicKey) - - return res, nil -} - -// Authorize attempts to unlock the next sequential nodes by verifying the provided PIN against the already set PIN. -// It sets the required flags that control the flow. -func (h *Handlers) Authorize(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_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin") - flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized") - flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") - - store := h.userdataStore - AccountPin, err := store.ReadEntry(ctx, sessionId, common.DATA_ACCOUNT_PIN) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read AccountPin entry with", "key", common.DATA_ACCOUNT_PIN, "error", err) - return res, err - } - if len(input) == 4 { - if common.VerifyPIN(string(AccountPin), string(input)) { - if h.st.MatchFlag(flag_account_authorized, false) { - res.FlagReset = append(res.FlagReset, flag_incorrect_pin) - res.FlagSet = append(res.FlagSet, flag_allow_update, flag_account_authorized) - err := h.resetIncorrectPINAttempts(ctx, sessionId) - if err != nil { - return res, err - } - } else { - res.FlagSet = append(res.FlagSet, flag_allow_update) - res.FlagReset = append(res.FlagReset, flag_account_authorized) - err := h.resetIncorrectPINAttempts(ctx, sessionId) - if err != nil { - return res, err - } - } - } else { - err := h.incrementIncorrectPINAttempts(ctx, sessionId) - if err != nil { - return res, err - } - res.FlagSet = append(res.FlagSet, flag_incorrect_pin) - res.FlagReset = append(res.FlagReset, flag_account_authorized) - return res, nil - } - } else { - return res, nil - } - return res, nil -} - -// ResetIncorrectPin resets the incorrect pin flag after a new PIN attempt. -func (h *Handlers) ResetIncorrectPin(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - store := h.userdataStore - - flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin") - flag_account_blocked, _ := h.flagManager.GetFlag("flag_account_blocked") - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - - res.FlagReset = append(res.FlagReset, flag_incorrect_pin) - - currentWrongPinAttempts, err := store.ReadEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS) - if err != nil { - if !db.IsNotFound(err) { - return res, err - } - } - pinAttemptsValue, _ := strconv.ParseUint(string(currentWrongPinAttempts), 0, 64) - remainingPINAttempts := common.AllowedPINAttempts - uint8(pinAttemptsValue) - if remainingPINAttempts == 0 { - res.FlagSet = append(res.FlagSet, flag_account_blocked) - return res, nil - } - if remainingPINAttempts < common.AllowedPINAttempts { - res.Content = strconv.Itoa(int(remainingPINAttempts)) - } - - return res, nil -} - -// Setback sets the flag_back_set flag when the navigation is back. -func (h *Handlers) SetBack(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - //TODO: - //Add check if the navigation is lateral nav instead of checking the input. - if string(input) == "0" { - flag_back_set, _ := h.flagManager.GetFlag("flag_back_set") - res.FlagSet = append(res.FlagSet, flag_back_set) - } - return res, nil -} - -// CheckAccountStatus queries the API using the TrackingId and sets flags -// based on the account status. -func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - - flag_account_success, _ := h.flagManager.GetFlag("flag_account_success") - flag_account_pending, _ := h.flagManager.GetFlag("flag_account_pending") - flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - - store := h.userdataStore - publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", common.DATA_PUBLIC_KEY, "error", err) - return res, err - } - - r, err := h.accountService.TrackAccountStatus(ctx, string(publicKey)) - if err != nil { - res.FlagSet = append(res.FlagSet, flag_api_error) - logg.ErrorCtxf(ctx, "failed on TrackAccountStatus", "error", err) - return res, err - } - - res.FlagReset = append(res.FlagReset, flag_api_error) - - if r.Active { - res.FlagSet = append(res.FlagSet, flag_account_success) - res.FlagReset = append(res.FlagReset, flag_account_pending) - } else { - res.FlagReset = append(res.FlagReset, flag_account_success) - res.FlagSet = append(res.FlagSet, flag_account_pending) - } - - return res, nil -} - -// Quit displays the Thank you message and exits the menu. -func (h *Handlers) Quit(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - - flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized") - - code := codeFromCtx(ctx) - l := gotext.NewLocale(translationDir, code) - l.AddDomain("default") - - res.Content = l.Get("Thank you for using Sarafu. Goodbye!") - res.FlagReset = append(res.FlagReset, flag_account_authorized) - return res, nil -} - -// QuitWithHelp displays helpline information then exits the menu. -func (h *Handlers) QuitWithHelp(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - - flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized") - - code := codeFromCtx(ctx) - l := gotext.NewLocale(translationDir, code) - l.AddDomain("default") - - res.Content = l.Get("For more help, please call: 0757628885") - res.FlagReset = append(res.FlagReset, flag_account_authorized) - return res, nil -} - -// ShowBlockedAccount displays a message after an account has been blocked and how to reach support. -func (h *Handlers) ShowBlockedAccount(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - code := codeFromCtx(ctx) - l := gotext.NewLocale(translationDir, code) - l.AddDomain("default") - res.Content = l.Get("Your account has been locked. For help on how to unblock your account, contact support at: 0757628885") - return res, nil -} - -// VerifyYob verifies the length of the given input. -func (h *Handlers) VerifyYob(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - var err error - - flag_incorrect_date_format, _ := h.flagManager.GetFlag("flag_incorrect_date_format") - date := string(input) - _, err = strconv.Atoi(date) - if err != nil { - // If conversion fails, input is not numeric - res.FlagSet = append(res.FlagSet, flag_incorrect_date_format) - return res, nil - } - - if utils.IsValidYOb(date) { - res.FlagReset = append(res.FlagReset, flag_incorrect_date_format) - } else { - res.FlagSet = append(res.FlagSet, flag_incorrect_date_format) - } - return res, nil -} - -// ResetIncorrectYob resets the incorrect date format flag after a new attempt. -func (h *Handlers) ResetIncorrectYob(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - - flag_incorrect_date_format, _ := h.flagManager.GetFlag("flag_incorrect_date_format") - res.FlagReset = append(res.FlagReset, flag_incorrect_date_format) - return res, nil -} - -// CheckBalance retrieves the balance of the active voucher and sets -// the balance as the result content. -func (h *Handlers) CheckBalance(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") - } - - code := codeFromCtx(ctx) - l := gotext.NewLocale(translationDir, code) - l.AddDomain("default") - - store := h.userdataStore - - // get the active sym and active balance - activeSym, err := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_SYM) - if err != nil { - if db.IsNotFound(err) { - balance := "0.00" - res.Content = l.Get("Balance: %s\n", balance) - return res, nil - } - - logg.ErrorCtxf(ctx, "failed to read activeSym entry with", "key", common.DATA_ACTIVE_SYM, "error", err) - return res, err - } - - activeBal, err := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_BAL) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read activeBal entry with", "key", common.DATA_ACTIVE_BAL, "error", err) - return res, err - } - - // Convert activeBal from []byte to float64 - balFloat, err := strconv.ParseFloat(string(activeBal), 64) - if err != nil { - logg.ErrorCtxf(ctx, "failed to parse activeBal as float", "value", string(activeBal), "error", err) - return res, err - } - - // Format to 2 decimal places - balStr := fmt.Sprintf("%.2f %s", balFloat, activeSym) - - res.Content = l.Get("Balance: %s\n", balStr) - - return res, nil -} - -// FetchCommunityBalance retrieves and displays the balance for community accounts in user's preferred language. -func (h *Handlers) FetchCommunityBalance(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - // retrieve the language code from the context - code := codeFromCtx(ctx) - // Initialize the localization system with the appropriate translation directory - l := gotext.NewLocale(translationDir, code) - l.AddDomain("default") - //TODO: - //Check if the address is a community account,if then,get the actual balance - res.Content = l.Get("Community Balance: 0.00") - return res, nil -} - -// ResetOthersPin handles the PIN reset process for other users' accounts by: -// 1. Retrieving the blocked phone number from the session -// 2. Fetching the temporary PIN associated with that number -// 3. Updating the account PIN with the temporary PIN -func (h *Handlers) ResetOthersPin(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - store := h.userdataStore - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - blockedPhonenumber, err := store.ReadEntry(ctx, sessionId, common.DATA_BLOCKED_NUMBER) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read blockedPhonenumber entry with", "key", common.DATA_BLOCKED_NUMBER, "error", err) - return res, err - } - temporaryPin, err := store.ReadEntry(ctx, string(blockedPhonenumber), common.DATA_TEMPORARY_VALUE) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read temporaryPin entry with", "key", common.DATA_TEMPORARY_VALUE, "error", err) - return res, err - } - - // Hash the PIN - hashedPIN, err := common.HashPIN(string(temporaryPin)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to hash temporaryPin", "error", err) - return res, err - } - - err = store.WriteEntry(ctx, string(blockedPhonenumber), common.DATA_ACCOUNT_PIN, []byte(hashedPIN)) - if err != nil { - return res, nil - } - - return res, nil -} - -// ResetUnregisteredNumber clears the unregistered number flag in the system, -// indicating that a number's registration status should no longer be marked as unregistered. -func (h *Handlers) ResetUnregisteredNumber(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - flag_unregistered_number, _ := h.flagManager.GetFlag("flag_unregistered_number") - res.FlagReset = append(res.FlagReset, flag_unregistered_number) - return res, nil -} - -// ValidateBlockedNumber performs validation of phone numbers, specifically for blocked numbers in the system. -// It checks phone number format and verifies registration status. -func (h *Handlers) ValidateBlockedNumber(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - var err error - - flag_unregistered_number, _ := h.flagManager.GetFlag("flag_unregistered_number") - store := h.userdataStore - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - blockedNumber := string(input) - _, err = store.ReadEntry(ctx, blockedNumber, common.DATA_PUBLIC_KEY) - if !common.IsValidPhoneNumber(blockedNumber) { - res.FlagSet = append(res.FlagSet, flag_unregistered_number) - return res, nil - } - if err != nil { - if db.IsNotFound(err) { - logg.InfoCtxf(ctx, "Invalid or unregistered number") - res.FlagSet = append(res.FlagSet, flag_unregistered_number) - return res, nil - } else { - logg.ErrorCtxf(ctx, "Error on ValidateBlockedNumber", "error", err) - return res, err - } - } - err = store.WriteEntry(ctx, sessionId, common.DATA_BLOCKED_NUMBER, []byte(blockedNumber)) - if err != nil { - return res, nil - } - return res, nil -} - -// ValidateRecipient validates that the given input is valid. -func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - store := h.userdataStore - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - - flag_invalid_recipient, _ := h.flagManager.GetFlag("flag_invalid_recipient") - flag_invalid_recipient_with_invite, _ := h.flagManager.GetFlag("flag_invalid_recipient_with_invite") - flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") - - recipient := string(input) - - if recipient != "0" { - recipientType, err := common.CheckRecipient(recipient) - if err != nil { - // Invalid recipient format (not a phone number, address, or valid alias format) - 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, common.DATA_TEMPORARY_VALUE, []byte(recipient)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write temporaryRecipient entry with", "key", common.DATA_TEMPORARY_VALUE, "value", recipient, "error", err) - return res, err - } - - switch recipientType { - case "phone number": - // format the phone number - formattedNumber, err := common.FormatPhoneNumber(recipient) - if err != nil { - 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, common.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", common.DATA_PUBLIC_KEY, "error", err) - return res, err - } - - // Save the publicKey as the recipient - err = store.WriteEntry(ctx, sessionId, common.DATA_RECIPIENT, publicKey) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write recipient entry with", "key", common.DATA_RECIPIENT, "value", string(publicKey), "error", err) - return res, err - } - - case "address": - // Save the valid Ethereum address as the recipient - err = store.WriteEntry(ctx, sessionId, common.DATA_RECIPIENT, []byte(recipient)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write recipient entry with", "key", common.DATA_RECIPIENT, "value", recipient, "error", err) - return res, err - } - - case "alias": - // Call the API to validate and retrieve the address for the alias - r, aliasErr := h.accountService.CheckAliasAddress(ctx, recipient) - if aliasErr != nil { - res.FlagSet = append(res.FlagSet, flag_api_error) - res.Content = recipient - - logg.ErrorCtxf(ctx, "failed on CheckAliasAddress", "error", aliasErr) - return res, err - } - - // Alias validation succeeded, save the Ethereum address - err = store.WriteEntry(ctx, sessionId, common.DATA_RECIPIENT, []byte(r.Address)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write recipient entry with", "key", common.DATA_RECIPIENT, "value", r.Address, "error", err) - return res, err - } - } - } - - return res, nil -} - -// TransactionReset resets the previous transaction data (Recipient and Amount) -// as well as the invalid flags. -func (h *Handlers) TransactionReset(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_invalid_recipient, _ := h.flagManager.GetFlag("flag_invalid_recipient") - flag_invalid_recipient_with_invite, _ := h.flagManager.GetFlag("flag_invalid_recipient_with_invite") - store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, common.DATA_AMOUNT, []byte("")) - if err != nil { - return res, nil - } - - err = store.WriteEntry(ctx, sessionId, common.DATA_RECIPIENT, []byte("")) - if err != nil { - return res, nil - } - - res.FlagReset = append(res.FlagReset, flag_invalid_recipient, flag_invalid_recipient_with_invite) - - return res, nil -} - -// InviteValidRecipient sends an invitation to the valid phone number. -func (h *Handlers) InviteValidRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - store := h.userdataStore - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - - code := codeFromCtx(ctx) - l := gotext.NewLocale(translationDir, code) - l.AddDomain("default") - - recipient, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) - - // TODO - // send an invitation SMS - // if successful - // res.Content = l.Get("Your invitation to %s to join Sarafu Network has been sent.", string(recipient)) - - res.Content = l.Get("Your invite request for %s to Sarafu Network failed. Please try again later.", string(recipient)) - return res, nil -} - -// ResetTransactionAmount resets the transaction amount and invalid flag. -func (h *Handlers) ResetTransactionAmount(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_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount") - store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, common.DATA_AMOUNT, []byte("")) - if err != nil { - return res, nil - } - - res.FlagReset = append(res.FlagReset, flag_invalid_amount) - - return res, nil -} - -// MaxAmount gets the current balance from the API and sets it as -// the result content. -func (h *Handlers) MaxAmount(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") - } - store := h.userdataStore - - activeBal, err := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_BAL) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read activeBal entry with", "key", common.DATA_ACTIVE_BAL, "error", err) - return res, err - } - - res.Content = string(activeBal) - - return res, nil -} - -// ValidateAmount ensures that the given input is a valid amount and that -// it is not more than the current balance. -func (h *Handlers) ValidateAmount(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") - } - flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount") - store := h.userdataStore - - var balanceValue float64 - - // retrieve the active balance - activeBal, err := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_BAL) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read activeBal entry with", "key", common.DATA_ACTIVE_BAL, "error", err) - return res, err - } - balanceValue, err = strconv.ParseFloat(string(activeBal), 64) - if err != nil { - logg.ErrorCtxf(ctx, "Failed to convert the activeBal to a float", "error", err) - return res, err - } - - // Extract numeric part from the input amount - amountStr := strings.TrimSpace(string(input)) - inputAmount, err := strconv.ParseFloat(amountStr, 64) - if err != nil { - res.FlagSet = append(res.FlagSet, flag_invalid_amount) - res.Content = amountStr - return res, nil - } - - if inputAmount > balanceValue { - res.FlagSet = append(res.FlagSet, flag_invalid_amount) - res.Content = amountStr - return res, nil - } - - // Format the amount with 2 decimal places before saving - formattedAmount := fmt.Sprintf("%.2f", inputAmount) - err = store.WriteEntry(ctx, sessionId, common.DATA_AMOUNT, []byte(formattedAmount)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write amount entry with", "key", common.DATA_AMOUNT, "value", formattedAmount, "error", err) - return res, err - } - - res.Content = formattedAmount - return res, nil -} - -// GetRecipient returns the transaction recipient phone number from the gdbm. -func (h *Handlers) GetRecipient(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") - } - store := h.userdataStore - recipient, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) - - res.Content = string(recipient) - - return res, nil -} - -// RetrieveBlockedNumber gets the current number during the pin reset for other's is in progress. -func (h *Handlers) RetrieveBlockedNumber(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") - } - store := h.userdataStore - blockedNumber, _ := store.ReadEntry(ctx, sessionId, common.DATA_BLOCKED_NUMBER) - - res.Content = string(blockedNumber) - - return res, nil -} - -// GetSender returns the sessionId (phoneNumber). -func (h *Handlers) GetSender(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") - } - - res.Content = sessionId - - return res, nil -} - -// GetAmount retrieves the amount from teh Gdbm Db. -func (h *Handlers) GetAmount(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") - } - store := h.userdataStore - - // retrieve the active symbol - activeSym, err := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_SYM) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read activeSym entry with", "key", common.DATA_ACTIVE_SYM, "error", err) - return res, err - } - - amount, _ := store.ReadEntry(ctx, sessionId, common.DATA_AMOUNT) - - res.Content = fmt.Sprintf("%s %s", string(amount), string(activeSym)) - - return res, nil -} - -// InitiateTransaction calls the TokenTransfer and returns a confirmation based on the result. -func (h *Handlers) InitiateTransaction(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") - - code := codeFromCtx(ctx) - l := gotext.NewLocale(translationDir, code) - l.AddDomain("default") - - data, err := common.ReadTransactionData(ctx, h.userdataStore, sessionId) - if err != nil { - return res, err - } - - finalAmountStr, err := common.ParseAndScaleAmount(data.Amount, data.ActiveDecimal) - if err != nil { - return res, err - } - - // Call TokenTransfer - r, err := h.accountService.TokenTransfer(ctx, finalAmountStr, data.PublicKey, data.Recipient, data.ActiveAddress) - if err != nil { - flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") - res.FlagSet = append(res.FlagSet, flag_api_error) - res.Content = l.Get("Your request failed. Please try again later.") - logg.ErrorCtxf(ctx, "failed on TokenTransfer", "error", err) - return res, nil - } - - trackingId := r.TrackingId - logg.InfoCtxf(ctx, "TokenTransfer", "trackingId", trackingId) - - res.Content = l.Get( - "Your request has been sent. %s will receive %s %s from %s.", - data.TemporaryValue, - data.Amount, - data.ActiveSym, - sessionId, - ) - - res.FlagReset = append(res.FlagReset, flag_account_authorized) - return res, nil -} - -// GetCurrentProfileInfo retrieves specific profile fields based on the current state of the USSD session. -// Uses flag management system to track profile field status and handle menu navigation. -func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - var profileInfo []byte - var defaultValue string - var err error - - flag_firstname_set, _ := h.flagManager.GetFlag("flag_firstname_set") - flag_familyname_set, _ := h.flagManager.GetFlag("flag_familyname_set") - flag_yob_set, _ := h.flagManager.GetFlag("flag_yob_set") - flag_gender_set, _ := h.flagManager.GetFlag("flag_gender_set") - flag_location_set, _ := h.flagManager.GetFlag("flag_location_set") - flag_offerings_set, _ := h.flagManager.GetFlag("flag_offerings_set") - flag_back_set, _ := h.flagManager.GetFlag("flag_back_set") - - res.FlagReset = append(res.FlagReset, flag_back_set) - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - language, ok := ctx.Value("Language").(lang.Language) - if !ok { - return res, fmt.Errorf("value for 'Language' is not of type lang.Language") - } - code := language.Code - if code == "swa" { - defaultValue = "Haipo" - } else { - defaultValue = "Not Provided" - } - - sm, _ := h.st.Where() - parts := strings.SplitN(sm, "_", 2) - filename := parts[1] - dbKeyStr := "DATA_" + strings.ToUpper(filename) - dbKey, err := common.StringToDataTyp(dbKeyStr) - - if err != nil { - return res, err - } - store := h.userdataStore - - switch dbKey { - case common.DATA_FIRST_NAME: - profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_FIRST_NAME) - if err != nil { - if db.IsNotFound(err) { - res.Content = defaultValue - break - } - logg.ErrorCtxf(ctx, "Failed to read first name entry with", "key", "error", common.DATA_FIRST_NAME, err) - return res, err - } - res.FlagSet = append(res.FlagSet, flag_firstname_set) - res.Content = string(profileInfo) - case common.DATA_FAMILY_NAME: - profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_FAMILY_NAME) - if err != nil { - if db.IsNotFound(err) { - res.Content = defaultValue - break - } - logg.ErrorCtxf(ctx, "Failed to read family name entry with", "key", "error", common.DATA_FAMILY_NAME, err) - return res, err - } - res.FlagSet = append(res.FlagSet, flag_familyname_set) - res.Content = string(profileInfo) - - case common.DATA_GENDER: - profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_GENDER) - if err != nil { - if db.IsNotFound(err) { - res.Content = defaultValue - break - } - logg.ErrorCtxf(ctx, "Failed to read gender entry with", "key", "error", common.DATA_GENDER, err) - return res, err - } - res.FlagSet = append(res.FlagSet, flag_gender_set) - res.Content = string(profileInfo) - case common.DATA_YOB: - profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_YOB) - if err != nil { - if db.IsNotFound(err) { - res.Content = defaultValue - break - } - logg.ErrorCtxf(ctx, "Failed to read year of birth(yob) entry with", "key", "error", common.DATA_YOB, err) - return res, err - } - res.FlagSet = append(res.FlagSet, flag_yob_set) - res.Content = string(profileInfo) - case common.DATA_LOCATION: - profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_LOCATION) - if err != nil { - if db.IsNotFound(err) { - res.Content = defaultValue - break - } - logg.ErrorCtxf(ctx, "Failed to read location entry with", "key", "error", common.DATA_LOCATION, err) - return res, err - } - res.FlagSet = append(res.FlagSet, flag_location_set) - res.Content = string(profileInfo) - case common.DATA_OFFERINGS: - profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_OFFERINGS) - if err != nil { - if db.IsNotFound(err) { - res.Content = defaultValue - break - } - logg.ErrorCtxf(ctx, "Failed to read offerings entry with", "key", "error", common.DATA_OFFERINGS, err) - return res, err - } - res.FlagSet = append(res.FlagSet, flag_offerings_set) - res.Content = string(profileInfo) - default: - break - } - - return res, nil -} - -// GetProfileInfo provides a comprehensive view of a user's profile. -func (h *Handlers) GetProfileInfo(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - var defaultValue string - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - language, ok := ctx.Value("Language").(lang.Language) - if !ok { - return res, fmt.Errorf("value for 'Language' is not of type lang.Language") - } - code := language.Code - if code == "swa" { - defaultValue = "Haipo" - } else { - defaultValue = "Not Provided" - } - - // Helper function to handle nil byte slices and convert them to string - getEntryOrDefault := func(entry []byte, err error) string { - if err != nil || entry == nil { - return defaultValue - } - return string(entry) - } - store := h.userdataStore - // Retrieve user data as strings with fallback to defaultValue - firstName := getEntryOrDefault(store.ReadEntry(ctx, sessionId, common.DATA_FIRST_NAME)) - familyName := getEntryOrDefault(store.ReadEntry(ctx, sessionId, common.DATA_FAMILY_NAME)) - yob := getEntryOrDefault(store.ReadEntry(ctx, sessionId, common.DATA_YOB)) - gender := getEntryOrDefault(store.ReadEntry(ctx, sessionId, common.DATA_GENDER)) - location := getEntryOrDefault(store.ReadEntry(ctx, sessionId, common.DATA_LOCATION)) - offerings := getEntryOrDefault(store.ReadEntry(ctx, sessionId, common.DATA_OFFERINGS)) - - // Construct the full name - name := utils.ConstructName(firstName, familyName, defaultValue) - - // Calculate age from year of birth - age := defaultValue - if yob != defaultValue { - if yobInt, err := strconv.Atoi(yob); err == nil { - age = strconv.Itoa(utils.CalculateAgeWithYOB(yobInt)) - } else { - return res, fmt.Errorf("invalid year of birth: %v", err) - } - } - switch language.Code { - case "eng": - res.Content = fmt.Sprintf( - "Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n", - name, gender, age, location, offerings, - ) - case "swa": - res.Content = fmt.Sprintf( - "Jina: %s\nJinsia: %s\nUmri: %s\nEneo: %s\nUnauza: %s\n", - name, gender, age, location, offerings, - ) - default: - res.Content = fmt.Sprintf( - "Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n", - name, gender, age, location, offerings, - ) - } - - return res, nil -} - -// SetDefaultVoucher retrieves the current vouchers -// and sets the first as the default voucher, if no active voucher is set. -func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - var err error - store := h.userdataStore - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - - flag_no_active_voucher, _ := h.flagManager.GetFlag("flag_no_active_voucher") - - // check if the user has an active sym - _, err = store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_SYM) - - if err != nil { - if db.IsNotFound(err) { - publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", common.DATA_PUBLIC_KEY, "error", err) - return res, err - } - - // Fetch vouchers from the API using the public key - vouchersResp, err := h.accountService.FetchVouchers(ctx, string(publicKey)) - if err != nil { - res.FlagSet = append(res.FlagSet, flag_no_active_voucher) - return res, nil - } - - // Return if there is no voucher - if len(vouchersResp) == 0 { - res.FlagSet = append(res.FlagSet, flag_no_active_voucher) - return res, nil - } - - // Use only the first voucher - firstVoucher := vouchersResp[0] - defaultSym := firstVoucher.TokenSymbol - defaultBal := firstVoucher.Balance - defaultDec := firstVoucher.TokenDecimals - defaultAddr := firstVoucher.ContractAddress - - // Scale down the balance - scaledBalance := common.ScaleDownBalance(defaultBal, defaultDec) - - // set the active symbol - err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_SYM, []byte(defaultSym)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write defaultSym entry with", "key", common.DATA_ACTIVE_SYM, "value", defaultSym, "error", err) - return res, err - } - // set the active balance - err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_BAL, []byte(scaledBalance)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write defaultBal entry with", "key", common.DATA_ACTIVE_BAL, "value", scaledBalance, "error", err) - return res, err - } - // set the active decimals - err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_DECIMAL, []byte(defaultDec)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write defaultDec entry with", "key", common.DATA_ACTIVE_DECIMAL, "value", defaultDec, "error", err) - return res, err - } - // set the active contract address - err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_ADDRESS, []byte(defaultAddr)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write defaultAddr entry with", "key", common.DATA_ACTIVE_ADDRESS, "value", defaultAddr, "error", err) - return res, err - } - - return res, nil - } - - logg.ErrorCtxf(ctx, "failed to read activeSym entry with", "key", common.DATA_ACTIVE_SYM, "error", err) - return res, err - } - - res.FlagReset = append(res.FlagReset, flag_no_active_voucher) - - return res, nil -} - -// CheckVouchers retrieves the token holdings from the API using the "PublicKey" and stores -// them to gdbm. -func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - - store := h.userdataStore - publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", common.DATA_PUBLIC_KEY, "error", err) - return res, err - } - - // Fetch vouchers from the API using the public key - vouchersResp, err := h.accountService.FetchVouchers(ctx, string(publicKey)) - if err != nil { - return res, nil - } - - // check the current active sym and update the data - activeSym, _ := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_SYM) - if activeSym != nil { - activeSymStr := string(activeSym) - - // Find the matching voucher data - var activeData *dataserviceapi.TokenHoldings - for _, voucher := range vouchersResp { - if voucher.TokenSymbol == activeSymStr { - activeData = &voucher - break - } - } - - if activeData == nil { - logg.ErrorCtxf(ctx, "activeSym not found in vouchers", "activeSym", activeSymStr) - return res, fmt.Errorf("activeSym %s not found in vouchers", activeSymStr) - } - - // Scale down the balance - scaledBalance := common.ScaleDownBalance(activeData.Balance, activeData.TokenDecimals) - - // Update the balance field with the scaled value - activeData.Balance = scaledBalance - - // Pass the matching voucher data to UpdateVoucherData - if err := common.UpdateVoucherData(ctx, h.userdataStore, sessionId, activeData); err != nil { - logg.ErrorCtxf(ctx, "failed on UpdateVoucherData", "error", err) - return res, err - } - } - - data := common.ProcessVouchers(vouchersResp) - - // Store all voucher data - dataMap := map[common.DataTyp]string{ - common.DATA_VOUCHER_SYMBOLS: data.Symbols, - common.DATA_VOUCHER_BALANCES: data.Balances, - common.DATA_VOUCHER_DECIMALS: data.Decimals, - common.DATA_VOUCHER_ADDRESSES: data.Addresses, - } - - for key, value := range dataMap { - if err := h.prefixDb.Put(ctx, []byte(common.ToBytes(key)), []byte(value)); err != nil { - return res, nil - } - } - - return res, nil -} - -// GetVoucherList fetches the list of vouchers and formats them. -func (h *Handlers) GetVoucherList(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - - // Read vouchers from the store - voucherData, err := h.prefixDb.Get(ctx, common.ToBytes(common.DATA_VOUCHER_SYMBOLS)) - if err != nil { - logg.ErrorCtxf(ctx, "Failed to read the voucherData from prefixDb", "error", err) - return res, err - } - - formattedData := h.ReplaceSeparatorFunc(string(voucherData)) - - res.Content = string(formattedData) - - return res, nil -} - -// ViewVoucher retrieves the token holding and balance from the subprefixDB -// and displays it to the user for them to select it. -func (h *Handlers) ViewVoucher(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") - } - - code := codeFromCtx(ctx) - l := gotext.NewLocale(translationDir, code) - l.AddDomain("default") - - flag_incorrect_voucher, _ := h.flagManager.GetFlag("flag_incorrect_voucher") - - inputStr := string(input) - if inputStr == "0" || inputStr == "99" { - res.FlagReset = append(res.FlagReset, flag_incorrect_voucher) - return res, nil - } - - metadata, err := common.GetVoucherData(ctx, h.prefixDb, inputStr) - if err != nil { - return res, fmt.Errorf("failed to retrieve voucher data: %v", err) - } - - if metadata == nil { - res.FlagSet = append(res.FlagSet, flag_incorrect_voucher) - return res, nil - } - - if err := common.StoreTemporaryVoucher(ctx, h.userdataStore, sessionId, metadata); err != nil { - logg.ErrorCtxf(ctx, "failed on StoreTemporaryVoucher", "error", err) - return res, err - } - - res.FlagReset = append(res.FlagReset, flag_incorrect_voucher) - res.Content = l.Get("Symbol: %s\nBalance: %s", metadata.TokenSymbol, metadata.Balance) - - return res, nil -} - -// SetVoucher retrieves the temp voucher data and sets it as the active data. -func (h *Handlers) SetVoucher(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") - } - - // Get temporary data - tempData, err := common.GetTemporaryVoucherData(ctx, h.userdataStore, sessionId) - if err != nil { - logg.ErrorCtxf(ctx, "failed on GetTemporaryVoucherData", "error", err) - return res, err - } - - // Set as active and clear temporary data - if err := common.UpdateVoucherData(ctx, h.userdataStore, sessionId, tempData); err != nil { - logg.ErrorCtxf(ctx, "failed on UpdateVoucherData", "error", err) - return res, err - } - - res.Content = tempData.TokenSymbol - return res, nil -} - -// GetVoucherDetails retrieves the voucher details. -func (h *Handlers) GetVoucherDetails(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - store := h.userdataStore - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - - flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") - - // get the active address - activeAddress, err := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_ADDRESS) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read activeAddress entry with", "key", common.DATA_ACTIVE_ADDRESS, "error", err) - return res, err - } - - // use the voucher contract address to get the data from the API - voucherData, err := h.accountService.VoucherData(ctx, string(activeAddress)) - if err != nil { - res.FlagSet = append(res.FlagSet, flag_api_error) - return res, nil - } - - res.Content = fmt.Sprintf( - "Name: %s\nSymbol: %s\nCommodity: %s\nLocation: %s", voucherData.TokenName, voucherData.TokenSymbol, voucherData.TokenCommodity, voucherData.TokenLocation, - ) - - return res, nil -} - -// CheckTransactions retrieves the transactions from the API using the "PublicKey" and stores to prefixDb. -func (h *Handlers) CheckTransactions(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") - } - - flag_no_transfers, _ := h.flagManager.GetFlag("flag_no_transfers") - flag_api_error, _ := h.flagManager.GetFlag("flag_api_error") - - store := h.userdataStore - publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", common.DATA_PUBLIC_KEY, "error", err) - return res, err - } - - // Fetch transactions from the API using the public key - transactionsResp, err := h.accountService.FetchTransactions(ctx, string(publicKey)) - if err != nil { - res.FlagSet = append(res.FlagSet, flag_api_error) - logg.ErrorCtxf(ctx, "failed on FetchTransactions", "error", err) - return res, err - } - - // Return if there are no transactions - if len(transactionsResp) == 0 { - res.FlagSet = append(res.FlagSet, flag_no_transfers) - return res, nil - } - - data := common.ProcessTransfers(transactionsResp) - - // Store all transaction data - dataMap := map[common.DataTyp]string{ - common.DATA_TX_SENDERS: data.Senders, - common.DATA_TX_RECIPIENTS: data.Recipients, - common.DATA_TX_VALUES: data.TransferValues, - common.DATA_TX_ADDRESSES: data.Addresses, - common.DATA_TX_HASHES: data.TxHashes, - common.DATA_TX_DATES: data.Dates, - common.DATA_TX_SYMBOLS: data.Symbols, - common.DATA_TX_DECIMALS: data.Decimals, - } - - for key, value := range dataMap { - if err := h.prefixDb.Put(ctx, []byte(common.ToBytes(key)), []byte(value)); err != nil { - logg.ErrorCtxf(ctx, "failed to write to prefixDb", "error", err) - return res, err - } - } - - res.FlagReset = append(res.FlagReset, flag_no_transfers) - - return res, nil -} - -// GetTransactionsList fetches the list of transactions and formats them. -func (h *Handlers) GetTransactionsList(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") - } - - store := h.userdataStore - publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", common.DATA_PUBLIC_KEY, "error", err) - return res, err - } - - // Read transactions from the store and format them - TransactionSenders, err := h.prefixDb.Get(ctx, common.ToBytes(common.DATA_TX_SENDERS)) - if err != nil { - logg.ErrorCtxf(ctx, "Failed to read the TransactionSenders from prefixDb", "error", err) - return res, err - } - TransactionSyms, err := h.prefixDb.Get(ctx, common.ToBytes(common.DATA_TX_SYMBOLS)) - if err != nil { - logg.ErrorCtxf(ctx, "Failed to read the TransactionSyms from prefixDb", "error", err) - return res, err - } - TransactionValues, err := h.prefixDb.Get(ctx, common.ToBytes(common.DATA_TX_VALUES)) - if err != nil { - logg.ErrorCtxf(ctx, "Failed to read the TransactionValues from prefixDb", "error", err) - return res, err - } - TransactionDates, err := h.prefixDb.Get(ctx, common.ToBytes(common.DATA_TX_DATES)) - if err != nil { - logg.ErrorCtxf(ctx, "Failed to read the TransactionDates from prefixDb", "error", err) - return res, err - } - - // Parse the data - senders := strings.Split(string(TransactionSenders), "\n") - syms := strings.Split(string(TransactionSyms), "\n") - values := strings.Split(string(TransactionValues), "\n") - dates := strings.Split(string(TransactionDates), "\n") - - var formattedTransactions []string - for i := 0; i < len(senders); i++ { - sender := strings.TrimSpace(senders[i]) - sym := strings.TrimSpace(syms[i]) - value := strings.TrimSpace(values[i]) - date := strings.Split(strings.TrimSpace(dates[i]), " ")[0] - - status := "Received" - if sender == string(publicKey) { - status = "Sent" - } - - // Use the ReplaceSeparator function for the menu separator - transactionLine := fmt.Sprintf("%d%s%s %s %s %s", i+1, h.ReplaceSeparatorFunc(":"), status, value, sym, date) - formattedTransactions = append(formattedTransactions, transactionLine) - } - - res.Content = strings.Join(formattedTransactions, "\n") - - return res, nil -} - -// ViewTransactionStatement retrieves the transaction statement -// and displays it to the user. -func (h *Handlers) ViewTransactionStatement(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") - } - store := h.userdataStore - publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", common.DATA_PUBLIC_KEY, "error", err) - return res, err - } - - flag_incorrect_statement, _ := h.flagManager.GetFlag("flag_incorrect_statement") - - inputStr := string(input) - if inputStr == "0" || inputStr == "99" || inputStr == "11" || inputStr == "22" { - res.FlagReset = append(res.FlagReset, flag_incorrect_statement) - return res, nil - } - - // Convert input string to integer - index, err := strconv.Atoi(strings.TrimSpace(inputStr)) - if err != nil { - return res, fmt.Errorf("invalid input: must be a number between 1 and 10") - } - - if index < 1 || index > 10 { - return res, fmt.Errorf("invalid input: index must be between 1 and 10") - } - - statement, err := common.GetTransferData(ctx, h.prefixDb, string(publicKey), index) - if err != nil { - return res, fmt.Errorf("failed to retrieve transfer data: %v", err) - } - - if statement == "" { - res.FlagSet = append(res.FlagSet, flag_incorrect_statement) - return res, nil - } - - res.FlagReset = append(res.FlagReset, flag_incorrect_statement) - res.Content = statement - - return res, nil -} - -// handles bulk updates of profile information. -func (h *Handlers) insertProfileItems(ctx context.Context, sessionId string, res *resource.Result) error { - var err error - store := h.userdataStore - profileFlagNames := []string{ - "flag_firstname_set", - "flag_familyname_set", - "flag_yob_set", - "flag_gender_set", - "flag_location_set", - "flag_offerings_set", - } - profileDataKeys := []common.DataTyp{ - common.DATA_FIRST_NAME, - common.DATA_FAMILY_NAME, - common.DATA_GENDER, - common.DATA_YOB, - common.DATA_LOCATION, - common.DATA_OFFERINGS, - } - for index, profileItem := range h.profile.ProfileItems { - // Ensure the profileItem is not "0"(is set) - if profileItem != "0" { - flag, _ := h.flagManager.GetFlag(profileFlagNames[index]) - isProfileItemSet := h.st.MatchFlag(flag, true) - if !isProfileItemSet { - err = store.WriteEntry(ctx, sessionId, profileDataKeys[index], []byte(profileItem)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write profile entry with", "key", profileDataKeys[index], "value", profileItem, "error", err) - return err - } - res.FlagSet = append(res.FlagSet, flag) - } - } - } - return nil -} - -// UpdateAllProfileItems is used to persist all the new profile information and setup the required profile flags. -func (h *Handlers) UpdateAllProfileItems(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") - } - err := h.insertProfileItems(ctx, sessionId, &res) - if err != nil { - return res, err - } - return res, nil -} - -// incrementIncorrectPINAttempts keeps track of the number of incorrect PIN attempts -func (h *Handlers) incrementIncorrectPINAttempts(ctx context.Context, sessionId string) error { - var pinAttemptsCount uint8 - store := h.userdataStore - - currentWrongPinAttempts, err := store.ReadEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS) - if err != nil { - if db.IsNotFound(err) { - //First time Wrong PIN attempt: initialize with a count of 1 - pinAttemptsCount = 1 - err = store.WriteEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS, []byte(strconv.Itoa(int(pinAttemptsCount)))) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write incorrect PIN attempts ", "key", common.DATA_INCORRECT_PIN_ATTEMPTS, "value", currentWrongPinAttempts, "error", err) - return err - } - return nil - } - } - pinAttemptsValue, _ := strconv.ParseUint(string(currentWrongPinAttempts), 0, 64) - pinAttemptsCount = uint8(pinAttemptsValue) + 1 - - err = store.WriteEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS, []byte(strconv.Itoa(int(pinAttemptsCount)))) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write incorrect PIN attempts ", "key", common.DATA_INCORRECT_PIN_ATTEMPTS, "value", pinAttemptsCount, "error", err) - return err - } - return nil -} - -// resetIncorrectPINAttempts resets the number of incorrect PIN attempts after a correct PIN entry -func (h *Handlers) resetIncorrectPINAttempts(ctx context.Context, sessionId string) error { - store := h.userdataStore - currentWrongPinAttempts, err := store.ReadEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS) - if err != nil { - if db.IsNotFound(err) { - return nil - } - return err - } - currentWrongPinAttemptsCount, _ := strconv.ParseUint(string(currentWrongPinAttempts), 0, 64) - if currentWrongPinAttemptsCount <= uint64(common.AllowedPINAttempts) { - err = store.WriteEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS, []byte(string("0"))) - if err != nil { - logg.ErrorCtxf(ctx, "failed to reset incorrect PIN attempts ", "key", common.DATA_INCORRECT_PIN_ATTEMPTS, "value", common.AllowedPINAttempts, "error", err) - return err - } - } - return nil -} - -// persistLanguageCode persists the selected ISO 639 language code -func (h *Handlers) persistLanguageCode(ctx context.Context, code string) error { - store := h.userdataStore - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return fmt.Errorf("missing session") - } - err := store.WriteEntry(ctx, sessionId, common.DATA_SELECTED_LANGUAGE_CODE, []byte(code)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to persist language code", "key", common.DATA_SELECTED_LANGUAGE_CODE, "value", code, "error", err) - return err - } - return nil -} diff --git a/internal/handlers/application/menu_handler_test.go b/internal/handlers/application/menu_handler_test.go deleted file mode 100644 index 487fe2b..0000000 --- a/internal/handlers/application/menu_handler_test.go +++ /dev/null @@ -1,2331 +0,0 @@ -package application - -import ( - "context" - "fmt" - "log" - "path" - "strconv" - "strings" - "testing" - - "git.defalsify.org/vise.git/cache" - "git.defalsify.org/vise.git/lang" - "git.defalsify.org/vise.git/persist" - "git.defalsify.org/vise.git/resource" - "git.defalsify.org/vise.git/state" - dbstorage "git.grassecon.net/urdt/ussd/internal/storage/db" - "git.grassecon.net/urdt/ussd/internal/testutil/mocks" - "git.grassecon.net/urdt/ussd/internal/testutil/testservice" - "git.grassecon.net/urdt/ussd/internal/utils" - "git.grassecon.net/urdt/ussd/models" - - "git.grassecon.net/urdt/ussd/common" - "github.com/alecthomas/assert/v2" - - testdataloader "github.com/peteole/testdata-loader" - "github.com/stretchr/testify/require" - - visedb "git.defalsify.org/vise.git/db" - memdb "git.defalsify.org/vise.git/db/mem" - dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" -) - -var ( - baseDir = testdataloader.GetBasePath() - flagsPath = path.Join(baseDir, "services", "registration", "pp.csv") -) - -// mockReplaceSeparator function -var mockReplaceSeparator = func(input string) string { - return strings.ReplaceAll(input, ":", ": ") -} - -// InitializeTestStore sets up and returns an in-memory database and store. -func InitializeTestStore(t *testing.T) (context.Context, *common.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 - store := &common.UserDataStore{Db: db} - - t.Cleanup(func() { - db.Close() // Ensure the DB is closed after each test - }) - - return ctx, store -} - -func InitializeTestSubPrefixDb(t *testing.T, ctx context.Context) *dbstorage.SubPrefixDb { - db := memdb.NewMemDb() - err := db.Connect(ctx, "") - if err != nil { - t.Fatal(err) - } - prefix := common.ToBytes(visedb.DATATYPE_USERDATA) - spdb := dbstorage.NewSubPrefixDb(db, prefix) - - return spdb -} - -func TestNewHandlers(t *testing.T) { - _, store := InitializeTestStore(t) - - fm, err := NewFlagManager(flagsPath) - if err != nil { - log.Fatal(err) - } - - accountService := testservice.TestAccountService{} - - // Test case for valid UserDataStore - t.Run("Valid UserDataStore", func(t *testing.T) { - handlers, err := NewHandlers(fm.parser, store, nil, &accountService, mockReplaceSeparator) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - if handlers == nil { - t.Fatal("expected handlers to be non-nil") - } - if handlers.userdataStore == nil { - t.Fatal("expected userdataStore to be set in handlers") - } - if handlers.ReplaceSeparatorFunc == nil { - t.Fatal("expected ReplaceSeparatorFunc to be set in handlers") - } - - // Test ReplaceSeparatorFunc functionality - input := "1:Menu item" - expectedOutput := "1: Menu item" - if handlers.ReplaceSeparatorFunc(input) != expectedOutput { - t.Fatalf("ReplaceSeparatorFunc function did not return expected output: got %v, want %v", handlers.ReplaceSeparatorFunc(input), expectedOutput) - } - }) - - // Test case for nil UserDataStore - t.Run("Nil UserDataStore", func(t *testing.T) { - handlers, err := NewHandlers(fm.parser, nil, nil, &accountService, mockReplaceSeparator) - if err == nil { - t.Fatal("expected an error, got none") - } - if handlers != nil { - t.Fatal("expected handlers to be nil") - } - expectedError := "cannot create handler with nil userdata store" - if err.Error() != expectedError { - t.Fatalf("expected error '%s', got '%v'", expectedError, err) - } - }) -} - -func TestInit(t *testing.T) { - sessionId := "session123" - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - fm, err := NewFlagManager(flagsPath) - if err != nil { - t.Fatal(err.Error()) - } - - adminstore, err := utils.NewAdminStore(ctx, "admin_numbers") - if err != nil { - t.Fatal(err.Error()) - } - - st := state.NewState(128) - ca := cache.NewCache() - - flag_admin_privilege, _ := fm.GetFlag("flag_admin_privilege") - - tests := []struct { - name string - setup func() (*Handlers, context.Context) - input []byte - expectedResult resource.Result - }{ - { - name: "Handler not ready", - setup: func() (*Handlers, context.Context) { - return &Handlers{}, ctx - }, - input: []byte("1"), - expectedResult: resource.Result{}, - }, - { - name: "State and memory initialization", - setup: func() (*Handlers, context.Context) { - pe := persist.NewPersister(store).WithSession(sessionId).WithContent(st, ca) - h := &Handlers{ - flagManager: fm.parser, - adminstore: adminstore, - pe: pe, - } - return h, context.WithValue(ctx, "SessionId", sessionId) - }, - input: []byte("1"), - expectedResult: resource.Result{ - FlagReset: []uint32{flag_admin_privilege}, - }, - }, - { - name: "Non-admin session initialization", - setup: func() (*Handlers, context.Context) { - pe := persist.NewPersister(store).WithSession("0712345678").WithContent(st, ca) - h := &Handlers{ - flagManager: fm.parser, - adminstore: adminstore, - pe: pe, - } - return h, context.WithValue(context.Background(), "SessionId", "0712345678") - }, - input: []byte("1"), - expectedResult: resource.Result{ - FlagReset: []uint32{flag_admin_privilege}, - }, - }, - { - name: "Move to top node on empty input", - setup: func() (*Handlers, context.Context) { - pe := persist.NewPersister(store).WithSession(sessionId).WithContent(st, ca) - h := &Handlers{ - flagManager: fm.parser, - adminstore: adminstore, - pe: pe, - } - st.Code = []byte("some pending bytecode") - return h, context.WithValue(ctx, "SessionId", sessionId) - }, - input: []byte(""), - expectedResult: resource.Result{ - FlagReset: []uint32{flag_admin_privilege}, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - h, testCtx := tt.setup() - res, err := h.Init(testCtx, "", tt.input) - - assert.NoError(t, err, "Unexpected error occurred") - assert.Equal(t, res, tt.expectedResult, "Expected result should match actual result") - }) - } -} - -func TestCreateAccount(t *testing.T) { - sessionId := "session123" - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - fm, err := NewFlagManager(flagsPath) - if err != nil { - t.Logf(err.Error()) - } - - flag_account_created, err := fm.GetFlag("flag_account_created") - if err != nil { - t.Logf(err.Error()) - } - - tests := []struct { - name string - serverResponse *models.AccountResult - expectedResult resource.Result - }{ - { - name: "Test account creation success", - serverResponse: &models.AccountResult{ - TrackingId: "1234567890", - PublicKey: "0xD3adB33f", - }, - expectedResult: resource.Result{ - FlagSet: []uint32{flag_account_created}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - mockAccountService := new(mocks.MockAccountService) - - h := &Handlers{ - userdataStore: store, - accountService: mockAccountService, - flagManager: fm.parser, - } - - mockAccountService.On("CreateAccount").Return(tt.serverResponse, nil) - - // Call the method you want to test - res, err := h.CreateAccount(ctx, "create_account", []byte("")) - - // Assert that no errors occurred - assert.NoError(t, err) - - // Assert that the account created flag has been set to the result - assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") - }) - } -} - -func TestWithPersister(t *testing.T) { - // Test case: Setting a persister - h := &Handlers{} - p := &persist.Persister{} - - result := h.WithPersister(p) - - 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.") -} - -func TestWithPersister_PanicWhenAlreadySet(t *testing.T) { - // Test case: Panic on multiple calls - h := &Handlers{pe: &persist.Persister{}} - require.Panics(t, func() { - h.WithPersister(&persist.Persister{}) - }, "Should panic when trying to set a persister again.") -} - -func TestSaveFirstname(t *testing.T) { - sessionId := "session123" - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - fm, _ := NewFlagManager(flagsPath) - - flag_allow_update, _ := fm.GetFlag("flag_allow_update") - flag_firstname_set, _ := fm.GetFlag("flag_firstname_set") - - // Set the flag in the State - mockState := state.NewState(128) - mockState.SetFlag(flag_allow_update) - - expectedResult := resource.Result{} - - // Define test data - firstName := "John" - - if err := store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(firstName)); err != nil { - t.Fatal(err) - } - - expectedResult.FlagSet = []uint32{flag_firstname_set} - - // Create the Handlers instance with the mock store - h := &Handlers{ - userdataStore: store, - flagManager: fm.parser, - st: mockState, - } - - // Call the method - res, err := h.SaveFirstname(ctx, "save_firstname", []byte(firstName)) - - // Assert results - assert.NoError(t, err) - assert.Equal(t, expectedResult, res) - - // Verify that the DATA_FIRST_NAME entry has been updated with the temporary value - storedFirstName, _ := store.ReadEntry(ctx, sessionId, common.DATA_FIRST_NAME) - assert.Equal(t, firstName, string(storedFirstName)) -} - -func TestSaveFamilyname(t *testing.T) { - sessionId := "session123" - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - fm, _ := NewFlagManager(flagsPath) - - flag_allow_update, _ := fm.GetFlag("flag_allow_update") - flag_firstname_set, _ := fm.GetFlag("flag_familyname_set") - - // Set the flag in the State - mockState := state.NewState(128) - mockState.SetFlag(flag_allow_update) - - expectedResult := resource.Result{} - - expectedResult.FlagSet = []uint32{flag_firstname_set} - - // Define test data - familyName := "Doeee" - - if err := store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(familyName)); err != nil { - t.Fatal(err) - } - - // Create the Handlers instance with the mock store - h := &Handlers{ - userdataStore: store, - st: mockState, - flagManager: fm.parser, - } - - // Call the method - res, err := h.SaveFamilyname(ctx, "save_familyname", []byte(familyName)) - - // Assert results - assert.NoError(t, err) - assert.Equal(t, expectedResult, res) - - // Verify that the DATA_FAMILY_NAME entry has been updated with the temporary value - storedFamilyName, _ := store.ReadEntry(ctx, sessionId, common.DATA_FAMILY_NAME) - assert.Equal(t, familyName, string(storedFamilyName)) -} - -func TestSaveYoB(t *testing.T) { - sessionId := "session123" - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - fm, _ := NewFlagManager(flagsPath) - - flag_allow_update, _ := fm.GetFlag("flag_allow_update") - flag_yob_set, _ := fm.GetFlag("flag_yob_set") - - // Set the flag in the State - mockState := state.NewState(108) - mockState.SetFlag(flag_allow_update) - - expectedResult := resource.Result{} - - // Define test data - yob := "1980" - - if err := store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(yob)); err != nil { - t.Fatal(err) - } - - expectedResult.FlagSet = []uint32{flag_yob_set} - - // Create the Handlers instance with the mock store - h := &Handlers{ - userdataStore: store, - flagManager: fm.parser, - st: mockState, - } - - // Call the method - res, err := h.SaveYob(ctx, "save_yob", []byte(yob)) - - // Assert results - assert.NoError(t, err) - assert.Equal(t, expectedResult, res) - - // Verify that the DATA_YOB entry has been updated with the temporary value - storedYob, _ := store.ReadEntry(ctx, sessionId, common.DATA_YOB) - assert.Equal(t, yob, string(storedYob)) -} - -func TestSaveLocation(t *testing.T) { - sessionId := "session123" - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - fm, _ := NewFlagManager(flagsPath) - - flag_allow_update, _ := fm.GetFlag("flag_allow_update") - flag_location_set, _ := fm.GetFlag("flag_location_set") - - // Set the flag in the State - mockState := state.NewState(108) - mockState.SetFlag(flag_allow_update) - - expectedResult := resource.Result{} - - // Define test data - location := "Kilifi" - - if err := store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(location)); err != nil { - t.Fatal(err) - } - - expectedResult.FlagSet = []uint32{flag_location_set} - - // Create the Handlers instance with the mock store - h := &Handlers{ - userdataStore: store, - flagManager: fm.parser, - st: mockState, - } - - // Call the method - res, err := h.SaveLocation(ctx, "save_location", []byte(location)) - - // Assert results - assert.NoError(t, err) - assert.Equal(t, expectedResult, res) - - // Verify that the DATA_LOCATION entry has been updated with the temporary value - storedLocation, _ := store.ReadEntry(ctx, sessionId, common.DATA_LOCATION) - assert.Equal(t, location, string(storedLocation)) -} - -func TestSaveOfferings(t *testing.T) { - sessionId := "session123" - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - fm, _ := NewFlagManager(flagsPath) - - flag_allow_update, _ := fm.GetFlag("flag_allow_update") - flag_offerings_set, _ := fm.GetFlag("flag_offerings_set") - - // Set the flag in the State - mockState := state.NewState(108) - mockState.SetFlag(flag_allow_update) - - expectedResult := resource.Result{} - - // Define test data - offerings := "Bananas" - - if err := store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(offerings)); err != nil { - t.Fatal(err) - } - - expectedResult.FlagSet = []uint32{flag_offerings_set} - - // Create the Handlers instance with the mock store - h := &Handlers{ - userdataStore: store, - flagManager: fm.parser, - st: mockState, - } - - // Call the method - res, err := h.SaveOfferings(ctx, "save_offerings", []byte(offerings)) - - // Assert results - assert.NoError(t, err) - assert.Equal(t, expectedResult, res) - - // Verify that the DATA_OFFERINGS entry has been updated with the temporary value - storedOfferings, _ := store.ReadEntry(ctx, sessionId, common.DATA_OFFERINGS) - assert.Equal(t, offerings, string(storedOfferings)) -} - -func TestSaveGender(t *testing.T) { - sessionId := "session123" - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - fm, _ := NewFlagManager(flagsPath) - - flag_allow_update, _ := fm.GetFlag("flag_allow_update") - flag_gender_set, _ := fm.GetFlag("flag_gender_set") - - // Set the flag in the State - mockState := state.NewState(108) - mockState.SetFlag(flag_allow_update) - - // Define test cases - tests := []struct { - name string - input []byte - expectedGender string - executingSymbol string - }{ - { - name: "Valid Male Input", - input: []byte("1"), - expectedGender: "male", - executingSymbol: "set_male", - }, - { - name: "Valid Female Input", - input: []byte("2"), - expectedGender: "female", - executingSymbol: "set_female", - }, - { - name: "Valid Unspecified Input", - input: []byte("3"), - executingSymbol: "set_unspecified", - expectedGender: "unspecified", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if err := store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(tt.expectedGender)); err != nil { - t.Fatal(err) - } - - mockState.ExecPath = append(mockState.ExecPath, tt.executingSymbol) - // Create the Handlers instance with the mock store - h := &Handlers{ - userdataStore: store, - st: mockState, - flagManager: fm.parser, - } - - expectedResult := resource.Result{} - - // Call the method - res, err := h.SaveGender(ctx, "save_gender", tt.input) - - expectedResult.FlagSet = []uint32{flag_gender_set} - - // Assert results - assert.NoError(t, err) - assert.Equal(t, expectedResult, res) - - // Verify that the DATA_GENDER entry has been updated with the temporary value - storedGender, _ := store.ReadEntry(ctx, sessionId, common.DATA_GENDER) - assert.Equal(t, tt.expectedGender, string(storedGender)) - }) - } -} - -func TestSaveTemporaryPin(t *testing.T) { - sessionId := "session123" - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - fm, err := NewFlagManager(flagsPath) - if err != nil { - log.Fatal(err) - } - - flag_incorrect_pin, _ := fm.parser.GetFlag("flag_incorrect_pin") - - // Create the Handlers instance with the mock flag manager - h := &Handlers{ - flagManager: fm.parser, - userdataStore: store, - } - - // Define test cases - tests := []struct { - name string - input []byte - expectedResult resource.Result - }{ - { - name: "Valid Pin entry", - input: []byte("1234"), - expectedResult: resource.Result{ - FlagReset: []uint32{flag_incorrect_pin}, - }, - }, - { - name: "Invalid Pin entry", - input: []byte("12343"), - expectedResult: resource.Result{ - FlagSet: []uint32{flag_incorrect_pin}, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Call the method - res, err := h.SaveTemporaryPin(ctx, "save_pin", tt.input) - - if err != nil { - t.Error(err) - } - // Assert that the Result FlagSet has the required flags after language switch - assert.Equal(t, res, tt.expectedResult, "Result should match expected result") - }) - } -} - -func TestCheckIdentifier(t *testing.T) { - sessionId := "session123" - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - // Define test cases - tests := []struct { - name string - publicKey []byte - mockErr error - expectedContent string - expectError bool - }{ - { - name: "Saved public Key", - publicKey: []byte("0xa8363"), - mockErr: nil, - expectedContent: "0xa8363", - expectError: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := store.WriteEntry(ctx, sessionId, common.DATA_PUBLIC_KEY, []byte(tt.publicKey)) - if err != nil { - t.Fatal(err) - } - - // Create the Handlers instance with the mock store - h := &Handlers{ - userdataStore: store, - } - - // Call the method - res, err := h.CheckIdentifier(ctx, "check_identifier", nil) - - // Assert results - assert.NoError(t, err) - assert.Equal(t, tt.expectedContent, res.Content) - }) - } -} - -func TestGetSender(t *testing.T) { - sessionId := "session123" - ctx, _ := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - // Create the Handlers instance - h := &Handlers{} - - // Call the method - res, _ := h.GetSender(ctx, "get_sender", []byte("")) - - //Assert that the sessionId is what was set as the result content. - assert.Equal(t, sessionId, res.Content) -} - -func TestGetAmount(t *testing.T) { - sessionId := "session123" - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - // Define test data - amount := "0.03" - activeSym := "SRF" - - err := store.WriteEntry(ctx, sessionId, common.DATA_AMOUNT, []byte(amount)) - if err != nil { - t.Fatal(err) - } - - err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_SYM, []byte(activeSym)) - if err != nil { - t.Fatal(err) - } - - // Create the Handlers instance with the mock store - h := &Handlers{ - userdataStore: store, - } - - // Call the method - res, _ := h.GetAmount(ctx, "get_amount", []byte("")) - - formattedAmount := fmt.Sprintf("%s %s", amount, activeSym) - - //Assert that the retrieved amount is what was set as the content - assert.Equal(t, formattedAmount, res.Content) -} - -func TestGetRecipient(t *testing.T) { - sessionId := "session123" - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - recepient := "0712345678" - - err := store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(recepient)) - if err != nil { - t.Fatal(err) - } - - // Create the Handlers instance with the mock store - h := &Handlers{ - userdataStore: store, - } - - // Call the method - res, _ := h.GetRecipient(ctx, "get_recipient", []byte("")) - - //Assert that the retrieved recepient is what was set as the content - assert.Equal(t, recepient, res.Content) -} - -func TestGetFlag(t *testing.T) { - fm, err := NewFlagManager(flagsPath) - expectedFlag := uint32(9) - if err != nil { - t.Logf(err.Error()) - } - flag, err := fm.GetFlag("flag_account_created") - if err != nil { - t.Logf(err.Error()) - } - - assert.Equal(t, uint32(flag), expectedFlag, "Flags should be equal to account created") -} - -func TestSetLanguage(t *testing.T) { - fm, err := NewFlagManager(flagsPath) - if err != nil { - log.Fatal(err) - } - - sessionId := "session123" - ctx, store := InitializeTestStore(t) - - ctx = context.WithValue(ctx, "SessionId", sessionId) - - // Define test cases - tests := []struct { - name string - execPath []string - expectedResult resource.Result - }{ - { - name: "Set Default Language (English)", - execPath: []string{"set_eng"}, - expectedResult: resource.Result{ - FlagSet: []uint32{state.FLAG_LANG, 8}, - Content: "eng", - }, - }, - { - name: "Set Swahili Language", - execPath: []string{"set_swa"}, - expectedResult: resource.Result{ - FlagSet: []uint32{state.FLAG_LANG, 8}, - Content: "swa", - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - mockState := state.NewState(16) - // Set the ExecPath - mockState.ExecPath = tt.execPath - - // Create the Handlers instance with the mock flag manager - h := &Handlers{ - flagManager: fm.parser, - userdataStore: store, - st: mockState, - } - - // Call the method - res, err := h.SetLanguage(ctx, "set_language", nil) - if err != nil { - t.Error(err) - } - - // Assert that the Result FlagSet has the required flags after language switch - assert.Equal(t, res, tt.expectedResult, "Result should match expected result") - }) - } -} - -func TestResetAllowUpdate(t *testing.T) { - fm, err := NewFlagManager(flagsPath) - if err != nil { - log.Fatal(err) - } - - flag_allow_update, _ := fm.parser.GetFlag("flag_allow_update") - - // Define test cases - tests := []struct { - name string - input []byte - expectedResult resource.Result - }{ - { - name: "Resets allow update", - input: []byte(""), - expectedResult: resource.Result{ - FlagReset: []uint32{flag_allow_update}, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Create the Handlers instance with the mock flag manager - h := &Handlers{ - flagManager: fm.parser, - } - - // Call the method - res, err := h.ResetAllowUpdate(context.Background(), "reset_allow update", tt.input) - if err != nil { - t.Error(err) - } - - // Assert that the Result FlagSet has the required flags after language switch - assert.Equal(t, res, tt.expectedResult, "Flags should be equal to account created") - }) - } -} - -func TestResetAccountAuthorized(t *testing.T) { - fm, err := NewFlagManager(flagsPath) - if err != nil { - log.Fatal(err) - } - - flag_account_authorized, _ := fm.parser.GetFlag("flag_account_authorized") - - // Define test cases - tests := []struct { - name string - input []byte - expectedResult resource.Result - }{ - { - name: "Resets account authorized", - input: []byte(""), - expectedResult: resource.Result{ - FlagReset: []uint32{flag_account_authorized}, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Create the Handlers instance with the mock flag manager - h := &Handlers{ - flagManager: fm.parser, - } - - // Call the method - res, err := h.ResetAccountAuthorized(context.Background(), "reset_account_authorized", tt.input) - if err != nil { - t.Error(err) - } - - // Assert that the Result FlagSet has the required flags after language switch - assert.Equal(t, res, tt.expectedResult, "Result should contain flag(s) that have been reset") - }) - } -} - -func TestIncorrectPinReset(t *testing.T) { - sessionId := "session123" - ctx, store := InitializeTestStore(t) - fm, err := NewFlagManager(flagsPath) - - if err != nil { - log.Fatal(err) - } - - flag_incorrect_pin, _ := fm.parser.GetFlag("flag_incorrect_pin") - flag_account_blocked, _ := fm.parser.GetFlag("flag_account_blocked") - - ctx = context.WithValue(ctx, "SessionId", sessionId) - - // Define test cases - tests := []struct { - name string - input []byte - attempts uint8 - expectedResult resource.Result - }{ - { - name: "Test when incorrect PIN attempts is 2", - input: []byte(""), - expectedResult: resource.Result{ - FlagReset: []uint32{flag_incorrect_pin}, - Content: "1", //Expected remaining PIN attempts - }, - attempts: 2, - }, - { - name: "Test incorrect pin reset when incorrect PIN attempts is 1", - input: []byte(""), - expectedResult: resource.Result{ - FlagReset: []uint32{flag_incorrect_pin}, - Content: "2", //Expected remaining PIN attempts - }, - attempts: 1, - }, - { - name: "Test incorrect pin reset when incorrect PIN attempts is 1", - input: []byte(""), - expectedResult: resource.Result{ - FlagReset: []uint32{flag_incorrect_pin}, - Content: "2", //Expected remaining PIN attempts - }, - attempts: 1, - }, - { - name: "Test incorrect pin reset when incorrect PIN attempts is 3(account expected to be blocked)", - input: []byte(""), - expectedResult: resource.Result{ - FlagReset: []uint32{flag_incorrect_pin}, - FlagSet: []uint32{flag_account_blocked}, - }, - attempts: 3, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - - if err := store.WriteEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS, []byte(strconv.Itoa(int(tt.attempts)))); err != nil { - t.Fatal(err) - } - - // Create the Handlers instance with the mock flag manager - h := &Handlers{ - flagManager: fm.parser, - userdataStore: store, - } - - // Call the method - res, err := h.ResetIncorrectPin(ctx, "reset_incorrect_pin", tt.input) - if err != nil { - t.Error(err) - } - - // Assert that the Result FlagSet has the required flags after language switch - assert.Equal(t, res, tt.expectedResult, "Result should contain flag(s) that have been reset") - }) - } -} - -func TestResetIncorrectYob(t *testing.T) { - fm, err := NewFlagManager(flagsPath) - if err != nil { - log.Fatal(err) - } - - flag_incorrect_date_format, _ := fm.parser.GetFlag("flag_incorrect_date_format") - - // Define test cases - tests := []struct { - name string - input []byte - expectedResult resource.Result - }{ - { - name: "Test incorrect yob reset", - input: []byte(""), - expectedResult: resource.Result{ - FlagReset: []uint32{flag_incorrect_date_format}, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Create the Handlers instance with the mock flag manager - h := &Handlers{ - flagManager: fm.parser, - } - - // Call the method - res, err := h.ResetIncorrectYob(context.Background(), "reset_incorrect_yob", tt.input) - if err != nil { - t.Error(err) - } - - // Assert that the Result FlagSet has the required flags after language switch - assert.Equal(t, res, tt.expectedResult, "Result should contain flag(s) that have been reset") - }) - } -} - -func TestAuthorize(t *testing.T) { - sessionId := "session123" - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - fm, err := NewFlagManager(flagsPath) - if err != nil { - t.Logf(err.Error()) - } - - // Create required mocks - mockAccountService := new(mocks.MockAccountService) - mockState := state.NewState(16) - flag_incorrect_pin, _ := fm.GetFlag("flag_incorrect_pin") - flag_account_authorized, _ := fm.GetFlag("flag_account_authorized") - flag_allow_update, _ := fm.GetFlag("flag_allow_update") - - // Set 1234 is the correct account pin - accountPIN := "1234" - - h := &Handlers{ - userdataStore: store, - accountService: mockAccountService, - flagManager: fm.parser, - st: mockState, - } - - tests := []struct { - name string - input []byte - expectedResult resource.Result - }{ - { - name: "Test with correct pin", - input: []byte("1234"), - expectedResult: resource.Result{ - FlagReset: []uint32{flag_incorrect_pin}, - FlagSet: []uint32{flag_allow_update, flag_account_authorized}, - }, - }, - { - name: "Test with incorrect pin", - input: []byte("1235"), - expectedResult: resource.Result{ - FlagReset: []uint32{flag_account_authorized}, - FlagSet: []uint32{flag_incorrect_pin}, - }, - }, - { - name: "Test with pin that is not a 4 digit", - input: []byte("1235aqds"), - expectedResult: resource.Result{}, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Hash the PIN - hashedPIN, err := common.HashPIN(accountPIN) - if err != nil { - logg.ErrorCtxf(ctx, "failed to hash temporaryPin", "error", err) - t.Fatal(err) - } - - err = store.WriteEntry(ctx, sessionId, common.DATA_ACCOUNT_PIN, []byte(hashedPIN)) - if err != nil { - t.Fatal(err) - } - - // Call the method under test - res, err := h.Authorize(ctx, "authorize", []byte(tt.input)) - - // Assert that no errors occurred - assert.NoError(t, err) - - //Assert that the account created flag has been set to the result - assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") - }) - } -} - -func TestVerifyYob(t *testing.T) { - fm, err := NewFlagManager(flagsPath) - if err != nil { - t.Logf(err.Error()) - } - - sessionId := "session123" - // Create required mocks - mockAccountService := new(mocks.MockAccountService) - mockState := state.NewState(16) - flag_incorrect_date_format, _ := fm.parser.GetFlag("flag_incorrect_date_format") - ctx := context.WithValue(context.Background(), "SessionId", sessionId) - - h := &Handlers{ - accountService: mockAccountService, - flagManager: fm.parser, - st: mockState, - } - - tests := []struct { - name string - input []byte - expectedResult resource.Result - }{ - { - name: "Test with correct yob", - input: []byte("1980"), - expectedResult: resource.Result{ - FlagReset: []uint32{flag_incorrect_date_format}, - }, - }, - { - name: "Test with incorrect yob", - input: []byte("sgahaha"), - expectedResult: resource.Result{ - FlagSet: []uint32{flag_incorrect_date_format}, - }, - }, - { - name: "Test with numeric but less 4 digits", - input: []byte("123"), - expectedResult: resource.Result{ - FlagSet: []uint32{flag_incorrect_date_format}, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Call the method under test - res, err := h.VerifyYob(ctx, "verify_yob", []byte(tt.input)) - - // Assert that no errors occurred - assert.NoError(t, err) - - //Assert that the account created flag has been set to the result - assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") - }) - } -} - -func TestVerifyCreatePin(t *testing.T) { - sessionId := "session123" - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - fm, err := NewFlagManager(flagsPath) - if err != nil { - t.Logf(err.Error()) - } - - // Create required mocks - mockAccountService := new(mocks.MockAccountService) - mockState := state.NewState(16) - - flag_valid_pin, _ := fm.parser.GetFlag("flag_valid_pin") - flag_pin_mismatch, _ := fm.parser.GetFlag("flag_pin_mismatch") - flag_pin_set, _ := fm.parser.GetFlag("flag_pin_set") - - h := &Handlers{ - userdataStore: store, - accountService: mockAccountService, - flagManager: fm.parser, - st: mockState, - } - - tests := []struct { - name string - input []byte - expectedResult resource.Result - }{ - { - name: "Test with correct PIN confirmation", - input: []byte("1234"), - expectedResult: resource.Result{ - FlagSet: []uint32{flag_valid_pin, flag_pin_set}, - FlagReset: []uint32{flag_pin_mismatch}, - }, - }, - { - name: "Test with PIN that does not match first ", - input: []byte("1324"), - expectedResult: resource.Result{ - FlagSet: []uint32{flag_pin_mismatch}, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte("1234")) - if err != nil { - t.Fatal(err) - } - - // Call the method under test - res, err := h.VerifyCreatePin(ctx, "verify_create_pin", []byte(tt.input)) - - // Assert that no errors occurred - assert.NoError(t, err) - - //Assert that the account created flag has been set to the result - assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") - }) - } -} - -func TestCheckAccountStatus(t *testing.T) { - sessionId := "session123" - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - fm, err := NewFlagManager(flagsPath) - if err != nil { - t.Logf(err.Error()) - } - flag_account_success, _ := fm.GetFlag("flag_account_success") - flag_account_pending, _ := fm.GetFlag("flag_account_pending") - flag_api_error, _ := fm.GetFlag("flag_api_call_error") - - tests := []struct { - name string - publicKey []byte - response *models.TrackStatusResult - expectedResult resource.Result - }{ - { - name: "Test when account is on the Sarafu network", - publicKey: []byte("TrackingId1234"), - response: &models.TrackStatusResult{ - Active: true, - }, - expectedResult: resource.Result{ - FlagSet: []uint32{flag_account_success}, - FlagReset: []uint32{flag_api_error, flag_account_pending}, - }, - }, - { - name: "Test when the account is not yet on the sarafu network", - publicKey: []byte("TrackingId1234"), - response: &models.TrackStatusResult{ - Active: false, - }, - expectedResult: resource.Result{ - FlagSet: []uint32{flag_account_pending}, - FlagReset: []uint32{flag_api_error, flag_account_success}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - mockAccountService := new(mocks.MockAccountService) - - h := &Handlers{ - userdataStore: store, - accountService: mockAccountService, - flagManager: fm.parser, - } - - err = store.WriteEntry(ctx, sessionId, common.DATA_PUBLIC_KEY, []byte(tt.publicKey)) - if err != nil { - t.Fatal(err) - } - - mockAccountService.On("TrackAccountStatus", string(tt.publicKey)).Return(tt.response, nil) - - // Call the method under test - res, _ := h.CheckAccountStatus(ctx, "check_account_status", []byte("")) - - // Assert that no errors occurred - assert.NoError(t, err) - - //Assert that the account created flag has been set to the result - assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") - }) - } -} - -func TestTransactionReset(t *testing.T) { - sessionId := "session123" - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - fm, err := NewFlagManager(flagsPath) - if err != nil { - t.Logf(err.Error()) - } - - flag_invalid_recipient, _ := fm.GetFlag("flag_invalid_recipient") - flag_invalid_recipient_with_invite, _ := fm.GetFlag("flag_invalid_recipient_with_invite") - - mockAccountService := new(mocks.MockAccountService) - - h := &Handlers{ - userdataStore: store, - accountService: mockAccountService, - flagManager: fm.parser, - } - tests := []struct { - name string - input []byte - status string - expectedResult resource.Result - }{ - { - name: "Test transaction reset for amount and recipient", - expectedResult: resource.Result{ - FlagReset: []uint32{flag_invalid_recipient, flag_invalid_recipient_with_invite}, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Call the method under test - res, _ := h.TransactionReset(ctx, "transaction_reset", tt.input) - - // Assert that no errors occurred - assert.NoError(t, err) - - //Assert that the account created flag has been set to the result - assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") - }) - } -} - -func TestResetTransactionAmount(t *testing.T) { - sessionId := "session123" - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - fm, err := NewFlagManager(flagsPath) - if err != nil { - t.Logf(err.Error()) - } - - flag_invalid_amount, _ := fm.parser.GetFlag("flag_invalid_amount") - - mockAccountService := new(mocks.MockAccountService) - - h := &Handlers{ - userdataStore: store, - accountService: mockAccountService, - flagManager: fm.parser, - } - - tests := []struct { - name string - expectedResult resource.Result - }{ - { - name: "Test amount reset", - expectedResult: resource.Result{ - FlagReset: []uint32{flag_invalid_amount}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Call the method under test - res, _ := h.ResetTransactionAmount(ctx, "transaction_reset_amount", []byte("")) - - // Assert that no errors occurred - assert.NoError(t, err) - - //Assert that the account created flag has been set to the result - assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") - }) - } -} - -func TestInitiateTransaction(t *testing.T) { - sessionId := "254712345678" - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - fm, err := NewFlagManager(flagsPath) - if err != nil { - t.Logf(err.Error()) - } - account_authorized_flag, _ := fm.parser.GetFlag("flag_account_authorized") - - mockAccountService := new(mocks.MockAccountService) - - h := &Handlers{ - userdataStore: store, - accountService: mockAccountService, - flagManager: fm.parser, - } - - tests := []struct { - name string - TemporaryValue []byte - ActiveSym []byte - StoredAmount []byte - TransferAmount string - PublicKey []byte - Recipient []byte - ActiveDecimal []byte - ActiveAddress []byte - TransferResponse *models.TokenTransferResponse - expectedResult resource.Result - }{ - { - name: "Test initiate transaction", - TemporaryValue: []byte("0711223344"), - ActiveSym: []byte("SRF"), - StoredAmount: []byte("1.00"), - TransferAmount: "1000000", - PublicKey: []byte("0X13242618721"), - Recipient: []byte("0x12415ass27192"), - ActiveDecimal: []byte("6"), - ActiveAddress: []byte("0xd4c288865Ce"), - TransferResponse: &models.TokenTransferResponse{ - TrackingId: "1234567890", - }, - expectedResult: resource.Result{ - FlagReset: []uint32{account_authorized_flag}, - Content: "Your request has been sent. 0711223344 will receive 1.00 SRF from 254712345678.", - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(tt.TemporaryValue)) - if err != nil { - t.Fatal(err) - } - err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_SYM, []byte(tt.ActiveSym)) - if err != nil { - t.Fatal(err) - } - err = store.WriteEntry(ctx, sessionId, common.DATA_AMOUNT, []byte(tt.StoredAmount)) - if err != nil { - t.Fatal(err) - } - err = store.WriteEntry(ctx, sessionId, common.DATA_PUBLIC_KEY, []byte(tt.PublicKey)) - if err != nil { - t.Fatal(err) - } - err = store.WriteEntry(ctx, sessionId, common.DATA_RECIPIENT, []byte(tt.Recipient)) - if err != nil { - t.Fatal(err) - } - err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_DECIMAL, []byte(tt.ActiveDecimal)) - if err != nil { - t.Fatal(err) - } - err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_ADDRESS, []byte(tt.ActiveAddress)) - if err != nil { - t.Fatal(err) - } - - mockAccountService.On("TokenTransfer").Return(tt.TransferResponse, nil) - - // Call the method under test - res, _ := h.InitiateTransaction(ctx, "transaction_reset_amount", []byte("")) - - // Assert that no errors occurred - assert.NoError(t, err) - - //Assert that the account created flag has been set to the result - assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") - }) - } -} - -func TestQuit(t *testing.T) { - fm, err := NewFlagManager(flagsPath) - if err != nil { - t.Logf(err.Error()) - } - flag_account_authorized, _ := fm.parser.GetFlag("flag_account_authorized") - - mockAccountService := new(mocks.MockAccountService) - - sessionId := "session123" - - ctx := context.WithValue(context.Background(), "SessionId", sessionId) - - h := &Handlers{ - accountService: mockAccountService, - flagManager: fm.parser, - } - tests := []struct { - name string - input []byte - status string - expectedResult resource.Result - }{ - { - name: "Test quit message", - expectedResult: resource.Result{ - FlagReset: []uint32{flag_account_authorized}, - Content: "Thank you for using Sarafu. Goodbye!", - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - - // Call the method under test - res, _ := h.Quit(ctx, "test_quit", tt.input) - - // Assert that no errors occurred - assert.NoError(t, err) - - //Assert that the account created flag has been set to the result - assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") - }) - } -} - -func TestValidateAmount(t *testing.T) { - fm, err := NewFlagManager(flagsPath) - if err != nil { - t.Logf(err.Error()) - } - - sessionId := "session123" - - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - flag_invalid_amount, _ := fm.parser.GetFlag("flag_invalid_amount") - - mockAccountService := new(mocks.MockAccountService) - - h := &Handlers{ - userdataStore: store, - accountService: mockAccountService, - flagManager: fm.parser, - } - tests := []struct { - name string - input []byte - activeBal []byte - balance string - expectedResult resource.Result - }{ - { - name: "Test with valid amount", - input: []byte("4.10"), - activeBal: []byte("5"), - expectedResult: resource.Result{ - Content: "4.10", - }, - }, - { - name: "Test with amount larger than active balance", - input: []byte("5.02"), - activeBal: []byte("5"), - expectedResult: resource.Result{ - FlagSet: []uint32{flag_invalid_amount}, - Content: "5.02", - }, - }, - { - name: "Test with invalid amount format", - input: []byte("0.02ms"), - activeBal: []byte("5"), - expectedResult: resource.Result{ - FlagSet: []uint32{flag_invalid_amount}, - Content: "0.02ms", - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_BAL, []byte(tt.activeBal)) - if err != nil { - t.Fatal(err) - } - - // Call the method under test - res, _ := h.ValidateAmount(ctx, "test_validate_amount", tt.input) - - // Assert no errors occurred - assert.NoError(t, err) - - // Assert the result matches the expected result - assert.Equal(t, tt.expectedResult, res, "Expected result should match actual result") - }) - } -} - -func TestValidateRecipient(t *testing.T) { - fm, err := NewFlagManager(flagsPath) - if err != nil { - log.Fatal(err) - } - - sessionId := "session123" - publicKey := "0X13242618721" - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - flag_invalid_recipient, _ := fm.parser.GetFlag("flag_invalid_recipient") - flag_invalid_recipient_with_invite, _ := fm.parser.GetFlag("flag_invalid_recipient_with_invite") - - // Define test cases - tests := []struct { - name string - input []byte - expectedResult resource.Result - }{ - { - name: "Test with invalid recepient", - input: []byte("7?1234"), - expectedResult: resource.Result{ - FlagSet: []uint32{flag_invalid_recipient}, - Content: "7?1234", - }, - }, - { - name: "Test with valid unregistered recepient", - input: []byte("0712345678"), - expectedResult: resource.Result{ - FlagSet: []uint32{flag_invalid_recipient_with_invite}, - Content: "0712345678", - }, - }, - { - name: "Test with valid registered recepient", - input: []byte("0711223344"), - expectedResult: resource.Result{}, - }, - { - name: "Test with address", - input: []byte("0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9"), - expectedResult: resource.Result{}, - }, - { - name: "Test with alias recepient", - input: []byte("alias123"), - expectedResult: resource.Result{}, - }, - } - - // store a public key for the valid recipient - err = store.WriteEntry(ctx, "+254711223344", common.DATA_PUBLIC_KEY, []byte(publicKey)) - if err != nil { - t.Fatal(err) - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - mockAccountService := new(mocks.MockAccountService) - // Create the Handlers instance - h := &Handlers{ - flagManager: fm.parser, - userdataStore: store, - accountService: mockAccountService, - } - - aliasResponse := &dataserviceapi.AliasAddress{ - Address: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", - } - - mockAccountService.On("CheckAliasAddress", string(tt.input)).Return(aliasResponse, nil) - - // Call the method - res, err := h.ValidateRecipient(ctx, "validate_recepient", tt.input) - - if err != nil { - t.Error(err) - } - - // Assert that the Result FlagSet has the required flags after language switch - assert.Equal(t, res, tt.expectedResult, "Result should contain flag(s) that have been reset") - }) - } -} - -func TestCheckBalance(t *testing.T) { - ctx, store := InitializeTestStore(t) - - tests := []struct { - name string - sessionId string - publicKey string - activeSym string - activeBal string - expectedResult resource.Result - expectError bool - }{ - { - name: "User with active sym", - sessionId: "session123", - publicKey: "0X98765432109", - activeSym: "ETH", - activeBal: "1.5", - expectedResult: resource.Result{Content: "Balance: 1.50 ETH\n"}, - expectError: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - mockAccountService := new(mocks.MockAccountService) - ctx := context.WithValue(ctx, "SessionId", tt.sessionId) - - h := &Handlers{ - userdataStore: store, - accountService: mockAccountService, - } - - err := store.WriteEntry(ctx, tt.sessionId, common.DATA_ACTIVE_SYM, []byte(tt.activeSym)) - if err != nil { - t.Fatal(err) - } - err = store.WriteEntry(ctx, tt.sessionId, common.DATA_ACTIVE_BAL, []byte(tt.activeBal)) - if err != nil { - t.Fatal(err) - } - - res, err := h.CheckBalance(ctx, "check_balance", []byte("")) - - if tt.expectError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - assert.Equal(t, tt.expectedResult, res, "Result should match expected output") - } - - mockAccountService.AssertExpectations(t) - }) - } -} - -func TestGetProfile(t *testing.T) { - sessionId := "session123" - ctx, store := InitializeTestStore(t) - - mockAccountService := new(mocks.MockAccountService) - mockState := state.NewState(16) - - h := &Handlers{ - userdataStore: store, - accountService: mockAccountService, - st: mockState, - } - - tests := []struct { - name string - languageCode string - keys []common.DataTyp - profileInfo []string - result resource.Result - }{ - { - name: "Test with full profile information in eng", - keys: []common.DataTyp{common.DATA_FAMILY_NAME, common.DATA_FIRST_NAME, common.DATA_GENDER, common.DATA_OFFERINGS, common.DATA_LOCATION, common.DATA_YOB}, - profileInfo: []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976"}, - languageCode: "eng", - result: resource.Result{ - Content: fmt.Sprintf( - "Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n", - "John Doee", "Male", "49", "Kilifi", "Bananas", - ), - }, - }, - { - name: "Test with with profile information in swa", - keys: []common.DataTyp{common.DATA_FAMILY_NAME, common.DATA_FIRST_NAME, common.DATA_GENDER, common.DATA_OFFERINGS, common.DATA_LOCATION, common.DATA_YOB}, - profileInfo: []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976"}, - languageCode: "swa", - result: resource.Result{ - Content: fmt.Sprintf( - "Jina: %s\nJinsia: %s\nUmri: %s\nEneo: %s\nUnauza: %s\n", - "John Doee", "Male", "49", "Kilifi", "Bananas", - ), - }, - }, - { - name: "Test with with profile information with language that is not yet supported", - keys: []common.DataTyp{common.DATA_FAMILY_NAME, common.DATA_FIRST_NAME, common.DATA_GENDER, common.DATA_OFFERINGS, common.DATA_LOCATION, common.DATA_YOB}, - profileInfo: []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976"}, - languageCode: "nor", - result: resource.Result{ - Content: fmt.Sprintf( - "Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n", - "John Doee", "Male", "49", "Kilifi", "Bananas", - ), - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ctx = context.WithValue(ctx, "SessionId", sessionId) - ctx = context.WithValue(ctx, "Language", lang.Language{ - Code: tt.languageCode, - }) - for index, key := range tt.keys { - err := store.WriteEntry(ctx, sessionId, key, []byte(tt.profileInfo[index])) - if err != nil { - t.Fatal(err) - } - } - - res, _ := h.GetProfileInfo(ctx, "get_profile_info", []byte("")) - - //Assert that the result set to content is what was expected - assert.Equal(t, res, tt.result, "Result should contain profile information served back to user") - }) - } -} - -func TestVerifyNewPin(t *testing.T) { - sessionId := "session123" - - fm, _ := NewFlagManager(flagsPath) - - flag_valid_pin, _ := fm.parser.GetFlag("flag_valid_pin") - mockAccountService := new(mocks.MockAccountService) - h := &Handlers{ - flagManager: fm.parser, - accountService: mockAccountService, - } - ctx := context.WithValue(context.Background(), "SessionId", sessionId) - - tests := []struct { - name string - input []byte - expectedResult resource.Result - }{ - { - name: "Test with valid pin", - input: []byte("1234"), - expectedResult: resource.Result{ - FlagSet: []uint32{flag_valid_pin}, - }, - }, - { - name: "Test with invalid pin", - input: []byte("123"), - expectedResult: resource.Result{ - FlagReset: []uint32{flag_valid_pin}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - //Call the function under test - res, _ := h.VerifyNewPin(ctx, "verify_new_pin", tt.input) - - //Assert that the result set to content is what was expected - assert.Equal(t, res, tt.expectedResult, "Result should contain flags set according to user input") - }) - } -} - -func TestConfirmPin(t *testing.T) { - sessionId := "session123" - - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - fm, _ := NewFlagManager(flagsPath) - flag_pin_mismatch, _ := fm.parser.GetFlag("flag_pin_mismatch") - mockAccountService := new(mocks.MockAccountService) - h := &Handlers{ - userdataStore: store, - flagManager: fm.parser, - accountService: mockAccountService, - } - - tests := []struct { - name string - input []byte - temporarypin []byte - expectedResult resource.Result - }{ - { - name: "Test with correct pin confirmation", - input: []byte("1234"), - temporarypin: []byte("1234"), - expectedResult: resource.Result{ - FlagReset: []uint32{flag_pin_mismatch}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Set up the expected behavior of the mock - err := store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(tt.temporarypin)) - if err != nil { - t.Fatal(err) - } - - //Call the function under test - res, _ := h.ConfirmPinChange(ctx, "confirm_pin_change", tt.temporarypin) - - //Assert that the result set to content is what was expected - assert.Equal(t, res, tt.expectedResult, "Result should contain flags set according to user input") - - }) - } -} - -func TestFetchCommunityBalance(t *testing.T) { - - // Define test data - sessionId := "session123" - ctx, store := InitializeTestStore(t) - - tests := []struct { - name string - languageCode string - expectedResult resource.Result - }{ - { - name: "Test community balance content when language is english", - expectedResult: resource.Result{ - Content: "Community Balance: 0.00", - }, - languageCode: "eng", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - - mockAccountService := new(mocks.MockAccountService) - mockState := state.NewState(16) - - h := &Handlers{ - userdataStore: store, - st: mockState, - accountService: mockAccountService, - } - ctx = context.WithValue(ctx, "SessionId", sessionId) - ctx = context.WithValue(ctx, "Language", lang.Language{ - Code: tt.languageCode, - }) - - // Call the method - res, _ := h.FetchCommunityBalance(ctx, "fetch_community_balance", []byte("")) - - //Assert that the result set to content is what was expected - assert.Equal(t, res, tt.expectedResult, "Result should match expected result") - }) - } -} - -func TestSetDefaultVoucher(t *testing.T) { - sessionId := "session123" - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - fm, err := NewFlagManager(flagsPath) - if err != nil { - t.Logf(err.Error()) - } - flag_no_active_voucher, err := fm.GetFlag("flag_no_active_voucher") - if err != nil { - t.Logf(err.Error()) - } - - publicKey := "0X13242618721" - - tests := []struct { - name string - vouchersResp []dataserviceapi.TokenHoldings - expectedResult resource.Result - }{ - { - name: "Test no vouchers available", - vouchersResp: []dataserviceapi.TokenHoldings{}, - expectedResult: resource.Result{ - FlagSet: []uint32{flag_no_active_voucher}, - }, - }, - { - name: "Test set default voucher when no active voucher is set", - vouchersResp: []dataserviceapi.TokenHoldings{ - dataserviceapi.TokenHoldings{ - ContractAddress: "0x123", - TokenSymbol: "TOKEN1", - TokenDecimals: "18", - Balance: "100", - }, - }, - expectedResult: resource.Result{}, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - mockAccountService := new(mocks.MockAccountService) - - h := &Handlers{ - userdataStore: store, - accountService: mockAccountService, - flagManager: fm.parser, - } - - err := store.WriteEntry(ctx, sessionId, common.DATA_PUBLIC_KEY, []byte(publicKey)) - if err != nil { - t.Fatal(err) - } - - mockAccountService.On("FetchVouchers", string(publicKey)).Return(tt.vouchersResp, nil) - - res, err := h.SetDefaultVoucher(ctx, "set_default_voucher", []byte("some-input")) - - assert.NoError(t, err) - - assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") - - mockAccountService.AssertExpectations(t) - }) - } -} - -func TestCheckVouchers(t *testing.T) { - mockAccountService := new(mocks.MockAccountService) - sessionId := "session123" - publicKey := "0X13242618721" - - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - spdb := InitializeTestSubPrefixDb(t, ctx) - - h := &Handlers{ - userdataStore: store, - accountService: mockAccountService, - prefixDb: spdb, - } - - err := store.WriteEntry(ctx, sessionId, common.DATA_PUBLIC_KEY, []byte(publicKey)) - if err != nil { - t.Fatal(err) - } - - mockVouchersResponse := []dataserviceapi.TokenHoldings{ - {ContractAddress: "0xd4c288865Ce", TokenSymbol: "SRF", TokenDecimals: "6", Balance: "100"}, - {ContractAddress: "0x41c188d63Qa", TokenSymbol: "MILO", TokenDecimals: "4", Balance: "200"}, - } - - expectedSym := []byte("1:SRF\n2:MILO") - - mockAccountService.On("FetchVouchers", string(publicKey)).Return(mockVouchersResponse, nil) - - _, err = h.CheckVouchers(ctx, "check_vouchers", []byte("")) - assert.NoError(t, err) - - // Read voucher sym data from the store - voucherData, err := spdb.Get(ctx, common.ToBytes(common.DATA_VOUCHER_SYMBOLS)) - if err != nil { - t.Fatal(err) - } - - // assert that the data is stored correctly - assert.Equal(t, expectedSym, voucherData) - - mockAccountService.AssertExpectations(t) -} - -func TestGetVoucherList(t *testing.T) { - sessionId := "session123" - - ctx := context.WithValue(context.Background(), "SessionId", sessionId) - - spdb := InitializeTestSubPrefixDb(t, ctx) - - // Initialize Handlers - h := &Handlers{ - prefixDb: spdb, - ReplaceSeparatorFunc: mockReplaceSeparator, - } - - mockSyms := []byte("1:SRF\n2:MILO") - - // Put voucher sym data from the store - err := spdb.Put(ctx, common.ToBytes(common.DATA_VOUCHER_SYMBOLS), mockSyms) - if err != nil { - t.Fatal(err) - } - - expectedSyms := []byte("1: SRF\n2: MILO") - - res, err := h.GetVoucherList(ctx, "", []byte("")) - - assert.NoError(t, err) - assert.Equal(t, res.Content, string(expectedSyms)) -} - -func TestViewVoucher(t *testing.T) { - fm, err := NewFlagManager(flagsPath) - if err != nil { - t.Logf(err.Error()) - } - ctx, store := InitializeTestStore(t) - sessionId := "session123" - - ctx = context.WithValue(ctx, "SessionId", sessionId) - - spdb := InitializeTestSubPrefixDb(t, ctx) - - h := &Handlers{ - userdataStore: store, - flagManager: fm.parser, - prefixDb: spdb, - } - - // Define mock voucher data - mockData := map[common.DataTyp][]byte{ - common.DATA_VOUCHER_SYMBOLS: []byte("1:SRF\n2:MILO"), - common.DATA_VOUCHER_BALANCES: []byte("1:100\n2:200"), - common.DATA_VOUCHER_DECIMALS: []byte("1:6\n2:4"), - common.DATA_VOUCHER_ADDRESSES: []byte("1:0xd4c288865Ce\n2:0x41c188d63Qa"), - } - - // Put the data - for key, value := range mockData { - err = spdb.Put(ctx, []byte(common.ToBytes(key)), []byte(value)) - if err != nil { - t.Fatal(err) - } - } - - res, err := h.ViewVoucher(ctx, "view_voucher", []byte("1")) - assert.NoError(t, err) - assert.Equal(t, res.Content, "Symbol: SRF\nBalance: 100") -} - -func TestSetVoucher(t *testing.T) { - ctx, store := InitializeTestStore(t) - sessionId := "session123" - - ctx = context.WithValue(ctx, "SessionId", sessionId) - - h := &Handlers{ - userdataStore: store, - } - - // Define the temporary voucher data - tempData := &dataserviceapi.TokenHoldings{ - TokenSymbol: "SRF", - Balance: "200", - TokenDecimals: "6", - ContractAddress: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", - } - - expectedData := fmt.Sprintf("%s,%s,%s,%s", tempData.TokenSymbol, tempData.Balance, tempData.TokenDecimals, tempData.ContractAddress) - - // store the expectedData - if err := store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(expectedData)); err != nil { - t.Fatal(err) - } - - res, err := h.SetVoucher(ctx, "set_voucher", []byte("")) - - assert.NoError(t, err) - - assert.Equal(t, string(tempData.TokenSymbol), res.Content) -} - -func TestGetVoucherDetails(t *testing.T) { - ctx, store := InitializeTestStore(t) - fm, err := NewFlagManager(flagsPath) - if err != nil { - t.Logf(err.Error()) - } - mockAccountService := new(mocks.MockAccountService) - - sessionId := "session123" - ctx = context.WithValue(ctx, "SessionId", sessionId) - expectedResult := resource.Result{} - - tokA_AAddress := "0x0000000000000000000000000000000000000000" - - h := &Handlers{ - userdataStore: store, - flagManager: fm.parser, - accountService: mockAccountService, - } - err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_ADDRESS, []byte(tokA_AAddress)) - if err != nil { - t.Fatal(err) - } - tokenDetails := &models.VoucherDataResult{ - TokenName: "Token A", - TokenSymbol: "TOKA", - TokenLocation: "Kilifi,Kenya", - TokenCommodity: "Farming", - } - expectedResult.Content = fmt.Sprintf( - "Name: %s\nSymbol: %s\nCommodity: %s\nLocation: %s", tokenDetails.TokenName, tokenDetails.TokenSymbol, tokenDetails.TokenCommodity, tokenDetails.TokenLocation, - ) - mockAccountService.On("VoucherData", string(tokA_AAddress)).Return(tokenDetails, nil) - - res, err := h.GetVoucherDetails(ctx, "SessionId", []byte("")) - assert.NoError(t, err) - assert.Equal(t, expectedResult, res) -} - -func TestCountIncorrectPINAttempts(t *testing.T) { - ctx, store := InitializeTestStore(t) - sessionId := "session123" - ctx = context.WithValue(ctx, "SessionId", sessionId) - attempts := uint8(2) - - h := &Handlers{ - userdataStore: store, - } - err := store.WriteEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS, []byte(strconv.Itoa(int(attempts)))) - if err != nil { - t.Logf(err.Error()) - } - err = h.incrementIncorrectPINAttempts(ctx, sessionId) - if err != nil { - t.Logf(err.Error()) - } - - attemptsAfterCount, err := store.ReadEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS) - if err != nil { - t.Logf(err.Error()) - } - pinAttemptsValue, _ := strconv.ParseUint(string(attemptsAfterCount), 0, 64) - pinAttemptsCount := uint8(pinAttemptsValue) - expectedAttempts := attempts + 1 - assert.Equal(t, pinAttemptsCount, expectedAttempts) - -} - -func TestResetIncorrectPINAttempts(t *testing.T) { - ctx, store := InitializeTestStore(t) - sessionId := "session123" - ctx = context.WithValue(ctx, "SessionId", sessionId) - - err := store.WriteEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS, []byte(string("2"))) - if err != nil { - t.Logf(err.Error()) - } - - h := &Handlers{ - userdataStore: store, - } - h.resetIncorrectPINAttempts(ctx, sessionId) - incorrectAttempts, err := store.ReadEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS) - - if err != nil { - t.Logf(err.Error()) - } - assert.Equal(t, "0", string(incorrectAttempts)) - -} - -func TestPersistLanguageCode(t *testing.T) { - ctx, store := InitializeTestStore(t) - - sessionId := "session123" - ctx = context.WithValue(ctx, "SessionId", sessionId) - - h := &Handlers{ - userdataStore: store, - } - tests := []struct { - name string - code string - expectedLanguageCode string - }{ - { - name: "Set Default Language (English)", - code: "eng", - expectedLanguageCode: "eng", - }, - { - name: "Set Swahili Language", - code: "swa", - expectedLanguageCode: "swa", - }, - } - - for _, test := range tests { - err := h.persistLanguageCode(ctx, test.code) - if err != nil { - t.Logf(err.Error()) - } - code, err := store.ReadEntry(ctx, sessionId, common.DATA_SELECTED_LANGUAGE_CODE) - - assert.Equal(t, test.expectedLanguageCode, string(code)) - } - -} diff --git a/internal/handlers/handler_service.go b/internal/handlers/handler_service.go deleted file mode 100644 index 6fb355b..0000000 --- a/internal/handlers/handler_service.go +++ /dev/null @@ -1,141 +0,0 @@ -package handlers - -import ( - "context" - "strings" - - "git.defalsify.org/vise.git/asm" - "git.defalsify.org/vise.git/db" - "git.defalsify.org/vise.git/engine" - "git.defalsify.org/vise.git/persist" - "git.defalsify.org/vise.git/resource" - - "git.grassecon.net/urdt/ussd/internal/handlers/application" - "git.grassecon.net/urdt/ussd/internal/utils" - "git.grassecon.net/urdt/ussd/remote" -) - -type HandlerService interface { - GetHandler() (*application.Handlers, error) -} - -func getParser(fp string, debug bool) (*asm.FlagParser, error) { - flagParser := asm.NewFlagParser().WithDebug() - _, err := flagParser.Load(fp) - if err != nil { - return nil, err - } - return flagParser, nil -} - -type LocalHandlerService struct { - Parser *asm.FlagParser - DbRs *resource.DbResource - Pe *persist.Persister - UserdataStore *db.Db - AdminStore *utils.AdminStore - Cfg engine.Config - Rs resource.Resource -} - -func NewLocalHandlerService(ctx context.Context, fp string, debug bool, dbResource *resource.DbResource, cfg engine.Config, rs resource.Resource) (*LocalHandlerService, error) { - parser, err := getParser(fp, debug) - if err != nil { - return nil, err - } - adminstore, err := utils.NewAdminStore(ctx, "admin_numbers") - if err != nil { - return nil, err - } - return &LocalHandlerService{ - Parser: parser, - DbRs: dbResource, - AdminStore: adminstore, - Cfg: cfg, - Rs: rs, - }, nil -} - -func (ls *LocalHandlerService) SetPersister(Pe *persist.Persister) { - ls.Pe = Pe -} - -func (ls *LocalHandlerService) SetDataStore(db *db.Db) { - ls.UserdataStore = db -} - -func (ls *LocalHandlerService) GetHandler(accountService remote.AccountServiceInterface) (*application.Handlers, error) { - replaceSeparatorFunc := func(input string) string { - return strings.ReplaceAll(input, ":", ls.Cfg.MenuSeparator) - } - - appHandlers, err := application.NewHandlers(ls.Parser, *ls.UserdataStore, ls.AdminStore, accountService, replaceSeparatorFunc) - if err != nil { - return nil, err - } - appHandlers = appHandlers.WithPersister(ls.Pe) - ls.DbRs.AddLocalFunc("set_language", appHandlers.SetLanguage) - ls.DbRs.AddLocalFunc("create_account", appHandlers.CreateAccount) - ls.DbRs.AddLocalFunc("save_temporary_pin", appHandlers.SaveTemporaryPin) - ls.DbRs.AddLocalFunc("verify_create_pin", appHandlers.VerifyCreatePin) - ls.DbRs.AddLocalFunc("check_identifier", appHandlers.CheckIdentifier) - ls.DbRs.AddLocalFunc("check_account_status", appHandlers.CheckAccountStatus) - ls.DbRs.AddLocalFunc("authorize_account", appHandlers.Authorize) - ls.DbRs.AddLocalFunc("quit", appHandlers.Quit) - ls.DbRs.AddLocalFunc("check_balance", appHandlers.CheckBalance) - ls.DbRs.AddLocalFunc("validate_recipient", appHandlers.ValidateRecipient) - ls.DbRs.AddLocalFunc("transaction_reset", appHandlers.TransactionReset) - ls.DbRs.AddLocalFunc("invite_valid_recipient", appHandlers.InviteValidRecipient) - ls.DbRs.AddLocalFunc("max_amount", appHandlers.MaxAmount) - ls.DbRs.AddLocalFunc("validate_amount", appHandlers.ValidateAmount) - ls.DbRs.AddLocalFunc("reset_transaction_amount", appHandlers.ResetTransactionAmount) - ls.DbRs.AddLocalFunc("get_recipient", appHandlers.GetRecipient) - ls.DbRs.AddLocalFunc("get_sender", appHandlers.GetSender) - ls.DbRs.AddLocalFunc("get_amount", appHandlers.GetAmount) - ls.DbRs.AddLocalFunc("reset_incorrect", appHandlers.ResetIncorrectPin) - ls.DbRs.AddLocalFunc("save_firstname", appHandlers.SaveFirstname) - ls.DbRs.AddLocalFunc("save_familyname", appHandlers.SaveFamilyname) - ls.DbRs.AddLocalFunc("save_gender", appHandlers.SaveGender) - ls.DbRs.AddLocalFunc("save_location", appHandlers.SaveLocation) - ls.DbRs.AddLocalFunc("save_yob", appHandlers.SaveYob) - ls.DbRs.AddLocalFunc("save_offerings", appHandlers.SaveOfferings) - ls.DbRs.AddLocalFunc("reset_account_authorized", appHandlers.ResetAccountAuthorized) - ls.DbRs.AddLocalFunc("reset_allow_update", appHandlers.ResetAllowUpdate) - ls.DbRs.AddLocalFunc("get_profile_info", appHandlers.GetProfileInfo) - ls.DbRs.AddLocalFunc("verify_yob", appHandlers.VerifyYob) - ls.DbRs.AddLocalFunc("reset_incorrect_date_format", appHandlers.ResetIncorrectYob) - ls.DbRs.AddLocalFunc("initiate_transaction", appHandlers.InitiateTransaction) - ls.DbRs.AddLocalFunc("verify_new_pin", appHandlers.VerifyNewPin) - ls.DbRs.AddLocalFunc("confirm_pin_change", appHandlers.ConfirmPinChange) - ls.DbRs.AddLocalFunc("quit_with_help", appHandlers.QuitWithHelp) - ls.DbRs.AddLocalFunc("fetch_community_balance", appHandlers.FetchCommunityBalance) - ls.DbRs.AddLocalFunc("set_default_voucher", appHandlers.SetDefaultVoucher) - ls.DbRs.AddLocalFunc("check_vouchers", appHandlers.CheckVouchers) - ls.DbRs.AddLocalFunc("get_vouchers", appHandlers.GetVoucherList) - ls.DbRs.AddLocalFunc("view_voucher", appHandlers.ViewVoucher) - ls.DbRs.AddLocalFunc("set_voucher", appHandlers.SetVoucher) - ls.DbRs.AddLocalFunc("get_voucher_details", appHandlers.GetVoucherDetails) - ls.DbRs.AddLocalFunc("reset_valid_pin", appHandlers.ResetValidPin) - ls.DbRs.AddLocalFunc("check_pin_mismatch", appHandlers.CheckBlockedNumPinMisMatch) - ls.DbRs.AddLocalFunc("validate_blocked_number", appHandlers.ValidateBlockedNumber) - ls.DbRs.AddLocalFunc("retrieve_blocked_number", appHandlers.RetrieveBlockedNumber) - ls.DbRs.AddLocalFunc("reset_unregistered_number", appHandlers.ResetUnregisteredNumber) - ls.DbRs.AddLocalFunc("reset_others_pin", appHandlers.ResetOthersPin) - ls.DbRs.AddLocalFunc("save_others_temporary_pin", appHandlers.SaveOthersTemporaryPin) - ls.DbRs.AddLocalFunc("get_current_profile_info", appHandlers.GetCurrentProfileInfo) - ls.DbRs.AddLocalFunc("check_transactions", appHandlers.CheckTransactions) - ls.DbRs.AddLocalFunc("get_transactions", appHandlers.GetTransactionsList) - ls.DbRs.AddLocalFunc("view_statement", appHandlers.ViewTransactionStatement) - ls.DbRs.AddLocalFunc("update_all_profile_items", appHandlers.UpdateAllProfileItems) - ls.DbRs.AddLocalFunc("set_back", appHandlers.SetBack) - ls.DbRs.AddLocalFunc("show_blocked_account", appHandlers.ShowBlockedAccount) - - return appHandlers, nil -} - -// TODO: enable setting of sessionId on engine init time -func (ls *LocalHandlerService) GetEngine() *engine.DefaultEngine { - en := engine.NewEngine(ls.Cfg, ls.Rs) - en = en.WithPersister(ls.Pe) - return en -} diff --git a/internal/handlers/single.go b/internal/handlers/single.go index 1b11a64..6ce7081 100644 --- a/internal/handlers/single.go +++ b/internal/handlers/single.go @@ -10,7 +10,7 @@ import ( "git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/resource" - "git.grassecon.net/urdt/ussd/internal/storage" + "git.grassecon.net/grassrootseconomics/visedriver/storage" ) var ( diff --git a/internal/http/at/parse.go b/internal/http/at/parse.go deleted file mode 100644 index 76e84e7..0000000 --- a/internal/http/at/parse.go +++ /dev/null @@ -1,120 +0,0 @@ -package at - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - "strings" - - "git.grassecon.net/urdt/ussd/common" - "git.grassecon.net/urdt/ussd/internal/handlers" -) - -type ATRequestParser struct { -} - -func (arp *ATRequestParser) GetSessionId(ctx context.Context, rq any) (string, error) { - rqv, ok := rq.(*http.Request) - if !ok { - logg.Warnf("got an invalid request", "req", rq) - return "", handlers.ErrInvalidRequest - } - // Capture body (if any) for logging - body, err := io.ReadAll(rqv.Body) - if err != nil { - logg.Warnf("failed to read request body", "err", err) - return "", fmt.Errorf("failed to read request body: %v", err) - } - // Reset the body for further reading - rqv.Body = io.NopCloser(bytes.NewReader(body)) - - // Log the body as JSON - bodyLog := map[string]string{"body": string(body)} - logBytes, err := json.Marshal(bodyLog) - if err != nil { - logg.Warnf("failed to marshal request body", "err", err) - } else { - decodedStr := string(logBytes) - sessionId, err := extractATSessionId(decodedStr) - if err != nil { - ctx = context.WithValue(ctx, "AT-SessionId", sessionId) - } - logg.DebugCtxf(ctx, "Received request:", decodedStr) - } - - if err := rqv.ParseForm(); err != nil { - logg.Warnf("failed to parse form data", "err", err) - return "", fmt.Errorf("failed to parse form data: %v", err) - } - - phoneNumber := rqv.FormValue("phoneNumber") - if phoneNumber == "" { - return "", fmt.Errorf("no phone number found") - } - - formattedNumber, err := common.FormatPhoneNumber(phoneNumber) - if err != nil { - logg.Warnf("failed to format phone number", "err", err) - return "", fmt.Errorf("failed to format number") - } - - return formattedNumber, nil -} - -func (arp *ATRequestParser) GetInput(rq any) ([]byte, error) { - rqv, ok := rq.(*http.Request) - if !ok { - return nil, handlers.ErrInvalidRequest - } - if err := rqv.ParseForm(); err != nil { - return nil, fmt.Errorf("failed to parse form data: %v", err) - } - - text := rqv.FormValue("text") - - parts := strings.Split(text, "*") - if len(parts) == 0 { - return nil, fmt.Errorf("no input found") - } - - trimmedInput := strings.TrimSpace(parts[len(parts)-1]) - return []byte(trimmedInput), nil -} - -func parseQueryParams(query string) map[string]string { - params := make(map[string]string) - - queryParams := strings.Split(query, "&") - for _, param := range queryParams { - // Split each key-value pair by '=' - parts := strings.SplitN(param, "=", 2) - if len(parts) == 2 { - params[parts[0]] = parts[1] - } - } - return params -} - -func extractATSessionId(decodedStr string) (string, error) { - var data map[string]string - err := json.Unmarshal([]byte(decodedStr), &data) - - if err != nil { - logg.Errorf("Error unmarshalling JSON: %v", err) - return "", nil - } - decodedBody, err := url.QueryUnescape(data["body"]) - if err != nil { - logg.Errorf("Error URL-decoding body: %v", err) - return "", nil - } - params := parseQueryParams(decodedBody) - - sessionId := params["sessionId"] - return sessionId, nil - -} diff --git a/internal/http/at/server.go b/internal/http/at/server.go deleted file mode 100644 index 3399dd5..0000000 --- a/internal/http/at/server.go +++ /dev/null @@ -1,98 +0,0 @@ -package at - -import ( - "io" - "net/http" - - "git.defalsify.org/vise.git/logging" - "git.grassecon.net/urdt/ussd/internal/handlers" - httpserver "git.grassecon.net/urdt/ussd/internal/http" -) - -var ( - logg = logging.NewVanilla().WithDomain("atserver").WithContextKey("SessionId").WithContextKey("AT-SessionId") -) - -type ATSessionHandler struct { - *httpserver.SessionHandler -} - -func NewATSessionHandler(h handlers.RequestHandler) *ATSessionHandler { - return &ATSessionHandler{ - SessionHandler: httpserver.ToSessionHandler(h), - } -} - -func (ash *ATSessionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { - var code int - var err error - - rqs := handlers.RequestSession{ - Ctx: req.Context(), - Writer: w, - } - - rp := ash.GetRequestParser() - cfg := ash.GetConfig() - cfg.SessionId, err = rp.GetSessionId(req.Context(), req) - if err != nil { - logg.ErrorCtxf(rqs.Ctx, "", "header processing error", err) - ash.WriteError(w, 400, err) - return - } - rqs.Config = cfg - rqs.Input, err = rp.GetInput(req) - if err != nil { - logg.ErrorCtxf(rqs.Ctx, "", "header processing error", err) - ash.WriteError(w, 400, err) - return - } - - rqs, err = ash.Process(rqs) - switch err { - case nil: // set code to 200 if no err - code = 200 - case handlers.ErrStorage, handlers.ErrEngineInit, handlers.ErrEngineExec, handlers.ErrEngineType: - code = 500 - default: - code = 500 - } - - if code != 200 { - ash.WriteError(w, 500, err) - return - } - - w.WriteHeader(200) - w.Header().Set("Content-Type", "text/plain") - rqs, err = ash.Output(rqs) - if err != nil { - ash.WriteError(w, 500, err) - return - } - - rqs, err = ash.Reset(rqs) - if err != nil { - ash.WriteError(w, 500, err) - return - } -} - -func (ash *ATSessionHandler) Output(rqs handlers.RequestSession) (handlers.RequestSession, error) { - var err error - var prefix string - - if rqs.Continue { - prefix = "CON " - } else { - prefix = "END " - } - - _, err = io.WriteString(rqs.Writer, prefix) - if err != nil { - return rqs, err - } - - _, err = rqs.Engine.Flush(rqs.Ctx, rqs.Writer) - return rqs, err -} diff --git a/internal/http/at/server_test.go b/internal/http/at/server_test.go deleted file mode 100644 index dd45c25..0000000 --- a/internal/http/at/server_test.go +++ /dev/null @@ -1,234 +0,0 @@ -package at - -import ( - "context" - "errors" - "io" - "net/http" - "net/http/httptest" - "net/url" - "strings" - "testing" - - "git.defalsify.org/vise.git/engine" - "git.grassecon.net/urdt/ussd/internal/handlers" - "git.grassecon.net/urdt/ussd/internal/testutil/mocks/httpmocks" -) - -func TestNewATSessionHandler(t *testing.T) { - mockHandler := &httpmocks.MockRequestHandler{} - ash := NewATSessionHandler(mockHandler) - - if ash == nil { - t.Fatal("NewATSessionHandler returned nil") - } - - if ash.SessionHandler == nil { - t.Fatal("SessionHandler is nil") - } -} - -func TestATSessionHandler_ServeHTTP(t *testing.T) { - tests := []struct { - name string - setupMocks func(*httpmocks.MockRequestHandler, *httpmocks.MockRequestParser, *httpmocks.MockEngine) - formData url.Values - expectedStatus int - expectedBody string - }{ - { - name: "Successful request", - setupMocks: func(mh *httpmocks.MockRequestHandler, mrp *httpmocks.MockRequestParser, me *httpmocks.MockEngine) { - mrp.GetSessionIdFunc = func(rq any) (string, error) { - req := rq.(*http.Request) - return req.FormValue("phoneNumber"), nil - } - mrp.GetInputFunc = func(rq any) ([]byte, error) { - req := rq.(*http.Request) - text := req.FormValue("text") - parts := strings.Split(text, "*") - return []byte(parts[len(parts)-1]), nil - } - mh.ProcessFunc = func(rqs handlers.RequestSession) (handlers.RequestSession, error) { - rqs.Continue = true - rqs.Engine = me - return rqs, nil - } - mh.GetConfigFunc = func() engine.Config { return engine.Config{} } - mh.GetRequestParserFunc = func() handlers.RequestParser { return mrp } - mh.OutputFunc = func(rs handlers.RequestSession) (handlers.RequestSession, error) { return rs, nil } - mh.ResetFunc = func(rs handlers.RequestSession) (handlers.RequestSession, error) { return rs, nil } - me.FlushFunc = func(context.Context, io.Writer) (int, error) { return 0, nil } - }, - formData: url.Values{ - "phoneNumber": []string{"+1234567890"}, - "text": []string{"1*2*3"}, - }, - expectedStatus: http.StatusOK, - expectedBody: "CON ", - }, - { - name: "GetSessionId error", - setupMocks: func(mh *httpmocks.MockRequestHandler, mrp *httpmocks.MockRequestParser, me *httpmocks.MockEngine) { - mrp.GetSessionIdFunc = func(rq any) (string, error) { - return "", errors.New("no phone number found") - } - mh.GetConfigFunc = func() engine.Config { return engine.Config{} } - mh.GetRequestParserFunc = func() handlers.RequestParser { return mrp } - }, - formData: url.Values{ - "text": []string{"1*2*3"}, - }, - expectedStatus: http.StatusBadRequest, - expectedBody: "", - }, - { - name: "GetInput error", - setupMocks: func(mh *httpmocks.MockRequestHandler, mrp *httpmocks.MockRequestParser, me *httpmocks.MockEngine) { - mrp.GetSessionIdFunc = func(rq any) (string, error) { - req := rq.(*http.Request) - return req.FormValue("phoneNumber"), nil - } - mrp.GetInputFunc = func(rq any) ([]byte, error) { - return nil, errors.New("no input found") - } - mh.GetConfigFunc = func() engine.Config { return engine.Config{} } - mh.GetRequestParserFunc = func() handlers.RequestParser { return mrp } - }, - formData: url.Values{ - "phoneNumber": []string{"+1234567890"}, - }, - expectedStatus: http.StatusBadRequest, - expectedBody: "", - }, - { - name: "Process error", - setupMocks: func(mh *httpmocks.MockRequestHandler, mrp *httpmocks.MockRequestParser, me *httpmocks.MockEngine) { - mrp.GetSessionIdFunc = func(rq any) (string, error) { - req := rq.(*http.Request) - return req.FormValue("phoneNumber"), nil - } - mrp.GetInputFunc = func(rq any) ([]byte, error) { - req := rq.(*http.Request) - text := req.FormValue("text") - parts := strings.Split(text, "*") - return []byte(parts[len(parts)-1]), nil - } - mh.ProcessFunc = func(rqs handlers.RequestSession) (handlers.RequestSession, error) { - return rqs, handlers.ErrStorage - } - mh.GetConfigFunc = func() engine.Config { return engine.Config{} } - mh.GetRequestParserFunc = func() handlers.RequestParser { return mrp } - }, - formData: url.Values{ - "phoneNumber": []string{"+1234567890"}, - "text": []string{"1*2*3"}, - }, - expectedStatus: http.StatusInternalServerError, - expectedBody: "", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - mockHandler := &httpmocks.MockRequestHandler{} - mockRequestParser := &httpmocks.MockRequestParser{} - mockEngine := &httpmocks.MockEngine{} - tt.setupMocks(mockHandler, mockRequestParser, mockEngine) - - ash := NewATSessionHandler(mockHandler) - - req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(tt.formData.Encode())) - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - w := httptest.NewRecorder() - - ash.ServeHTTP(w, req) - - if w.Code != tt.expectedStatus { - t.Errorf("Expected status %d, got %d", tt.expectedStatus, w.Code) - } - - if tt.expectedBody != "" && w.Body.String() != tt.expectedBody { - t.Errorf("Expected body %q, got %q", tt.expectedBody, w.Body.String()) - } - }) - } -} - -func TestATSessionHandler_Output(t *testing.T) { - tests := []struct { - name string - input handlers.RequestSession - expectedPrefix string - expectedError bool - }{ - { - name: "Continue true", - input: handlers.RequestSession{ - Continue: true, - Engine: &httpmocks.MockEngine{ - FlushFunc: func(context.Context, io.Writer) (int, error) { - return 0, nil - }, - }, - Writer: &httpmocks.MockWriter{}, - }, - expectedPrefix: "CON ", - expectedError: false, - }, - { - name: "Continue false", - input: handlers.RequestSession{ - Continue: false, - Engine: &httpmocks.MockEngine{ - FlushFunc: func(context.Context, io.Writer) (int, error) { - return 0, nil - }, - }, - Writer: &httpmocks.MockWriter{}, - }, - expectedPrefix: "END ", - expectedError: false, - }, - { - name: "Flush error", - input: handlers.RequestSession{ - Continue: true, - Engine: &httpmocks.MockEngine{ - FlushFunc: func(context.Context, io.Writer) (int, error) { - return 0, errors.New("write error") - }, - }, - Writer: &httpmocks.MockWriter{}, - }, - expectedPrefix: "CON ", - expectedError: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ash := &ATSessionHandler{} - _, err := ash.Output(tt.input) - - if tt.expectedError && err == nil { - t.Error("Expected an error, but got nil") - } - - if !tt.expectedError && err != nil { - t.Errorf("Unexpected error: %v", err) - } - - mw := tt.input.Writer.(*httpmocks.MockWriter) - if !mw.WriteStringCalled { - t.Error("WriteString was not called") - } - - if mw.WrittenString != tt.expectedPrefix { - t.Errorf("Expected prefix %q, got %q", tt.expectedPrefix, mw.WrittenString) - } - }) - } -} - - diff --git a/internal/http/server.go b/internal/http/server.go deleted file mode 100644 index 0a2533e..0000000 --- a/internal/http/server.go +++ /dev/null @@ -1,91 +0,0 @@ -package http - -import ( - "net/http" - "strconv" - - "git.defalsify.org/vise.git/logging" - - "git.grassecon.net/urdt/ussd/internal/handlers" -) - -var ( - logg = logging.NewVanilla().WithDomain("httpserver") -) - -type SessionHandler struct { - handlers.RequestHandler -} - -func ToSessionHandler(h handlers.RequestHandler) *SessionHandler { - return &SessionHandler{ - RequestHandler: h, - } -} - -func (f *SessionHandler) WriteError(w http.ResponseWriter, code int, err error) { - s := err.Error() - w.Header().Set("Content-Length", strconv.Itoa(len(s))) - w.WriteHeader(code) - _, err = w.Write([]byte(s)) - if err != nil { - logg.Errorf("error writing error!!", "err", err, "olderr", s) - w.WriteHeader(500) - } -} - -func (f *SessionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { - var code int - var err error - var perr error - - rqs := handlers.RequestSession{ - Ctx: req.Context(), - Writer: w, - } - - rp := f.GetRequestParser() - cfg := f.GetConfig() - cfg.SessionId, err = rp.GetSessionId(req.Context(), req) - if err != nil { - logg.ErrorCtxf(rqs.Ctx, "", "header processing error", err) - f.WriteError(w, 400, err) - } - rqs.Config = cfg - rqs.Input, err = rp.GetInput(req) - if err != nil { - logg.ErrorCtxf(rqs.Ctx, "", "header processing error", err) - f.WriteError(w, 400, err) - return - } - - rqs, err = f.Process(rqs) - switch err { - case handlers.ErrStorage: - code = 500 - case handlers.ErrEngineInit: - code = 500 - case handlers.ErrEngineExec: - code = 500 - default: - code = 200 - } - - if code != 200 { - f.WriteError(w, 500, err) - return - } - - w.WriteHeader(200) - w.Header().Set("Content-Type", "text/plain") - rqs, err = f.Output(rqs) - rqs, perr = f.Reset(rqs) - if err != nil { - f.WriteError(w, 500, err) - return - } - if perr != nil { - f.WriteError(w, 500, perr) - return - } -} diff --git a/internal/ssh/keystore.go b/internal/ssh/keystore.go deleted file mode 100644 index 206d684..0000000 --- a/internal/ssh/keystore.go +++ /dev/null @@ -1,65 +0,0 @@ -package ssh - -import ( - "context" - "fmt" - "os" - "path" - - "golang.org/x/crypto/ssh" - - "git.defalsify.org/vise.git/db" - - "git.grassecon.net/urdt/ussd/internal/storage" - dbstorage "git.grassecon.net/urdt/ussd/internal/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.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.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() error { - return s.store.Close() -} diff --git a/internal/ssh/ssh.go b/internal/ssh/ssh.go deleted file mode 100644 index 8209187..0000000 --- a/internal/ssh/ssh.go +++ /dev/null @@ -1,284 +0,0 @@ -package ssh - -import ( - "context" - "encoding/hex" - "encoding/base64" - "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/urdt/ussd/internal/handlers" - "git.grassecon.net/urdt/ussd/internal/storage" - "git.grassecon.net/urdt/ussd/remote" -) - -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.ConnData - ResourceDir string - 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, s.ResourceDir) - - 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: clear up why pointer here and by-value other cmds - accountService := &remote.AccountService{} - hl, err := lhs.GetHandler(accountService) - if err != nil { - return nil, nil, err - } - - en := lhs.GetEngine() - en = en.WithFirst(hl.Init) - if s.Debug { - en = en.WithDebug(nil) - } - // TODO: this is getting very hacky! - closer := func() { - err := menuStorageService.Close() - 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() - 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) - } -} diff --git a/internal/testutil/engine.go b/internal/testutil/engine.go deleted file mode 100644 index 5d581ba..0000000 --- a/internal/testutil/engine.go +++ /dev/null @@ -1,209 +0,0 @@ -package testutil - -import ( - "context" - "fmt" - "log" - "net/url" - "os" - "path" - "path/filepath" - "time" - - "git.defalsify.org/vise.git/engine" - "git.defalsify.org/vise.git/logging" - "git.defalsify.org/vise.git/resource" - "git.grassecon.net/urdt/ussd/config" - "git.grassecon.net/urdt/ussd/initializers" - "git.grassecon.net/urdt/ussd/internal/handlers" - "git.grassecon.net/urdt/ussd/internal/storage" - "git.grassecon.net/urdt/ussd/internal/testutil/testservice" - "git.grassecon.net/urdt/ussd/internal/testutil/testtag" - "git.grassecon.net/urdt/ussd/remote" - "github.com/jackc/pgx/v5/pgxpool" - testdataloader "github.com/peteole/testdata-loader" -) - -var ( - logg = logging.NewVanilla() - baseDir = testdataloader.GetBasePath() - scriptDir = path.Join(baseDir, "services", "registration") - setDbType string - setConnStr string - setDbSchema string -) - -func init() { - initializers.LoadEnvVariablesPath(baseDir) - config.LoadConfig() -} - -// SetDatabase updates the database used by TestEngine -func SetDatabase(database, connStr, dbSchema string) { - setDbType = database - setConnStr = connStr - setDbSchema = dbSchema -} - -// CleanDatabase removes all test data from the database -func CleanDatabase() { - if setDbType == "postgres" { - ctx := context.Background() - // Update the connection string with the new search path - updatedConnStr, err := updateSearchPath(setConnStr, setDbSchema) - if err != nil { - log.Fatalf("Failed to update search path: %v", err) - } - - dbConn, err := pgxpool.New(ctx, updatedConnStr) - if err != nil { - log.Fatalf("Failed to connect to database for cleanup: %v", err) - } - defer dbConn.Close() - - query := fmt.Sprintf("DELETE FROM %s.kv_vise;", setDbSchema) - _, execErr := dbConn.Exec(ctx, query) - if execErr != nil { - log.Printf("Failed to cleanup table %s.kv_vise: %v", setDbSchema, execErr) - } else { - log.Printf("Successfully cleaned up table %s.kv_vise", setDbSchema) - } - } else { - setConnStr, _ := filepath.Abs(setConnStr) - if err := os.RemoveAll(setConnStr); err != nil { - log.Fatalf("Failed to delete state store %s: %v", setConnStr, err) - } - } -} - -// updateSearchPath updates the search_path (schema) to be used in the connection -func updateSearchPath(connStr string, newSearchPath string) (string, error) { - u, err := url.Parse(connStr) - if err != nil { - return "", fmt.Errorf("invalid connection string: %w", err) - } - - // Parse the query parameters - q := u.Query() - - // Update or add the search_path parameter - q.Set("search_path", newSearchPath) - - // Rebuild the connection string with updated parameters - u.RawQuery = q.Encode() - - return u.String(), nil -} - -func TestEngine(sessionId string) (engine.Engine, func(), chan bool) { - var err error - ctx := context.Background() - ctx = context.WithValue(ctx, "SessionId", sessionId) - pfp := path.Join(scriptDir, "pp.csv") - - var eventChannel = make(chan bool) - - cfg := engine.Config{ - Root: "root", - SessionId: sessionId, - OutputSize: uint32(160), - FlagCount: uint32(128), - } - - if setDbType == "postgres" { - setConnStr = config.DbConn - setConnStr, err = updateSearchPath(setConnStr, setDbSchema) - if err != nil { - fmt.Println("Error:", err) - os.Exit(1) - } - } else { - setConnStr, err = filepath.Abs(setConnStr) - if err != nil { - fmt.Fprintf(os.Stderr, "connstr err: %v", err) - os.Exit(1) - } - } - - conn, err := storage.ToConnData(setConnStr) - if err != nil { - fmt.Fprintf(os.Stderr, "connstr parse err: %v", err) - os.Exit(1) - } - - resourceDir := scriptDir - menuStorageService := storage.NewMenuStorageService(conn, resourceDir) - - rs, err := menuStorageService.GetResource(ctx) - if err != nil { - fmt.Fprintf(os.Stderr, "resource error: %v", err) - os.Exit(1) - } - - pe, err := menuStorageService.GetPersister(ctx) - if err != nil { - fmt.Fprintf(os.Stderr, "persister error: %v", err) - os.Exit(1) - } - - userDataStore, err := menuStorageService.GetUserdataDb(ctx) - if err != nil { - fmt.Fprintf(os.Stderr, "userdb error: %v", err) - os.Exit(1) - } - - dbResource, ok := rs.(*resource.DbResource) - if !ok { - fmt.Fprintf(os.Stderr, "dbresource cast error") - os.Exit(1) - } - - lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs) - lhs.SetDataStore(&userDataStore) - lhs.SetPersister(pe) - - if err != nil { - fmt.Fprintf(os.Stderr, err.Error()) - os.Exit(1) - } - - if testtag.AccountService == nil { - testtag.AccountService = &remote.AccountService{} - } - - switch testtag.AccountService.(type) { - case *testservice.TestAccountService: - go func() { - eventChannel <- false - }() - case *remote.AccountService: - go func() { - time.Sleep(5 * time.Second) // Wait for 5 seconds - eventChannel <- true - }() - default: - panic("Unknown account service type") - } - - hl, err := lhs.GetHandler(testtag.AccountService) - if err != nil { - fmt.Fprintf(os.Stderr, err.Error()) - os.Exit(1) - } - - en := lhs.GetEngine() - en = en.WithFirst(hl.Init) - cleanFn := func() { - err := en.Finish() - if err != nil { - logg.Errorf(err.Error()) - } - - err = menuStorageService.Close() - if err != nil { - logg.Errorf(err.Error()) - } - logg.Infof("testengine storage closed") - } - return en, cleanFn, eventChannel -} diff --git a/internal/testutil/engine_test.go b/internal/testutil/engine_test.go deleted file mode 100644 index f747468..0000000 --- a/internal/testutil/engine_test.go +++ /dev/null @@ -1,15 +0,0 @@ -package testutil - -import ( - "testing" -) - -func TestCreateEngine(t *testing.T) { - o, clean, eventC := TestEngine("foo") - defer clean() - defer func() { - <-eventC - close(eventC) - }() - _ = o -} diff --git a/internal/testutil/mocks/httpmocks/request_handler_mock.go b/internal/testutil/mocks/httpmocks/request_handler_mock.go deleted file mode 100644 index f17abce..0000000 --- a/internal/testutil/mocks/httpmocks/request_handler_mock.go +++ /dev/null @@ -1,47 +0,0 @@ -package httpmocks - -import ( - "git.defalsify.org/vise.git/engine" - "git.defalsify.org/vise.git/persist" - "git.defalsify.org/vise.git/resource" - "git.grassecon.net/urdt/ussd/internal/handlers" -) - -// MockRequestHandler implements handlers.RequestHandler interface for testing -type MockRequestHandler struct { - ProcessFunc func(handlers.RequestSession) (handlers.RequestSession, error) - GetConfigFunc func() engine.Config - GetEngineFunc func(cfg engine.Config, rs resource.Resource, pe *persist.Persister) engine.Engine - OutputFunc func(rs handlers.RequestSession) (handlers.RequestSession, error) - ResetFunc func(rs handlers.RequestSession) (handlers.RequestSession, error) - ShutdownFunc func() - GetRequestParserFunc func() handlers.RequestParser -} - -func (m *MockRequestHandler) Process(rqs handlers.RequestSession) (handlers.RequestSession, error) { - return m.ProcessFunc(rqs) -} - -func (m *MockRequestHandler) GetConfig() engine.Config { - return m.GetConfigFunc() -} - -func (m *MockRequestHandler) GetEngine(cfg engine.Config, rs resource.Resource, pe *persist.Persister) engine.Engine { - return m.GetEngineFunc(cfg, rs, pe) -} - -func (m *MockRequestHandler) Output(rs handlers.RequestSession) (handlers.RequestSession, error) { - return m.OutputFunc(rs) -} - -func (m *MockRequestHandler) Reset(rs handlers.RequestSession) (handlers.RequestSession, error) { - return m.ResetFunc(rs) -} - -func (m *MockRequestHandler) Shutdown() { - m.ShutdownFunc() -} - -func (m *MockRequestHandler) GetRequestParser() handlers.RequestParser { - return m.GetRequestParserFunc() -} diff --git a/internal/testutil/mocks/service_mock.go b/internal/testutil/mocks/service_mock.go deleted file mode 100644 index 59d7205..0000000 --- a/internal/testutil/mocks/service_mock.go +++ /dev/null @@ -1,54 +0,0 @@ -package mocks - -import ( - "context" - - "git.grassecon.net/urdt/ussd/models" - dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" - "github.com/stretchr/testify/mock" -) - -// MockAccountService implements AccountServiceInterface for testing -type MockAccountService struct { - mock.Mock -} - -func (m *MockAccountService) CreateAccount(ctx context.Context) (*models.AccountResult, error) { - args := m.Called() - return args.Get(0).(*models.AccountResult), args.Error(1) -} - -func (m *MockAccountService) CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResult, error) { - args := m.Called(publicKey) - return args.Get(0).(*models.BalanceResult), args.Error(1) -} - -func (m *MockAccountService) TrackAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResult, error) { - args := m.Called(trackingId) - return args.Get(0).(*models.TrackStatusResult), args.Error(1) -} - -func (m *MockAccountService) FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) { - args := m.Called(publicKey) - return args.Get(0).([]dataserviceapi.TokenHoldings), args.Error(1) -} - -func (m *MockAccountService) FetchTransactions(ctx context.Context, publicKey string) ([]dataserviceapi.Last10TxResponse, error) { - args := m.Called(publicKey) - return args.Get(0).([]dataserviceapi.Last10TxResponse), args.Error(1) -} - -func (m *MockAccountService) VoucherData(ctx context.Context, address string) (*models.VoucherDataResult, error) { - args := m.Called(address) - return args.Get(0).(*models.VoucherDataResult), args.Error(1) -} - -func (m *MockAccountService) TokenTransfer(ctx context.Context, amount, from, to, tokenAddress string) (*models.TokenTransferResponse, error) { - args := m.Called() - return args.Get(0).(*models.TokenTransferResponse), args.Error(1) -} - -func (m *MockAccountService) CheckAliasAddress(ctx context.Context, alias string) (*dataserviceapi.AliasAddress, error) { - args := m.Called(alias) - return args.Get(0).(*dataserviceapi.AliasAddress), args.Error(1) -} diff --git a/internal/testutil/testservice/account_service.go b/internal/testutil/testservice/account_service.go deleted file mode 100644 index 96dacbc..0000000 --- a/internal/testutil/testservice/account_service.go +++ /dev/null @@ -1,62 +0,0 @@ -package testservice - -import ( - "context" - "encoding/json" - - "git.grassecon.net/urdt/ussd/models" - dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" -) - -type TestAccountService struct { -} - -func (tas *TestAccountService) CreateAccount(ctx context.Context) (*models.AccountResult, error) { - return &models.AccountResult{ - TrackingId: "075ccc86-f6ef-4d33-97d5-e91cfb37aa0d", - PublicKey: "0x623EFAFa8868df4B934dd12a8B26CB3Dd75A7AdD", - }, nil -} - -func (tas *TestAccountService) CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResult, error) { - balanceResponse := &models.BalanceResult{ - Balance: "0.003 CELO", - Nonce: json.Number("0"), - } - return balanceResponse, nil -} - -func (tas *TestAccountService) TrackAccountStatus(ctx context.Context, publicKey string) (*models.TrackStatusResult, error) { - return &models.TrackStatusResult{ - Active: true, - }, nil -} - -func (tas *TestAccountService) FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) { - return []dataserviceapi.TokenHoldings{ - dataserviceapi.TokenHoldings{ - ContractAddress: "0x6CC75A06ac72eB4Db2eE22F781F5D100d8ec03ee", - TokenSymbol: "SRF", - TokenDecimals: "6", - Balance: "2745987", - }, - }, nil -} - -func (tas *TestAccountService) FetchTransactions(ctx context.Context, publicKey string) ([]dataserviceapi.Last10TxResponse, error) { - return []dataserviceapi.Last10TxResponse{}, nil -} - -func (m TestAccountService) VoucherData(ctx context.Context, address string) (*models.VoucherDataResult, error) { - return &models.VoucherDataResult{}, nil -} - -func (tas *TestAccountService) TokenTransfer(ctx context.Context, amount, from, to, tokenAddress string) (*models.TokenTransferResponse, error) { - return &models.TokenTransferResponse{ - TrackingId: "e034d147-747d-42ea-928d-b5a7cb3426af", - }, nil -} - -func (m TestAccountService) CheckAliasAddress(ctx context.Context, alias string) (*dataserviceapi.AliasAddress, error) { - return &dataserviceapi.AliasAddress{}, nil -} diff --git a/internal/testutil/testtag/offlinetest.go b/internal/testutil/testtag/offlinetest.go deleted file mode 100644 index 831bf09..0000000 --- a/internal/testutil/testtag/offlinetest.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build !online - -package testtag - -import ( - "git.grassecon.net/urdt/ussd/remote" - accountservice "git.grassecon.net/urdt/ussd/internal/testutil/testservice" -) - -var ( - AccountService remote.AccountServiceInterface = &accountservice.TestAccountService{} -) diff --git a/internal/testutil/testtag/onlinetest.go b/internal/testutil/testtag/onlinetest.go deleted file mode 100644 index 835ba0d..0000000 --- a/internal/testutil/testtag/onlinetest.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build online - -package testtag - -import "git.grassecon.net/urdt/ussd/remote" - -var ( - AccountService remote.AccountServiceInterface -) diff --git a/menutraversal_test/group_test.json b/menutraversal_test/group_test.json deleted file mode 100644 index 0ffb49f..0000000 --- a/menutraversal_test/group_test.json +++ /dev/null @@ -1,443 +0,0 @@ -{ - "groups": [ - { - "name": "my_account_change_pin", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "3", - "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" - }, - { - "input": "5", - "expectedContent": "PIN Management\n1:Change PIN\n2:Reset other's PIN\n0:Back" - }, - { - "input": "1", - "expectedContent": "Enter your old PIN\n\n0:Back" - }, - { - "input": "1234", - "expectedContent": "Enter a new four number PIN:\n\n0:Back" - }, - { - "input": "1234", - "expectedContent": "Confirm your new PIN:\n\n0:Back" - }, - { - "input": "1234", - "expectedContent": "Your PIN change request has been successful\n\n0:Back\n9:Quit" - }, - { - "input": "0", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - } - ] - }, - { - "name": "menu_my_account_language_change", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "3", - "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" - }, - { - "input": "2", - "expectedContent": "Please enter your PIN:" - }, - { - "input": "1235", - "expectedContent": "Incorrect PIN. You have: 2 remaining attempt(s).\n1:Retry\n9:Quit" - }, - { - "input": "1", - "expectedContent": "Please enter your PIN:" - }, - { - "input": "1234", - "expectedContent": "Select language:\n1:English\n2:Kiswahili" - }, - { - "input": "1", - "expectedContent": "Your language change request was successful.\n0:Back\n9:Quit" - }, - { - "input": "0", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - } - ] - }, - { - "name": "menu_my_account_check_my_balance", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "3", - "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" - }, - { - "input": "3", - "expectedContent": "Balances:\n1:My balance\n2:Community balance\n0:Back" - }, - { - "input": "1", - "expectedContent": "Please enter your PIN:" - }, - { - "input": "1235", - "expectedContent": "Incorrect PIN. You have: 2 remaining attempt(s).\n1:Retry\n9:Quit" - }, - { - "input": "1", - "expectedContent": "Please enter your PIN:" - }, - { - "input": "1234", - "expectedContent": "Balance: {balance}\n\n0:Back\n9:Quit" - }, - { - "input": "0", - "expectedContent": "Balances:\n1:My balance\n2:Community balance\n0:Back" - }, - { - "input": "0", - "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" - }, - { - "input": "0", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - } - ] - }, - { - "name": "menu_my_account_check_community_balance", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "3", - "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" - }, - { - "input": "3", - "expectedContent": "Balances:\n1:My balance\n2:Community balance\n0:Back" - }, - { - "input": "2", - "expectedContent": "Please enter your PIN:" - }, - { - "input": "1235", - "expectedContent": "Incorrect PIN. You have: 2 remaining attempt(s).\n1:Retry\n9:Quit" - }, - { - "input": "1", - "expectedContent": "Please enter your PIN:" - }, - { - "input": "1234", - "expectedContent": "{balance}\n0:Back\n9:Quit" - }, - { - "input": "0", - "expectedContent": "Balances:\n1:My balance\n2:Community balance\n0:Back" - }, - { - "input": "0", - "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" - }, - { - "input": "0", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - } - ] - }, - { - "name": "menu_my_account_edit_all_account_details_starting_from_firstname", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "3", - "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" - }, - { - "input": "1", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "1", - "expectedContent": "Enter your first names:\n0:Back" - }, - { - "input": "foo", - "expectedContent": "Enter family name:\n0:Back" - }, - { - "input": "bar", - "expectedContent": "Select gender: \n1:Male\n2:Female\n3:Unspecified\n0:Back" - }, - { - "input": "1", - "expectedContent": "Enter your year of birth\n0:Back" - }, - { - "input": "1940", - "expectedContent": "Enter your location:\n0:Back" - }, - { - "input": "Kilifi", - "expectedContent": "Enter the services or goods you offer: \n0:Back" - }, - { - "input": "Bananas", - "expectedContent": "Please enter your PIN:" - }, - { - "input": "1234", - "expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit" - }, - { - "input": "0", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "0", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - } - ] - }, - { - "name": "menu_my_account_edit_familyname_when_all_account__details_have_been_set", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "3", - "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" - }, - { - "input": "1", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "2", - "expectedContent": "Enter family name:\n0:Back" - }, - { - "input": "bar", - "expectedContent": "Please enter your PIN:" - }, - { - "input": "1234", - "expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit" - }, - { - "input": "0", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "0", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - } - ] - }, - { - "name": "menu_my_account_edit_gender_when_all_account__details_have_been_set", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "3", - "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" - }, - { - "input": "1", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "3", - "expectedContent": "Select gender: \n1:Male\n2:Female\n3:Unspecified\n0:Back" - }, - { - "input": "1", - "expectedContent": "Please enter your PIN:" - }, - { - "input": "1234", - "expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit" - }, - { - "input": "0", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "0", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - } - ] - }, - { - "name": "menu_my_account_edit_yob_when_all_account__details_have_been_set", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "3", - "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" - }, - { - "input": "1", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "4", - "expectedContent": "Enter your year of birth\n0:Back" - }, - { - "input": "1945", - "expectedContent": "Please enter your PIN:" - }, - { - "input": "1234", - "expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit" - }, - { - "input": "0", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "0", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - } - ] - }, - { - "name": "menu_my_account_edit_location_when_all_account_details_have_been_set", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "3", - "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" - }, - { - "input": "1", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "5", - "expectedContent": "Enter your location:\n0:Back" - }, - { - "input": "Kilifi", - "expectedContent": "Please enter your PIN:" - }, - { - "input": "1234", - "expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit" - }, - { - "input": "0", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "0", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - } - ] - }, - { - "name": "menu_my_account_edit_offerings_when_all_account__details_have_been_set", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "3", - "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" - }, - { - "input": "1", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "6", - "expectedContent": "Enter the services or goods you offer: \n0:Back" - }, - { - "input": "Bananas", - "expectedContent": "Please enter your PIN:" - }, - { - "input": "1234", - "expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit" - }, - { - "input": "0", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "0", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - } - ] - }, - { - "name": "menu_my_account_view_profile", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "3", - "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" - }, - { - "input": "1", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "7", - "expectedContent": "Please enter your PIN:" - }, - { - "input": "1234", - "expectedContent": "My profile:\nName: foo bar\nGender: male\nAge: 80\nLocation: Kilifi\nYou provide: Bananas\n\n0:Back\n9:Quit" - }, - { - "input": "0", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "0", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - } - ] - } - ] -} \ No newline at end of file diff --git a/menutraversal_test/menu_traversal_test.go b/menutraversal_test/menu_traversal_test.go deleted file mode 100644 index 4aee26e..0000000 --- a/menutraversal_test/menu_traversal_test.go +++ /dev/null @@ -1,386 +0,0 @@ -package menutraversaltest - -import ( - "bytes" - "context" - "flag" - "log" - "math/rand" - "regexp" - "testing" - - "git.grassecon.net/urdt/ussd/internal/testutil" - "git.grassecon.net/urdt/ussd/internal/testutil/driver" - "github.com/gofrs/uuid" -) - -var ( - testData = driver.ReadData() - sessionID string - src = rand.NewSource(42) - g = rand.New(src) -) - -var groupTestFile = flag.String("test-file", "group_test.json", "The test file to use for running the group tests") -var database = flag.String("db", "gdbm", "Specify the database (gdbm or postgres)") -var connStr = flag.String("conn", ".test_state", "connection string") -var dbSchema = flag.String("schema", "test", "Specify the database schema (default test)") - -func GenerateSessionId() string { - uu := uuid.NewGenWithOptions(uuid.WithRandomReader(g)) - v, err := uu.NewV4() - if err != nil { - panic(err) - } - return v.String() -} - -// Extract the public key from the engine response -func extractPublicKey(response []byte) string { - // Regex pattern to match the public key starting with 0x and 40 characters - re := regexp.MustCompile(`0x[a-fA-F0-9]{40}`) - match := re.Find(response) - if match != nil { - return string(match) - } - return "" -} - -// Extracts the balance value from the engine response. -func extractBalance(response []byte) string { - // Regex to match "Balance: " followed by a newline - re := regexp.MustCompile(`(?m)^Balance:\s+(\d+(\.\d+)?)\s+([A-Z]+)`) - match := re.FindSubmatch(response) - if match != nil { - return string(match[1]) + " " + string(match[3]) // " " - } - return "" -} - -// Extracts the Maximum amount value from the engine response. -func extractMaxAmount(response []byte) string { - // Regex to match "Maximum amount: " followed by a newline - re := regexp.MustCompile(`(?m)^Maximum amount:\s+(\d+(\.\d+)?)`) - match := re.FindSubmatch(response) - if match != nil { - return string(match[1]) // "" - } - return "" -} - -// Extracts the send amount value from the engine response. -func extractSendAmount(response []byte) string { - // Regex to match the pattern "will receive X.XX SYM from" - re := regexp.MustCompile(`will receive (\d+\.\d{2}\s+[A-Z]+) from`) - match := re.FindSubmatch(response) - if match != nil { - return string(match[1]) // Returns "X.XX SYM" - } - return "" -} - -func TestMain(m *testing.M) { - // Parse the flags - flag.Parse() - sessionID = GenerateSessionId() - // set the db - testutil.SetDatabase(*database, *connStr, *dbSchema) - - // Cleanup the db after tests - defer testutil.CleanDatabase() - - m.Run() -} - -func TestAccountCreationSuccessful(t *testing.T) { - en, fn, eventChannel := testutil.TestEngine(sessionID) - defer fn() - ctx := context.Background() - sessions := testData - for _, session := range sessions { - groups := driver.FilterGroupsByName(session.Groups, "account_creation_successful") - for _, group := range groups { - for _, step := range group.Steps { - cont, err := en.Exec(ctx, []byte(step.Input)) - if err != nil { - t.Fatalf("Test case '%s' failed at input '%s': %v", group.Name, step.Input, err) - } - if !cont { - break - } - w := bytes.NewBuffer(nil) - _, err = en.Flush(ctx, w) - if err != nil { - t.Fatalf("Test case '%s' failed during Flush: %v", group.Name, err) - } - b := w.Bytes() - match, err := step.MatchesExpectedContent(b) - if err != nil { - t.Fatalf("Error compiling regex for step '%s': %v", step.Input, err) - } - if !match { - t.Fatalf("expected:\n\t%s\ngot:\n\t%s\n", step.ExpectedContent, b) - } - } - } - } - <-eventChannel -} - -func TestAccountRegistrationRejectTerms(t *testing.T) { - // Generate a new UUID for this edge case test - uu := uuid.NewGenWithOptions(uuid.WithRandomReader(g)) - v, err := uu.NewV4() - if err != nil { - t.Fail() - } - edgeCaseSessionID := v.String() - en, fn, _ := testutil.TestEngine(edgeCaseSessionID) - defer fn() - ctx := context.Background() - sessions := testData - for _, session := range sessions { - groups := driver.FilterGroupsByName(session.Groups, "account_creation_reject_terms") - for _, group := range groups { - for _, step := range group.Steps { - cont, err := en.Exec(ctx, []byte(step.Input)) - if err != nil { - t.Fatalf("Test case '%s' failed at input '%s': %v", group.Name, step.Input, err) - return - } - if !cont { - break - } - w := bytes.NewBuffer(nil) - if _, err := en.Flush(ctx, w); err != nil { - t.Fatalf("Test case '%s' failed during Flush: %v", group.Name, err) - } - - b := w.Bytes() - match, err := step.MatchesExpectedContent(b) - if err != nil { - t.Fatalf("Error compiling regex for step '%s': %v", step.Input, err) - } - if !match { - t.Fatalf("expected:\n\t%s\ngot:\n\t%s\n", step.ExpectedContent, b) - } - } - } - } -} - -func TestMainMenuHelp(t *testing.T) { - en, fn, _ := testutil.TestEngine(sessionID) - defer fn() - ctx := context.Background() - sessions := testData - for _, session := range sessions { - groups := driver.FilterGroupsByName(session.Groups, "main_menu_help") - for _, group := range groups { - for _, step := range group.Steps { - cont, err := en.Exec(ctx, []byte(step.Input)) - if err != nil { - t.Fatalf("Test case '%s' failed at input '%s': %v", group.Name, step.Input, err) - return - } - if !cont { - break - } - w := bytes.NewBuffer(nil) - if _, err := en.Flush(ctx, w); err != nil { - t.Fatalf("Test case '%s' failed during Flush: %v", group.Name, err) - } - - b := w.Bytes() - balance := extractBalance(b) - - expectedContent := []byte(step.ExpectedContent) - expectedContent = bytes.Replace(expectedContent, []byte("{balance}"), []byte(balance), -1) - - step.ExpectedContent = string(expectedContent) - match, err := step.MatchesExpectedContent(b) - if err != nil { - t.Fatalf("Error compiling regex for step '%s': %v", step.Input, err) - } - if !match { - t.Fatalf("expected:\n\t%s\ngot:\n\t%s\n", step.ExpectedContent, b) - } - } - } - } -} - -func TestMainMenuQuit(t *testing.T) { - en, fn, _ := testutil.TestEngine(sessionID) - defer fn() - ctx := context.Background() - sessions := testData - for _, session := range sessions { - groups := driver.FilterGroupsByName(session.Groups, "main_menu_quit") - for _, group := range groups { - for _, step := range group.Steps { - cont, err := en.Exec(ctx, []byte(step.Input)) - if err != nil { - t.Fatalf("Test case '%s' failed at input '%s': %v", group.Name, step.Input, err) - return - } - if !cont { - break - } - w := bytes.NewBuffer(nil) - if _, err := en.Flush(ctx, w); err != nil { - t.Fatalf("Test case '%s' failed during Flush: %v", group.Name, err) - } - - b := w.Bytes() - balance := extractBalance(b) - - expectedContent := []byte(step.ExpectedContent) - expectedContent = bytes.Replace(expectedContent, []byte("{balance}"), []byte(balance), -1) - - step.ExpectedContent = string(expectedContent) - match, err := step.MatchesExpectedContent(b) - if err != nil { - t.Fatalf("Error compiling regex for step '%s': %v", step.Input, err) - } - if !match { - t.Fatalf("expected:\n\t%s\ngot:\n\t%s\n", step.ExpectedContent, b) - } - } - } - } -} - -func TestMyAccount_MyAddress(t *testing.T) { - en, fn, _ := testutil.TestEngine(sessionID) - defer fn() - ctx := context.Background() - sessions := testData - for _, session := range sessions { - groups := driver.FilterGroupsByName(session.Groups, "menu_my_account_my_address") - for _, group := range groups { - for index, step := range group.Steps { - t.Logf("step %v with input %v", index, step.Input) - cont, err := en.Exec(ctx, []byte(step.Input)) - if err != nil { - t.Errorf("Test case '%s' failed at input '%s': %v", group.Name, step.Input, err) - return - } - if !cont { - break - } - w := bytes.NewBuffer(nil) - if _, err := en.Flush(ctx, w); err != nil { - t.Errorf("Test case '%s' failed during Flush: %v", group.Name, err) - } - b := w.Bytes() - - balance := extractBalance(b) - publicKey := extractPublicKey(b) - - expectedContent := []byte(step.ExpectedContent) - expectedContent = bytes.Replace(expectedContent, []byte("{balance}"), []byte(balance), -1) - expectedContent = bytes.Replace(expectedContent, []byte("{public_key}"), []byte(publicKey), -1) - - step.ExpectedContent = string(expectedContent) - match, err := step.MatchesExpectedContent(b) - if err != nil { - t.Fatalf("Error compiling regex for step '%s': %v", step.Input, err) - } - if !match { - t.Fatalf("expected:\n\t%s\ngot:\n\t%s\n", expectedContent, b) - } - } - } - } -} - -func TestMainMenuSend(t *testing.T) { - en, fn, _ := testutil.TestEngine(sessionID) - defer fn() - ctx := context.Background() - sessions := testData - for _, session := range sessions { - groups := driver.FilterGroupsByName(session.Groups, "send_with_invite") - for _, group := range groups { - for index, step := range group.Steps { - t.Logf("step %v with input %v", index, step.Input) - cont, err := en.Exec(ctx, []byte(step.Input)) - if err != nil { - t.Fatalf("Test case '%s' failed at input '%s': %v", group.Name, step.Input, err) - return - } - if !cont { - break - } - w := bytes.NewBuffer(nil) - if _, err := en.Flush(ctx, w); err != nil { - t.Fatalf("Test case '%s' failed during Flush: %v", group.Name, err) - } - - b := w.Bytes() - balance := extractBalance(b) - max_amount := extractMaxAmount(b) - send_amount := extractSendAmount(b) - - expectedContent := []byte(step.ExpectedContent) - expectedContent = bytes.Replace(expectedContent, []byte("{balance}"), []byte(balance), -1) - expectedContent = bytes.Replace(expectedContent, []byte("{max_amount}"), []byte(max_amount), -1) - expectedContent = bytes.Replace(expectedContent, []byte("{send_amount}"), []byte(send_amount), -1) - expectedContent = bytes.Replace(expectedContent, []byte("{session_id}"), []byte(sessionID), -1) - - step.ExpectedContent = string(expectedContent) - match, err := step.MatchesExpectedContent(b) - if err != nil { - t.Fatalf("Error compiling regex for step '%s': %v", step.Input, err) - } - if !match { - t.Fatalf("expected:\n\t%s\ngot:\n\t%s\n", step.ExpectedContent, b) - } - } - } - } -} - -func TestGroups(t *testing.T) { - groups, err := driver.LoadTestGroups(*groupTestFile) - if err != nil { - log.Fatalf("Failed to load test groups: %v", err) - } - en, fn, _ := testutil.TestEngine(sessionID) - defer fn() - ctx := context.Background() - // Create test cases from loaded groups - tests := driver.CreateTestCases(groups) - for _, tt := range tests { - t.Run(tt.Name, func(t *testing.T) { - cont, err := en.Exec(ctx, []byte(tt.Input)) - if err != nil { - t.Errorf("Test case '%s' failed at input '%s': %v", tt.Name, tt.Input, err) - return - } - if !cont { - return - } - w := bytes.NewBuffer(nil) - if _, err := en.Flush(ctx, w); err != nil { - t.Errorf("Test case '%s' failed during Flush: %v", tt.Name, err) - } - b := w.Bytes() - balance := extractBalance(b) - - expectedContent := []byte(tt.ExpectedContent) - expectedContent = bytes.Replace(expectedContent, []byte("{balance}"), []byte(balance), -1) - - tt.ExpectedContent = string(expectedContent) - - match, err := tt.MatchesExpectedContent(b) - if err != nil { - t.Fatalf("Error compiling regex for step '%s': %v", tt.Input, err) - } - if !match { - t.Fatalf("expected:\n\t%s\ngot:\n\t%s\n", tt.ExpectedContent, b) - } - }) - } -} diff --git a/menutraversal_test/profile_edit_start_familyname.json b/menutraversal_test/profile_edit_start_familyname.json deleted file mode 100644 index 98325b0..0000000 --- a/menutraversal_test/profile_edit_start_familyname.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "groups": [ - { - "name": "menu_my_account_edit_all_account_details_starting_from_family_name", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "3", - "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" - }, - { - "input": "1", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "2", - "expectedContent": "Enter family name:\n0:Back" - }, - { - "input": "bar", - "expectedContent": "Select gender: \n1:Male\n2:Female\n3:Unspecified\n0:Back" - }, - { - "input": "1", - "expectedContent": "Enter your year of birth\n0:Back" - }, - { - "input": "1940", - "expectedContent": "Enter your location:\n0:Back" - }, - { - "input": "Kilifi", - "expectedContent": "Enter the services or goods you offer: \n0:Back" - }, - { - "input": "Bananas", - "expectedContent": "Please enter your PIN:" - }, - { - "input": "1234", - "expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit" - }, - { - "input": "0", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "0", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - } - ] - } - ] -} - - - - - - - - - - - \ No newline at end of file diff --git a/menutraversal_test/profile_edit_start_firstname.json b/menutraversal_test/profile_edit_start_firstname.json deleted file mode 100644 index 0f6be8b..0000000 --- a/menutraversal_test/profile_edit_start_firstname.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "groups": [ - { - "name": "menu_my_account_edit_all_account_details_starting_from_firstname", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "3", - "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" - }, - { - "input": "1", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "1", - "expectedContent": "Enter your first names:\n0:Back" - }, - { - "input": "foo", - "expectedContent": "Enter family name:\n0:Back" - }, - { - "input": "bar", - "expectedContent": "Select gender: \n1:Male\n2:Female\n3:Unspecified\n0:Back" - }, - { - "input": "1", - "expectedContent": "Enter your year of birth\n0:Back" - }, - { - "input": "1940", - "expectedContent": "Enter your location:\n0:Back" - }, - { - "input": "Kilifi", - "expectedContent": "Enter the services or goods you offer: \n0:Back" - }, - { - "input": "Bananas", - "expectedContent": "Please enter your PIN:" - }, - { - "input": "1234", - "expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit" - }, - { - "input": "0", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "0", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - } - ] - } - ] -} diff --git a/menutraversal_test/profile_edit_start_gender.json b/menutraversal_test/profile_edit_start_gender.json deleted file mode 100644 index afca12a..0000000 --- a/menutraversal_test/profile_edit_start_gender.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "groups": [ - { - "name": "menu_my_account_edit_all_account_details_starting_from_gender", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "3", - "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" - }, - { - "input": "1", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "3", - "expectedContent": "Select gender: \n1:Male\n2:Female\n3:Unspecified\n0:Back" - }, - { - "input": "1", - "expectedContent": "Enter your year of birth\n0:Back" - }, - { - "input": "1940", - "expectedContent": "Enter your location:\n0:Back" - }, - { - "input": "Kilifi", - "expectedContent": "Enter the services or goods you offer: \n0:Back" - }, - { - "input": "Bananas", - "expectedContent": "Please enter your PIN:" - }, - { - "input": "1234", - "expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit" - }, - { - "input": "0", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "0", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - } - ] - } - ] -} - - \ No newline at end of file diff --git a/menutraversal_test/profile_edit_start_location.json b/menutraversal_test/profile_edit_start_location.json deleted file mode 100644 index 8852911..0000000 --- a/menutraversal_test/profile_edit_start_location.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "groups": [ - { - "name": "menu_my_account_edit_all_account_details_starting_from_location", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "3", - "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" - }, - { - "input": "1", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "5", - "expectedContent": "Enter your location:\n0:Back" - }, - { - "input": "Kilifi", - "expectedContent": "Enter the services or goods you offer: \n0:Back" - }, - { - "input": "Bananas", - "expectedContent": "Please enter your PIN:" - }, - { - "input": "1234", - "expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit" - }, - { - "input": "0", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "0", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - } - ] - } - ] -} - \ No newline at end of file diff --git a/menutraversal_test/profile_edit_start_offerings.json b/menutraversal_test/profile_edit_start_offerings.json deleted file mode 100644 index 6aa40f6..0000000 --- a/menutraversal_test/profile_edit_start_offerings.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "groups": [ - { - "name": "menu_my_account_edit_all_account_details_starting_from_offerings", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "3", - "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" - }, - { - "input": "1", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "6", - "expectedContent": "Enter the services or goods you offer: \n0:Back" - }, - { - "input": "Bananas", - "expectedContent": "Please enter your PIN:" - }, - { - "input": "1234", - "expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit" - }, - { - "input": "0", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "0", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - } - ] - } - ] -} - \ No newline at end of file diff --git a/menutraversal_test/profile_edit_start_yob.json b/menutraversal_test/profile_edit_start_yob.json deleted file mode 100644 index 45227f7..0000000 --- a/menutraversal_test/profile_edit_start_yob.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "groups": [ - { - "name": "menu_my_account_edit_all_account_details_starting_from_yob", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "3", - "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" - }, - { - "input": "1", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "4", - "expectedContent": "Enter your year of birth\n0:Back" - }, - { - "input": "1940", - "expectedContent": "Enter your location:\n0:Back" - }, - { - "input": "Kilifi", - "expectedContent": "Enter the services or goods you offer: \n0:Back" - }, - { - "input": "Bananas", - "expectedContent": "Please enter your PIN:" - }, - { - "input": "1234", - "expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit" - }, - { - "input": "0", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "0", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - } - ] - } - ] -} - \ No newline at end of file diff --git a/menutraversal_test/profile_edit_when_adjacent_item_set.json b/menutraversal_test/profile_edit_when_adjacent_item_set.json deleted file mode 100644 index f8d7263..0000000 --- a/menutraversal_test/profile_edit_when_adjacent_item_set.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "groups": [ - { - "name": "menu_my_account_edit_familyname_when_adjacent_profile_information_set", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "3", - "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" - }, - { - "input": "1", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "3", - "expectedContent": "Select gender: \n1:Male\n2:Female\n3:Unspecified\n0:Back" - }, - { - "input": "1", - "expectedContent": "Enter your year of birth\n0:Back" - }, - { - "input": "1940", - "expectedContent": "Enter your location:\n0:Back" - }, - { - "input": "Kilifi", - "expectedContent": "Enter the services or goods you offer: \n0:Back" - }, - { - "input": "Bananas", - "expectedContent": "Please enter your PIN:" - }, - { - "input": "1234", - "expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit" - }, - { - "input": "0", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "2", - "expectedContent": "Enter family name:\n0:Back" - }, - { - "input": "foo2", - "expectedContent": "Please enter your PIN:" - }, - { - "input": "1234", - "expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit" - }, - { - "input": "0", - "expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back" - }, - { - "input": "0", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - } - ] - } - ] -} - \ No newline at end of file diff --git a/menutraversal_test/test_setup.json b/menutraversal_test/test_setup.json deleted file mode 100644 index 8728640..0000000 --- a/menutraversal_test/test_setup.json +++ /dev/null @@ -1,133 +0,0 @@ -[ - { - "name": "session one", - "groups": [ - { - "name": "account_creation_successful", - "steps": [ - { - "input": "", - "expectedContent": "Welcome to Sarafu Network\nPlease select a language\n1:English\n2:Kiswahili" - }, - { - "input": "1", - "expectedContent": "Do you agree to terms and conditions?\nhttps://grassecon.org/pages/terms-and-conditions\n\n1:Yes\n2:No" - }, - { - "input": "1", - "expectedContent": "Please enter a new four number PIN for your account:\n0:Exit" - }, - { - "input": "1234", - "expectedContent": "Enter your four number PIN again:" - }, - { - "input": "1111", - "expectedContent": "The PIN is not a match. Try again\n1:Retry\n9:Quit" - }, - { - "input": "1", - "expectedContent": "Enter your four number PIN again:" - }, - { - "input": "1234", - "expectedContent": "Your account is being created...Thank you for using Sarafu. Goodbye!" - } - ] - }, - { - "name": "account_creation_reject_terms", - "steps": [ - { - "input": "", - "expectedContent": "Welcome to Sarafu Network\nPlease select a language\n1:English\n2:Kiswahili" - }, - { - "input": "1", - "expectedContent": "Do you agree to terms and conditions?\nhttps://grassecon.org/pages/terms-and-conditions\n\n1:Yes\n2:No" - }, - { - "input": "2", - "expectedContent": "Thank you for using Sarafu. Goodbye!" - } - ] - }, - { - "name": "send_with_invite", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "1", - "expectedContent": "Enter recipient's phone number/address/alias:\n0:Back" - }, - { - "input": "0@0", - "expectedContent": "0@0 is invalid, please try again:\n1:Retry\n9:Quit" - }, - { - "input": "1", - "expectedContent": "Enter recipient's phone number/address/alias:\n0:Back" - }, - { - "input": "0712345678", - "expectedContent": "0712345678 is not registered, please try again:\n1:Retry\n2:Invite to Sarafu Network\n9:Quit" - }, - { - "input": "2", - "expectedContent": "Your invite request for 0712345678 to Sarafu Network failed. Please try again later." - } - ] - }, - { - "name": "main_menu_help", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "4", - "expectedContent": "For more help,please call: 0757628885" - } - ] - }, - { - "name": "main_menu_quit", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "9", - "expectedContent": "Thank you for using Sarafu. Goodbye!" - } - ] - }, - { - "name": "menu_my_account_my_address", - "steps": [ - { - "input": "", - "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" - }, - { - "input": "3", - "expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back" - }, - { - "input": "6", - "expectedContent": "Address: {public_key}\n0:Back\n9:Quit" - }, - { - "input": "9", - "expectedContent": "Thank you for using Sarafu. Goodbye!" - } - ] - } - ] - } -] \ No newline at end of file diff --git a/models/account_response.go b/models/account_response.go deleted file mode 100644 index dc8e758..0000000 --- a/models/account_response.go +++ /dev/null @@ -1,6 +0,0 @@ -package models - -type AccountResult struct { - PublicKey string `json:"publicKey"` - TrackingId string `json:"trackingId"` -} diff --git a/models/balance_response.go b/models/balance_response.go deleted file mode 100644 index 88e9ce9..0000000 --- a/models/balance_response.go +++ /dev/null @@ -1,8 +0,0 @@ -package models - -import "encoding/json" - -type BalanceResult struct { - Balance string `json:"balance"` - Nonce json.Number `json:"nonce"` -} diff --git a/models/profile.go b/models/profile.go deleted file mode 100644 index d698318..0000000 --- a/models/profile.go +++ /dev/null @@ -1,18 +0,0 @@ -package models - -type Profile struct { - ProfileItems []string - Max int -} - -func (p *Profile) InsertOrShift(index int, value string) { - if index < len(p.ProfileItems) { - p.ProfileItems = append(p.ProfileItems[:index], value) - } else { - for len(p.ProfileItems) < index { - p.ProfileItems = append(p.ProfileItems, "0") - } - p.ProfileItems = append(p.ProfileItems, "0") - p.ProfileItems[index] = value - } -} diff --git a/models/token_transfer_response.go b/models/token_transfer_response.go deleted file mode 100644 index b4d6dc3..0000000 --- a/models/token_transfer_response.go +++ /dev/null @@ -1,5 +0,0 @@ -package models - -type TokenTransferResponse struct { - TrackingId string `json:"trackingId"` -} diff --git a/models/track_status_response.go b/models/track_status_response.go deleted file mode 100644 index 0c3c230..0000000 --- a/models/track_status_response.go +++ /dev/null @@ -1,18 +0,0 @@ -package models - -import ( - "encoding/json" - "time" -) - -type Transaction struct { - CreatedAt time.Time `json:"createdAt"` - Status string `json:"status"` - TransferValue json.Number `json:"transferValue"` - TxHash string `json:"txHash"` - TxType string `json:"txType"` -} - -type TrackStatusResult struct { - Active bool `json:"active"` -} diff --git a/models/voucher_data_result.go b/models/voucher_data_result.go deleted file mode 100644 index 9a10831..0000000 --- a/models/voucher_data_result.go +++ /dev/null @@ -1,10 +0,0 @@ -package models - -type VoucherDataResult struct { - TokenName string `json:"tokenName"` - TokenSymbol string `json:"tokenSymbol"` - TokenDecimals int `json:"tokenDecimals"` - SinkAddress string `json:"sinkAddress"` - TokenCommodity string `json:"tokenCommodity"` - TokenLocation string `json:"tokenLocation"` -} diff --git a/remote/account_service.go b/remote/account_service.go deleted file mode 100644 index b0e9eb4..0000000 --- a/remote/account_service.go +++ /dev/null @@ -1,294 +0,0 @@ -package remote - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "io" - "log" - "net/http" - "net/url" - - "git.grassecon.net/urdt/ussd/config" - "git.grassecon.net/urdt/ussd/models" - "github.com/grassrootseconomics/eth-custodial/pkg/api" - dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" -) - -type AccountServiceInterface interface { - CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResult, error) - CreateAccount(ctx context.Context) (*models.AccountResult, error) - TrackAccountStatus(ctx context.Context, publicKey string) (*models.TrackStatusResult, error) - FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) - FetchTransactions(ctx context.Context, publicKey string) ([]dataserviceapi.Last10TxResponse, error) - VoucherData(ctx context.Context, address string) (*models.VoucherDataResult, error) - TokenTransfer(ctx context.Context, amount, from, to, tokenAddress string) (*models.TokenTransferResponse, error) - CheckAliasAddress(ctx context.Context, alias string) (*dataserviceapi.AliasAddress, error) -} - -type AccountService struct { -} - -// Parameters: -// - trackingId: A unique identifier for the account.This should be obtained from a previous call to -// CreateAccount or a similar function that returns an AccountResponse. The `trackingId` field in the -// AccountResponse struct can be used here to check the account status during a transaction. -// -// Returns: -// - string: The status of the transaction as a string. If there is an error during the request or processing, this will be an empty string. -// - error: An error if any occurred during the HTTP request, reading the response, or unmarshalling the JSON data. -// If no error occurs, this will be nil -func (as *AccountService) TrackAccountStatus(ctx context.Context, publicKey string) (*models.TrackStatusResult, error) { - var r models.TrackStatusResult - - ep, err := url.JoinPath(config.TrackURL, publicKey) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", ep, nil) - if err != nil { - return nil, err - } - - _, err = doRequest(ctx, req, &r) - if err != nil { - return nil, err - } - - return &r, nil -} - -// CheckBalance retrieves the balance for a given public key from the custodial balance API endpoint. -// Parameters: -// - publicKey: The public key associated with the account whose balance needs to be checked. -func (as *AccountService) CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResult, error) { - var balanceResult models.BalanceResult - - ep, err := url.JoinPath(config.BalanceURL, publicKey) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", ep, nil) - if err != nil { - return nil, err - } - - _, err = doRequest(ctx, req, &balanceResult) - return &balanceResult, err -} - -// CreateAccount creates a new account in the custodial system. -// Returns: -// - *models.AccountResponse: A pointer to an AccountResponse struct containing the details of the created account. -// If there is an error during the request or processing, this will be nil. -// - error: An error if any occurred during the HTTP request, reading the response, or unmarshalling the JSON data. -// If no error occurs, this will be nil. -func (as *AccountService) CreateAccount(ctx context.Context) (*models.AccountResult, error) { - var r models.AccountResult - // Create a new request - req, err := http.NewRequest("POST", config.CreateAccountURL, nil) - if err != nil { - return nil, err - } - _, err = doRequest(ctx, req, &r) - if err != nil { - return nil, err - } - - return &r, nil -} - -// FetchVouchers retrieves the token holdings for a given public key from the data indexer API endpoint -// Parameters: -// - publicKey: The public key associated with the account. -func (as *AccountService) FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) { - var r struct { - Holdings []dataserviceapi.TokenHoldings `json:"holdings"` - } - - ep, err := url.JoinPath(config.VoucherHoldingsURL, publicKey) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", ep, nil) - if err != nil { - return nil, err - } - - _, err = doRequest(ctx, req, &r) - if err != nil { - return nil, err - } - - return r.Holdings, nil -} - -// FetchTransactions retrieves the last 10 transactions for a given public key from the data indexer API endpoint -// Parameters: -// - publicKey: The public key associated with the account. -func (as *AccountService) FetchTransactions(ctx context.Context, publicKey string) ([]dataserviceapi.Last10TxResponse, error) { - var r struct { - Transfers []dataserviceapi.Last10TxResponse `json:"transfers"` - } - - ep, err := url.JoinPath(config.VoucherTransfersURL, publicKey) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", ep, nil) - if err != nil { - return nil, err - } - - _, err = doRequest(ctx, req, &r) - if err != nil { - return nil, err - } - - return r.Transfers, nil -} - -// VoucherData retrieves voucher metadata from the data indexer API endpoint. -// Parameters: -// - address: The voucher address. -func (as *AccountService) VoucherData(ctx context.Context, address string) (*models.VoucherDataResult, error) { - var r struct { - TokenDetails models.VoucherDataResult `json:"tokenDetails"` - } - - ep, err := url.JoinPath(config.VoucherDataURL, address) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", ep, nil) - if err != nil { - return nil, err - } - - _, err = doRequest(ctx, req, &r) - return &r.TokenDetails, err -} - -// TokenTransfer creates a new token transfer in the custodial system. -// Returns: -// - *models.TokenTransferResponse: A pointer to an TokenTransferResponse struct containing the trackingId. -// If there is an error during the request or processing, this will be nil. -// - error: An error if any occurred during the HTTP request, reading the response, or unmarshalling the JSON data. -// If no error occurs, this will be nil. -func (as *AccountService) TokenTransfer(ctx context.Context, amount, from, to, tokenAddress string) (*models.TokenTransferResponse, error) { - var r models.TokenTransferResponse - - // Create request payload - payload := map[string]string{ - "amount": amount, - "from": from, - "to": to, - "tokenAddress": tokenAddress, - } - - payloadBytes, err := json.Marshal(payload) - if err != nil { - return nil, err - } - - // Create a new request - req, err := http.NewRequest("POST", config.TokenTransferURL, bytes.NewBuffer(payloadBytes)) - if err != nil { - return nil, err - } - _, err = doRequest(ctx, req, &r) - if err != nil { - return nil, err - } - - return &r, nil -} - -// CheckAliasAddress retrieves the address of an alias from the API endpoint. -// Parameters: -// - alias: The alias of the user. -func (as *AccountService) CheckAliasAddress(ctx context.Context, alias string) (*dataserviceapi.AliasAddress, error) { - var r dataserviceapi.AliasAddress - - ep, err := url.JoinPath(config.CheckAliasURL, alias) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", ep, nil) - if err != nil { - return nil, err - } - - _, err = doRequest(ctx, req, &r) - return &r, err -} - -func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { - var okResponse api.OKResponse - var errResponse api.ErrResponse - - req.Header.Set("Authorization", "Bearer "+config.BearerToken) - req.Header.Set("Content-Type", "application/json") - - logRequestDetails(req) - - resp, err := http.DefaultClient.Do(req) - if err != nil { - log.Printf("Failed to make %s request to endpoint: %s with reason: %s", req.Method, req.URL, err.Error()) - errResponse.Description = err.Error() - return nil, err - } - defer resp.Body.Close() - - log.Printf("Received response for %s: Status Code: %d | Content-Type: %s", req.URL, resp.StatusCode, resp.Header.Get("Content-Type")) - body, err := io.ReadAll(resp.Body) - if err != nil { - return nil, err - } - if resp.StatusCode >= http.StatusBadRequest { - err := json.Unmarshal([]byte(body), &errResponse) - if err != nil { - return nil, err - } - return nil, errors.New(errResponse.Description) - } - err = json.Unmarshal([]byte(body), &okResponse) - if err != nil { - return nil, err - } - if len(okResponse.Result) == 0 { - return nil, errors.New("Empty api result") - } - - v, err := json.Marshal(okResponse.Result) - if err != nil { - return nil, err - } - - err = json.Unmarshal(v, &rcpt) - return &okResponse, err -} - -func logRequestDetails(req *http.Request) { - var bodyBytes []byte - contentType := req.Header.Get("Content-Type") - if req.Body != nil { - bodyBytes, err := io.ReadAll(req.Body) - if err != nil { - log.Printf("Error reading request body: %s", err) - return - } - req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) - } else { - bodyBytes = []byte("-") - } - - log.Printf("URL: %s | Content-Type: %s | Method: %s| Request Body: %s", req.URL, contentType, req.Method, string(bodyBytes)) -} diff --git a/request/request.go b/request/request.go new file mode 100644 index 0000000..ce52ffb --- /dev/null +++ b/request/request.go @@ -0,0 +1,42 @@ +package request + +import ( + "context" + "io" + + "git.defalsify.org/vise.git/resource" + "git.defalsify.org/vise.git/persist" + "git.defalsify.org/vise.git/engine" + "git.defalsify.org/vise.git/logging" + "git.grassecon.net/grassrootseconomics/visedriver/storage" +) + +var ( + logg = logging.NewVanilla().WithDomain("visedriver.request") +) + +type RequestSession struct { + Ctx context.Context + Config engine.Config + Engine engine.Engine + Input []byte + Storage *storage.Storage + Writer io.Writer + Continue bool +} + +// TODO: seems like can remove this. +type RequestParser interface { + GetSessionId(ctx context.Context, rq any) (string, error) + GetInput(rq any) ([]byte, error) +} + +type RequestHandler interface { + GetConfig() engine.Config + GetRequestParser() RequestParser + GetEngine(cfg engine.Config, rs resource.Resource, pe *persist.Persister) engine.Engine + Process(rs RequestSession) (RequestSession, error) + Output(rs RequestSession) (RequestSession, error) + Reset(rs RequestSession) (RequestSession, error) + Shutdown() +} diff --git a/services/registration/Makefile b/services/registration/Makefile deleted file mode 100644 index d5950b5..0000000 --- a/services/registration/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# 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)" diff --git a/services/registration/_catch b/services/registration/_catch deleted file mode 100644 index e81b8e9..0000000 --- a/services/registration/_catch +++ /dev/null @@ -1 +0,0 @@ -Something went wrong.Please try again \ No newline at end of file diff --git a/services/registration/_catch.vis b/services/registration/_catch.vis deleted file mode 100644 index 72e55ad..0000000 --- a/services/registration/_catch.vis +++ /dev/null @@ -1 +0,0 @@ -HALT diff --git a/services/registration/_catch_swa b/services/registration/_catch_swa deleted file mode 100644 index 3affebd..0000000 --- a/services/registration/_catch_swa +++ /dev/null @@ -1 +0,0 @@ -Tatizo la kimtambo limetokea,tafadhali jaribu tena baadaye. \ No newline at end of file diff --git a/services/registration/account_creation b/services/registration/account_creation deleted file mode 100644 index e9463a6..0000000 --- a/services/registration/account_creation +++ /dev/null @@ -1 +0,0 @@ -Your account is being created... \ No newline at end of file diff --git a/services/registration/account_creation.vis b/services/registration/account_creation.vis deleted file mode 100644 index 380fe6d..0000000 --- a/services/registration/account_creation.vis +++ /dev/null @@ -1,4 +0,0 @@ -RELOAD verify_create_pin -CATCH create_pin_mismatch flag_pin_mismatch 1 -LOAD quit 0 -HALT diff --git a/services/registration/account_creation_failed b/services/registration/account_creation_failed deleted file mode 100644 index 0df00db..0000000 --- a/services/registration/account_creation_failed +++ /dev/null @@ -1 +0,0 @@ -Your account creation request failed. Please try again later. \ No newline at end of file diff --git a/services/registration/account_creation_failed.vis b/services/registration/account_creation_failed.vis deleted file mode 100644 index b62b797..0000000 --- a/services/registration/account_creation_failed.vis +++ /dev/null @@ -1,3 +0,0 @@ -MOUT quit 9 -HALT -INCMP quit 9 diff --git a/services/registration/account_creation_failed_swa b/services/registration/account_creation_failed_swa deleted file mode 100644 index 6f0ac7b..0000000 --- a/services/registration/account_creation_failed_swa +++ /dev/null @@ -1 +0,0 @@ -Ombi lako la kusajiliwa haliwezi kukamilishwa. Tafadhali jaribu tena baadaye. \ No newline at end of file diff --git a/services/registration/account_creation_swa b/services/registration/account_creation_swa deleted file mode 100644 index 6e5b1e1..0000000 --- a/services/registration/account_creation_swa +++ /dev/null @@ -1 +0,0 @@ -Akaunti yako inatengenezwa... \ No newline at end of file diff --git a/services/registration/account_menu b/services/registration/account_menu deleted file mode 100644 index 7aa9fe9..0000000 --- a/services/registration/account_menu +++ /dev/null @@ -1 +0,0 @@ -My Account \ No newline at end of file diff --git a/services/registration/account_menu_swa b/services/registration/account_menu_swa deleted file mode 100644 index c77102f..0000000 --- a/services/registration/account_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Akaunti yangu \ No newline at end of file diff --git a/services/registration/account_pending b/services/registration/account_pending deleted file mode 100644 index 4eadf25..0000000 --- a/services/registration/account_pending +++ /dev/null @@ -1 +0,0 @@ -Your account is still being created. \ No newline at end of file diff --git a/services/registration/account_pending.vis b/services/registration/account_pending.vis deleted file mode 100644 index d122613..0000000 --- a/services/registration/account_pending.vis +++ /dev/null @@ -1,3 +0,0 @@ -RELOAD check_account_status -CATCH main flag_account_success 1 -HALT diff --git a/services/registration/account_pending_swa b/services/registration/account_pending_swa deleted file mode 100644 index 2e514b5..0000000 --- a/services/registration/account_pending_swa +++ /dev/null @@ -1 +0,0 @@ -Akaunti yako bado inatengenezwa \ No newline at end of file diff --git a/services/registration/address b/services/registration/address deleted file mode 100644 index 6353876..0000000 --- a/services/registration/address +++ /dev/null @@ -1 +0,0 @@ -Address: {{.check_identifier}} \ No newline at end of file diff --git a/services/registration/address.vis b/services/registration/address.vis deleted file mode 100644 index dfc46d1..0000000 --- a/services/registration/address.vis +++ /dev/null @@ -1,8 +0,0 @@ -LOAD check_identifier 0 -RELOAD check_identifier -MAP check_identifier -MOUT back 0 -MOUT quit 9 -HALT -INCMP _ 0 -INCMP quit 9 diff --git a/services/registration/address_swa b/services/registration/address_swa deleted file mode 100644 index 3e7a55e..0000000 --- a/services/registration/address_swa +++ /dev/null @@ -1 +0,0 @@ -Anwani:{{.check_identifier}} \ No newline at end of file diff --git a/services/registration/amount b/services/registration/amount deleted file mode 100644 index 9142aba..0000000 --- a/services/registration/amount +++ /dev/null @@ -1,2 +0,0 @@ -Maximum amount: {{.max_amount}} -Enter amount: \ No newline at end of file diff --git a/services/registration/amount.vis b/services/registration/amount.vis deleted file mode 100644 index 2266160..0000000 --- a/services/registration/amount.vis +++ /dev/null @@ -1,15 +0,0 @@ -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 * diff --git a/services/registration/amount_swa b/services/registration/amount_swa deleted file mode 100644 index 0c8cf01..0000000 --- a/services/registration/amount_swa +++ /dev/null @@ -1,2 +0,0 @@ -Kiwango cha juu: {{.max_amount}} -Weka kiwango: \ No newline at end of file diff --git a/services/registration/api_failure b/services/registration/api_failure deleted file mode 100644 index 06d2d9e..0000000 --- a/services/registration/api_failure +++ /dev/null @@ -1 +0,0 @@ -Failed to connect to the custodial service.Please try again. \ No newline at end of file diff --git a/services/registration/api_failure.vis b/services/registration/api_failure.vis deleted file mode 100644 index 37b3deb..0000000 --- a/services/registration/api_failure.vis +++ /dev/null @@ -1,5 +0,0 @@ -MOUT retry 1 -MOUT quit 9 -HALT -INCMP _ 1 -INCMP quit 9 diff --git a/services/registration/back_menu b/services/registration/back_menu deleted file mode 100644 index 2278c97..0000000 --- a/services/registration/back_menu +++ /dev/null @@ -1 +0,0 @@ -Back \ No newline at end of file diff --git a/services/registration/back_menu_swa b/services/registration/back_menu_swa deleted file mode 100644 index c3e6e37..0000000 --- a/services/registration/back_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Rudi \ No newline at end of file diff --git a/services/registration/balances b/services/registration/balances deleted file mode 100644 index 27a69d5..0000000 --- a/services/registration/balances +++ /dev/null @@ -1 +0,0 @@ -Balances: \ No newline at end of file diff --git a/services/registration/balances.vis b/services/registration/balances.vis deleted file mode 100644 index 9a346d5..0000000 --- a/services/registration/balances.vis +++ /dev/null @@ -1,10 +0,0 @@ -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 . * diff --git a/services/registration/balances_swa b/services/registration/balances_swa deleted file mode 100644 index 1649055..0000000 --- a/services/registration/balances_swa +++ /dev/null @@ -1 +0,0 @@ -Salio: \ No newline at end of file diff --git a/services/registration/blocked_account.vis b/services/registration/blocked_account.vis deleted file mode 100644 index d8adab2..0000000 --- a/services/registration/blocked_account.vis +++ /dev/null @@ -1,2 +0,0 @@ -LOAD show_blocked_account 0 -HALT diff --git a/services/registration/change_language b/services/registration/change_language deleted file mode 100644 index 72bedfe..0000000 --- a/services/registration/change_language +++ /dev/null @@ -1 +0,0 @@ -Select language: \ No newline at end of file diff --git a/services/registration/change_language.vis b/services/registration/change_language.vis deleted file mode 100644 index f20bcfb..0000000 --- a/services/registration/change_language.vis +++ /dev/null @@ -1,10 +0,0 @@ -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 . * diff --git a/services/registration/change_language_menu b/services/registration/change_language_menu deleted file mode 100644 index 7175fce..0000000 --- a/services/registration/change_language_menu +++ /dev/null @@ -1 +0,0 @@ -Change language \ No newline at end of file diff --git a/services/registration/change_language_menu_swa b/services/registration/change_language_menu_swa deleted file mode 100644 index 58cdd10..0000000 --- a/services/registration/change_language_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Badili lugha \ No newline at end of file diff --git a/services/registration/change_language_swa b/services/registration/change_language_swa deleted file mode 100644 index 90e21a8..0000000 --- a/services/registration/change_language_swa +++ /dev/null @@ -1 +0,0 @@ -Chagua lugha: \ No newline at end of file diff --git a/services/registration/change_pin_menu b/services/registration/change_pin_menu deleted file mode 100644 index 4fa175a..0000000 --- a/services/registration/change_pin_menu +++ /dev/null @@ -1 +0,0 @@ -Change PIN \ No newline at end of file diff --git a/services/registration/change_pin_menu_swa b/services/registration/change_pin_menu_swa deleted file mode 100644 index bb51b21..0000000 --- a/services/registration/change_pin_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Badili PIN \ No newline at end of file diff --git a/services/registration/check_balance_menu b/services/registration/check_balance_menu deleted file mode 100644 index 253f368..0000000 --- a/services/registration/check_balance_menu +++ /dev/null @@ -1 +0,0 @@ -Check balances \ No newline at end of file diff --git a/services/registration/check_balance_menu_swa b/services/registration/check_balance_menu_swa deleted file mode 100644 index 4fe14f2..0000000 --- a/services/registration/check_balance_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Angalia salio \ No newline at end of file diff --git a/services/registration/check_statement b/services/registration/check_statement deleted file mode 100644 index 0e989db..0000000 --- a/services/registration/check_statement +++ /dev/null @@ -1 +0,0 @@ -Please enter your PIN to view statement: \ No newline at end of file diff --git a/services/registration/check_statement.vis b/services/registration/check_statement.vis deleted file mode 100644 index d79b5ca..0000000 --- a/services/registration/check_statement.vis +++ /dev/null @@ -1,12 +0,0 @@ -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 * diff --git a/services/registration/check_statement_menu b/services/registration/check_statement_menu deleted file mode 100644 index 70e2bd5..0000000 --- a/services/registration/check_statement_menu +++ /dev/null @@ -1 +0,0 @@ -Check statement \ No newline at end of file diff --git a/services/registration/check_statement_menu_swa b/services/registration/check_statement_menu_swa deleted file mode 100644 index b8a338d..0000000 --- a/services/registration/check_statement_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Taarifa ya matumizi \ No newline at end of file diff --git a/services/registration/check_statement_swa b/services/registration/check_statement_swa deleted file mode 100644 index 468364f..0000000 --- a/services/registration/check_statement_swa +++ /dev/null @@ -1 +0,0 @@ -Tafadhali weka PIN yako kuona taarifa ya matumizi: \ No newline at end of file diff --git a/services/registration/comminity_balance_swa b/services/registration/comminity_balance_swa deleted file mode 100644 index d9f1d6e..0000000 --- a/services/registration/comminity_balance_swa +++ /dev/null @@ -1 +0,0 @@ -{{.fetch_community_balance}} \ No newline at end of file diff --git a/services/registration/community_balance b/services/registration/community_balance deleted file mode 100644 index d9f1d6e..0000000 --- a/services/registration/community_balance +++ /dev/null @@ -1 +0,0 @@ -{{.fetch_community_balance}} \ No newline at end of file diff --git a/services/registration/community_balance.vis b/services/registration/community_balance.vis deleted file mode 100644 index fad90cc..0000000 --- a/services/registration/community_balance.vis +++ /dev/null @@ -1,12 +0,0 @@ -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 . * diff --git a/services/registration/community_balance_menu b/services/registration/community_balance_menu deleted file mode 100644 index a7344a2..0000000 --- a/services/registration/community_balance_menu +++ /dev/null @@ -1 +0,0 @@ -Community balance \ No newline at end of file diff --git a/services/registration/community_balance_menu_swa b/services/registration/community_balance_menu_swa deleted file mode 100644 index 726fc99..0000000 --- a/services/registration/community_balance_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Salio la kikundi \ No newline at end of file diff --git a/services/registration/confirm_create_pin b/services/registration/confirm_create_pin deleted file mode 100644 index e4632ad..0000000 --- a/services/registration/confirm_create_pin +++ /dev/null @@ -1 +0,0 @@ -Enter your four number PIN again: \ No newline at end of file diff --git a/services/registration/confirm_create_pin.vis b/services/registration/confirm_create_pin.vis deleted file mode 100644 index 02279dc..0000000 --- a/services/registration/confirm_create_pin.vis +++ /dev/null @@ -1,4 +0,0 @@ -LOAD save_temporary_pin 6 -HALT -LOAD verify_create_pin 8 -INCMP account_creation * diff --git a/services/registration/confirm_create_pin_swa b/services/registration/confirm_create_pin_swa deleted file mode 100644 index f697854..0000000 --- a/services/registration/confirm_create_pin_swa +++ /dev/null @@ -1 +0,0 @@ -Weka PIN yako tena: \ No newline at end of file diff --git a/services/registration/confirm_others_new_pin b/services/registration/confirm_others_new_pin deleted file mode 100644 index d345a0a..0000000 --- a/services/registration/confirm_others_new_pin +++ /dev/null @@ -1 +0,0 @@ -Please confirm new PIN for:{{.retrieve_blocked_number}} \ No newline at end of file diff --git a/services/registration/confirm_others_new_pin.vis b/services/registration/confirm_others_new_pin.vis deleted file mode 100644 index 9132dc4..0000000 --- a/services/registration/confirm_others_new_pin.vis +++ /dev/null @@ -1,14 +0,0 @@ -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 * diff --git a/services/registration/confirm_others_new_pin_swa b/services/registration/confirm_others_new_pin_swa deleted file mode 100644 index f0b09c8..0000000 --- a/services/registration/confirm_others_new_pin_swa +++ /dev/null @@ -1 +0,0 @@ -Tafadhali thibitisha PIN mpya ya: {{.retrieve_blocked_number}} \ No newline at end of file diff --git a/services/registration/confirm_pin_change b/services/registration/confirm_pin_change deleted file mode 100644 index 398a827..0000000 --- a/services/registration/confirm_pin_change +++ /dev/null @@ -1 +0,0 @@ -Confirm your new PIN: diff --git a/services/registration/confirm_pin_change.vis b/services/registration/confirm_pin_change.vis deleted file mode 100644 index cf485a1..0000000 --- a/services/registration/confirm_pin_change.vis +++ /dev/null @@ -1,5 +0,0 @@ -CATCH invalid_pin flag_valid_pin 0 -MOUT back 0 -HALT -INCMP _ 0 -INCMP * pin_reset_success diff --git a/services/registration/confirm_pin_change_swa b/services/registration/confirm_pin_change_swa deleted file mode 100644 index c7af4ea..0000000 --- a/services/registration/confirm_pin_change_swa +++ /dev/null @@ -1 +0,0 @@ -Thibitisha PIN yako mpya: diff --git a/services/registration/create_pin b/services/registration/create_pin deleted file mode 100644 index f8836f5..0000000 --- a/services/registration/create_pin +++ /dev/null @@ -1 +0,0 @@ -Please enter a new four number PIN for your account: \ No newline at end of file diff --git a/services/registration/create_pin.vis b/services/registration/create_pin.vis deleted file mode 100644 index 40989ec..0000000 --- a/services/registration/create_pin.vis +++ /dev/null @@ -1,9 +0,0 @@ -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 * diff --git a/services/registration/create_pin_mismatch b/services/registration/create_pin_mismatch deleted file mode 100644 index e75068c..0000000 --- a/services/registration/create_pin_mismatch +++ /dev/null @@ -1 +0,0 @@ -The PIN is not a match. Try again \ No newline at end of file diff --git a/services/registration/create_pin_mismatch.vis b/services/registration/create_pin_mismatch.vis deleted file mode 100644 index 91793b5..0000000 --- a/services/registration/create_pin_mismatch.vis +++ /dev/null @@ -1,5 +0,0 @@ -MOUT retry 1 -MOUT quit 9 -HALT -INCMP confirm_create_pin 1 -INCMP quit 9 diff --git a/services/registration/create_pin_mismatch_swa b/services/registration/create_pin_mismatch_swa deleted file mode 100644 index a1d7b6d..0000000 --- a/services/registration/create_pin_mismatch_swa +++ /dev/null @@ -1 +0,0 @@ -PIN uliyoweka haifanani. Jaribu tena \ No newline at end of file diff --git a/services/registration/create_pin_swa b/services/registration/create_pin_swa deleted file mode 100644 index 1fdd972..0000000 --- a/services/registration/create_pin_swa +++ /dev/null @@ -1 +0,0 @@ -Tafadhali weka PIN mpya yenye nambari nne kwa akaunti yako: \ No newline at end of file diff --git a/services/registration/display_profile_info b/services/registration/display_profile_info deleted file mode 100644 index 669c6c6..0000000 --- a/services/registration/display_profile_info +++ /dev/null @@ -1,5 +0,0 @@ -Wasifu wangu -Name: Not provided -Gender: Not provided -Age: Not provided -Location: Not provided \ No newline at end of file diff --git a/services/registration/display_profile_info.vis b/services/registration/display_profile_info.vis deleted file mode 100644 index 3790a08..0000000 --- a/services/registration/display_profile_info.vis +++ /dev/null @@ -1,3 +0,0 @@ -MOUT back 0 -HALT -INCMP _ 0 diff --git a/services/registration/display_profile_info_swa b/services/registration/display_profile_info_swa deleted file mode 100644 index e69de29..0000000 diff --git a/services/registration/edit_family_name b/services/registration/edit_family_name deleted file mode 100644 index 1d637be..0000000 --- a/services/registration/edit_family_name +++ /dev/null @@ -1,2 +0,0 @@ -Current family name: {{.get_current_profile_info}} -Enter family name: \ No newline at end of file diff --git a/services/registration/edit_family_name.vis b/services/registration/edit_family_name.vis deleted file mode 100644 index 590eab1..0000000 --- a/services/registration/edit_family_name.vis +++ /dev/null @@ -1,18 +0,0 @@ -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 * diff --git a/services/registration/edit_family_name_menu b/services/registration/edit_family_name_menu deleted file mode 100644 index 21a9033..0000000 --- a/services/registration/edit_family_name_menu +++ /dev/null @@ -1 +0,0 @@ -Edit family name \ No newline at end of file diff --git a/services/registration/edit_family_name_menu_swa b/services/registration/edit_family_name_menu_swa deleted file mode 100644 index 48a38b2..0000000 --- a/services/registration/edit_family_name_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Weka jina la familia \ No newline at end of file diff --git a/services/registration/edit_family_name_swa b/services/registration/edit_family_name_swa deleted file mode 100644 index a1a1cab..0000000 --- a/services/registration/edit_family_name_swa +++ /dev/null @@ -1,2 +0,0 @@ -Jina la familia la sasa: {{.get_current_profile_info}} -Weka jina la familia \ No newline at end of file diff --git a/services/registration/edit_first_name b/services/registration/edit_first_name deleted file mode 100644 index 3d141ee..0000000 --- a/services/registration/edit_first_name +++ /dev/null @@ -1,2 +0,0 @@ -Current name: {{.get_current_profile_info}} -Enter your first names: \ No newline at end of file diff --git a/services/registration/edit_first_name.vis b/services/registration/edit_first_name.vis deleted file mode 100644 index 6848b9c..0000000 --- a/services/registration/edit_first_name.vis +++ /dev/null @@ -1,18 +0,0 @@ -CATCH incorrect_pin flag_incorrect_pin 1 -CATCH update_firstname 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_firstname 128 -RELOAD save_firstname -CATCH pin_entry flag_firstname_set 1 -CATCH edit_family_name flag_familyname_set 0 -CATCH edit_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_firstname_set 0 diff --git a/services/registration/edit_first_name_menu b/services/registration/edit_first_name_menu deleted file mode 100644 index c7383b7..0000000 --- a/services/registration/edit_first_name_menu +++ /dev/null @@ -1 +0,0 @@ -Edit name \ No newline at end of file diff --git a/services/registration/edit_first_name_menu_swa b/services/registration/edit_first_name_menu_swa deleted file mode 100644 index 9395f7c..0000000 --- a/services/registration/edit_first_name_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Weka jina \ No newline at end of file diff --git a/services/registration/edit_first_name_swa b/services/registration/edit_first_name_swa deleted file mode 100644 index 5776bf0..0000000 --- a/services/registration/edit_first_name_swa +++ /dev/null @@ -1,2 +0,0 @@ -Jina la kwanza la sasa: {{.get_current_profile_info}} -Weka majina yako ya kwanza: \ No newline at end of file diff --git a/services/registration/edit_gender_menu b/services/registration/edit_gender_menu deleted file mode 100644 index 8946918..0000000 --- a/services/registration/edit_gender_menu +++ /dev/null @@ -1 +0,0 @@ -Edit gender \ No newline at end of file diff --git a/services/registration/edit_gender_menu_swa b/services/registration/edit_gender_menu_swa deleted file mode 100644 index 6d31ea8..0000000 --- a/services/registration/edit_gender_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Weka jinsia \ No newline at end of file diff --git a/services/registration/edit_location b/services/registration/edit_location deleted file mode 100644 index 4e11d1a..0000000 --- a/services/registration/edit_location +++ /dev/null @@ -1,2 +0,0 @@ -Current location: {{.get_current_profile_info}} -Enter your location: \ No newline at end of file diff --git a/services/registration/edit_location.vis b/services/registration/edit_location.vis deleted file mode 100644 index e4fcd8b..0000000 --- a/services/registration/edit_location.vis +++ /dev/null @@ -1,15 +0,0 @@ -CATCH incorrect_pin flag_incorrect_pin 1 -CATCH update_location flag_allow_update 1 -LOAD get_current_profile_info 0 -RELOAD get_current_profile_info -LOAD save_location 16 -MOUT back 0 -HALT -RELOAD set_back -CATCH _ flag_back_set 1 -RELOAD save_location -INCMP _ 0 -CATCH pin_entry flag_location_set 1 -CATCH edit_offerings flag_offerings_set 0 -CATCH pin_entry flag_location_set 0 -INCMP edit_offerings * diff --git a/services/registration/edit_location_menu b/services/registration/edit_location_menu deleted file mode 100644 index 39ff1b7..0000000 --- a/services/registration/edit_location_menu +++ /dev/null @@ -1 +0,0 @@ -Edit location \ No newline at end of file diff --git a/services/registration/edit_location_menu_swa b/services/registration/edit_location_menu_swa deleted file mode 100644 index a2a0e59..0000000 --- a/services/registration/edit_location_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Weka eneo \ No newline at end of file diff --git a/services/registration/edit_location_swa b/services/registration/edit_location_swa deleted file mode 100644 index 179c421..0000000 --- a/services/registration/edit_location_swa +++ /dev/null @@ -1,2 +0,0 @@ -Eneo la sasa: {{.get_current_profile_info}} -Weka eneo: \ No newline at end of file diff --git a/services/registration/edit_offerings b/services/registration/edit_offerings deleted file mode 100644 index 5bb0e7f..0000000 --- a/services/registration/edit_offerings +++ /dev/null @@ -1,2 +0,0 @@ -Current offerings: {{.get_current_profile_info}} -Enter the services or goods you offer: \ No newline at end of file diff --git a/services/registration/edit_offerings.vis b/services/registration/edit_offerings.vis deleted file mode 100644 index 9c1e747..0000000 --- a/services/registration/edit_offerings.vis +++ /dev/null @@ -1,13 +0,0 @@ -CATCH incorrect_pin flag_incorrect_pin 1 -CATCH update_offerings flag_allow_update 1 -LOAD get_current_profile_info 0 -RELOAD get_current_profile_info -LOAD save_offerings 8 -MOUT back 0 -HALT -RELOAD set_back -CATCH _ flag_back_set 1 -RELOAD save_offerings -INCMP _ 0 -CATCH pin_entry flag_offerings_set 1 -INCMP update_profile_items * diff --git a/services/registration/edit_offerings_menu b/services/registration/edit_offerings_menu deleted file mode 100644 index 477ad54..0000000 --- a/services/registration/edit_offerings_menu +++ /dev/null @@ -1 +0,0 @@ -Edit offerings \ No newline at end of file diff --git a/services/registration/edit_offerings_menu_swa b/services/registration/edit_offerings_menu_swa deleted file mode 100644 index f37e125..0000000 --- a/services/registration/edit_offerings_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Weka unachouza \ No newline at end of file diff --git a/services/registration/edit_offerings_swa b/services/registration/edit_offerings_swa deleted file mode 100644 index cd81497..0000000 --- a/services/registration/edit_offerings_swa +++ /dev/null @@ -1,2 +0,0 @@ -Unachouza kwa sasa: {{.get_current_profile_info}} -Weka unachouza \ No newline at end of file diff --git a/services/registration/edit_profile b/services/registration/edit_profile deleted file mode 100644 index 2c808e6..0000000 --- a/services/registration/edit_profile +++ /dev/null @@ -1 +0,0 @@ -My profile \ No newline at end of file diff --git a/services/registration/edit_profile.vis b/services/registration/edit_profile.vis deleted file mode 100644 index 0f0adb7..0000000 --- a/services/registration/edit_profile.vis +++ /dev/null @@ -1,23 +0,0 @@ -LOAD reset_account_authorized 16 -RELOAD reset_account_authorized -LOAD reset_allow_update 0 -RELOAD reset_allow_update -MOUT edit_first_name 1 -MOUT edit_family_name 2 -MOUT edit_gender 3 -MOUT edit_yob 4 -MOUT edit_location 5 -MOUT edit_offerings 6 -MOUT view 7 -MOUT back 0 -HALT -LOAD set_back 6 -INCMP ^ 0 -INCMP edit_first_name 1 -INCMP edit_family_name 2 -INCMP select_gender 3 -INCMP edit_yob 4 -INCMP edit_location 5 -INCMP edit_offerings 6 -INCMP view_profile 7 -INCMP . * diff --git a/services/registration/edit_profile_swa b/services/registration/edit_profile_swa deleted file mode 100644 index 8a12b7d..0000000 --- a/services/registration/edit_profile_swa +++ /dev/null @@ -1 +0,0 @@ -Wasifu wangu \ No newline at end of file diff --git a/services/registration/edit_yob b/services/registration/edit_yob deleted file mode 100644 index 105812b..0000000 --- a/services/registration/edit_yob +++ /dev/null @@ -1,2 +0,0 @@ -Current year of birth: {{.get_current_profile_info}} -Enter your year of birth \ No newline at end of file diff --git a/services/registration/edit_yob.vis b/services/registration/edit_yob.vis deleted file mode 100644 index 255bea5..0000000 --- a/services/registration/edit_yob.vis +++ /dev/null @@ -1,19 +0,0 @@ -CATCH incorrect_pin flag_incorrect_pin 1 -CATCH update_yob 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 verify_yob 6 -RELOAD verify_yob -CATCH incorrect_date_format flag_incorrect_date_format 1 -LOAD save_yob 32 -RELOAD save_yob -CATCH pin_entry flag_yob_set 1 -CATCH edit_location flag_location_set 0 -CATCH edit_offerings flag_offerings_set 0 -CATCH pin_entry flag_yob_set 0 -INCMP edit_location * diff --git a/services/registration/edit_yob_menu b/services/registration/edit_yob_menu deleted file mode 100644 index 3451781..0000000 --- a/services/registration/edit_yob_menu +++ /dev/null @@ -1 +0,0 @@ -Edit year of birth \ No newline at end of file diff --git a/services/registration/edit_yob_menu_swa b/services/registration/edit_yob_menu_swa deleted file mode 100644 index 9bb272a..0000000 --- a/services/registration/edit_yob_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Weka mwaka wa kuzaliwa \ No newline at end of file diff --git a/services/registration/edit_yob_swa b/services/registration/edit_yob_swa deleted file mode 100644 index f923c86..0000000 --- a/services/registration/edit_yob_swa +++ /dev/null @@ -1,2 +0,0 @@ -Mwaka wa sasa wa kuzaliwa: {{.get_current_profile_info}} -Weka mwaka wa kuzaliwa \ No newline at end of file diff --git a/services/registration/english_menu b/services/registration/english_menu deleted file mode 100644 index 3d38949..0000000 --- a/services/registration/english_menu +++ /dev/null @@ -1 +0,0 @@ -English \ No newline at end of file diff --git a/services/registration/enter_other_number b/services/registration/enter_other_number deleted file mode 100644 index 1c4a481..0000000 --- a/services/registration/enter_other_number +++ /dev/null @@ -1 +0,0 @@ -Enter other's phone number: \ No newline at end of file diff --git a/services/registration/enter_other_number.vis b/services/registration/enter_other_number.vis deleted file mode 100644 index 0957165..0000000 --- a/services/registration/enter_other_number.vis +++ /dev/null @@ -1,7 +0,0 @@ -CATCH no_admin_privilege flag_admin_privilege 0 -LOAD reset_account_authorized 0 -RELOAD reset_account_authorized -MOUT back 0 -HALT -INCMP _ 0 -INCMP enter_others_new_pin * diff --git a/services/registration/enter_other_number_swa b/services/registration/enter_other_number_swa deleted file mode 100644 index 214fc4a..0000000 --- a/services/registration/enter_other_number_swa +++ /dev/null @@ -1 +0,0 @@ -Weka nambari ya simu ili kutuma ombi la kubadilisha nambari ya siri: \ No newline at end of file diff --git a/services/registration/enter_others_new_pin b/services/registration/enter_others_new_pin deleted file mode 100644 index 52ae664..0000000 --- a/services/registration/enter_others_new_pin +++ /dev/null @@ -1 +0,0 @@ -Please enter new PIN for: {{.retrieve_blocked_number}} \ No newline at end of file diff --git a/services/registration/enter_others_new_pin.vis b/services/registration/enter_others_new_pin.vis deleted file mode 100644 index 7711c97..0000000 --- a/services/registration/enter_others_new_pin.vis +++ /dev/null @@ -1,12 +0,0 @@ -LOAD validate_blocked_number 6 -RELOAD validate_blocked_number -CATCH unregistered_number flag_unregistered_number 1 -LOAD retrieve_blocked_number 0 -RELOAD retrieve_blocked_number -MAP retrieve_blocked_number -MOUT back 0 -HALT -LOAD verify_new_pin 6 -RELOAD verify_new_pin -INCMP _ 0 -INCMP * confirm_others_new_pin diff --git a/services/registration/enter_others_new_pin_swa b/services/registration/enter_others_new_pin_swa deleted file mode 100644 index 77ec2f3..0000000 --- a/services/registration/enter_others_new_pin_swa +++ /dev/null @@ -1 +0,0 @@ -Tafadhali weka PIN mpya ya: {{.retrieve_blocked_number}} \ No newline at end of file diff --git a/services/registration/enter_pin b/services/registration/enter_pin deleted file mode 100644 index cbb44ca..0000000 --- a/services/registration/enter_pin +++ /dev/null @@ -1 +0,0 @@ -Please enter your PIN: \ No newline at end of file diff --git a/services/registration/enter_pin.vis b/services/registration/enter_pin.vis deleted file mode 100644 index 1217074..0000000 --- a/services/registration/enter_pin.vis +++ /dev/null @@ -1,4 +0,0 @@ -MOUT back 0 -HALT -INCMP _ 0 -INCMP display_profile_info * diff --git a/services/registration/enter_pin_swa b/services/registration/enter_pin_swa deleted file mode 100644 index bb30cfd..0000000 --- a/services/registration/enter_pin_swa +++ /dev/null @@ -1 +0,0 @@ -Weka PIN yako \ No newline at end of file diff --git a/services/registration/exit_menu b/services/registration/exit_menu deleted file mode 100644 index 1105a55..0000000 --- a/services/registration/exit_menu +++ /dev/null @@ -1 +0,0 @@ -Exit \ No newline at end of file diff --git a/services/registration/exit_menu_swa b/services/registration/exit_menu_swa deleted file mode 100644 index 474f1ff..0000000 --- a/services/registration/exit_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Ondoka \ No newline at end of file diff --git a/services/registration/female_menu b/services/registration/female_menu deleted file mode 100644 index 18b94e5..0000000 --- a/services/registration/female_menu +++ /dev/null @@ -1 +0,0 @@ -Female \ No newline at end of file diff --git a/services/registration/female_menu_swa b/services/registration/female_menu_swa deleted file mode 100644 index 0506300..0000000 --- a/services/registration/female_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Mwanamke \ No newline at end of file diff --git a/services/registration/help.vis b/services/registration/help.vis deleted file mode 100644 index 6244d4d..0000000 --- a/services/registration/help.vis +++ /dev/null @@ -1,2 +0,0 @@ -LOAD quit_with_help 0 -HALT diff --git a/services/registration/help_menu b/services/registration/help_menu deleted file mode 100644 index 0c64ced..0000000 --- a/services/registration/help_menu +++ /dev/null @@ -1 +0,0 @@ -Help \ No newline at end of file diff --git a/services/registration/help_menu_swa b/services/registration/help_menu_swa deleted file mode 100644 index 393e0c8..0000000 --- a/services/registration/help_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Usaidizi \ No newline at end of file diff --git a/services/registration/incorrect_date_format b/services/registration/incorrect_date_format deleted file mode 100644 index 56df792..0000000 --- a/services/registration/incorrect_date_format +++ /dev/null @@ -1,2 +0,0 @@ -The year of birth you entered is invalid. -Please try again. \ No newline at end of file diff --git a/services/registration/incorrect_date_format.vis b/services/registration/incorrect_date_format.vis deleted file mode 100644 index f4a8a2b..0000000 --- a/services/registration/incorrect_date_format.vis +++ /dev/null @@ -1,6 +0,0 @@ -LOAD reset_incorrect_date_format 8 -MOUT retry 1 -MOUT quit 9 -HALT -INCMP _ 1 -INCMP quit 9 diff --git a/services/registration/incorrect_date_format_swa b/services/registration/incorrect_date_format_swa deleted file mode 100644 index bd85f21..0000000 --- a/services/registration/incorrect_date_format_swa +++ /dev/null @@ -1,2 +0,0 @@ -Mwaka wa kuzaliwa ulioweka sio sahihi. -Tafadhali jaribu tena. \ No newline at end of file diff --git a/services/registration/incorrect_pin b/services/registration/incorrect_pin deleted file mode 100644 index 13a9562..0000000 --- a/services/registration/incorrect_pin +++ /dev/null @@ -1 +0,0 @@ -Incorrect PIN. You have: {{.reset_incorrect}} remaining attempt(s). \ No newline at end of file diff --git a/services/registration/incorrect_pin.vis b/services/registration/incorrect_pin.vis deleted file mode 100644 index 167364a..0000000 --- a/services/registration/incorrect_pin.vis +++ /dev/null @@ -1,9 +0,0 @@ -LOAD reset_incorrect 0 -RELOAD reset_incorrect -MAP reset_incorrect -CATCH blocked_account flag_account_blocked 1 -MOUT retry 1 -MOUT quit 9 -HALT -INCMP _ 1 -INCMP quit 9 diff --git a/services/registration/incorrect_pin_swa b/services/registration/incorrect_pin_swa deleted file mode 100644 index ed22beb..0000000 --- a/services/registration/incorrect_pin_swa +++ /dev/null @@ -1 +0,0 @@ -PIN ulioeka sio sahihi, una majaribio: {{.reset_incorrect}} yaliyobaki \ No newline at end of file diff --git a/services/registration/invalid_amount b/services/registration/invalid_amount deleted file mode 100644 index c4bbe3f..0000000 --- a/services/registration/invalid_amount +++ /dev/null @@ -1 +0,0 @@ -Amount {{.validate_amount}} is invalid, please try again: \ No newline at end of file diff --git a/services/registration/invalid_amount.vis b/services/registration/invalid_amount.vis deleted file mode 100644 index d5b5f03..0000000 --- a/services/registration/invalid_amount.vis +++ /dev/null @@ -1,7 +0,0 @@ -MAP validate_amount -RELOAD reset_transaction_amount -MOUT retry 1 -MOUT quit 9 -HALT -INCMP _ 1 -INCMP quit 9 diff --git a/services/registration/invalid_amount_swa b/services/registration/invalid_amount_swa deleted file mode 100644 index 836d7b2..0000000 --- a/services/registration/invalid_amount_swa +++ /dev/null @@ -1 +0,0 @@ -Kiwango {{.validate_amount}} sio sahihi, tafadhali weka tena: \ No newline at end of file diff --git a/services/registration/invalid_others_pin b/services/registration/invalid_others_pin deleted file mode 100644 index acdf45f..0000000 --- a/services/registration/invalid_others_pin +++ /dev/null @@ -1 +0,0 @@ -The PIN you have entered is invalid.Please try a 4 digit number instead. \ No newline at end of file diff --git a/services/registration/invalid_others_pin.vis b/services/registration/invalid_others_pin.vis deleted file mode 100644 index d218e6d..0000000 --- a/services/registration/invalid_others_pin.vis +++ /dev/null @@ -1,5 +0,0 @@ -MOUT retry 1 -MOUT quit 9 -HALT -INCMP enter_others_new_pin 1 -INCMP quit 9 diff --git a/services/registration/invalid_pin b/services/registration/invalid_pin deleted file mode 100644 index dd984ea..0000000 --- a/services/registration/invalid_pin +++ /dev/null @@ -1 +0,0 @@ -The PIN you entered is invalid.The PIN must be different from your current PIN.For help call +254757628885 \ No newline at end of file diff --git a/services/registration/invalid_pin.vis b/services/registration/invalid_pin.vis deleted file mode 100644 index 3790a08..0000000 --- a/services/registration/invalid_pin.vis +++ /dev/null @@ -1,3 +0,0 @@ -MOUT back 0 -HALT -INCMP _ 0 diff --git a/services/registration/invalid_pin_swa b/services/registration/invalid_pin_swa deleted file mode 100644 index 7512242..0000000 --- a/services/registration/invalid_pin_swa +++ /dev/null @@ -1 +0,0 @@ -PIN mpya na udhibitisho wa PIN mpya hazilingani.Tafadhali jaribu tena.Kwa usaidizi piga simu +254757628885. diff --git a/services/registration/invalid_recipient b/services/registration/invalid_recipient deleted file mode 100644 index d9fcb1d..0000000 --- a/services/registration/invalid_recipient +++ /dev/null @@ -1 +0,0 @@ -{{.validate_recipient}} is invalid, please try again: \ No newline at end of file diff --git a/services/registration/invalid_recipient.vis b/services/registration/invalid_recipient.vis deleted file mode 100644 index 09efdde..0000000 --- a/services/registration/invalid_recipient.vis +++ /dev/null @@ -1,7 +0,0 @@ -MAP validate_recipient -RELOAD transaction_reset -MOUT retry 1 -MOUT quit 9 -HALT -INCMP _ 1 -INCMP quit 9 diff --git a/services/registration/invalid_recipient_swa b/services/registration/invalid_recipient_swa deleted file mode 100644 index 13dda97..0000000 --- a/services/registration/invalid_recipient_swa +++ /dev/null @@ -1 +0,0 @@ -{{.validate_recipient}} sio sahihi, tafadhali weka tena: \ No newline at end of file diff --git a/services/registration/invite_menu b/services/registration/invite_menu deleted file mode 100644 index e44862a..0000000 --- a/services/registration/invite_menu +++ /dev/null @@ -1 +0,0 @@ -Invite to Sarafu Network \ No newline at end of file diff --git a/services/registration/invite_menu_swa b/services/registration/invite_menu_swa deleted file mode 100644 index 48c0ddf..0000000 --- a/services/registration/invite_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Karibisha kwa matandao wa Sarafu \ No newline at end of file diff --git a/services/registration/invite_recipient b/services/registration/invite_recipient deleted file mode 100644 index aa3438d..0000000 --- a/services/registration/invite_recipient +++ /dev/null @@ -1 +0,0 @@ -{{.validate_recipient}} is not registered, please try again: \ No newline at end of file diff --git a/services/registration/invite_recipient.vis b/services/registration/invite_recipient.vis deleted file mode 100644 index 1a4845f..0000000 --- a/services/registration/invite_recipient.vis +++ /dev/null @@ -1,8 +0,0 @@ -MAP validate_recipient -MOUT retry 1 -MOUT invite 2 -MOUT quit 9 -HALT -INCMP _ 1 -INCMP invite_result 2 -INCMP quit 9 diff --git a/services/registration/invite_recipient_swa b/services/registration/invite_recipient_swa deleted file mode 100644 index 30cf599..0000000 --- a/services/registration/invite_recipient_swa +++ /dev/null @@ -1 +0,0 @@ -{{.validate_recipient}} haijasajiliwa, tafadhali weka tena: \ No newline at end of file diff --git a/services/registration/invite_result.vis b/services/registration/invite_result.vis deleted file mode 100644 index 5f31749..0000000 --- a/services/registration/invite_result.vis +++ /dev/null @@ -1,2 +0,0 @@ -LOAD invite_valid_recipient 0 -HALT diff --git a/services/registration/kiswahili_menu b/services/registration/kiswahili_menu deleted file mode 100644 index e4d88a5..0000000 --- a/services/registration/kiswahili_menu +++ /dev/null @@ -1 +0,0 @@ -Kiswahili \ No newline at end of file diff --git a/services/registration/language_changed b/services/registration/language_changed deleted file mode 100644 index 839a631..0000000 --- a/services/registration/language_changed +++ /dev/null @@ -1 +0,0 @@ -Your language change request was successful. \ No newline at end of file diff --git a/services/registration/language_changed.vis b/services/registration/language_changed.vis deleted file mode 100644 index 832ef22..0000000 --- a/services/registration/language_changed.vis +++ /dev/null @@ -1,5 +0,0 @@ -MOUT back 0 -MOUT quit 9 -HALT -INCMP ^ 0 -INCMP quit 9 diff --git a/services/registration/language_changed_swa b/services/registration/language_changed_swa deleted file mode 100644 index 4a7f03b..0000000 --- a/services/registration/language_changed_swa +++ /dev/null @@ -1 +0,0 @@ -Ombi lako la kubadilisha lugha limefanikiwa. \ No newline at end of file diff --git a/services/registration/list_offering b/services/registration/list_offering deleted file mode 100644 index e69de29..0000000 diff --git a/services/registration/list_offering.vis b/services/registration/list_offering.vis deleted file mode 100644 index e69de29..0000000 diff --git a/services/registration/locale/swa/default.po b/services/registration/locale/swa/default.po deleted file mode 100644 index 6155063..0000000 --- a/services/registration/locale/swa/default.po +++ /dev/null @@ -1,32 +0,0 @@ -msgid "Your account balance is %s" -msgstr "Salio lako ni %s" - -msgid "Your request has been sent. %s will receive %s %s from %s." -msgstr "Ombi lako limetumwa. %s atapokea %s %s kutoka kwa %s." - -msgid "Thank you for using Sarafu. Goodbye!" -msgstr "Asante kwa kutumia huduma ya Sarafu. Kwaheri!" - -msgid "For more help, please call: 0757628885" -msgstr "Kwa usaidizi zaidi, piga: 0757628885" - -msgid "Your account has been locked. For help on how to unblock your account, contact support at: 0757628885" -msgstr "Akaunti yako imefungwa. Kwa usaidizi wa jinsi ya kufungua akaunti yako, wasiliana na usaidizi kwa: 0757628885" - -msgid "Balance: %s\n" -msgstr "Salio: %s\n" - -msgid "Your invite request for %s to Sarafu Network failed. Please try again later." -msgstr "Ombi lako la kumwalika %s kwa matandao wa Sarafu halikufaulu. Tafadhali jaribu tena baadaye." - -msgid "Your invitation to %s to join Sarafu Network has been sent." -msgstr "Ombi lako la kumwalika %s kwa matandao wa Sarafu limetumwa." - -msgid "Your request failed. Please try again later." -msgstr "Ombi lako halikufaulu. Tafadhali jaribu tena baadaye." - -msgid "Community Balance: 0.00" -msgstr "Salio la Kikundi: 0.00" - -msgid "Symbol: %s\nBalance: %s" -msgstr "Sarafu: %s\nSalio: %s" diff --git a/services/registration/main b/services/registration/main deleted file mode 100644 index afae8c1..0000000 --- a/services/registration/main +++ /dev/null @@ -1 +0,0 @@ -{{.check_balance}} \ No newline at end of file diff --git a/services/registration/main.vis b/services/registration/main.vis deleted file mode 100644 index 2982f47..0000000 --- a/services/registration/main.vis +++ /dev/null @@ -1,20 +0,0 @@ -LOAD set_default_voucher 8 -RELOAD set_default_voucher -LOAD check_vouchers 10 -RELOAD check_vouchers -LOAD check_balance 128 -RELOAD check_balance -CATCH api_failure flag_api_call_error 1 -MAP check_balance -MOUT send 1 -MOUT vouchers 2 -MOUT account 3 -MOUT help 4 -MOUT quit 9 -HALT -INCMP send 1 -INCMP my_vouchers 2 -INCMP my_account 3 -INCMP help 4 -INCMP quit 9 -INCMP . * diff --git a/services/registration/main_swa b/services/registration/main_swa deleted file mode 100644 index afae8c1..0000000 --- a/services/registration/main_swa +++ /dev/null @@ -1 +0,0 @@ -{{.check_balance}} \ No newline at end of file diff --git a/services/registration/male_menu b/services/registration/male_menu deleted file mode 100644 index 183883f..0000000 --- a/services/registration/male_menu +++ /dev/null @@ -1 +0,0 @@ -Male \ No newline at end of file diff --git a/services/registration/male_menu_swa b/services/registration/male_menu_swa deleted file mode 100644 index 7afdee9..0000000 --- a/services/registration/male_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Mwanaume \ No newline at end of file diff --git a/services/registration/my_account b/services/registration/my_account deleted file mode 100644 index 7aa9fe9..0000000 --- a/services/registration/my_account +++ /dev/null @@ -1 +0,0 @@ -My Account \ No newline at end of file diff --git a/services/registration/my_account.vis b/services/registration/my_account.vis deleted file mode 100644 index e3956d2..0000000 --- a/services/registration/my_account.vis +++ /dev/null @@ -1,17 +0,0 @@ -LOAD reset_allow_update 0 -MOUT profile 1 -MOUT change_language 2 -MOUT check_balance 3 -MOUT check_statement 4 -MOUT pin_options 5 -MOUT my_address 6 -MOUT back 0 -HALT -INCMP main 0 -INCMP edit_profile 1 -INCMP change_language 2 -INCMP balances 3 -INCMP check_statement 4 -INCMP pin_management 5 -INCMP address 6 -INCMP . * diff --git a/services/registration/my_account_swa b/services/registration/my_account_swa deleted file mode 100644 index c77102f..0000000 --- a/services/registration/my_account_swa +++ /dev/null @@ -1 +0,0 @@ -Akaunti yangu \ No newline at end of file diff --git a/services/registration/my_address_menu b/services/registration/my_address_menu deleted file mode 100644 index 5c13a7d..0000000 --- a/services/registration/my_address_menu +++ /dev/null @@ -1 +0,0 @@ -My Address \ No newline at end of file diff --git a/services/registration/my_address_menu_swa b/services/registration/my_address_menu_swa deleted file mode 100644 index 531bc4e..0000000 --- a/services/registration/my_address_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Anwani yangu \ No newline at end of file diff --git a/services/registration/my_balance b/services/registration/my_balance deleted file mode 100644 index afae8c1..0000000 --- a/services/registration/my_balance +++ /dev/null @@ -1 +0,0 @@ -{{.check_balance}} \ No newline at end of file diff --git a/services/registration/my_balance.vis b/services/registration/my_balance.vis deleted file mode 100644 index b6094c0..0000000 --- a/services/registration/my_balance.vis +++ /dev/null @@ -1,12 +0,0 @@ -LOAD reset_incorrect 6 -LOAD check_balance 0 -CATCH api_failure flag_api_call_error 1 -MAP check_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 . * diff --git a/services/registration/my_balance_menu b/services/registration/my_balance_menu deleted file mode 100644 index fdd930b..0000000 --- a/services/registration/my_balance_menu +++ /dev/null @@ -1 +0,0 @@ -My balance \ No newline at end of file diff --git a/services/registration/my_balance_menu_swa b/services/registration/my_balance_menu_swa deleted file mode 100644 index 810c386..0000000 --- a/services/registration/my_balance_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Salio langu \ No newline at end of file diff --git a/services/registration/my_balance_swa b/services/registration/my_balance_swa deleted file mode 100644 index afae8c1..0000000 --- a/services/registration/my_balance_swa +++ /dev/null @@ -1 +0,0 @@ -{{.check_balance}} \ No newline at end of file diff --git a/services/registration/my_vouchers b/services/registration/my_vouchers deleted file mode 100644 index 548de9c..0000000 --- a/services/registration/my_vouchers +++ /dev/null @@ -1 +0,0 @@ -My vouchers \ No newline at end of file diff --git a/services/registration/my_vouchers.vis b/services/registration/my_vouchers.vis deleted file mode 100644 index e79438e..0000000 --- a/services/registration/my_vouchers.vis +++ /dev/null @@ -1,9 +0,0 @@ -LOAD reset_account_authorized 16 -RELOAD reset_account_authorized -MOUT select_voucher 1 -MOUT voucher_details 2 -MOUT back 0 -HALT -INCMP _ 0 -INCMP select_voucher 1 -INCMP voucher_details 2 diff --git a/services/registration/new_pin b/services/registration/new_pin deleted file mode 100644 index 65d8ed3..0000000 --- a/services/registration/new_pin +++ /dev/null @@ -1 +0,0 @@ -Enter a new four number PIN: diff --git a/services/registration/new_pin.vis b/services/registration/new_pin.vis deleted file mode 100644 index 29013a9..0000000 --- a/services/registration/new_pin.vis +++ /dev/null @@ -1,13 +0,0 @@ -LOAD authorize_account 12 -RELOAD authorize_account -CATCH incorrect_pin flag_incorrect_pin 1 -CATCH old_pin flag_allow_update 0 -MOUT back 0 -HALT -INCMP _ 0 -LOAD save_temporary_pin 6 -LOAD verify_new_pin 0 -RELOAD save_temporary_pin -RELOAD verify_new_pin -INCMP * confirm_pin_change - diff --git a/services/registration/new_pin_swa b/services/registration/new_pin_swa deleted file mode 100644 index 1ec32d9..0000000 --- a/services/registration/new_pin_swa +++ /dev/null @@ -1,2 +0,0 @@ -Weka PIN mpya ya nne nambari: - diff --git a/services/registration/next_menu b/services/registration/next_menu deleted file mode 100644 index e2e838e..0000000 --- a/services/registration/next_menu +++ /dev/null @@ -1 +0,0 @@ -Next \ No newline at end of file diff --git a/services/registration/next_menu_swa b/services/registration/next_menu_swa deleted file mode 100644 index 6511e40..0000000 --- a/services/registration/next_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Mbele \ No newline at end of file diff --git a/services/registration/no_admin_privilege b/services/registration/no_admin_privilege deleted file mode 100644 index 27901dc..0000000 --- a/services/registration/no_admin_privilege +++ /dev/null @@ -1 +0,0 @@ -You do not have privileges to perform this action diff --git a/services/registration/no_admin_privilege.vis b/services/registration/no_admin_privilege.vis deleted file mode 100644 index 3cf1e4c..0000000 --- a/services/registration/no_admin_privilege.vis +++ /dev/null @@ -1,5 +0,0 @@ -MOUT quit 9 -MOUT back 0 -HALT -INCMP pin_management 0 -INCMP quit 9 diff --git a/services/registration/no_admin_privilege_swa b/services/registration/no_admin_privilege_swa deleted file mode 100644 index 6c6d3dc..0000000 --- a/services/registration/no_admin_privilege_swa +++ /dev/null @@ -1 +0,0 @@ -Huna mapendeleo ya kufanya kitendo hiki \ No newline at end of file diff --git a/services/registration/no_menu b/services/registration/no_menu deleted file mode 100644 index 289cc91..0000000 --- a/services/registration/no_menu +++ /dev/null @@ -1 +0,0 @@ -No \ No newline at end of file diff --git a/services/registration/no_menu_swa b/services/registration/no_menu_swa deleted file mode 100644 index a9d6b8d..0000000 --- a/services/registration/no_menu_swa +++ /dev/null @@ -1 +0,0 @@ -La \ No newline at end of file diff --git a/services/registration/no_transfers b/services/registration/no_transfers deleted file mode 100644 index 3439806..0000000 --- a/services/registration/no_transfers +++ /dev/null @@ -1 +0,0 @@ -No transfers history \ No newline at end of file diff --git a/services/registration/no_transfers.vis b/services/registration/no_transfers.vis deleted file mode 100644 index 832ef22..0000000 --- a/services/registration/no_transfers.vis +++ /dev/null @@ -1,5 +0,0 @@ -MOUT back 0 -MOUT quit 9 -HALT -INCMP ^ 0 -INCMP quit 9 diff --git a/services/registration/no_transfers_swa b/services/registration/no_transfers_swa deleted file mode 100644 index 1f82e82..0000000 --- a/services/registration/no_transfers_swa +++ /dev/null @@ -1 +0,0 @@ -Hakuna historia kwa akaunti yako \ No newline at end of file diff --git a/services/registration/no_voucher b/services/registration/no_voucher deleted file mode 100644 index 6303197..0000000 --- a/services/registration/no_voucher +++ /dev/null @@ -1 +0,0 @@ -You need a voucher to proceed \ No newline at end of file diff --git a/services/registration/no_voucher.vis b/services/registration/no_voucher.vis deleted file mode 100644 index 832ef22..0000000 --- a/services/registration/no_voucher.vis +++ /dev/null @@ -1,5 +0,0 @@ -MOUT back 0 -MOUT quit 9 -HALT -INCMP ^ 0 -INCMP quit 9 diff --git a/services/registration/no_voucher_swa b/services/registration/no_voucher_swa deleted file mode 100644 index 7291650..0000000 --- a/services/registration/no_voucher_swa +++ /dev/null @@ -1 +0,0 @@ -Unahitaji sarafu kuendelea \ No newline at end of file diff --git a/services/registration/old_pin b/services/registration/old_pin deleted file mode 100644 index 2c64d42..0000000 --- a/services/registration/old_pin +++ /dev/null @@ -1 +0,0 @@ -Enter your old PIN diff --git a/services/registration/old_pin.vis b/services/registration/old_pin.vis deleted file mode 100644 index 1e99f4f..0000000 --- a/services/registration/old_pin.vis +++ /dev/null @@ -1,7 +0,0 @@ -LOAD reset_allow_update 0 -MOUT back 0 -HALT -RELOAD reset_allow_update -INCMP _ 0 -INCMP new_pin * - diff --git a/services/registration/old_pin_swa b/services/registration/old_pin_swa deleted file mode 100644 index 312b597..0000000 --- a/services/registration/old_pin_swa +++ /dev/null @@ -1 +0,0 @@ -Weka PIN yako ya zamani: diff --git a/services/registration/others_pin_mismatch b/services/registration/others_pin_mismatch deleted file mode 100644 index deb9fe5..0000000 --- a/services/registration/others_pin_mismatch +++ /dev/null @@ -1 +0,0 @@ -The PIN you have entered is not a match diff --git a/services/registration/others_pin_mismatch.vis b/services/registration/others_pin_mismatch.vis deleted file mode 100644 index 37b3deb..0000000 --- a/services/registration/others_pin_mismatch.vis +++ /dev/null @@ -1,5 +0,0 @@ -MOUT retry 1 -MOUT quit 9 -HALT -INCMP _ 1 -INCMP quit 9 diff --git a/services/registration/others_pin_mismatch_swa b/services/registration/others_pin_mismatch_swa deleted file mode 100644 index 5787790..0000000 --- a/services/registration/others_pin_mismatch_swa +++ /dev/null @@ -1 +0,0 @@ -PIN uliyoweka hailingani.Jaribu tena. \ No newline at end of file diff --git a/services/registration/pin_entry b/services/registration/pin_entry deleted file mode 100644 index cbb44ca..0000000 --- a/services/registration/pin_entry +++ /dev/null @@ -1 +0,0 @@ -Please enter your PIN: \ No newline at end of file diff --git a/services/registration/pin_entry.vis b/services/registration/pin_entry.vis deleted file mode 100644 index 2eaf40f..0000000 --- a/services/registration/pin_entry.vis +++ /dev/null @@ -1,4 +0,0 @@ -LOAD authorize_account 0 -HALT -RELOAD authorize_account -MOVE _ diff --git a/services/registration/pin_entry_swa b/services/registration/pin_entry_swa deleted file mode 100644 index 1b5e646..0000000 --- a/services/registration/pin_entry_swa +++ /dev/null @@ -1 +0,0 @@ -Tafadhali weka PIN yako \ No newline at end of file diff --git a/services/registration/pin_management b/services/registration/pin_management deleted file mode 100644 index b60e816..0000000 --- a/services/registration/pin_management +++ /dev/null @@ -1 +0,0 @@ -PIN Management \ No newline at end of file diff --git a/services/registration/pin_management.vis b/services/registration/pin_management.vis deleted file mode 100644 index 5eb7d5a..0000000 --- a/services/registration/pin_management.vis +++ /dev/null @@ -1,8 +0,0 @@ -MOUT change_pin 1 -MOUT reset_pin 2 -MOUT back 0 -HALT -INCMP my_account 0 -INCMP old_pin 1 -INCMP enter_other_number 2 -INCMP . * diff --git a/services/registration/pin_management_swa b/services/registration/pin_management_swa deleted file mode 100644 index e69de29..0000000 diff --git a/services/registration/pin_options_menu b/services/registration/pin_options_menu deleted file mode 100644 index 778d28d..0000000 --- a/services/registration/pin_options_menu +++ /dev/null @@ -1 +0,0 @@ -PIN options \ No newline at end of file diff --git a/services/registration/pin_options_menu_swa b/services/registration/pin_options_menu_swa deleted file mode 100644 index e47ca0f..0000000 --- a/services/registration/pin_options_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Mipangilio ya PIN \ No newline at end of file diff --git a/services/registration/pin_reset_mismatch b/services/registration/pin_reset_mismatch deleted file mode 100644 index dc0236b..0000000 --- a/services/registration/pin_reset_mismatch +++ /dev/null @@ -1 +0,0 @@ -The PIN is not a match. Try again diff --git a/services/registration/pin_reset_mismatch.vis b/services/registration/pin_reset_mismatch.vis deleted file mode 100644 index 5dc7e7c..0000000 --- a/services/registration/pin_reset_mismatch.vis +++ /dev/null @@ -1,6 +0,0 @@ -MOUT retry 1 -MOUT quit 9 -HALT -INCMP confirm_pin_change 1 -INCMP quit 9 - diff --git a/services/registration/pin_reset_mismatch_swa b/services/registration/pin_reset_mismatch_swa deleted file mode 100644 index 5787790..0000000 --- a/services/registration/pin_reset_mismatch_swa +++ /dev/null @@ -1 +0,0 @@ -PIN uliyoweka hailingani.Jaribu tena. \ No newline at end of file diff --git a/services/registration/pin_reset_result b/services/registration/pin_reset_result deleted file mode 100644 index 60554b9..0000000 --- a/services/registration/pin_reset_result +++ /dev/null @@ -1 +0,0 @@ -PIN reset request for {{.retrieve_blocked_number}} was successful \ No newline at end of file diff --git a/services/registration/pin_reset_result.vis b/services/registration/pin_reset_result.vis deleted file mode 100644 index 34b9789..0000000 --- a/services/registration/pin_reset_result.vis +++ /dev/null @@ -1,8 +0,0 @@ -LOAD retrieve_blocked_number 0 -MAP retrieve_blocked_number -LOAD reset_others_pin 6 -MOUT back 0 -MOUT quit 9 -HALT -INCMP pin_management 0 -INCMP quit 9 diff --git a/services/registration/pin_reset_result_swa b/services/registration/pin_reset_result_swa deleted file mode 100644 index 30de04e..0000000 --- a/services/registration/pin_reset_result_swa +++ /dev/null @@ -1 +0,0 @@ -Ombi la kuweka upya PIN ya {{.retrieve_blocked_number}} limefanikiwa \ No newline at end of file diff --git a/services/registration/pin_reset_success b/services/registration/pin_reset_success deleted file mode 100644 index e9326ec..0000000 --- a/services/registration/pin_reset_success +++ /dev/null @@ -1 +0,0 @@ -Your PIN change request has been successful diff --git a/services/registration/pin_reset_success.vis b/services/registration/pin_reset_success.vis deleted file mode 100644 index 96dee73..0000000 --- a/services/registration/pin_reset_success.vis +++ /dev/null @@ -1,8 +0,0 @@ -LOAD confirm_pin_change 0 -RELOAD confirm_pin_change -CATCH pin_reset_mismatch flag_pin_mismatch 1 -MOUT back 0 -MOUT quit 9 -HALT -INCMP main 0 -INCMP quit 9 diff --git a/services/registration/pin_reset_success_swa b/services/registration/pin_reset_success_swa deleted file mode 100644 index af69b9f..0000000 --- a/services/registration/pin_reset_success_swa +++ /dev/null @@ -1 +0,0 @@ -Ombi lako la kubadili PIN limefanikiwa diff --git a/services/registration/pp.csv b/services/registration/pp.csv deleted file mode 100644 index aa1eb05..0000000 --- a/services/registration/pp.csv +++ /dev/null @@ -1,32 +0,0 @@ -flag,flag_language_set,8,checks whether the user has set their prefered language -flag,flag_account_created,9,this is set when an account has been created on the API -flag,flag_account_creation_failed,10,this is set when there's an error from the API during account creation -flag,flag_account_pending,11,this is set when an account does not have a status of SUCCESS -flag,flag_account_success,12,this is set when an account has a status of SUCCESS -flag,flag_pin_mismatch,13,this is set when the confirmation PIN matches the initial PIN during registration -flag,flag_pin_set,14,this is set when a newly registered user sets a PIN. This must be present for an account to access the main menu -flag,flag_account_authorized,15,this is set to allow a user access guarded nodes after providing a correct PIN -flag,flag_invalid_recipient,16,this is set when the transaction recipient is invalid -flag,flag_invalid_recipient_with_invite,17,this is set when the transaction recipient is valid but not on the platform -flag,flag_invalid_amount,18,this is set when the given transaction amount is invalid -flag,flag_incorrect_pin,19,this is set when the provided PIN is invalid or does not match the current account's PIN -flag,flag_valid_pin,20,this is set when the given PIN is valid -flag,flag_allow_update,21,this is set to allow a user to update their profile data -flag,flag_single_edit,22,this is set to allow a user to edit a single profile item such as year of birth -flag,flag_incorrect_date_format,23,this is set when the given year of birth is invalid -flag,flag_incorrect_voucher,24,this is set when the selected voucher is invalid -flag,flag_api_call_error,25,this is set when communication to an external service fails -flag,flag_no_active_voucher,26,this is set when a user does not have an active voucher -flag,flag_admin_privilege,27,this is set when a user has admin privileges. -flag,flag_unregistered_number,28,this is set when an unregistered phonenumber tries to perform an action -flag,flag_no_transfers,29,this is set when a user does not have any transactions -flag,flag_incorrect_statement,30,this is set when the selected statement is invalid -flag,flag_firstname_set,31,this is set when the first name of the profile is set -flag,flag_familyname_set,32,this is set when the family name of the profile is set -flag,flag_yob_set,33,this is set when the yob of the profile is set -flag,flag_gender_set,34,this is set when the gender of the profile is set -flag,flag_location_set,35,this is set when the location of the profile is set -flag,flag_offerings_set,36,this is set when the offerings of the profile is set -flag,flag_back_set,37,this is set when it is a back navigation -flag,flag_account_blocked,38,this is set when an account has been blocked after the allowed incorrect PIN attempts have been exceeded - diff --git a/services/registration/prev_menu b/services/registration/prev_menu deleted file mode 100644 index 72d90d8..0000000 --- a/services/registration/prev_menu +++ /dev/null @@ -1 +0,0 @@ -Prev \ No newline at end of file diff --git a/services/registration/prev_menu_swa b/services/registration/prev_menu_swa deleted file mode 100644 index e5a3e45..0000000 --- a/services/registration/prev_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Nyuma \ No newline at end of file diff --git a/services/registration/profile_menu b/services/registration/profile_menu deleted file mode 100644 index 0d6af58..0000000 --- a/services/registration/profile_menu +++ /dev/null @@ -1 +0,0 @@ -Profile \ No newline at end of file diff --git a/services/registration/profile_menu_swa b/services/registration/profile_menu_swa deleted file mode 100644 index 8a12b7d..0000000 --- a/services/registration/profile_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Wasifu wangu \ No newline at end of file diff --git a/services/registration/profile_update_success b/services/registration/profile_update_success deleted file mode 100644 index 652942a..0000000 --- a/services/registration/profile_update_success +++ /dev/null @@ -1 +0,0 @@ -Profile updated successfully diff --git a/services/registration/profile_update_success.vis b/services/registration/profile_update_success.vis deleted file mode 100644 index f670e6e..0000000 --- a/services/registration/profile_update_success.vis +++ /dev/null @@ -1,7 +0,0 @@ -LOAD update_all_profile_items 0 -RELOAD update_all_profile_items -MOUT back 0 -MOUT quit 9 -HALT -INCMP edit_profile 0 -INCMP quit 9 diff --git a/services/registration/profile_update_success_swa b/services/registration/profile_update_success_swa deleted file mode 100644 index df0af2c..0000000 --- a/services/registration/profile_update_success_swa +++ /dev/null @@ -1 +0,0 @@ -Ombi la Kuweka wasifu limefanikiwa diff --git a/services/registration/quit.vis b/services/registration/quit.vis deleted file mode 100644 index 0c8bb46..0000000 --- a/services/registration/quit.vis +++ /dev/null @@ -1,2 +0,0 @@ -LOAD quit 0 -HALT diff --git a/services/registration/quit_menu b/services/registration/quit_menu deleted file mode 100644 index f3f23ca..0000000 --- a/services/registration/quit_menu +++ /dev/null @@ -1 +0,0 @@ -Quit \ No newline at end of file diff --git a/services/registration/quit_menu_swa b/services/registration/quit_menu_swa deleted file mode 100644 index 474f1ff..0000000 --- a/services/registration/quit_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Ondoka \ No newline at end of file diff --git a/services/registration/reset_pin_menu b/services/registration/reset_pin_menu deleted file mode 100644 index 1f5d676..0000000 --- a/services/registration/reset_pin_menu +++ /dev/null @@ -1 +0,0 @@ -Reset other's PIN \ No newline at end of file diff --git a/services/registration/reset_pin_menu_swa b/services/registration/reset_pin_menu_swa deleted file mode 100644 index 49214fe..0000000 --- a/services/registration/reset_pin_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Badili PIN ya mwenzio \ No newline at end of file diff --git a/services/registration/retry_menu b/services/registration/retry_menu deleted file mode 100644 index ffde86c..0000000 --- a/services/registration/retry_menu +++ /dev/null @@ -1 +0,0 @@ -Retry \ No newline at end of file diff --git a/services/registration/retry_menu_swa b/services/registration/retry_menu_swa deleted file mode 100644 index c43b419..0000000 --- a/services/registration/retry_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Jaribu tena \ No newline at end of file diff --git a/services/registration/root b/services/registration/root deleted file mode 100644 index 3928a82..0000000 --- a/services/registration/root +++ /dev/null @@ -1 +0,0 @@ -Welcome to Sarafu Network \ No newline at end of file diff --git a/services/registration/root.vis b/services/registration/root.vis deleted file mode 100644 index 102e6e5..0000000 --- a/services/registration/root.vis +++ /dev/null @@ -1,10 +0,0 @@ -CATCH blocked_account flag_account_blocked 1 -CATCH select_language flag_language_set 0 -CATCH terms flag_account_created 0 -LOAD check_account_status 0 -RELOAD check_account_status -CATCH api_failure flag_api_call_error 1 -CATCH account_pending flag_account_pending 1 -CATCH create_pin flag_pin_set 0 -CATCH main flag_account_success 1 -HALT diff --git a/services/registration/root_swa b/services/registration/root_swa deleted file mode 100644 index 75bb624..0000000 --- a/services/registration/root_swa +++ /dev/null @@ -1 +0,0 @@ -Karibu Sarafu Network \ No newline at end of file diff --git a/services/registration/select_gender b/services/registration/select_gender deleted file mode 100644 index 22b9be9..0000000 --- a/services/registration/select_gender +++ /dev/null @@ -1,2 +0,0 @@ -Current gender: {{.get_current_profile_info}} -Select gender: \ No newline at end of file diff --git a/services/registration/select_gender.vis b/services/registration/select_gender.vis deleted file mode 100644 index e41da10..0000000 --- a/services/registration/select_gender.vis +++ /dev/null @@ -1,14 +0,0 @@ -CATCH incorrect_pin flag_incorrect_pin 1 -CATCH profile_update_success flag_allow_update 1 -LOAD get_current_profile_info 0 -RELOAD get_current_profile_info -MOUT male 1 -MOUT female 2 -MOUT unspecified 3 -MOUT back 0 -HALT -INCMP _ 0 -INCMP set_male 1 -INCMP set_female 2 -INCMP set_unspecified 3 -INCMP . * diff --git a/services/registration/select_gender_swa b/services/registration/select_gender_swa deleted file mode 100644 index 39d99d5..0000000 --- a/services/registration/select_gender_swa +++ /dev/null @@ -1,2 +0,0 @@ -Jinsia ya sasa: {{.get_current_profile_info}} -Chagua jinsia \ No newline at end of file diff --git a/services/registration/select_language b/services/registration/select_language deleted file mode 100644 index b3d4304..0000000 --- a/services/registration/select_language +++ /dev/null @@ -1,2 +0,0 @@ -Welcome to Sarafu Network -Please select a language \ No newline at end of file diff --git a/services/registration/select_language.vis b/services/registration/select_language.vis deleted file mode 100644 index 0f7f298..0000000 --- a/services/registration/select_language.vis +++ /dev/null @@ -1,6 +0,0 @@ -MOUT english 1 -MOUT kiswahili 2 -HALT -INCMP set_eng 1 -INCMP set_swa 2 -INCMP . * diff --git a/services/registration/select_voucher b/services/registration/select_voucher deleted file mode 100644 index 084b9b8..0000000 --- a/services/registration/select_voucher +++ /dev/null @@ -1,2 +0,0 @@ -Select number or symbol from your vouchers: -{{.get_vouchers}} \ No newline at end of file diff --git a/services/registration/select_voucher.vis b/services/registration/select_voucher.vis deleted file mode 100644 index 058d791..0000000 --- a/services/registration/select_voucher.vis +++ /dev/null @@ -1,16 +0,0 @@ -CATCH no_voucher flag_no_active_voucher 1 -LOAD get_vouchers 0 -MAP get_vouchers -MOUT back 0 -MOUT quit 99 -MNEXT next 11 -MPREV prev 22 -HALT -LOAD view_voucher 80 -RELOAD view_voucher -CATCH . flag_incorrect_voucher 1 -INCMP _ 0 -INCMP quit 99 -INCMP > 11 -INCMP < 22 -INCMP view_voucher * diff --git a/services/registration/select_voucher_menu b/services/registration/select_voucher_menu deleted file mode 100644 index 8ee06df..0000000 --- a/services/registration/select_voucher_menu +++ /dev/null @@ -1 +0,0 @@ -Select voucher \ No newline at end of file diff --git a/services/registration/select_voucher_menu_swa b/services/registration/select_voucher_menu_swa deleted file mode 100644 index 2cb4daf..0000000 --- a/services/registration/select_voucher_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Chagua Sarafu \ No newline at end of file diff --git a/services/registration/select_voucher_swa b/services/registration/select_voucher_swa deleted file mode 100644 index b4720bf..0000000 --- a/services/registration/select_voucher_swa +++ /dev/null @@ -1,2 +0,0 @@ -Chagua nambari au ishara kutoka kwa salio zako: -{{.get_vouchers}} \ No newline at end of file diff --git a/services/registration/send b/services/registration/send deleted file mode 100644 index 306466c..0000000 --- a/services/registration/send +++ /dev/null @@ -1 +0,0 @@ -Enter recipient's phone number/address/alias: \ No newline at end of file diff --git a/services/registration/send.vis b/services/registration/send.vis deleted file mode 100644 index 8928725..0000000 --- a/services/registration/send.vis +++ /dev/null @@ -1,11 +0,0 @@ -LOAD transaction_reset 0 -RELOAD transaction_reset -CATCH no_voucher flag_no_active_voucher 1 -MOUT back 0 -HALT -LOAD validate_recipient 20 -RELOAD validate_recipient -CATCH invalid_recipient flag_invalid_recipient 1 -CATCH invite_recipient flag_invalid_recipient_with_invite 1 -INCMP _ 0 -INCMP amount * diff --git a/services/registration/send_menu b/services/registration/send_menu deleted file mode 100644 index 5f5a837..0000000 --- a/services/registration/send_menu +++ /dev/null @@ -1 +0,0 @@ -Send \ No newline at end of file diff --git a/services/registration/send_menu_swa b/services/registration/send_menu_swa deleted file mode 100644 index 605c8e8..0000000 --- a/services/registration/send_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Tuma \ No newline at end of file diff --git a/services/registration/send_swa b/services/registration/send_swa deleted file mode 100644 index 016760e..0000000 --- a/services/registration/send_swa +++ /dev/null @@ -1 +0,0 @@ -Weka nambari ya simu: \ No newline at end of file diff --git a/services/registration/set_default.vis b/services/registration/set_default.vis deleted file mode 100644 index b66a1b7..0000000 --- a/services/registration/set_default.vis +++ /dev/null @@ -1,4 +0,0 @@ -LOAD set_language 6 -RELOAD set_language -CATCH terms flag_account_created 0 -MOVE language_changed diff --git a/services/registration/set_eng.vis b/services/registration/set_eng.vis deleted file mode 100644 index b66a1b7..0000000 --- a/services/registration/set_eng.vis +++ /dev/null @@ -1,4 +0,0 @@ -LOAD set_language 6 -RELOAD set_language -CATCH terms flag_account_created 0 -MOVE language_changed diff --git a/services/registration/set_female.vis b/services/registration/set_female.vis deleted file mode 100644 index da92520..0000000 --- a/services/registration/set_female.vis +++ /dev/null @@ -1,10 +0,0 @@ -LOAD save_gender 32 -RELOAD save_gender -CATCH incorrect_pin flag_incorrect_pin 1 -CATCH update_gender flag_allow_update 1 -CATCH pin_entry flag_gender_set 1 -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_gender_set 0 -MOVE edit_yob diff --git a/services/registration/set_male.vis b/services/registration/set_male.vis deleted file mode 100644 index 9a95937..0000000 --- a/services/registration/set_male.vis +++ /dev/null @@ -1,10 +0,0 @@ -LOAD save_gender 16 -RELOAD save_gender -CATCH incorrect_pin flag_incorrect_pin 1 -CATCH update_gender flag_allow_update 1 -CATCH pin_entry flag_gender_set 1 -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_gender_set 0 -MOVE edit_yob diff --git a/services/registration/set_swa.vis b/services/registration/set_swa.vis deleted file mode 100644 index b66a1b7..0000000 --- a/services/registration/set_swa.vis +++ /dev/null @@ -1,4 +0,0 @@ -LOAD set_language 6 -RELOAD set_language -CATCH terms flag_account_created 0 -MOVE language_changed diff --git a/services/registration/set_unspecified.vis b/services/registration/set_unspecified.vis deleted file mode 100644 index 824105c..0000000 --- a/services/registration/set_unspecified.vis +++ /dev/null @@ -1,10 +0,0 @@ -LOAD save_gender 8 -RELOAD save_gender -CATCH incorrect_pin flag_incorrect_pin 1 -CATCH update_gender flag_allow_update 1 -CATCH pin_entry flag_gender_set 1 -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_gender_set 0 -MOVE edit_yob diff --git a/services/registration/terms b/services/registration/terms deleted file mode 100644 index 8af5b06..0000000 --- a/services/registration/terms +++ /dev/null @@ -1,2 +0,0 @@ -Do you agree to terms and conditions? -https://grassecon.org/pages/terms-and-conditions diff --git a/services/registration/terms.vis b/services/registration/terms.vis deleted file mode 100644 index 372b6ca..0000000 --- a/services/registration/terms.vis +++ /dev/null @@ -1,5 +0,0 @@ -MOUT yes 1 -MOUT no 2 -HALT -INCMP create_pin 1 -INCMP quit * diff --git a/services/registration/terms_swa b/services/registration/terms_swa deleted file mode 100644 index 5678186..0000000 --- a/services/registration/terms_swa +++ /dev/null @@ -1,2 +0,0 @@ -Kwa kutumia hii huduma umekubali sheria na masharti? -https://grassecon.org/pages/terms-and-conditions diff --git a/services/registration/transaction_initiated.vis b/services/registration/transaction_initiated.vis deleted file mode 100644 index f8cf19c..0000000 --- a/services/registration/transaction_initiated.vis +++ /dev/null @@ -1,11 +0,0 @@ -LOAD reset_incorrect 6 -CATCH incorrect_pin flag_incorrect_pin 1 -CATCH _ flag_account_authorized 0 -RELOAD get_amount -MAP get_amount -RELOAD get_recipient -MAP get_recipient -RELOAD get_sender -MAP get_sender -LOAD initiate_transaction 0 -HALT diff --git a/services/registration/transaction_pin b/services/registration/transaction_pin deleted file mode 100644 index a1b7125..0000000 --- a/services/registration/transaction_pin +++ /dev/null @@ -1,2 +0,0 @@ -{{.get_recipient}} will receive {{.get_amount}} from {{.get_sender}} -Please enter your PIN to confirm: \ No newline at end of file diff --git a/services/registration/transaction_pin.vis b/services/registration/transaction_pin.vis deleted file mode 100644 index 0388f0c..0000000 --- a/services/registration/transaction_pin.vis +++ /dev/null @@ -1,15 +0,0 @@ -RELOAD get_amount -MAP get_amount -RELOAD get_recipient -MAP get_recipient -RELOAD get_sender -MAP get_sender -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_initiated * diff --git a/services/registration/transaction_pin_swa b/services/registration/transaction_pin_swa deleted file mode 100644 index 1924166..0000000 --- a/services/registration/transaction_pin_swa +++ /dev/null @@ -1,2 +0,0 @@ -{{.get_recipient}} atapokea {{.get_amount}} kutoka kwa {{.get_sender}} -Tafadhali weka PIN yako kudhibitisha: \ No newline at end of file diff --git a/services/registration/transactions b/services/registration/transactions deleted file mode 100644 index 8152c42..0000000 --- a/services/registration/transactions +++ /dev/null @@ -1 +0,0 @@ -{{.get_transactions}} \ No newline at end of file diff --git a/services/registration/transactions.vis b/services/registration/transactions.vis deleted file mode 100644 index b21f1dc..0000000 --- a/services/registration/transactions.vis +++ /dev/null @@ -1,15 +0,0 @@ -LOAD get_transactions 0 -MAP get_transactions -MOUT back 0 -MOUT quit 99 -MNEXT next 11 -MPREV prev 22 -HALT -LOAD view_statement 0 -RELOAD view_statement -CATCH . flag_incorrect_statement 1 -INCMP ^ 0 -INCMP quit 99 -INCMP > 11 -INCMP < 22 -INCMP view_statement * diff --git a/services/registration/transactions_swa b/services/registration/transactions_swa deleted file mode 100644 index 8152c42..0000000 --- a/services/registration/transactions_swa +++ /dev/null @@ -1 +0,0 @@ -{{.get_transactions}} \ No newline at end of file diff --git a/services/registration/unregistered_number b/services/registration/unregistered_number deleted file mode 100644 index 9cc33d7..0000000 --- a/services/registration/unregistered_number +++ /dev/null @@ -1 +0,0 @@ -The number you have entered is either not registered with Sarafu or is invalid. \ No newline at end of file diff --git a/services/registration/unregistered_number.vis b/services/registration/unregistered_number.vis deleted file mode 100644 index 0ff96be..0000000 --- a/services/registration/unregistered_number.vis +++ /dev/null @@ -1,7 +0,0 @@ -LOAD reset_unregistered_number 0 -RELOAD reset_unregistered_number -MOUT back 0 -MOUT quit 9 -HALT -INCMP ^ 0 -INCMP quit 9 diff --git a/services/registration/unregistered_number_swa b/services/registration/unregistered_number_swa deleted file mode 100644 index 19810cb..0000000 --- a/services/registration/unregistered_number_swa +++ /dev/null @@ -1 +0,0 @@ -Nambari uliyoingiza haijasajiliwa na Sarafu au sio sahihi. \ No newline at end of file diff --git a/services/registration/unspecified_menu b/services/registration/unspecified_menu deleted file mode 100644 index 4cd1a5c..0000000 --- a/services/registration/unspecified_menu +++ /dev/null @@ -1 +0,0 @@ -Unspecified \ No newline at end of file diff --git a/services/registration/unspecified_menu_swa b/services/registration/unspecified_menu_swa deleted file mode 100644 index 009301f..0000000 --- a/services/registration/unspecified_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Haijabainishwa \ No newline at end of file diff --git a/services/registration/update_age b/services/registration/update_age deleted file mode 100644 index 76ca306..0000000 --- a/services/registration/update_age +++ /dev/null @@ -1,2 +0,0 @@ -RELOAD save_yob -CATCH profile_update_success flag_allow_update 1 \ No newline at end of file diff --git a/services/registration/update_familyname.vis b/services/registration/update_familyname.vis deleted file mode 100644 index 7cd4d9f..0000000 --- a/services/registration/update_familyname.vis +++ /dev/null @@ -1,2 +0,0 @@ -RELOAD save_familyname -CATCH profile_update_success flag_allow_update 1 diff --git a/services/registration/update_firstname.vis b/services/registration/update_firstname.vis deleted file mode 100644 index dca7036..0000000 --- a/services/registration/update_firstname.vis +++ /dev/null @@ -1,2 +0,0 @@ -RELOAD save_firstname -CATCH profile_update_success flag_allow_update 1 diff --git a/services/registration/update_gender.vis b/services/registration/update_gender.vis deleted file mode 100644 index 506a56a..0000000 --- a/services/registration/update_gender.vis +++ /dev/null @@ -1,2 +0,0 @@ -RELOAD save_gender -CATCH profile_update_success flag_allow_update 1 diff --git a/services/registration/update_location.vis b/services/registration/update_location.vis deleted file mode 100644 index 16c4ea2..0000000 --- a/services/registration/update_location.vis +++ /dev/null @@ -1,2 +0,0 @@ -RELOAD save_location -CATCH profile_update_success flag_allow_update 1 diff --git a/services/registration/update_offerings.vis b/services/registration/update_offerings.vis deleted file mode 100644 index 4aeed74..0000000 --- a/services/registration/update_offerings.vis +++ /dev/null @@ -1,2 +0,0 @@ -RELOAD save_offerings -CATCH profile_update_success flag_allow_update 1 diff --git a/services/registration/update_profile_items.vis b/services/registration/update_profile_items.vis deleted file mode 100644 index beda013..0000000 --- a/services/registration/update_profile_items.vis +++ /dev/null @@ -1,3 +0,0 @@ -CATCH incorrect_pin flag_incorrect_pin 1 -CATCH profile_update_success flag_allow_update 1 -MOVE pin_entry diff --git a/services/registration/update_success b/services/registration/update_success deleted file mode 100644 index d8d5706..0000000 --- a/services/registration/update_success +++ /dev/null @@ -1 +0,0 @@ -Profile updated successfully \ No newline at end of file diff --git a/services/registration/update_success.vis b/services/registration/update_success.vis deleted file mode 100644 index 832ef22..0000000 --- a/services/registration/update_success.vis +++ /dev/null @@ -1,5 +0,0 @@ -MOUT back 0 -MOUT quit 9 -HALT -INCMP ^ 0 -INCMP quit 9 diff --git a/services/registration/update_success_swa b/services/registration/update_success_swa deleted file mode 100644 index 834ba86..0000000 --- a/services/registration/update_success_swa +++ /dev/null @@ -1 +0,0 @@ -Akaunti imeupdatiwa \ No newline at end of file diff --git a/services/registration/update_yob.vis b/services/registration/update_yob.vis deleted file mode 100644 index a9388ae..0000000 --- a/services/registration/update_yob.vis +++ /dev/null @@ -1,2 +0,0 @@ -RELOAD save_yob -CATCH profile_update_success flag_allow_update 1 diff --git a/services/registration/view_menu b/services/registration/view_menu deleted file mode 100644 index 03add31..0000000 --- a/services/registration/view_menu +++ /dev/null @@ -1 +0,0 @@ -View profile \ No newline at end of file diff --git a/services/registration/view_menu_swa b/services/registration/view_menu_swa deleted file mode 100644 index bd84b19..0000000 --- a/services/registration/view_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Angalia Wasifu \ No newline at end of file diff --git a/services/registration/view_profile b/services/registration/view_profile deleted file mode 100644 index 5f59496..0000000 --- a/services/registration/view_profile +++ /dev/null @@ -1,2 +0,0 @@ -My profile: -{{.get_profile_info}} \ No newline at end of file diff --git a/services/registration/view_profile.vis b/services/registration/view_profile.vis deleted file mode 100644 index 4f4947c..0000000 --- a/services/registration/view_profile.vis +++ /dev/null @@ -1,11 +0,0 @@ -LOAD get_profile_info 0 -MAP get_profile_info -LOAD reset_incorrect 6 -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 . * diff --git a/services/registration/view_profile_swa b/services/registration/view_profile_swa deleted file mode 100644 index 1362ebe..0000000 --- a/services/registration/view_profile_swa +++ /dev/null @@ -1,2 +0,0 @@ -Wasifu wangu: -{{.get_profile_info}} \ No newline at end of file diff --git a/services/registration/view_statement b/services/registration/view_statement deleted file mode 100644 index 1285cf9..0000000 --- a/services/registration/view_statement +++ /dev/null @@ -1 +0,0 @@ -{{.view_statement}} \ No newline at end of file diff --git a/services/registration/view_statement.vis b/services/registration/view_statement.vis deleted file mode 100644 index 4dde523..0000000 --- a/services/registration/view_statement.vis +++ /dev/null @@ -1,10 +0,0 @@ -MAP view_statement -MOUT back 0 -MOUT quit 9 -MNEXT next 11 -MPREV prev 22 -HALT -INCMP _ 0 -INCMP quit 9 -INCMP > 11 -INCMP < 22 diff --git a/services/registration/view_swa b/services/registration/view_swa deleted file mode 100644 index bd84b19..0000000 --- a/services/registration/view_swa +++ /dev/null @@ -1 +0,0 @@ -Angalia Wasifu \ No newline at end of file diff --git a/services/registration/view_voucher b/services/registration/view_voucher deleted file mode 100644 index 3940982..0000000 --- a/services/registration/view_voucher +++ /dev/null @@ -1,2 +0,0 @@ -Enter PIN to confirm selection: -{{.view_voucher}} \ No newline at end of file diff --git a/services/registration/view_voucher.vis b/services/registration/view_voucher.vis deleted file mode 100644 index 1480099..0000000 --- a/services/registration/view_voucher.vis +++ /dev/null @@ -1,10 +0,0 @@ -MAP view_voucher -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 voucher_set * diff --git a/services/registration/view_voucher_swa b/services/registration/view_voucher_swa deleted file mode 100644 index 485e2ef..0000000 --- a/services/registration/view_voucher_swa +++ /dev/null @@ -1,2 +0,0 @@ -Weka PIN ili kuthibitisha chaguo: -{{.view_voucher}} \ No newline at end of file diff --git a/services/registration/voucher_details b/services/registration/voucher_details deleted file mode 100644 index d437681..0000000 --- a/services/registration/voucher_details +++ /dev/null @@ -1 +0,0 @@ -{{.get_voucher_details}} \ No newline at end of file diff --git a/services/registration/voucher_details.vis b/services/registration/voucher_details.vis deleted file mode 100644 index 1b009f1..0000000 --- a/services/registration/voucher_details.vis +++ /dev/null @@ -1,6 +0,0 @@ -CATCH no_voucher flag_no_active_voucher 1 -LOAD get_voucher_details 0 -MAP get_voucher_details -MOUT back 0 -HALT -INCMP _ 0 diff --git a/services/registration/voucher_details_menu b/services/registration/voucher_details_menu deleted file mode 100644 index a588f23..0000000 --- a/services/registration/voucher_details_menu +++ /dev/null @@ -1 +0,0 @@ -Voucher details \ No newline at end of file diff --git a/services/registration/voucher_details_menu_swa b/services/registration/voucher_details_menu_swa deleted file mode 100644 index e84661b..0000000 --- a/services/registration/voucher_details_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Maelezo ya Sarafu \ No newline at end of file diff --git a/services/registration/voucher_details_swa b/services/registration/voucher_details_swa deleted file mode 100644 index d437681..0000000 --- a/services/registration/voucher_details_swa +++ /dev/null @@ -1 +0,0 @@ -{{.get_voucher_details}} \ No newline at end of file diff --git a/services/registration/voucher_set b/services/registration/voucher_set deleted file mode 100644 index e90d2e5..0000000 --- a/services/registration/voucher_set +++ /dev/null @@ -1 +0,0 @@ -Success! {{.set_voucher}} is now your active voucher. \ No newline at end of file diff --git a/services/registration/voucher_set.vis b/services/registration/voucher_set.vis deleted file mode 100644 index e75c693..0000000 --- a/services/registration/voucher_set.vis +++ /dev/null @@ -1,10 +0,0 @@ -LOAD reset_incorrect 6 -CATCH incorrect_pin flag_incorrect_pin 1 -CATCH _ flag_account_authorized 0 -LOAD set_voucher 12 -MAP set_voucher -MOUT back 0 -MOUT quit 9 -HALT -INCMP ^ 0 -INCMP quit 9 diff --git a/services/registration/voucher_set_swa b/services/registration/voucher_set_swa deleted file mode 100644 index 97d3fde..0000000 --- a/services/registration/voucher_set_swa +++ /dev/null @@ -1 +0,0 @@ -Hongera! {{.set_voucher}} ni Sarafu inayotumika sasa. \ No newline at end of file diff --git a/services/registration/vouchers_menu b/services/registration/vouchers_menu deleted file mode 100644 index 5084c32..0000000 --- a/services/registration/vouchers_menu +++ /dev/null @@ -1 +0,0 @@ -My Vouchers \ No newline at end of file diff --git a/services/registration/vouchers_menu_swa b/services/registration/vouchers_menu_swa deleted file mode 100644 index 64ba54e..0000000 --- a/services/registration/vouchers_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Sarafu yangu \ No newline at end of file diff --git a/services/registration/yes_menu b/services/registration/yes_menu deleted file mode 100644 index 3fdfb3d..0000000 --- a/services/registration/yes_menu +++ /dev/null @@ -1 +0,0 @@ -Yes \ No newline at end of file diff --git a/services/registration/yes_menu_swa b/services/registration/yes_menu_swa deleted file mode 100644 index 542d3c3..0000000 --- a/services/registration/yes_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Ndio \ No newline at end of file diff --git a/internal/handlers/base.go b/session/base.go similarity index 61% rename from internal/handlers/base.go rename to session/base.go index 6c77f49..99176b6 100644 --- a/internal/handlers/base.go +++ b/session/base.go @@ -1,24 +1,31 @@ -package handlers +package session import ( "git.defalsify.org/vise.git/db" "git.defalsify.org/vise.git/engine" "git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/resource" + "git.defalsify.org/vise.git/logging" + "git.grassecon.net/grassrootseconomics/visedriver/request" + "git.grassecon.net/grassrootseconomics/visedriver/storage" + "git.grassecon.net/grassrootseconomics/visedriver/errors" + "git.grassecon.net/grassrootseconomics/visedriver/entry" +) - "git.grassecon.net/urdt/ussd/internal/handlers/application" - "git.grassecon.net/urdt/ussd/internal/storage" +var ( + logg = logging.NewVanilla().WithDomain("visedriver.session") ) type BaseSessionHandler struct { cfgTemplate engine.Config - rp RequestParser - rs resource.Resource - hn *application.Handlers - provider storage.StorageProvider + rp request.RequestParser + rs resource.Resource + hn entry.EntryHandler + provider storage.StorageProvider } -func NewBaseSessionHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, rp RequestParser, hn *application.Handlers) *BaseSessionHandler { +//func NewBaseSessionHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, rp request.RequestParser, hn *handlers.Handlers) *BaseSessionHandler { +func NewBaseSessionHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, rp request.RequestParser, hn entry.EntryHandler) *BaseSessionHandler { return &BaseSessionHandler{ cfgTemplate: cfg, rs: rs, @@ -41,7 +48,7 @@ func (f *BaseSessionHandler) GetEngine(cfg engine.Config, rs resource.Resource, return en } -func (f *BaseSessionHandler) Process(rqs RequestSession) (RequestSession, error) { +func(f *BaseSessionHandler) Process(rqs request.RequestSession) (request.RequestSession, error) { var r bool var err error var ok bool @@ -51,10 +58,11 @@ func (f *BaseSessionHandler) Process(rqs RequestSession) (RequestSession, error) rqs.Storage, err = f.provider.Get(rqs.Config.SessionId) if err != nil { logg.ErrorCtxf(rqs.Ctx, "", "storage get error", err) - return rqs, ErrStorage + return rqs, errors.ErrStorage } - f.hn = f.hn.WithPersister(rqs.Storage.Persister) + //f.hn = f.hn.WithPersister(rqs.Storage.Persister) + f.hn.SetPersister(rqs.Storage.Persister) defer func() { f.hn.Exit() }() @@ -66,7 +74,7 @@ func (f *BaseSessionHandler) Process(rqs RequestSession) (RequestSession, error) if perr != nil { logg.ErrorCtxf(rqs.Ctx, "", "storage put error", perr) } - return rqs, ErrEngineType + return rqs, errors.ErrEngineType } en = en.WithFirst(f.hn.Init) if rqs.Config.EngineDebug { @@ -88,13 +96,13 @@ func (f *BaseSessionHandler) Process(rqs RequestSession) (RequestSession, error) return rqs, nil } -func (f *BaseSessionHandler) Output(rqs RequestSession) (RequestSession, error) { +func(f *BaseSessionHandler) Output(rqs request.RequestSession) (request.RequestSession, error) { var err error _, err = rqs.Engine.Flush(rqs.Ctx, rqs.Writer) return rqs, err } -func (f *BaseSessionHandler) Reset(rqs RequestSession) (RequestSession, error) { +func(f *BaseSessionHandler) Reset(rqs request.RequestSession) (request.RequestSession, error) { defer f.provider.Put(rqs.Config.SessionId, rqs.Storage) return rqs, rqs.Engine.Finish() } @@ -103,6 +111,6 @@ func (f *BaseSessionHandler) GetConfig() engine.Config { return f.cfgTemplate } -func (f *BaseSessionHandler) GetRequestParser() RequestParser { +func(f *BaseSessionHandler) GetRequestParser() request.RequestParser { return f.rp } diff --git a/session/http/handler.go b/session/http/handler.go new file mode 100644 index 0000000..80f4357 --- /dev/null +++ b/session/http/handler.go @@ -0,0 +1,92 @@ +package http + +import ( + "net/http" + "strconv" + + "git.defalsify.org/vise.git/logging" + "git.grassecon.net/grassrootseconomics/visedriver/request" + "git.grassecon.net/grassrootseconomics/visedriver/errors" +) + +var ( + logg = logging.NewVanilla().WithDomain("visedriver.http.session") +) + +// HTTPSessionHandler implements the session handler for HTTP +type HTTPSessionHandler struct { + request.RequestHandler +} + +func (f *HTTPSessionHandler) WriteError(w http.ResponseWriter, code int, err error) { + s := err.Error() + w.Header().Set("Content-Length", strconv.Itoa(len(s))) + w.WriteHeader(code) + _, err = w.Write([]byte(s)) + if err != nil { + logg.Errorf("error writing error!!", "err", err, "olderr", s) + w.WriteHeader(500) + } +} + +func NewHTTPSessionHandler(h request.RequestHandler) *HTTPSessionHandler { + return &HTTPSessionHandler{ + RequestHandler: h, + } +} + +func (hh *HTTPSessionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + var code int + var err error + var perr error + + rqs := request.RequestSession{ + Ctx: req.Context(), + Writer: w, + } + + rp := hh.GetRequestParser() + cfg := hh.GetConfig() + cfg.SessionId, err = rp.GetSessionId(req.Context(), req) + if err != nil { + logg.ErrorCtxf(rqs.Ctx, "", "header processing error", err) + hh.WriteError(w, 400, err) + } + rqs.Config = cfg + rqs.Input, err = rp.GetInput(req) + if err != nil { + logg.ErrorCtxf(rqs.Ctx, "", "header processing error", err) + hh.WriteError(w, 400, err) + return + } + + rqs, err = hh.Process(rqs) + switch err { + case errors.ErrStorage: + code = 500 + case errors.ErrEngineInit: + code = 500 + case errors.ErrEngineExec: + code = 500 + default: + code = 200 + } + + if code != 200 { + hh.WriteError(w, 500, err) + return + } + + w.WriteHeader(200) + w.Header().Set("Content-Type", "text/plain") + rqs, err = hh.Output(rqs) + rqs, perr = hh.Reset(rqs) + if err != nil { + hh.WriteError(w, 500, err) + return + } + if perr != nil { + hh.WriteError(w, 500, perr) + return + } +} diff --git a/internal/http/parse.go b/session/http/parse.go similarity index 90% rename from internal/http/parse.go rename to session/http/parse.go index b4e784d..c942242 100644 --- a/internal/http/parse.go +++ b/session/http/parse.go @@ -5,7 +5,7 @@ import ( "io/ioutil" "net/http" - "git.grassecon.net/urdt/ussd/internal/handlers" + "git.grassecon.net/grassrootseconomics/visedriver/internal/handlers" ) type DefaultRequestParser struct { diff --git a/internal/http/server_test.go b/session/http/server_test.go similarity index 89% rename from internal/http/server_test.go rename to session/http/server_test.go index 23afd5d..e2b3c49 100644 --- a/internal/http/server_test.go +++ b/session/http/server_test.go @@ -9,8 +9,9 @@ import ( "testing" "git.defalsify.org/vise.git/engine" - "git.grassecon.net/urdt/ussd/internal/handlers" - "git.grassecon.net/urdt/ussd/internal/testutil/mocks/httpmocks" + "git.grassecon.net/grassrootseconomics/visedriver/internal/handlers" + "git.grassecon.net/grassrootseconomics/visedriver/testutil/mocks/httpmocks" + "git.grassecon.net/grassrootseconomics/visedriver/request" ) // invalidRequestType is a custom type to test invalid request scenarios @@ -81,16 +82,16 @@ func TestSessionHandler_ServeHTTP(t *testing.T) { } mockRequestHandler := &httpmocks.MockRequestHandler{ - ProcessFunc: func(rs handlers.RequestSession) (handlers.RequestSession, error) { + ProcessFunc: func(rs request.RequestSession) (request.RequestSession, error) { return rs, tt.processErr }, - OutputFunc: func(rs handlers.RequestSession) (handlers.RequestSession, error) { + OutputFunc: func(rs request.RequestSession) (request.RequestSession, error) { return rs, tt.outputErr }, - ResetFunc: func(rs handlers.RequestSession) (handlers.RequestSession, error) { + ResetFunc: func(rs request.RequestSession) (request.RequestSession, error) { return rs, tt.resetErr }, - GetRequestParserFunc: func() handlers.RequestParser { + GetRequestParserFunc: func() request.RequestParser { return mockRequestParser }, GetConfigFunc: func() engine.Config { @@ -98,7 +99,9 @@ func TestSessionHandler_ServeHTTP(t *testing.T) { }, } - sessionHandler := ToSessionHandler(mockRequestHandler) + sessionHandler := &HTTPSessionHandler{ + RequestHandler: mockRequestHandler, + } req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(tt.input)) req.Header.Set("X-Vise-Session", tt.sessionID) @@ -116,7 +119,7 @@ func TestSessionHandler_ServeHTTP(t *testing.T) { } func TestSessionHandler_WriteError(t *testing.T) { - handler := &SessionHandler{} + handler := &HTTPSessionHandler{} mockWriter := &httpmocks.MockWriter{} err := errors.New("test error") diff --git a/internal/storage/db/gdbm/gdbm.go b/storage/db/gdbm/gdbm.go similarity index 100% rename from internal/storage/db/gdbm/gdbm.go rename to storage/db/gdbm/gdbm.go diff --git a/internal/storage/db/sub_prefix_db.go b/storage/db/sub_prefix_db.go similarity index 100% rename from internal/storage/db/sub_prefix_db.go rename to storage/db/sub_prefix_db.go diff --git a/internal/storage/db/sub_prefix_db_test.go b/storage/db/sub_prefix_db_test.go similarity index 100% rename from internal/storage/db/sub_prefix_db_test.go rename to storage/db/sub_prefix_db_test.go diff --git a/internal/storage/parse.go b/storage/parse.go similarity index 100% rename from internal/storage/parse.go rename to storage/parse.go diff --git a/internal/storage/parse_test.go b/storage/parse_test.go similarity index 100% rename from internal/storage/parse_test.go rename to storage/parse_test.go diff --git a/internal/storage/storage.go b/storage/storage.go similarity index 100% rename from internal/storage/storage.go rename to storage/storage.go diff --git a/internal/storage/storage_service.go b/storage/storage_service.go similarity index 95% rename from internal/storage/storage_service.go rename to storage/storage_service.go index 374af74..dc83bbc 100644 --- a/internal/storage/storage_service.go +++ b/storage/storage_service.go @@ -5,7 +5,8 @@ import ( "fmt" "os" "path" - + + "github.com/jackc/pgx/v5/pgxpool" "git.defalsify.org/vise.git/db" fsdb "git.defalsify.org/vise.git/db/fs" "git.defalsify.org/vise.git/db/postgres" @@ -13,8 +14,7 @@ import ( "git.defalsify.org/vise.git/logging" "git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/resource" - gdbmstorage "git.grassecon.net/urdt/ussd/internal/storage/db/gdbm" - "github.com/jackc/pgx/v5/pgxpool" + gdbmstorage "git.grassecon.net/grassrootseconomics/visedriver/storage/db/gdbm" ) var ( @@ -43,6 +43,11 @@ func NewMenuStorageService(conn ConnData, resourceDir string) *MenuStorageServic } } +func (ms *MenuStorageService) WithResourceDir(resourceDir string) *MenuStorageService { + ms.resourceDir = resourceDir + return ms +} + func (ms *MenuStorageService) getOrCreateDb(ctx context.Context, existingDb db.Db, section string) (db.Db, error) { var newDb db.Db var err error diff --git a/internal/testutil/driver/groupdriver.go b/testutil/driver/groupdriver.go similarity index 100% rename from internal/testutil/driver/groupdriver.go rename to testutil/driver/groupdriver.go diff --git a/internal/testutil/mocks/httpmocks/enginemock.go b/testutil/mocks/httpmocks/enginemock.go similarity index 100% rename from internal/testutil/mocks/httpmocks/enginemock.go rename to testutil/mocks/httpmocks/enginemock.go diff --git a/testutil/mocks/httpmocks/request_handler_mock.go b/testutil/mocks/httpmocks/request_handler_mock.go new file mode 100644 index 0000000..acd1a5a --- /dev/null +++ b/testutil/mocks/httpmocks/request_handler_mock.go @@ -0,0 +1,47 @@ +package httpmocks + +import ( + "git.defalsify.org/vise.git/engine" + "git.defalsify.org/vise.git/persist" + "git.defalsify.org/vise.git/resource" + "git.grassecon.net/grassrootseconomics/visedriver/request" +) + +// MockRequestHandler implements request.RequestHandler interface for testing +type MockRequestHandler struct { + ProcessFunc func(request.RequestSession) (request.RequestSession, error) + GetConfigFunc func() engine.Config + GetEngineFunc func(cfg engine.Config, rs resource.Resource, pe *persist.Persister) engine.Engine + OutputFunc func(rs request.RequestSession) (request.RequestSession, error) + ResetFunc func(rs request.RequestSession) (request.RequestSession, error) + ShutdownFunc func() + GetRequestParserFunc func() request.RequestParser +} + +func (m *MockRequestHandler) Process(rqs request.RequestSession) (request.RequestSession, error) { + return m.ProcessFunc(rqs) +} + +func (m *MockRequestHandler) GetConfig() engine.Config { + return m.GetConfigFunc() +} + +func (m *MockRequestHandler) GetEngine(cfg engine.Config, rs resource.Resource, pe *persist.Persister) engine.Engine { + return m.GetEngineFunc(cfg, rs, pe) +} + +func (m *MockRequestHandler) Output(rs request.RequestSession) (request.RequestSession, error) { + return m.OutputFunc(rs) +} + +func (m *MockRequestHandler) Reset(rs request.RequestSession) (request.RequestSession, error) { + return m.ResetFunc(rs) +} + +func (m *MockRequestHandler) Shutdown() { + m.ShutdownFunc() +} + +func (m *MockRequestHandler) GetRequestParser() request.RequestParser { + return m.GetRequestParserFunc() +} diff --git a/internal/testutil/mocks/httpmocks/request_parser_mock.go b/testutil/mocks/httpmocks/request_parser_mock.go similarity index 100% rename from internal/testutil/mocks/httpmocks/request_parser_mock.go rename to testutil/mocks/httpmocks/request_parser_mock.go diff --git a/internal/testutil/mocks/httpmocks/writer_mock.go b/testutil/mocks/httpmocks/writer_mock.go similarity index 100% rename from internal/testutil/mocks/httpmocks/writer_mock.go rename to testutil/mocks/httpmocks/writer_mock.go diff --git a/internal/utils/adminstore.go b/utils/adminstore.go similarity index 100% rename from internal/utils/adminstore.go rename to utils/adminstore.go diff --git a/internal/utils/age.go b/utils/age.go similarity index 100% rename from internal/utils/age.go rename to utils/age.go diff --git a/internal/utils/isocode.go b/utils/isocode.go similarity index 100% rename from internal/utils/isocode.go rename to utils/isocode.go diff --git a/internal/utils/name.go b/utils/name.go similarity index 100% rename from internal/utils/name.go rename to utils/name.go