menu-options #51
@ -71,6 +71,9 @@ func getHandler(appFlags *asm.FlagParser, rs *resource.DbResource, pe *persist.P
 | 
			
		||||
	rs.AddLocalFunc("reset_incorrect_date_format", ussdHandlers.ResetIncorrectYob)
 | 
			
		||||
	rs.AddLocalFunc("set_reset_single_edit", ussdHandlers.SetResetSingleEdit)
 | 
			
		||||
	rs.AddLocalFunc("initiate_transaction", ussdHandlers.InitiateTransaction)
 | 
			
		||||
	rs.AddLocalFunc("quit_with_help", ussdHandlers.QuitWithHelp)
 | 
			
		||||
	rs.AddLocalFunc("save_temporary_pin", ussdHandlers.SaveTemporaryPin)
 | 
			
		||||
	rs.AddLocalFunc("confirm_pin_change", ussdHandlers.ConfirmPinChange)
 | 
			
		||||
 | 
			
		||||
	return ussdHandlers, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										8
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								go.mod
									
									
									
									
									
								
							@ -4,22 +4,14 @@ go 1.22.6
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	git.defalsify.org/vise.git v0.1.0-rc.3.0.20240911162138-1f2af8672dc7
 | 
			
		||||
	github.com/alecthomas/assert/v2 v2.2.2
 | 
			
		||||
	gopkg.in/leonelquinteros/gotext.v1 v1.3.1
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/alecthomas/participle/v2 v2.0.0 // indirect
 | 
			
		||||
	github.com/alecthomas/repr v0.2.0 // indirect
 | 
			
		||||
	github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c // indirect
 | 
			
		||||
	github.com/davecgh/go-spew v1.1.1 // indirect
 | 
			
		||||
	github.com/fxamacker/cbor/v2 v2.4.0 // indirect
 | 
			
		||||
	github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 // indirect
 | 
			
		||||
	github.com/hexops/gotextdiff v1.0.3 // indirect
 | 
			
		||||
	github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a // indirect
 | 
			
		||||
	github.com/pmezard/go-difflib v1.0.0 // indirect
 | 
			
		||||
	github.com/stretchr/objx v0.5.2 // indirect
 | 
			
		||||
	github.com/stretchr/testify v1.9.0
 | 
			
		||||
	github.com/x448/float16 v0.8.4 // indirect
 | 
			
		||||
	gopkg.in/yaml.v3 v3.0.1 // indirect
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										12
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								go.sum
									
									
									
									
									
								
							@ -8,8 +8,6 @@ github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk
 | 
			
		||||
github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
 | 
			
		||||
github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c h1:H9Nm+I7Cg/YVPpEV1RzU3Wq2pjamPc/UtHDgItcb7lE=
 | 
			
		||||
github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c/go.mod h1:rGod7o6KPeJ+hyBpHfhi4v7blx9sf+QsHsA7KAsdN6U=
 | 
			
		||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 | 
			
		||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
			
		||||
github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88=
 | 
			
		||||
github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
 | 
			
		||||
github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 h1:U4kkNYryi/qfbBF8gh7Vsbuz+cVmhf5kt6pE9bYYyLo=
 | 
			
		||||
@ -20,17 +18,7 @@ github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a h1:0Q3H0YXzMHiciXtRcM
 | 
			
		||||
github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a/go.mod h1:CdTTBOYzS5E4mWS1N8NWP6AHI19MP0A2B18n3hLzRMk=
 | 
			
		||||
github.com/peteole/testdata-loader v0.3.0 h1:8jckE9KcyNHgyv/VPoaljvKZE0Rqr8+dPVYH6rfNr9I=
 | 
			
		||||
github.com/peteole/testdata-loader v0.3.0/go.mod h1:Mt0ZbRtb56u8SLJpNP+BnQbENljMorYBpqlvt3cS83U=
 | 
			
		||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 | 
			
		||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 | 
			
		||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
 | 
			
		||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
 | 
			
		||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
 | 
			
		||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 | 
			
		||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
 | 
			
		||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
 | 
			
		||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 | 
			
		||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 | 
			
		||||
gopkg.in/leonelquinteros/gotext.v1 v1.3.1 h1:8d9/fdTG0kn/B7NNGV1BsEyvektXFAbkMsTZS2sFSCc=
 | 
			
		||||
gopkg.in/leonelquinteros/gotext.v1 v1.3.1/go.mod h1:X1WlGDeAFIYsW6GjgMm4VwUwZ2XjI7Zan2InxSUQWrU=
 | 
			
		||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 | 
			
		||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 | 
			
		||||
 | 
			
		||||
@ -16,10 +16,9 @@ type AccountServiceInterface interface {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AccountService struct {
 | 
			
		||||
	Client *http.Client
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// CheckAccountStatus retrieves the status of an account transaction based on the provided tracking ID.
 | 
			
		||||
//
 | 
			
		||||
// Parameters:
 | 
			
		||||
@ -27,14 +26,12 @@ type AccountService struct {
 | 
			
		||||
//     CreateAccount or a similar function that returns an AccountResponse. The `trackingId` field in the
 | 
			
		||||
//     AccountResponse struct can be used here to check the account status during a transaction.
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
// Returns:
 | 
			
		||||
//   - string: The status of the transaction as a string. If there is an error during the request or processing, this will be an empty string.
 | 
			
		||||
//   - error: An error if any occurred during the HTTP request, reading the response, or unmarshalling the JSON data.
 | 
			
		||||
//     If no error occurs, this will be nil.
 | 
			
		||||
//
 | 
			
		||||
func (as *AccountService) CheckAccountStatus(trackingId string) (string, error) {
 | 
			
		||||
	resp, err := http.Get(config.TrackStatusURL + trackingId)
 | 
			
		||||
	resp, err := as.Client.Get(config.TrackStatusURL + trackingId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
@ -50,18 +47,15 @@ func (as *AccountService) CheckAccountStatus(trackingId string) (string, error)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	status := trackResp.Result.Transaction.Status
 | 
			
		||||
 | 
			
		||||
	return status, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// CheckBalance retrieves the balance for a given public key from the custodial balance API endpoint.
 | 
			
		||||
// Parameters:
 | 
			
		||||
//   - publicKey: The public key associated with the account whose balance needs to be checked.
 | 
			
		||||
func (as *AccountService) CheckBalance(publicKey string) (string, error) {
 | 
			
		||||
 | 
			
		||||
	resp, err := http.Get(config.BalanceURL + publicKey)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "0.0", err
 | 
			
		||||
@ -83,15 +77,14 @@ func (as *AccountService) CheckBalance(publicKey string) (string, error) {
 | 
			
		||||
	return balance, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//CreateAccount creates a new account in the custodial system.
 | 
			
		||||
// CreateAccount creates a new account in the custodial system.
 | 
			
		||||
// Returns:
 | 
			
		||||
//   - *models.AccountResponse: A pointer to an AccountResponse struct containing the details of the created account.
 | 
			
		||||
//     If there is an error during the request or processing, this will be nil.
 | 
			
		||||
//   - error: An error if any occurred during the HTTP request, reading the response, or unmarshalling the JSON data.
 | 
			
		||||
//     If no error occurs, this will be nil.
 | 
			
		||||
func (as *AccountService) CreateAccount() (*models.AccountResponse, error) {
 | 
			
		||||
	resp, err := http.Post(config.CreateAccountURL, "application/json", nil)
 | 
			
		||||
	resp, err := as.Client.Post(config.CreateAccountURL, "application/json", nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@ -107,6 +100,5 @@ func (as *AccountService) CreateAccount() (*models.AccountResponse, error) {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &accountResp, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"path"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strconv"
 | 
			
		||||
@ -27,6 +28,8 @@ var (
 | 
			
		||||
	logg           = logging.NewVanilla().WithDomain("ussdmenuhandler")
 | 
			
		||||
	scriptDir      = path.Join("services", "registration")
 | 
			
		||||
	translationDir = path.Join(scriptDir, "locale")
 | 
			
		||||
	validPin =  4
 | 
			
		||||
	validYOB = 4
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type FSData struct {
 | 
			
		||||
@ -73,10 +76,13 @@ func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db) (*Handlers, erro
 | 
			
		||||
	userDb := &utils.UserDataStore{
 | 
			
		||||
		Db: userdataStore,
 | 
			
		||||
	}
 | 
			
		||||
	client := &http.Client{}
 | 
			
		||||
	h := &Handlers{
 | 
			
		||||
		userdataStore:      userDb,
 | 
			
		||||
		flagManager:        appFlags,
 | 
			
		||||
		accountService:     &server.AccountService{},
 | 
			
		||||
		userdataStore: userDb,
 | 
			
		||||
		flagManager:   appFlags,
 | 
			
		||||
		accountService: &server.AccountService{
 | 
			
		||||
			Client: client,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	return h, nil
 | 
			
		||||
}
 | 
			
		||||
@ -188,6 +194,48 @@ func (h *Handlers) CreateAccount(ctx context.Context, sym string, input []byte)
 | 
			
		||||
	return res, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byte) (resource.Result, error) {
 | 
			
		||||
	var res resource.Result
 | 
			
		||||
	var err error
 | 
			
		||||
 | 
			
		||||
	sessionId, ok := ctx.Value("SessionId").(string)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return res, fmt.Errorf("missing session")
 | 
			
		||||
	}
 | 
			
		||||
	flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin")
 | 
			
		||||
 | 
			
		||||
	accountPIN := string(input)
 | 
			
		||||
	// Validate that the PIN is a 4-digit number
 | 
			
		||||
	if !isValidPIN(accountPIN) {
 | 
			
		||||
		res.FlagSet = append(res.FlagSet, flag_incorrect_pin)
 | 
			
		||||
		return res, nil
 | 
			
		||||
	}
 | 
			
		||||
	store := h.userdataStore
 | 
			
		||||
	err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_PIN, []byte(accountPIN))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return res, err
 | 
			
		||||
	}
 | 
			
		||||
	return res, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *Handlers) ConfirmPinChange(ctx context.Context, sym string, input []byte) (resource.Result, error) {
 | 
			
		||||
	var res resource.Result
 | 
			
		||||
	sessionId, ok := ctx.Value("SessionId").(string)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return res, fmt.Errorf("missing session")
 | 
			
		||||
	}
 | 
			
		||||
	store := h.userdataStore
 | 
			
		||||
	temporaryPin, err := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_PIN)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return res, err
 | 
			
		||||
	}
 | 
			
		||||
	err = store.WriteEntry(ctx, sessionId, utils.DATA_ACCOUNT_PIN, []byte(temporaryPin))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return res, err
 | 
			
		||||
	}
 | 
			
		||||
	return res, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SavePin persists the user's PIN choice into the filesystem
 | 
			
		||||
func (h *Handlers) SavePin(ctx context.Context, sym string, input []byte) (resource.Result, error) {
 | 
			
		||||
	var res resource.Result
 | 
			
		||||
@ -256,15 +304,19 @@ func (h *Handlers) VerifyPin(ctx context.Context, sym string, input []byte) (res
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return res, fmt.Errorf("missing session")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//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
 | 
			
		||||
	}
 | 
			
		||||
	TemporaryPIn, err := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_PIN)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if !db.IsNotFound(err) {
 | 
			
		||||
			return res, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if bytes.Equal(input, AccountPin) {
 | 
			
		||||
	if bytes.Equal(input, AccountPin) || bytes.Equal(input, TemporaryPIn) {
 | 
			
		||||
		res.FlagSet = []uint32{flag_valid_pin}
 | 
			
		||||
		res.FlagReset = []uint32{flag_pin_mismatch}
 | 
			
		||||
		res.FlagSet = append(res.FlagSet, flag_pin_set)
 | 
			
		||||
@ -322,9 +374,6 @@ func (h *Handlers) SaveFamilyname(ctx context.Context, sym string, input []byte)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return res, err
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return res, nil
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		return res, fmt.Errorf("a family name cannot be less than one character")
 | 
			
		||||
	}
 | 
			
		||||
@ -341,7 +390,7 @@ func (h *Handlers) SaveYob(ctx context.Context, sym string, input []byte) (resou
 | 
			
		||||
		return res, fmt.Errorf("missing session")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(input) == 4 {
 | 
			
		||||
	if len(input) == validPin {
 | 
			
		||||
		yob := string(input)
 | 
			
		||||
		store := h.userdataStore
 | 
			
		||||
		err = store.WriteEntry(ctx, sessionId, utils.DATA_YOB, []byte(yob))
 | 
			
		||||
@ -481,22 +530,19 @@ func (h *Handlers) Authorize(ctx context.Context, sym string, input []byte) (res
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return res, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		if len(input) == 4 {
 | 
			
		||||
			if bytes.Equal(input, AccountPin) {
 | 
			
		||||
				if h.st.MatchFlag(flag_account_authorized, false) {
 | 
			
		||||
					res.FlagReset = append(res.FlagReset, flag_incorrect_pin)
 | 
			
		||||
					res.FlagSet = append(res.FlagSet, flag_allow_update, flag_account_authorized)
 | 
			
		||||
				} else {
 | 
			
		||||
					res.FlagSet = append(res.FlagSet, flag_allow_update)
 | 
			
		||||
					res.FlagReset = append(res.FlagReset, flag_account_authorized)
 | 
			
		||||
				}
 | 
			
		||||
	if len(input) == validPin {
 | 
			
		||||
		if bytes.Equal(input, AccountPin) {
 | 
			
		||||
| 
					
	
	
	
	
	
	
	
	 
					
					carlos marked this conversation as resolved
					
				 
				 | 
			||||
			if h.st.MatchFlag(flag_account_authorized, false) {
 | 
			
		||||
				res.FlagReset = append(res.FlagReset, flag_incorrect_pin)
 | 
			
		||||
				res.FlagSet = append(res.FlagSet, flag_allow_update, flag_account_authorized)
 | 
			
		||||
			} else {
 | 
			
		||||
				res.FlagSet = append(res.FlagSet, flag_incorrect_pin)
 | 
			
		||||
				res.FlagSet = append(res.FlagSet, flag_allow_update)
 | 
			
		||||
				res.FlagReset = append(res.FlagReset, flag_account_authorized)
 | 
			
		||||
				return res, nil
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			res.FlagSet = append(res.FlagSet, flag_incorrect_pin)
 | 
			
		||||
			res.FlagReset = append(res.FlagReset, flag_account_authorized)
 | 
			
		||||
			return res, nil
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		return res, nil
 | 
			
		||||
@ -543,7 +589,6 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return res, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if status == "SUCCESS" {
 | 
			
		||||
		res.FlagSet = append(res.FlagSet, flag_account_success)
 | 
			
		||||
		res.FlagReset = append(res.FlagReset, flag_account_pending)
 | 
			
		||||
@ -569,6 +614,21 @@ func (h *Handlers) Quit(ctx context.Context, sym string, input []byte) (resource
 | 
			
		||||
	return res, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// QuitWithHelp displays helpline information then exits the menu
 | 
			
		||||
func (h *Handlers) QuitWithHelp(ctx context.Context, sym string, input []byte) (resource.Result, error) {
 | 
			
		||||
	var res resource.Result
 | 
			
		||||
 | 
			
		||||
	flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized")
 | 
			
		||||
 | 
			
		||||
	code := codeFromCtx(ctx)
 | 
			
		||||
	l := gotext.NewLocale(translationDir, code)
 | 
			
		||||
	l.AddDomain("default")
 | 
			
		||||
 | 
			
		||||
	res.Content = l.Get("For more help,please call: 0757628885")
 | 
			
		||||
	res.FlagReset = append(res.FlagReset, flag_account_authorized)
 | 
			
		||||
| 
					
	
	
	
	
	
	
	
	 
				
					
						lash
						commented  
			
		This should be a config variable. Let's put it as a global variable for now. You are sure this cannot be solved with a template? This should be a config variable. Let's put it as a global variable for now.
You are sure this cannot be solved with a template? 
			
			
		 | 
			||||
	return res, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// VerifyYob verifies the length of the given input
 | 
			
		||||
func (h *Handlers) VerifyYob(ctx context.Context, sym string, input []byte) (resource.Result, error) {
 | 
			
		||||
	var res resource.Result
 | 
			
		||||
@ -584,7 +644,7 @@ func (h *Handlers) VerifyYob(ctx context.Context, sym string, input []byte) (res
 | 
			
		||||
		return res, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(date) == 4 {
 | 
			
		||||
	if len(date) == validYOB {
 | 
			
		||||
		res.FlagReset = append(res.FlagReset, flag_incorrect_date_format)
 | 
			
		||||
	} else {
 | 
			
		||||
		res.FlagSet = append(res.FlagSet, flag_incorrect_date_format)
 | 
			
		||||
@ -748,7 +808,8 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte)
 | 
			
		||||
 | 
			
		||||
	flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount")
 | 
			
		||||
 | 
			
		||||
	publicKey, _ := utils.ReadEntry(ctx, h.userdataStore, sessionId, utils.DATA_PUBLIC_KEY)
 | 
			
		||||
	store := h.userdataStore
 | 
			
		||||
	publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY)
 | 
			
		||||
 | 
			
		||||
	amountStr := string(input)
 | 
			
		||||
 | 
			
		||||
@ -757,6 +818,7 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return res, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res.Content = balanceStr
 | 
			
		||||
 | 
			
		||||
	// Parse the balance
 | 
			
		||||
@ -764,6 +826,7 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte)
 | 
			
		||||
	if len(balanceParts) != 2 {
 | 
			
		||||
		return res, fmt.Errorf("unexpected balance format: %s", balanceStr)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	balanceValue, err := strconv.ParseFloat(balanceParts[0], 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return res, fmt.Errorf("failed to parse balance: %v", err)
 | 
			
		||||
@ -773,6 +836,7 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte)
 | 
			
		||||
	re := regexp.MustCompile(`^(\d+(\.\d+)?)\s*(?:CELO)?$`)
 | 
			
		||||
	matches := re.FindStringSubmatch(strings.TrimSpace(amountStr))
 | 
			
		||||
	if len(matches) < 2 {
 | 
			
		||||
 | 
			
		||||
		res.FlagSet = append(res.FlagSet, flag_invalid_amount)
 | 
			
		||||
		res.Content = amountStr
 | 
			
		||||
		return res, nil
 | 
			
		||||
@ -780,6 +844,7 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte)
 | 
			
		||||
 | 
			
		||||
	inputAmount, err := strconv.ParseFloat(matches[1], 64)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
 | 
			
		||||
		res.FlagSet = append(res.FlagSet, flag_invalid_amount)
 | 
			
		||||
		res.Content = amountStr
 | 
			
		||||
		return res, nil
 | 
			
		||||
@ -792,7 +857,7 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	res.Content = fmt.Sprintf("%.3f", inputAmount) // Format to 3 decimal places
 | 
			
		||||
	store := h.userdataStore
 | 
			
		||||
	store = h.userdataStore
 | 
			
		||||
	err = store.WriteEntry(ctx, sessionId, utils.DATA_AMOUNT, []byte(amountStr))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return res, err
 | 
			
		||||
 | 
			
		||||
@ -1,320 +0,0 @@
 | 
			
		||||
package ussd
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"git.defalsify.org/vise.git/resource"
 | 
			
		||||
	"git.grassecon.net/urdt/ussd/internal/handlers/ussd/mocks"
 | 
			
		||||
	"git.grassecon.net/urdt/ussd/internal/utils"
 | 
			
		||||
	"github.com/alecthomas/assert/v2"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestSaveFirstname(t *testing.T) {
 | 
			
		||||
	// Create a new instance of MockMyDataStore
 | 
			
		||||
	mockStore := new(mocks.MockUserDataStore)
 | 
			
		||||
 | 
			
		||||
	// Define test data
 | 
			
		||||
	sessionId := "session123"
 | 
			
		||||
	firstName := "John"
 | 
			
		||||
	ctx := context.WithValue(context.Background(), "SessionId", sessionId)
 | 
			
		||||
 | 
			
		||||
	// Set up the expected behavior of the mock
 | 
			
		||||
	mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_FIRST_NAME, []byte(firstName)).Return(nil)
 | 
			
		||||
 | 
			
		||||
	// Create the Handlers instance with the mock store
 | 
			
		||||
	h := &Handlers{
 | 
			
		||||
		userdataStore: mockStore,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Call the method
 | 
			
		||||
	res, err := h.SaveFirstname(ctx, "save_firstname", []byte(firstName))
 | 
			
		||||
 | 
			
		||||
	// Assert results
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, resource.Result{}, res)
 | 
			
		||||
 | 
			
		||||
	// Assert all expectations were met
 | 
			
		||||
	mockStore.AssertExpectations(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSaveFamilyname(t *testing.T) {
 | 
			
		||||
	// Create a new instance of UserDataStore
 | 
			
		||||
	mockStore := new(mocks.MockUserDataStore)
 | 
			
		||||
 | 
			
		||||
	// Define test data
 | 
			
		||||
	sessionId := "session123"
 | 
			
		||||
	familyName := "Doeee"
 | 
			
		||||
	ctx := context.WithValue(context.Background(), "SessionId", sessionId)
 | 
			
		||||
 | 
			
		||||
	// Set up the expected behavior of the mock
 | 
			
		||||
	mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_FAMILY_NAME, []byte(familyName)).Return(nil)
 | 
			
		||||
 | 
			
		||||
	// Create the Handlers instance with the mock store
 | 
			
		||||
	h := &Handlers{
 | 
			
		||||
		userdataStore: mockStore,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Call the method
 | 
			
		||||
	res, err := h.SaveFamilyname(ctx, "save_familyname", []byte(familyName))
 | 
			
		||||
 | 
			
		||||
	// Assert results
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, resource.Result{}, res)
 | 
			
		||||
 | 
			
		||||
	// Assert all expectations were met
 | 
			
		||||
	mockStore.AssertExpectations(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSaveYoB(t *testing.T) {
 | 
			
		||||
	// Create a new instance of MockMyDataStore
 | 
			
		||||
	mockStore := new(mocks.MockUserDataStore)
 | 
			
		||||
 | 
			
		||||
	// Define test data
 | 
			
		||||
	sessionId := "session123"
 | 
			
		||||
	yob := "1980"
 | 
			
		||||
	ctx := context.WithValue(context.Background(), "SessionId", sessionId)
 | 
			
		||||
 | 
			
		||||
	// Set up the expected behavior of the mock
 | 
			
		||||
	mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_YOB, []byte(yob)).Return(nil)
 | 
			
		||||
 | 
			
		||||
	// Create the Handlers instance with the mock store
 | 
			
		||||
	h := &Handlers{
 | 
			
		||||
		userdataStore: mockStore,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Call the method
 | 
			
		||||
	res, err := h.SaveYob(ctx, "save_yob", []byte(yob))
 | 
			
		||||
 | 
			
		||||
	// Assert results
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, resource.Result{}, res)
 | 
			
		||||
 | 
			
		||||
	// Assert all expectations were met
 | 
			
		||||
	mockStore.AssertExpectations(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSaveLocation(t *testing.T) {
 | 
			
		||||
	// Create a new instance of MockMyDataStore
 | 
			
		||||
	mockStore := new(mocks.MockUserDataStore)
 | 
			
		||||
 | 
			
		||||
	// Define test data
 | 
			
		||||
	sessionId := "session123"
 | 
			
		||||
	yob := "Kilifi"
 | 
			
		||||
	ctx := context.WithValue(context.Background(), "SessionId", sessionId)
 | 
			
		||||
 | 
			
		||||
	// Set up the expected behavior of the mock
 | 
			
		||||
	mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_LOCATION, []byte(yob)).Return(nil)
 | 
			
		||||
 | 
			
		||||
	// Create the Handlers instance with the mock store
 | 
			
		||||
	h := &Handlers{
 | 
			
		||||
		userdataStore: mockStore,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Call the method
 | 
			
		||||
	res, err := h.SaveLocation(ctx, "save_location", []byte(yob))
 | 
			
		||||
 | 
			
		||||
	// Assert results
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, resource.Result{}, res)
 | 
			
		||||
 | 
			
		||||
	// Assert all expectations were met
 | 
			
		||||
	mockStore.AssertExpectations(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSaveGender(t *testing.T) {
 | 
			
		||||
	// Create a new instance of MockMyDataStore
 | 
			
		||||
	mockStore := new(mocks.MockUserDataStore)
 | 
			
		||||
 | 
			
		||||
	// Define the session ID and context
 | 
			
		||||
	sessionId := "session123"
 | 
			
		||||
	ctx := context.WithValue(context.Background(), "SessionId", sessionId)
 | 
			
		||||
 | 
			
		||||
	// Define test cases
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name           string
 | 
			
		||||
		input          []byte
 | 
			
		||||
		expectedGender string
 | 
			
		||||
		expectCall     bool
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			name:           "Valid Male Input",
 | 
			
		||||
			input:          []byte("1"),
 | 
			
		||||
			expectedGender: "Male",
 | 
			
		||||
			expectCall:     true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:           "Valid Female Input",
 | 
			
		||||
			input:          []byte("2"),
 | 
			
		||||
			expectedGender: "Female",
 | 
			
		||||
			expectCall:     true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:           "Valid Unspecified Input",
 | 
			
		||||
			input:          []byte("3"),
 | 
			
		||||
			expectedGender: "Unspecified",
 | 
			
		||||
			expectCall:     true,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:           "Empty Input",
 | 
			
		||||
			input:          []byte(""),
 | 
			
		||||
			expectedGender: "",
 | 
			
		||||
			expectCall:     false,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			// Set up expectations for the mock database
 | 
			
		||||
			if tt.expectCall {
 | 
			
		||||
				expectedKey := utils.DATA_GENDER
 | 
			
		||||
				mockStore.On("WriteEntry", ctx, sessionId, expectedKey, []byte(tt.expectedGender)).Return(nil)
 | 
			
		||||
			} else {
 | 
			
		||||
				mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_GENDER, []byte(tt.expectedGender)).Return(nil)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Create the Handlers instance with the mock store
 | 
			
		||||
			h := &Handlers{
 | 
			
		||||
				userdataStore: mockStore,
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Call the method
 | 
			
		||||
			_, err := h.SaveGender(ctx, "someSym", tt.input)
 | 
			
		||||
 | 
			
		||||
			// Assert no error
 | 
			
		||||
			assert.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
			// Verify expectations
 | 
			
		||||
			if tt.expectCall {
 | 
			
		||||
				mockStore.AssertCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_GENDER, []byte(tt.expectedGender))
 | 
			
		||||
			} else {
 | 
			
		||||
				mockStore.AssertNotCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_GENDER, []byte(tt.expectedGender))
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCheckIdentifier(t *testing.T) {
 | 
			
		||||
	// Create a new instance of MockMyDataStore
 | 
			
		||||
	mockStore := new(mocks.MockUserDataStore)
 | 
			
		||||
 | 
			
		||||
	// Define the session ID and context
 | 
			
		||||
	sessionId := "session123"
 | 
			
		||||
	ctx := context.WithValue(context.Background(), "SessionId", sessionId)
 | 
			
		||||
 | 
			
		||||
	// Define test cases
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		name            string
 | 
			
		||||
		mockPublicKey   []byte
 | 
			
		||||
		mockErr         error
 | 
			
		||||
		expectedContent string
 | 
			
		||||
		expectError     bool
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			name:            "Saved public Key",
 | 
			
		||||
			mockPublicKey:   []byte("0xa8363"),
 | 
			
		||||
			mockErr:         nil,
 | 
			
		||||
			expectedContent: "0xa8363",
 | 
			
		||||
			expectError:     false,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		t.Run(tt.name, func(t *testing.T) {
 | 
			
		||||
			// Set up expectations for the mock database
 | 
			
		||||
			mockStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return(tt.mockPublicKey, tt.mockErr)
 | 
			
		||||
 | 
			
		||||
			// Create the Handlers instance with the mock store
 | 
			
		||||
			h := &Handlers{
 | 
			
		||||
				userdataStore: mockStore,
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Call the method
 | 
			
		||||
			res, err := h.CheckIdentifier(ctx, "check_identifier", nil)
 | 
			
		||||
 | 
			
		||||
			// Assert results
 | 
			
		||||
 | 
			
		||||
			assert.NoError(t, err)
 | 
			
		||||
			assert.Equal(t, tt.expectedContent, res.Content)
 | 
			
		||||
 | 
			
		||||
			// Verify expectations
 | 
			
		||||
			mockStore.AssertExpectations(t)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestMaxAmount(t *testing.T) {
 | 
			
		||||
	mockStore := new(mocks.MockUserDataStore)
 | 
			
		||||
	mockCreateAccountService := new(mocks.MockAccountService)
 | 
			
		||||
 | 
			
		||||
	// Define test data
 | 
			
		||||
	sessionId := "session123"
 | 
			
		||||
	ctx := context.WithValue(context.Background(), "SessionId", sessionId)
 | 
			
		||||
	publicKey := "0xcasgatweksalw1018221"
 | 
			
		||||
	expectedBalance := "0.003CELO"
 | 
			
		||||
 | 
			
		||||
	// Set up the expected behavior of the mock
 | 
			
		||||
	mockStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil)
 | 
			
		||||
	mockCreateAccountService.On("CheckBalance", publicKey).Return(expectedBalance, nil)
 | 
			
		||||
 | 
			
		||||
	// Create the Handlers instance with the mock store
 | 
			
		||||
	h := &Handlers{
 | 
			
		||||
		userdataStore:  mockStore,
 | 
			
		||||
		accountService: mockCreateAccountService,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Call the method
 | 
			
		||||
	res, _ := h.MaxAmount(ctx, "max_amount", []byte("check_balance"))
 | 
			
		||||
 | 
			
		||||
	//Assert that the balance that was set as the result content is what was returned by  Check Balance
 | 
			
		||||
	assert.Equal(t, expectedBalance, res.Content)
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetSender(t *testing.T) {
 | 
			
		||||
	mockStore := new(mocks.MockUserDataStore)
 | 
			
		||||
 | 
			
		||||
	// Define test data
 | 
			
		||||
	sessionId := "session123"
 | 
			
		||||
	ctx := context.WithValue(context.Background(), "SessionId", sessionId)
 | 
			
		||||
	publicKey := "0xcasgatweksalw1018221"
 | 
			
		||||
 | 
			
		||||
	// Set up the expected behavior of the mock
 | 
			
		||||
	mockStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil)
 | 
			
		||||
 | 
			
		||||
	// Create the Handlers instance with the mock store
 | 
			
		||||
	h := &Handlers{
 | 
			
		||||
		userdataStore: mockStore,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Call the method
 | 
			
		||||
	res, _ := h.GetSender(ctx, "max_amount", []byte("check_balance"))
 | 
			
		||||
 | 
			
		||||
	//Assert that the public key from readentry operation  is what was set as the result content.
 | 
			
		||||
	assert.Equal(t, publicKey, res.Content)
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetAmount(t *testing.T) {
 | 
			
		||||
	mockStore := new(mocks.MockUserDataStore)
 | 
			
		||||
 | 
			
		||||
	// Define test data
 | 
			
		||||
	sessionId := "session123"
 | 
			
		||||
	ctx := context.WithValue(context.Background(), "SessionId", sessionId)
 | 
			
		||||
	Amount := "0.03CELO"
 | 
			
		||||
 | 
			
		||||
	// Set up the expected behavior of the mock
 | 
			
		||||
	mockStore.On("ReadEntry", ctx, sessionId, utils.DATA_AMOUNT).Return([]byte(Amount), nil)
 | 
			
		||||
 | 
			
		||||
	// Create the Handlers instance with the mock store
 | 
			
		||||
	h := &Handlers{
 | 
			
		||||
		userdataStore: mockStore,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Call the method
 | 
			
		||||
	res, _ := h.GetAmount(ctx, "get_amount", []byte("Getting amount..."))
 | 
			
		||||
 | 
			
		||||
	//Assert that the retrieved amount is what was set as the content
 | 
			
		||||
	assert.Equal(t, Amount, res.Content)
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -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)
 | 
			
		||||
}
 | 
			
		||||
@ -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)
 | 
			
		||||
}
 | 
			
		||||
@ -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)
 | 
			
		||||
}
 | 
			
		||||
@ -1,10 +1,7 @@
 | 
			
		||||
package utils
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
 | 
			
		||||
	"git.defalsify.org/vise.git/db"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type DataTyp uint16
 | 
			
		||||
@ -25,6 +22,7 @@ const (
 | 
			
		||||
	DATA_OFFERINGS
 | 
			
		||||
	DATA_RECIPIENT
 | 
			
		||||
	DATA_AMOUNT
 | 
			
		||||
	DATA_TEMPORARY_PIN
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func typToBytes(typ DataTyp) []byte {
 | 
			
		||||
@ -37,21 +35,3 @@ func PackKey(typ DataTyp, data []byte) []byte {
 | 
			
		||||
	v := typToBytes(typ)
 | 
			
		||||
	return append(v, data...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ReadEntry(ctx context.Context, store db.Db, sessionId string, typ DataTyp) ([]byte, error) {
 | 
			
		||||
	store.SetPrefix(db.DATATYPE_USERDATA)
 | 
			
		||||
	store.SetSession(sessionId)
 | 
			
		||||
	k := PackKey(typ, []byte(sessionId))
 | 
			
		||||
	b, err := store.Get(ctx, k)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return b, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func WriteEntry(ctx context.Context, store db.Db, 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)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								services/registration/confirm_pin_change
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								services/registration/confirm_pin_change
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
Confirm your new PIN:
 | 
			
		||||
							
								
								
									
										7
									
								
								services/registration/confirm_pin_change.vis
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								services/registration/confirm_pin_change.vis
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
LOAD verify_pin 0
 | 
			
		||||
MOUT back 0
 | 
			
		||||
HALT
 | 
			
		||||
RELOAD verify_pin
 | 
			
		||||
CATCH  create_pin_mismatch flag_pin_mismatch 1
 | 
			
		||||
MOVE pin_reset_success
 | 
			
		||||
INCMP _ 0
 | 
			
		||||
							
								
								
									
										2
									
								
								services/registration/help.vis
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								services/registration/help.vis
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
			
		||||
LOAD quit_with_help 0
 | 
			
		||||
HALT
 | 
			
		||||
							
								
								
									
										1
									
								
								services/registration/invalid_pin
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								services/registration/invalid_pin
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
The PIN you entered is invalid.The PIN must be different from your current PIN.For help call +254757628885
 | 
			
		||||
							
								
								
									
										4
									
								
								services/registration/invalid_pin.vis
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								services/registration/invalid_pin.vis
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
			
		||||
MOUT back 0
 | 
			
		||||
HALT
 | 
			
		||||
INCMP _ 0
 | 
			
		||||
 | 
			
		||||
@ -6,3 +6,6 @@ msgstr "Ombi lako limetumwa. %s atapokea %s kutoka kwa %s."
 | 
			
		||||
 | 
			
		||||
msgid "Thank you for using Sarafu. Goodbye!"
 | 
			
		||||
msgstr "Asante kwa kutumia huduma ya Sarafu. Kwaheri!"
 | 
			
		||||
 | 
			
		||||
msgid "For more help,please call: 0757628885"
 | 
			
		||||
msgstr "Kwa usaidizi zaidi,piga: 0757628885"
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,6 @@ HALT
 | 
			
		||||
INCMP send 1
 | 
			
		||||
INCMP quit 2
 | 
			
		||||
INCMP my_account 3
 | 
			
		||||
INCMP quit 4
 | 
			
		||||
INCMP help 4
 | 
			
		||||
INCMP quit 9
 | 
			
		||||
INCMP . *
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								services/registration/new_pin
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								services/registration/new_pin
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
Enter a new four number pin
 | 
			
		||||
							
								
								
									
										7
									
								
								services/registration/new_pin.vis
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								services/registration/new_pin.vis
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
LOAD save_temporary_pin 0
 | 
			
		||||
MOUT back 0
 | 
			
		||||
HALT
 | 
			
		||||
RELOAD save_temporary_pin
 | 
			
		||||
CATCH invalid_pin flag_incorrect_pin 1
 | 
			
		||||
INCMP _ 0
 | 
			
		||||
MOVE confirm_pin_change 
 | 
			
		||||
							
								
								
									
										1
									
								
								services/registration/old_pin
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								services/registration/old_pin
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
Enter your old PIN
 | 
			
		||||
							
								
								
									
										9
									
								
								services/registration/old_pin.vis
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								services/registration/old_pin.vis
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
			
		||||
LOAD authorize_account 6
 | 
			
		||||
MOUT back 0
 | 
			
		||||
HALT
 | 
			
		||||
RELOAD authorize_account
 | 
			
		||||
CATCH incorrect_pin flag_incorrect_pin 1
 | 
			
		||||
MOVE new_pin
 | 
			
		||||
INCMP _ 0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4,3 +4,4 @@ MOUT guard_pin 3
 | 
			
		||||
MOUT back 0
 | 
			
		||||
HALT
 | 
			
		||||
INCMP _ 0
 | 
			
		||||
INCMP old_pin  1
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								services/registration/pin_reset_success
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								services/registration/pin_reset_success
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
Your PIN change request has been successful
 | 
			
		||||
							
								
								
									
										6
									
								
								services/registration/pin_reset_success.vis
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								services/registration/pin_reset_success.vis
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
			
		||||
LOAD confirm_pin_change 0
 | 
			
		||||
MOUT back 0
 | 
			
		||||
MOUT quit 9
 | 
			
		||||
HALT
 | 
			
		||||
INCMP _ 0
 | 
			
		||||
INCMP quit 9
 | 
			
		||||
@ -1,3 +1,4 @@
 | 
			
		||||
LOAD authorize_account 6
 | 
			
		||||
MAP validate_amount
 | 
			
		||||
RELOAD get_recipient
 | 
			
		||||
MAP get_recipient
 | 
			
		||||
@ -6,9 +7,9 @@ MAP get_sender
 | 
			
		||||
MOUT back 0
 | 
			
		||||
MOUT quit 9
 | 
			
		||||
HALT
 | 
			
		||||
LOAD authorize_account 6
 | 
			
		||||
RELOAD authorize_account
 | 
			
		||||
CATCH incorrect_pin flag_incorrect_pin 1
 | 
			
		||||
CATCH transaction_initiated flag_account_authorized 1
 | 
			
		||||
INCMP _ 0
 | 
			
		||||
INCMP quit 9
 | 
			
		||||
INCMP transaction_initiated *
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	
can you please put the pin length in a global variable and replace all similar occurrences and check with that?