Compare commits
8 Commits
menu-prima
...
phone-ussd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
807c113f71
|
||
|
|
54e869bff8
|
||
|
|
612654bedf
|
||
|
|
b31e594171
|
||
|
|
a21540de57
|
||
|
|
1ae19a4957
|
||
|
|
854af76179
|
||
|
|
b82b38fb27
|
@@ -11,9 +11,13 @@ import (
|
||||
func init() {
|
||||
DebugCap |= 1
|
||||
dbTypStr[db.DATATYPE_STATE] = "internal state"
|
||||
dbTypStr[db.DATATYPE_USERDATA + 1 + common.DATA_ACCOUNT] = "account"
|
||||
dbTypStr[db.DATATYPE_USERDATA + 1 + common.DATA_ACCOUNT_CREATED] = "account created"
|
||||
dbTypStr[db.DATATYPE_USERDATA + 1 + common.DATA_TRACKING_ID] = "tracking id"
|
||||
dbTypStr[db.DATATYPE_USERDATA + 1 + common.DATA_PUBLIC_KEY] = "public key"
|
||||
dbTypStr[db.DATATYPE_USERDATA + 1 + common.DATA_CUSTODIAL_ID] = "custodial id"
|
||||
dbTypStr[db.DATATYPE_USERDATA + 1 + common.DATA_ACCOUNT_PIN] = "account pin"
|
||||
dbTypStr[db.DATATYPE_USERDATA + 1 + common.DATA_ACCOUNT_STATUS] = "account status"
|
||||
dbTypStr[db.DATATYPE_USERDATA + 1 + common.DATA_FIRST_NAME] = "first name"
|
||||
dbTypStr[db.DATATYPE_USERDATA + 1 + common.DATA_FAMILY_NAME] = "family name"
|
||||
dbTypStr[db.DATATYPE_USERDATA + 1 + common.DATA_YOB] = "year of birth"
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"git.grassecon.net/urdt/ussd/initializers"
|
||||
"git.grassecon.net/urdt/ussd/internal/storage"
|
||||
"git.grassecon.net/urdt/ussd/debug"
|
||||
"git.defalsify.org/vise.git/db"
|
||||
"git.defalsify.org/vise.git/logging"
|
||||
)
|
||||
|
||||
@@ -48,14 +47,13 @@ func main() {
|
||||
|
||||
store, err := menuStorageService.GetUserdataDb(ctx)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "get userdata db: %v\n", err.Error())
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
store.SetPrefix(db.DATATYPE_USERDATA)
|
||||
|
||||
d, err := store.Dump(ctx, []byte(sessionId))
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "store dump fail: %v\n", err.Error())
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -69,7 +67,7 @@ func main() {
|
||||
fmt.Fprintf(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("%vValue: %v\n\n", o, string(v))
|
||||
fmt.Printf("%vValue: %v\n\n", o, v)
|
||||
}
|
||||
|
||||
err = store.Close()
|
||||
|
||||
2
go.mod
@@ -3,7 +3,7 @@ module git.grassecon.net/urdt/ussd
|
||||
go 1.23.0
|
||||
|
||||
require (
|
||||
git.defalsify.org/vise.git v0.2.3-0.20241231085136-8582c7e157d9
|
||||
git.defalsify.org/vise.git v0.2.1-0.20241212145627-683015d4df80
|
||||
github.com/alecthomas/assert/v2 v2.2.2
|
||||
github.com/gofrs/uuid v4.4.0+incompatible
|
||||
github.com/grassrootseconomics/eth-custodial v1.3.0-beta
|
||||
|
||||
4
go.sum
@@ -1,5 +1,5 @@
|
||||
git.defalsify.org/vise.git v0.2.3-0.20241231085136-8582c7e157d9 h1:O3m+NgWDWtJm8OculT99c4bDMAO4xLe2c8hpCKpsd9g=
|
||||
git.defalsify.org/vise.git v0.2.3-0.20241231085136-8582c7e157d9/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck=
|
||||
git.defalsify.org/vise.git v0.2.1-0.20241212145627-683015d4df80 h1:GYUVXRUtMpA40T4COeAduoay6CIgXjD5cfDYZOTFIKw=
|
||||
git.defalsify.org/vise.git v0.2.1-0.20241212145627-683015d4df80/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck=
|
||||
github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk=
|
||||
github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
|
||||
github.com/alecthomas/participle/v2 v2.0.0 h1:Fgrq+MbuSsJwIkw3fEj9h75vDP0Er5JzepJ0/HNHv0g=
|
||||
|
||||
@@ -116,7 +116,7 @@ func (ls *LocalHandlerService) GetHandler(accountService remote.AccountServiceIn
|
||||
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("check_pin_mismatch", ussdHandlers.CheckPinMisMatch)
|
||||
ls.DbRs.AddLocalFunc("validate_blocked_number", ussdHandlers.ValidateBlockedNumber)
|
||||
ls.DbRs.AddLocalFunc("retrieve_blocked_number", ussdHandlers.RetrieveBlockedNumber)
|
||||
ls.DbRs.AddLocalFunc("reset_unregistered_number", ussdHandlers.ResetUnregisteredNumber)
|
||||
|
||||
@@ -39,7 +39,7 @@ const (
|
||||
pinPattern = `^\d{4}$`
|
||||
)
|
||||
|
||||
// checks whether the given input is a 4 digit number
|
||||
// isValidPIN checks whether the given input is a 4 digit number
|
||||
func isValidPIN(pin string) bool {
|
||||
match, _ := regexp.MatchString(pinPattern, pin)
|
||||
return match
|
||||
@@ -69,19 +69,18 @@ func (fm *FlagManager) GetFlag(label string) (uint32, error) {
|
||||
}
|
||||
|
||||
type Handlers struct {
|
||||
pe *persist.Persister
|
||||
st *state.State
|
||||
ca cache.Memory
|
||||
userdataStore common.DataStore
|
||||
adminstore *utils.AdminStore
|
||||
flagManager *asm.FlagParser
|
||||
accountService remote.AccountServiceInterface
|
||||
prefixDb storage.PrefixDb
|
||||
profile *models.Profile
|
||||
pe *persist.Persister
|
||||
st *state.State
|
||||
ca cache.Memory
|
||||
userdataStore common.DataStore
|
||||
adminstore *utils.AdminStore
|
||||
flagManager *asm.FlagParser
|
||||
accountService remote.AccountServiceInterface
|
||||
prefixDb storage.PrefixDb
|
||||
profile *models.Profile
|
||||
ReplaceSeparatorFunc func(string) string
|
||||
}
|
||||
|
||||
// NewHandlers creates a new instance of the Handlers struct with the provided dependencies.
|
||||
func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db, adminstore *utils.AdminStore, accountService remote.AccountServiceInterface, replaceSeparatorFunc func(string) string) (*Handlers, error) {
|
||||
if userdataStore == nil {
|
||||
return nil, fmt.Errorf("cannot create handler with nil userdata store")
|
||||
@@ -95,18 +94,17 @@ func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db, adminstore *util
|
||||
prefixDb := storage.NewSubPrefixDb(userdataStore, prefix)
|
||||
|
||||
h := &Handlers{
|
||||
userdataStore: userDb,
|
||||
flagManager: appFlags,
|
||||
adminstore: adminstore,
|
||||
accountService: accountService,
|
||||
prefixDb: prefixDb,
|
||||
profile: &models.Profile{Max: 6},
|
||||
userdataStore: userDb,
|
||||
flagManager: appFlags,
|
||||
adminstore: adminstore,
|
||||
accountService: accountService,
|
||||
prefixDb: prefixDb,
|
||||
profile: &models.Profile{Max: 6},
|
||||
ReplaceSeparatorFunc: replaceSeparatorFunc,
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
|
||||
// WithPersister sets persister instance to the handlers.
|
||||
func (h *Handlers) WithPersister(pe *persist.Persister) *Handlers {
|
||||
if h.pe != nil {
|
||||
panic("persister already set")
|
||||
@@ -115,7 +113,6 @@ func (h *Handlers) WithPersister(pe *persist.Persister) *Handlers {
|
||||
return h
|
||||
}
|
||||
|
||||
// Init initializes the handler for a new session.
|
||||
func (h *Handlers) Init(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var r resource.Result
|
||||
if h.pe == nil {
|
||||
@@ -129,11 +126,6 @@ func (h *Handlers) Init(ctx context.Context, sym string, input []byte) (resource
|
||||
h.st = h.pe.GetState()
|
||||
h.ca = h.pe.GetMemory()
|
||||
|
||||
if len(input) == 0 {
|
||||
// move to the top node
|
||||
h.st.Code = []byte{}
|
||||
}
|
||||
|
||||
sessionId, _ := ctx.Value("SessionId").(string)
|
||||
flag_admin_privilege, _ := h.flagManager.GetFlag("flag_admin_privilege")
|
||||
|
||||
@@ -159,7 +151,7 @@ func (h *Handlers) Exit() {
|
||||
h.pe = nil
|
||||
}
|
||||
|
||||
// SetLanguage sets the language across the menu.
|
||||
// SetLanguage sets the language across the menu
|
||||
func (h *Handlers) SetLanguage(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
|
||||
@@ -183,7 +175,6 @@ func (h *Handlers) SetLanguage(ctx context.Context, sym string, input []byte) (r
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// handles the account creation when no existing account is present for the session and stores associated data in the user data store.
|
||||
func (h *Handlers) createAccountNoExist(ctx context.Context, sessionId string, res *resource.Result) error {
|
||||
flag_account_created, _ := h.flagManager.GetFlag("flag_account_created")
|
||||
r, err := h.accountService.CreateAccount(ctx)
|
||||
@@ -216,9 +207,9 @@ func (h *Handlers) createAccountNoExist(ctx context.Context, sessionId string, r
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateAccount checks if any account exists on the JSON data file, and if not,
|
||||
// CreateAccount checks if any account exists on the JSON data file, and if not
|
||||
// creates an account on the API,
|
||||
// sets the default values and flags.
|
||||
// sets the default values and flags
|
||||
func (h *Handlers) CreateAccount(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
var err error
|
||||
@@ -242,22 +233,19 @@ func (h *Handlers) CreateAccount(ctx context.Context, sym string, input []byte)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// CheckBlockedNumPinMisMatch checks if the provided PIN matches a temporary PIN stored for a blocked number.
|
||||
func (h *Handlers) CheckBlockedNumPinMisMatch(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
func (h *Handlers) CheckPinMisMatch(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
res := resource.Result{}
|
||||
flag_pin_mismatch, _ := h.flagManager.GetFlag("flag_pin_mismatch")
|
||||
sessionId, ok := ctx.Value("SessionId").(string)
|
||||
if !ok {
|
||||
return res, fmt.Errorf("missing session")
|
||||
}
|
||||
// Get blocked number from storage.
|
||||
store := h.userdataStore
|
||||
blockedNumber, err := store.ReadEntry(ctx, sessionId, common.DATA_BLOCKED_NUMBER)
|
||||
if err != nil {
|
||||
logg.ErrorCtxf(ctx, "failed to read blockedNumber entry with", "key", common.DATA_BLOCKED_NUMBER, "error", err)
|
||||
return res, err
|
||||
}
|
||||
// Get temporary PIN for the blocked number.
|
||||
temporaryPin, err := store.ReadEntry(ctx, string(blockedNumber), common.DATA_TEMPORARY_VALUE)
|
||||
if err != nil {
|
||||
logg.ErrorCtxf(ctx, "failed to read temporaryPin entry with", "key", common.DATA_TEMPORARY_VALUE, "error", err)
|
||||
@@ -271,7 +259,6 @@ func (h *Handlers) CheckBlockedNumPinMisMatch(ctx context.Context, sym string, i
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// VerifyNewPin checks if a new PIN meets the required format criteria.
|
||||
func (h *Handlers) VerifyNewPin(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
res := resource.Result{}
|
||||
_, ok := ctx.Value("SessionId").(string)
|
||||
@@ -280,7 +267,7 @@ func (h *Handlers) VerifyNewPin(ctx context.Context, sym string, input []byte) (
|
||||
}
|
||||
flag_valid_pin, _ := h.flagManager.GetFlag("flag_valid_pin")
|
||||
pinInput := string(input)
|
||||
// Validate that the PIN is a 4-digit number.
|
||||
// Validate that the PIN is a 4-digit number
|
||||
if isValidPIN(pinInput) {
|
||||
res.FlagSet = append(res.FlagSet, flag_valid_pin)
|
||||
} else {
|
||||
@@ -290,9 +277,9 @@ func (h *Handlers) VerifyNewPin(ctx context.Context, sym string, input []byte) (
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// SaveTemporaryPin saves the valid PIN input to the DATA_TEMPORARY_VALUE,
|
||||
// SaveTemporaryPin saves the valid PIN input to the DATA_TEMPORARY_VALUE
|
||||
// during the account creation process
|
||||
// and during the change PIN process.
|
||||
// and during the change PIN process
|
||||
func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
var err error
|
||||
@@ -305,7 +292,7 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt
|
||||
flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin")
|
||||
accountPIN := string(input)
|
||||
|
||||
// Validate that the PIN is a 4-digit number.
|
||||
// Validate that the PIN is a 4-digit number
|
||||
if !isValidPIN(accountPIN) {
|
||||
res.FlagSet = append(res.FlagSet, flag_incorrect_pin)
|
||||
return res, nil
|
||||
@@ -321,7 +308,6 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// SaveOthersTemporaryPin allows authorized users to set temporary PINs for blocked numbers.
|
||||
func (h *Handlers) SaveOthersTemporaryPin(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
var err error
|
||||
@@ -332,14 +318,12 @@ func (h *Handlers) SaveOthersTemporaryPin(ctx context.Context, sym string, input
|
||||
return res, fmt.Errorf("missing session")
|
||||
}
|
||||
temporaryPin := string(input)
|
||||
// First, we retrieve the blocked number associated with this session
|
||||
blockedNumber, err := store.ReadEntry(ctx, sessionId, common.DATA_BLOCKED_NUMBER)
|
||||
if err != nil {
|
||||
logg.ErrorCtxf(ctx, "failed to read blockedNumber entry with", "key", common.DATA_BLOCKED_NUMBER, "error", err)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Then we save the temporary PIN for that blocked number
|
||||
err = store.WriteEntry(ctx, string(blockedNumber), common.DATA_TEMPORARY_VALUE, []byte(temporaryPin))
|
||||
if err != nil {
|
||||
logg.ErrorCtxf(ctx, "failed to write temporaryPin entry with", "key", common.DATA_TEMPORARY_VALUE, "value", temporaryPin, "error", err)
|
||||
@@ -349,7 +333,6 @@ func (h *Handlers) SaveOthersTemporaryPin(ctx context.Context, sym string, input
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// ConfirmPinChange validates user's new PIN. If input matches the temporary PIN, saves it as the new account PIN.
|
||||
func (h *Handlers) ConfirmPinChange(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
sessionId, ok := ctx.Value("SessionId").(string)
|
||||
@@ -369,7 +352,6 @@ func (h *Handlers) ConfirmPinChange(ctx context.Context, sym string, input []byt
|
||||
} else {
|
||||
res.FlagSet = append(res.FlagSet, flag_pin_mismatch)
|
||||
}
|
||||
// If matched, save the confirmed PIN as the new account PIN
|
||||
err = store.WriteEntry(ctx, sessionId, common.DATA_ACCOUNT_PIN, []byte(temporaryPin))
|
||||
if err != nil {
|
||||
logg.ErrorCtxf(ctx, "failed to write temporaryPin entry with", "key", common.DATA_ACCOUNT_PIN, "value", temporaryPin, "error", err)
|
||||
@@ -380,7 +362,7 @@ func (h *Handlers) ConfirmPinChange(ctx context.Context, sym string, input []byt
|
||||
|
||||
// VerifyCreatePin checks whether the confirmation PIN is similar to the temporary PIN
|
||||
// If similar, it sets the USERFLAG_PIN_SET flag and writes the account PIN allowing the user
|
||||
// to access the main menu.
|
||||
// to access the main menu
|
||||
func (h *Handlers) VerifyCreatePin(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
|
||||
@@ -415,7 +397,7 @@ func (h *Handlers) VerifyCreatePin(ctx context.Context, sym string, input []byte
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// retrieves language codes from the context that can be used for handling translations.
|
||||
// codeFromCtx retrieves language codes from the context that can be used for handling translations
|
||||
func codeFromCtx(ctx context.Context) string {
|
||||
var code string
|
||||
if ctx.Value("Language") != nil {
|
||||
@@ -749,7 +731,7 @@ func (h *Handlers) ResetIncorrectPin(ctx context.Context, sym string, input []by
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Setback sets the flag_back_set flag when the navigation is back.
|
||||
// Setback sets the flag_back_set flag when the navigation is back
|
||||
func (h *Handlers) SetBack(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
//TODO:
|
||||
@@ -762,7 +744,7 @@ func (h *Handlers) SetBack(ctx context.Context, sym string, input []byte) (resou
|
||||
}
|
||||
|
||||
// CheckAccountStatus queries the API using the TrackingId and sets flags
|
||||
// based on the account status.
|
||||
// based on the account status
|
||||
func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
|
||||
@@ -802,7 +784,7 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Quit displays the Thank you message and exits the menu.
|
||||
// Quit displays the Thank you message and exits the menu
|
||||
func (h *Handlers) Quit(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
|
||||
@@ -817,7 +799,7 @@ func (h *Handlers) Quit(ctx context.Context, sym string, input []byte) (resource
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// QuitWithHelp displays helpline information then exits the menu.
|
||||
// QuitWithHelp displays helpline information then exits the menu
|
||||
func (h *Handlers) QuitWithHelp(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
|
||||
@@ -832,7 +814,7 @@ func (h *Handlers) QuitWithHelp(ctx context.Context, sym string, input []byte) (
|
||||
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) {
|
||||
var res resource.Result
|
||||
var err error
|
||||
@@ -854,7 +836,7 @@ func (h *Handlers) VerifyYob(ctx context.Context, sym string, input []byte) (res
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// ResetIncorrectYob resets the incorrect date format flag after a new attempt.
|
||||
// ResetIncorrectYob resets the incorrect date format flag after a new attempt
|
||||
func (h *Handlers) ResetIncorrectYob(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
|
||||
@@ -864,7 +846,7 @@ func (h *Handlers) ResetIncorrectYob(ctx context.Context, sym string, input []by
|
||||
}
|
||||
|
||||
// CheckBalance retrieves the balance of the active voucher and sets
|
||||
// the balance as the result content.
|
||||
// the balance as the result content
|
||||
func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
var err error
|
||||
@@ -914,12 +896,9 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) (
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// FetchCommunityBalance retrieves and displays the balance for community accounts in user's preferred language.
|
||||
func (h *Handlers) FetchCommunityBalance(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
// retrieve the language code from the context
|
||||
code := codeFromCtx(ctx)
|
||||
// Initialize the localization system with the appropriate translation directory
|
||||
l := gotext.NewLocale(translationDir, code)
|
||||
l.AddDomain("default")
|
||||
//TODO:
|
||||
@@ -928,10 +907,6 @@ func (h *Handlers) FetchCommunityBalance(ctx context.Context, sym string, input
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// ResetOthersPin handles the PIN reset process for other users' accounts by:
|
||||
// 1. Retrieving the blocked phone number from the session
|
||||
// 2. Fetching the temporary PIN associated with that number
|
||||
// 3. Updating the account PIN with the temporary PIN
|
||||
func (h *Handlers) ResetOthersPin(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
store := h.userdataStore
|
||||
@@ -957,8 +932,6 @@ func (h *Handlers) ResetOthersPin(ctx context.Context, sym string, input []byte)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// ResetUnregisteredNumber clears the unregistered number flag in the system,
|
||||
// indicating that a number's registration status should no longer be marked as unregistered.
|
||||
func (h *Handlers) ResetUnregisteredNumber(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
flag_unregistered_number, _ := h.flagManager.GetFlag("flag_unregistered_number")
|
||||
@@ -966,8 +939,6 @@ func (h *Handlers) ResetUnregisteredNumber(ctx context.Context, sym string, inpu
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// ValidateBlockedNumber performs validation of phone numbers, specifically for blocked numbers in the system.
|
||||
// It checks phone number format and verifies registration status.
|
||||
func (h *Handlers) ValidateBlockedNumber(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
var err error
|
||||
@@ -1096,7 +1067,7 @@ func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []by
|
||||
}
|
||||
|
||||
// TransactionReset resets the previous transaction data (Recipient and Amount)
|
||||
// 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) {
|
||||
var res resource.Result
|
||||
var err error
|
||||
@@ -1149,7 +1120,7 @@ func (h *Handlers) InviteValidRecipient(ctx context.Context, sym string, input [
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// 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) {
|
||||
var res resource.Result
|
||||
var err error
|
||||
@@ -1279,7 +1250,7 @@ func (h *Handlers) RetrieveBlockedNumber(ctx context.Context, sym string, input
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetSender returns the sessionId (phoneNumber).
|
||||
// GetSender returns the sessionId (phoneNumber)
|
||||
func (h *Handlers) GetSender(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
|
||||
@@ -1293,7 +1264,7 @@ func (h *Handlers) GetSender(ctx context.Context, sym string, input []byte) (res
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetAmount retrieves the amount from teh Gdbm Db.
|
||||
// GetAmount retrieves the amount from teh Gdbm Db
|
||||
func (h *Handlers) GetAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
|
||||
@@ -1317,7 +1288,7 @@ func (h *Handlers) GetAmount(ctx context.Context, sym string, input []byte) (res
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// InitiateTransaction calls the TokenTransfer and returns a confirmation based on the result.
|
||||
// InitiateTransaction calls the TokenTransfer and returns a confirmation based on the result
|
||||
func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
var err error
|
||||
@@ -1367,12 +1338,9 @@ func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input []
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetCurrentProfileInfo retrieves specific profile fields based on the current state of the USSD session.
|
||||
// Uses flag management system to track profile field status and handle menu navigation.
|
||||
func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
var profileInfo []byte
|
||||
var defaultValue string
|
||||
var err error
|
||||
|
||||
flag_firstname_set, _ := h.flagManager.GetFlag("flag_firstname_set")
|
||||
@@ -1389,18 +1357,6 @@ func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input
|
||||
if !ok {
|
||||
return res, fmt.Errorf("missing session")
|
||||
}
|
||||
language, ok := ctx.Value("Language").(lang.Language)
|
||||
if !ok {
|
||||
return res, fmt.Errorf("value for 'Language' is not of type lang.Language")
|
||||
}
|
||||
code := language.Code
|
||||
if code == "swa" {
|
||||
defaultValue = "Haipo"
|
||||
} else {
|
||||
defaultValue = "Not Provided"
|
||||
}
|
||||
|
||||
|
||||
sm, _ := h.st.Where()
|
||||
parts := strings.SplitN(sm, "_", 2)
|
||||
filename := parts[1]
|
||||
@@ -1417,7 +1373,7 @@ func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input
|
||||
profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_FIRST_NAME)
|
||||
if err != nil {
|
||||
if db.IsNotFound(err) {
|
||||
res.Content = defaultValue
|
||||
res.Content = "Not provided"
|
||||
break
|
||||
}
|
||||
logg.ErrorCtxf(ctx, "Failed to read first name entry with", "key", "error", common.DATA_FIRST_NAME, err)
|
||||
@@ -1429,7 +1385,7 @@ func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input
|
||||
profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_FAMILY_NAME)
|
||||
if err != nil {
|
||||
if db.IsNotFound(err) {
|
||||
res.Content = defaultValue
|
||||
res.Content = "Not provided"
|
||||
break
|
||||
}
|
||||
logg.ErrorCtxf(ctx, "Failed to read family name entry with", "key", "error", common.DATA_FAMILY_NAME, err)
|
||||
@@ -1442,7 +1398,7 @@ func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input
|
||||
profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_GENDER)
|
||||
if err != nil {
|
||||
if db.IsNotFound(err) {
|
||||
res.Content = defaultValue
|
||||
res.Content = "Not provided"
|
||||
break
|
||||
}
|
||||
logg.ErrorCtxf(ctx, "Failed to read gender entry with", "key", "error", common.DATA_GENDER, err)
|
||||
@@ -1454,7 +1410,7 @@ func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input
|
||||
profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_YOB)
|
||||
if err != nil {
|
||||
if db.IsNotFound(err) {
|
||||
res.Content = defaultValue
|
||||
res.Content = "Not provided"
|
||||
break
|
||||
}
|
||||
logg.ErrorCtxf(ctx, "Failed to read year of birth(yob) entry with", "key", "error", common.DATA_YOB, err)
|
||||
@@ -1466,7 +1422,7 @@ func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input
|
||||
profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_LOCATION)
|
||||
if err != nil {
|
||||
if db.IsNotFound(err) {
|
||||
res.Content = defaultValue
|
||||
res.Content = "Not provided"
|
||||
break
|
||||
}
|
||||
logg.ErrorCtxf(ctx, "Failed to read location entry with", "key", "error", common.DATA_LOCATION, err)
|
||||
@@ -1478,7 +1434,7 @@ func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input
|
||||
profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_OFFERINGS)
|
||||
if err != nil {
|
||||
if db.IsNotFound(err) {
|
||||
res.Content = defaultValue
|
||||
res.Content = "Not provided"
|
||||
break
|
||||
}
|
||||
logg.ErrorCtxf(ctx, "Failed to read offerings entry with", "key", "error", common.DATA_OFFERINGS, err)
|
||||
@@ -1493,7 +1449,6 @@ func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetProfileInfo provides a comprehensive view of a user's profile.
|
||||
func (h *Handlers) GetProfileInfo(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
var defaultValue string
|
||||
@@ -1562,7 +1517,7 @@ func (h *Handlers) GetProfileInfo(ctx context.Context, sym string, input []byte)
|
||||
}
|
||||
|
||||
// SetDefaultVoucher retrieves the current vouchers
|
||||
// and sets the first as the default voucher, if no active voucher is set.
|
||||
// and sets the first as the default voucher, if no active voucher is set
|
||||
func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
var err error
|
||||
@@ -1647,7 +1602,7 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by
|
||||
}
|
||||
|
||||
// CheckVouchers retrieves the token holdings from the API using the "PublicKey" and stores
|
||||
// them to gdbm.
|
||||
// them to gdbm
|
||||
func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
sessionId, ok := ctx.Value("SessionId").(string)
|
||||
@@ -1719,7 +1674,7 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetVoucherList fetches the list of vouchers and formats them.
|
||||
// GetVoucherList fetches the list of vouchers and formats them
|
||||
func (h *Handlers) GetVoucherList(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
|
||||
@@ -1738,7 +1693,7 @@ func (h *Handlers) GetVoucherList(ctx context.Context, sym string, input []byte)
|
||||
}
|
||||
|
||||
// ViewVoucher retrieves the token holding and balance from the subprefixDB
|
||||
// and displays it to the user for them to select it.
|
||||
// and displays it to the user for them to select it
|
||||
func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
sessionId, ok := ctx.Value("SessionId").(string)
|
||||
@@ -1779,7 +1734,7 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// SetVoucher retrieves the temp voucher data and sets it as the active data.
|
||||
// SetVoucher retrieves the temp voucher data and sets it as the active data
|
||||
func (h *Handlers) SetVoucher(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
|
||||
@@ -1805,7 +1760,7 @@ func (h *Handlers) SetVoucher(ctx context.Context, sym string, input []byte) (re
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetVoucherDetails retrieves the voucher details.
|
||||
// GetVoucherDetails retrieves the voucher details
|
||||
func (h *Handlers) GetVoucherDetails(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
store := h.userdataStore
|
||||
@@ -1837,7 +1792,7 @@ func (h *Handlers) GetVoucherDetails(ctx context.Context, sym string, input []by
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// CheckTransactions retrieves the transactions from the API using the "PublicKey" and stores to prefixDb.
|
||||
// CheckTransactions retrieves the transactions from the API using the "PublicKey" and stores to prefixDb
|
||||
func (h *Handlers) CheckTransactions(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
sessionId, ok := ctx.Value("SessionId").(string)
|
||||
@@ -1895,7 +1850,7 @@ func (h *Handlers) CheckTransactions(ctx context.Context, sym string, input []by
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetTransactionsList fetches the list of transactions and formats them.
|
||||
// GetTransactionsList reads the list of transactions from the db and formats them
|
||||
func (h *Handlers) GetTransactionsList(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
sessionId, ok := ctx.Value("SessionId").(string)
|
||||
@@ -1961,7 +1916,7 @@ func (h *Handlers) GetTransactionsList(ctx context.Context, sym string, input []
|
||||
}
|
||||
|
||||
// ViewTransactionStatement retrieves the transaction statement
|
||||
// and displays it to the user.
|
||||
// and displays it to the user
|
||||
func (h *Handlers) ViewTransactionStatement(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
sessionId, ok := ctx.Value("SessionId").(string)
|
||||
@@ -2009,7 +1964,6 @@ func (h *Handlers) ViewTransactionStatement(ctx context.Context, sym string, inp
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// handles bulk updates of profile information.
|
||||
func (h *Handlers) insertProfileItems(ctx context.Context, sessionId string, res *resource.Result) error {
|
||||
var err error
|
||||
store := h.userdataStore
|
||||
@@ -2032,22 +1986,21 @@ func (h *Handlers) insertProfileItems(ctx context.Context, sessionId string, res
|
||||
for index, profileItem := range h.profile.ProfileItems {
|
||||
// Ensure the profileItem is not "0"(is set)
|
||||
if profileItem != "0" {
|
||||
flag, _ := h.flagManager.GetFlag(profileFlagNames[index])
|
||||
isProfileItemSet := h.st.MatchFlag(flag, true)
|
||||
if !isProfileItemSet {
|
||||
err = store.WriteEntry(ctx, sessionId, profileDataKeys[index], []byte(profileItem))
|
||||
if err != nil {
|
||||
logg.ErrorCtxf(ctx, "failed to write profile entry with", "key", profileDataKeys[index], "value", profileItem, "error", err)
|
||||
return err
|
||||
}
|
||||
res.FlagSet = append(res.FlagSet, flag)
|
||||
err = store.WriteEntry(ctx, sessionId, profileDataKeys[index], []byte(profileItem))
|
||||
if err != nil {
|
||||
logg.ErrorCtxf(ctx, "failed to write profile entry with", "key", profileDataKeys[index], "value", profileItem, "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the flag for the current index
|
||||
flag, _ := h.flagManager.GetFlag(profileFlagNames[index])
|
||||
res.FlagSet = append(res.FlagSet, flag)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateAllProfileItems is used to persist all the new profile information and setup the required profile flags.
|
||||
// UpdateAllProfileItems is used to persist all the new profile information and setup the required profile flags
|
||||
func (h *Handlers) UpdateAllProfileItems(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||
var res resource.Result
|
||||
sessionId, ok := ctx.Value("SessionId").(string)
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.defalsify.org/vise.git/cache"
|
||||
"git.defalsify.org/vise.git/lang"
|
||||
"git.defalsify.org/vise.git/persist"
|
||||
"git.defalsify.org/vise.git/resource"
|
||||
@@ -16,7 +15,6 @@ import (
|
||||
"git.grassecon.net/urdt/ussd/internal/storage"
|
||||
"git.grassecon.net/urdt/ussd/internal/testutil/mocks"
|
||||
"git.grassecon.net/urdt/ussd/internal/testutil/testservice"
|
||||
"git.grassecon.net/urdt/ussd/internal/utils"
|
||||
"git.grassecon.net/urdt/ussd/models"
|
||||
|
||||
"git.grassecon.net/urdt/ussd/common"
|
||||
@@ -121,102 +119,6 @@ func TestNewHandlers(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
sessionId := "session123"
|
||||
ctx, store := InitializeTestStore(t)
|
||||
ctx = context.WithValue(ctx, "SessionId", sessionId)
|
||||
|
||||
fm, err := NewFlagManager(flagsPath)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
adminstore, err := utils.NewAdminStore(ctx, "admin_numbers")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
st := state.NewState(128)
|
||||
ca := cache.NewCache()
|
||||
|
||||
flag_admin_privilege, _ := fm.GetFlag("flag_admin_privilege")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
setup func() (*Handlers, context.Context)
|
||||
input []byte
|
||||
expectedResult resource.Result
|
||||
}{
|
||||
{
|
||||
name: "Handler not ready",
|
||||
setup: func() (*Handlers, context.Context) {
|
||||
return &Handlers{}, ctx
|
||||
},
|
||||
input: []byte("1"),
|
||||
expectedResult: resource.Result{},
|
||||
},
|
||||
{
|
||||
name: "State and memory initialization",
|
||||
setup: func() (*Handlers, context.Context) {
|
||||
pe := persist.NewPersister(store).WithSession(sessionId).WithContent(st, ca)
|
||||
h := &Handlers{
|
||||
flagManager: fm.parser,
|
||||
adminstore: adminstore,
|
||||
pe: pe,
|
||||
}
|
||||
return h, context.WithValue(ctx, "SessionId", sessionId)
|
||||
},
|
||||
input: []byte("1"),
|
||||
expectedResult: resource.Result{
|
||||
FlagReset: []uint32{flag_admin_privilege},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Non-admin session initialization",
|
||||
setup: func() (*Handlers, context.Context) {
|
||||
pe := persist.NewPersister(store).WithSession("0712345678").WithContent(st, ca)
|
||||
h := &Handlers{
|
||||
flagManager: fm.parser,
|
||||
adminstore: adminstore,
|
||||
pe: pe,
|
||||
}
|
||||
return h, context.WithValue(context.Background(), "SessionId", "0712345678")
|
||||
},
|
||||
input: []byte("1"),
|
||||
expectedResult: resource.Result{
|
||||
FlagReset: []uint32{flag_admin_privilege},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Move to top node on empty input",
|
||||
setup: func() (*Handlers, context.Context) {
|
||||
pe := persist.NewPersister(store).WithSession(sessionId).WithContent(st, ca)
|
||||
h := &Handlers{
|
||||
flagManager: fm.parser,
|
||||
adminstore: adminstore,
|
||||
pe: pe,
|
||||
}
|
||||
st.Code = []byte("some pending bytecode")
|
||||
return h, context.WithValue(ctx, "SessionId", sessionId)
|
||||
},
|
||||
input: []byte(""),
|
||||
expectedResult: resource.Result{
|
||||
FlagReset: []uint32{flag_admin_privilege},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
h, testCtx := tt.setup()
|
||||
res, err := h.Init(testCtx, "", tt.input)
|
||||
|
||||
assert.NoError(t, err, "Unexpected error occurred")
|
||||
assert.Equal(t, res, tt.expectedResult, "Expected result should match actual result")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateAccount(t *testing.T) {
|
||||
sessionId := "session123"
|
||||
ctx, store := InitializeTestStore(t)
|
||||
@@ -1798,7 +1700,7 @@ func TestGetProfile(t *testing.T) {
|
||||
result: resource.Result{
|
||||
Content: fmt.Sprintf(
|
||||
"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n",
|
||||
"John Doee", "Male", "49", "Kilifi", "Bananas",
|
||||
"John Doee", "Male", "48", "Kilifi", "Bananas",
|
||||
),
|
||||
},
|
||||
},
|
||||
@@ -1810,7 +1712,7 @@ func TestGetProfile(t *testing.T) {
|
||||
result: resource.Result{
|
||||
Content: fmt.Sprintf(
|
||||
"Jina: %s\nJinsia: %s\nUmri: %s\nEneo: %s\nUnauza: %s\n",
|
||||
"John Doee", "Male", "49", "Kilifi", "Bananas",
|
||||
"John Doee", "Male", "48", "Kilifi", "Bananas",
|
||||
),
|
||||
},
|
||||
},
|
||||
@@ -1822,7 +1724,7 @@ func TestGetProfile(t *testing.T) {
|
||||
result: resource.Result{
|
||||
Content: fmt.Sprintf(
|
||||
"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n",
|
||||
"John Doee", "Male", "49", "Kilifi", "Bananas",
|
||||
"John Doee", "Male", "48", "Kilifi", "Bananas",
|
||||
),
|
||||
},
|
||||
},
|
||||
|
||||
@@ -17,7 +17,8 @@ var (
|
||||
type DefaultRequestParser struct {
|
||||
}
|
||||
|
||||
func (rp *DefaultRequestParser) GetSessionId(rq any) (string, error) {
|
||||
|
||||
func(rp *DefaultRequestParser) GetSessionId(rq any) (string, error) {
|
||||
rqv, ok := rq.(*http.Request)
|
||||
if !ok {
|
||||
return "", handlers.ErrInvalidRequest
|
||||
@@ -29,7 +30,7 @@ func (rp *DefaultRequestParser) GetSessionId(rq any) (string, error) {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (rp *DefaultRequestParser) GetInput(rq any) ([]byte, error) {
|
||||
func(rp *DefaultRequestParser) GetInput(rq any) ([]byte, error) {
|
||||
rqv, ok := rq.(*http.Request)
|
||||
if !ok {
|
||||
return nil, handlers.ErrInvalidRequest
|
||||
@@ -52,24 +53,25 @@ func ToSessionHandler(h handlers.RequestHandler) *SessionHandler {
|
||||
}
|
||||
}
|
||||
|
||||
func (f *SessionHandler) writeError(w http.ResponseWriter, code int, err error) {
|
||||
func(f *SessionHandler) writeError(w http.ResponseWriter, code int, err error) {
|
||||
s := err.Error()
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(s)))
|
||||
w.WriteHeader(code)
|
||||
_, err = w.Write([]byte(s))
|
||||
_, err = w.Write([]byte{})
|
||||
if err != nil {
|
||||
logg.Errorf("error writing error!!", "err", err, "olderr", s)
|
||||
w.WriteHeader(500)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (f *SessionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
func(f *SessionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
var code int
|
||||
var err error
|
||||
var perr error
|
||||
|
||||
rqs := handlers.RequestSession{
|
||||
Ctx: req.Context(),
|
||||
Ctx: req.Context(),
|
||||
Writer: w,
|
||||
}
|
||||
|
||||
|
||||
@@ -62,10 +62,10 @@
|
||||
},
|
||||
{
|
||||
"input": "1234",
|
||||
"expectedContent": "Select language:\n1:English\n2:Kiswahili"
|
||||
"expectedContent": "Select language:\n0:English\n1:Kiswahili"
|
||||
},
|
||||
{
|
||||
"input": "1",
|
||||
"input": "0",
|
||||
"expectedContent": "Your language change request was successful.\n0:Back\n9:Quit"
|
||||
},
|
||||
{
|
||||
@@ -430,7 +430,7 @@
|
||||
},
|
||||
{
|
||||
"input": "1234",
|
||||
"expectedContent": "My profile:\nName: foo bar\nGender: male\nAge: 80\nLocation: Kilifi\nYou provide: Bananas\n\n0:Back\n9:Quit"
|
||||
"expectedContent": "My profile:\nName: foo bar\nGender: male\nAge: 84\nLocation: Kilifi\nYou provide: Bananas\n\n0:Back"
|
||||
},
|
||||
{
|
||||
"input": "0",
|
||||
|
||||
@@ -298,10 +298,9 @@ func TestMainMenuSend(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
sessions := testData
|
||||
for _, session := range sessions {
|
||||
groups := driver.FilterGroupsByName(session.Groups, "send_with_invite")
|
||||
groups := driver.FilterGroupsByName(session.Groups, "send_with_invalid_inputs")
|
||||
for _, group := range groups {
|
||||
for index, step := range group.Steps {
|
||||
t.Logf("step %v with input %v", index, step.Input)
|
||||
for _, step := range group.Steps {
|
||||
cont, err := en.Exec(ctx, []byte(step.Input))
|
||||
if err != nil {
|
||||
t.Fatalf("Test case '%s' failed at input '%s': %v", group.Name, step.Input, err)
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
"steps": [
|
||||
{
|
||||
"input": "",
|
||||
"expectedContent": "Welcome to Sarafu Network\nPlease select a language\n1:English\n2:Kiswahili"
|
||||
"expectedContent": "Welcome to Sarafu Network\nPlease select a language\n0:English\n1:Kiswahili"
|
||||
},
|
||||
{
|
||||
"input": "1",
|
||||
"expectedContent": "Do you agree to terms and conditions?\nhttps://grassecon.org/pages/terms-and-conditions\n\n1:Yes\n2:No"
|
||||
"input": "0",
|
||||
"expectedContent": "Do you agree to terms and conditions?\nhttps://grassecon.org/pages/terms-and-conditions\n\n0:Yes\n1:No"
|
||||
},
|
||||
{
|
||||
"input": "1",
|
||||
"input": "0",
|
||||
"expectedContent": "Please enter a new four number PIN for your account:\n0:Exit"
|
||||
},
|
||||
{
|
||||
@@ -40,14 +40,14 @@
|
||||
"steps": [
|
||||
{
|
||||
"input": "",
|
||||
"expectedContent": "Welcome to Sarafu Network\nPlease select a language\n1:English\n2:Kiswahili"
|
||||
"expectedContent": "Welcome to Sarafu Network\nPlease select a language\n0:English\n1:Kiswahili"
|
||||
},
|
||||
{
|
||||
"input": "0",
|
||||
"expectedContent": "Do you agree to terms and conditions?\nhttps://grassecon.org/pages/terms-and-conditions\n\n0:Yes\n1:No"
|
||||
},
|
||||
{
|
||||
"input": "1",
|
||||
"expectedContent": "Do you agree to terms and conditions?\nhttps://grassecon.org/pages/terms-and-conditions\n\n1:Yes\n2:No"
|
||||
},
|
||||
{
|
||||
"input": "2",
|
||||
"expectedContent": "Thank you for using Sarafu. Goodbye!"
|
||||
}
|
||||
]
|
||||
@@ -64,8 +64,8 @@
|
||||
"expectedContent": "Enter recipient's phone number/address/alias:\n0:Back"
|
||||
},
|
||||
{
|
||||
"input": "0@0",
|
||||
"expectedContent": "0@0 is invalid, please try again:\n1:Retry\n9:Quit"
|
||||
"input": "000",
|
||||
"expectedContent": "000 is invalid, please try again:\n1:Retry\n9:Quit"
|
||||
},
|
||||
{
|
||||
"input": "1",
|
||||
|
||||
BIN
screenshots/enter_amount.jpeg
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
screenshots/enter_recipient.jpeg
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
screenshots/help_info.jpeg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
screenshots/language_select.jpeg
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
screenshots/language_set.jpeg
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
screenshots/main_menu_new.jpeg
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
screenshots/main_page.jpeg
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
screenshots/menu_new_no_alias.jpeg
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
screenshots/my_account.jpeg
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
screenshots/my_account_new.jpeg
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
screenshots/no_vouchers_node.jpeg
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
screenshots/pin_set.jpeg
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
screenshots/quit_node.jpeg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
screenshots/terms.jpeg
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
screenshots/terms_page.jpeg
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
screenshots/voucher_details.jpeg
Normal file
|
After Width: | Height: | Size: 26 KiB |
@@ -7,4 +7,3 @@ HALT
|
||||
INCMP _ 0
|
||||
INCMP my_balance 1
|
||||
INCMP community_balance 2
|
||||
INCMP . *
|
||||
|
||||
@@ -2,9 +2,9 @@ LOAD reset_account_authorized 0
|
||||
LOAD reset_incorrect 0
|
||||
CATCH incorrect_pin flag_incorrect_pin 1
|
||||
CATCH pin_entry flag_account_authorized 0
|
||||
MOUT english 1
|
||||
MOUT kiswahili 2
|
||||
MOUT english 0
|
||||
MOUT kiswahili 1
|
||||
HALT
|
||||
INCMP set_default 1
|
||||
INCMP set_swa 2
|
||||
INCMP set_default 0
|
||||
INCMP set_swa 1
|
||||
INCMP . *
|
||||
|
||||
@@ -9,4 +9,3 @@ MOUT quit 9
|
||||
HALT
|
||||
INCMP _ 0
|
||||
INCMP quit 9
|
||||
INCMP . *
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
Jina la kwanza la sasa: {{.get_current_profile_info}}
|
||||
Jina la kwanza la sasa {{.get_current_profile_info}}
|
||||
Weka majina yako ya kwanza:
|
||||
@@ -1,2 +1,2 @@
|
||||
Eneo la sasa: {{.get_current_profile_info}}
|
||||
Eneo la sasa {{.get_current_profile_info}}
|
||||
Weka eneo:
|
||||
@@ -10,4 +10,5 @@ CATCH _ flag_back_set 1
|
||||
RELOAD save_offerings
|
||||
INCMP _ 0
|
||||
CATCH pin_entry flag_offerings_set 1
|
||||
CATCH pin_entry flag_offerings_set 0
|
||||
INCMP update_profile_items *
|
||||
|
||||
@@ -20,4 +20,3 @@ INCMP edit_yob 4
|
||||
INCMP edit_location 5
|
||||
INCMP edit_offerings 6
|
||||
INCMP view_profile 7
|
||||
INCMP . *
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
Mwaka wa sasa wa kuzaliwa: {{.get_current_profile_info}}
|
||||
Mwaka wa sasa wa kuzaliwa {{.get_current_profile_info}}
|
||||
Weka mwaka wa kuzaliwa
|
||||
@@ -14,4 +14,3 @@ INCMP balances 3
|
||||
INCMP check_statement 4
|
||||
INCMP pin_management 5
|
||||
INCMP address 6
|
||||
INCMP . *
|
||||
|
||||
@@ -9,4 +9,3 @@ MOUT quit 9
|
||||
HALT
|
||||
INCMP _ 0
|
||||
INCMP quit 9
|
||||
INCMP . *
|
||||
|
||||
@@ -11,4 +11,3 @@ INCMP _ 0
|
||||
INCMP set_male 1
|
||||
INCMP set_female 2
|
||||
INCMP set_unspecified 3
|
||||
INCMP . *
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
Jinsia ya sasa: {{.get_current_profile_info}}
|
||||
Jinsia ya sasa {{.get_current_profile_info}}
|
||||
Chagua jinsia
|
||||
@@ -1,6 +1,6 @@
|
||||
MOUT english 1
|
||||
MOUT kiswahili 2
|
||||
MOUT english 0
|
||||
MOUT kiswahili 1
|
||||
HALT
|
||||
INCMP set_eng 1
|
||||
INCMP set_swa 2
|
||||
INCMP set_eng 0
|
||||
INCMP set_swa 1
|
||||
INCMP . *
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
MOUT yes 1
|
||||
MOUT no 2
|
||||
MOUT yes 0
|
||||
MOUT no 1
|
||||
HALT
|
||||
INCMP create_pin 1
|
||||
INCMP create_pin 0
|
||||
INCMP quit *
|
||||
|
||||
@@ -4,8 +4,5 @@ LOAD reset_incorrect 6
|
||||
CATCH incorrect_pin flag_incorrect_pin 1
|
||||
CATCH pin_entry flag_account_authorized 0
|
||||
MOUT back 0
|
||||
MOUT quit 9
|
||||
HALT
|
||||
INCMP _ 0
|
||||
INCMP quit 9
|
||||
INCMP . *
|
||||
|
||||