Compare commits
81 Commits
send-input
...
master
Author | SHA1 | Date | |
---|---|---|---|
b11f11b5fa | |||
3d35a5de78 | |||
a19ace85f8 | |||
8f5ed0cd4f | |||
c29abfe21e | |||
9a6d8e5158 | |||
db431c750e | |||
2b9c6d641e | |||
3747f87a7c | |||
1f0568df32 | |||
|
24c513d4f0 | ||
b3fd6f5c1a | |||
73eb765408 | |||
f660f6c19a | |||
3fccfaab61 | |||
|
b50a51df9b | ||
|
df8c9aab0c | ||
|
ddefdd7fb3 | ||
5734011f96 | |||
|
379d98ccd5 | ||
f40e11c267 | |||
b698f08136 | |||
4d7589ad95 | |||
efdb52bccd | |||
2ff9fed3c5 | |||
477b4cf8f6 | |||
ed6651697a | |||
c359d99075 | |||
8d477356f3 | |||
7f3294a8a2 | |||
4b5f08e25e | |||
ea9cab930e | |||
a37f6e6da3 | |||
f59c3a53ef | |||
81c3378ea6 | |||
46a6d2bc6e | |||
|
721f80d0f2 | ||
f49e54a562 | |||
|
5081b6d4ce | ||
4d72ae0313 | |||
4fe64a7747 | |||
3004698d5b | |||
50c7ff1046 | |||
07b061a68b | |||
6339f0c2e5 | |||
|
1fa830f286 | ||
64fba91670 | |||
c15958a1ad | |||
ee442daefa | |||
656052dc74 | |||
11d30583a4 | |||
f83f539046 | |||
562bd4fa24 | |||
90df0eefc3 | |||
b37f2a0a11 | |||
68e4c9af03 | |||
c12e867ac3 | |||
79de0a9092 | |||
3ee15497a5 | |||
|
599815c343 | ||
|
462c0d7677 | ||
|
02823fd64e | ||
|
cd575c2edb | ||
|
52fd1eced2 | ||
|
5c7a535288 | ||
|
cc2f7b41df | ||
|
d39740a09a | ||
|
51b6fc0dde | ||
|
cc9760125a | ||
|
3a9f3fa373 | ||
|
89c21847b9 | ||
|
450dfa02cc | ||
|
f61e65f4fe | ||
|
a4d6cef9c0 | ||
|
2992f7ae8e | ||
|
dc61d05584 | ||
|
e92e498726 | ||
|
c3cbe1cd92 | ||
|
418080d093 | ||
|
2e30739ec9 | ||
|
dc1674ec55 |
10
.env.example
10
.env.example
@ -6,13 +6,9 @@ HOST=127.0.0.1
|
|||||||
AT_ENDPOINT=/ussd/africastalking
|
AT_ENDPOINT=/ussd/africastalking
|
||||||
|
|
||||||
#PostgreSQL
|
#PostgreSQL
|
||||||
DB_HOST=localhost
|
DB_CONN=postgres://postgres:strongpass@localhost:5432/urdt_ussd
|
||||||
DB_USER=postgres
|
#DB_TIMEZONE=Africa/Nairobi
|
||||||
DB_PASSWORD=strongpass
|
#DB_SCHEMA=vise
|
||||||
DB_NAME=urdt_ussd
|
|
||||||
DB_PORT=5432
|
|
||||||
DB_SSLMODE=disable
|
|
||||||
DB_TIMEZONE=Africa/Nairobi
|
|
||||||
|
|
||||||
#External API Calls
|
#External API Calls
|
||||||
CUSTODIAL_URL_BASE=http://localhost:5003
|
CUSTODIAL_URL_BASE=http://localhost:5003
|
||||||
|
@ -12,18 +12,17 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"git.defalsify.org/vise.git/engine"
|
"git.defalsify.org/vise.git/engine"
|
||||||
|
"git.defalsify.org/vise.git/lang"
|
||||||
"git.defalsify.org/vise.git/logging"
|
"git.defalsify.org/vise.git/logging"
|
||||||
"git.defalsify.org/vise.git/resource"
|
"git.defalsify.org/vise.git/resource"
|
||||||
"git.defalsify.org/vise.git/lang"
|
|
||||||
|
|
||||||
"git.grassecon.net/urdt/ussd/config"
|
"git.grassecon.net/urdt/ussd/config"
|
||||||
"git.grassecon.net/urdt/ussd/initializers"
|
"git.grassecon.net/urdt/ussd/initializers"
|
||||||
|
"git.grassecon.net/urdt/ussd/internal/args"
|
||||||
"git.grassecon.net/urdt/ussd/internal/handlers"
|
"git.grassecon.net/urdt/ussd/internal/handlers"
|
||||||
"git.grassecon.net/urdt/ussd/internal/http/at"
|
"git.grassecon.net/urdt/ussd/internal/http/at"
|
||||||
httpserver "git.grassecon.net/urdt/ussd/internal/http/at"
|
|
||||||
"git.grassecon.net/urdt/ussd/internal/storage"
|
"git.grassecon.net/urdt/ussd/internal/storage"
|
||||||
"git.grassecon.net/urdt/ussd/remote"
|
"git.grassecon.net/urdt/ussd/remote"
|
||||||
"git.grassecon.net/urdt/ussd/internal/args"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -36,21 +35,22 @@ var (
|
|||||||
func init() {
|
func init() {
|
||||||
initializers.LoadEnvVariables()
|
initializers.LoadEnvVariables()
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
config.LoadConfig()
|
config.LoadConfig()
|
||||||
|
|
||||||
var dbDir string
|
var connStr string
|
||||||
var resourceDir string
|
var resourceDir string
|
||||||
var size uint
|
var size uint
|
||||||
var database string
|
|
||||||
var engineDebug bool
|
var engineDebug bool
|
||||||
var host string
|
var host string
|
||||||
var port uint
|
var port uint
|
||||||
|
var err error
|
||||||
var gettextDir string
|
var gettextDir string
|
||||||
var langs args.LangVar
|
var langs args.LangVar
|
||||||
flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from")
|
|
||||||
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
|
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
|
||||||
flag.StringVar(&database, "db", "gdbm", "database to be used")
|
flag.StringVar(&connStr, "c", "", "connection string")
|
||||||
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
|
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
|
||||||
flag.UintVar(&size, "s", 160, "max size of output")
|
flag.UintVar(&size, "s", 160, "max size of output")
|
||||||
flag.StringVar(&host, "h", initializers.GetEnv("HOST", "127.0.0.1"), "http host")
|
flag.StringVar(&host, "h", initializers.GetEnv("HOST", "127.0.0.1"), "http host")
|
||||||
@ -59,10 +59,18 @@ func main() {
|
|||||||
flag.Var(&langs, "language", "add symbol resolution for language")
|
flag.Var(&langs, "language", "add symbol resolution for language")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
logg.Infof("start command", "build", build, "dbdir", dbDir, "resourcedir", resourceDir, "outputsize", size)
|
if connStr == "" {
|
||||||
|
connStr = config.DbConn
|
||||||
|
}
|
||||||
|
connData, err := storage.ToConnData(connStr)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "connstr err: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
logg.Infof("start command", "build", build, "conn", connData, "resourcedir", resourceDir, "outputsize", size)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
ctx = context.WithValue(ctx, "Database", database)
|
|
||||||
ln, err := lang.LanguageFromCode(config.DefaultLanguage)
|
ln, err := lang.LanguageFromCode(config.DefaultLanguage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "default language set error: %v", err)
|
fmt.Fprintf(os.Stderr, "default language set error: %v", err)
|
||||||
@ -83,14 +91,13 @@ func main() {
|
|||||||
cfg.EngineDebug = true
|
cfg.EngineDebug = true
|
||||||
}
|
}
|
||||||
|
|
||||||
menuStorageService := storage.NewMenuStorageService(dbDir, resourceDir)
|
menuStorageService := storage.NewMenuStorageService(connData, resourceDir)
|
||||||
rs, err := menuStorageService.GetResource(ctx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, err.Error())
|
fmt.Fprintf(os.Stderr, err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = menuStorageService.EnsureDbDir()
|
rs, err := menuStorageService.GetResource(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, err.Error())
|
fmt.Fprintf(os.Stderr, err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
@ -136,7 +143,7 @@ func main() {
|
|||||||
|
|
||||||
rp := &at.ATRequestParser{}
|
rp := &at.ATRequestParser{}
|
||||||
bsh := handlers.NewBaseSessionHandler(cfg, rs, stateStore, userdataStore, rp, hl)
|
bsh := handlers.NewBaseSessionHandler(cfg, rs, stateStore, userdataStore, rp, hl)
|
||||||
sh := httpserver.NewATSessionHandler(bsh)
|
sh := at.NewATSessionHandler(bsh)
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
mux.Handle(initializers.GetEnv("AT_ENDPOINT", "/"), sh)
|
mux.Handle(initializers.GetEnv("AT_ENDPOINT", "/"), sh)
|
||||||
|
@ -10,16 +10,16 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"git.defalsify.org/vise.git/engine"
|
"git.defalsify.org/vise.git/engine"
|
||||||
|
"git.defalsify.org/vise.git/lang"
|
||||||
"git.defalsify.org/vise.git/logging"
|
"git.defalsify.org/vise.git/logging"
|
||||||
"git.defalsify.org/vise.git/resource"
|
"git.defalsify.org/vise.git/resource"
|
||||||
"git.defalsify.org/vise.git/lang"
|
|
||||||
|
|
||||||
"git.grassecon.net/urdt/ussd/config"
|
"git.grassecon.net/urdt/ussd/config"
|
||||||
"git.grassecon.net/urdt/ussd/initializers"
|
"git.grassecon.net/urdt/ussd/initializers"
|
||||||
|
"git.grassecon.net/urdt/ussd/internal/args"
|
||||||
"git.grassecon.net/urdt/ussd/internal/handlers"
|
"git.grassecon.net/urdt/ussd/internal/handlers"
|
||||||
"git.grassecon.net/urdt/ussd/internal/storage"
|
"git.grassecon.net/urdt/ussd/internal/storage"
|
||||||
"git.grassecon.net/urdt/ussd/remote"
|
"git.grassecon.net/urdt/ussd/remote"
|
||||||
"git.grassecon.net/urdt/ussd/internal/args"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -48,20 +48,20 @@ func (p *asyncRequestParser) GetInput(r any) ([]byte, error) {
|
|||||||
func main() {
|
func main() {
|
||||||
config.LoadConfig()
|
config.LoadConfig()
|
||||||
|
|
||||||
|
var connStr string
|
||||||
var sessionId string
|
var sessionId string
|
||||||
var dbDir string
|
|
||||||
var resourceDir string
|
var resourceDir string
|
||||||
var size uint
|
var size uint
|
||||||
var database string
|
|
||||||
var engineDebug bool
|
var engineDebug bool
|
||||||
var host string
|
var host string
|
||||||
var port uint
|
var port uint
|
||||||
|
var err error
|
||||||
var gettextDir string
|
var gettextDir string
|
||||||
var langs args.LangVar
|
var langs args.LangVar
|
||||||
|
|
||||||
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
|
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
|
||||||
flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from")
|
|
||||||
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
|
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
|
||||||
flag.StringVar(&database, "db", "gdbm", "database to be used")
|
flag.StringVar(&connStr, "c", "", "connection string")
|
||||||
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
|
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
|
||||||
flag.UintVar(&size, "s", 160, "max size of output")
|
flag.UintVar(&size, "s", 160, "max size of output")
|
||||||
flag.StringVar(&host, "h", initializers.GetEnv("HOST", "127.0.0.1"), "http host")
|
flag.StringVar(&host, "h", initializers.GetEnv("HOST", "127.0.0.1"), "http host")
|
||||||
@ -70,10 +70,18 @@ func main() {
|
|||||||
flag.Var(&langs, "language", "add symbol resolution for language")
|
flag.Var(&langs, "language", "add symbol resolution for language")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
logg.Infof("start command", "dbdir", dbDir, "resourcedir", resourceDir, "outputsize", size, "sessionId", sessionId)
|
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.Background()
|
||||||
ctx = context.WithValue(ctx, "Database", database)
|
|
||||||
|
|
||||||
ln, err := lang.LanguageFromCode(config.DefaultLanguage)
|
ln, err := lang.LanguageFromCode(config.DefaultLanguage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -95,14 +103,13 @@ func main() {
|
|||||||
cfg.EngineDebug = true
|
cfg.EngineDebug = true
|
||||||
}
|
}
|
||||||
|
|
||||||
menuStorageService := storage.NewMenuStorageService(dbDir, resourceDir)
|
menuStorageService := storage.NewMenuStorageService(connData, resourceDir)
|
||||||
rs, err := menuStorageService.GetResource(ctx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, err.Error())
|
fmt.Fprintf(os.Stderr, err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = menuStorageService.EnsureDbDir()
|
rs, err := menuStorageService.GetResource(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, err.Error())
|
fmt.Fprintf(os.Stderr, err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -12,17 +12,17 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"git.defalsify.org/vise.git/engine"
|
"git.defalsify.org/vise.git/engine"
|
||||||
|
"git.defalsify.org/vise.git/lang"
|
||||||
"git.defalsify.org/vise.git/logging"
|
"git.defalsify.org/vise.git/logging"
|
||||||
"git.defalsify.org/vise.git/resource"
|
"git.defalsify.org/vise.git/resource"
|
||||||
"git.defalsify.org/vise.git/lang"
|
|
||||||
|
|
||||||
"git.grassecon.net/urdt/ussd/config"
|
"git.grassecon.net/urdt/ussd/config"
|
||||||
"git.grassecon.net/urdt/ussd/initializers"
|
"git.grassecon.net/urdt/ussd/initializers"
|
||||||
|
"git.grassecon.net/urdt/ussd/internal/args"
|
||||||
"git.grassecon.net/urdt/ussd/internal/handlers"
|
"git.grassecon.net/urdt/ussd/internal/handlers"
|
||||||
httpserver "git.grassecon.net/urdt/ussd/internal/http"
|
httpserver "git.grassecon.net/urdt/ussd/internal/http"
|
||||||
"git.grassecon.net/urdt/ussd/internal/storage"
|
"git.grassecon.net/urdt/ussd/internal/storage"
|
||||||
"git.grassecon.net/urdt/ussd/remote"
|
"git.grassecon.net/urdt/ussd/remote"
|
||||||
"git.grassecon.net/urdt/ussd/internal/args"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -38,18 +38,18 @@ func init() {
|
|||||||
func main() {
|
func main() {
|
||||||
config.LoadConfig()
|
config.LoadConfig()
|
||||||
|
|
||||||
var dbDir string
|
var connStr string
|
||||||
var resourceDir string
|
var resourceDir string
|
||||||
var size uint
|
var size uint
|
||||||
var database string
|
|
||||||
var engineDebug bool
|
var engineDebug bool
|
||||||
var host string
|
var host string
|
||||||
var port uint
|
var port uint
|
||||||
|
var err error
|
||||||
var gettextDir string
|
var gettextDir string
|
||||||
var langs args.LangVar
|
var langs args.LangVar
|
||||||
flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from")
|
|
||||||
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
|
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
|
||||||
flag.StringVar(&database, "db", "gdbm", "database to be used")
|
flag.StringVar(&connStr, "c", "", "connection string")
|
||||||
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
|
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
|
||||||
flag.UintVar(&size, "s", 160, "max size of output")
|
flag.UintVar(&size, "s", 160, "max size of output")
|
||||||
flag.StringVar(&host, "h", initializers.GetEnv("HOST", "127.0.0.1"), "http host")
|
flag.StringVar(&host, "h", initializers.GetEnv("HOST", "127.0.0.1"), "http host")
|
||||||
@ -58,10 +58,18 @@ func main() {
|
|||||||
flag.Var(&langs, "language", "add symbol resolution for language")
|
flag.Var(&langs, "language", "add symbol resolution for language")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
logg.Infof("start command", "dbdir", dbDir, "resourcedir", resourceDir, "outputsize", size)
|
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.Background()
|
||||||
ctx = context.WithValue(ctx, "Database", database)
|
|
||||||
|
|
||||||
ln, err := lang.LanguageFromCode(config.DefaultLanguage)
|
ln, err := lang.LanguageFromCode(config.DefaultLanguage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -83,14 +91,9 @@ func main() {
|
|||||||
cfg.EngineDebug = true
|
cfg.EngineDebug = true
|
||||||
}
|
}
|
||||||
|
|
||||||
menuStorageService := storage.NewMenuStorageService(dbDir, resourceDir)
|
menuStorageService := storage.NewMenuStorageService(connData, resourceDir)
|
||||||
rs, err := menuStorageService.GetResource(ctx)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, err.Error())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = menuStorageService.EnsureDbDir()
|
rs, err := menuStorageService.GetResource(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, err.Error())
|
fmt.Fprintf(os.Stderr, err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
36
cmd/main.go
36
cmd/main.go
@ -8,14 +8,14 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
|
|
||||||
"git.defalsify.org/vise.git/engine"
|
"git.defalsify.org/vise.git/engine"
|
||||||
|
"git.defalsify.org/vise.git/lang"
|
||||||
"git.defalsify.org/vise.git/logging"
|
"git.defalsify.org/vise.git/logging"
|
||||||
"git.defalsify.org/vise.git/resource"
|
"git.defalsify.org/vise.git/resource"
|
||||||
"git.defalsify.org/vise.git/lang"
|
|
||||||
"git.grassecon.net/urdt/ussd/config"
|
"git.grassecon.net/urdt/ussd/config"
|
||||||
"git.grassecon.net/urdt/ussd/initializers"
|
"git.grassecon.net/urdt/ussd/initializers"
|
||||||
|
"git.grassecon.net/urdt/ussd/internal/args"
|
||||||
"git.grassecon.net/urdt/ussd/internal/handlers"
|
"git.grassecon.net/urdt/ussd/internal/handlers"
|
||||||
"git.grassecon.net/urdt/ussd/internal/storage"
|
"git.grassecon.net/urdt/ussd/internal/storage"
|
||||||
"git.grassecon.net/urdt/ussd/internal/args"
|
|
||||||
"git.grassecon.net/urdt/ussd/remote"
|
"git.grassecon.net/urdt/ussd/remote"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -33,23 +33,34 @@ func init() {
|
|||||||
func main() {
|
func main() {
|
||||||
config.LoadConfig()
|
config.LoadConfig()
|
||||||
|
|
||||||
var dbDir string
|
var connStr string
|
||||||
var size uint
|
var size uint
|
||||||
var sessionId string
|
var sessionId string
|
||||||
var database string
|
|
||||||
var engineDebug bool
|
var engineDebug bool
|
||||||
|
var resourceDir string
|
||||||
|
var err error
|
||||||
var gettextDir string
|
var gettextDir string
|
||||||
var langs args.LangVar
|
var langs args.LangVar
|
||||||
|
|
||||||
|
flag.StringVar(&resourceDir, "resourcedir", scriptDir, "resource dir")
|
||||||
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
|
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
|
||||||
flag.StringVar(&database, "db", "gdbm", "database to be used")
|
flag.StringVar(&connStr, "c", "", "connection string")
|
||||||
flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from")
|
|
||||||
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
|
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
|
||||||
flag.UintVar(&size, "s", 160, "max size of output")
|
flag.UintVar(&size, "s", 160, "max size of output")
|
||||||
flag.StringVar(&gettextDir, "gettext", "", "use gettext translations from given directory")
|
flag.StringVar(&gettextDir, "gettext", "", "use gettext translations from given directory")
|
||||||
flag.Var(&langs, "language", "add symbol resolution for language")
|
flag.Var(&langs, "language", "add symbol resolution for language")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
logg.Infof("start command", "dbdir", dbDir, "outputsize", size)
|
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 {
|
if len(langs.Langs()) == 0 {
|
||||||
langs.Set(config.DefaultLanguage)
|
langs.Set(config.DefaultLanguage)
|
||||||
@ -57,7 +68,6 @@ func main() {
|
|||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
ctx = context.WithValue(ctx, "SessionId", sessionId)
|
ctx = context.WithValue(ctx, "SessionId", sessionId)
|
||||||
ctx = context.WithValue(ctx, "Database", database)
|
|
||||||
|
|
||||||
ln, err := lang.LanguageFromCode(config.DefaultLanguage)
|
ln, err := lang.LanguageFromCode(config.DefaultLanguage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -76,18 +86,12 @@ func main() {
|
|||||||
MenuSeparator: menuSeparator,
|
MenuSeparator: menuSeparator,
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceDir := scriptDir
|
menuStorageService := storage.NewMenuStorageService(connData, resourceDir)
|
||||||
menuStorageService := storage.NewMenuStorageService(dbDir, resourceDir)
|
|
||||||
if gettextDir != "" {
|
if gettextDir != "" {
|
||||||
menuStorageService = menuStorageService.WithGettext(gettextDir, langs.Langs())
|
menuStorageService = menuStorageService.WithGettext(gettextDir, langs.Langs())
|
||||||
}
|
}
|
||||||
|
|
||||||
err = menuStorageService.EnsureDbDir()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, err.Error())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
rs, err := menuStorageService.GetResource(ctx)
|
rs, err := menuStorageService.GetResource(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, err.Error())
|
fmt.Fprintf(os.Stderr, err.Error())
|
||||||
|
@ -14,7 +14,10 @@ import (
|
|||||||
"git.defalsify.org/vise.git/engine"
|
"git.defalsify.org/vise.git/engine"
|
||||||
"git.defalsify.org/vise.git/logging"
|
"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/ssh"
|
||||||
|
"git.grassecon.net/urdt/ussd/internal/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -26,25 +29,49 @@ var (
|
|||||||
build = "dev"
|
build = "dev"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
initializers.LoadEnvVariables()
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var dbDir string
|
config.LoadConfig()
|
||||||
|
|
||||||
|
var connStr string
|
||||||
|
var authConnStr string
|
||||||
var resourceDir string
|
var resourceDir string
|
||||||
var size uint
|
var size uint
|
||||||
var engineDebug bool
|
var engineDebug bool
|
||||||
var stateDebug bool
|
var stateDebug bool
|
||||||
var host string
|
var host string
|
||||||
var port uint
|
var port uint
|
||||||
flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from")
|
flag.StringVar(&connStr, "c", "", "connection string")
|
||||||
|
flag.StringVar(&authConnStr, "authdb", "", "auth connection string")
|
||||||
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
|
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
|
||||||
flag.BoolVar(&engineDebug, "engine-debug", false, "use engine debug output")
|
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
|
||||||
flag.BoolVar(&stateDebug, "state-debug", false, "use engine debug output")
|
|
||||||
flag.UintVar(&size, "s", 160, "max size of output")
|
flag.UintVar(&size, "s", 160, "max size of output")
|
||||||
flag.StringVar(&host, "h", "127.0.0.1", "http host")
|
flag.StringVar(&host, "h", "127.0.0.1", "socket host")
|
||||||
flag.UintVar(&port, "p", 7122, "http port")
|
flag.UintVar(&port, "p", 7122, "socket port")
|
||||||
flag.Parse()
|
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)
|
sshKeyFile := flag.Arg(0)
|
||||||
_, err := os.Stat(sshKeyFile)
|
_, err = os.Stat(sshKeyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "cannot open ssh server private key file: %v\n", err)
|
fmt.Fprintf(os.Stderr, "cannot open ssh server private key file: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
@ -57,7 +84,7 @@ func main() {
|
|||||||
logg.WarnCtxf(ctx, "!!!!! Do not expose to internet and only use with tunnel!")
|
logg.WarnCtxf(ctx, "!!!!! Do not expose to internet and only use with tunnel!")
|
||||||
logg.WarnCtxf(ctx, "!!!!! (See ssh -L <...>)")
|
logg.WarnCtxf(ctx, "!!!!! (See ssh -L <...>)")
|
||||||
|
|
||||||
logg.Infof("start command", "dbdir", dbDir, "resourcedir", resourceDir, "outputsize", size, "keyfile", sshKeyFile, "host", host, "port", port)
|
logg.Infof("start command", "conn", connData, "authconn", authConnData, "resourcedir", resourceDir, "outputsize", size, "keyfile", sshKeyFile, "host", host, "port", port)
|
||||||
|
|
||||||
pfp := path.Join(scriptDir, "pp.csv")
|
pfp := path.Join(scriptDir, "pp.csv")
|
||||||
|
|
||||||
@ -73,7 +100,7 @@ func main() {
|
|||||||
cfg.EngineDebug = true
|
cfg.EngineDebug = true
|
||||||
}
|
}
|
||||||
|
|
||||||
authKeyStore, err := ssh.NewSshKeyStore(ctx, dbDir)
|
authKeyStore, err := ssh.NewSshKeyStore(ctx, authConnData.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "keystore file open error: %v", err)
|
fmt.Fprintf(os.Stderr, "keystore file open error: %v", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
@ -95,7 +122,7 @@ func main() {
|
|||||||
Cfg: cfg,
|
Cfg: cfg,
|
||||||
Debug: engineDebug,
|
Debug: engineDebug,
|
||||||
FlagFile: pfp,
|
FlagFile: pfp,
|
||||||
DbDir: dbDir,
|
Conn: connData,
|
||||||
ResourceDir: resourceDir,
|
ResourceDir: resourceDir,
|
||||||
SrvKeyFile: sshKeyFile,
|
SrvKeyFile: sshKeyFile,
|
||||||
Host: host,
|
Host: host,
|
||||||
|
@ -55,6 +55,10 @@ const (
|
|||||||
DATA_ACTIVE_DECIMAL
|
DATA_ACTIVE_DECIMAL
|
||||||
// EVM address of the currently active voucher
|
// EVM address of the currently active voucher
|
||||||
DATA_ACTIVE_ADDRESS
|
DATA_ACTIVE_ADDRESS
|
||||||
|
//Holds count of the number of incorrect PIN attempts
|
||||||
|
DATA_INCORRECT_PIN_ATTEMPTS
|
||||||
|
//ISO 639 code for the selected language.
|
||||||
|
DATA_SELECTED_LANGUAGE_CODE
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -6,9 +6,13 @@ import (
|
|||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Define the regex pattern as a constant
|
|
||||||
const (
|
const (
|
||||||
|
// Define the regex pattern as a constant
|
||||||
pinPattern = `^\d{4}$`
|
pinPattern = `^\d{4}$`
|
||||||
|
|
||||||
|
//Allowed incorrect PIN attempts
|
||||||
|
AllowedPINAttempts = uint8(3)
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// checks whether the given input is a 4 digit number
|
// checks whether the given input is a 4 digit number
|
||||||
|
@ -23,17 +23,17 @@ type StorageServices interface {
|
|||||||
GetPersister(ctx context.Context) (*persist.Persister, error)
|
GetPersister(ctx context.Context) (*persist.Persister, error)
|
||||||
GetUserdataDb(ctx context.Context) (db.Db, error)
|
GetUserdataDb(ctx context.Context) (db.Db, error)
|
||||||
GetResource(ctx context.Context) (resource.Resource, error)
|
GetResource(ctx context.Context) (resource.Resource, error)
|
||||||
EnsureDbDir() error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type StorageService struct {
|
type StorageService struct {
|
||||||
svc *storage.MenuStorageService
|
svc *storage.MenuStorageService
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStorageService(dbDir string) *StorageService {
|
func NewStorageService(conn storage.ConnData) (*StorageService, error) {
|
||||||
return &StorageService{
|
svc := &StorageService{
|
||||||
svc: storage.NewMenuStorageService(dbDir, ""),
|
svc: storage.NewMenuStorageService(conn, ""),
|
||||||
}
|
}
|
||||||
|
return svc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func(ss *StorageService) GetPersister(ctx context.Context) (*persist.Persister, error) {
|
func(ss *StorageService) GetPersister(ctx context.Context) (*persist.Persister, error) {
|
||||||
@ -47,7 +47,3 @@ func(ss *StorageService) GetUserdataDb(ctx context.Context) (db.Db, error) {
|
|||||||
func(ss *StorageService) GetResource(ctx context.Context) (resource.Resource, error) {
|
func(ss *StorageService) GetResource(ctx context.Context) (resource.Resource, error) {
|
||||||
return nil, errors.New("not implemented")
|
return nil, errors.New("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func(ss *StorageService) EnsureDbDir() error {
|
|
||||||
return ss.svc.EnsureDbDir()
|
|
||||||
}
|
|
||||||
|
@ -40,6 +40,7 @@ var (
|
|||||||
VoucherTransfersURL string
|
VoucherTransfersURL string
|
||||||
VoucherDataURL string
|
VoucherDataURL string
|
||||||
CheckAliasURL string
|
CheckAliasURL string
|
||||||
|
DbConn string
|
||||||
DefaultLanguage string
|
DefaultLanguage string
|
||||||
Languages []string
|
Languages []string
|
||||||
)
|
)
|
||||||
@ -69,14 +70,20 @@ func setBase() error {
|
|||||||
dataURLBase = initializers.GetEnv("DATA_URL_BASE", "http://localhost:5006")
|
dataURLBase = initializers.GetEnv("DATA_URL_BASE", "http://localhost:5006")
|
||||||
BearerToken = initializers.GetEnv("BEARER_TOKEN", "")
|
BearerToken = initializers.GetEnv("BEARER_TOKEN", "")
|
||||||
|
|
||||||
_, err = url.JoinPath(custodialURLBase, "/foo")
|
_, err = url.Parse(custodialURLBase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = url.JoinPath(dataURLBase, "/bar")
|
_, err = url.Parse(dataURLBase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setConn() error {
|
||||||
|
DbConn = initializers.GetEnv("DB_CONN", "")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,6 +93,10 @@ func LoadConfig() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
err = setConn()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
err = setLanguage()
|
err = setLanguage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -37,23 +37,34 @@ func formatItem(k []byte, v []byte) (string, error) {
|
|||||||
func main() {
|
func main() {
|
||||||
config.LoadConfig()
|
config.LoadConfig()
|
||||||
|
|
||||||
var dbDir string
|
var connStr string
|
||||||
var sessionId string
|
var sessionId string
|
||||||
var database string
|
var database string
|
||||||
var engineDebug bool
|
var engineDebug bool
|
||||||
|
var err error
|
||||||
|
|
||||||
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
|
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
|
||||||
flag.StringVar(&database, "db", "gdbm", "database to be used")
|
flag.StringVar(&connStr, "c", ".state", "connection string")
|
||||||
flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from")
|
|
||||||
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
|
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
if connStr != "" {
|
||||||
|
connStr = config.DbConn
|
||||||
|
}
|
||||||
|
connData, err := storage.ToConnData(config.DbConn)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "connstr err: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
logg.Infof("start command", "conn", connData)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
ctx = context.WithValue(ctx, "SessionId", sessionId)
|
ctx = context.WithValue(ctx, "SessionId", sessionId)
|
||||||
ctx = context.WithValue(ctx, "Database", database)
|
ctx = context.WithValue(ctx, "Database", database)
|
||||||
|
|
||||||
resourceDir := scriptDir
|
resourceDir := scriptDir
|
||||||
menuStorageService := storage.NewMenuStorageService(dbDir, resourceDir)
|
menuStorageService := storage.NewMenuStorageService(connData, resourceDir)
|
||||||
|
|
||||||
store, err := menuStorageService.GetUserdataDb(ctx)
|
store, err := menuStorageService.GetUserdataDb(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -9,14 +9,16 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
|
|
||||||
"git.defalsify.org/vise.git/logging"
|
"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/urdt/ussd/common"
|
||||||
|
"git.grassecon.net/urdt/ussd/config"
|
||||||
|
"git.grassecon.net/urdt/ussd/initializers"
|
||||||
|
"git.grassecon.net/urdt/ussd/internal/storage"
|
||||||
|
testdataloader "github.com/peteole/testdata-loader"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
logg = logging.NewVanilla()
|
logg = logging.NewVanilla()
|
||||||
|
baseDir = testdataloader.GetBasePath()
|
||||||
scriptDir = path.Join("services", "registration")
|
scriptDir = path.Join("services", "registration")
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -24,27 +26,37 @@ func init() {
|
|||||||
initializers.LoadEnvVariables()
|
initializers.LoadEnvVariables()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
config.LoadConfig()
|
config.LoadConfig()
|
||||||
|
|
||||||
var dbDir string
|
var connStr string
|
||||||
var sessionId string
|
var sessionId string
|
||||||
var database string
|
var database string
|
||||||
var engineDebug bool
|
var engineDebug bool
|
||||||
|
var err error
|
||||||
|
|
||||||
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
|
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
|
||||||
flag.StringVar(&database, "db", "gdbm", "database to be used")
|
flag.StringVar(&connStr, "c", "", "connection string")
|
||||||
flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from")
|
|
||||||
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
|
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
if connStr != "" {
|
||||||
|
connStr = config.DbConn
|
||||||
|
}
|
||||||
|
connData, err := storage.ToConnData(config.DbConn)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "connstr err: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
logg.Infof("start command", "conn", connData)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
ctx = context.WithValue(ctx, "SessionId", sessionId)
|
ctx = context.WithValue(ctx, "SessionId", sessionId)
|
||||||
ctx = context.WithValue(ctx, "Database", database)
|
ctx = context.WithValue(ctx, "Database", database)
|
||||||
|
|
||||||
resourceDir := scriptDir
|
resourceDir := scriptDir
|
||||||
menuStorageService := storage.NewMenuStorageService(dbDir, resourceDir)
|
menuStorageService := storage.NewMenuStorageService(connData, resourceDir)
|
||||||
|
|
||||||
store, err := menuStorageService.GetUserdataDb(ctx)
|
store, err := menuStorageService.GetUserdataDb(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -75,5 +87,4 @@ func main() {
|
|||||||
fmt.Fprintf(os.Stderr, err.Error())
|
fmt.Fprintf(os.Stderr, err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,15 +3,21 @@ package initializers
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
)
|
)
|
||||||
|
|
||||||
func LoadEnvVariables() {
|
func LoadEnvVariables() {
|
||||||
err := godotenv.Load()
|
LoadEnvVariablesPath(".")
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadEnvVariablesPath(dir string) {
|
||||||
|
fp := path.Join(dir, ".env")
|
||||||
|
err := godotenv.Load(fp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error loading .env file")
|
log.Fatal("Error loading .env file", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package ussd
|
package application
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -161,9 +161,12 @@ func (h *Handlers) SetLanguage(ctx context.Context, sym string, input []byte) (r
|
|||||||
//Fallback to english instead?
|
//Fallback to english instead?
|
||||||
code = "eng"
|
code = "eng"
|
||||||
}
|
}
|
||||||
res.FlagSet = append(res.FlagSet, state.FLAG_LANG)
|
err := h.persistLanguageCode(ctx, code)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
res.Content = code
|
res.Content = code
|
||||||
|
res.FlagSet = append(res.FlagSet, state.FLAG_LANG)
|
||||||
languageSetFlag, err := h.flagManager.GetFlag("flag_language_set")
|
languageSetFlag, err := h.flagManager.GetFlag("flag_language_set")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logg.ErrorCtxf(ctx, "Error setting the languageSetFlag", "error", err)
|
logg.ErrorCtxf(ctx, "Error setting the languageSetFlag", "error", err)
|
||||||
@ -734,11 +737,23 @@ func (h *Handlers) Authorize(ctx context.Context, sym string, input []byte) (res
|
|||||||
if h.st.MatchFlag(flag_account_authorized, false) {
|
if h.st.MatchFlag(flag_account_authorized, false) {
|
||||||
res.FlagReset = append(res.FlagReset, flag_incorrect_pin)
|
res.FlagReset = append(res.FlagReset, flag_incorrect_pin)
|
||||||
res.FlagSet = append(res.FlagSet, flag_allow_update, flag_account_authorized)
|
res.FlagSet = append(res.FlagSet, flag_allow_update, flag_account_authorized)
|
||||||
|
err := h.resetIncorrectPINAttempts(ctx, sessionId)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
res.FlagSet = append(res.FlagSet, flag_allow_update)
|
res.FlagSet = append(res.FlagSet, flag_allow_update)
|
||||||
res.FlagReset = append(res.FlagReset, flag_account_authorized)
|
res.FlagReset = append(res.FlagReset, flag_account_authorized)
|
||||||
|
err := h.resetIncorrectPINAttempts(ctx, sessionId)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
err := h.incrementIncorrectPINAttempts(ctx, sessionId)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
res.FlagSet = append(res.FlagSet, flag_incorrect_pin)
|
res.FlagSet = append(res.FlagSet, flag_incorrect_pin)
|
||||||
res.FlagReset = append(res.FlagReset, flag_account_authorized)
|
res.FlagReset = append(res.FlagReset, flag_account_authorized)
|
||||||
return res, nil
|
return res, nil
|
||||||
@ -752,8 +767,34 @@ func (h *Handlers) Authorize(ctx context.Context, sym string, input []byte) (res
|
|||||||
// ResetIncorrectPin resets the incorrect pin flag after a new PIN attempt.
|
// 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) {
|
func (h *Handlers) ResetIncorrectPin(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||||
var res resource.Result
|
var res resource.Result
|
||||||
|
store := h.userdataStore
|
||||||
|
|
||||||
flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin")
|
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)
|
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
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -840,6 +881,16 @@ func (h *Handlers) QuitWithHelp(ctx context.Context, sym string, input []byte) (
|
|||||||
return res, nil
|
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.
|
// VerifyYob verifies the length of the given input.
|
||||||
func (h *Handlers) VerifyYob(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
func (h *Handlers) VerifyYob(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||||
var res resource.Result
|
var res resource.Result
|
||||||
@ -2075,3 +2126,68 @@ func (h *Handlers) UpdateAllProfileItems(ctx context.Context, sym string, input
|
|||||||
}
|
}
|
||||||
return res, nil
|
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
|
||||||
|
}
|
@ -1,10 +1,11 @@
|
|||||||
package ussd
|
package application
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"path"
|
"path"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -774,6 +775,11 @@ func TestSetLanguage(t *testing.T) {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sessionId := "session123"
|
||||||
|
ctx, store := InitializeTestStore(t)
|
||||||
|
|
||||||
|
ctx = context.WithValue(ctx, "SessionId", sessionId)
|
||||||
|
|
||||||
// Define test cases
|
// Define test cases
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@ -807,11 +813,12 @@ func TestSetLanguage(t *testing.T) {
|
|||||||
// Create the Handlers instance with the mock flag manager
|
// Create the Handlers instance with the mock flag manager
|
||||||
h := &Handlers{
|
h := &Handlers{
|
||||||
flagManager: fm.parser,
|
flagManager: fm.parser,
|
||||||
|
userdataStore: store,
|
||||||
st: mockState,
|
st: mockState,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the method
|
// Call the method
|
||||||
res, err := h.SetLanguage(context.Background(), "set_language", nil)
|
res, err := h.SetLanguage(ctx, "set_language", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -907,37 +914,79 @@ func TestResetAccountAuthorized(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIncorrectPinReset(t *testing.T) {
|
func TestIncorrectPinReset(t *testing.T) {
|
||||||
|
sessionId := "session123"
|
||||||
|
ctx, store := InitializeTestStore(t)
|
||||||
fm, err := NewFlagManager(flagsPath)
|
fm, err := NewFlagManager(flagsPath)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
flag_incorrect_pin, _ := fm.parser.GetFlag("flag_incorrect_pin")
|
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
|
// Define test cases
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
input []byte
|
input []byte
|
||||||
|
attempts uint8
|
||||||
expectedResult resource.Result
|
expectedResult resource.Result
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Test incorrect pin reset",
|
name: "Test when incorrect PIN attempts is 2",
|
||||||
input: []byte(""),
|
input: []byte(""),
|
||||||
expectedResult: resource.Result{
|
expectedResult: resource.Result{
|
||||||
FlagReset: []uint32{flag_incorrect_pin},
|
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 {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
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
|
// Create the Handlers instance with the mock flag manager
|
||||||
h := &Handlers{
|
h := &Handlers{
|
||||||
flagManager: fm.parser,
|
flagManager: fm.parser,
|
||||||
|
userdataStore: store,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the method
|
// Call the method
|
||||||
res, err := h.ResetIncorrectPin(context.Background(), "reset_incorrect_pin", tt.input)
|
res, err := h.ResetIncorrectPin(ctx, "reset_incorrect_pin", tt.input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -2190,3 +2239,93 @@ func TestGetVoucherDetails(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, expectedResult, res)
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -6,7 +6,7 @@ import (
|
|||||||
"git.defalsify.org/vise.git/persist"
|
"git.defalsify.org/vise.git/persist"
|
||||||
"git.defalsify.org/vise.git/resource"
|
"git.defalsify.org/vise.git/resource"
|
||||||
|
|
||||||
"git.grassecon.net/urdt/ussd/internal/handlers/ussd"
|
"git.grassecon.net/urdt/ussd/internal/handlers/application"
|
||||||
"git.grassecon.net/urdt/ussd/internal/storage"
|
"git.grassecon.net/urdt/ussd/internal/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -14,11 +14,11 @@ type BaseSessionHandler struct {
|
|||||||
cfgTemplate engine.Config
|
cfgTemplate engine.Config
|
||||||
rp RequestParser
|
rp RequestParser
|
||||||
rs resource.Resource
|
rs resource.Resource
|
||||||
hn *ussd.Handlers
|
hn *application.Handlers
|
||||||
provider storage.StorageProvider
|
provider storage.StorageProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBaseSessionHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, rp RequestParser, hn *ussd.Handlers) *BaseSessionHandler {
|
func NewBaseSessionHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, rp RequestParser, hn *application.Handlers) *BaseSessionHandler {
|
||||||
return &BaseSessionHandler{
|
return &BaseSessionHandler{
|
||||||
cfgTemplate: cfg,
|
cfgTemplate: cfg,
|
||||||
rs: rs,
|
rs: rs,
|
||||||
|
141
internal/handlers/handler_service.go
Normal file
141
internal/handlers/handler_service.go
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
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
|
||||||
|
}
|
@ -1,140 +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/ussd"
|
|
||||||
"git.grassecon.net/urdt/ussd/internal/utils"
|
|
||||||
"git.grassecon.net/urdt/ussd/remote"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HandlerService interface {
|
|
||||||
GetHandler() (*ussd.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) (*ussd.Handlers, error) {
|
|
||||||
replaceSeparatorFunc := func(input string) string {
|
|
||||||
return strings.ReplaceAll(input, ":", ls.Cfg.MenuSeparator)
|
|
||||||
}
|
|
||||||
|
|
||||||
ussdHandlers, err := ussd.NewHandlers(ls.Parser, *ls.UserdataStore, ls.AdminStore, accountService, replaceSeparatorFunc)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ussdHandlers = ussdHandlers.WithPersister(ls.Pe)
|
|
||||||
ls.DbRs.AddLocalFunc("set_language", ussdHandlers.SetLanguage)
|
|
||||||
ls.DbRs.AddLocalFunc("create_account", ussdHandlers.CreateAccount)
|
|
||||||
ls.DbRs.AddLocalFunc("save_temporary_pin", ussdHandlers.SaveTemporaryPin)
|
|
||||||
ls.DbRs.AddLocalFunc("verify_create_pin", ussdHandlers.VerifyCreatePin)
|
|
||||||
ls.DbRs.AddLocalFunc("check_identifier", ussdHandlers.CheckIdentifier)
|
|
||||||
ls.DbRs.AddLocalFunc("check_account_status", ussdHandlers.CheckAccountStatus)
|
|
||||||
ls.DbRs.AddLocalFunc("authorize_account", ussdHandlers.Authorize)
|
|
||||||
ls.DbRs.AddLocalFunc("quit", ussdHandlers.Quit)
|
|
||||||
ls.DbRs.AddLocalFunc("check_balance", ussdHandlers.CheckBalance)
|
|
||||||
ls.DbRs.AddLocalFunc("validate_recipient", ussdHandlers.ValidateRecipient)
|
|
||||||
ls.DbRs.AddLocalFunc("transaction_reset", ussdHandlers.TransactionReset)
|
|
||||||
ls.DbRs.AddLocalFunc("invite_valid_recipient", ussdHandlers.InviteValidRecipient)
|
|
||||||
ls.DbRs.AddLocalFunc("max_amount", ussdHandlers.MaxAmount)
|
|
||||||
ls.DbRs.AddLocalFunc("validate_amount", ussdHandlers.ValidateAmount)
|
|
||||||
ls.DbRs.AddLocalFunc("reset_transaction_amount", ussdHandlers.ResetTransactionAmount)
|
|
||||||
ls.DbRs.AddLocalFunc("get_recipient", ussdHandlers.GetRecipient)
|
|
||||||
ls.DbRs.AddLocalFunc("get_sender", ussdHandlers.GetSender)
|
|
||||||
ls.DbRs.AddLocalFunc("get_amount", ussdHandlers.GetAmount)
|
|
||||||
ls.DbRs.AddLocalFunc("reset_incorrect", ussdHandlers.ResetIncorrectPin)
|
|
||||||
ls.DbRs.AddLocalFunc("save_firstname", ussdHandlers.SaveFirstname)
|
|
||||||
ls.DbRs.AddLocalFunc("save_familyname", ussdHandlers.SaveFamilyname)
|
|
||||||
ls.DbRs.AddLocalFunc("save_gender", ussdHandlers.SaveGender)
|
|
||||||
ls.DbRs.AddLocalFunc("save_location", ussdHandlers.SaveLocation)
|
|
||||||
ls.DbRs.AddLocalFunc("save_yob", ussdHandlers.SaveYob)
|
|
||||||
ls.DbRs.AddLocalFunc("save_offerings", ussdHandlers.SaveOfferings)
|
|
||||||
ls.DbRs.AddLocalFunc("reset_account_authorized", ussdHandlers.ResetAccountAuthorized)
|
|
||||||
ls.DbRs.AddLocalFunc("reset_allow_update", ussdHandlers.ResetAllowUpdate)
|
|
||||||
ls.DbRs.AddLocalFunc("get_profile_info", ussdHandlers.GetProfileInfo)
|
|
||||||
ls.DbRs.AddLocalFunc("verify_yob", ussdHandlers.VerifyYob)
|
|
||||||
ls.DbRs.AddLocalFunc("reset_incorrect_date_format", ussdHandlers.ResetIncorrectYob)
|
|
||||||
ls.DbRs.AddLocalFunc("initiate_transaction", ussdHandlers.InitiateTransaction)
|
|
||||||
ls.DbRs.AddLocalFunc("verify_new_pin", ussdHandlers.VerifyNewPin)
|
|
||||||
ls.DbRs.AddLocalFunc("confirm_pin_change", ussdHandlers.ConfirmPinChange)
|
|
||||||
ls.DbRs.AddLocalFunc("quit_with_help", ussdHandlers.QuitWithHelp)
|
|
||||||
ls.DbRs.AddLocalFunc("fetch_community_balance", ussdHandlers.FetchCommunityBalance)
|
|
||||||
ls.DbRs.AddLocalFunc("set_default_voucher", ussdHandlers.SetDefaultVoucher)
|
|
||||||
ls.DbRs.AddLocalFunc("check_vouchers", ussdHandlers.CheckVouchers)
|
|
||||||
ls.DbRs.AddLocalFunc("get_vouchers", ussdHandlers.GetVoucherList)
|
|
||||||
ls.DbRs.AddLocalFunc("view_voucher", ussdHandlers.ViewVoucher)
|
|
||||||
ls.DbRs.AddLocalFunc("set_voucher", ussdHandlers.SetVoucher)
|
|
||||||
ls.DbRs.AddLocalFunc("get_voucher_details", ussdHandlers.GetVoucherDetails)
|
|
||||||
ls.DbRs.AddLocalFunc("reset_valid_pin", ussdHandlers.ResetValidPin)
|
|
||||||
ls.DbRs.AddLocalFunc("check_pin_mismatch", ussdHandlers.CheckBlockedNumPinMisMatch)
|
|
||||||
ls.DbRs.AddLocalFunc("validate_blocked_number", ussdHandlers.ValidateBlockedNumber)
|
|
||||||
ls.DbRs.AddLocalFunc("retrieve_blocked_number", ussdHandlers.RetrieveBlockedNumber)
|
|
||||||
ls.DbRs.AddLocalFunc("reset_unregistered_number", ussdHandlers.ResetUnregisteredNumber)
|
|
||||||
ls.DbRs.AddLocalFunc("reset_others_pin", ussdHandlers.ResetOthersPin)
|
|
||||||
ls.DbRs.AddLocalFunc("save_others_temporary_pin", ussdHandlers.SaveOthersTemporaryPin)
|
|
||||||
ls.DbRs.AddLocalFunc("get_current_profile_info", ussdHandlers.GetCurrentProfileInfo)
|
|
||||||
ls.DbRs.AddLocalFunc("check_transactions", ussdHandlers.CheckTransactions)
|
|
||||||
ls.DbRs.AddLocalFunc("get_transactions", ussdHandlers.GetTransactionsList)
|
|
||||||
ls.DbRs.AddLocalFunc("view_statement", ussdHandlers.ViewTransactionStatement)
|
|
||||||
ls.DbRs.AddLocalFunc("update_all_profile_items", ussdHandlers.UpdateAllProfileItems)
|
|
||||||
ls.DbRs.AddLocalFunc("set_back", ussdHandlers.SetBack)
|
|
||||||
|
|
||||||
return ussdHandlers, 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
|
|
||||||
}
|
|
@ -41,6 +41,7 @@ func NewAuther(ctx context.Context, keyStore *SshKeyStore) *auther {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func(a *auther) Check(conn ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
|
func(a *auther) Check(conn ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
|
||||||
|
logg.TraceCtxf(a.Ctx, "looking for publickey", "pubkey", fmt.Sprintf("%x", pubKey))
|
||||||
va, err := a.keyStore.Get(a.Ctx, pubKey)
|
va, err := a.keyStore.Get(a.Ctx, pubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -71,6 +72,20 @@ func(a *auther) Get(k []byte) (string, error) {
|
|||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SshRunner struct {
|
||||||
|
Ctx context.Context
|
||||||
|
Cfg engine.Config
|
||||||
|
FlagFile string
|
||||||
|
Conn storage.ConnData
|
||||||
|
ResourceDir string
|
||||||
|
Debug bool
|
||||||
|
SrvKeyFile string
|
||||||
|
Host string
|
||||||
|
Port uint
|
||||||
|
wg sync.WaitGroup
|
||||||
|
lst net.Listener
|
||||||
|
}
|
||||||
|
|
||||||
func(s *SshRunner) serve(ctx context.Context, sessionId string, ch ssh.NewChannel, en engine.Engine) error {
|
func(s *SshRunner) serve(ctx context.Context, sessionId string, ch ssh.NewChannel, en engine.Engine) error {
|
||||||
if ch == nil {
|
if ch == nil {
|
||||||
return errors.New("nil channel")
|
return errors.New("nil channel")
|
||||||
@ -128,32 +143,13 @@ func(s *SshRunner) serve(ctx context.Context, sessionId string, ch ssh.NewChanne
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type SshRunner struct {
|
|
||||||
Ctx context.Context
|
|
||||||
Cfg engine.Config
|
|
||||||
FlagFile string
|
|
||||||
DbDir string
|
|
||||||
ResourceDir string
|
|
||||||
Debug bool
|
|
||||||
SrvKeyFile string
|
|
||||||
Host string
|
|
||||||
Port uint
|
|
||||||
wg sync.WaitGroup
|
|
||||||
lst net.Listener
|
|
||||||
}
|
|
||||||
|
|
||||||
func(s *SshRunner) Stop() error {
|
func(s *SshRunner) Stop() error {
|
||||||
return s.lst.Close()
|
return s.lst.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func(s *SshRunner) GetEngine(sessionId string) (engine.Engine, func(), error) {
|
func(s *SshRunner) GetEngine(sessionId string) (engine.Engine, func(), error) {
|
||||||
ctx := s.Ctx
|
ctx := s.Ctx
|
||||||
menuStorageService := storage.NewMenuStorageService(s.DbDir, s.ResourceDir)
|
menuStorageService := storage.NewMenuStorageService(s.Conn, s.ResourceDir)
|
||||||
|
|
||||||
err := menuStorageService.EnsureDbDir()
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
rs, err := menuStorageService.GetResource(ctx)
|
rs, err := menuStorageService.GetResource(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -208,6 +204,7 @@ func(s *SshRunner) GetEngine(sessionId string) (engine.Engine, func(), error) {
|
|||||||
|
|
||||||
// adapted example from crypto/ssh package, NewServerConn doc
|
// adapted example from crypto/ssh package, NewServerConn doc
|
||||||
func(s *SshRunner) Run(ctx context.Context, keyStore *SshKeyStore) {
|
func(s *SshRunner) Run(ctx context.Context, keyStore *SshKeyStore) {
|
||||||
|
s.Ctx = ctx
|
||||||
running := true
|
running := true
|
||||||
|
|
||||||
// TODO: waitgroup should probably not be global
|
// TODO: waitgroup should probably not be global
|
||||||
|
86
internal/storage/parse.go
Normal file
86
internal/storage/parse.go
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"path"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DBTYPE_MEM = iota
|
||||||
|
DBTYPE_GDBM
|
||||||
|
DBTYPE_POSTGRES
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConnData struct {
|
||||||
|
typ int
|
||||||
|
str string
|
||||||
|
domain string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cd *ConnData) DbType() int {
|
||||||
|
return cd.typ
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cd *ConnData) String() string {
|
||||||
|
return cd.str
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cd *ConnData) Domain() string {
|
||||||
|
return cd.domain
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cd *ConnData) Path() string {
|
||||||
|
v, _ := url.Parse(cd.str)
|
||||||
|
v.RawQuery = ""
|
||||||
|
return v.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func probePostgres(s string) (string, string, bool) {
|
||||||
|
domain := "public"
|
||||||
|
v, err := url.Parse(s)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", false
|
||||||
|
}
|
||||||
|
if v.Scheme != "postgres" {
|
||||||
|
return "", "", false
|
||||||
|
}
|
||||||
|
vv := v.Query()
|
||||||
|
if vv.Has("search_path") {
|
||||||
|
domain = vv.Get("search_path")
|
||||||
|
}
|
||||||
|
return s, domain, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func probeGdbm(s string) (string, string, bool) {
|
||||||
|
if !path.IsAbs(s) {
|
||||||
|
return "", "", false
|
||||||
|
}
|
||||||
|
s = path.Clean(s)
|
||||||
|
return s, "", true
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToConnData(connStr string) (ConnData, error) {
|
||||||
|
var o ConnData
|
||||||
|
|
||||||
|
if connStr == "" {
|
||||||
|
return o, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
v, domain, ok := probePostgres(connStr)
|
||||||
|
if ok {
|
||||||
|
o.typ = DBTYPE_POSTGRES
|
||||||
|
o.str = v
|
||||||
|
o.domain = domain
|
||||||
|
return o, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
v, _, ok = probeGdbm(connStr)
|
||||||
|
if ok {
|
||||||
|
o.typ = DBTYPE_GDBM
|
||||||
|
o.str = v
|
||||||
|
return o, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return o, fmt.Errorf("invalid connection string: %s", connStr)
|
||||||
|
}
|
28
internal/storage/parse_test.go
Normal file
28
internal/storage/parse_test.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseConnStr(t *testing.T) {
|
||||||
|
_, err := ToConnData("postgres://foo:bar@localhost:5432/baz")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = ToConnData("/foo/bar")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = ToConnData("/foo/bar/")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = ToConnData("foo/bar")
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error")
|
||||||
|
}
|
||||||
|
_, err = ToConnData("http://foo/bar")
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error")
|
||||||
|
}
|
||||||
|
}
|
@ -13,8 +13,8 @@ import (
|
|||||||
"git.defalsify.org/vise.git/logging"
|
"git.defalsify.org/vise.git/logging"
|
||||||
"git.defalsify.org/vise.git/persist"
|
"git.defalsify.org/vise.git/persist"
|
||||||
"git.defalsify.org/vise.git/resource"
|
"git.defalsify.org/vise.git/resource"
|
||||||
"git.grassecon.net/urdt/ussd/initializers"
|
|
||||||
gdbmstorage "git.grassecon.net/urdt/ussd/internal/storage/db/gdbm"
|
gdbmstorage "git.grassecon.net/urdt/ussd/internal/storage/db/gdbm"
|
||||||
|
"github.com/jackc/pgx/v5/pgxpool"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -25,11 +25,10 @@ type StorageService interface {
|
|||||||
GetPersister(ctx context.Context) (*persist.Persister, error)
|
GetPersister(ctx context.Context) (*persist.Persister, error)
|
||||||
GetUserdataDb(ctx context.Context) db.Db
|
GetUserdataDb(ctx context.Context) db.Db
|
||||||
GetResource(ctx context.Context) (resource.Resource, error)
|
GetResource(ctx context.Context) (resource.Resource, error)
|
||||||
EnsureDbDir() error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type MenuStorageService struct {
|
type MenuStorageService struct {
|
||||||
dbDir string
|
conn ConnData
|
||||||
resourceDir string
|
resourceDir string
|
||||||
poResource resource.Resource
|
poResource resource.Resource
|
||||||
resourceStore db.Db
|
resourceStore db.Db
|
||||||
@ -37,29 +36,50 @@ type MenuStorageService struct {
|
|||||||
userDataStore db.Db
|
userDataStore db.Db
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildConnStr() string {
|
func NewMenuStorageService(conn ConnData, resourceDir string) *MenuStorageService {
|
||||||
host := initializers.GetEnv("DB_HOST", "localhost")
|
|
||||||
user := initializers.GetEnv("DB_USER", "postgres")
|
|
||||||
password := initializers.GetEnv("DB_PASSWORD", "")
|
|
||||||
dbName := initializers.GetEnv("DB_NAME", "")
|
|
||||||
port := initializers.GetEnv("DB_PORT", "5432")
|
|
||||||
|
|
||||||
connString := fmt.Sprintf(
|
|
||||||
"postgres://%s:%s@%s:%s/%s",
|
|
||||||
user, password, host, port, dbName,
|
|
||||||
)
|
|
||||||
logg.Debugf("pg conn string", "conn", connString)
|
|
||||||
|
|
||||||
return connString
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMenuStorageService(dbDir string, resourceDir string) *MenuStorageService {
|
|
||||||
return &MenuStorageService{
|
return &MenuStorageService{
|
||||||
dbDir: dbDir,
|
conn: conn,
|
||||||
resourceDir: resourceDir,
|
resourceDir: resourceDir,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ms *MenuStorageService) getOrCreateDb(ctx context.Context, existingDb db.Db, section string) (db.Db, error) {
|
||||||
|
var newDb db.Db
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if existingDb != nil {
|
||||||
|
return existingDb, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
connStr := ms.conn.String()
|
||||||
|
dbTyp := ms.conn.DbType()
|
||||||
|
if dbTyp == DBTYPE_POSTGRES {
|
||||||
|
// TODO: move to vise
|
||||||
|
err = ensureSchemaExists(ctx, ms.conn)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newDb = postgres.NewPgDb().WithSchema(ms.conn.Domain())
|
||||||
|
} else if dbTyp == DBTYPE_GDBM {
|
||||||
|
err = ms.ensureDbDir()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
connStr = path.Join(connStr, section)
|
||||||
|
newDb = gdbmstorage.NewThreadGdbmDb()
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("unsupported connection string: '%s'\n", ms.conn.String())
|
||||||
|
}
|
||||||
|
logg.DebugCtxf(ctx, "connecting to db", "conn", connStr, "conndata", ms.conn)
|
||||||
|
err = newDb.Connect(ctx, connStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return newDb, nil
|
||||||
|
}
|
||||||
|
|
||||||
// WithGettext triggers use of gettext for translation of templates and menus.
|
// WithGettext triggers use of gettext for translation of templates and menus.
|
||||||
//
|
//
|
||||||
// The first language in `lns` will be used as default language, to resolve node keys to
|
// The first language in `lns` will be used as default language, to resolve node keys to
|
||||||
@ -82,34 +102,21 @@ func (ms *MenuStorageService) WithGettext(path string, lns []lang.Language) *Men
|
|||||||
return ms
|
return ms
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MenuStorageService) getOrCreateDb(ctx context.Context, existingDb db.Db, fileName string) (db.Db, error) {
|
// ensureSchemaExists creates a new schema if it does not exist
|
||||||
database, ok := ctx.Value("Database").(string)
|
func ensureSchemaExists(ctx context.Context, conn ConnData) error {
|
||||||
if !ok {
|
h, err := pgxpool.New(ctx, conn.Path())
|
||||||
return nil, fmt.Errorf("failed to select the database")
|
|
||||||
}
|
|
||||||
|
|
||||||
if existingDb != nil {
|
|
||||||
return existingDb, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var newDb db.Db
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if database == "postgres" {
|
|
||||||
newDb = postgres.NewPgDb()
|
|
||||||
connStr := buildConnStr()
|
|
||||||
err = newDb.Connect(ctx, connStr)
|
|
||||||
} else {
|
|
||||||
newDb = gdbmstorage.NewThreadGdbmDb()
|
|
||||||
storeFile := path.Join(ms.dbDir, fileName)
|
|
||||||
err = newDb.Connect(ctx, storeFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return fmt.Errorf("failed to connect to the database: %w", err)
|
||||||
|
}
|
||||||
|
defer h.Close()
|
||||||
|
|
||||||
|
query := fmt.Sprintf("CREATE SCHEMA IF NOT EXISTS %s", conn.Domain())
|
||||||
|
_, err = h.Exec(ctx, query)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create schema: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return newDb, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MenuStorageService) GetPersister(ctx context.Context) (*persist.Persister, error) {
|
func (ms *MenuStorageService) GetPersister(ctx context.Context) (*persist.Persister, error) {
|
||||||
@ -166,8 +173,8 @@ func (ms *MenuStorageService) GetStateStore(ctx context.Context) (db.Db, error)
|
|||||||
return ms.stateStore, nil
|
return ms.stateStore, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MenuStorageService) EnsureDbDir() error {
|
func (ms *MenuStorageService) ensureDbDir() error {
|
||||||
err := os.MkdirAll(ms.dbDir, 0700)
|
err := os.MkdirAll(ms.conn.String(), 0700)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("state dir create exited with error: %v\n", err)
|
return fmt.Errorf("state dir create exited with error: %v\n", err)
|
||||||
}
|
}
|
@ -1,124 +0,0 @@
|
|||||||
package testutil
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.defalsify.org/vise.git/engine"
|
|
||||||
"git.defalsify.org/vise.git/logging"
|
|
||||||
"git.defalsify.org/vise.git/resource"
|
|
||||||
"git.grassecon.net/urdt/ussd/internal/handlers"
|
|
||||||
"git.grassecon.net/urdt/ussd/internal/storage"
|
|
||||||
"git.grassecon.net/urdt/ussd/internal/testutil/testservice"
|
|
||||||
"git.grassecon.net/urdt/ussd/internal/testutil/testtag"
|
|
||||||
testdataloader "github.com/peteole/testdata-loader"
|
|
||||||
"git.grassecon.net/urdt/ussd/remote"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
baseDir = testdataloader.GetBasePath()
|
|
||||||
logg = logging.NewVanilla()
|
|
||||||
scriptDir = path.Join(baseDir, "services", "registration")
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestEngine(sessionId string) (engine.Engine, func(), chan bool) {
|
|
||||||
ctx := context.Background()
|
|
||||||
ctx = context.WithValue(ctx, "SessionId", sessionId)
|
|
||||||
ctx = context.WithValue(ctx, "Database", "gdbm")
|
|
||||||
pfp := path.Join(scriptDir, "pp.csv")
|
|
||||||
|
|
||||||
var eventChannel = make(chan bool)
|
|
||||||
|
|
||||||
cfg := engine.Config{
|
|
||||||
Root: "root",
|
|
||||||
SessionId: sessionId,
|
|
||||||
OutputSize: uint32(160),
|
|
||||||
FlagCount: uint32(128),
|
|
||||||
}
|
|
||||||
|
|
||||||
dbDir := ".test_state"
|
|
||||||
resourceDir := scriptDir
|
|
||||||
menuStorageService := storage.NewMenuStorageService(dbDir, resourceDir)
|
|
||||||
|
|
||||||
err := menuStorageService.EnsureDbDir()
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
if testtag.AccountService == nil {
|
|
||||||
testtag.AccountService = &remote.AccountService{}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch testtag.AccountService.(type) {
|
|
||||||
case *testservice.TestAccountService:
|
|
||||||
go func() {
|
|
||||||
eventChannel <- false
|
|
||||||
}()
|
|
||||||
case *remote.AccountService:
|
|
||||||
go func() {
|
|
||||||
time.Sleep(5 * time.Second) // Wait for 5 seconds
|
|
||||||
eventChannel <- true
|
|
||||||
}()
|
|
||||||
default:
|
|
||||||
panic("Unknown account service type")
|
|
||||||
}
|
|
||||||
|
|
||||||
hl, err := lhs.GetHandler(testtag.AccountService)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, err.Error())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
en := lhs.GetEngine()
|
|
||||||
en = en.WithFirst(hl.Init)
|
|
||||||
cleanFn := func() {
|
|
||||||
err := en.Finish()
|
|
||||||
if err != nil {
|
|
||||||
logg.Errorf(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
err = menuStorageService.Close()
|
|
||||||
if err != nil {
|
|
||||||
logg.Errorf(err.Error())
|
|
||||||
}
|
|
||||||
logg.Infof("testengine storage closed")
|
|
||||||
}
|
|
||||||
return en, cleanFn, eventChannel
|
|
||||||
}
|
|
209
internal/testutil/engine.go
Normal file
209
internal/testutil/engine.go
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
package testutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.defalsify.org/vise.git/engine"
|
||||||
|
"git.defalsify.org/vise.git/logging"
|
||||||
|
"git.defalsify.org/vise.git/resource"
|
||||||
|
"git.grassecon.net/urdt/ussd/config"
|
||||||
|
"git.grassecon.net/urdt/ussd/initializers"
|
||||||
|
"git.grassecon.net/urdt/ussd/internal/handlers"
|
||||||
|
"git.grassecon.net/urdt/ussd/internal/storage"
|
||||||
|
"git.grassecon.net/urdt/ussd/internal/testutil/testservice"
|
||||||
|
"git.grassecon.net/urdt/ussd/internal/testutil/testtag"
|
||||||
|
"git.grassecon.net/urdt/ussd/remote"
|
||||||
|
"github.com/jackc/pgx/v5/pgxpool"
|
||||||
|
testdataloader "github.com/peteole/testdata-loader"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
logg = logging.NewVanilla()
|
||||||
|
baseDir = testdataloader.GetBasePath()
|
||||||
|
scriptDir = path.Join(baseDir, "services", "registration")
|
||||||
|
setDbType string
|
||||||
|
setConnStr string
|
||||||
|
setDbSchema string
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
initializers.LoadEnvVariablesPath(baseDir)
|
||||||
|
config.LoadConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDatabase updates the database used by TestEngine
|
||||||
|
func SetDatabase(database, connStr, dbSchema string) {
|
||||||
|
setDbType = database
|
||||||
|
setConnStr = connStr
|
||||||
|
setDbSchema = dbSchema
|
||||||
|
}
|
||||||
|
|
||||||
|
// CleanDatabase removes all test data from the database
|
||||||
|
func CleanDatabase() {
|
||||||
|
if setDbType == "postgres" {
|
||||||
|
ctx := context.Background()
|
||||||
|
// Update the connection string with the new search path
|
||||||
|
updatedConnStr, err := updateSearchPath(setConnStr, setDbSchema)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to update search path: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dbConn, err := pgxpool.New(ctx, updatedConnStr)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to connect to database for cleanup: %v", err)
|
||||||
|
}
|
||||||
|
defer dbConn.Close()
|
||||||
|
|
||||||
|
query := fmt.Sprintf("DELETE FROM %s.kv_vise;", setDbSchema)
|
||||||
|
_, execErr := dbConn.Exec(ctx, query)
|
||||||
|
if execErr != nil {
|
||||||
|
log.Printf("Failed to cleanup table %s.kv_vise: %v", setDbSchema, execErr)
|
||||||
|
} else {
|
||||||
|
log.Printf("Successfully cleaned up table %s.kv_vise", setDbSchema)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setConnStr, _ := filepath.Abs(setConnStr)
|
||||||
|
if err := os.RemoveAll(setConnStr); err != nil {
|
||||||
|
log.Fatalf("Failed to delete state store %s: %v", setConnStr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateSearchPath updates the search_path (schema) to be used in the connection
|
||||||
|
func updateSearchPath(connStr string, newSearchPath string) (string, error) {
|
||||||
|
u, err := url.Parse(connStr)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("invalid connection string: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the query parameters
|
||||||
|
q := u.Query()
|
||||||
|
|
||||||
|
// Update or add the search_path parameter
|
||||||
|
q.Set("search_path", newSearchPath)
|
||||||
|
|
||||||
|
// Rebuild the connection string with updated parameters
|
||||||
|
u.RawQuery = q.Encode()
|
||||||
|
|
||||||
|
return u.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEngine(sessionId string) (engine.Engine, func(), chan bool) {
|
||||||
|
var err error
|
||||||
|
ctx := context.Background()
|
||||||
|
ctx = context.WithValue(ctx, "SessionId", sessionId)
|
||||||
|
pfp := path.Join(scriptDir, "pp.csv")
|
||||||
|
|
||||||
|
var eventChannel = make(chan bool)
|
||||||
|
|
||||||
|
cfg := engine.Config{
|
||||||
|
Root: "root",
|
||||||
|
SessionId: sessionId,
|
||||||
|
OutputSize: uint32(160),
|
||||||
|
FlagCount: uint32(128),
|
||||||
|
}
|
||||||
|
|
||||||
|
if setDbType == "postgres" {
|
||||||
|
setConnStr = config.DbConn
|
||||||
|
setConnStr, err = updateSearchPath(setConnStr, setDbSchema)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error:", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setConnStr, err = filepath.Abs(setConnStr)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "connstr err: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := storage.ToConnData(setConnStr)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "connstr parse err: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceDir := scriptDir
|
||||||
|
menuStorageService := storage.NewMenuStorageService(conn, resourceDir)
|
||||||
|
|
||||||
|
rs, err := menuStorageService.GetResource(ctx)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "resource error: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
pe, err := menuStorageService.GetPersister(ctx)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "persister error: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
userDataStore, err := menuStorageService.GetUserdataDb(ctx)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "userdb error: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
dbResource, ok := rs.(*resource.DbResource)
|
||||||
|
if !ok {
|
||||||
|
fmt.Fprintf(os.Stderr, "dbresource cast error")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs)
|
||||||
|
lhs.SetDataStore(&userDataStore)
|
||||||
|
lhs.SetPersister(pe)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if testtag.AccountService == nil {
|
||||||
|
testtag.AccountService = &remote.AccountService{}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch testtag.AccountService.(type) {
|
||||||
|
case *testservice.TestAccountService:
|
||||||
|
go func() {
|
||||||
|
eventChannel <- false
|
||||||
|
}()
|
||||||
|
case *remote.AccountService:
|
||||||
|
go func() {
|
||||||
|
time.Sleep(5 * time.Second) // Wait for 5 seconds
|
||||||
|
eventChannel <- true
|
||||||
|
}()
|
||||||
|
default:
|
||||||
|
panic("Unknown account service type")
|
||||||
|
}
|
||||||
|
|
||||||
|
hl, err := lhs.GetHandler(testtag.AccountService)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
en := lhs.GetEngine()
|
||||||
|
en = en.WithFirst(hl.Init)
|
||||||
|
cleanFn := func() {
|
||||||
|
err := en.Finish()
|
||||||
|
if err != nil {
|
||||||
|
logg.Errorf(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = menuStorageService.Close()
|
||||||
|
if err != nil {
|
||||||
|
logg.Errorf(err.Error())
|
||||||
|
}
|
||||||
|
logg.Infof("testengine storage closed")
|
||||||
|
}
|
||||||
|
return en, cleanFn, eventChannel
|
||||||
|
}
|
15
internal/testutil/engine_test.go
Normal file
15
internal/testutil/engine_test.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package testutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCreateEngine(t *testing.T) {
|
||||||
|
o, clean, eventC := TestEngine("foo")
|
||||||
|
defer clean()
|
||||||
|
defer func() {
|
||||||
|
<-eventC
|
||||||
|
close(eventC)
|
||||||
|
}()
|
||||||
|
_ = o
|
||||||
|
}
|
@ -54,7 +54,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"input": "1235",
|
"input": "1235",
|
||||||
"expectedContent": "Incorrect PIN\n1:Retry\n9:Quit"
|
"expectedContent": "Incorrect PIN. You have: 2 remaining attempt(s).\n1:Retry\n9:Quit"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"input": "1",
|
"input": "1",
|
||||||
@ -95,7 +95,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"input": "1235",
|
"input": "1235",
|
||||||
"expectedContent": "Incorrect PIN\n1:Retry\n9:Quit"
|
"expectedContent": "Incorrect PIN. You have: 2 remaining attempt(s).\n1:Retry\n9:Quit"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"input": "1",
|
"input": "1",
|
||||||
@ -108,7 +108,6 @@
|
|||||||
{
|
{
|
||||||
"input": "0",
|
"input": "0",
|
||||||
"expectedContent": "Balances:\n1:My balance\n2:Community balance\n0:Back"
|
"expectedContent": "Balances:\n1:My balance\n2:Community balance\n0:Back"
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"input": "0",
|
"input": "0",
|
||||||
@ -141,7 +140,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"input": "1235",
|
"input": "1235",
|
||||||
"expectedContent": "Incorrect PIN\n1:Retry\n9:Quit"
|
"expectedContent": "Incorrect PIN. You have: 2 remaining attempt(s).\n1:Retry\n9:Quit"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"input": "1",
|
"input": "1",
|
||||||
@ -154,7 +153,6 @@
|
|||||||
{
|
{
|
||||||
"input": "0",
|
"input": "0",
|
||||||
"expectedContent": "Balances:\n1:My balance\n2:Community balance\n0:Back"
|
"expectedContent": "Balances:\n1:My balance\n2:Community balance\n0:Back"
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"input": "0",
|
"input": "0",
|
||||||
@ -258,7 +256,6 @@
|
|||||||
"input": "0",
|
"input": "0",
|
||||||
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
|
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
|
||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -444,9 +441,3 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -17,13 +16,15 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
testData = driver.ReadData()
|
testData = driver.ReadData()
|
||||||
testStore = ".test_state"
|
|
||||||
sessionID string
|
sessionID string
|
||||||
src = rand.NewSource(42)
|
src = rand.NewSource(42)
|
||||||
g = rand.New(src)
|
g = rand.New(src)
|
||||||
)
|
)
|
||||||
|
|
||||||
var groupTestFile = flag.String("test-file", "group_test.json", "The test file to use for running the group tests")
|
var groupTestFile = flag.String("test-file", "group_test.json", "The test file to use for running the group tests")
|
||||||
|
var database = flag.String("db", "gdbm", "Specify the database (gdbm or postgres)")
|
||||||
|
var connStr = flag.String("conn", ".test_state", "connection string")
|
||||||
|
var dbSchema = flag.String("schema", "test", "Specify the database schema (default test)")
|
||||||
|
|
||||||
func GenerateSessionId() string {
|
func GenerateSessionId() string {
|
||||||
uu := uuid.NewGenWithOptions(uuid.WithRandomReader(g))
|
uu := uuid.NewGenWithOptions(uuid.WithRandomReader(g))
|
||||||
@ -79,12 +80,15 @@ func extractSendAmount(response []byte) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
// Parse the flags
|
||||||
|
flag.Parse()
|
||||||
sessionID = GenerateSessionId()
|
sessionID = GenerateSessionId()
|
||||||
defer func() {
|
// set the db
|
||||||
if err := os.RemoveAll(testStore); err != nil {
|
testutil.SetDatabase(*database, *connStr, *dbSchema)
|
||||||
log.Fatalf("Failed to delete state store %s: %v", testStore, err)
|
|
||||||
}
|
// Cleanup the db after tests
|
||||||
}()
|
defer testutil.CleanDatabase()
|
||||||
|
|
||||||
m.Run()
|
m.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +125,6 @@ func TestAccountCreationSuccessful(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
<-eventChannel
|
<-eventChannel
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAccountRegistrationRejectTerms(t *testing.T) {
|
func TestAccountRegistrationRejectTerms(t *testing.T) {
|
||||||
|
2
services/registration/blocked_account.vis
Normal file
2
services/registration/blocked_account.vis
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
LOAD show_blocked_account 0
|
||||||
|
HALT
|
@ -1 +1 @@
|
|||||||
Incorrect PIN
|
Incorrect PIN. You have: {{.reset_incorrect}} remaining attempt(s).
|
@ -1,5 +1,7 @@
|
|||||||
LOAD reset_incorrect 0
|
LOAD reset_incorrect 0
|
||||||
RELOAD reset_incorrect
|
RELOAD reset_incorrect
|
||||||
|
MAP reset_incorrect
|
||||||
|
CATCH blocked_account flag_account_blocked 1
|
||||||
MOUT retry 1
|
MOUT retry 1
|
||||||
MOUT quit 9
|
MOUT quit 9
|
||||||
HALT
|
HALT
|
||||||
|
@ -1 +1 @@
|
|||||||
PIN ulioeka sio sahihi
|
PIN ulioeka sio sahihi, una majaribio: {{.reset_incorrect}} yaliyobaki
|
@ -10,6 +10,9 @@ msgstr "Asante kwa kutumia huduma ya Sarafu. Kwaheri!"
|
|||||||
msgid "For more help, please call: 0757628885"
|
msgid "For more help, please call: 0757628885"
|
||||||
msgstr "Kwa usaidizi zaidi, piga: 0757628885"
|
msgstr "Kwa usaidizi zaidi, piga: 0757628885"
|
||||||
|
|
||||||
|
msgid "Your account has been locked. For help on how to unblock your account, contact support at: 0757628885"
|
||||||
|
msgstr "Akaunti yako imefungwa. Kwa usaidizi wa jinsi ya kufungua akaunti yako, wasiliana na usaidizi kwa: 0757628885"
|
||||||
|
|
||||||
msgid "Balance: %s\n"
|
msgid "Balance: %s\n"
|
||||||
msgstr "Salio: %s\n"
|
msgstr "Salio: %s\n"
|
||||||
|
|
||||||
|
@ -28,3 +28,5 @@ flag,flag_gender_set,34,this is set when the gender of the profile is set
|
|||||||
flag,flag_location_set,35,this is set when the location of the profile is set
|
flag,flag_location_set,35,this is set when the location of the profile is set
|
||||||
flag,flag_offerings_set,36,this is set when the offerings of the profile is set
|
flag,flag_offerings_set,36,this is set when the offerings of the profile is set
|
||||||
flag,flag_back_set,37,this is set when it is a back navigation
|
flag,flag_back_set,37,this is set when it is a back navigation
|
||||||
|
flag,flag_account_blocked,38,this is set when an account has been blocked after the allowed incorrect PIN attempts have been exceeded
|
||||||
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
|||||||
|
CATCH blocked_account flag_account_blocked 1
|
||||||
CATCH select_language flag_language_set 0
|
CATCH select_language flag_language_set 0
|
||||||
CATCH terms flag_account_created 0
|
CATCH terms flag_account_created 0
|
||||||
LOAD check_account_status 0
|
LOAD check_account_status 0
|
||||||
|
Loading…
Reference in New Issue
Block a user