Merge pull request 'lash/admin-tool' (#8) from lash/admin-tool into master

Reviewed-on: #8
This commit is contained in:
lash 2025-01-17 10:02:04 +01:00
commit 71ff251d51
9 changed files with 246 additions and 226 deletions

View File

@ -1,7 +0,0 @@
{
"admins": [
{
"phonenumber" : "<replace with any admin number to test with >"
}
]
}

View File

@ -1,47 +0,0 @@
package commands
import (
"context"
"encoding/json"
"os"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store"
)
var (
logg = logging.NewVanilla().WithDomain("adminstore")
)
type Admin struct {
PhoneNumber string `json:"phonenumber"`
}
type Config struct {
Admins []Admin `json:"admins"`
}
func Seed(ctx context.Context) error {
var config Config
adminstore, err := store.NewAdminStore(ctx, "../admin_numbers")
store := adminstore.FsStore
if err != nil {
return err
}
defer store.Close()
data, err := os.ReadFile("admin_numbers.json")
if err != nil {
return err
}
if err := json.Unmarshal(data, &config); err != nil {
return err
}
for _, admin := range config.Admins {
err := store.Put(ctx, []byte(admin.PhoneNumber), []byte("1"))
if err != nil {
logg.Printf(logging.LVL_DEBUG, "Failed to insert admin number", admin.PhoneNumber)
return err
}
}
return nil
}

View File

@ -2,16 +2,72 @@ package main
import ( import (
"context" "context"
"log" "flag"
"fmt"
"os"
"path"
"git.grassecon.net/grassrootseconomics/sarafu-vise/devtools/admin/commands" "git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
"git.grassecon.net/grassrootseconomics/sarafu-vise/internal/cmd"
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers/application"
)
var (
logg = logging.NewVanilla().WithContextKey("SessionId")
scriptDir = path.Join("services", "registration")
) )
func main() { func main() {
ctx := context.Background() config.LoadConfig()
err := commands.Seed(ctx)
var sessionId string
var connStr string
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
flag.StringVar(&connStr, "c", "", "connection string")
flag.Parse()
if connStr == "" {
connStr = config.DbConn()
}
connData, err := storage.ToConnData(connStr)
if err != nil { if err != nil {
log.Fatalf("Failed to initialize a list of admins with error %s", err) fmt.Fprintf(os.Stderr, "connstr err: %v\n", err)
os.Exit(1)
}
ctx := context.Background()
ctx = context.WithValue(ctx, "SessionId", sessionId)
pfp := path.Join(scriptDir, "pp.csv")
flagParser, err := application.NewFlagManager(pfp)
if err != nil {
fmt.Fprintf(os.Stderr, "flagparser fail: %v\n", err)
os.Exit(1)
}
x := cmd.NewCmd(connData, sessionId, flagParser)
err = x.Parse(flag.Args())
if err != nil {
fmt.Fprintf(os.Stderr, "cmd parse fail: %v\n", err)
os.Exit(1)
}
logg.Infof("start command", "conn", connData, "subcmd", x)
menuStorageService := storage.NewMenuStorageService(connData, "")
if err != nil {
fmt.Fprintf(os.Stderr, "menu storage service error: %v\n", err)
os.Exit(1)
}
err = x.Exec(ctx, menuStorageService)
if err != nil {
fmt.Fprintf(os.Stderr, "cmd exec error: %v\n", err)
os.Exit(1)
} }
} }

View File

@ -37,9 +37,10 @@ var (
translationDir = path.Join(scriptDir, "locale") translationDir = path.Join(scriptDir, "locale")
) )
// TODO: this is only in use in testing, should be moved to test domain and/or replaced by asm.FlagParser
// FlagManager handles centralized flag management // FlagManager handles centralized flag management
type FlagManager struct { type FlagManager struct {
parser *asm.FlagParser *asm.FlagParser
} }
// NewFlagManager creates a new FlagManager instance // NewFlagManager creates a new FlagManager instance
@ -51,13 +52,17 @@ func NewFlagManager(csvPath string) (*FlagManager, error) {
} }
return &FlagManager{ return &FlagManager{
parser: parser, FlagParser: parser,
}, nil }, nil
} }
func (fm *FlagManager) SetDebug() {
fm.FlagParser = fm.FlagParser.WithDebug()
}
// GetFlag retrieves a flag value by its label // GetFlag retrieves a flag value by its label
func (fm *FlagManager) GetFlag(label string) (uint32, error) { func (fm *FlagManager) GetFlag(label string) (uint32, error) {
return fm.parser.GetFlag(label) return fm.FlagParser.GetFlag(label)
} }
type MenuHandlers struct { type MenuHandlers struct {
@ -65,8 +70,7 @@ type MenuHandlers struct {
st *state.State st *state.State
ca cache.Memory ca cache.Memory
userdataStore store.DataStore userdataStore store.DataStore
adminstore *store.AdminStore flagManager *FlagManager
flagManager *asm.FlagParser
accountService remote.AccountService accountService remote.AccountService
prefixDb storedb.PrefixDb prefixDb storedb.PrefixDb
profile *profile.Profile profile *profile.Profile
@ -74,7 +78,7 @@ type MenuHandlers struct {
} }
// NewHandlers creates a new instance of the Handlers struct with the provided dependencies. // NewHandlers creates a new instance of the Handlers struct with the provided dependencies.
func NewMenuHandlers(appFlags *asm.FlagParser, userdataStore db.Db, adminstore *store.AdminStore, accountService remote.AccountService, replaceSeparatorFunc func(string) string) (*MenuHandlers, error) { func NewMenuHandlers(appFlags *FlagManager, userdataStore db.Db, accountService remote.AccountService, replaceSeparatorFunc func(string) string) (*MenuHandlers, error) {
if userdataStore == nil { if userdataStore == nil {
return nil, fmt.Errorf("cannot create handler with nil userdata store") return nil, fmt.Errorf("cannot create handler with nil userdata store")
} }
@ -89,7 +93,6 @@ func NewMenuHandlers(appFlags *asm.FlagParser, userdataStore db.Db, adminstore *
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: userDb, userdataStore: userDb,
flagManager: appFlags, flagManager: appFlags,
adminstore: adminstore,
accountService: accountService, accountService: accountService,
prefixDb: prefixDb, prefixDb: prefixDb,
profile: &profile.Profile{Max: 6}, profile: &profile.Profile{Max: 6},
@ -133,15 +136,6 @@ func (h *MenuHandlers) Init(ctx context.Context, sym string, input []byte) (reso
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
} }
flag_admin_privilege, _ := h.flagManager.GetFlag("flag_admin_privilege")
isAdmin, _ := h.adminstore.IsAdmin(sessionId)
if isAdmin {
r.FlagSet = append(r.FlagSet, flag_admin_privilege)
} else {
r.FlagReset = append(r.FlagReset, flag_admin_privilege)
}
if h.st == nil || h.ca == nil { if h.st == nil || h.ca == nil {
logg.ErrorCtxf(ctx, "perister fail in handler", "state", h.st, "cache", h.ca) logg.ErrorCtxf(ctx, "perister fail in handler", "state", h.st, "cache", h.ca)
return r, fmt.Errorf("cannot get state and memory for handler") return r, fmt.Errorf("cannot get state and memory for handler")

View File

@ -14,11 +14,11 @@ 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.defalsify.org/vise.git/state" "git.defalsify.org/vise.git/state"
"git.grassecon.net/grassrootseconomics/sarafu-api/models"
"git.grassecon.net/grassrootseconomics/sarafu-api/testutil/testservice"
"git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store"
"git.grassecon.net/grassrootseconomics/common/pin" "git.grassecon.net/grassrootseconomics/common/pin"
"git.grassecon.net/grassrootseconomics/sarafu-api/models"
"git.grassecon.net/grassrootseconomics/sarafu-api/testutil/mocks"
"git.grassecon.net/grassrootseconomics/sarafu-api/testutil/testservice"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
"github.com/alecthomas/assert/v2" "github.com/alecthomas/assert/v2"
@ -84,7 +84,7 @@ func TestNewMenuHandlers(t *testing.T) {
// Test case for valid UserDataStore // Test case for valid UserDataStore
t.Run("Valid UserDataStore", func(t *testing.T) { t.Run("Valid UserDataStore", func(t *testing.T) {
handlers, err := NewMenuHandlers(fm.parser, store, nil, &accountService, mockReplaceSeparator) handlers, err := NewMenuHandlers(fm, store, &accountService, mockReplaceSeparator)
if err != nil { if err != nil {
t.Fatalf("expected no error, got %v", err) t.Fatalf("expected no error, got %v", err)
} }
@ -108,7 +108,7 @@ func TestNewMenuHandlers(t *testing.T) {
// Test case for nil UserDataStore // Test case for nil UserDataStore
t.Run("Nil UserDataStore", func(t *testing.T) { t.Run("Nil UserDataStore", func(t *testing.T) {
handlers, err := NewMenuHandlers(fm.parser, nil, nil, &accountService, mockReplaceSeparator) handlers, err := NewMenuHandlers(fm, nil, &accountService, mockReplaceSeparator)
if err == nil { if err == nil {
t.Fatal("expected an error, got none") t.Fatal("expected an error, got none")
} }
@ -132,16 +132,9 @@ func TestInit(t *testing.T) {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
adminstore, err := store.NewAdminStore(ctx, "admin_numbers")
if err != nil {
t.Fatal(err.Error())
}
st := state.NewState(128) st := state.NewState(128)
ca := cache.NewCache() ca := cache.NewCache()
flag_admin_privilege, _ := fm.GetFlag("flag_admin_privilege")
tests := []struct { tests := []struct {
name string name string
setup func() (*MenuHandlers, context.Context) setup func() (*MenuHandlers, context.Context)
@ -161,49 +154,40 @@ func TestInit(t *testing.T) {
setup: func() (*MenuHandlers, context.Context) { setup: func() (*MenuHandlers, context.Context) {
pe := persist.NewPersister(testStore).WithSession(sessionId).WithContent(st, ca) pe := persist.NewPersister(testStore).WithSession(sessionId).WithContent(st, ca)
h := &MenuHandlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm,
adminstore: adminstore,
pe: pe, pe: pe,
} }
return h, context.WithValue(ctx, "SessionId", sessionId) return h, context.WithValue(ctx, "SessionId", sessionId)
}, },
input: []byte("1"), input: []byte("1"),
expectedResult: resource.Result{ expectedResult: resource.Result{},
FlagReset: []uint32{flag_admin_privilege},
},
}, },
{ {
name: "Non-admin session initialization", name: "Non-admin session initialization",
setup: func() (*MenuHandlers, context.Context) { setup: func() (*MenuHandlers, context.Context) {
pe := persist.NewPersister(testStore).WithSession("0712345678").WithContent(st, ca) pe := persist.NewPersister(testStore).WithSession("0712345678").WithContent(st, ca)
h := &MenuHandlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm,
adminstore: adminstore,
pe: pe, pe: pe,
} }
return h, context.WithValue(context.Background(), "SessionId", "0712345678") return h, context.WithValue(context.Background(), "SessionId", "0712345678")
}, },
input: []byte("1"), input: []byte("1"),
expectedResult: resource.Result{ expectedResult: resource.Result{},
FlagReset: []uint32{flag_admin_privilege},
},
}, },
{ {
name: "Move to top node on empty input", name: "Move to top node on empty input",
setup: func() (*MenuHandlers, context.Context) { setup: func() (*MenuHandlers, context.Context) {
pe := persist.NewPersister(testStore).WithSession(sessionId).WithContent(st, ca) pe := persist.NewPersister(testStore).WithSession(sessionId).WithContent(st, ca)
h := &MenuHandlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm,
adminstore: adminstore,
pe: pe, pe: pe,
} }
st.Code = []byte("some pending bytecode") st.Code = []byte("some pending bytecode")
return h, context.WithValue(ctx, "SessionId", sessionId) return h, context.WithValue(ctx, "SessionId", sessionId)
}, },
input: []byte(""), input: []byte(""),
expectedResult: resource.Result{ expectedResult: resource.Result{},
FlagReset: []uint32{flag_admin_privilege},
},
}, },
} }
@ -256,7 +240,7 @@ func TestCreateAccount(t *testing.T) {
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm,
} }
mockAccountService.On("CreateAccount").Return(tt.serverResponse, nil) mockAccountService.On("CreateAccount").Return(tt.serverResponse, nil)
@ -320,7 +304,7 @@ func TestSaveFirstname(t *testing.T) {
// Create the MenuHandlers instance with the mock store // Create the MenuHandlers instance with the mock store
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
flagManager: fm.parser, flagManager: fm,
st: mockState, st: mockState,
} }
@ -365,7 +349,7 @@ func TestSaveFamilyname(t *testing.T) {
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
st: mockState, st: mockState,
flagManager: fm.parser, flagManager: fm,
} }
// Call the method // Call the method
@ -408,7 +392,7 @@ func TestSaveYoB(t *testing.T) {
// Create the MenuHandlers instance with the mock store // Create the MenuHandlers instance with the mock store
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
flagManager: fm.parser, flagManager: fm,
st: mockState, st: mockState,
} }
@ -452,7 +436,7 @@ func TestSaveLocation(t *testing.T) {
// Create the MenuHandlers instance with the mock store // Create the MenuHandlers instance with the mock store
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
flagManager: fm.parser, flagManager: fm,
st: mockState, st: mockState,
} }
@ -496,7 +480,7 @@ func TestSaveOfferings(t *testing.T) {
// Create the MenuHandlers instance with the mock store // Create the MenuHandlers instance with the mock store
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
flagManager: fm.parser, flagManager: fm,
st: mockState, st: mockState,
} }
@ -564,7 +548,7 @@ func TestSaveGender(t *testing.T) {
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
st: mockState, st: mockState,
flagManager: fm.parser, flagManager: fm,
} }
expectedResult := resource.Result{} expectedResult := resource.Result{}
@ -595,11 +579,11 @@ func TestSaveTemporaryPin(t *testing.T) {
log.Fatal(err) log.Fatal(err)
} }
flag_incorrect_pin, _ := fm.parser.GetFlag("flag_incorrect_pin") flag_incorrect_pin, _ := fm.GetFlag("flag_incorrect_pin")
// Create the MenuHandlers instance with the mock flag manager // Create the MenuHandlers instance with the mock flag manager
h := &MenuHandlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm,
userdataStore: store, userdataStore: store,
} }
@ -812,7 +796,7 @@ func TestSetLanguage(t *testing.T) {
// Create the MenuHandlers instance with the mock flag manager // Create the MenuHandlers instance with the mock flag manager
h := &MenuHandlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm,
userdataStore: store, userdataStore: store,
st: mockState, st: mockState,
} }
@ -846,7 +830,7 @@ func TestResetAllowUpdate(t *testing.T) {
log.Fatal(err) log.Fatal(err)
} }
flag_allow_update, _ := fm.parser.GetFlag("flag_allow_update") flag_allow_update, _ := fm.GetFlag("flag_allow_update")
// Define test cases // Define test cases
tests := []struct { tests := []struct {
@ -867,7 +851,7 @@ func TestResetAllowUpdate(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
// Create the MenuHandlers instance with the mock flag manager // Create the MenuHandlers instance with the mock flag manager
h := &MenuHandlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm,
} }
// Call the method // Call the method
@ -888,7 +872,7 @@ func TestResetAccountAuthorized(t *testing.T) {
log.Fatal(err) log.Fatal(err)
} }
flag_account_authorized, _ := fm.parser.GetFlag("flag_account_authorized") flag_account_authorized, _ := fm.GetFlag("flag_account_authorized")
// Define test cases // Define test cases
tests := []struct { tests := []struct {
@ -909,7 +893,7 @@ func TestResetAccountAuthorized(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
// Create the MenuHandlers instance with the mock flag manager // Create the MenuHandlers instance with the mock flag manager
h := &MenuHandlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm,
} }
// Call the method // Call the method
@ -933,8 +917,8 @@ func TestIncorrectPinReset(t *testing.T) {
log.Fatal(err) log.Fatal(err)
} }
flag_incorrect_pin, _ := fm.parser.GetFlag("flag_incorrect_pin") flag_incorrect_pin, _ := fm.GetFlag("flag_incorrect_pin")
flag_account_blocked, _ := fm.parser.GetFlag("flag_account_blocked") flag_account_blocked, _ := fm.GetFlag("flag_account_blocked")
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
@ -992,7 +976,7 @@ func TestIncorrectPinReset(t *testing.T) {
// Create the MenuHandlers instance with the mock flag manager // Create the MenuHandlers instance with the mock flag manager
h := &MenuHandlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm,
userdataStore: store, userdataStore: store,
} }
@ -1014,7 +998,7 @@ func TestResetIncorrectYob(t *testing.T) {
log.Fatal(err) log.Fatal(err)
} }
flag_incorrect_date_format, _ := fm.parser.GetFlag("flag_incorrect_date_format") flag_incorrect_date_format, _ := fm.GetFlag("flag_incorrect_date_format")
// Define test cases // Define test cases
tests := []struct { tests := []struct {
@ -1035,7 +1019,7 @@ func TestResetIncorrectYob(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
// Create the MenuHandlers instance with the mock flag manager // Create the MenuHandlers instance with the mock flag manager
h := &MenuHandlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm,
} }
// Call the method // Call the method
@ -1073,7 +1057,7 @@ func TestAuthorize(t *testing.T) {
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm,
st: mockState, st: mockState,
} }
@ -1141,12 +1125,12 @@ func TestVerifyYob(t *testing.T) {
// Create required mocks // Create required mocks
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
mockState := state.NewState(16) mockState := state.NewState(16)
flag_incorrect_date_format, _ := fm.parser.GetFlag("flag_incorrect_date_format") flag_incorrect_date_format, _ := fm.GetFlag("flag_incorrect_date_format")
ctx := context.WithValue(context.Background(), "SessionId", sessionId) ctx := context.WithValue(context.Background(), "SessionId", sessionId)
h := &MenuHandlers{ h := &MenuHandlers{
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm,
st: mockState, st: mockState,
} }
@ -1206,14 +1190,14 @@ func TestVerifyCreatePin(t *testing.T) {
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
mockState := state.NewState(16) mockState := state.NewState(16)
flag_valid_pin, _ := fm.parser.GetFlag("flag_valid_pin") flag_valid_pin, _ := fm.GetFlag("flag_valid_pin")
flag_pin_mismatch, _ := fm.parser.GetFlag("flag_pin_mismatch") flag_pin_mismatch, _ := fm.GetFlag("flag_pin_mismatch")
flag_pin_set, _ := fm.parser.GetFlag("flag_pin_set") flag_pin_set, _ := fm.GetFlag("flag_pin_set")
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm,
st: mockState, st: mockState,
} }
@ -1307,7 +1291,7 @@ func TestCheckAccountStatus(t *testing.T) {
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm,
} }
err = store.WriteEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY, []byte(tt.publicKey)) err = store.WriteEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY, []byte(tt.publicKey))
@ -1347,7 +1331,7 @@ func TestTransactionReset(t *testing.T) {
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm,
} }
tests := []struct { tests := []struct {
name string name string
@ -1387,14 +1371,14 @@ func TestResetTransactionAmount(t *testing.T) {
t.Logf(err.Error()) t.Logf(err.Error())
} }
flag_invalid_amount, _ := fm.parser.GetFlag("flag_invalid_amount") flag_invalid_amount, _ := fm.GetFlag("flag_invalid_amount")
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm,
} }
tests := []struct { tests := []struct {
@ -1431,14 +1415,14 @@ func TestInitiateTransaction(t *testing.T) {
if err != nil { if err != nil {
t.Logf(err.Error()) t.Logf(err.Error())
} }
account_authorized_flag, _ := fm.parser.GetFlag("flag_account_authorized") account_authorized_flag, _ := fm.GetFlag("flag_account_authorized")
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm,
} }
tests := []struct { tests := []struct {
@ -1524,7 +1508,7 @@ func TestQuit(t *testing.T) {
if err != nil { if err != nil {
t.Logf(err.Error()) t.Logf(err.Error())
} }
flag_account_authorized, _ := fm.parser.GetFlag("flag_account_authorized") flag_account_authorized, _ := fm.GetFlag("flag_account_authorized")
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
@ -1534,7 +1518,7 @@ func TestQuit(t *testing.T) {
h := &MenuHandlers{ h := &MenuHandlers{
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm,
} }
tests := []struct { tests := []struct {
name string name string
@ -1577,14 +1561,14 @@ func TestValidateAmount(t *testing.T) {
ctx, store := InitializeTestStore(t) ctx, store := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
flag_invalid_amount, _ := fm.parser.GetFlag("flag_invalid_amount") flag_invalid_amount, _ := fm.GetFlag("flag_invalid_amount")
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm,
} }
tests := []struct { tests := []struct {
name string name string
@ -1651,8 +1635,8 @@ func TestValidateRecipient(t *testing.T) {
ctx, store := InitializeTestStore(t) ctx, store := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
flag_invalid_recipient, _ := fm.parser.GetFlag("flag_invalid_recipient") flag_invalid_recipient, _ := fm.GetFlag("flag_invalid_recipient")
flag_invalid_recipient_with_invite, _ := fm.parser.GetFlag("flag_invalid_recipient_with_invite") flag_invalid_recipient_with_invite, _ := fm.GetFlag("flag_invalid_recipient_with_invite")
// Define test cases // Define test cases
tests := []struct { tests := []struct {
@ -1704,7 +1688,7 @@ func TestValidateRecipient(t *testing.T) {
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
// Create the MenuHandlers instance // Create the MenuHandlers instance
h := &MenuHandlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm,
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
} }
@ -1867,10 +1851,10 @@ func TestVerifyNewPin(t *testing.T) {
fm, _ := NewFlagManager(flagsPath) fm, _ := NewFlagManager(flagsPath)
flag_valid_pin, _ := fm.parser.GetFlag("flag_valid_pin") flag_valid_pin, _ := fm.GetFlag("flag_valid_pin")
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
h := &MenuHandlers{ h := &MenuHandlers{
flagManager: fm.parser, flagManager: fm,
accountService: mockAccountService, accountService: mockAccountService,
} }
ctx := context.WithValue(context.Background(), "SessionId", sessionId) ctx := context.WithValue(context.Background(), "SessionId", sessionId)
@ -1913,11 +1897,11 @@ func TestConfirmPin(t *testing.T) {
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId", sessionId)
fm, _ := NewFlagManager(flagsPath) fm, _ := NewFlagManager(flagsPath)
flag_pin_mismatch, _ := fm.parser.GetFlag("flag_pin_mismatch") flag_pin_mismatch, _ := fm.GetFlag("flag_pin_mismatch")
mockAccountService := new(mocks.MockAccountService) mockAccountService := new(mocks.MockAccountService)
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
flagManager: fm.parser, flagManager: fm,
accountService: mockAccountService, accountService: mockAccountService,
} }
@ -2047,7 +2031,7 @@ func TestSetDefaultVoucher(t *testing.T) {
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
accountService: mockAccountService, accountService: mockAccountService,
flagManager: fm.parser, flagManager: fm,
} }
err := store.WriteEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY, []byte(publicKey)) err := store.WriteEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY, []byte(publicKey))
@ -2155,7 +2139,7 @@ func TestViewVoucher(t *testing.T) {
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
flagManager: fm.parser, flagManager: fm,
prefixDb: spdb, prefixDb: spdb,
} }
@ -2228,7 +2212,7 @@ func TestGetVoucherDetails(t *testing.T) {
h := &MenuHandlers{ h := &MenuHandlers{
userdataStore: store, userdataStore: store,
flagManager: fm.parser, flagManager: fm,
accountService: mockAccountService, accountService: mockAccountService,
} }
err = store.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_ADDRESS, []byte(tokA_AAddress)) err = store.WriteEntry(ctx, sessionId, storedb.DATA_ACTIVE_ADDRESS, []byte(tokA_AAddress))

View File

@ -4,7 +4,6 @@ import (
"context" "context"
"strings" "strings"
"git.defalsify.org/vise.git/asm"
"git.defalsify.org/vise.git/db" "git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/engine" "git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/persist"
@ -12,47 +11,35 @@ import (
"git.grassecon.net/grassrootseconomics/sarafu-api/remote" "git.grassecon.net/grassrootseconomics/sarafu-api/remote"
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers/application" "git.grassecon.net/grassrootseconomics/sarafu-vise/handlers/application"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store"
) )
type HandlerService interface { type HandlerService interface {
GetHandler() (*application.MenuHandlers, error) GetHandler() (*application.MenuHandlers, 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 { type LocalHandlerService struct {
Parser *asm.FlagParser Parser *application.FlagManager
DbRs *resource.DbResource DbRs *resource.DbResource
Pe *persist.Persister Pe *persist.Persister
UserdataStore *db.Db UserdataStore *db.Db
AdminStore *store.AdminStore
Cfg engine.Config Cfg engine.Config
Rs resource.Resource Rs resource.Resource
} }
func NewLocalHandlerService(ctx context.Context, fp string, debug bool, dbResource *resource.DbResource, cfg engine.Config, rs resource.Resource) (*LocalHandlerService, error) { 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) parser, err := application.NewFlagManager(fp)
if err != nil { if err != nil {
return nil, err return nil, err
} }
adminstore, err := store.NewAdminStore(ctx, "admin_numbers") if debug {
if err != nil { parser.SetDebug()
return nil, err
} }
return &LocalHandlerService{ return &LocalHandlerService{
Parser: parser, Parser: parser,
DbRs: dbResource, DbRs: dbResource,
AdminStore: adminstore, Cfg: cfg,
Cfg: cfg, Rs: rs,
Rs: rs,
}, nil }, nil
} }
@ -69,7 +56,7 @@ func (ls *LocalHandlerService) GetHandler(accountService remote.AccountService)
return strings.ReplaceAll(input, ":", ls.Cfg.MenuSeparator) return strings.ReplaceAll(input, ":", ls.Cfg.MenuSeparator)
} }
appHandlers, err := application.NewMenuHandlers(ls.Parser, *ls.UserdataStore, ls.AdminStore, accountService, replaceSeparatorFunc) appHandlers, err := application.NewMenuHandlers(ls.Parser, *ls.UserdataStore, accountService, replaceSeparatorFunc)
if err != nil { if err != nil {
return nil, err return nil, err
} }

99
internal/cmd/cmd.go Normal file
View File

@ -0,0 +1,99 @@
package cmd
import (
"context"
"fmt"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers/application"
)
var (
logg = logging.NewVanilla().WithDomain("cmd").WithContextKey("SessionId")
)
type Cmd struct {
sessionId string
conn storage.ConnData
flagParser *application.FlagManager
cmd int
enable bool
exec func(ctx context.Context, ss storage.StorageService) error
}
func NewCmd(conn storage.ConnData, sessionId string, flagParser *application.FlagManager) *Cmd {
return &Cmd{
conn: conn,
sessionId: sessionId,
flagParser: flagParser,
}
}
func (c *Cmd) Exec(ctx context.Context, ss storage.StorageService) error {
return c.exec(ctx, ss)
}
func (c *Cmd) execAdmin(ctx context.Context, ss storage.StorageService) error {
pe, err := ss.GetPersister(ctx)
if err != nil {
return err
}
err = pe.Load(c.sessionId)
if err != nil {
return err
}
defer func() {
err := pe.Save(c.sessionId)
if err != nil {
logg.ErrorCtxf(ctx, "failed persister save: %v", err)
}
}()
st := pe.GetState()
flag, err := c.flagParser.GetFlag("flag_admin_privilege")
if err != nil {
return err
}
if c.enable {
logg.InfoCtxf(ctx, "setting admin flag", "flag", flag)
st.SetFlag(flag)
} else {
st.ResetFlag(flag)
}
return nil
}
func (c *Cmd) parseCmdAdmin(cmd string, param string, more []string) (bool, error) {
if cmd == "admin" {
if param == "1" {
c.enable = true
} else if param != "0" {
return false, fmt.Errorf("invalid parameter: %v", param)
}
c.exec = c.execAdmin
return true, nil
}
return false, nil
}
func (c *Cmd) Parse(args []string) error {
if len(args) < 2 {
return fmt.Errorf("Wrong number of arguments: %v", args)
}
cmd := args[0]
param := args[1]
args = args[2:]
r, err := c.parseCmdAdmin(cmd, param, args)
if err != nil {
return err
}
if r {
return nil
}
return fmt.Errorf("unknown subcommand: %s", cmd)
}

View File

@ -1,51 +0,0 @@
package store
import (
"context"
"git.defalsify.org/vise.git/db"
fsdb "git.defalsify.org/vise.git/db/fs"
"git.defalsify.org/vise.git/logging"
)
var (
logg = logging.NewVanilla().WithDomain("adminstore")
)
type AdminStore struct {
ctx context.Context
FsStore db.Db
}
func NewAdminStore(ctx context.Context, fileName string) (*AdminStore, error) {
fsStore, err := getFsStore(ctx, fileName)
if err != nil {
return nil, err
}
return &AdminStore{ctx: ctx, FsStore: fsStore}, nil
}
func getFsStore(ctx context.Context, connectStr string) (db.Db, error) {
fsStore := fsdb.NewFsDb()
err := fsStore.Connect(ctx, connectStr)
fsStore.SetPrefix(db.DATATYPE_USERDATA)
if err != nil {
return nil, err
}
return fsStore, nil
}
// Checks if the given sessionId is listed as an admin.
func (as *AdminStore) IsAdmin(sessionId string) (bool, error) {
_, err := as.FsStore.Get(as.ctx, []byte(sessionId))
if err != nil {
if db.IsNotFound(err) {
logg.Printf(logging.LVL_INFO, "Returning false because session id was not found")
return false, nil
} else {
return false, err
}
}
return true, nil
}

View File

@ -6,10 +6,15 @@ import (
"math/big" "math/big"
"strings" "strings"
"git.defalsify.org/vise.git/logging"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
) )
var (
logg = logging.NewVanilla().WithDomain("vouchers").WithContextKey("SessionId")
)
// VoucherMetadata helps organize data fields // VoucherMetadata helps organize data fields
type VoucherMetadata struct { type VoucherMetadata struct {
Symbols string Symbols string