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 92% rename from devtools/admin/commands/seed.go rename to cmd/admin/commands/seed.go index e76c83d..25db7cc 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/internal/utils" ) var ( diff --git a/devtools/admin/main.go b/cmd/admin/main.go similarity index 73% rename from devtools/admin/main.go rename to cmd/admin/main.go index 9a527f3..6f780d2 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/devtools/admin/commands" ) func main() { diff --git a/cmd/async/main.go b/cmd/async/main.go deleted file mode 100644 index 3aca4f2..0000000 --- a/cmd/async/main.go +++ /dev/null @@ -1,201 +0,0 @@ -package main - -import ( - "context" - "flag" - "fmt" - "os" - "os/signal" - "path" - "syscall" - - "git.defalsify.org/vise.git/engine" - "git.defalsify.org/vise.git/logging" - "git.defalsify.org/vise.git/resource" - "git.defalsify.org/vise.git/lang" - - "git.grassecon.net/urdt/ussd/config" - "git.grassecon.net/urdt/ussd/initializers" - "git.grassecon.net/urdt/ussd/handlers" - "git.grassecon.net/urdt/ussd/internal/storage" - "git.grassecon.net/urdt/ussd/remote" - "git.grassecon.net/urdt/ussd/request" - "git.grassecon.net/urdt/ussd/internal/args" -) - -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 database string - 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() - ctx = context.WithValue(ctx, "Database", database) - - ln, err := lang.LanguageFromCode(config.DefaultLanguage) - if err != nil { - fmt.Fprintf(os.Stderr, "default language set error: %v", err) - os.Exit(1) - } - ctx = context.WithValue(ctx, "Language", ln) - - pfp := path.Join(scriptDir, "pp.csv") - - cfg := engine.Config{ - Root: "root", - OutputSize: uint32(size), - FlagCount: uint32(128), - MenuSeparator: menuSeparator, - } - - if engineDebug { - cfg.EngineDebug = true - } - - menuStorageService := 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 := request.RequestSession{ - Ctx: ctx, - Writer: os.Stdout, - Config: cfg, - } - - cint := make(chan os.Signal) - cterm := make(chan os.Signal) - signal.Notify(cint, os.Interrupt, syscall.SIGINT) - signal.Notify(cterm, os.Interrupt, syscall.SIGTERM) - go func() { - select { - case _ = <-cint: - case _ = <-cterm: - } - sh.Shutdown() - }() - - for true { - rqs, err = sh.Process(rqs) - if err != nil { - logg.ErrorCtxf(ctx, "error in process: %v", "err", err) - fmt.Errorf("error in process: %v", err) - os.Exit(1) - } - rqs, err = sh.Output(rqs) - if err != nil { - logg.ErrorCtxf(ctx, "error in output: %v", "err", err) - fmt.Errorf("error in output: %v", err) - os.Exit(1) - } - rqs, err = sh.Reset(rqs) - if err != nil { - logg.ErrorCtxf(ctx, "error in reset: %v", "err", err) - fmt.Errorf("error in reset: %v", err) - os.Exit(1) - } - fmt.Println("") - _, err = fmt.Scanln(&rqs.Input) - if err != nil { - logg.ErrorCtxf(ctx, "error in input", "err", err) - fmt.Errorf("error in input: %v", err) - os.Exit(1) - } - } -} diff --git a/cmd/http/main.go b/cmd/http/main.go deleted file mode 100644 index c917448..0000000 --- a/cmd/http/main.go +++ /dev/null @@ -1,166 +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/logging" - "git.defalsify.org/vise.git/resource" - "git.defalsify.org/vise.git/lang" - - "git.grassecon.net/urdt/ussd/config" - "git.grassecon.net/urdt/ussd/initializers" - "git.grassecon.net/urdt/ussd/handlers" - httpserver "git.grassecon.net/urdt/ussd/internal/http" - "git.grassecon.net/urdt/ussd/internal/storage" - "git.grassecon.net/urdt/ussd/remote" - "git.grassecon.net/urdt/ussd/internal/args" -) - -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 database string - var engineDebug bool - var host string - var port uint - var err error - var gettextDir string - var langs args.LangVar - - flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir") - flag.StringVar(&connStr, "c", "", "connection string") - flag.BoolVar(&engineDebug, "d", false, "use engine debug output") - flag.UintVar(&size, "s", 160, "max size of output") - flag.StringVar(&host, "h", initializers.GetEnv("HOST", "127.0.0.1"), "http host") - flag.UintVar(&port, "p", initializers.GetEnvUint("PORT", 7123), "http port") - flag.StringVar(&gettextDir, "gettext", "", "use gettext translations from given directory") - flag.Var(&langs, "language", "add symbol resolution for language") - flag.Parse() - - if connStr != "" { - connStr = config.DbConn - } - connData, err := 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() - ctx = context.WithValue(ctx, "Database", database) - - ln, err := lang.LanguageFromCode(config.DefaultLanguage) - if err != nil { - fmt.Fprintf(os.Stderr, "default language set error: %v", err) - os.Exit(1) - } - ctx = context.WithValue(ctx, "Language", ln) - - pfp := path.Join(scriptDir, "pp.csv") - - cfg := engine.Config{ - Root: "root", - OutputSize: uint32(size), - FlagCount: uint32(128), - MenuSeparator: menuSeparator, - } - - if engineDebug { - cfg.EngineDebug = true - } - - menuStorageService := 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) - // TODO: less hacky way of making session handler - //sh := request.ToSessionHandler(bsh) - sh := &httpserver.SessionHandler{ - RequestHandler: 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 576dd17..0000000 --- a/cmd/main.go +++ /dev/null @@ -1,148 +0,0 @@ -package main - -import ( - "context" - "flag" - "fmt" - "os" - "path" - - "git.defalsify.org/vise.git/engine" - "git.defalsify.org/vise.git/logging" - "git.defalsify.org/vise.git/resource" - "git.defalsify.org/vise.git/lang" - "git.grassecon.net/urdt/ussd/config" - "git.grassecon.net/urdt/ussd/handlers" - "git.grassecon.net/urdt/ussd/initializers" - "git.grassecon.net/urdt/ussd/internal/storage" - "git.grassecon.net/urdt/ussd/internal/args" - "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 database 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) - ctx = context.WithValue(ctx, "Database", database) - - ln, err := lang.LanguageFromCode(config.DefaultLanguage) - if err != nil { - fmt.Fprintf(os.Stderr, "default language set error: %v", err) - os.Exit(1) - } - ctx = context.WithValue(ctx, "Language", ln) - - pfp := path.Join(scriptDir, "pp.csv") - - cfg := engine.Config{ - Root: "root", - 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 749f340..d7923ae 100644 --- a/devtools/store/generate/main.go +++ b/cmd/store/generate/main.go @@ -9,10 +9,10 @@ import ( "path" "git.defalsify.org/vise.git/logging" - "git.grassecon.net/urdt/ussd/config" - "git.grassecon.net/urdt/ussd/internal/storage" - "git.grassecon.net/urdt/ussd/initializers" - "git.grassecon.net/urdt/ussd/common" + "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 949a9de..507aa0f 100644 --- a/common/storage.go +++ b/common/storage.go @@ -7,8 +7,8 @@ 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.grassecon.net/grassrootseconomics/visedriver/storage" + dbstorage "git.grassecon.net/grassrootseconomics/visedriver/storage/db" ) var ( 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/errors/errors.go b/errors/errors.go index 890d344..40974b1 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -1,7 +1,7 @@ package errors import ( - "git.grassecon.net/urdt/ussd/internal/handlers" + "git.grassecon.net/grassrootseconomics/visedriver/internal/handlers" ) var ( diff --git a/go.mod b/go.mod index 41c6700..d614e1b 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 diff --git a/handlers/base.go b/handlers/base.go index f5d5884..12df12f 100644 --- a/handlers/base.go +++ b/handlers/base.go @@ -7,10 +7,10 @@ import ( "git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/logging" - "git.grassecon.net/urdt/ussd/request" - "git.grassecon.net/urdt/ussd/errors" - "git.grassecon.net/urdt/ussd/internal/handlers/application" - "git.grassecon.net/urdt/ussd/internal/storage" + "git.grassecon.net/grassrootseconomics/visedriver/request" + "git.grassecon.net/grassrootseconomics/visedriver/errors" + "git.grassecon.net/grassrootseconomics/visedriver/internal/handlers/application" + "git.grassecon.net/grassrootseconomics/visedriver/storage" ) var ( diff --git a/handlers/local.go b/handlers/local.go deleted file mode 100644 index 6fb355b..0000000 --- a/handlers/local.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/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/menuhandler.go b/internal/handlers/application/menuhandler.go deleted file mode 100644 index 193f7fe..0000000 --- a/internal/handlers/application/menuhandler.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/menuhandler_test.go b/internal/handlers/application/menuhandler_test.go deleted file mode 100644 index 487fe2b..0000000 --- a/internal/handlers/application/menuhandler_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/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/parse.go b/internal/http/parse.go index b4e784d..c942242 100644 --- a/internal/http/parse.go +++ b/internal/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.go b/internal/http/server.go index 9ef00b5..540db6c 100644 --- a/internal/http/server.go +++ b/internal/http/server.go @@ -6,8 +6,8 @@ import ( "git.defalsify.org/vise.git/logging" - "git.grassecon.net/urdt/ussd/internal/handlers" - "git.grassecon.net/urdt/ussd/request" + "git.grassecon.net/grassrootseconomics/visedriver/internal/handlers" + "git.grassecon.net/grassrootseconomics/visedriver/request" ) var ( diff --git a/internal/http/server_test.go b/internal/http/server_test.go index 67f1030..0201e3a 100644 --- a/internal/http/server_test.go +++ b/internal/http/server_test.go @@ -9,9 +9,9 @@ import ( "testing" "git.defalsify.org/vise.git/engine" - "git.grassecon.net/urdt/ussd/internal/handlers" - "git.grassecon.net/urdt/ussd/testutil/mocks/httpmocks" - "git.grassecon.net/urdt/ussd/request" + "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 diff --git a/internal/ssh/keystore.go b/internal/ssh/keystore.go index 206d684..68bfe5d 100644 --- a/internal/ssh/keystore.go +++ b/internal/ssh/keystore.go @@ -10,8 +10,8 @@ import ( "git.defalsify.org/vise.git/db" - "git.grassecon.net/urdt/ussd/internal/storage" - dbstorage "git.grassecon.net/urdt/ussd/internal/storage/db/gdbm" + "git.grassecon.net/grassrootseconomics/visedriver/storage" + dbstorage "git.grassecon.net/grassrootseconomics/visedriver/storage/db/gdbm" ) type SshKeyStore struct { diff --git a/internal/ssh/ssh.go b/internal/ssh/ssh.go index ff16cb9..426bac9 100644 --- a/internal/ssh/ssh.go +++ b/internal/ssh/ssh.go @@ -17,9 +17,9 @@ import ( "git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/state" - "git.grassecon.net/urdt/ussd/handlers" - "git.grassecon.net/urdt/ussd/internal/storage" - "git.grassecon.net/urdt/ussd/remote" + "git.grassecon.net/grassrootseconomics/visedriver/handlers" + "git.grassecon.net/grassrootseconomics/visedriver/storage" + "git.grassecon.net/grassrootseconomics/visedriver/remote" ) var ( diff --git a/internal/testutil/mocks/servicemock.go b/internal/testutil/mocks/servicemock.go index 59d7205..9033376 100644 --- a/internal/testutil/mocks/servicemock.go +++ b/internal/testutil/mocks/servicemock.go @@ -3,7 +3,7 @@ package mocks import ( "context" - "git.grassecon.net/urdt/ussd/models" + "git.grassecon.net/grassrootseconomics/visedriver/models" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" "github.com/stretchr/testify/mock" ) 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/menutraversal_test/menu_traversal_test.go b/menutraversal_test/menu_traversal_test.go index 52e2273..d41cd3b 100644 --- a/menutraversal_test/menu_traversal_test.go +++ b/menutraversal_test/menu_traversal_test.go @@ -11,8 +11,8 @@ import ( "regexp" "testing" - "git.grassecon.net/urdt/ussd/internal/testutil" - "git.grassecon.net/urdt/ussd/internal/testutil/driver" + "git.grassecon.net/grassrootseconomics/visedriver/internal/testutil" + "git.grassecon.net/grassrootseconomics/visedriver/internal/testutil/driver" "github.com/gofrs/uuid" ) diff --git a/remote/accountservice.go b/remote/accountservice.go index b0e9eb4..3fbaaf0 100644 --- a/remote/accountservice.go +++ b/remote/accountservice.go @@ -10,8 +10,8 @@ import ( "net/http" "net/url" - "git.grassecon.net/urdt/ussd/config" - "git.grassecon.net/urdt/ussd/models" + "git.grassecon.net/grassrootseconomics/visedriver/config" + "git.grassecon.net/grassrootseconomics/visedriver/models" "github.com/grassrootseconomics/eth-custodial/pkg/api" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" ) diff --git a/request/request.go b/request/request.go index 23aa3fe..2963f09 100644 --- a/request/request.go +++ b/request/request.go @@ -10,7 +10,7 @@ import ( "git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/engine" "git.defalsify.org/vise.git/logging" - "git.grassecon.net/urdt/ussd/internal/storage" + "git.grassecon.net/grassrootseconomics/visedriver/storage" ) var ( 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/storageservice.go b/storage/storageservice.go similarity index 98% rename from internal/storage/storageservice.go rename to storage/storageservice.go index 16f7614..6d4ad80 100644 --- a/internal/storage/storageservice.go +++ b/storage/storageservice.go @@ -13,7 +13,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" + gdbmstorage "git.grassecon.net/grassrootseconomics/visedriver/storage/db/gdbm" ) var ( 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/engine.go b/testutil/engine.go similarity index 88% rename from internal/testutil/engine.go rename to testutil/engine.go index 57f2b7c..c0cb845 100644 --- a/internal/testutil/engine.go +++ b/testutil/engine.go @@ -11,12 +11,12 @@ import ( "git.defalsify.org/vise.git/engine" "git.defalsify.org/vise.git/logging" "git.defalsify.org/vise.git/resource" - "git.grassecon.net/urdt/ussd/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/grassrootseconomics/visedriver/handlers" + "git.grassecon.net/grassrootseconomics/visedriver/storage" + "git.grassecon.net/grassrootseconomics/visedriver/internal/testutil/testservice" + "git.grassecon.net/grassrootseconomics/visedriver/internal/testutil/testtag" testdataloader "github.com/peteole/testdata-loader" - "git.grassecon.net/urdt/ussd/remote" + "git.grassecon.net/grassrootseconomics/visedriver/remote" ) var ( diff --git a/internal/testutil/engine_test.go b/testutil/engine_test.go similarity index 100% rename from internal/testutil/engine_test.go rename to testutil/engine_test.go diff --git a/testutil/mocks/httpmocks/requesthandlermock.go b/testutil/mocks/httpmocks/requesthandlermock.go index e887711..acd1a5a 100644 --- a/testutil/mocks/httpmocks/requesthandlermock.go +++ b/testutil/mocks/httpmocks/requesthandlermock.go @@ -4,7 +4,7 @@ import ( "git.defalsify.org/vise.git/engine" "git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/resource" - "git.grassecon.net/urdt/ussd/request" + "git.grassecon.net/grassrootseconomics/visedriver/request" ) // MockRequestHandler implements request.RequestHandler interface for testing diff --git a/internal/testutil/testservice/accountservice.go b/testutil/testservice/accountservice.go similarity index 97% rename from internal/testutil/testservice/accountservice.go rename to testutil/testservice/accountservice.go index 96dacbc..300ef52 100644 --- a/internal/testutil/testservice/accountservice.go +++ b/testutil/testservice/accountservice.go @@ -4,7 +4,7 @@ import ( "context" "encoding/json" - "git.grassecon.net/urdt/ussd/models" + "git.grassecon.net/grassrootseconomics/visedriver/models" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" ) diff --git a/testutil/testtag/offlinetest.go b/testutil/testtag/offlinetest.go new file mode 100644 index 0000000..e8119b8 --- /dev/null +++ b/testutil/testtag/offlinetest.go @@ -0,0 +1,12 @@ +// +build !online + +package testtag + +import ( + "git.grassecon.net/grassrootseconomics/visedriver/remote" + accountservice "git.grassecon.net/grassrootseconomics/visedriver/internal/testutil/testservice" +) + +var ( + AccountService remote.AccountServiceInterface = &accountservice.TestAccountService{} +) diff --git a/internal/testutil/testtag/onlinetest.go b/testutil/testtag/onlinetest.go similarity index 58% rename from internal/testutil/testtag/onlinetest.go rename to testutil/testtag/onlinetest.go index 835ba0d..46a0f88 100644 --- a/internal/testutil/testtag/onlinetest.go +++ b/testutil/testtag/onlinetest.go @@ -2,7 +2,7 @@ package testtag -import "git.grassecon.net/urdt/ussd/remote" +import "git.grassecon.net/grassrootseconomics/visedriver/remote" var ( AccountService remote.AccountServiceInterface 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