Compare commits

..

4 Commits

Author SHA1 Message Date
lash
c4c3d6c998
Set upstream go-vise dependency version in go.mod 2024-09-07 21:14:03 +01:00
lash
4accb847b9
Successfully executed account regisration using http 2024-09-06 03:05:18 +01:00
lash
350b040a59
Add storage retrieval solution for http handler 2024-09-06 01:28:51 +01:00
lash
e6754a1e92
WIP http server harness 2024-09-06 00:40:57 +01:00
11 changed files with 1243 additions and 661 deletions

View File

@ -12,9 +12,9 @@ import (
fsdb "git.defalsify.org/vise.git/db/fs" fsdb "git.defalsify.org/vise.git/db/fs"
gdbmdb "git.defalsify.org/vise.git/db/gdbm" gdbmdb "git.defalsify.org/vise.git/db/gdbm"
"git.defalsify.org/vise.git/engine" "git.defalsify.org/vise.git/engine"
"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.defalsify.org/vise.git/logging"
"git.grassecon.net/urdt/ussd/internal/handlers/ussd" "git.grassecon.net/urdt/ussd/internal/handlers/ussd"
) )
@ -23,7 +23,7 @@ var (
scriptDir = path.Join("services", "registration") scriptDir = path.Join("services", "registration")
) )
func getParser(fp string, debug bool) (*asm.FlagParser, error) { func getFlags(fp string, debug bool) (*asm.FlagParser, error) {
flagParser := asm.NewFlagParser().WithDebug() flagParser := asm.NewFlagParser().WithDebug()
_, err := flagParser.Load(fp) _, err := flagParser.Load(fp)
if err != nil { if err != nil {
@ -113,21 +113,23 @@ func getEngine(cfg engine.Config, rs resource.Resource, pr *persist.Persister) *
func main() { func main() {
var dbDir string var dbDir string
var resourceDir string
var size uint var size uint
var sessionId string var sessionId string
var debug bool var debug bool
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(&dbDir, "dbdir", ".state", "database dir to read from")
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
flag.BoolVar(&debug, "d", false, "use engine debug output") flag.BoolVar(&debug, "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.Parse() flag.Parse()
logg.Infof("start command", "dbdir", dbDir, "outputsize", size) logg.Infof("start command", "dbdir", dbDir, "resourcedir", resourceDir, "outputsize", size)
ctx := context.Background() ctx := context.Background()
ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "SessionId",sessionId)
pfp := path.Join(scriptDir, "pp.csv") pfp := path.Join(scriptDir, "pp.csv")
flagParser, err := getParser(pfp, true) flagParser, err := getFlags(pfp, true)
if err != nil { if err != nil {
os.Exit(1) os.Exit(1)
@ -140,7 +142,7 @@ func main() {
FlagCount: uint32(16), FlagCount: uint32(16),
} }
rs, err := getResource(scriptDir, ctx) rs, err := getResource(resourceDir, 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)

1
go-vise Submodule

@ -0,0 +1 @@
Subproject commit 2bddc363f20210ab019eec29d8ba4104d147e9b7

View File

@ -29,6 +29,23 @@ var (
translationDir = path.Join(scriptDir, "locale") translationDir = path.Join(scriptDir, "locale")
) )
const (
TrackingIdKey = "TRACKINGID"
PublicKeyKey = "PUBLICKEY"
CustodialIdKey = "CUSTODIALID"
AccountPin = "ACCOUNTPIN"
AccountStatus = "ACCOUNTSTATUS"
FirstName = "FIRSTNAME"
FamilyName = "FAMILYNAME"
YearOfBirth = "YOB"
Location = "LOCATION"
Gender = "GENDER"
Offerings = "OFFERINGS"
Recipient = "RECIPIENT"
Amount = "AMOUNT"
AccountCreated = "ACCOUNTCREATED"
)
type FSData struct { type FSData struct {
Path string Path string
St *state.State St *state.State
@ -61,8 +78,9 @@ type Handlers struct {
pe *persist.Persister pe *persist.Persister
st *state.State st *state.State
ca cache.Memory ca cache.Memory
userdataStore utils.DataStore userdataStore db.Db
flagManager *asm.FlagParser flagManager *asm.FlagParser
accountFileHandler *utils.AccountFileHandler
accountService server.AccountServiceInterface accountService server.AccountServiceInterface
} }
@ -70,12 +88,10 @@ func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db) (*Handlers, erro
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")
} }
userDb := &utils.UserDataStore{
Db: userdataStore,
}
h := &Handlers{ h := &Handlers{
userdataStore: userDb, userdataStore: userdataStore,
flagManager: appFlags, flagManager: appFlags,
accountFileHandler: utils.NewAccountFileHandler(userdataStore),
accountService: &server.AccountService{}, accountService: &server.AccountService{},
} }
return h, nil return h, nil
@ -152,8 +168,7 @@ func (h *Handlers) createAccountNoExist(ctx context.Context, sessionId string, r
} }
for key, value := range data { for key, value := range data {
store := h.userdataStore err := utils.WriteEntry(ctx, h.userdataStore, sessionId, key, []byte(value))
err := store.WriteEntry(ctx, sessionId, key, []byte(value))
if err != nil { if err != nil {
return err return err
} }
@ -170,15 +185,20 @@ func (h *Handlers) createAccountNoExist(ctx context.Context, sessionId string, r
func (h *Handlers) CreateAccount(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) CreateAccount(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error var err error
sessionId, ok := ctx.Value("SessionId").(string) sessionId, ok := ctx.Value("SessionId").(string)
if !ok { if !ok {
return res, fmt.Errorf("missing session") return res, fmt.Errorf("missing session")
} }
store := h.userdataStore _, err = utils.ReadEntry(ctx, h.userdataStore, sessionId, utils.DATA_ACCOUNT_CREATED)
_, err = store.ReadEntry(ctx, sessionId, utils.DATA_ACCOUNT_CREATED)
if err != nil { if err != nil {
if db.IsNotFound(err) { if db.IsNotFound(err) {
logg.Printf(logging.LVL_INFO, "Creating an account because it doesn't exist") fmt.Println("Creating an account because it doesn't exist")
err = h.createAccountNoExist(ctx, sessionId, &res)
if err != nil {
return res, err
}
} else {
err = h.createAccountNoExist(ctx, sessionId, &res) err = h.createAccountNoExist(ctx, sessionId, &res)
if err != nil { if err != nil {
return res, err return res, err
@ -208,11 +228,12 @@ func (h *Handlers) SavePin(ctx context.Context, sym string, input []byte) (resou
} }
res.FlagReset = append(res.FlagReset, flag_incorrect_pin) res.FlagReset = append(res.FlagReset, flag_incorrect_pin)
store := h.userdataStore
err = store.WriteEntry(ctx, sessionId, utils.DATA_ACCOUNT_PIN, []byte(accountPIN)) err = utils.WriteEntry(ctx, h.userdataStore, sessionId, utils.DATA_ACCOUNT_PIN, []byte(accountPIN))
if err != nil { if err != nil {
return res, err return res, nil
} }
return res, nil return res, nil
} }
@ -257,12 +278,7 @@ func (h *Handlers) VerifyPin(ctx context.Context, sym string, input []byte) (res
return res, fmt.Errorf("missing session") return res, fmt.Errorf("missing session")
} }
//AccountPin, _ := utils.ReadEntry(ctx, h.userdataStore, sessionId, utils.DATA_ACCOUNT_PIN) AccountPin, _ := utils.ReadEntry(ctx, h.userdataStore, sessionId, utils.DATA_ACCOUNT_PIN)
store := h.userdataStore
AccountPin, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACCOUNT_PIN)
if err != nil {
return res, err
}
if bytes.Equal(input, AccountPin) { if bytes.Equal(input, AccountPin) {
res.FlagSet = []uint32{flag_valid_pin} res.FlagSet = []uint32{flag_valid_pin}
@ -285,103 +301,67 @@ func codeFromCtx(ctx context.Context) string {
return code return code
} }
// SaveFirstname updates the first name in the gdbm with the provided input. // SaveFirstname updates the first name in a JSON data file with the provided input.
func (h *Handlers) SaveFirstname(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) SaveFirstname(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
if len(input) > 0 { if len(input) > 0 {
firstName := string(input) //name := string(input)
store := h.userdataStore //key := []byte(FirstName)
err = store.WriteEntry(ctx, sessionId, utils.DATA_FIRST_NAME, []byte(firstName)) //value := []byte(name)
if err != nil { //h.db.Store(key, value, true)
return res, err
}
} }
return res, nil return res, nil
} }
// SaveFamilyname updates the family name in the gdbm with the provided input. // SaveFamilyname updates the family name in a JSON data file with the provided input.
func (h *Handlers) SaveFamilyname(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) SaveFamilyname(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
if len(input) > 0 { if len(input) > 0 {
familyName := string(input) //secondname := string(input)
store := h.userdataStore //key := []byte(FamilyName)
err = store.WriteEntry(ctx, sessionId, utils.DATA_FAMILY_NAME, []byte(familyName)) //value := []byte(secondname)
if err != nil { //h.db.Store(key, value, true)
return res, err
}
if err != nil {
return res, nil
}
} else {
return res, fmt.Errorf("a family name cannot be less than one character")
} }
return res, nil return res, nil
} }
// SaveYOB updates the Year of Birth(YOB) in the gdbm with the provided input. // SaveYOB updates the Year of Birth(YOB) in a JSON data file with the provided input.
func (h *Handlers) SaveYob(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) SaveYob(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
if len(input) == 4 {
yob := string(input) yob := string(input)
store := h.userdataStore if len(yob) == 4 {
err = store.WriteEntry(ctx, sessionId, utils.DATA_YOB, []byte(yob)) //yob := string(input)
if err != nil { //key := []byte(YearOfBirth)
return res, err //value := []byte(yob)
} //h.db.Store(key, value, true)
} }
return res, nil return res, nil
} }
// SaveLocation updates the location in the gdbm with the provided input. // SaveLocation updates the location in a JSON data file with the provided input.
func (h *Handlers) SaveLocation(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) SaveLocation(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
if len(input) > 0 { if len(input) > 0 {
location := string(input) //location := string(input)
store := h.userdataStore //key := []byte(Location)
err = store.WriteEntry(ctx, sessionId, utils.DATA_LOCATION, []byte(location)) //value := []byte(location)
if err != nil {
return res, err //h.db.Store(key, value, true)
}
} }
return res, nil return res, nil
} }
// SaveGender updates the gender in the gdbm with the provided input. // SaveGender updates the gender in a JSON data file with the provided input.
func (h *Handlers) SaveGender(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) SaveGender(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
if len(input) > 0 { if len(input) > 0 {
gender := string(input) gender := string(input)
@ -393,34 +373,23 @@ func (h *Handlers) SaveGender(ctx context.Context, sym string, input []byte) (re
case "3": case "3":
gender = "Unspecified" gender = "Unspecified"
} }
store := h.userdataStore //key := []byte(Gender)
err = store.WriteEntry(ctx, sessionId, utils.DATA_GENDER, []byte(gender)) //value := []byte(gender)
if err != nil { //h.db.Store(key, value, true)
return res, nil
} }
}
return res, nil return res, nil
} }
// SaveOfferings updates the offerings(goods and services provided by the user) in the gdbm with the provided input. // SaveOfferings updates the offerings(goods and services provided by the user) in a JSON data file with the provided input.
func (h *Handlers) SaveOfferings(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) SaveOfferings(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
if len(input) > 0 { if len(input) > 0 {
offerings := string(input) //offerings := string(input)
store := h.userdataStore //key := []byte(Offerings)
err = store.WriteEntry(ctx, sessionId, utils.DATA_OFFERINGS, []byte(offerings)) //value := []byte(offerings)
if err != nil { //h.db.Store(key, value, true)
return res, nil
} }
}
return res, nil return res, nil
} }
@ -448,16 +417,11 @@ func (h *Handlers) ResetAccountAuthorized(ctx context.Context, sym string, input
func (h *Handlers) CheckIdentifier(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) CheckIdentifier(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
sessionId, ok := ctx.Value("SessionId").(string) //publicKey, err := h.db.Fetch([]byte(PublicKeyKey))
if !ok { // if err != nil {
return res, fmt.Errorf("missing session") // return res, err
} // }
res.Content = "string(publicKey)"
store := h.userdataStore
publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY)
res.Content = string(publicKey)
return res, nil return res, nil
} }
@ -467,20 +431,14 @@ func (h *Handlers) Authorize(ctx context.Context, sym string, input []byte) (res
var res resource.Result var res resource.Result
var err error var err error
flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin")
flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized")
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
sessionId, ok := ctx.Value("SessionId").(string) sessionId, ok := ctx.Value("SessionId").(string)
if !ok { if !ok {
return res, fmt.Errorf("missing session") return res, fmt.Errorf("missing session")
} }
AccountPin, err := utils.ReadEntry(ctx, h.userdataStore, sessionId, utils.DATA_ACCOUNT_PIN)
flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin")
flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized")
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
store := h.userdataStore
AccountPin, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACCOUNT_PIN)
if err != nil {
return res, err
}
if err == nil { if err == nil {
if len(input) == 4 { if len(input) == 4 {
@ -527,22 +485,26 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b
if !ok { if !ok {
return res, fmt.Errorf("missing session") return res, fmt.Errorf("missing session")
} }
store := h.userdataStore
trackingId, err := store.ReadEntry(ctx, sessionId, utils.DATA_TRACKING_ID) trackingId, _ := utils.ReadEntry(ctx, h.userdataStore, sessionId, utils.DATA_TRACKING_ID)
if err != nil {
return res, err
}
status, err := h.accountService.CheckAccountStatus(string(trackingId)) status, err := h.accountService.CheckAccountStatus(string(trackingId))
if err != nil { if err != nil {
fmt.Println("Error checking account status:", err) fmt.Println("Error checking account status:", err)
return res, err return res, err
} }
err = store.WriteEntry(ctx, sessionId, utils.DATA_ACCOUNT_STATUS, []byte(status)) // err = h.db.Store(toBytes(AccountStatus), toBytes(status), true)
if err != nil { // if err != nil {
return res, nil // return res, nil
} // }
// err = h.db.Store(toBytes(TrackingIdKey), toBytes(status), true)
// if err != nil {
// return res, nil
// }
if status == "SUCCESS" { if status == "SUCCESS" {
res.FlagSet = append(res.FlagSet, flag_account_success) res.FlagSet = append(res.FlagSet, flag_account_success)
@ -609,16 +571,14 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) (
var res resource.Result var res resource.Result
var err error var err error
// publicKey, err := h.db.Fetch([]byte(PublicKeyKey))
sessionId, ok := ctx.Value("SessionId").(string) sessionId, ok := ctx.Value("SessionId").(string)
if !ok { if !ok {
return res, fmt.Errorf("missing session") return res, fmt.Errorf("missing session")
} }
store := h.userdataStore publicKey, _ := utils.ReadEntry(ctx, h.userdataStore, sessionId, utils.DATA_PUBLIC_KEY)
publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY)
if err != nil {
return res, err
}
balance, err := h.accountService.CheckBalance(string(publicKey)) balance, err := h.accountService.CheckBalance(string(publicKey))
if err != nil { if err != nil {
@ -632,12 +592,6 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) (
// ValidateRecipient validates that the given input is a valid phone number. // ValidateRecipient validates that the given input is a valid phone number.
func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
recipient := string(input) recipient := string(input)
@ -651,11 +605,12 @@ func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []by
return res, nil return res, nil
} }
store := h.userdataStore
err = store.WriteEntry(ctx, sessionId, utils.DATA_RECIPIENT, []byte(recipient)) // accountData["Recipient"] = recipient
if err != nil { // key := []byte(Recipient)
return res, nil // value := []byte(recipient)
}
// h.db.Store(key, value, true)
} }
return res, nil return res, nil
@ -665,25 +620,18 @@ func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []by
// as well as the invalid flags // as well as the invalid flags
func (h *Handlers) TransactionReset(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) TransactionReset(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
flag_invalid_recipient, _ := h.flagManager.GetFlag("flag_invalid_recipient") flag_invalid_recipient, _ := h.flagManager.GetFlag("flag_invalid_recipient")
flag_invalid_recipient_with_invite, _ := h.flagManager.GetFlag("flag_invalid_recipient_with_invite") flag_invalid_recipient_with_invite, _ := h.flagManager.GetFlag("flag_invalid_recipient_with_invite")
store := h.userdataStore
err = store.WriteEntry(ctx, sessionId, utils.DATA_AMOUNT, []byte(""))
if err != nil {
return res, nil
}
err = store.WriteEntry(ctx, sessionId, utils.DATA_RECIPIENT, []byte("")) // err := h.db.Delete([]byte(Amount))
if err != nil { // if err != nil && !errors.Is(err, gdbm.ErrItemNotFound) {
return res, nil // return res, err
} // }
// err = h.db.Delete([]byte(Recipient))
// if err != nil && !errors.Is(err, gdbm.ErrItemNotFound) {
// return res, err
// }
res.FlagReset = append(res.FlagReset, flag_invalid_recipient, flag_invalid_recipient_with_invite) res.FlagReset = append(res.FlagReset, flag_invalid_recipient, flag_invalid_recipient_with_invite)
@ -693,19 +641,13 @@ func (h *Handlers) TransactionReset(ctx context.Context, sym string, input []byt
// ResetTransactionAmount resets the transaction amount and invalid flag // ResetTransactionAmount resets the transaction amount and invalid flag
func (h *Handlers) ResetTransactionAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) ResetTransactionAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount") flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount")
store := h.userdataStore
err = store.WriteEntry(ctx, sessionId, utils.DATA_AMOUNT, []byte("")) // err := h.db.Delete([]byte(Amount))
if err != nil { // if err != nil && !errors.Is(err, gdbm.ErrItemNotFound) {
return res, nil // return res, err
} // }
res.FlagReset = append(res.FlagReset, flag_invalid_amount) res.FlagReset = append(res.FlagReset, flag_invalid_amount)
@ -718,14 +660,12 @@ func (h *Handlers) MaxAmount(ctx context.Context, sym string, input []byte) (res
var res resource.Result var res resource.Result
var err error var err error
sessionId, ok := ctx.Value("SessionId").(string) // publicKey, err := h.db.Fetch([]byte(PublicKeyKey))
if !ok { // if err != nil {
return res, fmt.Errorf("missing session") // return res, err
} // }
store := h.userdataStore
publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY)
balance, err := h.accountService.CheckBalance(string(publicKey)) balance, err := h.accountService.CheckBalance(string("publicKey"))
if err != nil { if err != nil {
return res, nil return res, nil
} }
@ -741,18 +681,16 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte)
var res resource.Result var res resource.Result
var err error var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount") flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount")
publicKey, _ := utils.ReadEntry(ctx, h.userdataStore, sessionId, utils.DATA_PUBLIC_KEY)
amountStr := string(input) amountStr := string(input)
// publicKey, err := h.db.Fetch([]byte(PublicKeyKey))
balanceStr, err := h.accountService.CheckBalance(string(publicKey)) // if err != nil {
// return res, err
// }
balanceStr, err := h.accountService.CheckBalance(string("publicKey"))
if err != nil { if err != nil {
return res, err return res, err
@ -792,8 +730,10 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte)
} }
res.Content = fmt.Sprintf("%.3f", inputAmount) // Format to 3 decimal places res.Content = fmt.Sprintf("%.3f", inputAmount) // Format to 3 decimal places
store := h.userdataStore // key := []byte(Amount)
err = store.WriteEntry(ctx, sessionId, utils.DATA_AMOUNT, []byte(amountStr)) // value := []byte(res.Content)
// h.db.Store(key, value, true)
if err != nil { if err != nil {
return res, err return res, err
} }
@ -801,18 +741,16 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte)
return res, nil return res, nil
} }
// GetRecipient returns the transaction recipient from the gdbm. // GetRecipient returns the transaction recipient from a JSON data file.
func (h *Handlers) GetRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) GetRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
sessionId, ok := ctx.Value("SessionId").(string) // recipient, err := h.db.Fetch([]byte(Recipient))
if !ok { // if err != nil {
return res, fmt.Errorf("missing session") // return res, err
} // }
store := h.userdataStore
recipient, _ := store.ReadEntry(ctx, sessionId, utils.DATA_RECIPIENT)
res.Content = string(recipient) res.Content = string("recipient")
return res, nil return res, nil
} }
@ -821,15 +759,12 @@ func (h *Handlers) GetRecipient(ctx context.Context, sym string, input []byte) (
func (h *Handlers) GetSender(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) GetSender(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
sessionId, ok := ctx.Value("SessionId").(string) // publicKey, err := h.db.Fetch([]byte(PublicKeyKey))
if !ok { // if err != nil {
return res, fmt.Errorf("missing session") // return res, err
} // }
store := h.userdataStore res.Content = string("publicKey")
publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY)
res.Content = string(publicKey)
return res, nil return res, nil
} }
@ -838,14 +773,11 @@ func (h *Handlers) GetSender(ctx context.Context, sym string, input []byte) (res
func (h *Handlers) GetAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) GetAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
sessionId, ok := ctx.Value("SessionId").(string) // amount, err := h.db.Fetch([]byte(Amount))
if !ok { // if err != nil {
return res, fmt.Errorf("missing session") // return res, err
} // }
store := h.userdataStore res.Content = string("amount")
amount, _ := store.ReadEntry(ctx, sessionId, utils.DATA_AMOUNT)
res.Content = string(amount)
return res, nil return res, nil
} }
@ -855,23 +787,17 @@ func (h *Handlers) GetAmount(ctx context.Context, sym string, input []byte) (res
func (h *Handlers) QuitWithBalance(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) QuitWithBalance(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized") flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized")
code := codeFromCtx(ctx) code := codeFromCtx(ctx)
l := gotext.NewLocale(translationDir, code) l := gotext.NewLocale(translationDir, code)
l.AddDomain("default") l.AddDomain("default")
// publicKey, err := h.db.Fetch([]byte(PublicKeyKey))
store := h.userdataStore // if err != nil {
publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) // return res, err
if err != nil { // }
return res, err balance, err := h.accountService.CheckBalance(string("publicKey"))
}
balance, err := h.accountService.CheckBalance(string(publicKey))
if err != nil { if err != nil {
return res, nil return res, nil
} }
@ -881,28 +807,31 @@ func (h *Handlers) QuitWithBalance(ctx context.Context, sym string, input []byte
} }
// InitiateTransaction returns a confirmation and resets the transaction data // InitiateTransaction returns a confirmation and resets the transaction data
// on the gdbm store. // on the JSON file.
func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
var err error var err error
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
code := codeFromCtx(ctx) code := codeFromCtx(ctx)
l := gotext.NewLocale(translationDir, code) l := gotext.NewLocale(translationDir, code)
l.AddDomain("default") l.AddDomain("default")
// TODO // TODO
// Use the amount, recipient and sender to call the API and initialize the transaction // Use the amount, recipient and sender to call the API and initialize the transaction
store := h.userdataStore
publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY)
amount, _ := store.ReadEntry(ctx, sessionId, utils.DATA_AMOUNT) // publicKey, err := h.db.Fetch([]byte(PublicKeyKey))
// if err != nil {
// return res, err
// }
// amount, err := h.db.Fetch([]byte(Amount))
// if err != nil {
// return res, err
// }
// recipient, err := h.db.Fetch([]byte(Recipient))
// if err != nil {
// return res, err
// }
recipient, _ := store.ReadEntry(ctx, sessionId, utils.DATA_RECIPIENT) //res.Content = l.Get("Your request has been sent. %s will receive %s from %s.", string(recipient), string(amount), string(publicKey))
res.Content = l.Get("Your request has been sent. %s will receive %s from %s.", string(recipient), string(amount), string(publicKey))
account_authorized_flag, err := h.flagManager.GetFlag("flag_account_authorized") account_authorized_flag, err := h.flagManager.GetFlag("flag_account_authorized")
if err != nil { if err != nil {
@ -916,55 +845,62 @@ func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input []
// GetProfileInfo retrieves and formats the profile information of a user from a Gdbm backed storage. // GetProfileInfo retrieves and formats the profile information of a user from a Gdbm backed storage.
func (h *Handlers) GetProfileInfo(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) GetProfileInfo(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
// Default value when an entry is not found // Define default values
defaultValue := "Not Provided" defaultValue := "Not provided"
name := defaultValue
familyName := defaultValue
yob := defaultValue
gender := defaultValue
location := defaultValue
offerings := defaultValue
// Helper function to handle nil byte slices and convert them to string // Fetch data using a map for better organization
getEntryOrDefault := func(entry []byte, err error) string { // dataKeys := map[string]*string{
if err != nil || entry == nil { // FirstName: &name,
return defaultValue // FamilyName: &familyName,
} // YearOfBirth: &yob,
return string(entry) // Location: &location,
} // Gender: &gender,
store := h.userdataStore // Offerings: &offerings,
// Retrieve user data as strings with fallback to defaultValue // }
firstName := getEntryOrDefault(store.ReadEntry(ctx, sessionId, utils.DATA_FIRST_NAME))
familyName := getEntryOrDefault(store.ReadEntry(ctx, sessionId, utils.DATA_FAMILY_NAME)) // Iterate over keys and fetch values
yob := getEntryOrDefault(store.ReadEntry(ctx, sessionId, utils.DATA_YOB)) //iter := h.db.Iterator()
gender := getEntryOrDefault(store.ReadEntry(ctx, sessionId, utils.DATA_GENDER)) // next := h.db.Iterator()
location := getEntryOrDefault(store.ReadEntry(ctx, sessionId, utils.DATA_LOCATION)) // //defer iter.Close() // Ensure the iterator is closed
offerings := getEntryOrDefault(store.ReadEntry(ctx, sessionId, utils.DATA_OFFERINGS)) // for key, err := next(); err == nil; key, err = next() {
// if valuePointer, ok := dataKeys[string(key)]; ok {
// // value, fetchErr := h.db.Fetch(key)
// // if fetchErr == nil {
// // *valuePointer = string(value)
// // }
// }
// }
// Construct the full name // Construct the full name
name := defaultValue
if familyName != defaultValue { if familyName != defaultValue {
if firstName == defaultValue { if name == defaultValue {
name = familyName name = familyName
} else { } else {
name = firstName + " " + familyName name = name + " " + familyName
} }
} }
// Calculate age from year of birth // Calculate age from year of birth
age := defaultValue var age string
if yob != defaultValue { if yob != defaultValue {
if yobInt, err := strconv.Atoi(yob); err == nil { yobInt, err := strconv.Atoi(yob)
age = strconv.Itoa(utils.CalculateAgeWithYOB(yobInt)) if err != nil {
} else {
return res, fmt.Errorf("invalid year of birth: %v", err) return res, fmt.Errorf("invalid year of birth: %v", err)
} }
age = strconv.Itoa(utils.CalculateAgeWithYOB(yobInt))
} else {
age = defaultValue
} }
// Format the result // Format the result
res.Content = fmt.Sprintf( formattedData := fmt.Sprintf("Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n", name, gender, age, location, offerings)
"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n", res.Content = formattedData
name, gender, age, location, offerings,
)
return res, nil return res, nil
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,59 +0,0 @@
package mocks
import (
"context"
"git.defalsify.org/vise.git/lang"
"github.com/stretchr/testify/mock"
)
type MockDb struct {
mock.Mock
}
func (m *MockDb) SetPrefix(prefix uint8) {
m.Called(prefix)
}
func (m *MockDb) Prefix() uint8 {
args := m.Called()
return args.Get(0).(uint8)
}
func (m *MockDb) Safe() bool {
args := m.Called()
return args.Get(0).(bool)
}
func (m *MockDb) SetLanguage(language *lang.Language) {
m.Called(language)
}
func (m *MockDb) SetLock(uint8, bool) error {
args := m.Called()
return args.Error(0)
}
func (m *MockDb) Connect(ctx context.Context, connectionStr string) error {
args := m.Called(ctx, connectionStr)
return args.Error(0)
}
func (m *MockDb) SetSession(sessionId string) {
m.Called(sessionId)
}
func (m *MockDb) Put(ctx context.Context, key, value []byte) error {
args := m.Called(ctx, key, value)
return args.Error(0)
}
func (m *MockDb) Get(ctx context.Context, key []byte) ([]byte, error) {
args := m.Called(ctx, key)
return nil, args.Error(0)
}
func (m *MockDb) Close() error {
args := m.Called(nil)
return args.Error(0)
}

View File

@ -0,0 +1,44 @@
package mocks
import (
"git.grassecon.net/urdt/ussd/internal/models"
"github.com/stretchr/testify/mock"
)
type MockAccountFileHandler struct {
mock.Mock
}
func (m *MockAccountFileHandler) EnsureFileExists() error {
args := m.Called()
return args.Error(0)
}
func (m *MockAccountFileHandler) ReadAccountData() (map[string]string, error) {
args := m.Called()
return args.Get(0).(map[string]string), args.Error(1)
}
func (m *MockAccountFileHandler) WriteAccountData(data map[string]string) error {
args := m.Called(data)
return args.Error(0)
}
type MockAccountService struct {
mock.Mock
}
func (m *MockAccountService) CreateAccount() (*models.AccountResponse, error) {
args := m.Called()
return args.Get(0).(*models.AccountResponse), args.Error(1)
}
func (m *MockAccountService) CheckAccountStatus(TrackingId string) (string, error) {
args := m.Called()
return args.Get(0).(string), args.Error(1)
}
func (m *MockAccountService) CheckBalance(PublicKey string) (string, error) {
args := m.Called()
return args.Get(0).(string), args.Error(1)
}

View File

@ -1,26 +0,0 @@
package mocks
import (
"git.grassecon.net/urdt/ussd/internal/models"
"github.com/stretchr/testify/mock"
)
// MockAccountService implements AccountServiceInterface for testing
type MockAccountService struct {
mock.Mock
}
func (m *MockAccountService) CreateAccount() (*models.AccountResponse, error) {
args := m.Called()
return args.Get(0).(*models.AccountResponse), args.Error(1)
}
func (m *MockAccountService) CheckBalance(publicKey string) (string, error) {
args := m.Called(publicKey)
return args.String(0), args.Error(1)
}
func (m *MockAccountService) CheckAccountStatus(trackingId string) (string, error) {
args := m.Called(trackingId)
return args.String(0), args.Error(1)
}

View File

@ -1,24 +0,0 @@
package mocks
import (
"context"
"git.defalsify.org/vise.git/db"
"git.grassecon.net/urdt/ussd/internal/utils"
"github.com/stretchr/testify/mock"
)
type MockUserDataStore struct {
db.Db
mock.Mock
}
func (m *MockUserDataStore) ReadEntry(ctx context.Context, sessionId string, typ utils.DataTyp) ([]byte, error) {
args := m.Called(ctx, sessionId, typ)
return args.Get(0).([]byte), args.Error(1)
}
func (m *MockUserDataStore) WriteEntry(ctx context.Context, sessionId string, typ utils.DataTyp, value []byte) error {
args := m.Called(ctx, sessionId, typ, value)
return args.Error(0)
}

View File

@ -0,0 +1,77 @@
package utils
import (
"context"
"encoding/json"
"git.defalsify.org/vise.git/db"
)
type AccountFileHandler struct {
//FilePath string
store db.Db
}
// func NewAccountFileHandler(path string) *AccountFileHandler {
// return &AccountFileHandler{FilePath: path}
// }
func NewAccountFileHandler(store db.Db) *AccountFileHandler {
return &AccountFileHandler{
store: store,
}
}
// func (afh *AccountFileHandler) ReadAccountData() (map[string]string, error) {
// jsonData, err := os.ReadFile(afh.FilePath)
// if err != nil {
// return nil, err
// }
// var accountData map[string]string
// err = json.Unmarshal(jsonData, &accountData)
// if err != nil {
// return nil, err
// }
// return accountData, nil
// }
func (afh *AccountFileHandler) ReadAccountData(ctx context.Context, sessionId string) (map[string]string, error) {
var accountData map[string]string
jsonData, err := ReadEntry(ctx, afh.store, sessionId, DATA_ACCOUNT)
err = json.Unmarshal(jsonData, &accountData)
if err != nil {
return nil, err
}
return accountData, nil
}
// func (afh *AccountFileHandler) WriteAccountData(accountData map[string]string) error {
// jsonData, err := json.Marshal(accountData)
// if err != nil {
// return err
// }
// return os.WriteFile(afh.FilePath, jsonData, 0644)
// }
func (afh *AccountFileHandler) WriteAccountData(ctx context.Context, sessionId string, accountData map[string]string) error {
_, err := json.Marshal(accountData)
if err != nil {
return err
}
return nil
}
// func (afh *AccountFileHandler) EnsureFileExists() error {
// f, err := os.OpenFile(afh.FilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
// if err != nil {
// return err
// }
// return f.Close()
// }
func (afh *AccountFileHandler) EnsureFileExists() error {
return nil
}

View File

@ -16,15 +16,6 @@ const (
DATA_PUBLIC_KEY DATA_PUBLIC_KEY
DATA_CUSTODIAL_ID DATA_CUSTODIAL_ID
DATA_ACCOUNT_PIN DATA_ACCOUNT_PIN
DATA_ACCOUNT_STATUS
DATA_FIRST_NAME
DATA_FAMILY_NAME
DATA_YOB
DATA_LOCATION
DATA_GENDER
DATA_OFFERINGS
DATA_RECIPIENT
DATA_AMOUNT
) )
func typToBytes(typ DataTyp) []byte { func typToBytes(typ DataTyp) []byte {
@ -33,16 +24,15 @@ func typToBytes(typ DataTyp) []byte {
return b[:] return b[:]
} }
func PackKey(typ DataTyp, data []byte) []byte { func packKey(typ DataTyp, data []byte) []byte {
v := typToBytes(typ) v := typToBytes(typ)
return append(v, data...) return append(v, data...)
} }
func ReadEntry(ctx context.Context, store db.Db, sessionId string, typ DataTyp) ([]byte, error) { func ReadEntry(ctx context.Context, store db.Db, sessionId string, typ DataTyp) ([]byte, error) {
store.SetPrefix(db.DATATYPE_USERDATA) store.SetPrefix(db.DATATYPE_USERDATA)
store.SetSession(sessionId) store.SetSession(sessionId)
k := PackKey(typ, []byte(sessionId)) k := packKey(typ, []byte(sessionId))
b, err := store.Get(ctx, k) b, err := store.Get(ctx, k)
if err != nil { if err != nil {
return nil, err return nil, err
@ -53,6 +43,6 @@ func ReadEntry(ctx context.Context, store db.Db, sessionId string, typ DataTyp)
func WriteEntry(ctx context.Context, store db.Db, sessionId string, typ DataTyp, value []byte) error { func WriteEntry(ctx context.Context, store db.Db, sessionId string, typ DataTyp, value []byte) error {
store.SetPrefix(db.DATATYPE_USERDATA) store.SetPrefix(db.DATATYPE_USERDATA)
store.SetSession(sessionId) store.SetSession(sessionId)
k := PackKey(typ, []byte(sessionId)) k := packKey(typ, []byte(sessionId))
return store.Put(ctx, k, value) return store.Put(ctx, k, value)
} }

View File

@ -1,32 +0,0 @@
package utils
import (
"context"
"git.defalsify.org/vise.git/db"
)
type DataStore interface {
db.Db
ReadEntry(ctx context.Context, sessionId string, typ DataTyp) ([]byte, error)
WriteEntry(ctx context.Context, sessionId string, typ DataTyp, value []byte) error
}
type UserDataStore struct {
db.Db
}
// ReadEntry retrieves an entry from the store based on the provided parameters.
func (store *UserDataStore) ReadEntry(ctx context.Context, sessionId string, typ DataTyp) ([]byte, error) {
store.SetPrefix(db.DATATYPE_USERDATA)
store.SetSession(sessionId)
k := PackKey(typ, []byte(sessionId))
return store.Get(ctx, k)
}
func (store *UserDataStore) WriteEntry(ctx context.Context, sessionId string, typ DataTyp, value []byte) error {
store.SetPrefix(db.DATATYPE_USERDATA)
store.SetSession(sessionId)
k := PackKey(typ, []byte(sessionId))
return store.Put(ctx, k, value)
}