From 188cb573dd713278b417d8fab9ea1bdc0ec6f9cb Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 25 Sep 2024 13:27:13 +0300 Subject: [PATCH 001/289] add dummy vouchers list --- internal/handlers/handlerservice.go | 1 + internal/handlers/ussd/menuhandler.go | 32 ++++++++++++++++++++++++ services/registration/main.vis | 2 +- services/registration/select_voucher | 2 ++ services/registration/select_voucher.vis | 9 +++++++ 5 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 services/registration/select_voucher create mode 100644 services/registration/select_voucher.vis diff --git a/internal/handlers/handlerservice.go b/internal/handlers/handlerservice.go index 1d6f5fd..b733efe 100644 --- a/internal/handlers/handlerservice.go +++ b/internal/handlers/handlerservice.go @@ -94,6 +94,7 @@ func (ls *LocalHandlerService) GetHandler() (*ussd.Handlers, error) { ls.DbRs.AddLocalFunc("verify_new_pin", ussdHandlers.VerifyNewPin) ls.DbRs.AddLocalFunc("confirm_pin_change", ussdHandlers.ConfirmPinChange) ls.DbRs.AddLocalFunc("quit_with_help", ussdHandlers.QuitWithHelp) + ls.DbRs.AddLocalFunc("get_vouchers",ussdHandlers.GetVoucherList) return ussdHandlers, nil } diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index ff8d8bd..7902cd2 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -254,6 +254,38 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt return res, nil } + +func (h *Handlers) GetVoucherList(ctx context.Context,sym string,input []byte) (resource.Result,error){ + var res resource.Result + vouchers := []string{ + "SRF", + "CRF", + "VCF", + "VSAPA", + "FSTMP", + "FSAW", + "PTAQ", + "VCRXT", + "VSGAQ", + "QPWIQQ", + "FSTMP", + "FSAW", + "PTAQ", + "VCRXT", + "VSGAQ", + "QPWIQQ", + "FSTMP", + "FSAW", + "PTAQ", + "VCRXT", + "VSGAQ", + "QPWIQQ", + } + res.Content = strings.Join(vouchers,"\n") + + 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) diff --git a/services/registration/main.vis b/services/registration/main.vis index d883dca..b5d791d 100644 --- a/services/registration/main.vis +++ b/services/registration/main.vis @@ -8,7 +8,7 @@ MOUT help 4 MOUT quit 9 HALT INCMP send 1 -INCMP quit 2 +INCMP select_voucher 2 INCMP my_account 3 INCMP help 4 INCMP quit 9 diff --git a/services/registration/select_voucher b/services/registration/select_voucher new file mode 100644 index 0000000..084b9b8 --- /dev/null +++ b/services/registration/select_voucher @@ -0,0 +1,2 @@ +Select number or symbol from your vouchers: +{{.get_vouchers}} \ No newline at end of file diff --git a/services/registration/select_voucher.vis b/services/registration/select_voucher.vis new file mode 100644 index 0000000..3919f71 --- /dev/null +++ b/services/registration/select_voucher.vis @@ -0,0 +1,9 @@ +LOAD get_vouchers 0 +MAP get_vouchers +MNEXT next 11 +MPREV back 22 +HALT +INCMP > 11 +INCMP < 22 +INCMP _* + From 7aa44caea27c8e45f5ac2a02e20c123430ccf0fa Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 25 Sep 2024 15:57:23 +0300 Subject: [PATCH 002/289] add voucher nodes --- services/registration/main.vis | 2 +- services/registration/my_vouchers | 1 + services/registration/my_vouchers.vis | 9 +++++++++ services/registration/select_voucher_menu | 1 + services/registration/voucher_details_menu | 1 + 5 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 services/registration/my_vouchers create mode 100644 services/registration/my_vouchers.vis create mode 100644 services/registration/select_voucher_menu create mode 100644 services/registration/voucher_details_menu diff --git a/services/registration/main.vis b/services/registration/main.vis index b5d791d..1009039 100644 --- a/services/registration/main.vis +++ b/services/registration/main.vis @@ -8,7 +8,7 @@ MOUT help 4 MOUT quit 9 HALT INCMP send 1 -INCMP select_voucher 2 +INCMP my_vouchers 2 INCMP my_account 3 INCMP help 4 INCMP quit 9 diff --git a/services/registration/my_vouchers b/services/registration/my_vouchers new file mode 100644 index 0000000..548de9c --- /dev/null +++ b/services/registration/my_vouchers @@ -0,0 +1 @@ +My vouchers \ No newline at end of file diff --git a/services/registration/my_vouchers.vis b/services/registration/my_vouchers.vis new file mode 100644 index 0000000..b70dbfa --- /dev/null +++ b/services/registration/my_vouchers.vis @@ -0,0 +1,9 @@ +MOUT select_voucher 1 +MOUT voucher_details 2 +MOUT back 0 +HALT +INCMP _ 0 +INCMP select_voucher 1 + + + diff --git a/services/registration/select_voucher_menu b/services/registration/select_voucher_menu new file mode 100644 index 0000000..8ee06df --- /dev/null +++ b/services/registration/select_voucher_menu @@ -0,0 +1 @@ +Select voucher \ No newline at end of file diff --git a/services/registration/voucher_details_menu b/services/registration/voucher_details_menu new file mode 100644 index 0000000..a588f23 --- /dev/null +++ b/services/registration/voucher_details_menu @@ -0,0 +1 @@ +Voucher details \ No newline at end of file From 0e376e0d9e0bc7164bff7e4314c8ffb74ce5306a Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 25 Sep 2024 16:03:08 +0300 Subject: [PATCH 003/289] include back and quit --- services/registration/select_voucher.vis | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/services/registration/select_voucher.vis b/services/registration/select_voucher.vis index 3919f71..4fb1d40 100644 --- a/services/registration/select_voucher.vis +++ b/services/registration/select_voucher.vis @@ -1,9 +1,11 @@ LOAD get_vouchers 0 MAP get_vouchers +MOUT back 0 +MOUT quit 9 MNEXT next 11 -MPREV back 22 +MPREV prev 22 HALT +INCMP _ 0 +INCMP quit 9 INCMP > 11 INCMP < 22 -INCMP _* - From 221db4e998ce4b5bcda91e6f99ec3aec18f28fbb Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 25 Sep 2024 16:06:06 +0300 Subject: [PATCH 004/289] return a numbered list of vouchers --- internal/handlers/ussd/menuhandler.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 7902cd2..e998bd5 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -281,7 +281,12 @@ func (h *Handlers) GetVoucherList(ctx context.Context,sym string,input []byte) ( "VSGAQ", "QPWIQQ", } - res.Content = strings.Join(vouchers,"\n") + + var numberedVouchers []string + for i, voucher := range vouchers { + numberedVouchers = append(numberedVouchers, fmt.Sprintf("%d:%s", i+1, voucher)) + } + res.Content = strings.Join(numberedVouchers,"\n") return res,nil } From 4c339450810a8ee212b2fe464fac847f567f7ad8 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 27 Sep 2024 19:10:08 +0300 Subject: [PATCH 005/289] use latest go-vise update --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index c4c5167..e3a441a 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module git.grassecon.net/urdt/ussd go 1.22.6 require ( - git.defalsify.org/vise.git v0.1.0-rc.3.0.20240923162317-c20d557a3dbb + git.defalsify.org/vise.git v0.1.0-rc.3.0.20240926120105-89b0529cf7ac github.com/alecthomas/assert/v2 v2.2.2 github.com/peteole/testdata-loader v0.3.0 gopkg.in/leonelquinteros/gotext.v1 v1.3.1 diff --git a/go.sum b/go.sum index ed5636f..3f7a262 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ git.defalsify.org/vise.git v0.1.0-rc.3.0.20240923162317-c20d557a3dbb h1:6P4kxihcwMjDKzvUFC6t2zGNb7MDW+l/ACGlSAN1N8Y= git.defalsify.org/vise.git v0.1.0-rc.3.0.20240923162317-c20d557a3dbb/go.mod h1:JDguWmcoWBdsnpw7PUjVZAEpdC/ubBmjdUBy3tjP63M= +git.defalsify.org/vise.git v0.1.0-rc.3.0.20240926120105-89b0529cf7ac h1:D4KI22KWXT8S66sHIjWhTBX6SXRfnd7j8VErq3PPbok= +git.defalsify.org/vise.git v0.1.0-rc.3.0.20240926120105-89b0529cf7ac/go.mod h1:JDguWmcoWBdsnpw7PUjVZAEpdC/ubBmjdUBy3tjP63M= 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= From 3a46fda769941e196b0e62ad12a4924782de9dd1 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Sat, 28 Sep 2024 12:26:37 +0300 Subject: [PATCH 006/289] use save_temporary_pin and updated tests --- internal/handlers/handlerservice.go | 7 +-- internal/handlers/ussd/menuhandler.go | 59 +++++++------------- internal/handlers/ussd/menuhandler_test.go | 51 +++-------------- services/registration/account_creation.vis | 2 +- services/registration/confirm_create_pin.vis | 4 +- services/registration/create_pin.vis | 4 +- 6 files changed, 38 insertions(+), 89 deletions(-) diff --git a/internal/handlers/handlerservice.go b/internal/handlers/handlerservice.go index 3dffe16..1a556cc 100644 --- a/internal/handlers/handlerservice.go +++ b/internal/handlers/handlerservice.go @@ -60,8 +60,8 @@ func (ls *LocalHandlerService) GetHandler() (*ussd.Handlers, error) { ussdHandlers = ussdHandlers.WithPersister(ls.Pe) ls.DbRs.AddLocalFunc("set_language", ussdHandlers.SetLanguage) ls.DbRs.AddLocalFunc("create_account", ussdHandlers.CreateAccount) - ls.DbRs.AddLocalFunc("save_pin", ussdHandlers.SavePin) - ls.DbRs.AddLocalFunc("verify_pin", ussdHandlers.VerifyPin) + ls.DbRs.AddLocalFunc("save_temporary_pin", ussdHandlers.SaveTemporaryPin) + ls.DbRs.AddLocalFunc("verify_create_pin", ussdHandlers.VerifyCreatePin) ls.DbRs.AddLocalFunc("check_identifier", ussdHandlers.CheckIdentifier) ls.DbRs.AddLocalFunc("check_account_status", ussdHandlers.CheckAccountStatus) ls.DbRs.AddLocalFunc("authorize_account", ussdHandlers.Authorize) @@ -89,11 +89,10 @@ func (ls *LocalHandlerService) GetHandler() (*ussd.Handlers, error) { ls.DbRs.AddLocalFunc("verify_yob", ussdHandlers.VerifyYob) ls.DbRs.AddLocalFunc("reset_incorrect_date_format", ussdHandlers.ResetIncorrectYob) ls.DbRs.AddLocalFunc("initiate_transaction", ussdHandlers.InitiateTransaction) - ls.DbRs.AddLocalFunc("save_temporary_pin", ussdHandlers.SaveTemporaryPin) ls.DbRs.AddLocalFunc("verify_new_pin", ussdHandlers.VerifyNewPin) ls.DbRs.AddLocalFunc("confirm_pin_change", ussdHandlers.ConfirmPinChange) ls.DbRs.AddLocalFunc("quit_with_help", ussdHandlers.QuitWithHelp) - ls.DbRs.AddLocalFunc("get_vouchers",ussdHandlers.GetVoucherList) + ls.DbRs.AddLocalFunc("get_vouchers", ussdHandlers.GetVoucherList) return ussdHandlers, nil } diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 5ebdaa5..165a456 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -180,34 +180,6 @@ func (h *Handlers) CreateAccount(ctx context.Context, sym string, input []byte) 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 - 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 - } - - res.FlagReset = append(res.FlagReset, flag_incorrect_pin) - store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_ACCOUNT_PIN, []byte(accountPIN)) - if err != nil { - return res, err - } - return res, nil -} - func (h *Handlers) VerifyNewPin(ctx context.Context, sym string, input []byte) (resource.Result, error) { res := resource.Result{} _, ok := ctx.Value("SessionId").(string) @@ -226,6 +198,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_PIN +// during the account creation 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 @@ -234,6 +209,7 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt if !ok { return res, fmt.Errorf("missing session") } + flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin") accountPIN := string(input) @@ -243,16 +219,19 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt res.FlagSet = append(res.FlagSet, flag_incorrect_pin) return res, nil } + + res.FlagReset = append(res.FlagReset, flag_incorrect_pin) + 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) GetVoucherList(ctx context.Context,sym string,input []byte) (resource.Result,error){ +func (h *Handlers) GetVoucherList(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result vouchers := []string{ "SRF", @@ -283,9 +262,9 @@ func (h *Handlers) GetVoucherList(ctx context.Context,sym string,input []byte) ( for i, voucher := range vouchers { numberedVouchers = append(numberedVouchers, fmt.Sprintf("%d:%s", i+1, voucher)) } - res.Content = strings.Join(numberedVouchers,"\n") + res.Content = strings.Join(numberedVouchers, "\n") - return res,nil + return res, nil } func (h *Handlers) ConfirmPinChange(ctx context.Context, sym string, input []byte) (resource.Result, error) { @@ -313,10 +292,10 @@ func (h *Handlers) ConfirmPinChange(ctx context.Context, sym string, input []byt return res, nil } -// VerifyPin checks whether the confirmation PIN is similar to the account PIN -// If similar, it sets the USERFLAG_PIN_SET flag allowing the user +// 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 -func (h *Handlers) VerifyPin(ctx context.Context, sym string, input []byte) (resource.Result, error) { +func (h *Handlers) VerifyCreatePin(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result flag_valid_pin, _ := h.flagManager.GetFlag("flag_valid_pin") @@ -328,14 +307,13 @@ func (h *Handlers) VerifyPin(ctx context.Context, sym string, input []byte) (res 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) + temporaryPin, err := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_PIN) if err != nil { return res, err } - if bytes.Equal(input, AccountPin) { + if bytes.Equal(input, temporaryPin) { res.FlagSet = []uint32{flag_valid_pin} res.FlagReset = []uint32{flag_pin_mismatch} res.FlagSet = append(res.FlagSet, flag_pin_set) @@ -343,6 +321,11 @@ func (h *Handlers) VerifyPin(ctx context.Context, sym string, input []byte) (res res.FlagSet = []uint32{flag_pin_mismatch} } + err = store.WriteEntry(ctx, sessionId, utils.DATA_ACCOUNT_PIN, []byte(temporaryPin)) + if err != nil { + return res, err + } + return res, nil } diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 83e6f0c..1ce8b51 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -171,7 +171,7 @@ func TestSaveFamilyname(t *testing.T) { mockStore.AssertExpectations(t) } -func TestSavePin(t *testing.T) { +func TestSaveTemporaryPIn(t *testing.T) { fm, err := NewFlagManager(flagsPath) mockStore := new(mocks.MockUserDataStore) if err != nil { @@ -213,10 +213,10 @@ func TestSavePin(t *testing.T) { t.Run(tt.name, func(t *testing.T) { // Set up the expected behavior of the mock - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACCOUNT_PIN, []byte(tt.input)).Return(nil) + mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_PIN, []byte(tt.input)).Return(nil) // Call the method - res, err := h.SavePin(ctx, "save_pin", tt.input) + res, err := h.SaveTemporaryPin(ctx, "save_pin", tt.input) if err != nil { t.Error(err) @@ -937,7 +937,7 @@ func TestVerifyYob(t *testing.T) { } } -func TestVerifyPin(t *testing.T) { +func TestVerifyCreatePin(t *testing.T) { fm, err := NewFlagManager(flagsPath) if err != nil { @@ -986,7 +986,7 @@ func TestVerifyPin(t *testing.T) { }, } - typ := utils.DATA_ACCOUNT_PIN + typ := utils.DATA_TEMPORARY_PIN for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -994,8 +994,11 @@ func TestVerifyPin(t *testing.T) { // Define expected interactions with the mock mockDataStore.On("ReadEntry", ctx, sessionId, typ).Return([]byte(firstSetPin), nil) + // Set up the expected behavior of the mock + mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACCOUNT_PIN, []byte(firstSetPin)).Return(nil) + // Call the method under test - res, err := h.VerifyPin(ctx, "verify_pin", []byte(tt.input)) + res, err := h.VerifyCreatePin(ctx, "verify_create_pin", []byte(tt.input)) // Assert that no errors occurred assert.NoError(t, err) @@ -1693,42 +1696,6 @@ func TestVerifyNewPin(t *testing.T) { } -func TestSaveTemporaryPIn(t *testing.T) { - - fm, err := NewFlagManager(flagsPath) - - if err != nil { - t.Logf(err.Error()) - } - - // Create a new instance of UserDataStore - mockStore := new(mocks.MockUserDataStore) - - // Define test data - sessionId := "session123" - PIN := "1234" - ctx := context.WithValue(context.Background(), "SessionId", sessionId) - - // Set up the expected behavior of the mock - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_PIN, []byte(PIN)).Return(nil) - - // Create the Handlers instance with the mock store - h := &Handlers{ - userdataStore: mockStore, - flagManager: fm.parser, - } - - // Call the method - res, err := h.SaveTemporaryPin(ctx, "save_temporary_pin", []byte(PIN)) - - // Assert results - assert.NoError(t, err) - assert.Equal(t, resource.Result{}, res) - - // Assert all expectations were met - mockStore.AssertExpectations(t) -} - func TestConfirmPin(t *testing.T) { sessionId := "session123" diff --git a/services/registration/account_creation.vis b/services/registration/account_creation.vis index f4f326b..380fe6d 100644 --- a/services/registration/account_creation.vis +++ b/services/registration/account_creation.vis @@ -1,4 +1,4 @@ -RELOAD verify_pin +RELOAD verify_create_pin CATCH create_pin_mismatch flag_pin_mismatch 1 LOAD quit 0 HALT diff --git a/services/registration/confirm_create_pin.vis b/services/registration/confirm_create_pin.vis index 1235916..1a3173c 100644 --- a/services/registration/confirm_create_pin.vis +++ b/services/registration/confirm_create_pin.vis @@ -1,4 +1,4 @@ -LOAD save_pin 0 +LOAD save_temporary_pin 0 HALT -LOAD verify_pin 8 +LOAD verify_create_pin 8 INCMP account_creation * diff --git a/services/registration/create_pin.vis b/services/registration/create_pin.vis index e0e330f..c76e1bf 100644 --- a/services/registration/create_pin.vis +++ b/services/registration/create_pin.vis @@ -2,8 +2,8 @@ LOAD create_account 0 CATCH account_creation_failed flag_account_creation_failed 1 MOUT exit 0 HALT -LOAD save_pin 0 -RELOAD save_pin +LOAD save_temporary_pin 0 +RELOAD save_temporary_pin CATCH . flag_incorrect_pin 1 INCMP quit 0 INCMP confirm_create_pin * From 31aea6b807ed352b44e7640a794bab87269dbe4e Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Sat, 28 Sep 2024 14:07:37 +0300 Subject: [PATCH 007/289] added model and func to fetch vouchers from the API --- internal/handlers/server/accountservice.go | 29 ++++++++++++++++++ internal/handlers/ussd/menuhandler.go | 35 +++++++--------------- internal/mocks/servicemock.go | 7 ++++- internal/models/vouchersresponse.go | 7 +++++ 4 files changed, 53 insertions(+), 25 deletions(-) create mode 100644 internal/models/vouchersresponse.go diff --git a/internal/handlers/server/accountservice.go b/internal/handlers/server/accountservice.go index f4375a1..ca460c7 100644 --- a/internal/handlers/server/accountservice.go +++ b/internal/handlers/server/accountservice.go @@ -13,6 +13,7 @@ type AccountServiceInterface interface { CheckBalance(publicKey string) (string, error) CreateAccount() (*models.AccountResponse, error) CheckAccountStatus(trackingId string) (string, error) + FetchVouchersFromAPI() ([]models.VoucherHolding, error) } type AccountService struct { @@ -110,3 +111,31 @@ func (as *AccountService) CreateAccount() (*models.AccountResponse, error) { return &accountResp, nil } + +// fetchVouchersFromAPI calls the API to get the list of vouchers belonging to the user +func (as *AccountService) FetchVouchersFromAPI() ([]models.VoucherHolding, error) { + // TODO replace with the actual request once ready + mockJSON := `[ + { + "symbol": "MUMO", + "address": "0x078b3a26596218507781722A4e8825BFB9570Fba" + }, + { + "symbol": "SRF", + "address": "0x45d747172e77d55575c197CbA9451bC2CD8F4958" + }, + { + "symbol": "HALGAN", + "address": "0x12169Fb5931A599ad1283bb8311Dad54Feb51A28" + } + ]` + + // Unmarshal the JSON response + var holdings []models.VoucherHolding + err := json.Unmarshal([]byte(mockJSON), &holdings) + if err != nil { + return nil, err + } + + return holdings, nil +} diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 165a456..19c7d1a 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -231,36 +231,23 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt return res, nil } +// GetVoucherList fetches the list of vouchers and formats them +// checks whether they are synced internally before calling the API func (h *Handlers) GetVoucherList(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result - vouchers := []string{ - "SRF", - "CRF", - "VCF", - "VSAPA", - "FSTMP", - "FSAW", - "PTAQ", - "VCRXT", - "VSGAQ", - "QPWIQQ", - "FSTMP", - "FSAW", - "PTAQ", - "VCRXT", - "VSGAQ", - "QPWIQQ", - "FSTMP", - "FSAW", - "PTAQ", - "VCRXT", - "VSGAQ", - "QPWIQQ", + + // check if the vouchers exist internally and if not + // fetch from the API + + // Fetch vouchers from API + vouchers, err := h.accountService.FetchVouchersFromAPI() + if err != nil { + return res, fmt.Errorf("error fetching vouchers: %w", err) } var numberedVouchers []string for i, voucher := range vouchers { - numberedVouchers = append(numberedVouchers, fmt.Sprintf("%d:%s", i+1, voucher)) + numberedVouchers = append(numberedVouchers, fmt.Sprintf("%d:%s", i+1, voucher.Symbol)) } res.Content = strings.Join(numberedVouchers, "\n") diff --git a/internal/mocks/servicemock.go b/internal/mocks/servicemock.go index 9fb6d3e..30386b3 100644 --- a/internal/mocks/servicemock.go +++ b/internal/mocks/servicemock.go @@ -23,4 +23,9 @@ func (m *MockAccountService) CheckBalance(publicKey string) (string, error) { func (m *MockAccountService) CheckAccountStatus(trackingId string) (string, error) { args := m.Called(trackingId) return args.String(0), args.Error(1) -} \ No newline at end of file +} + +func (m *MockAccountService) FetchVouchersFromAPI() ([]models.VoucherHolding, error) { + args := m.Called() + return args.Get(0).([]models.VoucherHolding), args.Error(1) +} diff --git a/internal/models/vouchersresponse.go b/internal/models/vouchersresponse.go new file mode 100644 index 0000000..08967b7 --- /dev/null +++ b/internal/models/vouchersresponse.go @@ -0,0 +1,7 @@ +package models + +// VoucherHolding represents a single voucher holding +type VoucherHolding struct { + Symbol string `json:"symbol"` + Address string `json:"address"` +} \ No newline at end of file From 517f9806643b4012cf6aaedfbe3450f4c781c0c6 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Sat, 5 Oct 2024 16:56:49 +0300 Subject: [PATCH 008/289] get the vouchers list and store in gdbm --- internal/handlers/handlerservice.go | 1 + internal/handlers/server/accountservice.go | 100 +++++++++++++++------ internal/handlers/ussd/menuhandler.go | 63 +++++++++++-- internal/mocks/servicemock.go | 4 +- internal/models/vouchersresponse.go | 18 ++-- internal/utils/db.go | 1 + services/registration/main.vis | 2 + 7 files changed, 152 insertions(+), 37 deletions(-) diff --git a/internal/handlers/handlerservice.go b/internal/handlers/handlerservice.go index 1a556cc..8f0ff16 100644 --- a/internal/handlers/handlerservice.go +++ b/internal/handlers/handlerservice.go @@ -92,6 +92,7 @@ func (ls *LocalHandlerService) GetHandler() (*ussd.Handlers, error) { ls.DbRs.AddLocalFunc("verify_new_pin", ussdHandlers.VerifyNewPin) ls.DbRs.AddLocalFunc("confirm_pin_change", ussdHandlers.ConfirmPinChange) ls.DbRs.AddLocalFunc("quit_with_help", ussdHandlers.QuitWithHelp) + ls.DbRs.AddLocalFunc("check_vouchers", ussdHandlers.CheckVouchers) ls.DbRs.AddLocalFunc("get_vouchers", ussdHandlers.GetVoucherList) return ussdHandlers, nil diff --git a/internal/handlers/server/accountservice.go b/internal/handlers/server/accountservice.go index ca460c7..d53db57 100644 --- a/internal/handlers/server/accountservice.go +++ b/internal/handlers/server/accountservice.go @@ -13,14 +13,12 @@ type AccountServiceInterface interface { CheckBalance(publicKey string) (string, error) CreateAccount() (*models.AccountResponse, error) CheckAccountStatus(trackingId string) (string, error) - FetchVouchersFromAPI() ([]models.VoucherHolding, error) + FetchVouchers(publicKey string) (*models.VoucherHoldingResponse, error) } type AccountService struct { } - - // CheckAccountStatus retrieves the status of an account transaction based on the provided tracking ID. // // Parameters: @@ -28,12 +26,10 @@ 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) if err != nil { @@ -57,7 +53,6 @@ func (as *AccountService) CheckAccountStatus(trackingId string) (string, error) 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. @@ -84,8 +79,7 @@ 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. @@ -112,30 +106,86 @@ func (as *AccountService) CreateAccount() (*models.AccountResponse, error) { return &accountResp, nil } -// fetchVouchersFromAPI calls the API to get the list of vouchers belonging to the user -func (as *AccountService) FetchVouchersFromAPI() ([]models.VoucherHolding, error) { +// FetchVouchers retrieves the token holdings for a given public key from the custodial holdings API endpoint +// Parameters: +// - publicKey: The public key associated with the account. +func (as *AccountService) FetchVouchers(publicKey string) (*models.VoucherHoldingResponse, error) { // TODO replace with the actual request once ready - mockJSON := `[ - { - "symbol": "MUMO", - "address": "0x078b3a26596218507781722A4e8825BFB9570Fba" - }, - { - "symbol": "SRF", - "address": "0x45d747172e77d55575c197CbA9451bC2CD8F4958" - }, - { - "symbol": "HALGAN", - "address": "0x12169Fb5931A599ad1283bb8311Dad54Feb51A28" + mockJSON := `{ + "ok": true, + "description": "Token holdings with current balances", + "result": { + "holdings": [ + { + "contractAddress": "0x6CC75A06ac72eB4Db2eE22F781F5D100d8ec03ee", + "tokenSymbol": "FSPTST", + "tokenDecimals": "6", + "balance": "8869964242" + }, + { + "contractAddress": "0x724F2910D790B54A39a7638282a45B1D83564fFA", + "tokenSymbol": "GEO", + "tokenDecimals": "6", + "balance": "9884" + }, + { + "contractAddress": "0x2105a206B7bec31E2F90acF7385cc8F7F5f9D273", + "tokenSymbol": "MFNK", + "tokenDecimals": "6", + "balance": "19788697" + }, + { + "contractAddress": "0x63DE2Ac8D1008351Cc69Fb8aCb94Ba47728a7E83", + "tokenSymbol": "MILO", + "tokenDecimals": "6", + "balance": "75" + }, + { + "contractAddress": "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", + "tokenSymbol": "SOHAIL", + "tokenDecimals": "6", + "balance": "27874115" + }, + { + "contractAddress": "0x45d747172e77d55575c197CbA9451bC2CD8F4958", + "tokenSymbol": "SRQIF", + "tokenDecimals": "6", + "balance": "2745987" + }, + { + "contractAddress": "0x45d747172e77d55575c197CbA9451bC2CD8F4958", + "tokenSymbol": "SRFI", + "tokenDecimals": "6", + "balance": "2745987" + }, + { + "contractAddress": "0x45d747172e77d55575c197CbA9451bC2CD8F4958", + "tokenSymbol": "SRFU", + "tokenDecimals": "6", + "balance": "2745987" + }, + { + "contractAddress": "0x45d747172e77d55575c197CbA9451bC2CD8F4958", + "tokenSymbol": "SRQF", + "tokenDecimals": "6", + "balance": "2745987" + }, + { + "contractAddress": "0x45d747172e77d55575c197CbA9451bC2CD8F4958", + "tokenSymbol": "SREF", + "tokenDecimals": "6", + "balance": "2745987" + } + ] } - ]` + }` // Unmarshal the JSON response - var holdings []models.VoucherHolding + var holdings models.VoucherHoldingResponse err := json.Unmarshal([]byte(mockJSON), &holdings) if err != nil { return nil, err } - return holdings, nil + return &holdings, nil } diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 19c7d1a..d55abaf 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -3,6 +3,7 @@ package ussd import ( "bytes" "context" + "encoding/json" "fmt" "path" "regexp" @@ -232,22 +233,36 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt } // GetVoucherList fetches the list of vouchers and formats them -// checks whether they are synced internally before calling the API +// checks whether they are stored internally before calling the API func (h *Handlers) GetVoucherList(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") + } // check if the vouchers exist internally and if not // fetch from the API - // Fetch vouchers from API - vouchers, err := h.accountService.FetchVouchersFromAPI() + // Read vouchers from the store + store := h.userdataStore + voucherData, err := store.ReadEntry(ctx, sessionId, utils.DATA_VOUCHER_LIST) if err != nil { - return res, fmt.Errorf("error fetching vouchers: %w", err) + return res, err + } + + // Unmarshal the stored JSON data into the correct struct + var vouchers []struct { + TokenSymbol string `json:"tokenSymbol"` + } + err = json.Unmarshal(voucherData, &vouchers) + if err != nil { + return res, fmt.Errorf("failed to unmarshal vouchers: %v", err) } var numberedVouchers []string for i, voucher := range vouchers { - numberedVouchers = append(numberedVouchers, fmt.Sprintf("%d:%s", i+1, voucher.Symbol)) + numberedVouchers = append(numberedVouchers, fmt.Sprintf("%d:%s", i+1, voucher.TokenSymbol)) } res.Content = strings.Join(numberedVouchers, "\n") @@ -1007,3 +1022,41 @@ func (h *Handlers) GetProfileInfo(ctx context.Context, sym string, input []byte) return res, nil } + +// CheckVouchers retrieves the token holdings from the API using the "PublicKey" and stores +// them to gdbm +func (h *Handlers) CheckVouchers(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") + } + + store := h.userdataStore + publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) + if err != nil { + return res, nil + } + + // Fetch vouchers from the API + vouchersResp, err := h.accountService.FetchVouchers(string(publicKey)) + if err != nil { + return res, nil + } + + // Convert only the list of holdings (vouchers) to JSON + voucherBytes, err := json.Marshal(vouchersResp.Result.Holdings) + if err != nil { + return res, nil + } + + // Store the voucher symbols in the userdataStore + err = store.WriteEntry(ctx, sessionId, utils.DATA_VOUCHER_LIST, voucherBytes) + if err != nil { + return res, nil + } + + return res, nil +} diff --git a/internal/mocks/servicemock.go b/internal/mocks/servicemock.go index 30386b3..8fbde0f 100644 --- a/internal/mocks/servicemock.go +++ b/internal/mocks/servicemock.go @@ -25,7 +25,7 @@ func (m *MockAccountService) CheckAccountStatus(trackingId string) (string, erro return args.String(0), args.Error(1) } -func (m *MockAccountService) FetchVouchersFromAPI() ([]models.VoucherHolding, error) { +func (m *MockAccountService) FetchVouchers(publicKey string) (*models.VoucherHoldingResponse, error) { args := m.Called() - return args.Get(0).([]models.VoucherHolding), args.Error(1) + return args.Get(0).(*models.VoucherHoldingResponse), args.Error(1) } diff --git a/internal/models/vouchersresponse.go b/internal/models/vouchersresponse.go index 08967b7..010730f 100644 --- a/internal/models/vouchersresponse.go +++ b/internal/models/vouchersresponse.go @@ -1,7 +1,15 @@ package models -// VoucherHolding represents a single voucher holding -type VoucherHolding struct { - Symbol string `json:"symbol"` - Address string `json:"address"` -} \ No newline at end of file +// VoucherHoldingResponse represents a single voucher holding +type VoucherHoldingResponse struct { + Ok bool `json:"ok"` + Description string `json:"description"` + Result struct { + Holdings []struct { + ContractAddress string `json:"contractAddress"` + TokenSymbol string `json:"tokenSymbol"` + TokenDecimals string `json:"tokenDecimals"` + Balance string `json:"balance"` + } `json:"holdings"` + } `json:"result"` +} diff --git a/internal/utils/db.go b/internal/utils/db.go index 410da68..3080c1b 100644 --- a/internal/utils/db.go +++ b/internal/utils/db.go @@ -23,6 +23,7 @@ const ( DATA_RECIPIENT DATA_AMOUNT DATA_TEMPORARY_PIN + DATA_VOUCHER_LIST ) func typToBytes(typ DataTyp) []byte { diff --git a/services/registration/main.vis b/services/registration/main.vis index 1009039..88f8a42 100644 --- a/services/registration/main.vis +++ b/services/registration/main.vis @@ -1,5 +1,7 @@ LOAD check_balance 64 RELOAD check_balance +LOAD check_vouchers 10 +RELOAD check_vouchers MAP check_balance MOUT send 1 MOUT vouchers 2 From 755899be4e6a1e0dc5c6b731910ade18d40284ad Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Mon, 7 Oct 2024 08:59:15 +0300 Subject: [PATCH 009/289] store the pre-rendered vouchers list --- internal/handlers/ussd/menuhandler.go | 32 +++++++-------------------- internal/storage/db.go | 28 +++++++++++------------ 2 files changed, 22 insertions(+), 38 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index d55abaf..4c09acb 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -3,7 +3,6 @@ package ussd import ( "bytes" "context" - "encoding/json" "fmt" "path" "regexp" @@ -251,20 +250,7 @@ func (h *Handlers) GetVoucherList(ctx context.Context, sym string, input []byte) return res, err } - // Unmarshal the stored JSON data into the correct struct - var vouchers []struct { - TokenSymbol string `json:"tokenSymbol"` - } - err = json.Unmarshal(voucherData, &vouchers) - if err != nil { - return res, fmt.Errorf("failed to unmarshal vouchers: %v", err) - } - - var numberedVouchers []string - for i, voucher := range vouchers { - numberedVouchers = append(numberedVouchers, fmt.Sprintf("%d:%s", i+1, voucher.TokenSymbol)) - } - res.Content = strings.Join(numberedVouchers, "\n") + res.Content = string(voucherData) return res, nil } @@ -1027,8 +1013,6 @@ func (h *Handlers) GetProfileInfo(ctx context.Context, sym string, input []byte) // them to gdbm func (h *Handlers) CheckVouchers(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") @@ -1040,20 +1024,20 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) return res, nil } - // Fetch vouchers from the API + // Fetch vouchers from the API using the public key vouchersResp, err := h.accountService.FetchVouchers(string(publicKey)) if err != nil { return res, nil } - // Convert only the list of holdings (vouchers) to JSON - voucherBytes, err := json.Marshal(vouchersResp.Result.Holdings) - if err != nil { - return res, nil + var numberedVouchers []string + for i, voucher := range vouchersResp.Result.Holdings { + numberedVouchers = append(numberedVouchers, fmt.Sprintf("%d:%s", i+1, voucher.TokenSymbol)) } - // Store the voucher symbols in the userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_VOUCHER_LIST, voucherBytes) + voucherList := strings.Join(numberedVouchers, "\n") + + err = store.WriteEntry(ctx, sessionId, utils.DATA_VOUCHER_LIST, []byte(voucherList)) if err != nil { return res, nil } diff --git a/internal/storage/db.go b/internal/storage/db.go index b2ac6a9..060f0c0 100644 --- a/internal/storage/db.go +++ b/internal/storage/db.go @@ -12,32 +12,32 @@ const ( type SubPrefixDb struct { store db.Db - pfx []byte + pfx []byte } func NewSubPrefixDb(store db.Db, pfx []byte) *SubPrefixDb { return &SubPrefixDb{ store: store, - pfx: pfx, + pfx: pfx, } } -func(s *SubPrefixDb) toKey(k []byte) []byte { - return append(s.pfx, k...) +func (s *SubPrefixDb) toKey(k []byte) []byte { + return append(s.pfx, k...) } -func(s *SubPrefixDb) Get(ctx context.Context, key []byte) ([]byte, error) { - s.store.SetPrefix(DATATYPE_USERSUB) +func (s *SubPrefixDb) Get(ctx context.Context, key []byte) ([]byte, error) { + s.store.SetPrefix(DATATYPE_USERSUB) key = s.toKey(key) - v, err := s.store.Get(ctx, key) - if err != nil { - return nil, err - } - return v, nil + v, err := s.store.Get(ctx, key) + if err != nil { + return nil, err + } + return v, nil } -func(s *SubPrefixDb) Put(ctx context.Context, key []byte, val []byte) error { - s.store.SetPrefix(DATATYPE_USERSUB) +func (s *SubPrefixDb) Put(ctx context.Context, key []byte, val []byte) error { + s.store.SetPrefix(DATATYPE_USERSUB) key = s.toKey(key) - return s.store.Put(ctx, key, val) + return s.store.Put(ctx, key, val) } From e4ed9a65bbc777bf98232a0b887fab73530ae291 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Mon, 7 Oct 2024 13:49:12 +0300 Subject: [PATCH 010/289] store the symbols and balances --- internal/handlers/server/accountservice.go | 36 ---------------------- internal/handlers/ussd/menuhandler.go | 29 +++++++++++------ 2 files changed, 19 insertions(+), 46 deletions(-) diff --git a/internal/handlers/server/accountservice.go b/internal/handlers/server/accountservice.go index d53db57..9f6ce03 100644 --- a/internal/handlers/server/accountservice.go +++ b/internal/handlers/server/accountservice.go @@ -139,42 +139,6 @@ func (as *AccountService) FetchVouchers(publicKey string) (*models.VoucherHoldin "tokenSymbol": "MILO", "tokenDecimals": "6", "balance": "75" - }, - { - "contractAddress": "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", - "tokenSymbol": "SOHAIL", - "tokenDecimals": "6", - "balance": "27874115" - }, - { - "contractAddress": "0x45d747172e77d55575c197CbA9451bC2CD8F4958", - "tokenSymbol": "SRQIF", - "tokenDecimals": "6", - "balance": "2745987" - }, - { - "contractAddress": "0x45d747172e77d55575c197CbA9451bC2CD8F4958", - "tokenSymbol": "SRFI", - "tokenDecimals": "6", - "balance": "2745987" - }, - { - "contractAddress": "0x45d747172e77d55575c197CbA9451bC2CD8F4958", - "tokenSymbol": "SRFU", - "tokenDecimals": "6", - "balance": "2745987" - }, - { - "contractAddress": "0x45d747172e77d55575c197CbA9451bC2CD8F4958", - "tokenSymbol": "SRQF", - "tokenDecimals": "6", - "balance": "2745987" - }, - { - "contractAddress": "0x45d747172e77d55575c197CbA9451bC2CD8F4958", - "tokenSymbol": "SREF", - "tokenDecimals": "6", - "balance": "2745987" } ] } diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 4c09acb..0ff1017 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -21,6 +21,8 @@ import ( "git.grassecon.net/urdt/ussd/internal/handlers/server" "git.grassecon.net/urdt/ussd/internal/utils" "gopkg.in/leonelquinteros/gotext.v1" + + "git.grassecon.net/urdt/ussd/internal/storage" ) var ( @@ -235,19 +237,17 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt // checks whether they are stored internally before calling the API func (h *Handlers) GetVoucherList(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") - } // check if the vouchers exist internally and if not // fetch from the API // Read vouchers from the store store := h.userdataStore - voucherData, err := store.ReadEntry(ctx, sessionId, utils.DATA_VOUCHER_LIST) + prefixdb := storage.NewSubPrefixDb(store, []byte("token_holdings")) + + voucherData, err := prefixdb.Get(ctx, []byte("tokens")) if err != nil { - return res, err + return res, nil } res.Content = string(voucherData) @@ -1030,14 +1030,23 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) return res, nil } - var numberedVouchers []string + var numberedSymbols []string + var numberedBalances []string for i, voucher := range vouchersResp.Result.Holdings { - numberedVouchers = append(numberedVouchers, fmt.Sprintf("%d:%s", i+1, voucher.TokenSymbol)) + numberedSymbols = append(numberedSymbols, fmt.Sprintf("%d:%s", i+1, voucher.TokenSymbol)) + numberedBalances = append(numberedBalances, fmt.Sprintf("%d:%s", i+1, voucher.Balance)) } - voucherList := strings.Join(numberedVouchers, "\n") + voucherSymbolList := strings.Join(numberedSymbols, "\n") + voucherBalanceList := strings.Join(numberedBalances, "\n") - err = store.WriteEntry(ctx, sessionId, utils.DATA_VOUCHER_LIST, []byte(voucherList)) + prefixdb := storage.NewSubPrefixDb(store, []byte("token_holdings")) + err = prefixdb.Put(ctx, []byte("tokens"), []byte(voucherSymbolList)) + if err != nil { + return res, nil + } + + err = prefixdb.Put(ctx, []byte(voucherSymbolList), []byte(voucherBalanceList)) if err != nil { return res, nil } From 06ebcc0f07886f05ece7c0c04e3a71ad6312c5e5 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Mon, 7 Oct 2024 16:15:13 +0300 Subject: [PATCH 011/289] added swahili template --- services/registration/select_voucher_swa | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 services/registration/select_voucher_swa diff --git a/services/registration/select_voucher_swa b/services/registration/select_voucher_swa new file mode 100644 index 0000000..b4720bf --- /dev/null +++ b/services/registration/select_voucher_swa @@ -0,0 +1,2 @@ +Chagua nambari au ishara kutoka kwa salio zako: +{{.get_vouchers}} \ No newline at end of file From cb4a52e4f245bddf9755434004a4cdb7fffd9f65 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Mon, 7 Oct 2024 16:16:57 +0300 Subject: [PATCH 012/289] view a selected voucher and verify the PIN --- internal/handlers/handlerservice.go | 1 + internal/handlers/ussd/menuhandler.go | 68 ++++++++++++++++++++++++ services/registration/my_vouchers.vis | 3 -- services/registration/pp.csv | 2 +- services/registration/select_voucher.vis | 6 ++- services/registration/view_voucher | 2 + services/registration/view_voucher.vis | 11 ++++ services/registration/view_voucher_swa | 2 + services/registration/voucher_set | 1 + services/registration/voucher_set.vis | 5 ++ services/registration/voucher_set_swa | 1 + 11 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 services/registration/view_voucher create mode 100644 services/registration/view_voucher.vis create mode 100644 services/registration/view_voucher_swa create mode 100644 services/registration/voucher_set create mode 100644 services/registration/voucher_set.vis create mode 100644 services/registration/voucher_set_swa diff --git a/internal/handlers/handlerservice.go b/internal/handlers/handlerservice.go index 8f0ff16..4c152b9 100644 --- a/internal/handlers/handlerservice.go +++ b/internal/handlers/handlerservice.go @@ -94,6 +94,7 @@ func (ls *LocalHandlerService) GetHandler() (*ussd.Handlers, error) { ls.DbRs.AddLocalFunc("quit_with_help", ussdHandlers.QuitWithHelp) ls.DbRs.AddLocalFunc("check_vouchers", ussdHandlers.CheckVouchers) ls.DbRs.AddLocalFunc("get_vouchers", ussdHandlers.GetVoucherList) + ls.DbRs.AddLocalFunc("view_voucher", ussdHandlers.ViewVoucher) return ussdHandlers, nil } diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 0ff1017..c254401 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -1053,3 +1053,71 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) return res, nil } + +// ViewVoucher retrieves the token holding and balance from the subprefixDB +func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (resource.Result, error) { + var res resource.Result + var err error + inputStr := string(input) + + if inputStr == "0" || inputStr == "00" { + return res, nil + } + + flag_incorrect_voucher, _ := h.flagManager.GetFlag("flag_incorrect_voucher") + + // Initialize the store and prefix database + store := h.userdataStore + prefixdb := storage.NewSubPrefixDb(store, []byte("token_holdings")) + + // Retrieve the voucher symbol list + voucherSymbolList, err := prefixdb.Get(ctx, []byte("tokens")) + if err != nil { + return res, fmt.Errorf("failed to retrieve voucher symbol list: %v", err) + } + + // Retrieve the voucher balance list + voucherBalanceList, err := prefixdb.Get(ctx, []byte(voucherSymbolList)) + if err != nil { + return res, fmt.Errorf("failed to retrieve voucher balance list: %v", err) + } + + // Convert the symbol and balance lists from byte arrays to strings + voucherSymbols := string(voucherSymbolList) + voucherBalances := string(voucherBalanceList) + + // Split the lists into slices for processing + symbols := strings.Split(voucherSymbols, "\n") + balances := strings.Split(voucherBalances, "\n") + + var matchedSymbol, matchedBalance string + + for i, symbol := range symbols { + symbolParts := strings.SplitN(symbol, ":", 2) + if len(symbolParts) != 2 { + continue + } + voucherNum := symbolParts[0] + voucherSymbol := symbolParts[1] + + // Check if input matches either the number or the symbol + if inputStr == voucherNum || strings.EqualFold(inputStr, voucherSymbol) { + matchedSymbol = voucherSymbol + // Ensure there's a corresponding balance + if i < len(balances) { + matchedBalance = strings.SplitN(balances[i], ":", 2)[1] // Extract balance after the "x:balance" format + } + break + } + } + + // If a match is found, return the symbol and balance + if matchedSymbol != "" && matchedBalance != "" { + res.Content = fmt.Sprintf("%s\n%s", matchedSymbol, matchedBalance) + res.FlagReset = append(res.FlagReset, flag_incorrect_voucher) + } else { + res.FlagSet = append(res.FlagSet, flag_incorrect_voucher) + } + + return res, nil +} diff --git a/services/registration/my_vouchers.vis b/services/registration/my_vouchers.vis index b70dbfa..9702573 100644 --- a/services/registration/my_vouchers.vis +++ b/services/registration/my_vouchers.vis @@ -4,6 +4,3 @@ MOUT back 0 HALT INCMP _ 0 INCMP select_voucher 1 - - - diff --git a/services/registration/pp.csv b/services/registration/pp.csv index fd552e4..2a7bb21 100644 --- a/services/registration/pp.csv +++ b/services/registration/pp.csv @@ -12,5 +12,5 @@ flag,flag_invalid_amount,18,this is set when the given transaction amount is inv flag,flag_incorrect_pin,19,this is set when the provided PIN is invalid or does not match the current account's PIN flag,flag_valid_pin,20,this is set when the given PIN is valid flag,flag_allow_update,21,this is set to allow a user to update their profile data -flag,flag_single_edit,22,this is set to allow a user to edit a single profile item such as year of birth +flag,flag_incorrect_voucher,22,this is set when the selected voucher is invalid flag,flag_incorrect_date_format,23,this is set when the given year of birth is invalid diff --git a/services/registration/select_voucher.vis b/services/registration/select_voucher.vis index 4fb1d40..50b99ad 100644 --- a/services/registration/select_voucher.vis +++ b/services/registration/select_voucher.vis @@ -1,11 +1,15 @@ LOAD get_vouchers 0 MAP get_vouchers MOUT back 0 -MOUT quit 9 +MOUT quit 00 MNEXT next 11 MPREV prev 22 HALT +LOAD view_voucher 80 +RELOAD view_voucher +CATCH . flag_incorrect_voucher 1 INCMP _ 0 INCMP quit 9 INCMP > 11 INCMP < 22 +INCMP view_voucher * diff --git a/services/registration/view_voucher b/services/registration/view_voucher new file mode 100644 index 0000000..3940982 --- /dev/null +++ b/services/registration/view_voucher @@ -0,0 +1,2 @@ +Enter PIN to confirm selection: +{{.view_voucher}} \ No newline at end of file diff --git a/services/registration/view_voucher.vis b/services/registration/view_voucher.vis new file mode 100644 index 0000000..ee8bf85 --- /dev/null +++ b/services/registration/view_voucher.vis @@ -0,0 +1,11 @@ +RELOAD view_voucher +MAP view_voucher +MOUT back 0 +MOUT quit 9 +LOAD authorize_account 6 +HALT +RELOAD authorize_account +CATCH incorrect_pin flag_incorrect_pin 1 +INCMP _ 0 +INCMP quit 9 +INCMP voucher_set * diff --git a/services/registration/view_voucher_swa b/services/registration/view_voucher_swa new file mode 100644 index 0000000..485e2ef --- /dev/null +++ b/services/registration/view_voucher_swa @@ -0,0 +1,2 @@ +Weka PIN ili kuthibitisha chaguo: +{{.view_voucher}} \ No newline at end of file diff --git a/services/registration/voucher_set b/services/registration/voucher_set new file mode 100644 index 0000000..838c1ef --- /dev/null +++ b/services/registration/voucher_set @@ -0,0 +1 @@ +Success! symbol is now your active voucher. \ No newline at end of file diff --git a/services/registration/voucher_set.vis b/services/registration/voucher_set.vis new file mode 100644 index 0000000..832ef22 --- /dev/null +++ b/services/registration/voucher_set.vis @@ -0,0 +1,5 @@ +MOUT back 0 +MOUT quit 9 +HALT +INCMP ^ 0 +INCMP quit 9 diff --git a/services/registration/voucher_set_swa b/services/registration/voucher_set_swa new file mode 100644 index 0000000..320a315 --- /dev/null +++ b/services/registration/voucher_set_swa @@ -0,0 +1 @@ +Hongera! symbol ni Sarafu inayotumika sasa. \ No newline at end of file From 7b374ad801a37e1b88f2c45ce3b7d92852a68880 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 8 Oct 2024 13:41:09 +0300 Subject: [PATCH 013/289] define importable token list --- internal/handlers/server/accountservice.go | 22 ++++--- internal/handlers/ussd/menuhandler.go | 68 +++++++++++++--------- sample_tokens.json | 44 ++++++++++++++ 3 files changed, 100 insertions(+), 34 deletions(-) create mode 100644 sample_tokens.json diff --git a/internal/handlers/server/accountservice.go b/internal/handlers/server/accountservice.go index f4375a1..88c3354 100644 --- a/internal/handlers/server/accountservice.go +++ b/internal/handlers/server/accountservice.go @@ -4,6 +4,7 @@ import ( "encoding/json" "io" "net/http" + "os" "git.grassecon.net/urdt/ussd/config" "git.grassecon.net/urdt/ussd/internal/models" @@ -18,8 +19,6 @@ type AccountServiceInterface interface { type AccountService struct { } - - // CheckAccountStatus retrieves the status of an account transaction based on the provided tracking ID. // // Parameters: @@ -27,12 +26,10 @@ 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) if err != nil { @@ -56,7 +53,6 @@ func (as *AccountService) CheckAccountStatus(trackingId string) (string, error) 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. @@ -83,8 +79,7 @@ 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. @@ -110,3 +105,16 @@ func (as *AccountService) CreateAccount() (*models.AccountResponse, error) { return &accountResp, nil } + +func GetTokenList() (*models.ApiResponse, error) { + file, err := os.Open("sample_tokens.json") + if err != nil { + return nil, err + } + defer file.Close() + var apiResponse models.ApiResponse + if err := json.NewDecoder(file).Decode(&apiResponse); err != nil { + return nil, err + } + return &apiResponse, nil +} diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index e998bd5..a7a58bf 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -256,36 +256,50 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt func (h *Handlers) GetVoucherList(ctx context.Context,sym string,input []byte) (resource.Result,error){ - var res resource.Result - vouchers := []string{ - "SRF", - "CRF", - "VCF", - "VSAPA", - "FSTMP", - "FSAW", - "PTAQ", - "VCRXT", - "VSGAQ", - "QPWIQQ", - "FSTMP", - "FSAW", - "PTAQ", - "VCRXT", - "VSGAQ", - "QPWIQQ", - "FSTMP", - "FSAW", - "PTAQ", - "VCRXT", - "VSGAQ", - "QPWIQQ", + res := resource.Result{} + //as := h.accountService.(*server.AccountService) + tokenList,err := server.GetTokenList() + fmt.Println("Error here:",err) + if err != nil { + return res,err } - var numberedVouchers []string - for i, voucher := range vouchers { - numberedVouchers = append(numberedVouchers, fmt.Sprintf("%d:%s", i+1, voucher)) + holdings := tokenList.Result.Holdings + fmt.Println("TokenList:",tokenList.Result.Holdings) + + // vouchers := []string{ + // "SRF", + // "CRF", + // "VCF", + // "VSAPA", + // "FSTMP", + // "FSAW", + // "PTAQ", + // "VCRXT", + // "VSGAQ", + // "QPWIQQ", + // "FSTMP", + // "FSAW", + // "PTAQ", + // "VCRXT", + // "VSGAQ", + // "QPWIQQ", + // "FSTMP", + // "FSAW", + // "PTAQ", + // "VCRXT", + // "VSGAQ", + // "QPWIQQ", + // } + var numberedVouchers []string + for i,token := range holdings { + numberedVouchers = append(numberedVouchers, fmt.Sprintf("%d:%s", i+1, token.TokenSymbol)) } + + // var numberedVouchers []string + // for i, voucher := range vouchers { + // numberedVouchers = append(numberedVouchers, fmt.Sprintf("%d:%s", i+1, voucher)) + // } res.Content = strings.Join(numberedVouchers,"\n") return res,nil diff --git a/sample_tokens.json b/sample_tokens.json new file mode 100644 index 0000000..07126ed --- /dev/null +++ b/sample_tokens.json @@ -0,0 +1,44 @@ +{ + "ok": true, + "description": "Token holdings with current balances", + "result": { + "holdings": [ + { + "contractAddress": "0x6CC75A06ac72eB4Db2eE22F781F5D100d8ec03ee", + "tokenSymbol": "FSPTST", + "tokenDecimals": "6", + "balance": "8869964242" + }, + { + "contractAddress": "0x724F2910D790B54A39a7638282a45B1D83564fFA", + "tokenSymbol": "GEO", + "tokenDecimals": "6", + "balance": "9884" + }, + { + "contractAddress": "0x2105a206B7bec31E2F90acF7385cc8F7F5f9D273", + "tokenSymbol": "MFNK", + "tokenDecimals": "6", + "balance": "19788697" + }, + { + "contractAddress": "0x63DE2Ac8D1008351Cc69Fb8aCb94Ba47728a7E83", + "tokenSymbol": "MILO", + "tokenDecimals": "6", + "balance": "75" + }, + { + "contractAddress": "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", + "tokenSymbol": "SOHAIL", + "tokenDecimals": "6", + "balance": "27874115" + }, + { + "contractAddress": "0x45d747172e77d55575c197CbA9451bC2CD8F4958", + "tokenSymbol": "SRF", + "tokenDecimals": "6", + "balance": "2745987" + } + ] + } + } From 4b6fd35e7a3c66ea3f28f03b6abd212b38bd0007 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 8 Oct 2024 13:43:57 +0300 Subject: [PATCH 014/289] define importable voucher response --- internal/models/tokenresponse.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 internal/models/tokenresponse.go diff --git a/internal/models/tokenresponse.go b/internal/models/tokenresponse.go new file mode 100644 index 0000000..d243d93 --- /dev/null +++ b/internal/models/tokenresponse.go @@ -0,0 +1,18 @@ +package models + +type ApiResponse struct { + OK bool `json:"ok"` + Description string `json:"description"` + Result Result `json:"result"` +} + +type Result struct { + Holdings []Holding `json:"holdings"` +} + +type Holding struct { + ContractAddress string `json:"contractAddress"` + TokenSymbol string `json:"tokenSymbol"` + TokenDecimals string `json:"tokenDecimals"` + Balance string `json:"balance"` +} From 2c98a8e1331861a0c1754ed62ea72baec1853af3 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 8 Oct 2024 14:34:21 +0300 Subject: [PATCH 015/289] read token list from json file --- internal/handlers/server/accountservice.go | 53 ++-------------------- 1 file changed, 5 insertions(+), 48 deletions(-) diff --git a/internal/handlers/server/accountservice.go b/internal/handlers/server/accountservice.go index 2b0efc0..b83507f 100644 --- a/internal/handlers/server/accountservice.go +++ b/internal/handlers/server/accountservice.go @@ -111,59 +111,16 @@ func (as *AccountService) CreateAccount() (*models.AccountResponse, error) { // Parameters: // - publicKey: The public key associated with the account. func (as *AccountService) FetchVouchers(publicKey string) (*models.VoucherHoldingResponse, error) { - // TODO replace with the actual request once ready - mockJSON := `{ - "ok": true, - "description": "Token holdings with current balances", - "result": { - "holdings": [ - { - "contractAddress": "0x6CC75A06ac72eB4Db2eE22F781F5D100d8ec03ee", - "tokenSymbol": "FSPTST", - "tokenDecimals": "6", - "balance": "8869964242" - }, - { - "contractAddress": "0x724F2910D790B54A39a7638282a45B1D83564fFA", - "tokenSymbol": "GEO", - "tokenDecimals": "6", - "balance": "9884" - }, - { - "contractAddress": "0x2105a206B7bec31E2F90acF7385cc8F7F5f9D273", - "tokenSymbol": "MFNK", - "tokenDecimals": "6", - "balance": "19788697" - }, - { - "contractAddress": "0x63DE2Ac8D1008351Cc69Fb8aCb94Ba47728a7E83", - "tokenSymbol": "MILO", - "tokenDecimals": "6", - "balance": "75" - } - ] - } - }` - - // Unmarshal the JSON response - var holdings models.VoucherHoldingResponse - err := json.Unmarshal([]byte(mockJSON), &holdings) - if err != nil { - return nil, err - } - - return &holdings, nil -} - -func GetTokenList() (*models.ApiResponse, error) { file, err := os.Open("sample_tokens.json") if err != nil { return nil, err } defer file.Close() - var apiResponse models.ApiResponse - if err := json.NewDecoder(file).Decode(&apiResponse); err != nil { + var holdings models.VoucherHoldingResponse + + if err := json.NewDecoder(file).Decode(&holdings); err != nil { return nil, err } - return &apiResponse, nil + return &holdings, nil } + From 9ccb6cc066cbbb1f0da585d6d1f6f0941901b6e3 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 9 Oct 2024 15:05:59 +0300 Subject: [PATCH 016/289] use 99 as the quit --- internal/handlers/ussd/menuhandler.go | 2 +- services/registration/select_voucher.vis | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index c254401..b634f91 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -1060,7 +1060,7 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r var err error inputStr := string(input) - if inputStr == "0" || inputStr == "00" { + if inputStr == "0" || inputStr == "99" { return res, nil } diff --git a/services/registration/select_voucher.vis b/services/registration/select_voucher.vis index 50b99ad..08aa434 100644 --- a/services/registration/select_voucher.vis +++ b/services/registration/select_voucher.vis @@ -1,7 +1,7 @@ LOAD get_vouchers 0 MAP get_vouchers MOUT back 0 -MOUT quit 00 +MOUT quit 99 MNEXT next 11 MPREV prev 22 HALT @@ -9,7 +9,7 @@ LOAD view_voucher 80 RELOAD view_voucher CATCH . flag_incorrect_voucher 1 INCMP _ 0 -INCMP quit 9 +INCMP quit 99 INCMP > 11 INCMP < 22 INCMP view_voucher * From 6c904a8b3fab516bb49d1a950cda05785883fc0a Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 9 Oct 2024 15:38:19 +0300 Subject: [PATCH 017/289] add the temporary and active symbol --- internal/utils/db.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/utils/db.go b/internal/utils/db.go index 3080c1b..f70e08b 100644 --- a/internal/utils/db.go +++ b/internal/utils/db.go @@ -24,6 +24,8 @@ const ( DATA_AMOUNT DATA_TEMPORARY_PIN DATA_VOUCHER_LIST + DATA_TEMPORARY_SYM + DATA_ACTIVE_SYM ) func typToBytes(typ DataTyp) []byte { From 9ad7d5a5226619eac07e99bcd4ffe1f3ec89548b Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 9 Oct 2024 15:39:06 +0300 Subject: [PATCH 018/289] set the active symbol --- internal/handlers/handlerservice.go | 1 + internal/handlers/ussd/menuhandler.go | 49 +++++++++++++++++++++++++-- services/registration/voucher_set | 2 +- services/registration/voucher_set.vis | 2 ++ services/registration/voucher_set_swa | 2 +- 5 files changed, 52 insertions(+), 4 deletions(-) diff --git a/internal/handlers/handlerservice.go b/internal/handlers/handlerservice.go index 4c152b9..3b79ea2 100644 --- a/internal/handlers/handlerservice.go +++ b/internal/handlers/handlerservice.go @@ -95,6 +95,7 @@ func (ls *LocalHandlerService) GetHandler() (*ussd.Handlers, error) { ls.DbRs.AddLocalFunc("check_vouchers", ussdHandlers.CheckVouchers) ls.DbRs.AddLocalFunc("get_vouchers", ussdHandlers.GetVoucherList) ls.DbRs.AddLocalFunc("view_voucher", ussdHandlers.ViewVoucher) + ls.DbRs.AddLocalFunc("set_voucher", ussdHandlers.SetVoucher) return ussdHandlers, nil } diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index b634f91..fbb254b 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -1058,6 +1058,13 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result var err error + store := h.userdataStore + + sessionId, ok := ctx.Value("SessionId").(string) + if !ok { + return res, fmt.Errorf("missing session") + } + inputStr := string(input) if inputStr == "0" || inputStr == "99" { @@ -1067,7 +1074,6 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r flag_incorrect_voucher, _ := h.flagManager.GetFlag("flag_incorrect_voucher") // Initialize the store and prefix database - store := h.userdataStore prefixdb := storage.NewSubPrefixDb(store, []byte("token_holdings")) // Retrieve the voucher symbol list @@ -1111,8 +1117,12 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r } } - // If a match is found, return the symbol and balance + // If a match is found, write the temporary sym , then return the symbol and balance if matchedSymbol != "" && matchedBalance != "" { + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_SYM, []byte(matchedSymbol)) + if err != nil { + return res, err + } res.Content = fmt.Sprintf("%s\n%s", matchedSymbol, matchedBalance) res.FlagReset = append(res.FlagReset, flag_incorrect_voucher) } else { @@ -1121,3 +1131,38 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r return res, nil } + +// SetVoucher retrieves the temporary voucher, sets it as the active voucher and +// clears the temporary voucher/sym +func (h *Handlers) SetVoucher(ctx context.Context, sym string, input []byte) (resource.Result, error) { + var res resource.Result + var err error + store := h.userdataStore + + sessionId, ok := ctx.Value("SessionId").(string) + if !ok { + return res, fmt.Errorf("missing session") + } + + // get the current temporary symbol + temporarySym, err := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_SYM) + if err != nil { + return res, err + } + + // set the active symbol + err = store.WriteEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM, []byte(temporarySym)) + if err != nil { + return res, err + } + + // reset the temporary symbol + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_SYM, []byte("")) + if err != nil { + return res, err + } + + res.Content = string(temporarySym) + + return res, nil +} diff --git a/services/registration/voucher_set b/services/registration/voucher_set index 838c1ef..e90d2e5 100644 --- a/services/registration/voucher_set +++ b/services/registration/voucher_set @@ -1 +1 @@ -Success! symbol is now your active voucher. \ No newline at end of file +Success! {{.set_voucher}} is now your active voucher. \ No newline at end of file diff --git a/services/registration/voucher_set.vis b/services/registration/voucher_set.vis index 832ef22..e3e81f5 100644 --- a/services/registration/voucher_set.vis +++ b/services/registration/voucher_set.vis @@ -1,3 +1,5 @@ +LOAD set_voucher 12 +MAP set_voucher MOUT back 0 MOUT quit 9 HALT diff --git a/services/registration/voucher_set_swa b/services/registration/voucher_set_swa index 320a315..97d3fde 100644 --- a/services/registration/voucher_set_swa +++ b/services/registration/voucher_set_swa @@ -1 +1 @@ -Hongera! symbol ni Sarafu inayotumika sasa. \ No newline at end of file +Hongera! {{.set_voucher}} ni Sarafu inayotumika sasa. \ No newline at end of file From 7c08a0f0afad4f01b52321f17e4ef4a7f458a635 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 10 Oct 2024 14:48:23 +0300 Subject: [PATCH 019/289] add temp and active balance --- internal/handlers/ussd/menuhandler.go | 19 +++++++++++++++++++ internal/utils/db.go | 2 ++ 2 files changed, 21 insertions(+) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index fbb254b..e459975 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -1123,6 +1123,10 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r if err != nil { return res, err } + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_BAL, []byte(matchedBalance)) + if err != nil { + return res, err + } res.Content = fmt.Sprintf("%s\n%s", matchedSymbol, matchedBalance) res.FlagReset = append(res.FlagReset, flag_incorrect_voucher) } else { @@ -1149,18 +1153,33 @@ func (h *Handlers) SetVoucher(ctx context.Context, sym string, input []byte) (re if err != nil { return res, err } + // get the current temporary balance + temporaryBal, err := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_BAL) + if err != nil { + return res, err + } // set the active symbol err = store.WriteEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM, []byte(temporarySym)) if err != nil { return res, err } + // set the active balance + err = store.WriteEntry(ctx, sessionId, utils.DATA_ACTIVE_BAL, []byte(temporaryBal)) + if err != nil { + return res, err + } // reset the temporary symbol err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_SYM, []byte("")) if err != nil { return res, err } + // reset the temporary balance + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_BAL, []byte("")) + if err != nil { + return res, err + } res.Content = string(temporarySym) diff --git a/internal/utils/db.go b/internal/utils/db.go index f70e08b..45e7681 100644 --- a/internal/utils/db.go +++ b/internal/utils/db.go @@ -26,6 +26,8 @@ const ( DATA_VOUCHER_LIST DATA_TEMPORARY_SYM DATA_ACTIVE_SYM + DATA_TEMPORARY_BAL + DATA_ACTIVE_BAL ) func typToBytes(typ DataTyp) []byte { From ea2df552958f5b9fb53dcc916f4ac9a635f28547 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 10 Oct 2024 15:18:13 +0300 Subject: [PATCH 020/289] use go-vise v0.2.0 --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index e3a441a..cdadce5 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module git.grassecon.net/urdt/ussd go 1.22.6 require ( - git.defalsify.org/vise.git v0.1.0-rc.3.0.20240926120105-89b0529cf7ac + git.defalsify.org/vise.git v0.2.0 github.com/alecthomas/assert/v2 v2.2.2 github.com/peteole/testdata-loader v0.3.0 gopkg.in/leonelquinteros/gotext.v1 v1.3.1 diff --git a/go.sum b/go.sum index 3f7a262..d8a1553 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ git.defalsify.org/vise.git v0.1.0-rc.3.0.20240923162317-c20d557a3dbb h1:6P4kxihc git.defalsify.org/vise.git v0.1.0-rc.3.0.20240923162317-c20d557a3dbb/go.mod h1:JDguWmcoWBdsnpw7PUjVZAEpdC/ubBmjdUBy3tjP63M= git.defalsify.org/vise.git v0.1.0-rc.3.0.20240926120105-89b0529cf7ac h1:D4KI22KWXT8S66sHIjWhTBX6SXRfnd7j8VErq3PPbok= git.defalsify.org/vise.git v0.1.0-rc.3.0.20240926120105-89b0529cf7ac/go.mod h1:JDguWmcoWBdsnpw7PUjVZAEpdC/ubBmjdUBy3tjP63M= +git.defalsify.org/vise.git v0.2.0 h1:X2ZgiGRq4C+9qOlDMP0b/oE5QHjVQNT4aEFZB88ST0Q= +git.defalsify.org/vise.git v0.2.0/go.mod h1:JDguWmcoWBdsnpw7PUjVZAEpdC/ubBmjdUBy3tjP63M= 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= From 6c93fb76b11eacfbd44a27436ae0d6ea1a0bbcb8 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 11 Oct 2024 09:36:43 +0300 Subject: [PATCH 021/289] correctly added the flag and the flag count --- cmd/africastalking/main.go | 2 +- cmd/async/main.go | 2 +- cmd/http/main.go | 2 +- cmd/main.go | 2 +- services/registration/pp.csv | 3 ++- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cmd/africastalking/main.go b/cmd/africastalking/main.go index c24c4b1..4dbf555 100644 --- a/cmd/africastalking/main.go +++ b/cmd/africastalking/main.go @@ -87,7 +87,7 @@ func main() { cfg := engine.Config{ Root: "root", OutputSize: uint32(size), - FlagCount: uint32(16), + FlagCount: uint32(17), } if engineDebug { diff --git a/cmd/async/main.go b/cmd/async/main.go index 09236fd..eda54f8 100644 --- a/cmd/async/main.go +++ b/cmd/async/main.go @@ -60,7 +60,7 @@ func main() { cfg := engine.Config{ Root: "root", OutputSize: uint32(size), - FlagCount: uint32(16), + FlagCount: uint32(17), } if engineDebug { diff --git a/cmd/http/main.go b/cmd/http/main.go index 6b868ed..3708f92 100644 --- a/cmd/http/main.go +++ b/cmd/http/main.go @@ -48,7 +48,7 @@ func main() { cfg := engine.Config{ Root: "root", OutputSize: uint32(size), - FlagCount: uint32(16), + FlagCount: uint32(17), } if engineDebug { diff --git a/cmd/main.go b/cmd/main.go index 9db5e0a..b0cdb80 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -40,7 +40,7 @@ func main() { Root: "root", SessionId: sessionId, OutputSize: uint32(size), - FlagCount: uint32(16), + FlagCount: uint32(17), } resourceDir := scriptDir diff --git a/services/registration/pp.csv b/services/registration/pp.csv index 2a7bb21..1391771 100644 --- a/services/registration/pp.csv +++ b/services/registration/pp.csv @@ -12,5 +12,6 @@ flag,flag_invalid_amount,18,this is set when the given transaction amount is inv flag,flag_incorrect_pin,19,this is set when the provided PIN is invalid or does not match the current account's PIN flag,flag_valid_pin,20,this is set when the given PIN is valid flag,flag_allow_update,21,this is set to allow a user to update their profile data -flag,flag_incorrect_voucher,22,this is set when the selected voucher is invalid +flag,flag_single_edit,22,this is set to allow a user to edit a single profile item such as year of birth flag,flag_incorrect_date_format,23,this is set when the given year of birth is invalid +flag,flag_incorrect_voucher,24,this is set when the selected voucher is invalid From 8f834b3d76e44a8c854eefccfa19bb8be397d1da Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 11 Oct 2024 09:41:47 +0300 Subject: [PATCH 022/289] ensure that a user is authorized --- services/registration/voucher_set.vis | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/registration/voucher_set.vis b/services/registration/voucher_set.vis index e3e81f5..e75c693 100644 --- a/services/registration/voucher_set.vis +++ b/services/registration/voucher_set.vis @@ -1,3 +1,6 @@ +LOAD reset_incorrect 6 +CATCH incorrect_pin flag_incorrect_pin 1 +CATCH _ flag_account_authorized 0 LOAD set_voucher 12 MAP set_voucher MOUT back 0 From 672eebb8fb43ac8947730532a5d0830c1da93587 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 11 Oct 2024 09:42:08 +0300 Subject: [PATCH 023/289] display the balance based on the symbol --- internal/handlers/ussd/menuhandler.go | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index e459975..fb1db3f 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -660,11 +660,28 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) ( return res, err } - balance, err := h.accountService.CheckBalance(string(publicKey)) + // check if the user has an active sym + activeSym, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM) if err != nil { - return res, nil + if db.IsNotFound(err) { + logg.Printf(logging.LVL_INFO, "Using the default sym to fetch balance") + balance, err := h.accountService.CheckBalance(string(publicKey)) + if err != nil { + return res, err + } + + res.Content = balance + + return res, nil + } } - res.Content = balance + + activeBal, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_BAL) + if err != nil { + return res, err + } + + res.Content = fmt.Sprintf("%s %s", activeBal, activeSym) return res, nil } From a5b1c5b74e9c7da4f650a9c6d1b77f4d1ae4f379 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Sat, 12 Oct 2024 14:32:40 +0300 Subject: [PATCH 024/289] cleaned up the code --- internal/handlers/ussd/menuhandler.go | 65 +++++++++++++-------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index fb1db3f..4196325 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -233,28 +233,6 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt return res, nil } -// GetVoucherList fetches the list of vouchers and formats them -// checks whether they are stored internally before calling the API -func (h *Handlers) GetVoucherList(ctx context.Context, sym string, input []byte) (resource.Result, error) { - var res resource.Result - - // check if the vouchers exist internally and if not - // fetch from the API - - // Read vouchers from the store - store := h.userdataStore - prefixdb := storage.NewSubPrefixDb(store, []byte("token_holdings")) - - voucherData, err := prefixdb.Get(ctx, []byte("tokens")) - if err != nil { - return res, nil - } - - res.Content = string(voucherData) - - 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) @@ -1057,13 +1035,13 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) voucherSymbolList := strings.Join(numberedSymbols, "\n") voucherBalanceList := strings.Join(numberedBalances, "\n") - prefixdb := storage.NewSubPrefixDb(store, []byte("token_holdings")) - err = prefixdb.Put(ctx, []byte("tokens"), []byte(voucherSymbolList)) + prefixdb := storage.NewSubPrefixDb(store, []byte("pfx")) + err = prefixdb.Put(ctx, []byte("sym"), []byte(voucherSymbolList)) if err != nil { return res, nil } - err = prefixdb.Put(ctx, []byte(voucherSymbolList), []byte(voucherBalanceList)) + err = prefixdb.Put(ctx, []byte("bal"), []byte(voucherBalanceList)) if err != nil { return res, nil } @@ -1071,6 +1049,24 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) return res, nil } +// 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 + + // Read vouchers from the store + store := h.userdataStore + prefixdb := storage.NewSubPrefixDb(store, []byte("pfx")) + + voucherData, err := prefixdb.Get(ctx, []byte("sym")) + if err != nil { + return res, nil + } + + res.Content = string(voucherData) + + return res, nil +} + // ViewVoucher retrieves the token holding and balance from the subprefixDB func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result @@ -1082,25 +1078,25 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r return res, fmt.Errorf("missing session") } + flag_incorrect_voucher, _ := h.flagManager.GetFlag("flag_incorrect_voucher") + inputStr := string(input) if inputStr == "0" || inputStr == "99" { + res.FlagReset = append(res.FlagReset, flag_incorrect_voucher) return res, nil } - flag_incorrect_voucher, _ := h.flagManager.GetFlag("flag_incorrect_voucher") - - // Initialize the store and prefix database - prefixdb := storage.NewSubPrefixDb(store, []byte("token_holdings")) + prefixdb := storage.NewSubPrefixDb(store, []byte("pfx")) // Retrieve the voucher symbol list - voucherSymbolList, err := prefixdb.Get(ctx, []byte("tokens")) + voucherSymbolList, err := prefixdb.Get(ctx, []byte("sym")) if err != nil { return res, fmt.Errorf("failed to retrieve voucher symbol list: %v", err) } // Retrieve the voucher balance list - voucherBalanceList, err := prefixdb.Get(ctx, []byte(voucherSymbolList)) + voucherBalanceList, err := prefixdb.Get(ctx, []byte("bal")) if err != nil { return res, fmt.Errorf("failed to retrieve voucher balance list: %v", err) } @@ -1134,7 +1130,7 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r } } - // If a match is found, write the temporary sym , then return the symbol and balance + // If a match is found, write the temporary sym, then return the symbol and balance if matchedSymbol != "" && matchedBalance != "" { err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_SYM, []byte(matchedSymbol)) if err != nil { @@ -1153,8 +1149,9 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r return res, nil } -// SetVoucher retrieves the temporary voucher, sets it as the active voucher and -// clears the temporary voucher/sym +// SetVoucher retrieves the temporary sym and balance, +// sets them as the active data and +// clears the temporary data func (h *Handlers) SetVoucher(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result var err error From e9684fcf45b4fc3873d84dda5d932bf7721b193b Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Sat, 12 Oct 2024 16:28:02 +0300 Subject: [PATCH 025/289] check whether the active symbol is empty --- internal/handlers/ussd/menuhandler.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 4196325..d6d8102 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -652,6 +652,20 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) ( return res, nil } + + return res, err + } + + if len(activeSym) == 0 { + logg.Printf(logging.LVL_INFO, "Using the default sym to fetch balance") + balance, err := h.accountService.CheckBalance(string(publicKey)) + if err != nil { + return res, err + } + + res.Content = balance + + return res, nil } activeBal, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_BAL) From b6d24bf92938fce74eada07f3e454fcf71e32fa0 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Sat, 12 Oct 2024 16:29:12 +0300 Subject: [PATCH 026/289] update the TestCheckBalance --- internal/handlers/ussd/menuhandler_test.go | 83 ++++++++++++++++------ 1 file changed, 61 insertions(+), 22 deletions(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 1ce8b51..21edb3d 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -1560,33 +1560,72 @@ func TestValidateRecipient(t *testing.T) { } func TestCheckBalance(t *testing.T) { - - mockDataStore := new(mocks.MockUserDataStore) - sessionId := "session123" - publicKey := "0X13242618721" - balance := "0.003 CELO" - - expectedResult := resource.Result{ - Content: "0.003 CELO", + tests := []struct { + name string + sessionId string + publicKey string + activeSym string + activeBal string + expectedResult resource.Result + expectError bool + }{ + { + name: "User with active sym", + sessionId: "session456", + publicKey: "0X98765432109", + activeSym: "ETH", + activeBal: "1.5", + expectedResult: resource.Result{Content: "1.5 ETH"}, + expectError: false, + }, + { + name: "User without active sym", + sessionId: "session123", + publicKey: "0X13242618721", + activeSym: "", + activeBal: "", + expectedResult: resource.Result{Content: "0.003 CELO"}, + expectError: false, + }, } - mockCreateAccountService := new(mocks.MockAccountService) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockDataStore := new(mocks.MockUserDataStore) + mockAccountService := new(mocks.MockAccountService) + ctx := context.WithValue(context.Background(), "SessionId", tt.sessionId) - ctx := context.WithValue(context.Background(), "SessionId", sessionId) + h := &Handlers{ + userdataStore: mockDataStore, + accountService: mockAccountService, + } - h := &Handlers{ - userdataStore: mockDataStore, - accountService: mockCreateAccountService, - //flagManager: fm.parser, + // Mock calls for public key + mockDataStore.On("ReadEntry", ctx, tt.sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(tt.publicKey), nil) + + if tt.activeSym == "" { + // Mock for user without active sym + mockDataStore.On("ReadEntry", ctx, tt.sessionId, utils.DATA_ACTIVE_SYM).Return([]byte{}, db.ErrNotFound{}) + mockAccountService.On("CheckBalance", tt.publicKey).Return("0.003 CELO", nil) + } else { + // Mock for user with active sym + mockDataStore.On("ReadEntry", ctx, tt.sessionId, utils.DATA_ACTIVE_SYM).Return([]byte(tt.activeSym), nil) + mockDataStore.On("ReadEntry", ctx, tt.sessionId, utils.DATA_ACTIVE_BAL).Return([]byte(tt.activeBal), nil) + } + + res, err := h.CheckBalance(ctx, "check_balance", []byte("123456")) + + if tt.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, tt.expectedResult, res, "Result should match expected output") + } + + mockDataStore.AssertExpectations(t) + mockAccountService.AssertExpectations(t) + }) } - //mock call operations - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil) - mockCreateAccountService.On("CheckBalance", string(publicKey)).Return(balance, nil) - - res, _ := h.CheckBalance(ctx, "check_balance", []byte("123456")) - - assert.Equal(t, res, expectedResult, "Result should contain flag(s) that have been reset") - } func TestGetProfile(t *testing.T) { From a9f986797677d6430ad7d783dc0241b35ca62674 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Sat, 12 Oct 2024 17:36:00 +0300 Subject: [PATCH 027/289] added the TestSetVoucher --- internal/handlers/ussd/menuhandler_test.go | 35 +++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 21edb3d..9159722 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -1782,5 +1782,38 @@ func TestConfirmPin(t *testing.T) { }) } - +} + +func TestSetVoucher(t *testing.T) { + mockDataStore := new(mocks.MockUserDataStore) + + sessionId := "session123" + ctx := context.WithValue(context.Background(), "SessionId", sessionId) + + temporarySym := []byte("tempSym") + temporaryBal := []byte("tempBal") + + // Set expectations for the mock data store + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_SYM).Return(temporarySym, nil) + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_BAL).Return(temporaryBal, nil) + mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM, temporarySym).Return(nil) + mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_BAL, temporaryBal).Return(nil) + mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_SYM, []byte("")).Return(nil) + mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_BAL, []byte("")).Return(nil) + + h := &Handlers{ + userdataStore: mockDataStore, + } + + // Call the method under test + res, err := h.SetVoucher(ctx, "someSym", []byte{}) + + // Assert that no errors occurred + assert.NoError(t, err) + + // Assert that the result content is correct + assert.Equal(t, string(temporarySym), res.Content) + + // Assert that expectations were met + mockDataStore.AssertExpectations(t) } From 7fe8f0b7d578d1541207a8604a909c08b8124a68 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Sat, 12 Oct 2024 18:03:13 +0300 Subject: [PATCH 028/289] updated the args under FetchVouchers --- internal/mocks/servicemock.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/mocks/servicemock.go b/internal/mocks/servicemock.go index 8fbde0f..f8f638a 100644 --- a/internal/mocks/servicemock.go +++ b/internal/mocks/servicemock.go @@ -26,6 +26,6 @@ func (m *MockAccountService) CheckAccountStatus(trackingId string) (string, erro } func (m *MockAccountService) FetchVouchers(publicKey string) (*models.VoucherHoldingResponse, error) { - args := m.Called() + args := m.Called(publicKey) return args.Get(0).(*models.VoucherHoldingResponse), args.Error(1) } From f5dbfe553d90ee2e57cf7371ff66486828ccfbea Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Sat, 12 Oct 2024 20:06:00 +0300 Subject: [PATCH 029/289] use the check_balance for the max_amount --- internal/handlers/handlerservice.go | 1 - services/registration/amount | 2 +- services/registration/amount.vis | 4 ++-- services/registration/amount_swa | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/internal/handlers/handlerservice.go b/internal/handlers/handlerservice.go index 3b79ea2..0d891f1 100644 --- a/internal/handlers/handlerservice.go +++ b/internal/handlers/handlerservice.go @@ -69,7 +69,6 @@ func (ls *LocalHandlerService) GetHandler() (*ussd.Handlers, error) { ls.DbRs.AddLocalFunc("check_balance", ussdHandlers.CheckBalance) ls.DbRs.AddLocalFunc("validate_recipient", ussdHandlers.ValidateRecipient) ls.DbRs.AddLocalFunc("transaction_reset", ussdHandlers.TransactionReset) - ls.DbRs.AddLocalFunc("max_amount", ussdHandlers.MaxAmount) ls.DbRs.AddLocalFunc("validate_amount", ussdHandlers.ValidateAmount) ls.DbRs.AddLocalFunc("reset_transaction_amount", ussdHandlers.ResetTransactionAmount) ls.DbRs.AddLocalFunc("get_recipient", ussdHandlers.GetRecipient) diff --git a/services/registration/amount b/services/registration/amount index 9142aba..d3e8602 100644 --- a/services/registration/amount +++ b/services/registration/amount @@ -1,2 +1,2 @@ -Maximum amount: {{.max_amount}} +Maximum amount: {{.check_balance}} Enter amount: \ No newline at end of file diff --git a/services/registration/amount.vis b/services/registration/amount.vis index b491fab..5a02ff9 100644 --- a/services/registration/amount.vis +++ b/services/registration/amount.vis @@ -1,6 +1,6 @@ LOAD reset_transaction_amount 0 -LOAD max_amount 10 -MAP max_amount +LOAD check_balance 48 +MAP check_balance MOUT back 0 HALT LOAD validate_amount 64 diff --git a/services/registration/amount_swa b/services/registration/amount_swa index 0c8cf01..d071f63 100644 --- a/services/registration/amount_swa +++ b/services/registration/amount_swa @@ -1,2 +1,2 @@ -Kiwango cha juu: {{.max_amount}} +Kiwango cha juu: {{.check_balance}} Weka kiwango: \ No newline at end of file From 7df77a134307823e058ca05541a004283189d0e1 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Sat, 12 Oct 2024 20:07:06 +0300 Subject: [PATCH 030/289] updated the ValidateAmount to also check the active symbol, updated tests --- internal/handlers/ussd/menuhandler.go | 88 +++++++++------------- internal/handlers/ussd/menuhandler_test.go | 76 +++++++++---------- 2 files changed, 72 insertions(+), 92 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index d6d8102..3e164af 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -761,74 +761,60 @@ func (h *Handlers) ResetTransactionAmount(ctx context.Context, sym string, input return res, nil } -// MaxAmount gets the current balance from the API and sets it as -// the result content. -func (h *Handlers) MaxAmount(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") - } - store := h.userdataStore - publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) - - balance, err := h.accountService.CheckBalance(string(publicKey)) - if err != nil { - return res, nil - } - - res.Content = balance - - return res, nil -} - // ValidateAmount ensures that the given input is a valid amount and that // it is not more than the current balance. func (h *Handlers) ValidateAmount(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_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount") - store := h.userdataStore - publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) - - amountStr := string(input) - - balanceStr, err := h.accountService.CheckBalance(string(publicKey)) + publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) if err != nil { return res, err } - res.Content = balanceStr - // Parse the balance - balanceParts := strings.Split(balanceStr, " ") - 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) + // retrieve the active symbol + activeSym, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM) + useActiveSymbol := err == nil && len(activeSym) > 0 + + var balanceValue float64 + if useActiveSymbol { + // If active symbol is set, retrieve its balance + activeBal, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_BAL) + if err != nil { + return res, fmt.Errorf("failed to get active balance: %v", err) + } + balanceValue, err = strconv.ParseFloat(string(activeBal), 64) + if err != nil { + return res, fmt.Errorf("failed to parse active balance: %v", err) + } + } else { + // If no active symbol, use the current balance from the API + balanceStr, err := h.accountService.CheckBalance(string(publicKey)) + if err != nil { + return res, fmt.Errorf("failed to check balance: %v", err) + } + res.Content = balanceStr + + // Parse the balance string + balanceParts := strings.Split(balanceStr, " ") + 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) + } } - // Extract numeric part from input - 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 - } - - inputAmount, err := strconv.ParseFloat(matches[1], 64) + // Extract numeric part from the input amount + amountStr := strings.TrimSpace(string(input)) + inputAmount, err := strconv.ParseFloat(amountStr, 64) if err != nil { res.FlagSet = append(res.FlagSet, flag_invalid_amount) res.Content = amountStr @@ -841,12 +827,12 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte) return res, nil } - res.Content = fmt.Sprintf("%.3f", inputAmount) // Format to 3 decimal places err = store.WriteEntry(ctx, sessionId, utils.DATA_AMOUNT, []byte(amountStr)) if err != nil { return res, err } + res.Content = fmt.Sprintf("%.3f", inputAmount) return res, nil } diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 9159722..4fd9d22 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -434,34 +434,6 @@ func TestCheckIdentifier(t *testing.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) @@ -1444,59 +1416,81 @@ func TestValidateAmount(t *testing.T) { name string input []byte publicKey []byte + activeSym []byte + activeBal []byte balance string expectedResult resource.Result }{ { - name: "Test with valid amount", + name: "Test with valid amount and active symbol", input: []byte("0.001"), - balance: "0.003 CELO", publicKey: []byte("0xrqeqrequuq"), + activeSym: []byte("CELO"), + activeBal: []byte("0.003"), expectedResult: resource.Result{ Content: "0.001", }, }, { - name: "Test with amount larger than balance", + name: "Test with amount larger than active balance", input: []byte("0.02"), - balance: "0.003 CELO", publicKey: []byte("0xrqeqrequuq"), + activeSym: []byte("CELO"), + activeBal: []byte("0.003"), expectedResult: resource.Result{ FlagSet: []uint32{flag_invalid_amount}, Content: "0.02", }, }, { - name: "Test with invalid amount", + name: "Test with invalid amount format", input: []byte("0.02ms"), - balance: "0.003 CELO", publicKey: []byte("0xrqeqrequuq"), + balance: "0.003 CELO", expectedResult: resource.Result{ FlagSet: []uint32{flag_invalid_amount}, Content: "0.02ms", }, }, + { + name: "Test fallback to current balance without active symbol", + input: []byte("0.001"), + publicKey: []byte("0xrqeqrequuq"), + balance: "0.003 CELO", + expectedResult: resource.Result{ + Content: "0.001", + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - + // Mock behavior for public key retrieval mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return(tt.publicKey, nil) - mockCreateAccountService.On("CheckBalance", string(tt.publicKey)).Return(tt.balance, nil) + + // Mock behavior for active symbol and balance retrieval (if present) + if len(tt.activeSym) > 0 { + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM).Return(tt.activeSym, nil) + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACTIVE_BAL).Return(tt.activeBal, nil) + } else { + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM).Return(nil, fmt.Errorf("not found")) + mockCreateAccountService.On("CheckBalance", string(tt.publicKey)).Return(tt.balance, nil) + } + + // Mock behavior for storing the amount (if valid) mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_AMOUNT, tt.input).Return(nil).Maybe() // Call the method under test res, _ := h.ValidateAmount(ctx, "test_validate_amount", tt.input) - // Assert that no errors occurred + // Assert no errors occurred assert.NoError(t, err) - //Assert that the account created flag has been set to the result - assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") + // Assert the result matches the expected result + assert.Equal(t, tt.expectedResult, res, "Expected result should match actual result") - // Assert that expectations were met + // Assert all expectations were met mockDataStore.AssertExpectations(t) - }) } } From 8ed98b3e6cc3e3e0d2baf6eda6a26ff919a333b5 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Tue, 15 Oct 2024 14:53:00 +0300 Subject: [PATCH 031/289] resolve case issue --- internal/handlers/ussd/menuhandler_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 4fd9d22..f36814a 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -171,7 +171,7 @@ func TestSaveFamilyname(t *testing.T) { mockStore.AssertExpectations(t) } -func TestSaveTemporaryPIn(t *testing.T) { +func TestSaveTemporaryPin(t *testing.T) { fm, err := NewFlagManager(flagsPath) mockStore := new(mocks.MockUserDataStore) if err != nil { From 6c6af5ec210a0b5782c9d17ca3b2d4900dc270cc Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Tue, 15 Oct 2024 15:46:02 +0300 Subject: [PATCH 032/289] set a default voucher as the active sym if none exists --- internal/handlers/handlerservice.go | 1 + internal/handlers/ussd/menuhandler.go | 93 ++++++++++++++++++--------- services/registration/main.vis | 2 + 3 files changed, 67 insertions(+), 29 deletions(-) diff --git a/internal/handlers/handlerservice.go b/internal/handlers/handlerservice.go index 0d891f1..129d851 100644 --- a/internal/handlers/handlerservice.go +++ b/internal/handlers/handlerservice.go @@ -91,6 +91,7 @@ func (ls *LocalHandlerService) GetHandler() (*ussd.Handlers, error) { ls.DbRs.AddLocalFunc("verify_new_pin", ussdHandlers.VerifyNewPin) ls.DbRs.AddLocalFunc("confirm_pin_change", ussdHandlers.ConfirmPinChange) ls.DbRs.AddLocalFunc("quit_with_help", ussdHandlers.QuitWithHelp) + ls.DbRs.AddLocalFunc("set_default_voucher", ussdHandlers.SetDefaultVoucher) ls.DbRs.AddLocalFunc("check_vouchers", ussdHandlers.CheckVouchers) ls.DbRs.AddLocalFunc("get_vouchers", ussdHandlers.GetVoucherList) ls.DbRs.AddLocalFunc("view_voucher", ussdHandlers.ViewVoucher) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 3e164af..af3b99f 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -633,41 +633,13 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) ( } store := h.userdataStore - publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) - if err != nil { - return res, err - } - // check if the user has an active sym + // get the active sym and active balance activeSym, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM) if err != nil { - if db.IsNotFound(err) { - logg.Printf(logging.LVL_INFO, "Using the default sym to fetch balance") - balance, err := h.accountService.CheckBalance(string(publicKey)) - if err != nil { - return res, err - } - - res.Content = balance - - return res, nil - } - return res, err } - if len(activeSym) == 0 { - logg.Printf(logging.LVL_INFO, "Using the default sym to fetch balance") - balance, err := h.accountService.CheckBalance(string(publicKey)) - if err != nil { - return res, err - } - - res.Content = balance - - return res, nil - } - activeBal, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_BAL) if err != nil { return res, err @@ -1004,6 +976,69 @@ func (h *Handlers) GetProfileInfo(ctx context.Context, sym string, input []byte) return res, nil } +// SetDefaultVoucher retrieves the current vouchers +// 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 + store := h.userdataStore + + sessionId, ok := ctx.Value("SessionId").(string) + if !ok { + return res, fmt.Errorf("missing session") + } + + fmt.Println("Running SetDefaultVoucher") + + // check if the user has an active sym + _, err = store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM) + + if err != nil { + if db.IsNotFound(err) { + publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) + + if err != nil { + return res, nil + } + + // Fetch vouchers from the API using the public key + vouchersResp, err := h.accountService.FetchVouchers(string(publicKey)) + if err != nil { + return res, nil + } + + // Ensure there is at least one voucher + if len(vouchersResp.Result.Holdings) == 0 { + return res, err + } + + // Use only the first voucher + firstVoucher := vouchersResp.Result.Holdings[0] + defaultSym := firstVoucher.TokenSymbol + defaultBal := firstVoucher.Balance + + // set the active symbol + err = store.WriteEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM, []byte(defaultSym)) + if err != nil { + return res, err + } + // set the active balance + err = store.WriteEntry(ctx, sessionId, utils.DATA_ACTIVE_BAL, []byte(defaultBal)) + if err != nil { + return res, err + } + + return res, nil + } + + fmt.Println("Nothing will happen as the error in not 404") + + return res, err + } + + return res, nil +} + // CheckVouchers retrieves the token holdings from the API using the "PublicKey" and stores // them to gdbm func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) (resource.Result, error) { diff --git a/services/registration/main.vis b/services/registration/main.vis index 88f8a42..b809ece 100644 --- a/services/registration/main.vis +++ b/services/registration/main.vis @@ -1,3 +1,5 @@ +LOAD set_default_voucher 8 +RELOAD set_default_voucher LOAD check_balance 64 RELOAD check_balance LOAD check_vouchers 10 From 859e203a006159da26aa784fa2f87ae4a0772b57 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Tue, 15 Oct 2024 15:54:43 +0300 Subject: [PATCH 033/289] removed debug comments --- internal/handlers/ussd/menuhandler.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index af3b99f..c3d1870 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -988,8 +988,6 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by return res, fmt.Errorf("missing session") } - fmt.Println("Running SetDefaultVoucher") - // check if the user has an active sym _, err = store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM) @@ -1031,8 +1029,6 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by return res, nil } - fmt.Println("Nothing will happen as the error in not 404") - return res, err } From b2fb9faf6c450d5afe1e79f9a6a6220c4a9b2a6d Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Tue, 15 Oct 2024 16:17:33 +0300 Subject: [PATCH 034/289] use the active balance to validate the amount --- internal/handlers/ussd/menuhandler.go | 41 +++++---------------------- 1 file changed, 7 insertions(+), 34 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index c3d1870..f263e4b 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -745,43 +745,16 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte) flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount") store := h.userdataStore - publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) + var balanceValue float64 + + // retrieve the active balance + activeBal, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_BAL) if err != nil { return res, err } - - // retrieve the active symbol - activeSym, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM) - useActiveSymbol := err == nil && len(activeSym) > 0 - - var balanceValue float64 - if useActiveSymbol { - // If active symbol is set, retrieve its balance - activeBal, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_BAL) - if err != nil { - return res, fmt.Errorf("failed to get active balance: %v", err) - } - balanceValue, err = strconv.ParseFloat(string(activeBal), 64) - if err != nil { - return res, fmt.Errorf("failed to parse active balance: %v", err) - } - } else { - // If no active symbol, use the current balance from the API - balanceStr, err := h.accountService.CheckBalance(string(publicKey)) - if err != nil { - return res, fmt.Errorf("failed to check balance: %v", err) - } - res.Content = balanceStr - - // Parse the balance string - balanceParts := strings.Split(balanceStr, " ") - 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) - } + balanceValue, err = strconv.ParseFloat(string(activeBal), 64) + if err != nil { + return res, err } // Extract numeric part from the input amount From f378f154223349108e953f2a2c0edeb76b9c2680 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Tue, 15 Oct 2024 16:29:51 +0300 Subject: [PATCH 035/289] updated tests --- internal/handlers/ussd/menuhandler_test.go | 61 ++++------------------ 1 file changed, 9 insertions(+), 52 deletions(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index f36814a..901a15a 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -1415,17 +1415,13 @@ func TestValidateAmount(t *testing.T) { tests := []struct { name string input []byte - publicKey []byte - activeSym []byte activeBal []byte balance string expectedResult resource.Result }{ { - name: "Test with valid amount and active symbol", + name: "Test with valid amount", input: []byte("0.001"), - publicKey: []byte("0xrqeqrequuq"), - activeSym: []byte("CELO"), activeBal: []byte("0.003"), expectedResult: resource.Result{ Content: "0.001", @@ -1434,8 +1430,6 @@ func TestValidateAmount(t *testing.T) { { name: "Test with amount larger than active balance", input: []byte("0.02"), - publicKey: []byte("0xrqeqrequuq"), - activeSym: []byte("CELO"), activeBal: []byte("0.003"), expectedResult: resource.Result{ FlagSet: []uint32{flag_invalid_amount}, @@ -1445,37 +1439,18 @@ func TestValidateAmount(t *testing.T) { { name: "Test with invalid amount format", input: []byte("0.02ms"), - publicKey: []byte("0xrqeqrequuq"), balance: "0.003 CELO", expectedResult: resource.Result{ FlagSet: []uint32{flag_invalid_amount}, Content: "0.02ms", }, }, - { - name: "Test fallback to current balance without active symbol", - input: []byte("0.001"), - publicKey: []byte("0xrqeqrequuq"), - balance: "0.003 CELO", - expectedResult: resource.Result{ - Content: "0.001", - }, - }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - // Mock behavior for public key retrieval - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return(tt.publicKey, nil) - - // Mock behavior for active symbol and balance retrieval (if present) - if len(tt.activeSym) > 0 { - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM).Return(tt.activeSym, nil) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACTIVE_BAL).Return(tt.activeBal, nil) - } else { - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM).Return(nil, fmt.Errorf("not found")) - mockCreateAccountService.On("CheckBalance", string(tt.publicKey)).Return(tt.balance, nil) - } + // Mock behavior for active balance retrieval + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACTIVE_BAL).Return(tt.activeBal, nil) // Mock behavior for storing the amount (if valid) mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_AMOUNT, tt.input).Return(nil).Maybe() @@ -1572,15 +1547,6 @@ func TestCheckBalance(t *testing.T) { expectedResult: resource.Result{Content: "1.5 ETH"}, expectError: false, }, - { - name: "User without active sym", - sessionId: "session123", - publicKey: "0X13242618721", - activeSym: "", - activeBal: "", - expectedResult: resource.Result{Content: "0.003 CELO"}, - expectError: false, - }, } for _, tt := range tests { @@ -1593,21 +1559,12 @@ func TestCheckBalance(t *testing.T) { userdataStore: mockDataStore, accountService: mockAccountService, } - - // Mock calls for public key - mockDataStore.On("ReadEntry", ctx, tt.sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(tt.publicKey), nil) - - if tt.activeSym == "" { - // Mock for user without active sym - mockDataStore.On("ReadEntry", ctx, tt.sessionId, utils.DATA_ACTIVE_SYM).Return([]byte{}, db.ErrNotFound{}) - mockAccountService.On("CheckBalance", tt.publicKey).Return("0.003 CELO", nil) - } else { - // Mock for user with active sym - mockDataStore.On("ReadEntry", ctx, tt.sessionId, utils.DATA_ACTIVE_SYM).Return([]byte(tt.activeSym), nil) - mockDataStore.On("ReadEntry", ctx, tt.sessionId, utils.DATA_ACTIVE_BAL).Return([]byte(tt.activeBal), nil) - } - - res, err := h.CheckBalance(ctx, "check_balance", []byte("123456")) + + // Mock for user with active sym + mockDataStore.On("ReadEntry", ctx, tt.sessionId, utils.DATA_ACTIVE_SYM).Return([]byte(tt.activeSym), nil) + mockDataStore.On("ReadEntry", ctx, tt.sessionId, utils.DATA_ACTIVE_BAL).Return([]byte(tt.activeBal), nil) + + res, err := h.CheckBalance(ctx, "check_balance", []byte("")) if tt.expectError { assert.Error(t, err) From a336856c9b8fc4b028c29cce967d043a609468c3 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Tue, 15 Oct 2024 17:02:51 +0300 Subject: [PATCH 036/289] use separate functions to process voucher data --- internal/handlers/ussd/menuhandler.go | 79 ++++++++++++++++----------- 1 file changed, 48 insertions(+), 31 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index f263e4b..8041bf7 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -1029,15 +1029,8 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) return res, nil } - var numberedSymbols []string - var numberedBalances []string - for i, voucher := range vouchersResp.Result.Holdings { - numberedSymbols = append(numberedSymbols, fmt.Sprintf("%d:%s", i+1, voucher.TokenSymbol)) - numberedBalances = append(numberedBalances, fmt.Sprintf("%d:%s", i+1, voucher.Balance)) - } - - voucherSymbolList := strings.Join(numberedSymbols, "\n") - voucherBalanceList := strings.Join(numberedBalances, "\n") + // process voucher data + voucherSymbolList, voucherBalanceList := ProcessVouchers(vouchersResp.Result.Holdings) prefixdb := storage.NewSubPrefixDb(store, []byte("pfx")) err = prefixdb.Put(ctx, []byte("sym"), []byte(voucherSymbolList)) @@ -1053,6 +1046,26 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) return res, nil } +// ProcessVouchers formats the holdings into symbol and balance lists. +func ProcessVouchers(holdings []struct { + ContractAddress string `json:"contractAddress"` + TokenSymbol string `json:"tokenSymbol"` + TokenDecimals string `json:"tokenDecimals"` + Balance string `json:"balance"` +}) (string, string) { + var numberedSymbols, numberedBalances []string + + for i, voucher := range holdings { + numberedSymbols = append(numberedSymbols, fmt.Sprintf("%d:%s", i+1, voucher.TokenSymbol)) + numberedBalances = append(numberedBalances, fmt.Sprintf("%d:%s", i+1, voucher.Balance)) + } + + voucherSymbolList := strings.Join(numberedSymbols, "\n") + voucherBalanceList := strings.Join(numberedBalances, "\n") + + return voucherSymbolList, voucherBalanceList +} + // 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 @@ -1074,7 +1087,6 @@ func (h *Handlers) GetVoucherList(ctx context.Context, sym string, input []byte) // ViewVoucher retrieves the token holding and balance from the subprefixDB func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result - var err error store := h.userdataStore sessionId, ok := ctx.Value("SessionId").(string) @@ -1105,10 +1117,31 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r return res, fmt.Errorf("failed to retrieve voucher balance list: %v", err) } - // Convert the symbol and balance lists from byte arrays to strings - voucherSymbols := string(voucherSymbolList) - voucherBalances := string(voucherBalanceList) + // match the voucher symbol and balance with the input + matchedSymbol, matchedBalance := MatchVoucher(inputStr, string(voucherSymbolList), string(voucherBalanceList)) + // If a match is found, write the temporary sym and balance + if matchedSymbol != "" && matchedBalance != "" { + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_SYM, []byte(matchedSymbol)) + if err != nil { + return res, err + } + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_BAL, []byte(matchedBalance)) + if err != nil { + return res, err + } + + res.FlagReset = append(res.FlagReset, flag_incorrect_voucher) + res.Content = fmt.Sprintf("%s\n%s", matchedSymbol, matchedBalance) + } else { + res.FlagSet = append(res.FlagSet, flag_incorrect_voucher) + } + + return res, nil +} + +// MatchVoucher finds the matching voucher symbol and balance based on the input. +func MatchVoucher(inputStr string, voucherSymbols, voucherBalances string) (string, string) { // Split the lists into slices for processing symbols := strings.Split(voucherSymbols, "\n") balances := strings.Split(voucherBalances, "\n") @@ -1128,29 +1161,13 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r matchedSymbol = voucherSymbol // Ensure there's a corresponding balance if i < len(balances) { - matchedBalance = strings.SplitN(balances[i], ":", 2)[1] // Extract balance after the "x:balance" format + matchedBalance = strings.SplitN(balances[i], ":", 2)[1] } break } } - // If a match is found, write the temporary sym, then return the symbol and balance - if matchedSymbol != "" && matchedBalance != "" { - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_SYM, []byte(matchedSymbol)) - if err != nil { - return res, err - } - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_BAL, []byte(matchedBalance)) - if err != nil { - return res, err - } - res.Content = fmt.Sprintf("%s\n%s", matchedSymbol, matchedBalance) - res.FlagReset = append(res.FlagReset, flag_incorrect_voucher) - } else { - res.FlagSet = append(res.FlagSet, flag_incorrect_voucher) - } - - return res, nil + return matchedSymbol, matchedBalance } // SetVoucher retrieves the temporary sym and balance, From f73b7a8b04595cabbff4944e0b13fe57842f38f4 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 16 Oct 2024 22:40:40 +0300 Subject: [PATCH 037/289] setup api responses --- internal/handlers/server/api.go | 60 +++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 internal/handlers/server/api.go diff --git a/internal/handlers/server/api.go b/internal/handlers/server/api.go new file mode 100644 index 0000000..646458c --- /dev/null +++ b/internal/handlers/server/api.go @@ -0,0 +1,60 @@ +package server + +type ( + OKResponse struct { + Ok bool `json:"ok"` + Description string `json:"description"` + Result map[string]any `json:"result"` + } + + ErrResponse struct { + Ok bool `json:"ok"` + Description string `json:"description"` + ErrCode string `json:"errorCode"` + } + + TransferRequest struct { + From string `json:"from" validate:"required,eth_addr_checksum"` + To string `json:"to" validate:"required,eth_addr_checksum"` + TokenAddress string `json:"tokenAddress" validate:"required,eth_addr_checksum"` + Amount string `json:"amount" validate:"required,number,gt=0"` + } + + PoolSwapRequest struct { + From string `json:"from" validate:"required,eth_addr_checksum"` + FromTokenAddress string `json:"fromTokenAddress" validate:"required,eth_addr_checksum"` + ToTokenAddress string `json:"toTokenAddress" validate:"required,eth_addr_checksum"` + PoolAddress string `json:"poolAddress" validate:"required,eth_addr_checksum"` + Amount string `json:"amount" validate:"required,number,gt=0"` + } + + PoolDepositRequest struct { + From string `json:"from" validate:"required,eth_addr_checksum"` + TokenAddress string `json:"tokenAddress" validate:"required,eth_addr_checksum"` + PoolAddress string `json:"poolAddress" validate:"required,eth_addr_checksum"` + Amount string `json:"amount" validate:"required,number,gt=0"` + } + + AccountAddressParam struct { + Address string `param:"address" validate:"required,eth_addr_checksum"` + } + + TrackingIDParam struct { + TrackingID string `param:"trackingId" validate:"required,uuid"` + } + + OTXByAccountRequest struct { + Address string `param:"address" validate:"required,eth_addr_checksum"` + PerPage int `query:"perPage" validate:"required,number,gt=0"` + Cursor int `query:"cursor" validate:"number"` + Next bool `query:"next"` + } +) + +const ( + ErrCodeInternalServerError = "E01" + ErrCodeInvalidJSON = "E02" + ErrCodeInvalidAPIKey = "E03" + ErrCodeValidationFailed = "E04" + ErrCodeAccountNotExists = "E05" +) From eea3be3a39c1fe5ee1be7ea2f7c7ad7a5a8e3125 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 17 Oct 2024 13:49:56 +0300 Subject: [PATCH 038/289] resolve failing test --- internal/handlers/ussd/menuhandler_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index c624e0f..499c426 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -1440,7 +1440,6 @@ func TestValidateAmount(t *testing.T) { t.Logf(err.Error()) } flag_invalid_amount, _ := fm.parser.GetFlag("flag_invalid_amount") - flag_api_error, _ := fm.GetFlag("flag_api_call_error") mockDataStore := new(mocks.MockUserDataStore) mockCreateAccountService := new(mocks.MockAccountService) @@ -1466,7 +1465,6 @@ func TestValidateAmount(t *testing.T) { activeBal: []byte("0.003"), expectedResult: resource.Result{ Content: "0.001", - FlagReset: []uint32{flag_api_error}, }, }, { @@ -1475,7 +1473,6 @@ func TestValidateAmount(t *testing.T) { activeBal: []byte("0.003"), expectedResult: resource.Result{ FlagSet: []uint32{flag_invalid_amount}, - FlagReset: []uint32{flag_api_error}, Content: "0.02", }, }, @@ -1485,7 +1482,6 @@ func TestValidateAmount(t *testing.T) { balance: "0.003 CELO", expectedResult: resource.Result{ FlagSet: []uint32{flag_invalid_amount}, - FlagReset: []uint32{flag_api_error}, Content: "0.02ms", }, }, From 4f043628358f5e3edb7c73ae239b17f07eee8869 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 17 Oct 2024 16:08:18 +0300 Subject: [PATCH 039/289] pass error description to error response --- internal/handlers/server/accountservice.go | 116 ++++++++++++++++++--- 1 file changed, 103 insertions(+), 13 deletions(-) diff --git a/internal/handlers/server/accountservice.go b/internal/handlers/server/accountservice.go index 1ddf7e7..7bb3dee 100644 --- a/internal/handlers/server/accountservice.go +++ b/internal/handlers/server/accountservice.go @@ -2,6 +2,7 @@ package server import ( "encoding/json" + "fmt" "io" "net/http" @@ -9,17 +10,21 @@ import ( "git.grassecon.net/urdt/ussd/internal/models" ) +var apiResponse struct { + Ok bool `json:"ok"` + Description string `json:"description"` +} + type AccountServiceInterface interface { CheckBalance(publicKey string) (*models.BalanceResponse, error) - CreateAccount() (*models.AccountResponse, error) + CreateAccount() (*OKResponse, *ErrResponse) CheckAccountStatus(trackingId string) (*models.TrackStatusResponse, error) + TrackAccountStatus(publicKey string) (*OKResponse, *ErrResponse) } type AccountService struct { } -// CheckAccountStatus retrieves the status of an account transaction based on the provided tracking ID. -// // Parameters: // - trackingId: A unique identifier for the account.This should be obtained from a previous call to // CreateAccount or a similar function that returns an AccountResponse. The `trackingId` field in the @@ -28,9 +33,9 @@ type AccountService struct { // 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. +// If no error occurs, this will be nil func (as *AccountService) CheckAccountStatus(trackingId string) (*models.TrackStatusResponse, error) { - resp, err := http.Get(config.TrackStatusURL + trackingId) + resp, err := http.Get(config.BalanceURL + trackingId) if err != nil { return nil, err } @@ -40,12 +45,67 @@ func (as *AccountService) CheckAccountStatus(trackingId string) (*models.TrackSt if err != nil { return nil, err } + var trackResp models.TrackStatusResponse err = json.Unmarshal(body, &trackResp) if err != nil { return nil, err } return &trackResp, nil + +} + +func (as *AccountService) TrackAccountStatus(publicKey string) (*OKResponse, *ErrResponse) { + var errResponse ErrResponse + var okResponse OKResponse + var err error + // Construct the URL with the path parameter + url := fmt.Sprintf("%s/%s", config.TrackURL, publicKey) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + errResponse.Description = err.Error() + return nil, &errResponse + } + // Set headers + req.Header.Set("Content-Type", "application/json") + req.Header.Set("X-GE-KEY", "xd") + + // Send the request + resp, err := http.DefaultClient.Do(req) + if err != nil { + errResponse.Description = err.Error() + return nil, &errResponse + } + defer resp.Body.Close() + + // Read the response body + body, err := io.ReadAll(resp.Body) + if err != nil { + errResponse.Description = err.Error() + return nil, &errResponse + } + + // Step 2: Unmarshal into the generic struct + err = json.Unmarshal([]byte(body), &apiResponse) + if err != nil { + errResponse.Description = err.Error() + return nil, &errResponse + } + if apiResponse.Ok { + err = json.Unmarshal([]byte(body), &okResponse) + if err != nil { + errResponse.Description = err.Error() + return nil, &errResponse + } + return &okResponse, nil + } else { + err := json.Unmarshal([]byte(body), &errResponse) + if err != nil { + errResponse.Description = err.Error() + return nil, &errResponse + } + return nil, &errResponse + } } // CheckBalance retrieves the balance for a given public key from the custodial balance API endpoint. @@ -75,20 +135,50 @@ func (as *AccountService) CheckBalance(publicKey string) (*models.BalanceRespons // 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) +func (as *AccountService) CreateAccount() (*OKResponse, *ErrResponse) { + + var errResponse ErrResponse + var okResponse OKResponse + var err error + + // Create a new request + req, err := http.NewRequest("POST", config.CreateAccountURL, nil) if err != nil { - return nil, err + errResponse.Description = err.Error() + return nil, &errResponse + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("X-GE-KEY", "xd") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + errResponse.Description = err.Error() + return nil, &errResponse } defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) if err != nil { - return nil, err + errResponse.Description = err.Error() + return nil, &errResponse } - var accountResp models.AccountResponse - err = json.Unmarshal(body, &accountResp) + err = json.Unmarshal([]byte(body), &apiResponse) if err != nil { - return nil, err + return nil, &errResponse + } + if apiResponse.Ok { + err = json.Unmarshal([]byte(body), &okResponse) + if err != nil { + errResponse.Description = err.Error() + return nil, &errResponse + } + return &okResponse, nil + } else { + err := json.Unmarshal([]byte(body), &errResponse) + if err != nil { + errResponse.Description = err.Error() + return nil, &errResponse + } + return nil, &errResponse } - return &accountResp, nil } From b8e12e5215ec48c49dc7673a0dd9509a155df5e1 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Fri, 18 Oct 2024 17:01:21 +0300 Subject: [PATCH 040/289] update api endpoints --- config/config.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/config/config.go b/config/config.go index 0571503..a035d24 100644 --- a/config/config.go +++ b/config/config.go @@ -1,10 +1,7 @@ package config - - const ( - CreateAccountURL = "https://custodial.sarafu.africa/api/account/create" - TrackStatusURL = "https://custodial.sarafu.africa/api/track/" - BalanceURL = "https://custodial.sarafu.africa/api/account/status/" + CreateAccountURL = "http://localhost:5003/api/v2/account/create" + BalanceURL = "https://custodial.sarafu.africa/api/account/status/" + TrackURL = "http://localhost:5003/api/v2/account/status" ) - From 81c4189c8eaf254bec11a7a78681dc83e9d8b1ad Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Fri, 18 Oct 2024 17:02:08 +0300 Subject: [PATCH 041/289] update tests --- internal/handlers/ussd/menuhandler_test.go | 142 +++++++++++---------- 1 file changed, 78 insertions(+), 64 deletions(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 0bde51a..97c0dee 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -15,6 +15,7 @@ import ( "git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/state" + "git.grassecon.net/urdt/ussd/internal/handlers/server" "git.grassecon.net/urdt/ussd/internal/mocks" "git.grassecon.net/urdt/ussd/internal/models" "git.grassecon.net/urdt/ussd/internal/utils" @@ -78,68 +79,75 @@ func TestCreateAccount(t *testing.T) { if err != nil { t.Logf(err.Error()) } - // Create required mocks - mockDataStore := new(mocks.MockUserDataStore) - mockCreateAccountService := new(mocks.MockAccountService) - expectedResult := resource.Result{} - accountCreatedFlag, err := fm.GetFlag("flag_account_created") - + flag_account_created, err := fm.GetFlag("flag_account_created") if err != nil { t.Logf(err.Error()) } - expectedResult.FlagSet = append(expectedResult.FlagSet, accountCreatedFlag) // Define session ID and mock data sessionId := "session123" - typ := utils.DATA_ACCOUNT_CREATED - fakeError := db.ErrNotFound{} - // Create context with session ID + notFoundErr := db.ErrNotFound{} ctx := context.WithValue(context.Background(), "SessionId", sessionId) - // Define expected interactions with the mock - mockDataStore.On("ReadEntry", ctx, sessionId, typ).Return([]byte("123"), fakeError) - expectedAccountResp := &models.AccountResponse{ - Ok: true, - Result: struct { - CustodialId json.Number `json:"custodialId"` - PublicKey string `json:"publicKey"` - TrackingId string `json:"trackingId"` - }{ - CustodialId: "12", - PublicKey: "0x8E0XSCSVA", - TrackingId: "d95a7e83-196c-4fd0-866fSGAGA", + tests := []struct { + name string + serverResponse *server.OKResponse + expectedResult resource.Result + }{ + { + name: "Test account creation success", + serverResponse: &server.OKResponse{ + Ok: true, + Description: "Account creation successed", + Result: map[string]any{ + "trackingId": "1234567890", + "publicKey": "1235QERYU", + }, + }, + expectedResult: resource.Result{ + FlagSet: []uint32{flag_account_created}, + }, }, } - mockCreateAccountService.On("CreateAccount").Return(expectedAccountResp, nil) - data := map[utils.DataTyp]string{ - utils.DATA_TRACKING_ID: expectedAccountResp.Result.TrackingId, - utils.DATA_PUBLIC_KEY: expectedAccountResp.Result.PublicKey, - utils.DATA_CUSTODIAL_ID: expectedAccountResp.Result.CustodialId.String(), + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + mockDataStore := new(mocks.MockUserDataStore) + mockCreateAccountService := new(mocks.MockAccountService) + + // Create a Handlers instance with the mock data store + h := &Handlers{ + userdataStore: mockDataStore, + accountService: mockCreateAccountService, + flagManager: fm.parser, + } + + data := map[utils.DataTyp]string{ + utils.DATA_TRACKING_ID: tt.serverResponse.Result["trackingId"].(string), + utils.DATA_PUBLIC_KEY: tt.serverResponse.Result["publicKey"].(string), + } + + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACCOUNT_CREATED).Return([]byte(""), notFoundErr) + mockCreateAccountService.On("CreateAccount").Return(tt.serverResponse, nil) + + for key, value := range data { + mockDataStore.On("WriteEntry", ctx, sessionId, key, []byte(value)).Return(nil) + } + + // Call the method you want to test + res, err := h.CreateAccount(ctx, "create_account", []byte("some-input")) + + // Assert that no errors occurred + assert.NoError(t, err) + + // Assert that the account created flag has been set to the result + assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") + + // Assert that expectations were met + mockDataStore.AssertExpectations(t) + }) } - - for key, value := range data { - mockDataStore.On("WriteEntry", ctx, sessionId, key, []byte(value)).Return(nil) - } - - // Create a Handlers instance with the mock data store - h := &Handlers{ - userdataStore: mockDataStore, - accountService: mockCreateAccountService, - flagManager: fm.parser, - } - - // Call the method you want to test - res, err := h.CreateAccount(ctx, "create_account", []byte("some-input")) - - // Assert that no errors occurred - assert.NoError(t, err) - - //Assert that the account created flag has been set to the result - assert.Equal(t, res, expectedResult, "Expected result should be equal to the actual result") - - // Assert that expectations were met - mockDataStore.AssertExpectations(t) } func TestWithPersister(t *testing.T) { @@ -1072,12 +1080,20 @@ func TestCheckAccountStatus(t *testing.T) { tests := []struct { name string input []byte + serverResponse *server.OKResponse response *models.TrackStatusResponse expectedResult resource.Result }{ { - name: "Test when account status is Success", + name: "Test when account is on the Sarafu network", input: []byte("TrackingId1234"), + serverResponse: &server.OKResponse{ + Ok: true, + Description: "Account creation successed", + Result: map[string]any{ + "active": true, + }, + }, response: &models.TrackStatusResponse{ Ok: true, Result: struct { @@ -1104,17 +1120,7 @@ func TestCheckAccountStatus(t *testing.T) { }, }, { - name: "Test when fetching account status is not Success", - input: []byte("TrackingId1234"), - response: &models.TrackStatusResponse{ - Ok: false, - }, - expectedResult: resource.Result{ - FlagSet: []uint32{flag_api_error}, - }, - }, - { - name: "Test when checking account status api call is a SUCCESS but an account is not yet ready", + name: "Test when the account is not yet on the sarafu network", input: []byte("TrackingId1234"), response: &models.TrackStatusResponse{ Ok: true, @@ -1129,13 +1135,20 @@ func TestCheckAccountStatus(t *testing.T) { }{ Transaction: Transaction{ CreatedAt: time.Now(), - Status: "IN_NETWORK", + Status: "SUCCESS", TransferValue: json.Number("0.5"), TxHash: "0x123abc456def", TxType: "transfer", }, }, }, + serverResponse: &server.OKResponse{ + Ok: true, + Description: "Account creation successed", + Result: map[string]any{ + "active": false, + }, + }, expectedResult: resource.Result{ FlagSet: []uint32{flag_account_pending}, FlagReset: []uint32{flag_api_error, flag_account_success}, @@ -1155,9 +1168,10 @@ func TestCheckAccountStatus(t *testing.T) { status := tt.response.Result.Transaction.Status // Define expected interactions with the mock - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TRACKING_ID).Return(tt.input, nil) + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return(tt.input, nil) mockCreateAccountService.On("CheckAccountStatus", string(tt.input)).Return(tt.response, nil) + mockCreateAccountService.On("TrackAccountStatus", string(tt.input)).Return(tt.serverResponse, nil) mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACCOUNT_STATUS, []byte(status)).Return(nil).Maybe() // Call the method under test From 128a354b34f2ed7f2eb44d99054dc4ac9d161a2c Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Fri, 18 Oct 2024 17:03:48 +0300 Subject: [PATCH 042/289] use api structs --- internal/handlers/ussd/menuhandler.go | 48 +++++++++++---------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 6059dd4..adf4111 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -27,6 +27,8 @@ var ( logg = logging.NewVanilla().WithDomain("ussdmenuhandler") scriptDir = path.Join("services", "registration") translationDir = path.Join(scriptDir, "locale") + okResponse *server.OKResponse + errResponse *server.ErrResponse ) // FlagManager handles centralized flag management @@ -136,11 +138,16 @@ func (h *Handlers) SetLanguage(ctx context.Context, sym string, input []byte) (r } func (h *Handlers) createAccountNoExist(ctx context.Context, sessionId string, res *resource.Result) error { - accountResp, err := h.accountService.CreateAccount() + okResponse, errResponse := h.accountService.CreateAccount() + if errResponse != nil { + return nil + } + trackingId := okResponse.Result["trackingId"].(string) + publicKey := okResponse.Result["publicKey"].(string) + data := map[utils.DataTyp]string{ - utils.DATA_TRACKING_ID: accountResp.Result.TrackingId, - utils.DATA_PUBLIC_KEY: accountResp.Result.PublicKey, - utils.DATA_CUSTODIAL_ID: accountResp.Result.CustodialId.String(), + utils.DATA_TRACKING_ID: trackingId, + utils.DATA_PUBLIC_KEY: publicKey, } for key, value := range data { @@ -152,7 +159,7 @@ func (h *Handlers) createAccountNoExist(ctx context.Context, sessionId string, r } flag_account_created, _ := h.flagManager.GetFlag("flag_account_created") res.FlagSet = append(res.FlagSet, flag_account_created) - return err + return nil } @@ -191,7 +198,6 @@ func (h *Handlers) SavePin(ctx context.Context, sym string, input []byte) (resou } flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin") - accountPIN := string(input) // Validate that the PIN is a 4-digit number if !isValidPIN(accountPIN) { @@ -368,7 +374,6 @@ func (h *Handlers) SaveYob(ctx context.Context, sym string, input []byte) (resou if !ok { return res, fmt.Errorf("missing session") } - if len(input) == 4 { yob := string(input) store := h.userdataStore @@ -411,7 +416,6 @@ func (h *Handlers) SaveGender(ctx context.Context, sym string, input []byte) (re if !ok { return res, fmt.Errorf("missing session") } - gender := strings.Split(symbol, "_")[1] store := h.userdataStore err = store.WriteEntry(ctx, sessionId, utils.DATA_GENDER, []byte(gender)) @@ -430,7 +434,6 @@ func (h *Handlers) SaveOfferings(ctx context.Context, sym string, input []byte) if !ok { return res, fmt.Errorf("missing session") } - if len(input) > 0 { offerings := string(input) store := h.userdataStore @@ -456,7 +459,6 @@ func (h *Handlers) ResetAllowUpdate(ctx context.Context, sym string, input []byt // ResetAccountAuthorized resets the account authorization flag after a successful PIN entry. func (h *Handlers) ResetAccountAuthorized(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result - flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized") res.FlagReset = append(res.FlagReset, flag_account_authorized) @@ -466,12 +468,10 @@ func (h *Handlers) ResetAccountAuthorized(ctx context.Context, sym string, input // CheckIdentifier retrieves the PublicKey from the JSON data file. func (h *Handlers) CheckIdentifier(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 publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) @@ -485,12 +485,10 @@ func (h *Handlers) CheckIdentifier(ctx context.Context, sym string, input []byte func (h *Handlers) Authorize(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") flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized") flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") @@ -542,28 +540,20 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b return res, fmt.Errorf("missing session") } store := h.userdataStore - trackingId, err := store.ReadEntry(ctx, sessionId, utils.DATA_TRACKING_ID) + publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) if err != nil { return res, err } - - accountStatus, err := h.accountService.CheckAccountStatus(string(trackingId)) - if err != nil { - fmt.Println("Error checking account status:", err) - return res, err - } - if !accountStatus.Ok { - res.FlagSet = append(res.FlagSet, flag_api_error) + okResponse, errResponse = h.accountService.TrackAccountStatus(string(publicKey)) + if errResponse != nil { return res, err } res.FlagReset = append(res.FlagReset, flag_api_error) - status := accountStatus.Result.Transaction.Status - - err = store.WriteEntry(ctx, sessionId, utils.DATA_ACCOUNT_STATUS, []byte(status)) - if err != nil { - return res, nil + isActive := okResponse.Result["active"].(bool) + if !ok { + return res, err } - if accountStatus.Result.Transaction.Status == "SUCCESS" { + if isActive { res.FlagSet = append(res.FlagSet, flag_account_success) res.FlagReset = append(res.FlagReset, flag_account_pending) } else { From 1c57c95d93efdf6d26a795f1987a9da8a712bac2 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Fri, 18 Oct 2024 17:04:02 +0300 Subject: [PATCH 043/289] use api structs --- internal/mocks/servicemock.go | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/internal/mocks/servicemock.go b/internal/mocks/servicemock.go index d828045..7796b77 100644 --- a/internal/mocks/servicemock.go +++ b/internal/mocks/servicemock.go @@ -1,6 +1,7 @@ package mocks import ( + "git.grassecon.net/urdt/ussd/internal/handlers/server" "git.grassecon.net/urdt/ussd/internal/models" "github.com/stretchr/testify/mock" ) @@ -10,9 +11,19 @@ type MockAccountService struct { mock.Mock } -func (m *MockAccountService) CreateAccount() (*models.AccountResponse, error) { +func (m *MockAccountService) CreateAccount() (*server.OKResponse, *server.ErrResponse) { args := m.Called() - return args.Get(0).(*models.AccountResponse), args.Error(1) + okResponse, ok := args.Get(0).(*server.OKResponse) + errResponse, err := args.Get(1).(*server.ErrResponse) + + if ok { + return okResponse, nil + } + + if err { + return nil, errResponse + } + return nil, nil } func (m *MockAccountService) CheckBalance(publicKey string) (*models.BalanceResponse, error) { @@ -23,4 +34,17 @@ func (m *MockAccountService) CheckBalance(publicKey string) (*models.BalanceResp func (m *MockAccountService) CheckAccountStatus(trackingId string) (*models.TrackStatusResponse, error) { args := m.Called(trackingId) return args.Get(0).(*models.TrackStatusResponse), args.Error(1) -} \ No newline at end of file +} + +func (m *MockAccountService) TrackAccountStatus(publicKey string) (*server.OKResponse, *server.ErrResponse) { + args := m.Called(publicKey) + okResponse, ok := args.Get(0).(*server.OKResponse) + errResponse, err := args.Get(1).(*server.ErrResponse) + if ok { + return okResponse, nil + } + if err { + return nil, errResponse + } + return nil, nil +} From 353e24de33e79f79705b9022edc6a59ce3ce4245 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Fri, 18 Oct 2024 17:04:43 +0300 Subject: [PATCH 044/289] define api structs --- internal/models/accountresponse.go | 17 ++++++----------- internal/models/trackstatusresponse.go | 3 +-- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/internal/models/accountresponse.go b/internal/models/accountresponse.go index 1422a20..efcc30b 100644 --- a/internal/models/accountresponse.go +++ b/internal/models/accountresponse.go @@ -1,15 +1,10 @@ package models -import ( - "encoding/json" - -) - type AccountResponse struct { - Ok bool `json:"ok"` - Result struct { - CustodialId json.Number `json:"custodialId"` - PublicKey string `json:"publicKey"` - TrackingId string `json:"trackingId"` + Ok bool `json:"ok"` + Description string `json:"description"` // Include the description field + Result struct { + PublicKey string `json:"publicKey"` + TrackingId string `json:"trackingId"` } `json:"result"` -} \ No newline at end of file +} diff --git a/internal/models/trackstatusresponse.go b/internal/models/trackstatusresponse.go index 6054281..667c544 100644 --- a/internal/models/trackstatusresponse.go +++ b/internal/models/trackstatusresponse.go @@ -5,7 +5,6 @@ import ( "time" ) - type TrackStatusResponse struct { Ok bool `json:"ok"` Result struct { @@ -17,4 +16,4 @@ type TrackStatusResponse struct { TxType string `json:"txType"` } } `json:"result"` -} \ No newline at end of file +} From b8860478b6f469572ec13f68b4d07215cbf4a9f9 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Fri, 18 Oct 2024 17:36:51 +0300 Subject: [PATCH 045/289] implement expected structs --- internal/handlers/server/accountservice.go | 28 ++++++++++++---------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/internal/handlers/server/accountservice.go b/internal/handlers/server/accountservice.go index 451c661..c284d63 100644 --- a/internal/handlers/server/accountservice.go +++ b/internal/handlers/server/accountservice.go @@ -187,19 +187,13 @@ func (as *AccountService) CreateAccount() (*OKResponse, *ErrResponse) { } } -func (tas *TestAccountService) CreateAccount() (*models.AccountResponse, error) { - return &models.AccountResponse{ - Ok: true, - Result: struct { - CustodialId json.Number `json:"custodialId"` - PublicKey string `json:"publicKey"` - TrackingId string `json:"trackingId"` - }{ - CustodialId: json.Number("182"), - PublicKey: "0x48ADca309b5085852207FAaf2816eD72B52F527C", - TrackingId: "28ebe84d-b925-472c-87ae-bbdfa1fb97be", - }, +func (tas *TestAccountService) CreateAccount() (*OKResponse, *ErrResponse) { + return &OKResponse{ + Ok: true, + Description: "Account creation request received successfully", + Result: map[string]any{"publicKey": "0x48ADca309b5085852207FAaf2816eD72B52F527C", "trackingId": "28ebe84d-b925-472c-87ae-bbdfa1fb97be"}, }, nil + } func (tas *TestAccountService) CheckBalance(publicKey string) (*models.BalanceResponse, error) { @@ -218,6 +212,16 @@ func (tas *TestAccountService) CheckBalance(publicKey string) (*models.BalanceRe return balanceResponse, nil } +func (tas *TestAccountService) TrackAccountStatus(publicKey string) (*OKResponse, *ErrResponse) { + return &OKResponse{ + Ok: true, + Description: "Account creation succeeded", + Result: map[string]any{ + "active": true, + }, + }, nil +} + func (tas *TestAccountService) CheckAccountStatus(trackingId string) (*models.TrackStatusResponse, error) { trackResponse := &models.TrackStatusResponse{ Ok: true, From f643aa4d14091a13f62bee23b73d736de7170bac Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Fri, 18 Oct 2024 17:37:04 +0300 Subject: [PATCH 046/289] update tests --- internal/handlers/ussd/menuhandler_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index de1a481..f84ca06 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -1082,7 +1082,7 @@ func TestCheckAccountStatus(t *testing.T) { input: []byte("TrackingId1234"), serverResponse: &server.OKResponse{ Ok: true, - Description: "Account creation successed", + Description: "Account creation succeeded", Result: map[string]any{ "active": true, }, @@ -1137,7 +1137,7 @@ func TestCheckAccountStatus(t *testing.T) { }, serverResponse: &server.OKResponse{ Ok: true, - Description: "Account creation successed", + Description: "Account creation succeeded", Result: map[string]any{ "active": false, }, From 25bc7006a4d743f0a74e9d64b3703b59e025d8ae Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 18 Oct 2024 18:31:40 +0300 Subject: [PATCH 047/289] show a balance of 0 and prevent sending when no voucher exists --- internal/handlers/ussd/menuhandler.go | 18 ++++++++++++------ services/registration/no_voucher | 1 + services/registration/no_voucher.vis | 5 +++++ services/registration/no_voucher_swa | 1 + services/registration/pp.csv | 3 ++- services/registration/send.vis | 1 + 6 files changed, 22 insertions(+), 7 deletions(-) create mode 100644 services/registration/no_voucher create mode 100644 services/registration/no_voucher.vis create mode 100644 services/registration/no_voucher_swa diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 4f010d6..93acc02 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -624,7 +624,7 @@ func (h *Handlers) ResetIncorrectYob(ctx context.Context, sym string, input []by return res, nil } -// CheckBalance retrieves the balance from the API using the "PublicKey" and sets +// CheckBalance retrieves the balance of the active voucher and sets // the balance as the result content func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result @@ -640,12 +640,13 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) ( // get the active sym and active balance activeSym, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM) if err != nil { - return res, err + res.Content = "0.00" + return res, nil } activeBal, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_BAL) if err != nil { - return res, err + return res, nil } res.Content = fmt.Sprintf("%s %s", activeBal, activeSym) @@ -991,6 +992,8 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by return res, fmt.Errorf("missing session") } + flag_no_active_voucher, _ := h.flagManager.GetFlag("flag_no_active_voucher") + // check if the user has an active sym _, err = store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM) @@ -1008,9 +1011,10 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by return res, nil } - // Ensure there is at least one voucher + // Return if there is no voucher if len(vouchersResp.Result.Holdings) == 0 { - return res, err + res.FlagSet = append(res.FlagSet, flag_no_active_voucher) + return res, nil } // Use only the first voucher @@ -1035,6 +1039,8 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by return res, err } + res.FlagReset = append(res.FlagReset, flag_no_active_voucher) + return res, nil } @@ -1160,7 +1166,7 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r if err != nil { return res, err } - + res.FlagReset = append(res.FlagReset, flag_incorrect_voucher) res.Content = fmt.Sprintf("%s\n%s", matchedSymbol, matchedBalance) } else { diff --git a/services/registration/no_voucher b/services/registration/no_voucher new file mode 100644 index 0000000..332f00e --- /dev/null +++ b/services/registration/no_voucher @@ -0,0 +1 @@ +You need a voucher to send \ No newline at end of file diff --git a/services/registration/no_voucher.vis b/services/registration/no_voucher.vis new file mode 100644 index 0000000..832ef22 --- /dev/null +++ b/services/registration/no_voucher.vis @@ -0,0 +1,5 @@ +MOUT back 0 +MOUT quit 9 +HALT +INCMP ^ 0 +INCMP quit 9 diff --git a/services/registration/no_voucher_swa b/services/registration/no_voucher_swa new file mode 100644 index 0000000..66e8f26 --- /dev/null +++ b/services/registration/no_voucher_swa @@ -0,0 +1 @@ +Unahitaji sarafu kutuma \ No newline at end of file diff --git a/services/registration/pp.csv b/services/registration/pp.csv index 96d3e8a..ec0d8c1 100644 --- a/services/registration/pp.csv +++ b/services/registration/pp.csv @@ -15,4 +15,5 @@ flag,flag_allow_update,21,this is set to allow a user to update their profile da flag,flag_single_edit,22,this is set to allow a user to edit a single profile item such as year of birth flag,flag_incorrect_date_format,23,this is set when the given year of birth is invalid flag,flag_incorrect_voucher,24,this is set when the selected voucher is invalid -flag,flag_api_call_error,25,this is set when communication to an external service fails +flag,flag_api_call_error,25,this is set when communication to an external service fails +flag,flag_no_active_voucher,26,this is set when a user does not have an active voucher diff --git a/services/registration/send.vis b/services/registration/send.vis index e120302..0ff0927 100644 --- a/services/registration/send.vis +++ b/services/registration/send.vis @@ -1,4 +1,5 @@ LOAD transaction_reset 0 +CATCH no_voucher flag_no_active_voucher 1 MOUT back 0 HALT LOAD validate_recipient 20 From 3bf2045f1552e365113b90861779ac358a55a361 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Sat, 19 Oct 2024 16:07:40 +0300 Subject: [PATCH 048/289] added FetchVouchers to the TestAccountService --- internal/handlers/server/accountservice.go | 29 +++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/internal/handlers/server/accountservice.go b/internal/handlers/server/accountservice.go index e38e13d..ebe825e 100644 --- a/internal/handlers/server/accountservice.go +++ b/internal/handlers/server/accountservice.go @@ -132,7 +132,6 @@ func (tas *TestAccountService) CreateAccount() (*models.AccountResponse, error) } func (tas *TestAccountService) CheckBalance(publicKey string) (*models.BalanceResponse, error) { - balanceResponse := &models.BalanceResponse{ Ok: true, Result: struct { @@ -170,3 +169,31 @@ func (tas *TestAccountService) CheckAccountStatus(trackingId string) (*models.Tr } return trackResponse, nil } + +func (tas *TestAccountService) FetchVouchers(publicKey string) (*models.VoucherHoldingResponse, error) { + return &models.VoucherHoldingResponse{ + Ok: true, + Result: struct { + Holdings []struct { + ContractAddress string `json:"contractAddress"` + TokenSymbol string `json:"tokenSymbol"` + TokenDecimals string `json:"tokenDecimals"` + Balance string `json:"balance"` + } `json:"holdings"` + }{ + Holdings: []struct { + ContractAddress string `json:"contractAddress"` + TokenSymbol string `json:"tokenSymbol"` + TokenDecimals string `json:"tokenDecimals"` + Balance string `json:"balance"` + }{ + { + ContractAddress: "0x6CC75A06ac72eB4Db2eE22F781F5D100d8ec03ee", + TokenSymbol: "SRF", + TokenDecimals: "6", + Balance: "2745987", + }, + }, + }, + }, nil +} From 367d3f0593c4ed5621a32e4187bfb0558be200ac Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 21 Oct 2024 11:07:32 +0300 Subject: [PATCH 049/289] remove manually added api.go file --- internal/handlers/server/api.go | 60 --------------------------------- 1 file changed, 60 deletions(-) delete mode 100644 internal/handlers/server/api.go diff --git a/internal/handlers/server/api.go b/internal/handlers/server/api.go deleted file mode 100644 index 646458c..0000000 --- a/internal/handlers/server/api.go +++ /dev/null @@ -1,60 +0,0 @@ -package server - -type ( - OKResponse struct { - Ok bool `json:"ok"` - Description string `json:"description"` - Result map[string]any `json:"result"` - } - - ErrResponse struct { - Ok bool `json:"ok"` - Description string `json:"description"` - ErrCode string `json:"errorCode"` - } - - TransferRequest struct { - From string `json:"from" validate:"required,eth_addr_checksum"` - To string `json:"to" validate:"required,eth_addr_checksum"` - TokenAddress string `json:"tokenAddress" validate:"required,eth_addr_checksum"` - Amount string `json:"amount" validate:"required,number,gt=0"` - } - - PoolSwapRequest struct { - From string `json:"from" validate:"required,eth_addr_checksum"` - FromTokenAddress string `json:"fromTokenAddress" validate:"required,eth_addr_checksum"` - ToTokenAddress string `json:"toTokenAddress" validate:"required,eth_addr_checksum"` - PoolAddress string `json:"poolAddress" validate:"required,eth_addr_checksum"` - Amount string `json:"amount" validate:"required,number,gt=0"` - } - - PoolDepositRequest struct { - From string `json:"from" validate:"required,eth_addr_checksum"` - TokenAddress string `json:"tokenAddress" validate:"required,eth_addr_checksum"` - PoolAddress string `json:"poolAddress" validate:"required,eth_addr_checksum"` - Amount string `json:"amount" validate:"required,number,gt=0"` - } - - AccountAddressParam struct { - Address string `param:"address" validate:"required,eth_addr_checksum"` - } - - TrackingIDParam struct { - TrackingID string `param:"trackingId" validate:"required,uuid"` - } - - OTXByAccountRequest struct { - Address string `param:"address" validate:"required,eth_addr_checksum"` - PerPage int `query:"perPage" validate:"required,number,gt=0"` - Cursor int `query:"cursor" validate:"number"` - Next bool `query:"next"` - } -) - -const ( - ErrCodeInternalServerError = "E01" - ErrCodeInvalidJSON = "E02" - ErrCodeInvalidAPIKey = "E03" - ErrCodeValidationFailed = "E04" - ErrCodeAccountNotExists = "E05" -) From 5b0a38351325bcf43eae700f5a06ac4e8bd8883b Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 21 Oct 2024 11:09:37 +0300 Subject: [PATCH 050/289] use importable api structs --- internal/handlers/server/accountservice.go | 29 ++++++++++++---------- internal/handlers/ussd/menuhandler_test.go | 14 +++++++---- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/internal/handlers/server/accountservice.go b/internal/handlers/server/accountservice.go index c284d63..39d1c66 100644 --- a/internal/handlers/server/accountservice.go +++ b/internal/handlers/server/accountservice.go @@ -9,18 +9,19 @@ import ( "git.grassecon.net/urdt/ussd/config" "git.grassecon.net/urdt/ussd/internal/models" + "github.com/grassrootseconomics/eth-custodial/pkg/api" ) -var apiResponse struct { +type ApiResponse struct { Ok bool `json:"ok"` Description string `json:"description"` } type AccountServiceInterface interface { CheckBalance(publicKey string) (*models.BalanceResponse, error) - CreateAccount() (*OKResponse, *ErrResponse) + CreateAccount() (*api.OKResponse, *api.ErrResponse) CheckAccountStatus(trackingId string) (*models.TrackStatusResponse, error) - TrackAccountStatus(publicKey string) (*OKResponse, *ErrResponse) + TrackAccountStatus(publicKey string) (*api.OKResponse, *api.ErrResponse) } type AccountService struct { @@ -59,9 +60,9 @@ func (as *AccountService) CheckAccountStatus(trackingId string) (*models.TrackSt } -func (as *AccountService) TrackAccountStatus(publicKey string) (*OKResponse, *ErrResponse) { - var errResponse ErrResponse - var okResponse OKResponse +func (as *AccountService) TrackAccountStatus(publicKey string) (*api.OKResponse, *api.ErrResponse) { + var errResponse api.ErrResponse + var okResponse api.OKResponse var err error // Construct the URL with the path parameter url := fmt.Sprintf("%s/%s", config.TrackURL, publicKey) @@ -90,6 +91,7 @@ func (as *AccountService) TrackAccountStatus(publicKey string) (*OKResponse, *Er } // Step 2: Unmarshal into the generic struct + var apiResponse ApiResponse err = json.Unmarshal([]byte(body), &apiResponse) if err != nil { errResponse.Description = err.Error() @@ -139,10 +141,10 @@ func (as *AccountService) CheckBalance(publicKey string) (*models.BalanceRespons // 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() (*OKResponse, *ErrResponse) { +func (as *AccountService) CreateAccount() (*api.OKResponse, *api.ErrResponse) { - var errResponse ErrResponse - var okResponse OKResponse + var errResponse api.ErrResponse + var okResponse api.OKResponse var err error // Create a new request @@ -166,6 +168,7 @@ func (as *AccountService) CreateAccount() (*OKResponse, *ErrResponse) { errResponse.Description = err.Error() return nil, &errResponse } + var apiResponse ApiResponse err = json.Unmarshal([]byte(body), &apiResponse) if err != nil { return nil, &errResponse @@ -187,8 +190,8 @@ func (as *AccountService) CreateAccount() (*OKResponse, *ErrResponse) { } } -func (tas *TestAccountService) CreateAccount() (*OKResponse, *ErrResponse) { - return &OKResponse{ +func (tas *TestAccountService) CreateAccount() (*api.OKResponse, *api.ErrResponse) { + return &api.OKResponse{ Ok: true, Description: "Account creation request received successfully", Result: map[string]any{"publicKey": "0x48ADca309b5085852207FAaf2816eD72B52F527C", "trackingId": "28ebe84d-b925-472c-87ae-bbdfa1fb97be"}, @@ -212,8 +215,8 @@ func (tas *TestAccountService) CheckBalance(publicKey string) (*models.BalanceRe return balanceResponse, nil } -func (tas *TestAccountService) TrackAccountStatus(publicKey string) (*OKResponse, *ErrResponse) { - return &OKResponse{ +func (tas *TestAccountService) TrackAccountStatus(publicKey string) (*api.OKResponse, *api.ErrResponse) { + return &api.OKResponse{ Ok: true, Description: "Account creation succeeded", Result: map[string]any{ diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index f84ca06..d78f526 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -20,6 +20,7 @@ import ( "git.grassecon.net/urdt/ussd/internal/models" "git.grassecon.net/urdt/ussd/internal/utils" "github.com/alecthomas/assert/v2" + "github.com/grassrootseconomics/eth-custodial/pkg/api" testdataloader "github.com/peteole/testdata-loader" "github.com/stretchr/testify/require" ) @@ -74,6 +75,8 @@ func TestCreateAccount(t *testing.T) { } // Create required mocks flag_account_created, err := fm.GetFlag("flag_account_created") + //flag_api_call_error, err := fm.GetFlag("flag_api_call_error,") + flag_api_call_error, _ := fm.GetFlag("flag_api_call_error") if err != nil { t.Logf(err.Error()) } @@ -85,12 +88,12 @@ func TestCreateAccount(t *testing.T) { tests := []struct { name string - serverResponse *server.OKResponse + serverResponse *api.OKResponse expectedResult resource.Result }{ { name: "Test account creation success", - serverResponse: &server.OKResponse{ + serverResponse: &api.OKResponse{ Ok: true, Description: "Account creation successed", Result: map[string]any{ @@ -100,6 +103,7 @@ func TestCreateAccount(t *testing.T) { }, expectedResult: resource.Result{ FlagSet: []uint32{flag_account_created}, + FlagReset: []uint32{flag_api_call_error}, }, }, } @@ -1073,14 +1077,14 @@ func TestCheckAccountStatus(t *testing.T) { tests := []struct { name string input []byte - serverResponse *server.OKResponse + serverResponse *api.OKResponse response *models.TrackStatusResponse expectedResult resource.Result }{ { name: "Test when account is on the Sarafu network", input: []byte("TrackingId1234"), - serverResponse: &server.OKResponse{ + serverResponse: &api.OKResponse{ Ok: true, Description: "Account creation succeeded", Result: map[string]any{ @@ -1135,7 +1139,7 @@ func TestCheckAccountStatus(t *testing.T) { }, }, }, - serverResponse: &server.OKResponse{ + serverResponse: &api.OKResponse{ Ok: true, Description: "Account creation succeeded", Result: map[string]any{ From d81bc0eefb78ba78eac2c61dcdfb1e1413822766 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 21 Oct 2024 11:10:01 +0300 Subject: [PATCH 051/289] use importable api structs --- internal/handlers/ussd/menuhandler.go | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 3efcbb1..0fc30cc 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -3,6 +3,7 @@ package ussd import ( "bytes" "context" + "errors" "fmt" "path" "regexp" @@ -10,6 +11,7 @@ import ( "strings" "git.defalsify.org/vise.git/asm" + "github.com/grassrootseconomics/eth-custodial/pkg/api" "git.defalsify.org/vise.git/cache" "git.defalsify.org/vise.git/db" @@ -27,8 +29,8 @@ var ( logg = logging.NewVanilla().WithDomain("ussdmenuhandler") scriptDir = path.Join("services", "registration") translationDir = path.Join(scriptDir, "locale") - okResponse *server.OKResponse - errResponse *server.ErrResponse + okResponse *api.OKResponse + errResponse *api.ErrResponse ) // FlagManager handles centralized flag management @@ -138,12 +140,19 @@ func (h *Handlers) SetLanguage(ctx context.Context, sym string, input []byte) (r } func (h *Handlers) createAccountNoExist(ctx context.Context, sessionId string, res *resource.Result) error { + flag_account_created, _ := h.flagManager.GetFlag("flag_account_created") + flag_api_call_error, _ := h.flagManager.GetFlag("flag_api_call_error") okResponse, errResponse := h.accountService.CreateAccount() if errResponse != nil { - return nil + if !errResponse.Ok { + res.FlagSet = append(res.FlagSet, flag_api_call_error) + return nil + } + return errors.New(errResponse.Description) } trackingId := okResponse.Result["trackingId"].(string) publicKey := okResponse.Result["publicKey"].(string) + res.FlagReset = append(res.FlagReset, flag_api_call_error) data := map[utils.DataTyp]string{ utils.DATA_TRACKING_ID: trackingId, @@ -157,7 +166,6 @@ func (h *Handlers) createAccountNoExist(ctx context.Context, sessionId string, r return err } } - flag_account_created, _ := h.flagManager.GetFlag("flag_account_created") res.FlagSet = append(res.FlagSet, flag_account_created) return nil @@ -546,6 +554,9 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b } okResponse, errResponse = h.accountService.TrackAccountStatus(string(publicKey)) if errResponse != nil { + if !errResponse.Ok { + res.FlagSet = append(res.FlagSet, flag_api_error) + } return res, err } res.FlagReset = append(res.FlagReset, flag_api_error) From 4beeb9986a3050dbe75c790ace6243a4c6e9b140 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 21 Oct 2024 11:10:23 +0300 Subject: [PATCH 052/289] use importable api structs --- internal/mocks/servicemock.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/internal/mocks/servicemock.go b/internal/mocks/servicemock.go index 7796b77..0cf07c6 100644 --- a/internal/mocks/servicemock.go +++ b/internal/mocks/servicemock.go @@ -1,8 +1,8 @@ package mocks import ( - "git.grassecon.net/urdt/ussd/internal/handlers/server" "git.grassecon.net/urdt/ussd/internal/models" + "github.com/grassrootseconomics/eth-custodial/pkg/api" "github.com/stretchr/testify/mock" ) @@ -11,10 +11,10 @@ type MockAccountService struct { mock.Mock } -func (m *MockAccountService) CreateAccount() (*server.OKResponse, *server.ErrResponse) { +func (m *MockAccountService) CreateAccount() (*api.OKResponse, *api.ErrResponse) { args := m.Called() - okResponse, ok := args.Get(0).(*server.OKResponse) - errResponse, err := args.Get(1).(*server.ErrResponse) + okResponse, ok := args.Get(0).(*api.OKResponse) + errResponse, err := args.Get(1).(*api.ErrResponse) if ok { return okResponse, nil @@ -36,10 +36,10 @@ func (m *MockAccountService) CheckAccountStatus(trackingId string) (*models.Trac return args.Get(0).(*models.TrackStatusResponse), args.Error(1) } -func (m *MockAccountService) TrackAccountStatus(publicKey string) (*server.OKResponse, *server.ErrResponse) { +func (m *MockAccountService) TrackAccountStatus(publicKey string) (*api.OKResponse, *api.ErrResponse) { args := m.Called(publicKey) - okResponse, ok := args.Get(0).(*server.OKResponse) - errResponse, err := args.Get(1).(*server.ErrResponse) + okResponse, ok := args.Get(0).(*api.OKResponse) + errResponse, err := args.Get(1).(*api.ErrResponse) if ok { return okResponse, nil } From 66d2e2e838b13aacc90cfd9314f51047dd18b387 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 21 Oct 2024 11:10:42 +0300 Subject: [PATCH 053/289] add custodial api structs --- go.mod | 12 +++++++++--- go.sum | 6 ++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1f67f34..e104186 100644 --- a/go.mod +++ b/go.mod @@ -1,27 +1,33 @@ module git.grassecon.net/urdt/ussd -go 1.22.6 +go 1.23.0 + +toolchain go1.23.2 require ( git.defalsify.org/vise.git v0.1.0-rc.3.0.20240923162317-c20d557a3dbb github.com/alecthomas/assert/v2 v2.2.2 github.com/peteole/testdata-loader v0.3.0 gopkg.in/leonelquinteros/gotext.v1 v1.3.1 + ) +require github.com/grassrootseconomics/eth-custodial v1.3.0-beta // indirect + 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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect github.com/gofrs/uuid v4.4.0+incompatible 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/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // 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 + ) diff --git a/go.sum b/go.sum index 0eccb60..a3feb64 100644 --- a/go.sum +++ b/go.sum @@ -10,10 +10,14 @@ github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c h1:H9Nm+I7Cg/YV 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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/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/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/grassrootseconomics/eth-custodial v1.3.0-beta h1:twrMBhl89GqDUL9PlkzQxMP/6OST1BByrNDj+rqXDmU= +github.com/grassrootseconomics/eth-custodial v1.3.0-beta/go.mod h1:7uhRcdnJplX4t6GKCEFkbeDhhjlcaGJeJqevbcvGLZo= github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 h1:U4kkNYryi/qfbBF8gh7Vsbuz+cVmhf5kt6pE9bYYyLo= github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4/go.mod h1:zpZDgZFzeq9s0MIeB1P50NIEWDFFHSFBohI/NbaTD/Y= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= @@ -24,6 +28,8 @@ github.com/peteole/testdata-loader v0.3.0 h1:8jckE9KcyNHgyv/VPoaljvKZE0Rqr8+dPVY 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/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/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= From acd0af25c6e84322f3cb46ec7f43928d0f24affa Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 21 Oct 2024 11:11:04 +0300 Subject: [PATCH 054/289] catch api call error --- services/registration/create_pin.vis | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/registration/create_pin.vis b/services/registration/create_pin.vis index e0e330f..44d2cf1 100644 --- a/services/registration/create_pin.vis +++ b/services/registration/create_pin.vis @@ -1,4 +1,6 @@ LOAD create_account 0 +RELOAD create_account +CATCH api_failure flag_api_call_error 1 CATCH account_creation_failed flag_account_creation_failed 1 MOUT exit 0 HALT From 0c08654df35dd7bac88c0ea24836e595ec0d5b20 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 21 Oct 2024 16:42:57 +0300 Subject: [PATCH 055/289] move driver to testutil --- driver/groupdriver.go | 111 ------------------------------------------ 1 file changed, 111 deletions(-) delete mode 100644 driver/groupdriver.go diff --git a/driver/groupdriver.go b/driver/groupdriver.go deleted file mode 100644 index 68cb7e3..0000000 --- a/driver/groupdriver.go +++ /dev/null @@ -1,111 +0,0 @@ -package driver - -import ( - "encoding/json" - "log" - "os" - "regexp" -) - -type Step struct { - Input string `json:"input"` - ExpectedContent string `json:"expectedContent"` -} - -func (s *Step) MatchesExpectedContent(content []byte) (bool, error) { - pattern := regexp.QuoteMeta(s.ExpectedContent) - re, err := regexp.Compile(pattern) - if err != nil { - return false, err - } - if re.Match([]byte(content)) { - return true, nil - } - return false, nil -} - -// Group represents a group of steps -type Group struct { - Name string `json:"name"` - Steps []Step `json:"steps"` -} - -type TestCase struct { - Name string - Input string - ExpectedContent string -} - -func (s *TestCase) MatchesExpectedContent(content []byte) (bool, error) { - pattern := regexp.QuoteMeta(s.ExpectedContent) - re, err := regexp.Compile(pattern) - if err != nil { - return false, err - } - // Check if the content matches the regex pattern - if re.Match(content) { - return true, nil - } - return false, nil -} - -// DataGroup represents the overall structure of the JSON. -type DataGroup struct { - Groups []Group `json:"groups"` -} - -type Session struct { - Name string `json:"name"` - Groups []Group `json:"groups"` -} - -func ReadData() []Session { - data, err := os.ReadFile("test_setup.json") - if err != nil { - log.Fatalf("Failed to read file: %v", err) - } - // Unmarshal JSON data - var sessions []Session - err = json.Unmarshal(data, &sessions) - if err != nil { - log.Fatalf("Failed to unmarshal JSON: %v", err) - } - - return sessions -} - -func FilterGroupsByName(groups []Group, name string) []Group { - var filteredGroups []Group - for _, group := range groups { - if group.Name == name { - filteredGroups = append(filteredGroups, group) - } - } - return filteredGroups -} - -func LoadTestGroups(filePath string) (DataGroup, error) { - var sessionsData DataGroup - data, err := os.ReadFile(filePath) - if err != nil { - return sessionsData, err - } - err = json.Unmarshal(data, &sessionsData) - return sessionsData, err -} - -func CreateTestCases(group DataGroup) []TestCase { - var tests []TestCase - for _, group := range group.Groups { - for _, step := range group.Steps { - // Create a test case for each group - tests = append(tests, TestCase{ - Name: group.Name, - Input: step.Input, - ExpectedContent: step.ExpectedContent, - }) - } - } - - return tests -} From 14455f65cb974a8e65a5b35f344af8914b0654e5 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 21 Oct 2024 16:43:24 +0300 Subject: [PATCH 056/289] move account service to testutil --- internal/handlers/server/accountservice.go | 59 ---------------------- 1 file changed, 59 deletions(-) diff --git a/internal/handlers/server/accountservice.go b/internal/handlers/server/accountservice.go index 5b71e6f..1ddf7e7 100644 --- a/internal/handlers/server/accountservice.go +++ b/internal/handlers/server/accountservice.go @@ -4,7 +4,6 @@ import ( "encoding/json" "io" "net/http" - "time" "git.grassecon.net/urdt/ussd/config" "git.grassecon.net/urdt/ussd/internal/models" @@ -19,9 +18,6 @@ type AccountServiceInterface interface { type AccountService struct { } -type TestAccountService struct { -} - // CheckAccountStatus retrieves the status of an account transaction based on the provided tracking ID. // // Parameters: @@ -96,58 +92,3 @@ func (as *AccountService) CreateAccount() (*models.AccountResponse, error) { } return &accountResp, nil } - -func (tas *TestAccountService) CreateAccount() (*models.AccountResponse, error) { - return &models.AccountResponse{ - Ok: true, - Result: struct { - CustodialId json.Number `json:"custodialId"` - PublicKey string `json:"publicKey"` - TrackingId string `json:"trackingId"` - }{ - CustodialId: json.Number("182"), - PublicKey: "0x48ADca309b5085852207FAaf2816eD72B52F527C", - TrackingId: "28ebe84d-b925-472c-87ae-bbdfa1fb97be", - }, - }, nil -} - -func (tas *TestAccountService) CheckBalance(publicKey string) (*models.BalanceResponse, error) { - - balanceResponse := &models.BalanceResponse{ - Ok: true, - Result: struct { - Balance string `json:"balance"` - Nonce json.Number `json:"nonce"` - }{ - Balance: "0.003 CELO", - Nonce: json.Number("0"), - }, - } - - return balanceResponse, nil -} - -func (tas *TestAccountService) CheckAccountStatus(trackingId string) (*models.TrackStatusResponse, error) { - trackResponse := &models.TrackStatusResponse{ - Ok: true, - Result: struct { - Transaction struct { - CreatedAt time.Time "json:\"createdAt\"" - Status string "json:\"status\"" - TransferValue json.Number "json:\"transferValue\"" - TxHash string "json:\"txHash\"" - TxType string "json:\"txType\"" - } - }{ - Transaction: models.Transaction{ - CreatedAt: time.Now(), - Status: "SUCCESS", - TransferValue: json.Number("0.5"), - TxHash: "0x123abc456def", - TxType: "transfer", - }, - }, - } - return trackResponse, nil -} From 3af943f77c81f44b0cee548611aa3a1f7a9863f2 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 21 Oct 2024 16:44:02 +0300 Subject: [PATCH 057/289] move account service tags switch to test tags package --- internal/testutil/offlinetest.go | 11 ----------- internal/testutil/onlinetest.go | 9 --------- 2 files changed, 20 deletions(-) delete mode 100644 internal/testutil/offlinetest.go delete mode 100644 internal/testutil/onlinetest.go diff --git a/internal/testutil/offlinetest.go b/internal/testutil/offlinetest.go deleted file mode 100644 index 476ade3..0000000 --- a/internal/testutil/offlinetest.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build !online - -package testutil - -import ( - "git.grassecon.net/urdt/ussd/internal/handlers/server" -) - -var ( - AccountService server.AccountServiceInterface = &server.TestAccountService{} -) diff --git a/internal/testutil/onlinetest.go b/internal/testutil/onlinetest.go deleted file mode 100644 index ddb5cf0..0000000 --- a/internal/testutil/onlinetest.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build online - -package testutil - -import "git.grassecon.net/urdt/ussd/internal/handlers/server" - -var ( - AccountService server.AccountServiceInterface -) From a904cdbf44f0f83f29e1151fe4d7e81f768d8abd Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 21 Oct 2024 16:45:06 +0300 Subject: [PATCH 058/289] move driver to testutil --- internal/testutil/driver/groupdriver.go | 111 ++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 internal/testutil/driver/groupdriver.go diff --git a/internal/testutil/driver/groupdriver.go b/internal/testutil/driver/groupdriver.go new file mode 100644 index 0000000..68cb7e3 --- /dev/null +++ b/internal/testutil/driver/groupdriver.go @@ -0,0 +1,111 @@ +package driver + +import ( + "encoding/json" + "log" + "os" + "regexp" +) + +type Step struct { + Input string `json:"input"` + ExpectedContent string `json:"expectedContent"` +} + +func (s *Step) MatchesExpectedContent(content []byte) (bool, error) { + pattern := regexp.QuoteMeta(s.ExpectedContent) + re, err := regexp.Compile(pattern) + if err != nil { + return false, err + } + if re.Match([]byte(content)) { + return true, nil + } + return false, nil +} + +// Group represents a group of steps +type Group struct { + Name string `json:"name"` + Steps []Step `json:"steps"` +} + +type TestCase struct { + Name string + Input string + ExpectedContent string +} + +func (s *TestCase) MatchesExpectedContent(content []byte) (bool, error) { + pattern := regexp.QuoteMeta(s.ExpectedContent) + re, err := regexp.Compile(pattern) + if err != nil { + return false, err + } + // Check if the content matches the regex pattern + if re.Match(content) { + return true, nil + } + return false, nil +} + +// DataGroup represents the overall structure of the JSON. +type DataGroup struct { + Groups []Group `json:"groups"` +} + +type Session struct { + Name string `json:"name"` + Groups []Group `json:"groups"` +} + +func ReadData() []Session { + data, err := os.ReadFile("test_setup.json") + if err != nil { + log.Fatalf("Failed to read file: %v", err) + } + // Unmarshal JSON data + var sessions []Session + err = json.Unmarshal(data, &sessions) + if err != nil { + log.Fatalf("Failed to unmarshal JSON: %v", err) + } + + return sessions +} + +func FilterGroupsByName(groups []Group, name string) []Group { + var filteredGroups []Group + for _, group := range groups { + if group.Name == name { + filteredGroups = append(filteredGroups, group) + } + } + return filteredGroups +} + +func LoadTestGroups(filePath string) (DataGroup, error) { + var sessionsData DataGroup + data, err := os.ReadFile(filePath) + if err != nil { + return sessionsData, err + } + err = json.Unmarshal(data, &sessionsData) + return sessionsData, err +} + +func CreateTestCases(group DataGroup) []TestCase { + var tests []TestCase + for _, group := range group.Groups { + for _, step := range group.Steps { + // Create a test case for each group + tests = append(tests, TestCase{ + Name: group.Name, + Input: step.Input, + ExpectedContent: step.ExpectedContent, + }) + } + } + + return tests +} From 961d8d1a5ce11964430ec50527d7cd529497c53e Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 21 Oct 2024 16:46:29 +0300 Subject: [PATCH 059/289] update package import --- menutraversal_test/menu_traversal_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/menutraversal_test/menu_traversal_test.go b/menutraversal_test/menu_traversal_test.go index 5eb1ef8..7391e5b 100644 --- a/menutraversal_test/menu_traversal_test.go +++ b/menutraversal_test/menu_traversal_test.go @@ -9,8 +9,8 @@ import ( "regexp" "testing" - "git.grassecon.net/urdt/ussd/driver" "git.grassecon.net/urdt/ussd/internal/testutil" + "git.grassecon.net/urdt/ussd/internal/testutil/driver" "github.com/gofrs/uuid" ) From 4a9ef6b5f24cba95c583991b5c35d79016f93cb3 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 21 Oct 2024 16:47:00 +0300 Subject: [PATCH 060/289] move test account service to testutil --- .../testservice/TestAccountService.go | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 internal/testutil/testservice/TestAccountService.go diff --git a/internal/testutil/testservice/TestAccountService.go b/internal/testutil/testservice/TestAccountService.go new file mode 100644 index 0000000..40c3886 --- /dev/null +++ b/internal/testutil/testservice/TestAccountService.go @@ -0,0 +1,65 @@ +package testservice + +import ( + "encoding/json" + "time" + + "git.grassecon.net/urdt/ussd/internal/models" +) + +type TestAccountService struct { +} + +func (tas *TestAccountService) CreateAccount() (*models.AccountResponse, error) { + return &models.AccountResponse{ + Ok: true, + Result: struct { + CustodialId json.Number `json:"custodialId"` + PublicKey string `json:"publicKey"` + TrackingId string `json:"trackingId"` + }{ + CustodialId: json.Number("182"), + PublicKey: "0x48ADca309b5085852207FAaf2816eD72B52F527C", + TrackingId: "28ebe84d-b925-472c-87ae-bbdfa1fb97be", + }, + }, nil +} + +func (tas *TestAccountService) CheckBalance(publicKey string) (*models.BalanceResponse, error) { + balanceResponse := &models.BalanceResponse{ + Ok: true, + Result: struct { + Balance string `json:"balance"` + Nonce json.Number `json:"nonce"` + }{ + Balance: "0.003 CELO", + Nonce: json.Number("0"), + }, + } + + return balanceResponse, nil +} + +func (tas *TestAccountService) CheckAccountStatus(trackingId string) (*models.TrackStatusResponse, error) { + trackResponse := &models.TrackStatusResponse{ + Ok: true, + Result: struct { + Transaction struct { + CreatedAt time.Time "json:\"createdAt\"" + Status string "json:\"status\"" + TransferValue json.Number "json:\"transferValue\"" + TxHash string "json:\"txHash\"" + TxType string "json:\"txType\"" + } + }{ + Transaction: models.Transaction{ + CreatedAt: time.Now(), + Status: "SUCCESS", + TransferValue: json.Number("0.5"), + TxHash: "0x123abc456def", + TxType: "transfer", + }, + }, + } + return trackResponse, nil +} From 549d09890b86d73b6ac9f6f4bad34107df5e2274 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 21 Oct 2024 16:47:25 +0300 Subject: [PATCH 061/289] update imports --- internal/testutil/TestEngine.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/internal/testutil/TestEngine.go b/internal/testutil/TestEngine.go index 2432a3f..ca48655 100644 --- a/internal/testutil/TestEngine.go +++ b/internal/testutil/TestEngine.go @@ -13,6 +13,8 @@ import ( "git.grassecon.net/urdt/ussd/internal/handlers" "git.grassecon.net/urdt/ussd/internal/handlers/server" "git.grassecon.net/urdt/ussd/internal/storage" + "git.grassecon.net/urdt/ussd/internal/testutil/testservice" + "git.grassecon.net/urdt/ussd/internal/testutil/testtag" testdataloader "github.com/peteole/testdata-loader" ) @@ -79,12 +81,12 @@ func TestEngine(sessionId string) (engine.Engine, func(), chan bool) { os.Exit(1) } - if AccountService == nil { - AccountService = &server.AccountService{} + if testtag.AccountService == nil { + testtag.AccountService = &server.AccountService{} } - switch AccountService.(type) { - case *server.TestAccountService: + switch testtag.AccountService.(type) { + case *testservice.TestAccountService: go func() { eventChannel <- false }() @@ -97,7 +99,7 @@ func TestEngine(sessionId string) (engine.Engine, func(), chan bool) { panic("Unknown account service type") } - hl, err := lhs.GetHandler(AccountService) + hl, err := lhs.GetHandler(testtag.AccountService) if err != nil { fmt.Fprintf(os.Stderr, err.Error()) os.Exit(1) From f3a5178de70d4a6290b1fc2b3746174581a54341 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 21 Oct 2024 16:47:43 +0300 Subject: [PATCH 062/289] update imports --- internal/handlers/ussd/menuhandler_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 38c468c..42e97fd 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -15,9 +15,10 @@ import ( "git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/state" - "git.grassecon.net/urdt/ussd/internal/handlers/server" "git.grassecon.net/urdt/ussd/internal/mocks" "git.grassecon.net/urdt/ussd/internal/models" + "git.grassecon.net/urdt/ussd/internal/testutil/testservice" + "git.grassecon.net/urdt/ussd/internal/utils" "github.com/alecthomas/assert/v2" testdataloader "github.com/peteole/testdata-loader" @@ -31,7 +32,7 @@ var ( func TestNewHandlers(t *testing.T) { fm, err := NewFlagManager(flagsPath) - accountService := server.TestAccountService{} + accountService := testservice.TestAccountService{} if err != nil { t.Logf(err.Error()) } From eaac771722225641a28271502b10267094763936 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 21 Oct 2024 16:48:24 +0300 Subject: [PATCH 063/289] move into testtag package --- internal/testutil/testtag/offlinetest.go | 12 ++++++++++++ internal/testutil/testtag/onlinetest.go | 9 +++++++++ 2 files changed, 21 insertions(+) create mode 100644 internal/testutil/testtag/offlinetest.go create mode 100644 internal/testutil/testtag/onlinetest.go diff --git a/internal/testutil/testtag/offlinetest.go b/internal/testutil/testtag/offlinetest.go new file mode 100644 index 0000000..70e2e80 --- /dev/null +++ b/internal/testutil/testtag/offlinetest.go @@ -0,0 +1,12 @@ +// +build !online + +package testtag + +import ( + "git.grassecon.net/urdt/ussd/internal/handlers/server" + accountservice "git.grassecon.net/urdt/ussd/internal/testutil/testservice" +) + +var ( + AccountService server.AccountServiceInterface = &accountservice.TestAccountService{} +) diff --git a/internal/testutil/testtag/onlinetest.go b/internal/testutil/testtag/onlinetest.go new file mode 100644 index 0000000..92cbb14 --- /dev/null +++ b/internal/testutil/testtag/onlinetest.go @@ -0,0 +1,9 @@ +// +build online + +package testtag + +import "git.grassecon.net/urdt/ussd/internal/handlers/server" + +var ( + AccountService server.AccountServiceInterface +) From 5909659fa96708b52a1e21a244b7794002c37090 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Mon, 21 Oct 2024 16:52:07 +0300 Subject: [PATCH 064/289] Use dynamic balance --- menutraversal_test/group_test.json | 44 +++++++++++------------ menutraversal_test/menu_traversal_test.go | 38 ++++++++++++++++++-- menutraversal_test/test_setup.json | 8 ++--- 3 files changed, 62 insertions(+), 28 deletions(-) diff --git a/menutraversal_test/group_test.json b/menutraversal_test/group_test.json index 203ff08..8b765f5 100644 --- a/menutraversal_test/group_test.json +++ b/menutraversal_test/group_test.json @@ -5,7 +5,7 @@ "steps": [ { "input": "", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" }, { "input": "3", @@ -33,7 +33,7 @@ }, { "input": "0", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" } ] }, @@ -42,7 +42,7 @@ "steps": [ { "input": "", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" }, { "input": "3", @@ -70,7 +70,7 @@ }, { "input": "0", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" } ] }, @@ -79,7 +79,7 @@ "steps": [ { "input": "", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" }, { "input": "3", @@ -116,7 +116,7 @@ }, { "input": "0", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" } ] }, @@ -125,7 +125,7 @@ "steps": [ { "input": "", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" }, { "input": "3", @@ -162,7 +162,7 @@ }, { "input": "0", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" } ] }, @@ -171,7 +171,7 @@ "steps": [ { "input": "", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" }, { "input": "3", @@ -203,7 +203,7 @@ }, { "input": "0", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" } ] }, @@ -212,7 +212,7 @@ "steps": [ { "input": "", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" }, { "input": "3", @@ -244,7 +244,7 @@ }, { "input": "0", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" } ] @@ -254,7 +254,7 @@ "steps": [ { "input": "", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" }, { "input": "3", @@ -286,7 +286,7 @@ }, { "input": "0", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" } ] }, @@ -295,7 +295,7 @@ "steps": [ { "input": "", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" }, { "input": "3", @@ -327,7 +327,7 @@ }, { "input": "0", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" } ] }, @@ -336,7 +336,7 @@ "steps": [ { "input": "", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" }, { "input": "3", @@ -368,7 +368,7 @@ }, { "input": "0", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" } ] }, @@ -377,7 +377,7 @@ "steps": [ { "input": "", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" }, { "input": "3", @@ -409,7 +409,7 @@ }, { "input": "0", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" } ] }, @@ -418,7 +418,7 @@ "steps": [ { "input": "", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" }, { "input": "3", @@ -446,7 +446,7 @@ }, { "input": "0", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" } ] } diff --git a/menutraversal_test/menu_traversal_test.go b/menutraversal_test/menu_traversal_test.go index 5eb1ef8..a32e17a 100644 --- a/menutraversal_test/menu_traversal_test.go +++ b/menutraversal_test/menu_traversal_test.go @@ -43,6 +43,17 @@ func extractPublicKey(response []byte) string { return "" } +// Extracts the balance value from the engine response. +func extractBalance(response []byte) string { + // Regex to match "Balance: " followed by a newline + re := regexp.MustCompile(`(?m)^Balance:\s+(\d+(\.\d+)?)\s+([A-Z]+)`) + match := re.FindSubmatch(response) + if match != nil && len(match) > 0 { + return string(match[1]) + " " + string(match[3]) // " " + } + return "" +} + func TestMain(m *testing.M) { sessionID = GenerateSessionId() defer func() { @@ -154,6 +165,12 @@ func TestMainMenuHelp(t *testing.T) { } b := w.Bytes() + balance := extractBalance(b) + + expectedContent := []byte(step.ExpectedContent) + expectedContent = bytes.Replace(expectedContent, []byte("{balance}"), []byte(balance), -1) + + step.ExpectedContent = string(expectedContent) match, err := step.MatchesExpectedContent(b) if err != nil { t.Fatalf("Error compiling regex for step '%s': %v", step.Input, err) @@ -189,6 +206,12 @@ func TestMainMenuQuit(t *testing.T) { } b := w.Bytes() + balance := extractBalance(b) + + expectedContent := []byte(step.ExpectedContent) + expectedContent = bytes.Replace(expectedContent, []byte("{balance}"), []byte(balance), -1) + + step.ExpectedContent = string(expectedContent) match, err := step.MatchesExpectedContent(b) if err != nil { t.Fatalf("Error compiling regex for step '%s': %v", step.Input, err) @@ -225,8 +248,13 @@ func TestMyAccount_MyAddress(t *testing.T) { } b := w.Bytes() + balance := extractBalance(b) publicKey := extractPublicKey(b) - expectedContent := bytes.Replace([]byte(step.ExpectedContent), []byte("{public_key}"), []byte(publicKey), -1) + + expectedContent := []byte(step.ExpectedContent) + expectedContent = bytes.Replace(expectedContent, []byte("{balance}"), []byte(balance), -1) + expectedContent = bytes.Replace(expectedContent, []byte("{public_key}"), []byte(publicKey), -1) + step.ExpectedContent = string(expectedContent) match, err := step.MatchesExpectedContent(b) if err != nil { @@ -265,6 +293,13 @@ func TestGroups(t *testing.T) { t.Errorf("Test case '%s' failed during Flush: %v", tt.Name, err) } b := w.Bytes() + balance := extractBalance(b) + + expectedContent := []byte(tt.ExpectedContent) + expectedContent = bytes.Replace(expectedContent, []byte("{balance}"), []byte(balance), -1) + + tt.ExpectedContent = string(expectedContent) + match, err := tt.MatchesExpectedContent(b) if err != nil { t.Fatalf("Error compiling regex for step '%s': %v", tt.Input, err) @@ -272,7 +307,6 @@ func TestGroups(t *testing.T) { if !match { t.Fatalf("expected:\n\t%s\ngot:\n\t%s\n", tt.ExpectedContent, b) } - }) } } diff --git a/menutraversal_test/test_setup.json b/menutraversal_test/test_setup.json index 56c0278..619744b 100644 --- a/menutraversal_test/test_setup.json +++ b/menutraversal_test/test_setup.json @@ -57,7 +57,7 @@ "steps": [ { "input": "", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" }, { "input": "1", @@ -106,7 +106,7 @@ "steps": [ { "input": "", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" }, { "input": "4", @@ -119,7 +119,7 @@ "steps": [ { "input": "", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" }, { "input": "9", @@ -132,7 +132,7 @@ "steps": [ { "input": "", - "expectedContent": "Balance: 0.003 CELO\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" + "expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit" }, { "input": "3", From 9c75942b0b8d3533664eb6a8816e5f999fd6ed07 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 21 Oct 2024 16:54:16 +0300 Subject: [PATCH 065/289] chore: remove commented code --- internal/handlers/ussd/menuhandler_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index d78f526..3b4b00f 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -75,7 +75,6 @@ func TestCreateAccount(t *testing.T) { } // Create required mocks flag_account_created, err := fm.GetFlag("flag_account_created") - //flag_api_call_error, err := fm.GetFlag("flag_api_call_error,") flag_api_call_error, _ := fm.GetFlag("flag_api_call_error") if err != nil { t.Logf(err.Error()) @@ -102,7 +101,7 @@ func TestCreateAccount(t *testing.T) { }, }, expectedResult: resource.Result{ - FlagSet: []uint32{flag_account_created}, + FlagSet: []uint32{flag_account_created}, FlagReset: []uint32{flag_api_call_error}, }, }, From 02cb75f97a61150830bfbdcb58860c7b52c96c68 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Mon, 21 Oct 2024 17:14:59 +0300 Subject: [PATCH 066/289] increase the size to resolve sink error --- services/registration/confirm_create_pin.vis | 2 +- services/registration/create_pin.vis | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/services/registration/confirm_create_pin.vis b/services/registration/confirm_create_pin.vis index 1a3173c..02279dc 100644 --- a/services/registration/confirm_create_pin.vis +++ b/services/registration/confirm_create_pin.vis @@ -1,4 +1,4 @@ -LOAD save_temporary_pin 0 +LOAD save_temporary_pin 6 HALT LOAD verify_create_pin 8 INCMP account_creation * diff --git a/services/registration/create_pin.vis b/services/registration/create_pin.vis index c76e1bf..40989ec 100644 --- a/services/registration/create_pin.vis +++ b/services/registration/create_pin.vis @@ -2,7 +2,7 @@ LOAD create_account 0 CATCH account_creation_failed flag_account_creation_failed 1 MOUT exit 0 HALT -LOAD save_temporary_pin 0 +LOAD save_temporary_pin 6 RELOAD save_temporary_pin CATCH . flag_incorrect_pin 1 INCMP quit 0 From 0547bc7e5fe0b2c35d9973553b05d48d853fd082 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Tue, 22 Oct 2024 14:24:22 +0300 Subject: [PATCH 067/289] added send menu test with dynamic max_amount --- menutraversal_test/menu_traversal_test.go | 57 +++++++++++++++++++++++ menutraversal_test/test_setup.json | 8 ++-- 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/menutraversal_test/menu_traversal_test.go b/menutraversal_test/menu_traversal_test.go index a32e17a..8d028c9 100644 --- a/menutraversal_test/menu_traversal_test.go +++ b/menutraversal_test/menu_traversal_test.go @@ -54,6 +54,17 @@ func extractBalance(response []byte) string { return "" } +// Extracts the Maximum amount value from the engine response. +func extractMaxAmount(response []byte) string { + // Regex to match "Maximum amount: " followed by a newline + re := regexp.MustCompile(`(?m)^Maximum amount:\s+(\d+(\.\d+)?)\s+([A-Z]+)`) + match := re.FindSubmatch(response) + if match != nil && len(match) > 0 { + return string(match[1]) + " " + string(match[3]) // " " + } + return "" +} + func TestMain(m *testing.M) { sessionID = GenerateSessionId() defer func() { @@ -268,6 +279,52 @@ func TestMyAccount_MyAddress(t *testing.T) { } } +func TestMainMenuSend(t *testing.T) { + en, fn, _ := testutil.TestEngine(sessionID) + defer fn() + ctx := context.Background() + sessions := testData + for _, session := range sessions { + groups := driver.FilterGroupsByName(session.Groups, "send_with_invalid_inputs") + for _, group := range groups { + 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) + return + } + if !cont { + break + } + w := bytes.NewBuffer(nil) + if _, err := en.Flush(ctx, w); err != nil { + t.Fatalf("Test case '%s' failed during Flush: %v", group.Name, err) + } + + b := w.Bytes() + balance := extractBalance(b) + max_amount := extractMaxAmount(b) + publicKey := extractPublicKey(b) + + expectedContent := []byte(step.ExpectedContent) + expectedContent = bytes.Replace(expectedContent, []byte("{balance}"), []byte(balance), -1) + expectedContent = bytes.Replace(expectedContent, []byte("{max_amount}"), []byte(max_amount), -1) + expectedContent = bytes.Replace(expectedContent, []byte("{public_key}"), []byte(publicKey), -1) + + step.ExpectedContent = string(expectedContent) + match, err := step.MatchesExpectedContent(b) + if err != nil { + t.Fatalf("Error compiling regex for step '%s': %v", step.Input, err) + } + if !match { + t.Fatalf("expected:\n\t%s\ngot:\n\t%s\n", step.ExpectedContent, b) + } + } + } + } +} + + func TestGroups(t *testing.T) { groups, err := driver.LoadTestGroups(groupTestFile) if err != nil { diff --git a/menutraversal_test/test_setup.json b/menutraversal_test/test_setup.json index 619744b..736d4de 100644 --- a/menutraversal_test/test_setup.json +++ b/menutraversal_test/test_setup.json @@ -73,15 +73,15 @@ }, { "input": "065656", - "expectedContent": "Maximum amount: 0.003 CELO\nEnter amount:\n0:Back" + "expectedContent": "{max_amount}\nEnter amount:\n0:Back" }, { - "input": "0.1", - "expectedContent": "Amount 0.1 is invalid, please try again:\n1:retry\n9:Quit" + "input": "10000000", + "expectedContent": "Amount 10000000 is invalid, please try again:\n1:retry\n9:Quit" }, { "input": "1", - "expectedContent": "Maximum amount: 0.003 CELO\nEnter amount:\n0:Back" + "expectedContent": "{max_amount}\nEnter amount:\n0:Back" }, { "input": "0.001", From f37ec13c757fce0e3cc3db308e95fd695b9b396f Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Tue, 22 Oct 2024 16:31:29 +0300 Subject: [PATCH 068/289] polish code --- menutraversal_test/menu_traversal_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/menutraversal_test/menu_traversal_test.go b/menutraversal_test/menu_traversal_test.go index 8d028c9..2b2a093 100644 --- a/menutraversal_test/menu_traversal_test.go +++ b/menutraversal_test/menu_traversal_test.go @@ -48,7 +48,7 @@ func extractBalance(response []byte) string { // Regex to match "Balance: " followed by a newline re := regexp.MustCompile(`(?m)^Balance:\s+(\d+(\.\d+)?)\s+([A-Z]+)`) match := re.FindSubmatch(response) - if match != nil && len(match) > 0 { + if match != nil { return string(match[1]) + " " + string(match[3]) // " " } return "" @@ -59,7 +59,7 @@ func extractMaxAmount(response []byte) string { // Regex to match "Maximum amount: " followed by a newline re := regexp.MustCompile(`(?m)^Maximum amount:\s+(\d+(\.\d+)?)\s+([A-Z]+)`) match := re.FindSubmatch(response) - if match != nil && len(match) > 0 { + if match != nil { return string(match[1]) + " " + string(match[3]) // " " } return "" @@ -324,7 +324,6 @@ func TestMainMenuSend(t *testing.T) { } } - func TestGroups(t *testing.T) { groups, err := driver.LoadTestGroups(groupTestFile) if err != nil { From e05dbb4885d033c398713adffbea31c36e8a2279 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 22 Oct 2024 20:36:58 +0300 Subject: [PATCH 069/289] check for back option --- internal/handlers/ussd/menuhandler.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 36d1ad5..2c4a4a5 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -27,6 +27,7 @@ var ( logg = logging.NewVanilla().WithDomain("ussdmenuhandler") scriptDir = path.Join("services", "registration") translationDir = path.Join(scriptDir, "locale") + backOption = []byte("0") ) // FlagManager handles centralized flag management @@ -326,6 +327,9 @@ func (h *Handlers) SaveFirstname(ctx context.Context, sym string, input []byte) return res, fmt.Errorf("missing session") } if len(input) > 0 { + if bytes.Equal(input, backOption) { + return res, nil + } firstName := string(input) store := h.userdataStore err = store.WriteEntry(ctx, sessionId, utils.DATA_FIRST_NAME, []byte(firstName)) @@ -345,8 +349,10 @@ func (h *Handlers) SaveFamilyname(ctx context.Context, sym string, input []byte) if !ok { return res, fmt.Errorf("missing session") } - if len(input) > 0 { + if bytes.Equal(input, backOption) { + return res, nil + } familyName := string(input) store := h.userdataStore err = store.WriteEntry(ctx, sessionId, utils.DATA_FAMILY_NAME, []byte(familyName)) @@ -389,8 +395,10 @@ func (h *Handlers) SaveLocation(ctx context.Context, sym string, input []byte) ( if !ok { return res, fmt.Errorf("missing session") } - if len(input) > 0 { + if bytes.Equal(input, backOption) { + return res, nil + } location := string(input) store := h.userdataStore err = store.WriteEntry(ctx, sessionId, utils.DATA_LOCATION, []byte(location)) @@ -411,7 +419,9 @@ func (h *Handlers) SaveGender(ctx context.Context, sym string, input []byte) (re if !ok { return res, fmt.Errorf("missing session") } - + if bytes.Equal(input, backOption) { + return res, nil + } gender := strings.Split(symbol, "_")[1] store := h.userdataStore err = store.WriteEntry(ctx, sessionId, utils.DATA_GENDER, []byte(gender)) From 306666a15e321ea3c9b81ed9496d1634ccfbb479 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 22 Oct 2024 20:37:30 +0300 Subject: [PATCH 070/289] load and reload after halt --- services/registration/enter_familyname.vis | 3 +-- services/registration/enter_location.vis | 2 +- services/registration/enter_name.vis | 6 +----- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/services/registration/enter_familyname.vis b/services/registration/enter_familyname.vis index b9fe7b0..5a684ed 100644 --- a/services/registration/enter_familyname.vis +++ b/services/registration/enter_familyname.vis @@ -1,9 +1,8 @@ CATCH incorrect_pin flag_incorrect_pin 1 CATCH profile_update_success flag_allow_update 1 -LOAD save_familyname 0 -RELOAD save_familyname MOUT back 0 HALT +LOAD save_familyname 0 RELOAD save_familyname INCMP _ 0 INCMP pin_entry * diff --git a/services/registration/enter_location.vis b/services/registration/enter_location.vis index fdd29ce..c8da2dd 100644 --- a/services/registration/enter_location.vis +++ b/services/registration/enter_location.vis @@ -1,8 +1,8 @@ CATCH incorrect_pin flag_incorrect_pin 1 CATCH profile_update_success flag_allow_update 1 -LOAD save_location 0 MOUT back 0 HALT +LOAD save_location 0 RELOAD save_location INCMP _ 0 INCMP pin_entry * diff --git a/services/registration/enter_name.vis b/services/registration/enter_name.vis index 563577e..799b2a1 100644 --- a/services/registration/enter_name.vis +++ b/services/registration/enter_name.vis @@ -1,12 +1,8 @@ CATCH incorrect_pin flag_incorrect_pin 1 CATCH profile_update_success flag_allow_update 1 -LOAD save_firstname 0 -RELOAD save_firstname MOUT back 0 HALT +LOAD save_firstname 0 RELOAD save_firstname INCMP _ 0 INCMP pin_entry * - - - From b9a63f3c6feb15b9d895f18aee4861e333f0fc0c Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 22 Oct 2024 21:30:48 +0300 Subject: [PATCH 071/289] merge dep --- go.mod | 15 +++++++++++++-- go.sum | 38 ++++++++++++++++++++++++++++++-------- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 7654709..1225673 100644 --- a/go.mod +++ b/go.mod @@ -12,9 +12,20 @@ require ( ) -require github.com/joho/godotenv v1.5.1 // indirect +require github.com/joho/godotenv v1.5.1 -require github.com/grassrootseconomics/eth-custodial v1.3.0-beta // indirect +require ( + github.com/grassrootseconomics/eth-custodial v1.3.0-beta + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.7.1 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/rogpeppe/go-internal v1.13.1 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/text v0.18.0 // indirect +) require ( github.com/alecthomas/participle/v2 v2.0.0 // indirect diff --git a/go.sum b/go.sum index 1d1de2d..d566e2c 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,3 @@ -git.defalsify.org/vise.git v0.1.0-rc.3.0.20240923162317-c20d557a3dbb h1:6P4kxihcwMjDKzvUFC6t2zGNb7MDW+l/ACGlSAN1N8Y= -git.defalsify.org/vise.git v0.1.0-rc.3.0.20240923162317-c20d557a3dbb/go.mod h1:JDguWmcoWBdsnpw7PUjVZAEpdC/ubBmjdUBy3tjP63M= -git.defalsify.org/vise.git v0.2.0 h1:X2ZgiGRq4C+9qOlDMP0b/oE5QHjVQNT4aEFZB88ST0Q= -git.defalsify.org/vise.git v0.2.0/go.mod h1:JDguWmcoWBdsnpw7PUjVZAEpdC/ubBmjdUBy3tjP63M= git.defalsify.org/vise.git v0.2.1-0.20241017112704-307fa6fcdc6b h1:dxBplsIlzJHV+5EH+gzB+w08Blt7IJbb2jeRe1OEjLU= git.defalsify.org/vise.git v0.2.1-0.20241017112704-307fa6fcdc6b/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck= github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk= @@ -12,8 +8,8 @@ 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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= @@ -26,25 +22,51 @@ github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 h1:U4kkNYryi/qf github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4/go.mod h1:zpZDgZFzeq9s0MIeB1P50NIEWDFFHSFBohI/NbaTD/Y= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= +github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a h1:0Q3H0YXzMHiciXtRcM+j0jiCe8WKPQHoRgQiRTnfcLY= github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a/go.mod h1:CdTTBOYzS5E4mWS1N8NWP6AHI19MP0A2B18n3hLzRMk= +github.com/pashagolub/pgxmock/v4 v4.3.0 h1:DqT7fk0OCK6H0GvqtcMsLpv8cIwWqdxWgfZNLeHCb/s= +github.com/pashagolub/pgxmock/v4 v4.3.0/go.mod h1:9VoVHXwS3XR/yPtKGzwQvwZX1kzGB9sM8SviDcHDa3A= 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/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 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.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 3179ec1f62d46eda15240866d007131b5e11b755 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 22 Oct 2024 21:35:52 +0300 Subject: [PATCH 072/289] add local track endpoint --- config/config.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index dba0da7..43466c3 100644 --- a/config/config.go +++ b/config/config.go @@ -6,11 +6,13 @@ var ( CreateAccountURL string TrackStatusURL string BalanceURL string + TrackURL string ) // LoadConfig initializes the configuration values after environment variables are loaded. func LoadConfig() { - CreateAccountURL = initializers.GetEnv("CREATE_ACCOUNT_URL", "https://custodial.sarafu.africa/api/account/create") + CreateAccountURL = initializers.GetEnv("CREATE_ACCOUNT_URL", "http://localhost:5003/api/v2/account/create") TrackStatusURL = initializers.GetEnv("TRACK_STATUS_URL", "https://custodial.sarafu.africa/api/track/") BalanceURL = initializers.GetEnv("BALANCE_URL", "https://custodial.sarafu.africa/api/account/status/") + TrackURL = initializers.GetEnv("TRACK_URL", "http://localhost:5003/api/v2/account/status") } From 5f2c6cce163e0605f57179d9c2fbd7bc9cf2619a Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 22 Oct 2024 21:36:28 +0300 Subject: [PATCH 073/289] add required track endpoint --- .env.example | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 97d3317..ab370a7 100644 --- a/.env.example +++ b/.env.example @@ -12,6 +12,7 @@ DB_SSLMODE=disable DB_TIMEZONE=Africa/Nairobi #External API Calls -CREATE_ACCOUNT_URL=https://custodial.sarafu.africa/api/account/create +CREATE_ACCOUNT_URL=http://localhost:5003/api/v2/account/create TRACK_STATUS_URL=https://custodial.sarafu.africa/api/track/ BALANCE_URL=https://custodial.sarafu.africa/api/account/status/ +TRACK_URL=http://localhost:5003/api/v2/account/status From 5f1ee396d84d069c25a5ca5d71bccbad855e373f Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 23 Oct 2024 06:35:19 +0300 Subject: [PATCH 074/289] Fix PIN being requested twice --- services/registration/my_vouchers.vis | 2 ++ services/registration/view_voucher.vis | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/services/registration/my_vouchers.vis b/services/registration/my_vouchers.vis index 9702573..b59441a 100644 --- a/services/registration/my_vouchers.vis +++ b/services/registration/my_vouchers.vis @@ -1,3 +1,5 @@ +LOAD reset_account_authorized 16 +RELOAD reset_account_authorized MOUT select_voucher 1 MOUT voucher_details 2 MOUT back 0 diff --git a/services/registration/view_voucher.vis b/services/registration/view_voucher.vis index ee8bf85..1480099 100644 --- a/services/registration/view_voucher.vis +++ b/services/registration/view_voucher.vis @@ -1,4 +1,3 @@ -RELOAD view_voucher MAP view_voucher MOUT back 0 MOUT quit 9 From 1e6cf6a33a94a6ebbe8a212b0db1c231ba7fe7ec Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 23 Oct 2024 11:08:51 +0300 Subject: [PATCH 075/289] run mod tidy --- go.mod | 13 ++++++++++++- go.sum | 35 ++++++++++++++++++++++++++++++----- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 38be305..3349bf8 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,18 @@ require ( gopkg.in/leonelquinteros/gotext.v1 v1.3.1 ) -require github.com/joho/godotenv v1.5.1 // indirect +require ( + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.7.0 // indirect + github.com/jackc/puddle/v2 v2.2.1 // indirect + github.com/joho/godotenv v1.5.1 + github.com/kr/text v0.2.0 // indirect + github.com/rogpeppe/go-internal v1.13.1 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/text v0.18.0 // indirect +) require ( github.com/alecthomas/participle/v2 v2.0.0 // indirect diff --git a/go.sum b/go.sum index 2abec41..ef40172 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,3 @@ -git.defalsify.org/vise.git v0.1.0-rc.3.0.20240923162317-c20d557a3dbb h1:6P4kxihcwMjDKzvUFC6t2zGNb7MDW+l/ACGlSAN1N8Y= -git.defalsify.org/vise.git v0.1.0-rc.3.0.20240923162317-c20d557a3dbb/go.mod h1:JDguWmcoWBdsnpw7PUjVZAEpdC/ubBmjdUBy3tjP63M= -git.defalsify.org/vise.git v0.2.0 h1:X2ZgiGRq4C+9qOlDMP0b/oE5QHjVQNT4aEFZB88ST0Q= -git.defalsify.org/vise.git v0.2.0/go.mod h1:JDguWmcoWBdsnpw7PUjVZAEpdC/ubBmjdUBy3tjP63M= git.defalsify.org/vise.git v0.2.1-0.20241017112704-307fa6fcdc6b h1:dxBplsIlzJHV+5EH+gzB+w08Blt7IJbb2jeRe1OEjLU= git.defalsify.org/vise.git v0.2.1-0.20241017112704-307fa6fcdc6b/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck= github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk= @@ -12,6 +8,8 @@ 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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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= @@ -22,23 +20,50 @@ github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 h1:U4kkNYryi/qf github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4/go.mod h1:zpZDgZFzeq9s0MIeB1P50NIEWDFFHSFBohI/NbaTD/Y= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.0 h1:FG6VLIdzvAPhnYqP14sQ2xhFLkiUQHCs6ySqO91kF4g= +github.com/jackc/pgx/v5 v5.7.0/go.mod h1:awP1KNnjylvpxHuHP63gzjhnGkI1iw+PMoIwvoleN/8= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a h1:0Q3H0YXzMHiciXtRcM+j0jiCe8WKPQHoRgQiRTnfcLY= github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a/go.mod h1:CdTTBOYzS5E4mWS1N8NWP6AHI19MP0A2B18n3hLzRMk= +github.com/pashagolub/pgxmock/v4 v4.3.0 h1:DqT7fk0OCK6H0GvqtcMsLpv8cIwWqdxWgfZNLeHCb/s= +github.com/pashagolub/pgxmock/v4 v4.3.0/go.mod h1:9VoVHXwS3XR/yPtKGzwQvwZX1kzGB9sM8SviDcHDa3A= 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/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 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.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From fb32dde136d2587b55638fece25f78a455750d57 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 23 Oct 2024 12:45:10 +0300 Subject: [PATCH 076/289] run go mod tidy --- go.mod | 13 ++++++++++++- go.sum | 35 ++++++++++++++++++++++++++++++----- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 38be305..3349bf8 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,18 @@ require ( gopkg.in/leonelquinteros/gotext.v1 v1.3.1 ) -require github.com/joho/godotenv v1.5.1 // indirect +require ( + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.7.0 // indirect + github.com/jackc/puddle/v2 v2.2.1 // indirect + github.com/joho/godotenv v1.5.1 + github.com/kr/text v0.2.0 // indirect + github.com/rogpeppe/go-internal v1.13.1 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/text v0.18.0 // indirect +) require ( github.com/alecthomas/participle/v2 v2.0.0 // indirect diff --git a/go.sum b/go.sum index 2abec41..ef40172 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,3 @@ -git.defalsify.org/vise.git v0.1.0-rc.3.0.20240923162317-c20d557a3dbb h1:6P4kxihcwMjDKzvUFC6t2zGNb7MDW+l/ACGlSAN1N8Y= -git.defalsify.org/vise.git v0.1.0-rc.3.0.20240923162317-c20d557a3dbb/go.mod h1:JDguWmcoWBdsnpw7PUjVZAEpdC/ubBmjdUBy3tjP63M= -git.defalsify.org/vise.git v0.2.0 h1:X2ZgiGRq4C+9qOlDMP0b/oE5QHjVQNT4aEFZB88ST0Q= -git.defalsify.org/vise.git v0.2.0/go.mod h1:JDguWmcoWBdsnpw7PUjVZAEpdC/ubBmjdUBy3tjP63M= git.defalsify.org/vise.git v0.2.1-0.20241017112704-307fa6fcdc6b h1:dxBplsIlzJHV+5EH+gzB+w08Blt7IJbb2jeRe1OEjLU= git.defalsify.org/vise.git v0.2.1-0.20241017112704-307fa6fcdc6b/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck= github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk= @@ -12,6 +8,8 @@ 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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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= @@ -22,23 +20,50 @@ github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 h1:U4kkNYryi/qf github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4/go.mod h1:zpZDgZFzeq9s0MIeB1P50NIEWDFFHSFBohI/NbaTD/Y= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.0 h1:FG6VLIdzvAPhnYqP14sQ2xhFLkiUQHCs6ySqO91kF4g= +github.com/jackc/pgx/v5 v5.7.0/go.mod h1:awP1KNnjylvpxHuHP63gzjhnGkI1iw+PMoIwvoleN/8= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a h1:0Q3H0YXzMHiciXtRcM+j0jiCe8WKPQHoRgQiRTnfcLY= github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a/go.mod h1:CdTTBOYzS5E4mWS1N8NWP6AHI19MP0A2B18n3hLzRMk= +github.com/pashagolub/pgxmock/v4 v4.3.0 h1:DqT7fk0OCK6H0GvqtcMsLpv8cIwWqdxWgfZNLeHCb/s= +github.com/pashagolub/pgxmock/v4 v4.3.0/go.mod h1:9VoVHXwS3XR/yPtKGzwQvwZX1kzGB9sM8SviDcHDa3A= 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/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 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.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From b41e52af63c845386946845238e99548b78bc0bc Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 23 Oct 2024 12:45:54 +0300 Subject: [PATCH 077/289] pass context.Context --- internal/handlers/server/accountservice.go | 19 ++++++++++--------- internal/handlers/ussd/menuhandler.go | 12 ++++++------ internal/mocks/servicemock.go | 8 +++++--- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/internal/handlers/server/accountservice.go b/internal/handlers/server/accountservice.go index 5b71e6f..f86c2fb 100644 --- a/internal/handlers/server/accountservice.go +++ b/internal/handlers/server/accountservice.go @@ -1,6 +1,7 @@ package server import ( + "context" "encoding/json" "io" "net/http" @@ -11,9 +12,9 @@ import ( ) type AccountServiceInterface interface { - CheckBalance(publicKey string) (*models.BalanceResponse, error) - CreateAccount() (*models.AccountResponse, error) - CheckAccountStatus(trackingId string) (*models.TrackStatusResponse, error) + CheckBalance(publicKey string, ctx context.Context) (*models.BalanceResponse, error) + CreateAccount(ctx context.Context) (*models.AccountResponse, error) + CheckAccountStatus(trackingId string, ctx context.Context) (*models.TrackStatusResponse, error) } type AccountService struct { @@ -33,7 +34,7 @@ type TestAccountService struct { // - 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) (*models.TrackStatusResponse, error) { +func (as *AccountService) CheckAccountStatus(trackingId string, ctx context.Context) (*models.TrackStatusResponse, error) { resp, err := http.Get(config.TrackStatusURL + trackingId) if err != nil { return nil, err @@ -55,7 +56,7 @@ func (as *AccountService) CheckAccountStatus(trackingId string) (*models.TrackSt // 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) (*models.BalanceResponse, error) { +func (as *AccountService) CheckBalance(publicKey string, ctx context.Context) (*models.BalanceResponse, error) { resp, err := http.Get(config.BalanceURL + publicKey) if err != nil { return nil, err @@ -79,7 +80,7 @@ func (as *AccountService) CheckBalance(publicKey string) (*models.BalanceRespons // 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) { +func (as *AccountService) CreateAccount(ctx context.Context) (*models.AccountResponse, error) { resp, err := http.Post(config.CreateAccountURL, "application/json", nil) if err != nil { return nil, err @@ -97,7 +98,7 @@ func (as *AccountService) CreateAccount() (*models.AccountResponse, error) { return &accountResp, nil } -func (tas *TestAccountService) CreateAccount() (*models.AccountResponse, error) { +func (tas *TestAccountService) CreateAccount(ctx context.Context) (*models.AccountResponse, error) { return &models.AccountResponse{ Ok: true, Result: struct { @@ -112,7 +113,7 @@ func (tas *TestAccountService) CreateAccount() (*models.AccountResponse, error) }, nil } -func (tas *TestAccountService) CheckBalance(publicKey string) (*models.BalanceResponse, error) { +func (tas *TestAccountService) CheckBalance(publicKey string, ctx context.Context) (*models.BalanceResponse, error) { balanceResponse := &models.BalanceResponse{ Ok: true, @@ -128,7 +129,7 @@ func (tas *TestAccountService) CheckBalance(publicKey string) (*models.BalanceRe return balanceResponse, nil } -func (tas *TestAccountService) CheckAccountStatus(trackingId string) (*models.TrackStatusResponse, error) { +func (tas *TestAccountService) CheckAccountStatus(trackingId string, ctx context.Context) (*models.TrackStatusResponse, error) { trackResponse := &models.TrackStatusResponse{ Ok: true, Result: struct { diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 36d1ad5..03351c0 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -136,7 +136,7 @@ func (h *Handlers) SetLanguage(ctx context.Context, sym string, input []byte) (r } func (h *Handlers) createAccountNoExist(ctx context.Context, sessionId string, res *resource.Result) error { - accountResp, err := h.accountService.CreateAccount() + accountResp, err := h.accountService.CreateAccount(ctx) data := map[utils.DataTyp]string{ utils.DATA_TRACKING_ID: accountResp.Result.TrackingId, utils.DATA_PUBLIC_KEY: accountResp.Result.PublicKey, @@ -547,7 +547,7 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b return res, err } - accountStatus, err := h.accountService.CheckAccountStatus(string(trackingId)) + accountStatus, err := h.accountService.CheckAccountStatus(string(trackingId),ctx) if err != nil { fmt.Println("Error checking account status:", err) return res, err @@ -656,7 +656,7 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) ( return res, err } - balanceResponse, err := h.accountService.CheckBalance(string(publicKey)) + balanceResponse, err := h.accountService.CheckBalance(string(publicKey),ctx) if err != nil { return res, nil } @@ -688,7 +688,7 @@ func (h *Handlers) FetchCustodialBalances(ctx context.Context, sym string, input return res, err } - balanceResponse, err := h.accountService.CheckBalance(string(publicKey)) + balanceResponse, err := h.accountService.CheckBalance(string(publicKey),ctx) if err != nil { return res, nil } @@ -806,7 +806,7 @@ func (h *Handlers) MaxAmount(ctx context.Context, sym string, input []byte) (res store := h.userdataStore publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) - balanceResp, err := h.accountService.CheckBalance(string(publicKey)) + balanceResp, err := h.accountService.CheckBalance(string(publicKey),ctx) if err != nil { return res, nil } @@ -836,7 +836,7 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte) amountStr := string(input) - balanceRes, err := h.accountService.CheckBalance(string(publicKey)) + balanceRes, err := h.accountService.CheckBalance(string(publicKey),ctx) balanceStr := balanceRes.Result.Balance if !balanceRes.Ok { diff --git a/internal/mocks/servicemock.go b/internal/mocks/servicemock.go index d828045..8c2b4ea 100644 --- a/internal/mocks/servicemock.go +++ b/internal/mocks/servicemock.go @@ -1,6 +1,8 @@ package mocks import ( + "context" + "git.grassecon.net/urdt/ussd/internal/models" "github.com/stretchr/testify/mock" ) @@ -10,17 +12,17 @@ type MockAccountService struct { mock.Mock } -func (m *MockAccountService) CreateAccount() (*models.AccountResponse, error) { +func (m *MockAccountService) CreateAccount(ctx context.Context) (*models.AccountResponse, error) { args := m.Called() return args.Get(0).(*models.AccountResponse), args.Error(1) } -func (m *MockAccountService) CheckBalance(publicKey string) (*models.BalanceResponse, error) { +func (m *MockAccountService) CheckBalance(publicKey string,ctx context.Context) (*models.BalanceResponse, error) { args := m.Called(publicKey) return args.Get(0).(*models.BalanceResponse), args.Error(1) } -func (m *MockAccountService) CheckAccountStatus(trackingId string) (*models.TrackStatusResponse, error) { +func (m *MockAccountService) CheckAccountStatus(trackingId string,ctx context.Context) (*models.TrackStatusResponse, error) { args := m.Called(trackingId) return args.Get(0).(*models.TrackStatusResponse), args.Error(1) } \ No newline at end of file From 176473aa264cc0c353e2a78f0c69f8cb3bc31aa2 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 23 Oct 2024 13:54:42 +0300 Subject: [PATCH 078/289] Rename prefix to vouchers --- internal/handlers/ussd/menuhandler.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 621a43e..d464ca3 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -1068,7 +1068,7 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) // process voucher data voucherSymbolList, voucherBalanceList := ProcessVouchers(vouchersResp.Result.Holdings) - prefixdb := storage.NewSubPrefixDb(store, []byte("pfx")) + prefixdb := storage.NewSubPrefixDb(store, []byte("vouchers")) err = prefixdb.Put(ctx, []byte("sym"), []byte(voucherSymbolList)) if err != nil { return res, nil @@ -1108,7 +1108,7 @@ func (h *Handlers) GetVoucherList(ctx context.Context, sym string, input []byte) // Read vouchers from the store store := h.userdataStore - prefixdb := storage.NewSubPrefixDb(store, []byte("pfx")) + prefixdb := storage.NewSubPrefixDb(store, []byte("vouchers")) voucherData, err := prefixdb.Get(ctx, []byte("sym")) if err != nil { @@ -1139,7 +1139,7 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r return res, nil } - prefixdb := storage.NewSubPrefixDb(store, []byte("pfx")) + prefixdb := storage.NewSubPrefixDb(store, []byte("vouchers")) // Retrieve the voucher symbol list voucherSymbolList, err := prefixdb.Get(ctx, []byte("sym")) From 4011597d9c9d6653c35cb569970aba62066b59e9 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 23 Oct 2024 14:02:13 +0300 Subject: [PATCH 079/289] Check specific db error --- internal/handlers/ussd/menuhandler.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index d464ca3..009d3cc 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -640,8 +640,12 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) ( // get the active sym and active balance activeSym, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM) if err != nil { - res.Content = "0.00" - return res, nil + if db.IsNotFound(err) { + res.Content = "0.00" + return res, nil + } + + return res, err } activeBal, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_BAL) From a553731f02f3fb8bb53150a6982eca1629372a9b Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 23 Oct 2024 17:45:41 +0300 Subject: [PATCH 080/289] Cleaned up code --- internal/handlers/ussd/menuhandler.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 009d3cc..f57b4e7 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -1004,7 +1004,6 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by if err != nil { if db.IsNotFound(err) { publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) - if err != nil { return res, nil } From 9bc9d04a49c591869692b8c59fd4ed0aa8e81087 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 24 Oct 2024 10:00:38 +0300 Subject: [PATCH 081/289] use errresponse and okresponse for deserialization --- internal/handlers/server/accountservice.go | 97 ++++++++-------------- 1 file changed, 34 insertions(+), 63 deletions(-) diff --git a/internal/handlers/server/accountservice.go b/internal/handlers/server/accountservice.go index 39d1c66..6ae9630 100644 --- a/internal/handlers/server/accountservice.go +++ b/internal/handlers/server/accountservice.go @@ -2,6 +2,7 @@ package server import ( "encoding/json" + "errors" "fmt" "io" "net/http" @@ -12,16 +13,17 @@ import ( "github.com/grassrootseconomics/eth-custodial/pkg/api" ) -type ApiResponse struct { - Ok bool `json:"ok"` - Description string `json:"description"` -} +var ( + okResponse api.OKResponse + errResponse api.ErrResponse + EMPTY_RESPONSE = 0 +) type AccountServiceInterface interface { CheckBalance(publicKey string) (*models.BalanceResponse, error) - CreateAccount() (*api.OKResponse, *api.ErrResponse) + CreateAccount() (*api.OKResponse, error) CheckAccountStatus(trackingId string) (*models.TrackStatusResponse, error) - TrackAccountStatus(publicKey string) (*api.OKResponse, *api.ErrResponse) + TrackAccountStatus(publicKey string) (*api.OKResponse, error) } type AccountService struct { @@ -60,58 +62,42 @@ func (as *AccountService) CheckAccountStatus(trackingId string) (*models.TrackSt } -func (as *AccountService) TrackAccountStatus(publicKey string) (*api.OKResponse, *api.ErrResponse) { - var errResponse api.ErrResponse - var okResponse api.OKResponse +func (as *AccountService) TrackAccountStatus(publicKey string) (*api.OKResponse, error) { var err error // Construct the URL with the path parameter url := fmt.Sprintf("%s/%s", config.TrackURL, publicKey) req, err := http.NewRequest("GET", url, nil) if err != nil { - errResponse.Description = err.Error() - return nil, &errResponse + return nil, err } - // Set headers + req.Header.Set("Content-Type", "application/json") req.Header.Set("X-GE-KEY", "xd") - // Send the request resp, err := http.DefaultClient.Do(req) if err != nil { - errResponse.Description = err.Error() - return nil, &errResponse + return nil, err } defer resp.Body.Close() - // Read the response body body, err := io.ReadAll(resp.Body) if err != nil { errResponse.Description = err.Error() - return nil, &errResponse + return nil, err } - - // Step 2: Unmarshal into the generic struct - var apiResponse ApiResponse - err = json.Unmarshal([]byte(body), &apiResponse) + err = json.Unmarshal([]byte(body), &okResponse) if err != nil { - errResponse.Description = err.Error() - return nil, &errResponse - } - if apiResponse.Ok { - err = json.Unmarshal([]byte(body), &okResponse) - if err != nil { - errResponse.Description = err.Error() - return nil, &errResponse - } - return &okResponse, nil - } else { err := json.Unmarshal([]byte(body), &errResponse) if err != nil { - errResponse.Description = err.Error() - return nil, &errResponse + return nil, err } - return nil, &errResponse + return nil, errors.New(errResponse.Description) } + if len(okResponse.Result) == EMPTY_RESPONSE { + return nil, errors.New("Empty api result") + } + return &okResponse, nil + } // CheckBalance retrieves the balance for a given public key from the custodial balance API endpoint. @@ -141,17 +127,13 @@ func (as *AccountService) CheckBalance(publicKey string) (*models.BalanceRespons // 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() (*api.OKResponse, *api.ErrResponse) { - - var errResponse api.ErrResponse - var okResponse api.OKResponse +func (as *AccountService) CreateAccount() (*api.OKResponse, error) { var err error // Create a new request req, err := http.NewRequest("POST", config.CreateAccountURL, nil) if err != nil { - errResponse.Description = err.Error() - return nil, &errResponse + return nil, err } req.Header.Set("Content-Type", "application/json") req.Header.Set("X-GE-KEY", "xd") @@ -159,38 +141,29 @@ func (as *AccountService) CreateAccount() (*api.OKResponse, *api.ErrResponse) { resp, err := http.DefaultClient.Do(req) if err != nil { errResponse.Description = err.Error() - return nil, &errResponse + return nil, err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { - errResponse.Description = err.Error() - return nil, &errResponse + return nil, err } - var apiResponse ApiResponse - err = json.Unmarshal([]byte(body), &apiResponse) + err = json.Unmarshal([]byte(body), &okResponse) if err != nil { - return nil, &errResponse - } - if apiResponse.Ok { - err = json.Unmarshal([]byte(body), &okResponse) - if err != nil { - errResponse.Description = err.Error() - return nil, &errResponse - } - return &okResponse, nil - } else { err := json.Unmarshal([]byte(body), &errResponse) if err != nil { - errResponse.Description = err.Error() - return nil, &errResponse + return nil, err } - return nil, &errResponse + return nil, errors.New(errResponse.Description) } + if len(okResponse.Result) == EMPTY_RESPONSE { + return nil, errors.New("Empty api result") + } + return &okResponse, nil } -func (tas *TestAccountService) CreateAccount() (*api.OKResponse, *api.ErrResponse) { +func (tas *TestAccountService) CreateAccount() (*api.OKResponse, error) { return &api.OKResponse{ Ok: true, Description: "Account creation request received successfully", @@ -200,7 +173,6 @@ func (tas *TestAccountService) CreateAccount() (*api.OKResponse, *api.ErrRespons } func (tas *TestAccountService) CheckBalance(publicKey string) (*models.BalanceResponse, error) { - balanceResponse := &models.BalanceResponse{ Ok: true, Result: struct { @@ -211,11 +183,10 @@ func (tas *TestAccountService) CheckBalance(publicKey string) (*models.BalanceRe Nonce: json.Number("0"), }, } - return balanceResponse, nil } -func (tas *TestAccountService) TrackAccountStatus(publicKey string) (*api.OKResponse, *api.ErrResponse) { +func (tas *TestAccountService) TrackAccountStatus(publicKey string) (*api.OKResponse, error) { return &api.OKResponse{ Ok: true, Description: "Account creation succeeded", From 08e709f1b349f1bbe51c829c852977d0eab3743c Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 24 Oct 2024 10:02:15 +0300 Subject: [PATCH 082/289] check for error responses --- internal/handlers/ussd/menuhandler.go | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 0fc30cc..e7f52eb 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -3,7 +3,6 @@ package ussd import ( "bytes" "context" - "errors" "fmt" "path" "regexp" @@ -141,24 +140,17 @@ func (h *Handlers) SetLanguage(ctx context.Context, sym string, input []byte) (r func (h *Handlers) createAccountNoExist(ctx context.Context, sessionId string, res *resource.Result) error { flag_account_created, _ := h.flagManager.GetFlag("flag_account_created") - flag_api_call_error, _ := h.flagManager.GetFlag("flag_api_call_error") - okResponse, errResponse := h.accountService.CreateAccount() - if errResponse != nil { - if !errResponse.Ok { - res.FlagSet = append(res.FlagSet, flag_api_call_error) - return nil - } - return errors.New(errResponse.Description) + okResponse, err := h.accountService.CreateAccount() + if err != nil { + return err } trackingId := okResponse.Result["trackingId"].(string) publicKey := okResponse.Result["publicKey"].(string) - res.FlagReset = append(res.FlagReset, flag_api_call_error) data := map[utils.DataTyp]string{ utils.DATA_TRACKING_ID: trackingId, utils.DATA_PUBLIC_KEY: publicKey, } - for key, value := range data { store := h.userdataStore err := store.WriteEntry(ctx, sessionId, key, []byte(value)) @@ -552,11 +544,9 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b if err != nil { return res, err } - okResponse, errResponse = h.accountService.TrackAccountStatus(string(publicKey)) - if errResponse != nil { - if !errResponse.Ok { - res.FlagSet = append(res.FlagSet, flag_api_error) - } + okResponse, err = h.accountService.TrackAccountStatus(string(publicKey)) + if err != nil { + res.FlagSet = append(res.FlagSet, flag_api_error) return res, err } res.FlagReset = append(res.FlagReset, flag_api_error) From 308ca99fb082d646aa34aae5610841232fbb8df4 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 24 Oct 2024 10:02:32 +0300 Subject: [PATCH 083/289] remove reload account creation --- services/registration/create_pin.vis | 2 -- 1 file changed, 2 deletions(-) diff --git a/services/registration/create_pin.vis b/services/registration/create_pin.vis index 44d2cf1..e0e330f 100644 --- a/services/registration/create_pin.vis +++ b/services/registration/create_pin.vis @@ -1,6 +1,4 @@ LOAD create_account 0 -RELOAD create_account -CATCH api_failure flag_api_call_error 1 CATCH account_creation_failed flag_account_creation_failed 1 MOUT exit 0 HALT From d74a4cc33ba5fb1c04f2a6b1a03062ea1f8cc0e7 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 24 Oct 2024 10:10:03 +0300 Subject: [PATCH 084/289] update service mock method signatures --- internal/mocks/servicemock.go | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/internal/mocks/servicemock.go b/internal/mocks/servicemock.go index 0cf07c6..0b56314 100644 --- a/internal/mocks/servicemock.go +++ b/internal/mocks/servicemock.go @@ -11,19 +11,9 @@ type MockAccountService struct { mock.Mock } -func (m *MockAccountService) CreateAccount() (*api.OKResponse, *api.ErrResponse) { +func (m *MockAccountService) CreateAccount() (*api.OKResponse, error) { args := m.Called() - okResponse, ok := args.Get(0).(*api.OKResponse) - errResponse, err := args.Get(1).(*api.ErrResponse) - - if ok { - return okResponse, nil - } - - if err { - return nil, errResponse - } - return nil, nil + return args.Get(0).(*api.OKResponse), args.Error(1) } func (m *MockAccountService) CheckBalance(publicKey string) (*models.BalanceResponse, error) { @@ -36,15 +26,7 @@ func (m *MockAccountService) CheckAccountStatus(trackingId string) (*models.Trac return args.Get(0).(*models.TrackStatusResponse), args.Error(1) } -func (m *MockAccountService) TrackAccountStatus(publicKey string) (*api.OKResponse, *api.ErrResponse) { +func (m *MockAccountService) TrackAccountStatus(publicKey string) (*api.OKResponse, error) { args := m.Called(publicKey) - okResponse, ok := args.Get(0).(*api.OKResponse) - errResponse, err := args.Get(1).(*api.ErrResponse) - if ok { - return okResponse, nil - } - if err { - return nil, errResponse - } - return nil, nil + return args.Get(0).(*api.OKResponse), args.Error(1) } From 9f2d57ea0361c1d131b55a9d5080456eb80535d1 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 24 Oct 2024 10:10:14 +0300 Subject: [PATCH 085/289] update tests --- internal/handlers/ussd/menuhandler_test.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 3b4b00f..8828690 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -75,11 +75,9 @@ func TestCreateAccount(t *testing.T) { } // Create required mocks flag_account_created, err := fm.GetFlag("flag_account_created") - flag_api_call_error, _ := fm.GetFlag("flag_api_call_error") if err != nil { t.Logf(err.Error()) } - // Define session ID and mock data sessionId := "session123" notFoundErr := db.ErrNotFound{} @@ -101,8 +99,7 @@ func TestCreateAccount(t *testing.T) { }, }, expectedResult: resource.Result{ - FlagSet: []uint32{flag_account_created}, - FlagReset: []uint32{flag_api_call_error}, + FlagSet: []uint32{flag_account_created}, }, }, } From f3a028f1fc73ef2a84b80787585386af59b83920 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 24 Oct 2024 12:03:32 +0300 Subject: [PATCH 086/289] move to testutil --- internal/mocks/dbmock.go | 59 ------------------- internal/mocks/httpmocks/enginemock.go | 30 ---------- .../mocks/httpmocks/requesthandlermock.go | 47 --------------- internal/mocks/httpmocks/requestparsermock.go | 15 ----- internal/mocks/httpmocks/writermock.go | 25 -------- internal/mocks/servicemock.go | 26 -------- internal/mocks/userdbmock.go | 24 -------- 7 files changed, 226 deletions(-) delete mode 100644 internal/mocks/dbmock.go delete mode 100644 internal/mocks/httpmocks/enginemock.go delete mode 100644 internal/mocks/httpmocks/requesthandlermock.go delete mode 100644 internal/mocks/httpmocks/requestparsermock.go delete mode 100644 internal/mocks/httpmocks/writermock.go delete mode 100644 internal/mocks/servicemock.go delete mode 100644 internal/mocks/userdbmock.go diff --git a/internal/mocks/dbmock.go b/internal/mocks/dbmock.go deleted file mode 100644 index 0b40eab..0000000 --- a/internal/mocks/dbmock.go +++ /dev/null @@ -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) -} diff --git a/internal/mocks/httpmocks/enginemock.go b/internal/mocks/httpmocks/enginemock.go deleted file mode 100644 index 12d07f4..0000000 --- a/internal/mocks/httpmocks/enginemock.go +++ /dev/null @@ -1,30 +0,0 @@ -package httpmocks - -import ( - "context" - "io" -) - -// MockEngine implements the engine.Engine interface for testing -type MockEngine struct { - InitFunc func(context.Context) (bool, error) - ExecFunc func(context.Context, []byte) (bool, error) - FlushFunc func(context.Context, io.Writer) (int, error) - FinishFunc func() error -} - -func (m *MockEngine) Init(ctx context.Context) (bool, error) { - return m.InitFunc(ctx) -} - -func (m *MockEngine) Exec(ctx context.Context, input []byte) (bool, error) { - return m.ExecFunc(ctx, input) -} - -func (m *MockEngine) Flush(ctx context.Context, w io.Writer) (int, error) { - return m.FlushFunc(ctx, w) -} - -func (m *MockEngine) Finish() error { - return m.FinishFunc() -} diff --git a/internal/mocks/httpmocks/requesthandlermock.go b/internal/mocks/httpmocks/requesthandlermock.go deleted file mode 100644 index f17abce..0000000 --- a/internal/mocks/httpmocks/requesthandlermock.go +++ /dev/null @@ -1,47 +0,0 @@ -package httpmocks - -import ( - "git.defalsify.org/vise.git/engine" - "git.defalsify.org/vise.git/persist" - "git.defalsify.org/vise.git/resource" - "git.grassecon.net/urdt/ussd/internal/handlers" -) - -// MockRequestHandler implements handlers.RequestHandler interface for testing -type MockRequestHandler struct { - ProcessFunc func(handlers.RequestSession) (handlers.RequestSession, error) - GetConfigFunc func() engine.Config - GetEngineFunc func(cfg engine.Config, rs resource.Resource, pe *persist.Persister) engine.Engine - OutputFunc func(rs handlers.RequestSession) (handlers.RequestSession, error) - ResetFunc func(rs handlers.RequestSession) (handlers.RequestSession, error) - ShutdownFunc func() - GetRequestParserFunc func() handlers.RequestParser -} - -func (m *MockRequestHandler) Process(rqs handlers.RequestSession) (handlers.RequestSession, error) { - return m.ProcessFunc(rqs) -} - -func (m *MockRequestHandler) GetConfig() engine.Config { - return m.GetConfigFunc() -} - -func (m *MockRequestHandler) GetEngine(cfg engine.Config, rs resource.Resource, pe *persist.Persister) engine.Engine { - return m.GetEngineFunc(cfg, rs, pe) -} - -func (m *MockRequestHandler) Output(rs handlers.RequestSession) (handlers.RequestSession, error) { - return m.OutputFunc(rs) -} - -func (m *MockRequestHandler) Reset(rs handlers.RequestSession) (handlers.RequestSession, error) { - return m.ResetFunc(rs) -} - -func (m *MockRequestHandler) Shutdown() { - m.ShutdownFunc() -} - -func (m *MockRequestHandler) GetRequestParser() handlers.RequestParser { - return m.GetRequestParserFunc() -} diff --git a/internal/mocks/httpmocks/requestparsermock.go b/internal/mocks/httpmocks/requestparsermock.go deleted file mode 100644 index 54b16bf..0000000 --- a/internal/mocks/httpmocks/requestparsermock.go +++ /dev/null @@ -1,15 +0,0 @@ -package httpmocks - -// MockRequestParser implements the handlers.RequestParser interface for testing -type MockRequestParser struct { - GetSessionIdFunc func(any) (string, error) - GetInputFunc func(any) ([]byte, error) -} - -func (m *MockRequestParser) GetSessionId(rq any) (string, error) { - return m.GetSessionIdFunc(rq) -} - -func (m *MockRequestParser) GetInput(rq any) ([]byte, error) { - return m.GetInputFunc(rq) -} diff --git a/internal/mocks/httpmocks/writermock.go b/internal/mocks/httpmocks/writermock.go deleted file mode 100644 index 0d171d2..0000000 --- a/internal/mocks/httpmocks/writermock.go +++ /dev/null @@ -1,25 +0,0 @@ -package httpmocks - -import "net/http" - -// MockWriter implements a mock io.Writer for testing -type MockWriter struct { - WriteStringCalled bool - WrittenString string -} - -func (m *MockWriter) Write(p []byte) (n int, err error) { - return len(p), nil -} - -func (m *MockWriter) WriteString(s string) (n int, err error) { - m.WriteStringCalled = true - m.WrittenString = s - return len(s), nil -} - -func (m *MockWriter) Header() http.Header { - return http.Header{} -} - -func (m *MockWriter) WriteHeader(statusCode int) {} \ No newline at end of file diff --git a/internal/mocks/servicemock.go b/internal/mocks/servicemock.go deleted file mode 100644 index d828045..0000000 --- a/internal/mocks/servicemock.go +++ /dev/null @@ -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) (*models.BalanceResponse, error) { - args := m.Called(publicKey) - return args.Get(0).(*models.BalanceResponse), args.Error(1) -} - -func (m *MockAccountService) CheckAccountStatus(trackingId string) (*models.TrackStatusResponse, error) { - args := m.Called(trackingId) - return args.Get(0).(*models.TrackStatusResponse), args.Error(1) -} \ No newline at end of file diff --git a/internal/mocks/userdbmock.go b/internal/mocks/userdbmock.go deleted file mode 100644 index ff3f18d..0000000 --- a/internal/mocks/userdbmock.go +++ /dev/null @@ -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) -} From 651969668f64e82fcfe18a26b9a18f5b44fef677 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 24 Oct 2024 12:05:11 +0300 Subject: [PATCH 087/289] move to testutil --- internal/testutil/mocks/dbmock.go | 59 +++++++++++++++++++ .../testutil/mocks/httpmocks/enginemock.go | 30 ++++++++++ .../mocks/httpmocks/requesthandlermock.go | 47 +++++++++++++++ .../mocks/httpmocks/requestparsermock.go | 15 +++++ .../testutil/mocks/httpmocks/writermock.go | 25 ++++++++ internal/testutil/mocks/servicemock.go | 26 ++++++++ 6 files changed, 202 insertions(+) create mode 100644 internal/testutil/mocks/dbmock.go create mode 100644 internal/testutil/mocks/httpmocks/enginemock.go create mode 100644 internal/testutil/mocks/httpmocks/requesthandlermock.go create mode 100644 internal/testutil/mocks/httpmocks/requestparsermock.go create mode 100644 internal/testutil/mocks/httpmocks/writermock.go create mode 100644 internal/testutil/mocks/servicemock.go diff --git a/internal/testutil/mocks/dbmock.go b/internal/testutil/mocks/dbmock.go new file mode 100644 index 0000000..0b40eab --- /dev/null +++ b/internal/testutil/mocks/dbmock.go @@ -0,0 +1,59 @@ +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) +} diff --git a/internal/testutil/mocks/httpmocks/enginemock.go b/internal/testutil/mocks/httpmocks/enginemock.go new file mode 100644 index 0000000..12d07f4 --- /dev/null +++ b/internal/testutil/mocks/httpmocks/enginemock.go @@ -0,0 +1,30 @@ +package httpmocks + +import ( + "context" + "io" +) + +// MockEngine implements the engine.Engine interface for testing +type MockEngine struct { + InitFunc func(context.Context) (bool, error) + ExecFunc func(context.Context, []byte) (bool, error) + FlushFunc func(context.Context, io.Writer) (int, error) + FinishFunc func() error +} + +func (m *MockEngine) Init(ctx context.Context) (bool, error) { + return m.InitFunc(ctx) +} + +func (m *MockEngine) Exec(ctx context.Context, input []byte) (bool, error) { + return m.ExecFunc(ctx, input) +} + +func (m *MockEngine) Flush(ctx context.Context, w io.Writer) (int, error) { + return m.FlushFunc(ctx, w) +} + +func (m *MockEngine) Finish() error { + return m.FinishFunc() +} diff --git a/internal/testutil/mocks/httpmocks/requesthandlermock.go b/internal/testutil/mocks/httpmocks/requesthandlermock.go new file mode 100644 index 0000000..f17abce --- /dev/null +++ b/internal/testutil/mocks/httpmocks/requesthandlermock.go @@ -0,0 +1,47 @@ +package httpmocks + +import ( + "git.defalsify.org/vise.git/engine" + "git.defalsify.org/vise.git/persist" + "git.defalsify.org/vise.git/resource" + "git.grassecon.net/urdt/ussd/internal/handlers" +) + +// MockRequestHandler implements handlers.RequestHandler interface for testing +type MockRequestHandler struct { + ProcessFunc func(handlers.RequestSession) (handlers.RequestSession, error) + GetConfigFunc func() engine.Config + GetEngineFunc func(cfg engine.Config, rs resource.Resource, pe *persist.Persister) engine.Engine + OutputFunc func(rs handlers.RequestSession) (handlers.RequestSession, error) + ResetFunc func(rs handlers.RequestSession) (handlers.RequestSession, error) + ShutdownFunc func() + GetRequestParserFunc func() handlers.RequestParser +} + +func (m *MockRequestHandler) Process(rqs handlers.RequestSession) (handlers.RequestSession, error) { + return m.ProcessFunc(rqs) +} + +func (m *MockRequestHandler) GetConfig() engine.Config { + return m.GetConfigFunc() +} + +func (m *MockRequestHandler) GetEngine(cfg engine.Config, rs resource.Resource, pe *persist.Persister) engine.Engine { + return m.GetEngineFunc(cfg, rs, pe) +} + +func (m *MockRequestHandler) Output(rs handlers.RequestSession) (handlers.RequestSession, error) { + return m.OutputFunc(rs) +} + +func (m *MockRequestHandler) Reset(rs handlers.RequestSession) (handlers.RequestSession, error) { + return m.ResetFunc(rs) +} + +func (m *MockRequestHandler) Shutdown() { + m.ShutdownFunc() +} + +func (m *MockRequestHandler) GetRequestParser() handlers.RequestParser { + return m.GetRequestParserFunc() +} diff --git a/internal/testutil/mocks/httpmocks/requestparsermock.go b/internal/testutil/mocks/httpmocks/requestparsermock.go new file mode 100644 index 0000000..54b16bf --- /dev/null +++ b/internal/testutil/mocks/httpmocks/requestparsermock.go @@ -0,0 +1,15 @@ +package httpmocks + +// MockRequestParser implements the handlers.RequestParser interface for testing +type MockRequestParser struct { + GetSessionIdFunc func(any) (string, error) + GetInputFunc func(any) ([]byte, error) +} + +func (m *MockRequestParser) GetSessionId(rq any) (string, error) { + return m.GetSessionIdFunc(rq) +} + +func (m *MockRequestParser) GetInput(rq any) ([]byte, error) { + return m.GetInputFunc(rq) +} diff --git a/internal/testutil/mocks/httpmocks/writermock.go b/internal/testutil/mocks/httpmocks/writermock.go new file mode 100644 index 0000000..0d171d2 --- /dev/null +++ b/internal/testutil/mocks/httpmocks/writermock.go @@ -0,0 +1,25 @@ +package httpmocks + +import "net/http" + +// MockWriter implements a mock io.Writer for testing +type MockWriter struct { + WriteStringCalled bool + WrittenString string +} + +func (m *MockWriter) Write(p []byte) (n int, err error) { + return len(p), nil +} + +func (m *MockWriter) WriteString(s string) (n int, err error) { + m.WriteStringCalled = true + m.WrittenString = s + return len(s), nil +} + +func (m *MockWriter) Header() http.Header { + return http.Header{} +} + +func (m *MockWriter) WriteHeader(statusCode int) {} \ No newline at end of file diff --git a/internal/testutil/mocks/servicemock.go b/internal/testutil/mocks/servicemock.go new file mode 100644 index 0000000..d828045 --- /dev/null +++ b/internal/testutil/mocks/servicemock.go @@ -0,0 +1,26 @@ +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) (*models.BalanceResponse, error) { + args := m.Called(publicKey) + return args.Get(0).(*models.BalanceResponse), args.Error(1) +} + +func (m *MockAccountService) CheckAccountStatus(trackingId string) (*models.TrackStatusResponse, error) { + args := m.Called(trackingId) + return args.Get(0).(*models.TrackStatusResponse), args.Error(1) +} \ No newline at end of file From 5692440099109d321a7a8487407b82fcd6cb561c Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 24 Oct 2024 12:05:27 +0300 Subject: [PATCH 088/289] move to testutil --- internal/testutil/mocks/userdbmock.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 internal/testutil/mocks/userdbmock.go diff --git a/internal/testutil/mocks/userdbmock.go b/internal/testutil/mocks/userdbmock.go new file mode 100644 index 0000000..ff3f18d --- /dev/null +++ b/internal/testutil/mocks/userdbmock.go @@ -0,0 +1,24 @@ +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) +} From 57a07af8caee42c2a5a64abffaa41e7203a93fa5 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 24 Oct 2024 12:06:44 +0300 Subject: [PATCH 089/289] correct import --- internal/http/http_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/http/http_test.go b/internal/http/http_test.go index 8f6f312..14bb90a 100644 --- a/internal/http/http_test.go +++ b/internal/http/http_test.go @@ -13,7 +13,7 @@ import ( "git.defalsify.org/vise.git/engine" "git.grassecon.net/urdt/ussd/internal/handlers" - "git.grassecon.net/urdt/ussd/internal/mocks/httpmocks" + "git.grassecon.net/urdt/ussd/internal/testutil/mocks/httpmocks" ) // invalidRequestType is a custom type to test invalid request scenarios From f99486c19067bfe084e08b1811500c6173b8e350 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 24 Oct 2024 12:07:00 +0300 Subject: [PATCH 090/289] correct import --- internal/handlers/ussd/menuhandler_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 42e97fd..482e997 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -15,8 +15,8 @@ import ( "git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/state" - "git.grassecon.net/urdt/ussd/internal/mocks" "git.grassecon.net/urdt/ussd/internal/models" + "git.grassecon.net/urdt/ussd/internal/testutil/mocks" "git.grassecon.net/urdt/ussd/internal/testutil/testservice" "git.grassecon.net/urdt/ussd/internal/utils" From 579b46db65b858b25f5196215f11ed08eeb120d5 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 24 Oct 2024 14:34:12 +0300 Subject: [PATCH 091/289] Replace the public key with the sessionId --- internal/handlers/ussd/menuhandler.go | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 36d1ad5..bdb9fb7 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -906,7 +906,7 @@ func (h *Handlers) GetRecipient(ctx context.Context, sym string, input []byte) ( return res, nil } -// GetSender retrieves the public key from the Gdbm Db +// GetSender returns the sessionId (phoneNumber) func (h *Handlers) GetSender(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result @@ -915,10 +915,7 @@ func (h *Handlers) GetSender(ctx context.Context, sym string, input []byte) (res return res, fmt.Errorf("missing session") } - store := h.userdataStore - publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) - - res.Content = string(publicKey) + res.Content = string(sessionId) return res, nil } @@ -955,13 +952,12 @@ func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input [] // TODO // Use the amount, recipient and sender to call the API and initialize the transaction store := h.userdataStore - publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) amount, _ := store.ReadEntry(ctx, sessionId, utils.DATA_AMOUNT) recipient, _ := store.ReadEntry(ctx, sessionId, utils.DATA_RECIPIENT) - res.Content = l.Get("Your request has been sent. %s will receive %s from %s.", string(recipient), string(amount), string(publicKey)) + res.Content = l.Get("Your request has been sent. %s will receive %s from %s.", string(recipient), string(amount), string(sessionId)) account_authorized_flag, err := h.flagManager.GetFlag("flag_account_authorized") if err != nil { From 6200728435c09aa010f65a66862fbcd2e6420bb8 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 24 Oct 2024 14:45:15 +0300 Subject: [PATCH 092/289] Updated the menuhander test --- internal/handlers/ussd/menuhandler_test.go | 27 +++++++--------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 38c468c..bd72d65 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -509,12 +509,8 @@ func TestGetSender(t *testing.T) { mockStore := new(mocks.MockUserDataStore) // Define test data - sessionId := "session123" + sessionId := "254712345678" 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{ @@ -522,11 +518,10 @@ func TestGetSender(t *testing.T) { } // 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) + res, _ := h.GetSender(ctx, "get_sender", []byte("")) + //Assert that the sessionId is what was set as the result content. + assert.Equal(t, sessionId, res.Content) } func TestGetAmount(t *testing.T) { @@ -1284,7 +1279,7 @@ func TestResetInvalidAmount(t *testing.T) { } func TestInitiateTransaction(t *testing.T) { - sessionId := "session123" + sessionId := "254712345678" fm, err := NewFlagManager(flagsPath) @@ -1307,30 +1302,26 @@ func TestInitiateTransaction(t *testing.T) { tests := []struct { name string input []byte - PublicKey []byte Recipient []byte Amount []byte status string expectedResult resource.Result }{ { - name: "Test amount reset", - PublicKey: []byte("0x1241527192"), - Amount: []byte("0.002CELO"), + name: "Test initiate transaction", + Amount: []byte("0.002 CELO"), Recipient: []byte("0x12415ass27192"), expectedResult: resource.Result{ FlagReset: []uint32{account_authorized_flag}, - Content: "Your request has been sent. 0x12415ass27192 will receive 0.002CELO from 0x1241527192.", + Content: "Your request has been sent. 0x12415ass27192 will receive 0.002 CELO from 254712345678.", }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Define expected interactions with the mock - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return(tt.PublicKey, nil) mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_AMOUNT).Return(tt.Amount, nil) mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_RECIPIENT).Return(tt.Recipient, nil) - //mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_AMOUNT, []byte("")).Return(nil) // Call the method under test res, _ := h.InitiateTransaction(ctx, "transaction_reset_amount", tt.input) @@ -1343,10 +1334,8 @@ func TestInitiateTransaction(t *testing.T) { // Assert that expectations were met mockDataStore.AssertExpectations(t) - }) } - } func TestQuit(t *testing.T) { From 75459f852b8b5b8df43a2ccb1cf05db1e159c877 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 24 Oct 2024 15:12:57 +0300 Subject: [PATCH 093/289] Return the full balance string --- internal/handlers/ussd/menuhandler.go | 7 ++++++- services/registration/locale/swa/default.po | 4 +++- services/registration/main | 2 +- services/registration/main_swa | 2 +- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 36d1ad5..ce56a58 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -650,6 +650,10 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) ( return res, fmt.Errorf("missing session") } + code := codeFromCtx(ctx) + l := gotext.NewLocale(translationDir, code) + l.AddDomain("default") + store := h.userdataStore publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) if err != nil { @@ -666,7 +670,8 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) ( } res.FlagReset = append(res.FlagReset, flag_api_error) balance := balanceResponse.Result.Balance - res.Content = balance + + res.Content = l.Get("Balance: %s\n", balance) return res, nil } diff --git a/services/registration/locale/swa/default.po b/services/registration/locale/swa/default.po index 5289dd7..0a3909b 100644 --- a/services/registration/locale/swa/default.po +++ b/services/registration/locale/swa/default.po @@ -7,6 +7,8 @@ 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" + +msgid "Balance: %s\n" +msgstr "Salio: %s\n" diff --git a/services/registration/main b/services/registration/main index bf15ea5..afae8c1 100644 --- a/services/registration/main +++ b/services/registration/main @@ -1 +1 @@ -Balance: {{.check_balance}} +{{.check_balance}} \ No newline at end of file diff --git a/services/registration/main_swa b/services/registration/main_swa index b72abf0..afae8c1 100644 --- a/services/registration/main_swa +++ b/services/registration/main_swa @@ -1 +1 @@ -Salio: {{.check_balance}} +{{.check_balance}} \ No newline at end of file From 39c0560abef514ca1fa49083444f8874146e6c4f Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 24 Oct 2024 15:21:48 +0300 Subject: [PATCH 094/289] Updated the test --- internal/handlers/ussd/menuhandler_test.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 38c468c..672a4fa 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -1625,7 +1625,6 @@ func TestValidateRecipient(t *testing.T) { } func TestCheckBalance(t *testing.T) { - sessionId := "session123" publicKey := "0X13242618721" fm, _ := NewFlagManager(flagsPath) @@ -1655,7 +1654,7 @@ func TestCheckBalance(t *testing.T) { }, }, { - name: "Test when checking a balance is a success", + name: "Test when checking a balance is a success", balanceResonse: &models.BalanceResponse{ Ok: true, Result: struct { @@ -1667,7 +1666,7 @@ func TestCheckBalance(t *testing.T) { }, }, expectedResult: resource.Result{ - Content: "0.003 CELO", + Content: "Balance: 0.003 CELO\n", FlagReset: []uint32{flag_api_error}, }, }, @@ -1700,10 +1699,8 @@ func TestCheckBalance(t *testing.T) { //Assert that the result set to content is what was expected assert.Equal(t, res, tt.expectedResult, "Result should contain flags set according to user input") - }) } - } func TestGetProfile(t *testing.T) { From abc01b7cee44a3bf39f2874b9a0f787b663c8de1 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 24 Oct 2024 16:21:34 +0300 Subject: [PATCH 095/289] change to local setup endpoint --- config/config.go | 2 +- internal/handlers/server/accountservice.go | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/config/config.go b/config/config.go index 43466c3..0ba88a4 100644 --- a/config/config.go +++ b/config/config.go @@ -11,7 +11,7 @@ var ( // LoadConfig initializes the configuration values after environment variables are loaded. func LoadConfig() { - CreateAccountURL = initializers.GetEnv("CREATE_ACCOUNT_URL", "http://localhost:5003/api/v2/account/create") + CreateAccountURL = initializers.GetEnv("CREATE_ACCOUNT_URL", "http://localhost:5003/api/v2/account/creates") TrackStatusURL = initializers.GetEnv("TRACK_STATUS_URL", "https://custodial.sarafu.africa/api/track/") BalanceURL = initializers.GetEnv("BALANCE_URL", "https://custodial.sarafu.africa/api/account/status/") TrackURL = initializers.GetEnv("TRACK_URL", "http://localhost:5003/api/v2/account/status") diff --git a/internal/handlers/server/accountservice.go b/internal/handlers/server/accountservice.go index 6ae9630..9534520 100644 --- a/internal/handlers/server/accountservice.go +++ b/internal/handlers/server/accountservice.go @@ -14,9 +14,8 @@ import ( ) var ( - okResponse api.OKResponse - errResponse api.ErrResponse - EMPTY_RESPONSE = 0 + okResponse api.OKResponse + errResponse api.ErrResponse ) type AccountServiceInterface interface { @@ -93,7 +92,7 @@ func (as *AccountService) TrackAccountStatus(publicKey string) (*api.OKResponse, } return nil, errors.New(errResponse.Description) } - if len(okResponse.Result) == EMPTY_RESPONSE { + if len(okResponse.Result) == 0 { return nil, errors.New("Empty api result") } return &okResponse, nil @@ -150,6 +149,7 @@ func (as *AccountService) CreateAccount() (*api.OKResponse, error) { return nil, err } err = json.Unmarshal([]byte(body), &okResponse) + if err != nil { err := json.Unmarshal([]byte(body), &errResponse) if err != nil { @@ -157,7 +157,7 @@ func (as *AccountService) CreateAccount() (*api.OKResponse, error) { } return nil, errors.New(errResponse.Description) } - if len(okResponse.Result) == EMPTY_RESPONSE { + if len(okResponse.Result) == 0 { return nil, errors.New("Empty api result") } return &okResponse, nil From ee9a683eb0f6824e9e342d1f7dd85714a597200d Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 24 Oct 2024 16:30:44 +0300 Subject: [PATCH 096/289] Merge branch 'master' into menu-voucherlist --- internal/handlers/ussd/menuhandler.go | 10 +++----- internal/handlers/ussd/menuhandler_test.go | 27 +++++++--------------- 2 files changed, 11 insertions(+), 26 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index f178231..a9cb5b7 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -849,7 +849,7 @@ func (h *Handlers) GetRecipient(ctx context.Context, sym string, input []byte) ( return res, nil } -// GetSender retrieves the public key from the Gdbm Db +// GetSender returns the sessionId (phoneNumber) func (h *Handlers) GetSender(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result @@ -858,10 +858,7 @@ func (h *Handlers) GetSender(ctx context.Context, sym string, input []byte) (res return res, fmt.Errorf("missing session") } - store := h.userdataStore - publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) - - res.Content = string(publicKey) + res.Content = string(sessionId) return res, nil } @@ -898,13 +895,12 @@ func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input [] // TODO // Use the amount, recipient and sender to call the API and initialize the transaction store := h.userdataStore - publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) amount, _ := store.ReadEntry(ctx, sessionId, utils.DATA_AMOUNT) recipient, _ := store.ReadEntry(ctx, sessionId, utils.DATA_RECIPIENT) - res.Content = l.Get("Your request has been sent. %s will receive %s from %s.", string(recipient), string(amount), string(publicKey)) + res.Content = l.Get("Your request has been sent. %s will receive %s from %s.", string(recipient), string(amount), string(sessionId)) account_authorized_flag, err := h.flagManager.GetFlag("flag_account_authorized") if err != nil { diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index e201531..e86167b 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -478,12 +478,8 @@ func TestGetSender(t *testing.T) { mockStore := new(mocks.MockUserDataStore) // Define test data - sessionId := "session123" + sessionId := "254712345678" 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{ @@ -491,11 +487,10 @@ func TestGetSender(t *testing.T) { } // 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) + res, _ := h.GetSender(ctx, "get_sender", []byte("")) + //Assert that the sessionId is what was set as the result content. + assert.Equal(t, sessionId, res.Content) } func TestGetAmount(t *testing.T) { @@ -1256,7 +1251,7 @@ func TestResetInvalidAmount(t *testing.T) { } func TestInitiateTransaction(t *testing.T) { - sessionId := "session123" + sessionId := "254712345678" fm, err := NewFlagManager(flagsPath) @@ -1279,30 +1274,26 @@ func TestInitiateTransaction(t *testing.T) { tests := []struct { name string input []byte - PublicKey []byte Recipient []byte Amount []byte status string expectedResult resource.Result }{ { - name: "Test amount reset", - PublicKey: []byte("0x1241527192"), - Amount: []byte("0.002CELO"), + name: "Test initiate transaction", + Amount: []byte("0.002 CELO"), Recipient: []byte("0x12415ass27192"), expectedResult: resource.Result{ FlagReset: []uint32{account_authorized_flag}, - Content: "Your request has been sent. 0x12415ass27192 will receive 0.002CELO from 0x1241527192.", + Content: "Your request has been sent. 0x12415ass27192 will receive 0.002 CELO from 254712345678.", }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Define expected interactions with the mock - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return(tt.PublicKey, nil) mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_AMOUNT).Return(tt.Amount, nil) mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_RECIPIENT).Return(tt.Recipient, nil) - //mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_AMOUNT, []byte("")).Return(nil) // Call the method under test res, _ := h.InitiateTransaction(ctx, "transaction_reset_amount", tt.input) @@ -1315,10 +1306,8 @@ func TestInitiateTransaction(t *testing.T) { // Assert that expectations were met mockDataStore.AssertExpectations(t) - }) } - } func TestQuit(t *testing.T) { From 2b34a0900c3640a994a3f75b2927382018b8c932 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 24 Oct 2024 16:35:53 +0300 Subject: [PATCH 097/289] check for status code and unmarshal on errResponse --- internal/handlers/server/accountservice.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/internal/handlers/server/accountservice.go b/internal/handlers/server/accountservice.go index 9534520..27896e7 100644 --- a/internal/handlers/server/accountservice.go +++ b/internal/handlers/server/accountservice.go @@ -84,14 +84,17 @@ func (as *AccountService) TrackAccountStatus(publicKey string) (*api.OKResponse, errResponse.Description = err.Error() return nil, err } - err = json.Unmarshal([]byte(body), &okResponse) - if err != nil { + if resp.StatusCode >= http.StatusBadRequest { err := json.Unmarshal([]byte(body), &errResponse) if err != nil { return nil, err } return nil, errors.New(errResponse.Description) } + err = json.Unmarshal([]byte(body), &okResponse) + if err != nil { + return nil, err + } if len(okResponse.Result) == 0 { return nil, errors.New("Empty api result") } @@ -148,15 +151,17 @@ func (as *AccountService) CreateAccount() (*api.OKResponse, error) { if err != nil { return nil, err } - err = json.Unmarshal([]byte(body), &okResponse) - - if err != nil { + if resp.StatusCode >= http.StatusBadRequest { err := json.Unmarshal([]byte(body), &errResponse) if err != nil { return nil, err } return nil, errors.New(errResponse.Description) } + err = json.Unmarshal([]byte(body), &okResponse) + if err != nil { + return nil, err + } if len(okResponse.Result) == 0 { return nil, errors.New("Empty api result") } From c796bbdcfcc535cd05fc14d552c0d02dea27a996 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 24 Oct 2024 16:36:09 +0300 Subject: [PATCH 098/289] correct create endpoint --- config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 0ba88a4..43466c3 100644 --- a/config/config.go +++ b/config/config.go @@ -11,7 +11,7 @@ var ( // LoadConfig initializes the configuration values after environment variables are loaded. func LoadConfig() { - CreateAccountURL = initializers.GetEnv("CREATE_ACCOUNT_URL", "http://localhost:5003/api/v2/account/creates") + CreateAccountURL = initializers.GetEnv("CREATE_ACCOUNT_URL", "http://localhost:5003/api/v2/account/create") TrackStatusURL = initializers.GetEnv("TRACK_STATUS_URL", "https://custodial.sarafu.africa/api/track/") BalanceURL = initializers.GetEnv("BALANCE_URL", "https://custodial.sarafu.africa/api/account/status/") TrackURL = initializers.GetEnv("TRACK_URL", "http://localhost:5003/api/v2/account/status") From 69a4530269f35d428aff1cd66ea41464ba7b257e Mon Sep 17 00:00:00 2001 From: carlos Date: Thu, 24 Oct 2024 15:41:47 +0200 Subject: [PATCH 099/289] Delete services/registration/locale/swa/default.mo remove dev file --- services/registration/locale/swa/default.mo | Bin 67 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 services/registration/locale/swa/default.mo diff --git a/services/registration/locale/swa/default.mo b/services/registration/locale/swa/default.mo deleted file mode 100644 index e0ceea9b640e4a5c6a1f3b961292aa843b9d620c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67 ycmca7#4?ou2pEA_28dOFm>Gz5fS47CEr6H>i0yzF20&^(Qgd?h89efH5*YxXiUslj From cff50538fa60feddda030b7535a7681cd89b1044 Mon Sep 17 00:00:00 2001 From: carlos Date: Thu, 24 Oct 2024 15:45:29 +0200 Subject: [PATCH 100/289] Delete cover.out delete cover.out --- cover.out | 738 ------------------------------------------------------ 1 file changed, 738 deletions(-) delete mode 100644 cover.out diff --git a/cover.out b/cover.out deleted file mode 100644 index 8f9f054..0000000 --- a/cover.out +++ /dev/null @@ -1,738 +0,0 @@ -mode: set -git.grassecon.net/urdt/ussd/cmd/main.go:22.13,50.16 18 0 -git.grassecon.net/urdt/ussd/cmd/main.go:50.16,53.3 2 0 -git.grassecon.net/urdt/ussd/cmd/main.go:55.2,56.16 2 0 -git.grassecon.net/urdt/ussd/cmd/main.go:56.16,59.3 2 0 -git.grassecon.net/urdt/ussd/cmd/main.go:61.2,62.16 2 0 -git.grassecon.net/urdt/ussd/cmd/main.go:62.16,65.3 2 0 -git.grassecon.net/urdt/ussd/cmd/main.go:67.2,68.16 2 0 -git.grassecon.net/urdt/ussd/cmd/main.go:68.16,71.3 2 0 -git.grassecon.net/urdt/ussd/cmd/main.go:73.2,74.9 2 0 -git.grassecon.net/urdt/ussd/cmd/main.go:74.9,77.3 2 0 -git.grassecon.net/urdt/ussd/cmd/main.go:79.2,83.16 4 0 -git.grassecon.net/urdt/ussd/cmd/main.go:83.16,86.3 2 0 -git.grassecon.net/urdt/ussd/cmd/main.go:88.2,89.16 2 0 -git.grassecon.net/urdt/ussd/cmd/main.go:89.16,92.3 2 0 -git.grassecon.net/urdt/ussd/cmd/main.go:94.2,96.17 3 0 -git.grassecon.net/urdt/ussd/cmd/main.go:96.17,98.3 1 0 -git.grassecon.net/urdt/ussd/cmd/main.go:100.2,101.16 2 0 -git.grassecon.net/urdt/ussd/cmd/main.go:101.16,104.3 2 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:30.66,32.2 1 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:34.62,36.2 1 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:38.13,66.17 20 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:66.17,68.3 1 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:70.2,72.16 3 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:72.16,75.3 2 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:77.2,78.16 2 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:78.16,81.3 2 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:83.2,84.16 2 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:84.16,87.3 2 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:88.2,91.9 3 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:91.9,93.3 1 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:95.2,99.16 4 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:99.16,102.3 2 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:104.2,105.16 2 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:105.16,108.3 2 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:109.2,126.12 10 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:126.12,127.10 1 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:128.19,128.19 0 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:129.20,129.20 0 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:131.3,131.16 1 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:134.2,134.11 1 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:134.11,136.17 2 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:136.17,140.4 3 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:141.3,142.17 2 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:142.17,146.4 3 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:147.3,148.17 2 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:148.17,152.4 3 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:153.3,155.17 3 0 -git.grassecon.net/urdt/ussd/cmd/async/main.go:155.17,159.4 3 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:31.66,33.9 2 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:33.9,35.3 1 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:36.2,36.40 1 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:36.40,38.3 1 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:40.2,41.23 2 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:41.23,43.3 1 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:45.2,45.25 1 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:48.62,50.9 2 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:50.9,52.3 1 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:53.2,53.40 1 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:53.40,55.3 1 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:57.2,60.21 3 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:60.21,62.3 1 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:64.2,64.41 1 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:67.13,93.17 18 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:93.17,95.3 1 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:97.2,99.16 3 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:99.16,102.3 2 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:104.2,105.16 2 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:105.16,108.3 2 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:110.2,111.16 2 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:111.16,114.3 2 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:115.2,118.9 3 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:118.9,120.3 1 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:122.2,125.16 3 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:125.16,128.3 2 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:130.2,131.16 2 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:131.16,134.3 2 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:136.2,137.16 2 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:137.16,140.3 2 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:141.2,156.12 11 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:156.12,157.10 1 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:158.19,158.19 0 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:159.20,159.20 0 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:161.3,161.18 1 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:163.2,164.16 2 0 -git.grassecon.net/urdt/ussd/cmd/africastalking/main.go:164.16,166.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:32.102,34.16 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:34.16,36.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:37.2,40.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:40.16,42.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:44.2,46.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:46.16,48.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:52.2,52.24 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:58.91,61.16 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:61.16,63.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:64.2,67.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:67.16,69.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:71.2,73.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:73.16,75.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:78.2,78.26 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:87.76,89.16 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:89.16,91.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:92.2,95.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:95.16,97.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:99.2,101.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:101.16,103.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:105.2,105.26 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:21.159,29.2 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:31.40,33.16 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:33.16,35.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:38.117,42.2 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:44.81,52.16 6 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:52.16,55.3 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:57.2,60.9 4 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:60.9,63.18 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:63.18,65.4 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:66.3,66.28 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:68.2,69.28 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:69.28,71.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:72.2,75.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:75.16,78.18 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:78.18,80.4 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:81.3,81.18 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:84.2,85.17 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:88.81,92.2 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:94.79,97.2 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:99.55,101.2 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:103.62,105.2 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:16.64,19.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:19.16,21.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:22.2,22.24 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:34.156,36.16 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:36.16,38.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:39.2,44.8 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:47.68,49.2 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:51.56,53.2 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:55.69,57.16 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:57.16,59.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:60.2,98.26 38 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:102.66,106.2 3 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:28.13,54.17 18 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:54.17,56.3 1 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:58.2,60.16 3 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:60.16,63.3 2 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:65.2,66.16 2 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:66.16,69.3 2 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:71.2,72.16 2 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:72.16,75.3 2 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:76.2,79.9 3 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:79.9,81.3 1 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:83.2,86.16 3 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:86.16,89.3 2 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:91.2,92.16 2 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:92.16,95.3 2 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:97.2,98.16 2 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:98.16,101.3 2 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:102.2,117.12 11 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:117.12,118.10 1 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:119.19,119.19 0 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:120.20,120.20 0 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:122.3,122.18 1 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:124.2,125.16 2 0 -git.grassecon.net/urdt/ussd/cmd/http/main.go:125.16,127.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:32.102,34.16 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:34.16,36.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:37.2,40.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:40.16,42.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:44.2,46.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:46.16,48.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:52.2,52.24 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:58.91,61.16 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:61.16,63.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:64.2,67.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:67.16,69.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:71.2,73.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:73.16,75.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:78.2,78.26 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:87.76,89.16 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:89.16,91.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:92.2,95.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:95.16,97.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:99.2,101.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:101.16,103.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:105.2,105.26 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:38.59,41.16 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:41.16,43.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:45.2,47.8 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:51.62,53.2 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:64.84,65.26 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:65.26,67.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:68.2,76.15 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:83.34,86.2 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:88.67,89.17 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:89.17,90.33 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:92.2,93.10 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:96.97,99.17 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:99.17,102.3 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:103.2,105.32 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:105.32,108.3 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:109.2,113.15 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:117.104,123.32 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:123.32,125.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:126.2,130.16 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:130.16,132.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:133.2,135.17 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:138.108,146.31 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:146.31,149.17 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:149.17,151.4 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:153.2,155.12 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:162.106,166.9 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:166.9,168.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:169.2,171.16 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:171.16,172.25 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:172.25,175.18 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:175.18,177.5 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:180.2,180.17 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:184.100,189.9 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:189.9,191.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:193.2,197.29 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:197.29,200.3 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:202.2,205.16 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:205.16,207.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:208.2,208.17 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:211.105,214.9 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:214.9,216.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:217.2,220.26 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:220.26,222.3 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:222.8,224.3 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:226.2,226.17 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:229.109,234.9 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:234.9,236.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:237.2,242.29 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:242.29,245.3 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:246.2,248.16 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:248.16,250.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:251.2,251.17 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:254.109,257.9 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:257.9,259.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:260.2,264.16 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:264.16,266.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:267.2,267.38 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:267.38,269.3 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:269.8,271.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:272.2,273.16 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:273.16,275.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:276.2,276.17 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:282.102,290.9 6 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:290.9,292.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:293.2,295.16 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:295.16,297.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:299.2,299.36 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:299.36,303.3 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:303.8,305.3 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:307.2,307.17 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:311.46,313.34 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:313.34,316.3 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:317.2,317.13 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:321.106,325.9 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:325.9,327.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:328.2,328.20 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:328.20,332.17 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:332.17,334.4 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:337.2,337.17 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:341.107,345.9 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:345.9,347.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:349.2,349.20 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:349.20,353.17 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:353.17,355.4 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:356.8,358.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:360.2,360.17 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:364.100,368.9 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:368.9,370.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:372.2,372.21 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:372.21,376.17 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:376.17,378.4 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:381.2,381.17 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:385.105,389.9 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:389.9,391.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:393.2,393.20 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:393.20,397.17 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:397.17,399.4 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:402.2,402.17 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:406.103,411.9 5 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:411.9,413.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:415.2,418.16 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:418.16,420.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:422.2,422.17 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:426.106,430.9 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:430.9,432.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:434.2,434.20 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:434.20,438.17 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:438.17,440.4 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:443.2,443.17 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:447.109,454.2 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:457.115,464.2 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:467.108,471.9 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:471.9,473.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:475.2,480.17 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:485.102,490.9 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:490.9,492.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:494.2,500.16 6 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:500.16,502.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:503.2,503.21 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:503.21,504.37 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:504.37,505.54 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:505.54,508.5 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:508.10,511.5 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:512.9,516.4 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:517.8,519.3 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:520.2,520.17 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:524.110,529.2 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:533.111,541.9 6 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:541.9,543.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:544.2,546.16 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:546.16,548.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:550.2,551.16 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:551.16,554.3 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:555.2,555.23 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:555.23,558.3 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:559.2,563.16 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:563.16,565.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:566.2,566.58 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:566.58,569.3 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:569.8,572.3 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:573.2,573.17 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:577.97,589.2 8 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:592.105,604.2 8 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:607.102,615.16 6 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:615.16,619.3 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:621.2,621.20 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:621.20,623.3 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:623.8,625.3 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:627.2,627.17 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:631.110,638.2 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:642.105,649.9 5 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:649.9,651.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:653.2,655.16 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:655.16,657.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:659.2,660.16 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:660.16,662.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:663.2,663.25 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:663.25,666.3 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:667.2,671.17 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:674.115,679.9 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:679.9,681.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:682.2,687.16 5 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:687.16,689.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:691.2,692.16 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:692.16,694.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:695.2,695.25 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:695.25,698.3 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:699.2,702.21 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:703.12,704.59 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:705.19,706.69 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:707.10,708.8 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:710.2,710.17 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:714.110,719.9 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:719.9,721.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:723.2,727.22 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:727.22,729.25 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:729.25,734.4 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:735.3,737.17 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:737.17,739.4 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:742.2,742.17 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:747.109,752.9 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:752.9,754.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:756.2,760.16 5 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:760.16,762.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:764.2,765.16 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:765.16,767.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:769.2,771.17 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:775.115,780.9 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:780.9,782.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:784.2,787.16 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:787.16,789.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:791.2,793.17 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:798.102,803.9 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:803.9,805.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:806.2,810.16 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:810.16,812.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:813.2,817.17 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:822.107,827.9 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:827.9,829.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:831.2,841.16 7 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:841.16,843.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:844.2,848.28 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:848.28,850.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:851.2,852.16 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:852.16,854.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:857.2,859.22 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:859.22,863.3 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:865.2,866.16 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:866.16,870.3 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:872.2,872.32 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:872.32,876.3 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:878.2,880.16 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:880.16,882.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:884.2,884.17 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:888.105,892.9 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:892.9,894.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:895.2,900.17 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:904.102,908.9 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:908.9,910.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:912.2,917.17 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:921.102,925.9 3 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:925.9,927.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:928.2,933.17 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:938.108,942.9 4 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:942.9,944.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:946.2,954.16 7 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:954.16,956.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:957.2,958.16 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:958.16,960.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:961.2,963.17 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:968.112,972.9 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:972.9,974.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:976.2,991.16 10 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:991.16,993.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:995.2,996.17 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:999.107,1003.9 4 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1003.9,1005.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1006.2,1007.9 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1007.9,1009.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1010.2,1011.19 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1011.19,1013.3 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1013.8,1015.3 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1018.2,1018.60 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1018.60,1019.33 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1019.33,1021.4 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1022.3,1022.23 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1024.2,1035.32 9 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1035.32,1036.32 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1036.32,1038.4 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1038.9,1040.4 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1044.2,1045.25 2 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1045.25,1046.51 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1046.51,1048.4 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1048.9,1050.4 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1052.2,1052.23 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1053.13,1057.4 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1058.13,1062.4 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1063.10,1067.4 1 1 -git.grassecon.net/urdt/ussd/internal/handlers/ussd/menuhandler.go:1070.2,1070.17 1 1 -git.grassecon.net/urdt/ussd/internal/mocks/dbmock.go:14.42,16.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/dbmock.go:18.33,21.2 2 0 -git.grassecon.net/urdt/ussd/internal/mocks/dbmock.go:23.30,26.2 2 0 -git.grassecon.net/urdt/ussd/internal/mocks/dbmock.go:28.55,30.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/dbmock.go:32.45,35.2 2 0 -git.grassecon.net/urdt/ussd/internal/mocks/dbmock.go:37.75,40.2 2 0 -git.grassecon.net/urdt/ussd/internal/mocks/dbmock.go:42.47,44.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/dbmock.go:46.68,49.2 2 0 -git.grassecon.net/urdt/ussd/internal/mocks/dbmock.go:51.71,54.2 2 0 -git.grassecon.net/urdt/ussd/internal/mocks/dbmock.go:56.32,59.2 2 0 -git.grassecon.net/urdt/ussd/internal/mocks/servicemock.go:13.79,16.2 2 1 -git.grassecon.net/urdt/ussd/internal/mocks/servicemock.go:18.94,21.2 2 1 -git.grassecon.net/urdt/ussd/internal/mocks/servicemock.go:23.105,26.2 2 1 -git.grassecon.net/urdt/ussd/internal/mocks/userdbmock.go:16.113,19.2 2 1 -git.grassecon.net/urdt/ussd/internal/mocks/userdbmock.go:21.118,24.2 2 1 -git.grassecon.net/urdt/ussd/internal/utils/age.go:7.51,13.29 6 0 -git.grassecon.net/urdt/ussd/internal/utils/age.go:13.29,15.3 1 0 -git.grassecon.net/urdt/ussd/internal/utils/age.go:16.2,18.30 3 0 -git.grassecon.net/urdt/ussd/internal/utils/age.go:18.30,20.3 1 0 -git.grassecon.net/urdt/ussd/internal/utils/age.go:21.2,21.12 1 0 -git.grassecon.net/urdt/ussd/internal/utils/age.go:32.39,35.2 2 1 -git.grassecon.net/urdt/ussd/internal/utils/db.go:28.37,32.2 3 0 -git.grassecon.net/urdt/ussd/internal/utils/db.go:34.47,37.2 2 0 -git.grassecon.net/urdt/ussd/internal/utils/isocode.go:9.38,11.2 1 1 -git.grassecon.net/urdt/ussd/internal/utils/userStore.go:20.107,25.2 4 0 -git.grassecon.net/urdt/ussd/internal/utils/userStore.go:27.112,32.2 4 0 -git.grassecon.net/urdt/ussd/internal/mocks/dbmock.go:14.42,16.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/dbmock.go:18.33,21.2 2 0 -git.grassecon.net/urdt/ussd/internal/mocks/dbmock.go:23.30,26.2 2 0 -git.grassecon.net/urdt/ussd/internal/mocks/dbmock.go:28.55,30.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/dbmock.go:32.45,35.2 2 0 -git.grassecon.net/urdt/ussd/internal/mocks/dbmock.go:37.75,40.2 2 0 -git.grassecon.net/urdt/ussd/internal/mocks/dbmock.go:42.47,44.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/dbmock.go:46.68,49.2 2 0 -git.grassecon.net/urdt/ussd/internal/mocks/dbmock.go:51.71,54.2 2 0 -git.grassecon.net/urdt/ussd/internal/mocks/dbmock.go:56.32,59.2 2 0 -git.grassecon.net/urdt/ussd/internal/mocks/servicemock.go:13.79,16.2 2 0 -git.grassecon.net/urdt/ussd/internal/mocks/servicemock.go:18.94,21.2 2 0 -git.grassecon.net/urdt/ussd/internal/mocks/servicemock.go:23.105,26.2 2 0 -git.grassecon.net/urdt/ussd/internal/mocks/userdbmock.go:16.113,19.2 2 0 -git.grassecon.net/urdt/ussd/internal/mocks/userdbmock.go:21.118,24.2 2 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:20.38,21.16 1 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:21.16,23.3 1 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:24.2,24.24 1 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:27.76,30.8 3 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:30.8,33.3 2 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:34.2,36.16 3 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:36.16,38.3 1 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:39.2,42.12 4 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:45.35,46.19 1 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:46.19,48.3 1 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:51.35,52.19 1 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:52.19,54.3 1 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:55.2,56.14 2 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:59.46,62.2 2 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:64.54,67.2 2 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:69.57,72.2 2 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:74.37,79.2 4 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:81.40,86.2 4 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:88.63,93.2 4 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:95.80,100.2 4 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:102.78,107.2 4 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:109.39,115.2 5 0 -git.grassecon.net/urdt/ussd/internal/storage/storage.go:27.86,36.2 3 0 -git.grassecon.net/urdt/ussd/internal/storage/storage.go:38.73,40.2 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storage.go:42.79,44.2 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storage.go:46.47,48.2 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:35.82,40.2 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:42.93,46.16 4 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:46.16,48.3 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:49.2,51.16 3 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:54.81,58.16 4 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:58.16,60.3 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:61.2,61.30 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:64.91,67.16 3 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:67.16,69.3 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:70.2,71.17 2 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:74.81,75.26 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:75.26,76.44 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:78.2,81.16 4 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:81.16,83.3 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:84.2,84.27 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:87.51,89.16 2 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:89.16,91.3 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:92.2,92.12 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:95.45,99.47 4 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:99.47,101.3 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:102.2,102.12 1 0 -git.grassecon.net/urdt/ussd/internal/utils/age.go:7.51,13.29 6 0 -git.grassecon.net/urdt/ussd/internal/utils/age.go:13.29,15.3 1 0 -git.grassecon.net/urdt/ussd/internal/utils/age.go:16.2,18.30 3 0 -git.grassecon.net/urdt/ussd/internal/utils/age.go:18.30,20.3 1 0 -git.grassecon.net/urdt/ussd/internal/utils/age.go:21.2,21.12 1 0 -git.grassecon.net/urdt/ussd/internal/utils/age.go:32.39,35.2 2 0 -git.grassecon.net/urdt/ussd/internal/utils/db.go:28.37,32.2 3 0 -git.grassecon.net/urdt/ussd/internal/utils/db.go:34.47,37.2 2 0 -git.grassecon.net/urdt/ussd/internal/utils/isocode.go:9.38,11.2 1 0 -git.grassecon.net/urdt/ussd/internal/utils/userStore.go:20.107,25.2 4 0 -git.grassecon.net/urdt/ussd/internal/utils/userStore.go:27.112,32.2 4 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:21.159,29.2 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:31.40,33.16 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:33.16,35.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:38.117,42.2 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:44.81,52.16 6 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:52.16,55.3 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:57.2,60.9 4 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:60.9,63.18 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:63.18,65.4 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:66.3,66.28 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:68.2,69.28 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:69.28,71.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:72.2,75.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:75.16,78.18 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:78.18,80.4 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:81.3,81.18 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:84.2,85.17 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:88.81,92.2 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:94.79,97.2 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:99.55,101.2 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/base.go:103.62,105.2 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:16.64,19.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:19.16,21.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:22.2,22.24 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:34.156,36.16 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:36.16,38.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:39.2,44.8 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:47.68,49.2 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:51.56,53.2 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:55.69,57.16 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:57.16,59.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:60.2,98.26 38 0 -git.grassecon.net/urdt/ussd/internal/handlers/handlerservice.go:102.66,106.2 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:32.102,34.16 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:34.16,36.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:37.2,40.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:40.16,42.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:44.2,46.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:46.16,48.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:52.2,52.24 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:58.91,61.16 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:61.16,63.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:64.2,67.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:67.16,69.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:71.2,73.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:73.16,75.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:78.2,78.26 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:87.76,89.16 2 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:89.16,91.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:92.2,95.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:95.16,97.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:99.2,101.16 3 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:101.16,103.3 1 0 -git.grassecon.net/urdt/ussd/internal/handlers/server/accountservice.go:105.2,105.26 1 0 -git.grassecon.net/urdt/ussd/internal/http/at_session_handler.go:14.71,18.2 1 1 -git.grassecon.net/urdt/ussd/internal/http/at_session_handler.go:20.82,32.16 7 1 -git.grassecon.net/urdt/ussd/internal/http/at_session_handler.go:32.16,36.3 3 1 -git.grassecon.net/urdt/ussd/internal/http/at_session_handler.go:37.2,39.16 3 1 -git.grassecon.net/urdt/ussd/internal/http/at_session_handler.go:39.16,43.3 3 1 -git.grassecon.net/urdt/ussd/internal/http/at_session_handler.go:45.2,46.13 2 1 -git.grassecon.net/urdt/ussd/internal/http/at_session_handler.go:47.11,48.13 1 1 -git.grassecon.net/urdt/ussd/internal/http/at_session_handler.go:49.99,50.13 1 1 -git.grassecon.net/urdt/ussd/internal/http/at_session_handler.go:51.10,52.13 1 0 -git.grassecon.net/urdt/ussd/internal/http/at_session_handler.go:55.2,55.17 1 1 -git.grassecon.net/urdt/ussd/internal/http/at_session_handler.go:55.17,58.3 2 1 -git.grassecon.net/urdt/ussd/internal/http/at_session_handler.go:60.2,63.16 4 1 -git.grassecon.net/urdt/ussd/internal/http/at_session_handler.go:63.16,66.3 2 0 -git.grassecon.net/urdt/ussd/internal/http/at_session_handler.go:68.2,69.16 2 1 -git.grassecon.net/urdt/ussd/internal/http/at_session_handler.go:69.16,72.3 2 0 -git.grassecon.net/urdt/ussd/internal/http/at_session_handler.go:75.99,79.18 3 1 -git.grassecon.net/urdt/ussd/internal/http/at_session_handler.go:79.18,81.3 1 1 -git.grassecon.net/urdt/ussd/internal/http/at_session_handler.go:81.8,83.3 1 1 -git.grassecon.net/urdt/ussd/internal/http/at_session_handler.go:85.2,86.16 2 1 -git.grassecon.net/urdt/ussd/internal/http/at_session_handler.go:86.16,88.3 1 0 -git.grassecon.net/urdt/ussd/internal/http/at_session_handler.go:90.2,91.17 2 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:21.69,23.9 2 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:23.9,25.3 1 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:26.2,27.13 2 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:27.13,29.3 1 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:30.2,30.15 1 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:33.65,35.9 2 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:35.9,37.3 1 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:38.2,40.16 3 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:40.16,42.3 1 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:43.2,43.15 1 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:50.66,54.2 1 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:56.80,61.16 5 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:61.16,64.3 2 0 -git.grassecon.net/urdt/ussd/internal/http/server.go:65.2,65.8 1 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:68.77,81.16 8 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:81.16,84.3 2 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:85.2,87.16 3 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:87.16,91.3 3 0 -git.grassecon.net/urdt/ussd/internal/http/server.go:93.2,94.13 2 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:95.27,96.13 1 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:97.30,98.13 1 0 -git.grassecon.net/urdt/ussd/internal/http/server.go:99.30,100.13 1 0 -git.grassecon.net/urdt/ussd/internal/http/server.go:101.10,102.13 1 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:105.2,105.17 1 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:105.17,108.3 2 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:110.2,114.16 5 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:114.16,117.3 2 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:118.2,118.17 1 1 -git.grassecon.net/urdt/ussd/internal/http/server.go:118.17,121.3 2 1 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/enginemock.go:16.62,18.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/enginemock.go:20.76,22.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/enginemock.go:24.75,26.2 1 1 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/enginemock.go:28.37,30.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/requesthandlermock.go:21.100,23.2 1 1 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/requesthandlermock.go:25.56,27.2 1 1 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/requesthandlermock.go:29.118,31.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/requesthandlermock.go:33.98,35.2 1 1 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/requesthandlermock.go:37.97,39.2 1 1 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/requesthandlermock.go:41.41,43.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/requesthandlermock.go:45.72,47.2 1 1 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/requestparsermock.go:9.66,11.2 1 1 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/requestparsermock.go:13.62,15.2 1 1 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/writermock.go:11.57,13.2 1 1 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/writermock.go:15.63,19.2 3 1 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/writermock.go:21.43,23.2 1 1 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/writermock.go:25.51,25.52 0 1 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:20.38,21.16 1 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:21.16,23.3 1 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:24.2,24.24 1 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:27.76,30.8 3 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:30.8,33.3 2 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:34.2,36.16 3 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:36.16,38.3 1 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:39.2,42.12 4 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:45.35,46.19 1 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:46.19,48.3 1 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:51.35,52.19 1 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:52.19,54.3 1 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:55.2,56.14 2 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:59.46,62.2 2 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:64.54,67.2 2 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:69.57,72.2 2 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:74.37,79.2 4 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:81.40,86.2 4 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:88.63,93.2 4 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:95.80,100.2 4 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:102.78,107.2 4 0 -git.grassecon.net/urdt/ussd/internal/storage/gdbm.go:109.39,115.2 5 0 -git.grassecon.net/urdt/ussd/internal/storage/storage.go:27.86,36.2 3 0 -git.grassecon.net/urdt/ussd/internal/storage/storage.go:38.73,40.2 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storage.go:42.79,44.2 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storage.go:46.47,48.2 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:35.82,40.2 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:42.93,46.16 4 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:46.16,48.3 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:49.2,51.16 3 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:54.81,58.16 4 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:58.16,60.3 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:61.2,61.30 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:64.91,67.16 3 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:67.16,69.3 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:70.2,71.17 2 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:74.81,75.26 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:75.26,76.44 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:78.2,81.16 4 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:81.16,83.3 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:84.2,84.27 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:87.51,89.16 2 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:89.16,91.3 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:92.2,92.12 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:95.45,99.47 4 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:99.47,101.3 1 0 -git.grassecon.net/urdt/ussd/internal/storage/storageservice.go:102.2,102.12 1 0 -git.grassecon.net/urdt/ussd/internal/utils/age.go:7.51,13.29 6 0 -git.grassecon.net/urdt/ussd/internal/utils/age.go:13.29,15.3 1 0 -git.grassecon.net/urdt/ussd/internal/utils/age.go:16.2,18.30 3 0 -git.grassecon.net/urdt/ussd/internal/utils/age.go:18.30,20.3 1 0 -git.grassecon.net/urdt/ussd/internal/utils/age.go:21.2,21.12 1 0 -git.grassecon.net/urdt/ussd/internal/utils/age.go:32.39,35.2 2 0 -git.grassecon.net/urdt/ussd/internal/utils/db.go:28.37,32.2 3 0 -git.grassecon.net/urdt/ussd/internal/utils/db.go:34.47,37.2 2 0 -git.grassecon.net/urdt/ussd/internal/utils/isocode.go:9.38,11.2 1 0 -git.grassecon.net/urdt/ussd/internal/utils/userStore.go:20.107,25.2 4 0 -git.grassecon.net/urdt/ussd/internal/utils/userStore.go:27.112,32.2 4 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/enginemock.go:16.62,18.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/enginemock.go:20.76,22.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/enginemock.go:24.75,26.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/enginemock.go:28.37,30.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/requesthandlermock.go:21.100,23.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/requesthandlermock.go:25.56,27.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/requesthandlermock.go:29.118,31.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/requesthandlermock.go:33.98,35.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/requesthandlermock.go:37.97,39.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/requesthandlermock.go:41.41,43.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/requesthandlermock.go:45.72,47.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/requestparsermock.go:9.66,11.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/requestparsermock.go:13.62,15.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/writermock.go:11.57,13.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/writermock.go:15.63,19.2 3 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/writermock.go:21.43,23.2 1 0 -git.grassecon.net/urdt/ussd/internal/mocks/httpmocks/writermock.go:25.51,25.52 0 0 From 5c75e35fe0e8ff81f251df52965af5063090addc Mon Sep 17 00:00:00 2001 From: carlos Date: Thu, 24 Oct 2024 15:45:52 +0200 Subject: [PATCH 101/289] Delete coverage.html delete cover.html --- coverage.html | 2961 ------------------------------------------------- 1 file changed, 2961 deletions(-) delete mode 100644 coverage.html diff --git a/coverage.html b/coverage.html deleted file mode 100644 index a448bc0..0000000 --- a/coverage.html +++ /dev/null @@ -1,2961 +0,0 @@ - - - - - - africastalking: Go Coverage Report - - - -
- -
- not tracked - - not covered - covered - -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - From 383f074cae99a2a72f17a926f3bb3b823055b469 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 24 Oct 2024 17:32:08 +0300 Subject: [PATCH 102/289] update method signatures --- internal/handlers/server/accountservice.go | 28 +++++++--------------- internal/handlers/ussd/menuhandler.go | 10 ++++---- internal/mocks/servicemock.go | 6 ++--- 3 files changed, 17 insertions(+), 27 deletions(-) diff --git a/internal/handlers/server/accountservice.go b/internal/handlers/server/accountservice.go index d449f2f..1b5272a 100644 --- a/internal/handlers/server/accountservice.go +++ b/internal/handlers/server/accountservice.go @@ -20,10 +20,10 @@ var ( ) type AccountServiceInterface interface { - CheckBalance(publicKey string, ctx context.Context) (*models.BalanceResponse, error) + CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResponse, error) CreateAccount(ctx context.Context) (*api.OKResponse, error) - CheckAccountStatus(trackingId string, ctx context.Context) (*models.TrackStatusResponse, error) - TrackAccountStatus(publicKey string) (*api.OKResponse, error) + CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResponse, error) + TrackAccountStatus(ctx context.Context, publicKey string) (*api.OKResponse, error) } type AccountService struct { @@ -41,7 +41,7 @@ type TestAccountService struct { // - 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, ctx context.Context) (*models.TrackStatusResponse, error) { +func (as *AccountService) CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResponse, error) { resp, err := http.Get(config.BalanceURL + trackingId) if err != nil { return nil, err @@ -62,7 +62,7 @@ func (as *AccountService) CheckAccountStatus(trackingId string, ctx context.Cont } -func (as *AccountService) TrackAccountStatus(publicKey string) (*api.OKResponse, error) { +func (as *AccountService) TrackAccountStatus(ctx context.Context, publicKey string) (*api.OKResponse, error) { var err error // Construct the URL with the path parameter url := fmt.Sprintf("%s/%s", config.TrackURL, publicKey) @@ -106,7 +106,7 @@ func (as *AccountService) TrackAccountStatus(publicKey string) (*api.OKResponse, // 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, ctx context.Context) (*models.BalanceResponse, error) { +func (as *AccountService) CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResponse, error) { resp, err := http.Get(config.BalanceURL + publicKey) if err != nil { return nil, err @@ -178,7 +178,7 @@ func (tas *TestAccountService) CreateAccount(ctx context.Context) (*api.OKRespon } -func (tas *TestAccountService) CheckBalance(publicKey string, ctx context.Context) (*models.BalanceResponse, error) { +func (tas *TestAccountService) CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResponse, error) { balanceResponse := &models.BalanceResponse{ Ok: true, Result: struct { @@ -192,7 +192,7 @@ func (tas *TestAccountService) CheckBalance(publicKey string, ctx context.Contex return balanceResponse, nil } -func (tas *TestAccountService) TrackAccountStatus(publicKey string) (*api.OKResponse, error) { +func (tas *TestAccountService) TrackAccountStatus(ctx context.Context, publicKey string) (*api.OKResponse, error) { return &api.OKResponse{ Ok: true, Description: "Account creation succeeded", @@ -202,17 +202,7 @@ func (tas *TestAccountService) TrackAccountStatus(publicKey string) (*api.OKResp }, nil } -func (tas *TestAccountService) TrackAccountStatus(publicKey ,) (*api.OKResponse, error) { - return &api.OKResponse{ - Ok: true, - Description: "Account creation succeeded", - Result: map[string]any{ - "active": true, - }, - }, nil -} - -func (tas *TestAccountService) CheckAccountStatus(trackingId string, ctx context.Context) (*models.TrackStatusResponse, error) { +func (tas *TestAccountService) CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResponse, error) { trackResponse := &models.TrackStatusResponse{ Ok: true, Result: struct { diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 4c03d7b..cb9f8fd 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -544,7 +544,7 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b if err != nil { return res, err } - okResponse, err = h.accountService.TrackAccountStatus(string(publicKey),ctx) + okResponse, err = h.accountService.TrackAccountStatus(ctx, string(publicKey)) if err != nil { res.FlagSet = append(res.FlagSet, flag_api_error) return res, err @@ -651,7 +651,7 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) ( return res, err } - balanceResponse, err := h.accountService.CheckBalance(string(publicKey),ctx) + balanceResponse, err := h.accountService.CheckBalance(ctx, string(publicKey)) if err != nil { return res, nil } @@ -684,7 +684,7 @@ func (h *Handlers) FetchCustodialBalances(ctx context.Context, sym string, input return res, err } - balanceResponse, err := h.accountService.CheckBalance(string(publicKey),ctx) + balanceResponse, err := h.accountService.CheckBalance(ctx, string(publicKey)) if err != nil { return res, nil } @@ -802,7 +802,7 @@ func (h *Handlers) MaxAmount(ctx context.Context, sym string, input []byte) (res store := h.userdataStore publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) - balanceResp, err := h.accountService.CheckBalance(string(publicKey),ctx) + balanceResp, err := h.accountService.CheckBalance(ctx, string(publicKey)) if err != nil { return res, nil } @@ -832,7 +832,7 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte) amountStr := string(input) - balanceRes, err := h.accountService.CheckBalance(string(publicKey),ctx) + balanceRes, err := h.accountService.CheckBalance(ctx, string(publicKey)) balanceStr := balanceRes.Result.Balance if !balanceRes.Ok { diff --git a/internal/mocks/servicemock.go b/internal/mocks/servicemock.go index b7d44e7..9aab44d 100644 --- a/internal/mocks/servicemock.go +++ b/internal/mocks/servicemock.go @@ -18,17 +18,17 @@ func (m *MockAccountService) CreateAccount(ctx context.Context) (*api.OKResponse return args.Get(0).(*api.OKResponse), args.Error(1) } -func (m *MockAccountService) CheckBalance(publicKey string,ctx context.Context) (*models.BalanceResponse, error) { +func (m *MockAccountService) CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResponse, error) { args := m.Called(publicKey) return args.Get(0).(*models.BalanceResponse), args.Error(1) } -func (m *MockAccountService) CheckAccountStatus(trackingId string,ctx context.Context) (*models.TrackStatusResponse, error) { +func (m *MockAccountService) CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResponse, error) { args := m.Called(trackingId) return args.Get(0).(*models.TrackStatusResponse), args.Error(1) } -func (m *MockAccountService) TrackAccountStatus(publicKey string) (*api.OKResponse, error) { +func (m *MockAccountService) TrackAccountStatus(ctx context.Context,publicKey string) (*api.OKResponse, error) { args := m.Called(publicKey) return args.Get(0).(*api.OKResponse), args.Error(1) } From 6e7b46666e13525065d7005b9918bb3eb2eb0e03 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 24 Oct 2024 17:34:42 +0300 Subject: [PATCH 103/289] ensure mod match with master --- go.mod | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 76aaf74..7112503 100644 --- a/go.mod +++ b/go.mod @@ -12,13 +12,7 @@ require ( ) -require ( - github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect - github.com/jackc/pgx/v5 v5.7.0 // indirect - github.com/jackc/puddle/v2 v2.2.1 // indirect - github.com/joho/godotenv v1.5.1 - github.com/kr/text v0.2.0 +require github.com/joho/godotenv v1.5.1 require ( github.com/grassrootseconomics/eth-custodial v1.3.0-beta @@ -32,11 +26,6 @@ require ( golang.org/x/sync v0.8.0 // indirect golang.org/x/text v0.18.0 // indirect ) - github.com/rogpeppe/go-internal v1.13.1 // indirect - golang.org/x/crypto v0.27.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/text v0.18.0 // indirect -) require ( github.com/alecthomas/participle/v2 v2.0.0 // indirect @@ -55,3 +44,5 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) + + From 728815f0c6780022524d17e0c0f6a916f394cd58 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 24 Oct 2024 17:50:37 +0300 Subject: [PATCH 104/289] Include the active symbol in the send menu --- internal/handlers/handlerservice.go | 1 + internal/handlers/ussd/menuhandler.go | 41 +++++++++++++++++++-- services/registration/amount | 2 +- services/registration/amount.vis | 7 ++-- services/registration/amount_swa | 2 +- services/registration/locale/swa/default.po | 4 +- 6 files changed, 46 insertions(+), 11 deletions(-) diff --git a/internal/handlers/handlerservice.go b/internal/handlers/handlerservice.go index d14f7a7..311e694 100644 --- a/internal/handlers/handlerservice.go +++ b/internal/handlers/handlerservice.go @@ -70,6 +70,7 @@ func (ls *LocalHandlerService) GetHandler(accountService server.AccountServiceIn ls.DbRs.AddLocalFunc("check_balance", ussdHandlers.CheckBalance) ls.DbRs.AddLocalFunc("validate_recipient", ussdHandlers.ValidateRecipient) ls.DbRs.AddLocalFunc("transaction_reset", ussdHandlers.TransactionReset) + ls.DbRs.AddLocalFunc("max_amount", ussdHandlers.MaxAmount) ls.DbRs.AddLocalFunc("validate_amount", ussdHandlers.ValidateAmount) ls.DbRs.AddLocalFunc("reset_transaction_amount", ussdHandlers.ResetTransactionAmount) ls.DbRs.AddLocalFunc("get_recipient", ussdHandlers.GetRecipient) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index a9cb5b7..56080bb 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -785,6 +785,28 @@ func (h *Handlers) ResetTransactionAmount(ctx context.Context, sym string, input return res, nil } +// MaxAmount gets the current balance from the API and sets it as +// the result content. +func (h *Handlers) MaxAmount(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") + } + store := h.userdataStore + + activeBal, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_BAL) + if err != nil { + return res, err + } + + res.Content = string(activeBal) + + return res, nil +} + // ValidateAmount ensures that the given input is a valid amount and that // it is not more than the current balance. func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) { @@ -824,12 +846,14 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte) return res, nil } - err = store.WriteEntry(ctx, sessionId, utils.DATA_AMOUNT, []byte(amountStr)) + // Format the amount with 2 decimal places before saving + formattedAmount := fmt.Sprintf("%.2f", inputAmount) + err = store.WriteEntry(ctx, sessionId, utils.DATA_AMOUNT, []byte(formattedAmount)) if err != nil { return res, err } - res.Content = fmt.Sprintf("%.3f", inputAmount) + res.Content = fmt.Sprintf("%s", formattedAmount) return res, nil } @@ -872,9 +896,16 @@ func (h *Handlers) GetAmount(ctx context.Context, sym string, input []byte) (res return res, fmt.Errorf("missing session") } store := h.userdataStore + + // retrieve the active symbol + activeSym, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM) + if err != nil { + return res, err + } + amount, _ := store.ReadEntry(ctx, sessionId, utils.DATA_AMOUNT) - res.Content = string(amount) + res.Content = fmt.Sprintf("%s %s", string(amount), string(activeSym)) return res, nil } @@ -900,7 +931,9 @@ func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input [] recipient, _ := store.ReadEntry(ctx, sessionId, utils.DATA_RECIPIENT) - res.Content = l.Get("Your request has been sent. %s will receive %s from %s.", string(recipient), string(amount), string(sessionId)) + activeSym, _ := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM) + + res.Content = l.Get("Your request has been sent. %s will receive %s %s from %s.", string(recipient), string(amount), string(activeSym), string(sessionId)) account_authorized_flag, err := h.flagManager.GetFlag("flag_account_authorized") if err != nil { diff --git a/services/registration/amount b/services/registration/amount index d3e8602..9142aba 100644 --- a/services/registration/amount +++ b/services/registration/amount @@ -1,2 +1,2 @@ -Maximum amount: {{.check_balance}} +Maximum amount: {{.max_amount}} Enter amount: \ No newline at end of file diff --git a/services/registration/amount.vis b/services/registration/amount.vis index 7c2a0a7..82e1fd4 100644 --- a/services/registration/amount.vis +++ b/services/registration/amount.vis @@ -1,6 +1,7 @@ LOAD reset_transaction_amount 0 -LOAD check_balance 48 -MAP check_balance +LOAD max_amount 10 +RELOAD max_amount +MAP max_amount MOUT back 0 HALT LOAD validate_amount 64 @@ -10,5 +11,5 @@ CATCH invalid_amount flag_invalid_amount 1 INCMP _ 0 LOAD get_recipient 12 LOAD get_sender 64 -LOAD get_amount 12 +LOAD get_amount 32 INCMP transaction_pin * diff --git a/services/registration/amount_swa b/services/registration/amount_swa index d071f63..0c8cf01 100644 --- a/services/registration/amount_swa +++ b/services/registration/amount_swa @@ -1,2 +1,2 @@ -Kiwango cha juu: {{.check_balance}} +Kiwango cha juu: {{.max_amount}} Weka kiwango: \ No newline at end of file diff --git a/services/registration/locale/swa/default.po b/services/registration/locale/swa/default.po index 0a3909b..ba9a9bb 100644 --- a/services/registration/locale/swa/default.po +++ b/services/registration/locale/swa/default.po @@ -1,8 +1,8 @@ msgid "Your account balance is %s" msgstr "Salio lako ni %s" -msgid "Your request has been sent. %s will receive %s from %s." -msgstr "Ombi lako limetumwa. %s atapokea %s kutoka kwa %s." +msgid "Your request has been sent. %s will receive %s %s from %s." +msgstr "Ombi lako limetumwa. %s atapokea %s %s kutoka kwa %s." msgid "Thank you for using Sarafu. Goodbye!" msgstr "Asante kwa kutumia huduma ya Sarafu. Kwaheri!" From a92c640cb7ab15c16507d1ff5ae7019cc8a7e52d Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 24 Oct 2024 18:15:54 +0300 Subject: [PATCH 105/289] Updated tests --- internal/handlers/ussd/menuhandler_test.go | 53 ++++++++++++---------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index e86167b..97df63e 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -494,26 +494,30 @@ func TestGetSender(t *testing.T) { } func TestGetAmount(t *testing.T) { - mockStore := new(mocks.MockUserDataStore) + mockDataStore := new(mocks.MockUserDataStore) // Define test data sessionId := "session123" ctx := context.WithValue(context.Background(), "SessionId", sessionId) - Amount := "0.03CELO" + amount := "0.03" + activeSym := "SRF" // Set up the expected behavior of the mock - mockStore.On("ReadEntry", ctx, sessionId, utils.DATA_AMOUNT).Return([]byte(Amount), nil) + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM).Return([]byte(activeSym), nil) + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_AMOUNT).Return([]byte(amount), nil) // Create the Handlers instance with the mock store h := &Handlers{ - userdataStore: mockStore, + userdataStore: mockDataStore, } // Call the method - res, _ := h.GetAmount(ctx, "get_amount", []byte("Getting amount...")) + res, _ := h.GetAmount(ctx, "get_amount", []byte("")) + + formattedAmount := fmt.Sprintf("%s %s", amount, activeSym) //Assert that the retrieved amount is what was set as the content - assert.Equal(t, Amount, res.Content) + assert.Equal(t, formattedAmount, res.Content) } @@ -1276,16 +1280,18 @@ func TestInitiateTransaction(t *testing.T) { input []byte Recipient []byte Amount []byte + ActiveSym []byte status string expectedResult resource.Result }{ { name: "Test initiate transaction", - Amount: []byte("0.002 CELO"), + Amount: []byte("0.002"), + ActiveSym: []byte("SRF"), Recipient: []byte("0x12415ass27192"), expectedResult: resource.Result{ FlagReset: []uint32{account_authorized_flag}, - Content: "Your request has been sent. 0x12415ass27192 will receive 0.002 CELO from 254712345678.", + Content: "Your request has been sent. 0x12415ass27192 will receive 0.002 SRF from 254712345678.", }, }, } @@ -1294,6 +1300,7 @@ func TestInitiateTransaction(t *testing.T) { // Define expected interactions with the mock mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_AMOUNT).Return(tt.Amount, nil) mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_RECIPIENT).Return(tt.Recipient, nil) + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM).Return(tt.ActiveSym, nil) // Call the method under test res, _ := h.InitiateTransaction(ctx, "transaction_reset_amount", tt.input) @@ -1444,28 +1451,28 @@ func TestValidateAmount(t *testing.T) { }{ { name: "Test with valid amount", - input: []byte("0.001"), - activeBal: []byte("0.003"), + input: []byte("4.10"), + activeBal: []byte("5"), expectedResult: resource.Result{ - Content: "0.001", + Content: "4.10", }, }, { name: "Test with amount larger than active balance", - input: []byte("0.02"), - activeBal: []byte("0.003"), + input: []byte("5.02"), + activeBal: []byte("5"), expectedResult: resource.Result{ - FlagSet: []uint32{flag_invalid_amount}, - Content: "0.02", + FlagSet: []uint32{flag_invalid_amount}, + Content: "5.02", }, }, { - name: "Test with invalid amount format", - input: []byte("0.02ms"), - balance: "0.003 CELO", + name: "Test with invalid amount format", + input: []byte("0.02ms"), + activeBal: []byte("5"), expectedResult: resource.Result{ - FlagSet: []uint32{flag_invalid_amount}, - Content: "0.02ms", + FlagSet: []uint32{flag_invalid_amount}, + Content: "0.02ms", }, }, } @@ -1567,7 +1574,7 @@ func TestCheckBalance(t *testing.T) { publicKey: "0X98765432109", activeSym: "ETH", activeBal: "1.5", - expectedResult: resource.Result{Content: "1.5 ETH"}, + expectedResult: resource.Result{Content: "Balance: 1.5 ETH\n"}, expectError: false, }, } @@ -1582,11 +1589,11 @@ func TestCheckBalance(t *testing.T) { userdataStore: mockDataStore, accountService: mockAccountService, } - + // Mock for user with active sym mockDataStore.On("ReadEntry", ctx, tt.sessionId, utils.DATA_ACTIVE_SYM).Return([]byte(tt.activeSym), nil) mockDataStore.On("ReadEntry", ctx, tt.sessionId, utils.DATA_ACTIVE_BAL).Return([]byte(tt.activeBal), nil) - + res, err := h.CheckBalance(ctx, "check_balance", []byte("")) if tt.expectError { From d113ea82fdd41b844bcef380b0288946ac3679be Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 24 Oct 2024 20:21:28 +0300 Subject: [PATCH 106/289] Add dynamic send_amount and session_id --- menutraversal_test/menu_traversal_test.go | 22 +++++++++++++++++----- menutraversal_test/test_setup.json | 8 ++++---- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/menutraversal_test/menu_traversal_test.go b/menutraversal_test/menu_traversal_test.go index 2b2a093..900ebcc 100644 --- a/menutraversal_test/menu_traversal_test.go +++ b/menutraversal_test/menu_traversal_test.go @@ -56,11 +56,22 @@ func extractBalance(response []byte) string { // Extracts the Maximum amount value from the engine response. func extractMaxAmount(response []byte) string { - // Regex to match "Maximum amount: " followed by a newline - re := regexp.MustCompile(`(?m)^Maximum amount:\s+(\d+(\.\d+)?)\s+([A-Z]+)`) + // Regex to match "Maximum amount: " followed by a newline + re := regexp.MustCompile(`(?m)^Maximum amount:\s+(\d+(\.\d+)?)`) match := re.FindSubmatch(response) if match != nil { - return string(match[1]) + " " + string(match[3]) // " " + return string(match[1]) // "" + } + return "" +} + +// Extracts the send amount value from the engine response. +func extractSendAmount(response []byte) string { + // Regex to match the pattern "will receive X.XX SYM from" + re := regexp.MustCompile(`will receive (\d+\.\d{2}\s+[A-Z]+) from`) + match := re.FindSubmatch(response) + if match != nil { + return string(match[1]) // Returns "X.XX SYM" } return "" } @@ -304,12 +315,13 @@ func TestMainMenuSend(t *testing.T) { b := w.Bytes() balance := extractBalance(b) max_amount := extractMaxAmount(b) - publicKey := extractPublicKey(b) + send_amount := extractSendAmount(b) expectedContent := []byte(step.ExpectedContent) expectedContent = bytes.Replace(expectedContent, []byte("{balance}"), []byte(balance), -1) expectedContent = bytes.Replace(expectedContent, []byte("{max_amount}"), []byte(max_amount), -1) - expectedContent = bytes.Replace(expectedContent, []byte("{public_key}"), []byte(publicKey), -1) + expectedContent = bytes.Replace(expectedContent, []byte("{send_amount}"), []byte(send_amount), -1) + expectedContent = bytes.Replace(expectedContent, []byte("{session_id}"), []byte(sessionID), -1) step.ExpectedContent = string(expectedContent) match, err := step.MatchesExpectedContent(b) diff --git a/menutraversal_test/test_setup.json b/menutraversal_test/test_setup.json index 736d4de..13166a4 100644 --- a/menutraversal_test/test_setup.json +++ b/menutraversal_test/test_setup.json @@ -84,8 +84,8 @@ "expectedContent": "{max_amount}\nEnter amount:\n0:Back" }, { - "input": "0.001", - "expectedContent": "065656 will receive 0.001 from {public_key}\nPlease enter your PIN to confirm:\n0:Back\n9:Quit" + "input": "1.00", + "expectedContent": "065656 will receive {send_amount} from {session_id}\nPlease enter your PIN to confirm:\n0:Back\n9:Quit" }, { "input": "1222", @@ -93,11 +93,11 @@ }, { "input": "1", - "expectedContent": "065656 will receive 0.001 from {public_key}\nPlease enter your PIN to confirm:\n0:Back\n9:Quit" + "expectedContent": "065656 will receive {send_amount} from {session_id}\nPlease enter your PIN to confirm:\n0:Back\n9:Quit" }, { "input": "1234", - "expectedContent": "Your request has been sent. 065656 will receive 0.001 from {public_key}." + "expectedContent": "Your request has been sent. 065656 will receive {send_amount} from {session_id}." } ] }, From b4454f7517070d1f1f3a121e5b8769df5243e974 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 24 Oct 2024 20:44:29 +0300 Subject: [PATCH 107/289] Added context to FetchVouchers --- internal/handlers/server/accountservice.go | 6 +++--- internal/handlers/ussd/menuhandler.go | 4 ++-- internal/mocks/servicemock.go | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/handlers/server/accountservice.go b/internal/handlers/server/accountservice.go index 58774ce..3e2f91d 100644 --- a/internal/handlers/server/accountservice.go +++ b/internal/handlers/server/accountservice.go @@ -25,7 +25,7 @@ type AccountServiceInterface interface { CreateAccount(ctx context.Context) (*api.OKResponse, error) CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResponse, error) TrackAccountStatus(ctx context.Context, publicKey string) (*api.OKResponse, error) - FetchVouchers(publicKey string) (*models.VoucherHoldingResponse, error) + FetchVouchers(ctx context.Context, publicKey string) (*models.VoucherHoldingResponse, error) } type AccountService struct { @@ -174,7 +174,7 @@ func (as *AccountService) CreateAccount(ctx context.Context) (*api.OKResponse, e // FetchVouchers retrieves the token holdings for a given public key from the custodial holdings API endpoint // Parameters: // - publicKey: The public key associated with the account. -func (as *AccountService) FetchVouchers(publicKey string) (*models.VoucherHoldingResponse, error) { +func (as *AccountService) FetchVouchers(ctx context.Context, publicKey string) (*models.VoucherHoldingResponse, error) { file, err := os.Open("sample_tokens.json") if err != nil { return nil, err @@ -245,7 +245,7 @@ func (tas *TestAccountService) CheckAccountStatus(ctx context.Context, trackingI return trackResponse, nil } -func (tas *TestAccountService) FetchVouchers(publicKey string) (*models.VoucherHoldingResponse, error) { +func (tas *TestAccountService) FetchVouchers(ctx context.Context, publicKey string) (*models.VoucherHoldingResponse, error) { return &models.VoucherHoldingResponse{ Ok: true, Result: struct { diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index ec0a5b3..f4d279b 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -1035,7 +1035,7 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by } // Fetch vouchers from the API using the public key - vouchersResp, err := h.accountService.FetchVouchers(string(publicKey)) + vouchersResp, err := h.accountService.FetchVouchers(ctx, string(publicKey)) if err != nil { return res, nil } @@ -1089,7 +1089,7 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) } // Fetch vouchers from the API using the public key - vouchersResp, err := h.accountService.FetchVouchers(string(publicKey)) + vouchersResp, err := h.accountService.FetchVouchers(ctx, string(publicKey)) if err != nil { return res, nil } diff --git a/internal/mocks/servicemock.go b/internal/mocks/servicemock.go index 6a217ce..de0e99a 100644 --- a/internal/mocks/servicemock.go +++ b/internal/mocks/servicemock.go @@ -34,7 +34,7 @@ func (m *MockAccountService) TrackAccountStatus(ctx context.Context,publicKey st } -func (m *MockAccountService) FetchVouchers(publicKey string) (*models.VoucherHoldingResponse, error) { +func (m *MockAccountService) FetchVouchers(ctx context.Context, publicKey string) (*models.VoucherHoldingResponse, error) { args := m.Called(publicKey) return args.Get(0).(*models.VoucherHoldingResponse), args.Error(1) } From a3be98c5144f46171a970a044ceff0114d8a9337 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Fri, 25 Oct 2024 09:36:43 +0300 Subject: [PATCH 108/289] update test account service --- .../testservice/TestAccountService.go | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/internal/testutil/testservice/TestAccountService.go b/internal/testutil/testservice/TestAccountService.go index 40c3886..81f66ef 100644 --- a/internal/testutil/testservice/TestAccountService.go +++ b/internal/testutil/testservice/TestAccountService.go @@ -1,31 +1,29 @@ package testservice import ( + "context" "encoding/json" "time" "git.grassecon.net/urdt/ussd/internal/models" + "github.com/grassrootseconomics/eth-custodial/pkg/api" ) type TestAccountService struct { } -func (tas *TestAccountService) CreateAccount() (*models.AccountResponse, error) { - return &models.AccountResponse{ - Ok: true, - Result: struct { - CustodialId json.Number `json:"custodialId"` - PublicKey string `json:"publicKey"` - TrackingId string `json:"trackingId"` - }{ - CustodialId: json.Number("182"), - PublicKey: "0x48ADca309b5085852207FAaf2816eD72B52F527C", - TrackingId: "28ebe84d-b925-472c-87ae-bbdfa1fb97be", +func (tas *TestAccountService) CreateAccount(ctx context.Context) (*api.OKResponse, error) { + return &api.OKResponse{ + Ok: true, + Description: "Account creation succeeded", + Result: map[string]any{ + "trackingId": "075ccc86-f6ef-4d33-97d5-e91cfb37aa0d", + "publicKey": "0x623EFAFa8868df4B934dd12a8B26CB3Dd75A7AdD", }, }, nil } -func (tas *TestAccountService) CheckBalance(publicKey string) (*models.BalanceResponse, error) { +func (tas *TestAccountService) CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResponse, error) { balanceResponse := &models.BalanceResponse{ Ok: true, Result: struct { @@ -40,7 +38,7 @@ func (tas *TestAccountService) CheckBalance(publicKey string) (*models.BalanceRe return balanceResponse, nil } -func (tas *TestAccountService) CheckAccountStatus(trackingId string) (*models.TrackStatusResponse, error) { +func (tas *TestAccountService) CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResponse, error) { trackResponse := &models.TrackStatusResponse{ Ok: true, Result: struct { @@ -63,3 +61,13 @@ func (tas *TestAccountService) CheckAccountStatus(trackingId string) (*models.Tr } return trackResponse, nil } + +func (tas *TestAccountService) TrackAccountStatus(ctx context.Context, publicKey string) (*api.OKResponse, error) { + return &api.OKResponse{ + Ok: true, + Description: "Account creation succeeded", + Result: map[string]any{ + "active": true, + }, + }, nil +} From a0e97cfe5b07638d37fdb57a03333001ee81f4da Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Fri, 25 Oct 2024 09:37:16 +0300 Subject: [PATCH 109/289] remove test account service implementation --- internal/handlers/server/accountservice.go | 60 ---------------------- 1 file changed, 60 deletions(-) diff --git a/internal/handlers/server/accountservice.go b/internal/handlers/server/accountservice.go index a861e71..93e57a3 100644 --- a/internal/handlers/server/accountservice.go +++ b/internal/handlers/server/accountservice.go @@ -28,9 +28,6 @@ type AccountServiceInterface interface { type AccountService struct { } -type TestAccountService struct { -} - // Parameters: // - trackingId: A unique identifier for the account.This should be obtained from a previous call to // CreateAccount or a similar function that returns an AccountResponse. The `trackingId` field in the @@ -167,60 +164,3 @@ func (as *AccountService) CreateAccount(ctx context.Context) (*api.OKResponse, e } return &okResponse, nil } - -func (tas *TestAccountService) CreateAccount(ctx context.Context) (*api.OKResponse, error) { - return &api.OKResponse{ - Ok: true, - Description: "Account creation request received successfully", - Result: map[string]any{"publicKey": "0x48ADca309b5085852207FAaf2816eD72B52F527C", "trackingId": "28ebe84d-b925-472c-87ae-bbdfa1fb97be"}, - }, nil - -} - -func (tas *TestAccountService) CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResponse, error) { - balanceResponse := &models.BalanceResponse{ - Ok: true, - Result: struct { - Balance string `json:"balance"` - Nonce json.Number `json:"nonce"` - }{ - Balance: "0.003 CELO", - Nonce: json.Number("0"), - }, - } - return balanceResponse, nil -} - -func (tas *TestAccountService) TrackAccountStatus(ctx context.Context, publicKey string) (*api.OKResponse, error) { - return &api.OKResponse{ - Ok: true, - Description: "Account creation succeeded", - Result: map[string]any{ - "active": true, - }, - }, nil -} - -func (tas *TestAccountService) CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResponse, error) { - trackResponse := &models.TrackStatusResponse{ - Ok: true, - Result: struct { - Transaction struct { - CreatedAt time.Time "json:\"createdAt\"" - Status string "json:\"status\"" - TransferValue json.Number "json:\"transferValue\"" - TxHash string "json:\"txHash\"" - TxType string "json:\"txType\"" - } - }{ - Transaction: models.Transaction{ - CreatedAt: time.Now(), - Status: "SUCCESS", - TransferValue: json.Number("0.5"), - TxHash: "0x123abc456def", - TxType: "transfer", - }, - }, - } - return trackResponse, nil -} From 3792bfdc1f0250122d77b13001ef03f84d2cc996 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Fri, 25 Oct 2024 09:38:09 +0300 Subject: [PATCH 110/289] run mod tidy --- go.mod | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 7112503..0b30354 100644 --- a/go.mod +++ b/go.mod @@ -7,19 +7,17 @@ toolchain go1.23.2 require ( git.defalsify.org/vise.git v0.2.1-0.20241017112704-307fa6fcdc6b github.com/alecthomas/assert/v2 v2.2.2 + github.com/grassrootseconomics/eth-custodial v1.3.0-beta github.com/peteole/testdata-loader v0.3.0 gopkg.in/leonelquinteros/gotext.v1 v1.3.1 - ) -require github.com/joho/godotenv v1.5.1 - require ( - github.com/grassrootseconomics/eth-custodial v1.3.0-beta github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgx/v5 v5.7.1 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/joho/godotenv v1.5.1 github.com/kr/text v0.2.0 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect golang.org/x/crypto v0.27.0 // indirect @@ -42,7 +40,4 @@ require ( github.com/stretchr/testify v1.9.0 github.com/x448/float16 v0.8.4 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - ) - - From 3ef64271e7429d00012c579155a20c97784ec38d Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 25 Oct 2024 17:24:09 +0300 Subject: [PATCH 111/289] Store and retrieve the voucher decimals and contract address --- internal/handlers/ussd/menuhandler.go | 284 +++++++++++++++++--------- internal/utils/db.go | 4 + 2 files changed, 187 insertions(+), 101 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index f4d279b..ec33ce6 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -57,6 +57,14 @@ func (fm *FlagManager) GetFlag(label string) (uint32, error) { return fm.parser.GetFlag(label) } +// VoucherMetadata helps organize voucher data fields +type VoucherMetadata struct { + Symbol string + Balance string + Decimal string + Address string +} + type Handlers struct { pe *persist.Persister st *state.State @@ -1094,41 +1102,49 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) return res, nil } - // process voucher data - voucherSymbolList, voucherBalanceList := ProcessVouchers(vouchersResp.Result.Holdings) - prefixdb := storage.NewSubPrefixDb(store, []byte("vouchers")) - err = prefixdb.Put(ctx, []byte("sym"), []byte(voucherSymbolList)) - if err != nil { - return res, nil + data := processVouchers(vouchersResp.Result.Holdings) + + // Store all voucher data + dataMap := map[string]string{ + "sym": data.Symbol, + "bal": data.Balance, + "deci": data.Decimal, + "addr": data.Address, } - err = prefixdb.Put(ctx, []byte("bal"), []byte(voucherBalanceList)) - if err != nil { - return res, nil + for key, value := range dataMap { + if err := prefixdb.Put(ctx, []byte(key), []byte(value)); err != nil { + return res, nil + } } return res, nil } -// ProcessVouchers formats the holdings into symbol and balance lists. -func ProcessVouchers(holdings []struct { +// processVouchers converts holdings into formatted strings +func processVouchers(holdings []struct { ContractAddress string `json:"contractAddress"` TokenSymbol string `json:"tokenSymbol"` TokenDecimals string `json:"tokenDecimals"` Balance string `json:"balance"` -}) (string, string) { - var numberedSymbols, numberedBalances []string +}) VoucherMetadata { + var data VoucherMetadata + var symbols, balances, decimals, addresses []string - for i, voucher := range holdings { - numberedSymbols = append(numberedSymbols, fmt.Sprintf("%d:%s", i+1, voucher.TokenSymbol)) - numberedBalances = append(numberedBalances, fmt.Sprintf("%d:%s", i+1, voucher.Balance)) + for i, h := range holdings { + symbols = append(symbols, fmt.Sprintf("%d:%s", i+1, h.TokenSymbol)) + balances = append(balances, fmt.Sprintf("%d:%s", i+1, h.Balance)) + decimals = append(decimals, fmt.Sprintf("%d:%s", i+1, h.TokenDecimals)) + addresses = append(addresses, fmt.Sprintf("%d:%s", i+1, h.ContractAddress)) } - voucherSymbolList := strings.Join(numberedSymbols, "\n") - voucherBalanceList := strings.Join(numberedBalances, "\n") + data.Symbol = strings.Join(symbols, "\n") + data.Balance = strings.Join(balances, "\n") + data.Decimal = strings.Join(decimals, "\n") + data.Address = strings.Join(addresses, "\n") - return voucherSymbolList, voucherBalanceList + return data } // GetVoucherList fetches the list of vouchers and formats them @@ -1162,7 +1178,6 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r flag_incorrect_voucher, _ := h.flagManager.GetFlag("flag_incorrect_voucher") inputStr := string(input) - if inputStr == "0" || inputStr == "99" { res.FlagReset = append(res.FlagReset, flag_incorrect_voucher) return res, nil @@ -1170,118 +1185,185 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r prefixdb := storage.NewSubPrefixDb(store, []byte("vouchers")) - // Retrieve the voucher symbol list - voucherSymbolList, err := prefixdb.Get(ctx, []byte("sym")) + // Retrieve the voucher metadata + metadata, err := getVoucherData(ctx, prefixdb, inputStr) if err != nil { - return res, fmt.Errorf("failed to retrieve voucher symbol list: %v", err) + return res, fmt.Errorf("failed to retrieve voucher data: %v", err) } - // Retrieve the voucher balance list - voucherBalanceList, err := prefixdb.Get(ctx, []byte("bal")) - if err != nil { - return res, fmt.Errorf("failed to retrieve voucher balance list: %v", err) - } - - // match the voucher symbol and balance with the input - matchedSymbol, matchedBalance := MatchVoucher(inputStr, string(voucherSymbolList), string(voucherBalanceList)) - - // If a match is found, write the temporary sym and balance - if matchedSymbol != "" && matchedBalance != "" { - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_SYM, []byte(matchedSymbol)) - if err != nil { - return res, err - } - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_BAL, []byte(matchedBalance)) - if err != nil { - return res, err - } - - res.FlagReset = append(res.FlagReset, flag_incorrect_voucher) - res.Content = fmt.Sprintf("%s\n%s", matchedSymbol, matchedBalance) - } else { + if metadata == nil { res.FlagSet = append(res.FlagSet, flag_incorrect_voucher) + return res, nil } + if err := h.storeTemporaryVoucher(ctx, sessionId, metadata); err != nil { + return resource.Result{}, err + } + + res.FlagReset = append(res.FlagReset, flag_incorrect_voucher) + res.Content = fmt.Sprintf("%s\n%s", metadata.Symbol, metadata.Balance) + return res, nil } -// MatchVoucher finds the matching voucher symbol and balance based on the input. -func MatchVoucher(inputStr string, voucherSymbols, voucherBalances string) (string, string) { - // Split the lists into slices for processing - symbols := strings.Split(voucherSymbols, "\n") - balances := strings.Split(voucherBalances, "\n") +// getVoucherData retrieves and matches voucher data +func getVoucherData(ctx context.Context, db *storage.SubPrefixDb, input string) (*VoucherMetadata, error) { + keys := []string{"sym", "bal", "deci", "addr"} + data := make(map[string]string) - var matchedSymbol, matchedBalance string + for _, key := range keys { + value, err := db.Get(ctx, []byte(key)) + if err != nil { + return nil, fmt.Errorf("failed to get %s: %v", key, err) + } + data[key] = string(value) + } - for i, symbol := range symbols { - symbolParts := strings.SplitN(symbol, ":", 2) - if len(symbolParts) != 2 { + symbol, balance, decimal, address := matchVoucher(input, + data["sym"], + data["bal"], + data["deci"], + data["addr"]) + + if symbol == "" { + return nil, nil + } + + return &VoucherMetadata{ + Symbol: symbol, + Balance: balance, + Decimal: decimal, + Address: address, + }, nil +} + +// MatchVoucher finds the matching voucher symbol, balance, decimals and contract address based on the input. +func matchVoucher(input, symbols, balances, decimals, addresses string) (symbol, balance, decimal, address string) { + symList := strings.Split(symbols, "\n") + balList := strings.Split(balances, "\n") + decList := strings.Split(decimals, "\n") + addrList := strings.Split(addresses, "\n") + + for i, sym := range symList { + parts := strings.SplitN(sym, ":", 2) + if len(parts) != 2 { continue } - voucherNum := symbolParts[0] - voucherSymbol := symbolParts[1] - // Check if input matches either the number or the symbol - if inputStr == voucherNum || strings.EqualFold(inputStr, voucherSymbol) { - matchedSymbol = voucherSymbol - // Ensure there's a corresponding balance - if i < len(balances) { - matchedBalance = strings.SplitN(balances[i], ":", 2)[1] + if input == parts[0] || strings.EqualFold(input, parts[1]) { + symbol = parts[1] + if i < len(balList) { + balance = strings.SplitN(balList[i], ":", 2)[1] + } + if i < len(decList) { + decimal = strings.SplitN(decList[i], ":", 2)[1] + } + if i < len(addrList) { + address = strings.SplitN(addrList[i], ":", 2)[1] } break } } - - return matchedSymbol, matchedBalance + return +} + +func (h *Handlers) storeTemporaryVoucher(ctx context.Context, sessionId string, data *VoucherMetadata) error { + entries := map[utils.DataTyp][]byte{ + utils.DATA_TEMPORARY_SYM: []byte(data.Symbol), + utils.DATA_TEMPORARY_BAL: []byte(data.Balance), + utils.DATA_TEMPORARY_DECIMAL: []byte(data.Decimal), + utils.DATA_TEMPORARY_ADDRESS: []byte(data.Address), + } + + for key, value := range entries { + if err := h.userdataStore.WriteEntry(ctx, sessionId, key, value); err != nil { + return err + } + } + return nil } -// SetVoucher retrieves the temporary sym and balance, -// sets them as the active data and -// clears the temporary data func (h *Handlers) SetVoucher(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result var err error - store := h.userdataStore - + sessionId, ok := ctx.Value("SessionId").(string) if !ok { return res, fmt.Errorf("missing session") } - // get the current temporary symbol - temporarySym, err := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_SYM) + // Get temporary data + tempData, err := h.getTemporaryVoucherData(ctx, sessionId) if err != nil { - return res, err - } - // get the current temporary balance - temporaryBal, err := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_BAL) - if err != nil { - return res, err + return resource.Result{}, err } - // set the active symbol - err = store.WriteEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM, []byte(temporarySym)) - if err != nil { - return res, err - } - // set the active balance - err = store.WriteEntry(ctx, sessionId, utils.DATA_ACTIVE_BAL, []byte(temporaryBal)) - if err != nil { - return res, err + // Set as active and clear temporary + if err := h.updateVoucherData(ctx, sessionId, tempData); err != nil { + return resource.Result{}, err } - // reset the temporary symbol - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_SYM, []byte("")) - if err != nil { - return res, err - } - // reset the temporary balance - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_BAL, []byte("")) - if err != nil { - return res, err - } - - res.Content = string(temporarySym) - - return res, nil + return resource.Result{Content: tempData.Symbol}, nil +} + +func (h *Handlers) getTemporaryVoucherData(ctx context.Context, sessionId string) (*VoucherMetadata, error) { + store := h.userdataStore + + keys := []utils.DataTyp{ + utils.DATA_TEMPORARY_SYM, + utils.DATA_TEMPORARY_BAL, + utils.DATA_TEMPORARY_DECIMAL, + utils.DATA_TEMPORARY_ADDRESS, + } + + data := &VoucherMetadata{} + values := make([][]byte, len(keys)) + + for i, key := range keys { + value, err := store.ReadEntry(ctx, sessionId, key) + if err != nil { + return nil, err + } + values[i] = value + } + + data.Symbol = string(values[0]) + data.Balance = string(values[1]) + data.Decimal = string(values[2]) + data.Address = string(values[3]) + + return data, nil +} + +func (h *Handlers) updateVoucherData(ctx context.Context, sessionId string, data *VoucherMetadata) error { + // Set active voucher data + activeEntries := map[utils.DataTyp][]byte{ + utils.DATA_ACTIVE_SYM: []byte(data.Symbol), + utils.DATA_ACTIVE_BAL: []byte(data.Balance), + utils.DATA_ACTIVE_DECIMAL: []byte(data.Decimal), + utils.DATA_ACTIVE_ADDRESS: []byte(data.Address), + } + + // Clear temporary voucher data + tempEntries := map[utils.DataTyp][]byte{ + utils.DATA_TEMPORARY_SYM: []byte(""), + utils.DATA_TEMPORARY_BAL: []byte(""), + utils.DATA_TEMPORARY_DECIMAL: []byte(""), + utils.DATA_TEMPORARY_ADDRESS: []byte(""), + } + + // Write all entries + for key, value := range activeEntries { + if err := h.userdataStore.WriteEntry(ctx, sessionId, key, value); err != nil { + return err + } + } + + for key, value := range tempEntries { + if err := h.userdataStore.WriteEntry(ctx, sessionId, key, value); err != nil { + return err + } + } + + return nil } diff --git a/internal/utils/db.go b/internal/utils/db.go index 45e7681..3c2c81e 100644 --- a/internal/utils/db.go +++ b/internal/utils/db.go @@ -28,6 +28,10 @@ const ( DATA_ACTIVE_SYM DATA_TEMPORARY_BAL DATA_ACTIVE_BAL + DATA_TEMPORARY_DECIMAL + DATA_ACTIVE_DECIMAL + DATA_TEMPORARY_ADDRESS + DATA_ACTIVE_ADDRESS ) func typToBytes(typ DataTyp) []byte { From 4e1b2d5ddb13e6cec13bc82515c53df72670c79b Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Fri, 25 Oct 2024 18:01:52 +0300 Subject: [PATCH 112/289] update account services --- internal/handlers/server/accountservice.go | 86 ------------------- .../testservice/TestAccountService.go | 28 ++++++ 2 files changed, 28 insertions(+), 86 deletions(-) diff --git a/internal/handlers/server/accountservice.go b/internal/handlers/server/accountservice.go index 8ef909d..890d1db 100644 --- a/internal/handlers/server/accountservice.go +++ b/internal/handlers/server/accountservice.go @@ -8,7 +8,6 @@ import ( "io" "net/http" "os" - "time" "git.grassecon.net/urdt/ussd/config" "git.grassecon.net/urdt/ussd/internal/models" @@ -184,88 +183,3 @@ func (as *AccountService) FetchVouchers(ctx context.Context, publicKey string) ( } return &holdings, nil } - -func (tas *TestAccountService) CreateAccount(ctx context.Context) (*api.OKResponse, error) { - return &api.OKResponse{ - Ok: true, - Description: "Account creation request received successfully", - Result: map[string]any{"publicKey": "0x48ADca309b5085852207FAaf2816eD72B52F527C", "trackingId": "28ebe84d-b925-472c-87ae-bbdfa1fb97be"}, - }, nil - -} - -func (tas *TestAccountService) CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResponse, error) { - balanceResponse := &models.BalanceResponse{ - Ok: true, - Result: struct { - Balance string `json:"balance"` - Nonce json.Number `json:"nonce"` - }{ - Balance: "0.003 CELO", - Nonce: json.Number("0"), - }, - } - return balanceResponse, nil -} - -func (tas *TestAccountService) TrackAccountStatus(ctx context.Context, publicKey string) (*api.OKResponse, error) { - return &api.OKResponse{ - Ok: true, - Description: "Account creation succeeded", - Result: map[string]any{ - "active": true, - }, - }, nil -} - -func (tas *TestAccountService) CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResponse, error) { - trackResponse := &models.TrackStatusResponse{ - Ok: true, - Result: struct { - Transaction struct { - CreatedAt time.Time "json:\"createdAt\"" - Status string "json:\"status\"" - TransferValue json.Number "json:\"transferValue\"" - TxHash string "json:\"txHash\"" - TxType string "json:\"txType\"" - } - }{ - Transaction: models.Transaction{ - CreatedAt: time.Now(), - Status: "SUCCESS", - TransferValue: json.Number("0.5"), - TxHash: "0x123abc456def", - TxType: "transfer", - }, - }, - } - return trackResponse, nil -} - -func (tas *TestAccountService) FetchVouchers(ctx context.Context, publicKey string) (*models.VoucherHoldingResponse, error) { - return &models.VoucherHoldingResponse{ - Ok: true, - Result: struct { - Holdings []struct { - ContractAddress string `json:"contractAddress"` - TokenSymbol string `json:"tokenSymbol"` - TokenDecimals string `json:"tokenDecimals"` - Balance string `json:"balance"` - } `json:"holdings"` - }{ - Holdings: []struct { - ContractAddress string `json:"contractAddress"` - TokenSymbol string `json:"tokenSymbol"` - TokenDecimals string `json:"tokenDecimals"` - Balance string `json:"balance"` - }{ - { - ContractAddress: "0x6CC75A06ac72eB4Db2eE22F781F5D100d8ec03ee", - TokenSymbol: "SRF", - TokenDecimals: "6", - Balance: "2745987", - }, - }, - }, - }, nil -} diff --git a/internal/testutil/testservice/TestAccountService.go b/internal/testutil/testservice/TestAccountService.go index 81f66ef..6332345 100644 --- a/internal/testutil/testservice/TestAccountService.go +++ b/internal/testutil/testservice/TestAccountService.go @@ -71,3 +71,31 @@ func (tas *TestAccountService) TrackAccountStatus(ctx context.Context, publicKey }, }, nil } + +func (tas *TestAccountService) FetchVouchers(ctx context.Context, publicKey string) (*models.VoucherHoldingResponse, error) { + return &models.VoucherHoldingResponse{ + Ok: true, + Result: struct { + Holdings []struct { + ContractAddress string `json:"contractAddress"` + TokenSymbol string `json:"tokenSymbol"` + TokenDecimals string `json:"tokenDecimals"` + Balance string `json:"balance"` + } `json:"holdings"` + }{ + Holdings: []struct { + ContractAddress string `json:"contractAddress"` + TokenSymbol string `json:"tokenSymbol"` + TokenDecimals string `json:"tokenDecimals"` + Balance string `json:"balance"` + }{ + { + ContractAddress: "0x6CC75A06ac72eB4Db2eE22F781F5D100d8ec03ee", + TokenSymbol: "SRF", + TokenDecimals: "6", + Balance: "2745987", + }, + }, + }, + }, nil +} From ddae746b9d3e0e9b9470040e48d210de0d65ceeb Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Mon, 28 Oct 2024 11:07:59 +0300 Subject: [PATCH 113/289] formatted code --- internal/handlers/ussd/menuhandler.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index ec33ce6..1385261 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -1219,10 +1219,10 @@ func getVoucherData(ctx context.Context, db *storage.SubPrefixDb, input string) data[key] = string(value) } - symbol, balance, decimal, address := matchVoucher(input, - data["sym"], - data["bal"], - data["deci"], + symbol, balance, decimal, address := matchVoucher(input, + data["sym"], + data["bal"], + data["deci"], data["addr"]) if symbol == "" { @@ -1286,7 +1286,7 @@ func (h *Handlers) storeTemporaryVoucher(ctx context.Context, sessionId string, func (h *Handlers) SetVoucher(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") @@ -1308,7 +1308,7 @@ func (h *Handlers) SetVoucher(ctx context.Context, sym string, input []byte) (re func (h *Handlers) getTemporaryVoucherData(ctx context.Context, sessionId string) (*VoucherMetadata, error) { store := h.userdataStore - + keys := []utils.DataTyp{ utils.DATA_TEMPORARY_SYM, utils.DATA_TEMPORARY_BAL, From dc782d87a8a0cf3e324fc9f3ce7b93b01a420803 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Mon, 28 Oct 2024 11:20:06 +0300 Subject: [PATCH 114/289] Updated the TestSetVoucher --- internal/handlers/ussd/menuhandler.go | 9 +++--- internal/handlers/ussd/menuhandler_test.go | 37 +++++++++++++++++++--- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 1385261..f04b3f8 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -1197,7 +1197,7 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r } if err := h.storeTemporaryVoucher(ctx, sessionId, metadata); err != nil { - return resource.Result{}, err + return res, err } res.FlagReset = append(res.FlagReset, flag_incorrect_voucher) @@ -1295,15 +1295,16 @@ func (h *Handlers) SetVoucher(ctx context.Context, sym string, input []byte) (re // Get temporary data tempData, err := h.getTemporaryVoucherData(ctx, sessionId) if err != nil { - return resource.Result{}, err + return res, err } // Set as active and clear temporary if err := h.updateVoucherData(ctx, sessionId, tempData); err != nil { - return resource.Result{}, err + return res, err } - return resource.Result{Content: tempData.Symbol}, nil + res.Content = tempData.Symbol + return res, nil } func (h *Handlers) getTemporaryVoucherData(ctx context.Context, sessionId string) (*VoucherMetadata, error) { diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 9bcee63..b53a289 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -1816,16 +1816,43 @@ func TestSetVoucher(t *testing.T) { sessionId := "session123" ctx := context.WithValue(context.Background(), "SessionId", sessionId) + // Define the temporary voucher data temporarySym := []byte("tempSym") temporaryBal := []byte("tempBal") + temporaryDecimal := []byte("2") + temporaryAddress := []byte("0x123456") - // Set expectations for the mock data store + // Define the expected active entries + activeEntries := map[utils.DataTyp][]byte{ + utils.DATA_ACTIVE_SYM: temporarySym, + utils.DATA_ACTIVE_BAL: temporaryBal, + utils.DATA_ACTIVE_DECIMAL: temporaryDecimal, + utils.DATA_ACTIVE_ADDRESS: temporaryAddress, + } + + // Define the temporary entries to be cleared + tempEntries := map[utils.DataTyp][]byte{ + utils.DATA_TEMPORARY_SYM: []byte(""), + utils.DATA_TEMPORARY_BAL: []byte(""), + utils.DATA_TEMPORARY_DECIMAL: []byte(""), + utils.DATA_TEMPORARY_ADDRESS: []byte(""), + } + + // Mocking ReadEntry calls for temporary data retrieval mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_SYM).Return(temporarySym, nil) mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_BAL).Return(temporaryBal, nil) - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM, temporarySym).Return(nil) - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_BAL, temporaryBal).Return(nil) - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_SYM, []byte("")).Return(nil) - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_BAL, []byte("")).Return(nil) + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_DECIMAL).Return(temporaryDecimal, nil) + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_ADDRESS).Return(temporaryAddress, nil) + + // Mocking WriteEntry calls for setting active data + for key, value := range activeEntries { + mockDataStore.On("WriteEntry", ctx, sessionId, key, value).Return(nil) + } + + // Mocking WriteEntry calls for clearing temporary data + for key, value := range tempEntries { + mockDataStore.On("WriteEntry", ctx, sessionId, key, value).Return(nil) + } h := &Handlers{ userdataStore: mockDataStore, From 72d5c186dd7a04b738262263ed5c785103f5e88f Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 28 Oct 2024 15:18:40 +0300 Subject: [PATCH 115/289] add admin privilege flag --- services/registration/pp.csv | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/registration/pp.csv b/services/registration/pp.csv index ec0d8c1..cee8d13 100644 --- a/services/registration/pp.csv +++ b/services/registration/pp.csv @@ -17,3 +17,5 @@ flag,flag_incorrect_date_format,23,this is set when the given year of birth is i flag,flag_incorrect_voucher,24,this is set when the selected voucher is invalid flag,flag_api_call_error,25,this is set when communication to an external service fails flag,flag_no_active_voucher,26,this is set when a user does not have an active voucher +flag,flag_admin_privilege,27,this is set when a user has admin privileges. + From 0cc0bdf9f71836301879eb068f22c96382f0bf96 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 28 Oct 2024 15:19:35 +0300 Subject: [PATCH 116/289] add pin reset for others nodes --- services/registration/enter_others_new_pin | 1 + services/registration/enter_others_new_pin.vis | 8 ++++++++ services/registration/invalid_others_pin | 1 + services/registration/invalid_others_pin.vis | 5 +++++ services/registration/no_admin_privilege | 1 + services/registration/no_admin_privilege.vis | 5 +++++ services/registration/others_pin_mismatch | 1 + services/registration/others_pin_mismatch.vis | 5 +++++ services/registration/pin_management.vis | 3 +-- services/registration/pin_reset_result | 1 + services/registration/pin_reset_result.vis | 7 +++++++ 11 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 services/registration/enter_others_new_pin create mode 100644 services/registration/enter_others_new_pin.vis create mode 100644 services/registration/invalid_others_pin create mode 100644 services/registration/invalid_others_pin.vis create mode 100644 services/registration/no_admin_privilege create mode 100644 services/registration/no_admin_privilege.vis create mode 100644 services/registration/others_pin_mismatch create mode 100644 services/registration/others_pin_mismatch.vis create mode 100644 services/registration/pin_reset_result create mode 100644 services/registration/pin_reset_result.vis diff --git a/services/registration/enter_others_new_pin b/services/registration/enter_others_new_pin new file mode 100644 index 0000000..52ae664 --- /dev/null +++ b/services/registration/enter_others_new_pin @@ -0,0 +1 @@ +Please enter new PIN for: {{.retrieve_blocked_number}} \ No newline at end of file diff --git a/services/registration/enter_others_new_pin.vis b/services/registration/enter_others_new_pin.vis new file mode 100644 index 0000000..aa2818d --- /dev/null +++ b/services/registration/enter_others_new_pin.vis @@ -0,0 +1,8 @@ +LOAD retrieve_blocked_number 0 +MAP retrieve_blocked_number +MOUT back 0 +HALT +INCMP _ 0 +LOAD verify_new_pin 0 +RELOAD verify_new_pin +INCMP * confirm_others_new_pin diff --git a/services/registration/invalid_others_pin b/services/registration/invalid_others_pin new file mode 100644 index 0000000..acdf45f --- /dev/null +++ b/services/registration/invalid_others_pin @@ -0,0 +1 @@ +The PIN you have entered is invalid.Please try a 4 digit number instead. \ No newline at end of file diff --git a/services/registration/invalid_others_pin.vis b/services/registration/invalid_others_pin.vis new file mode 100644 index 0000000..d218e6d --- /dev/null +++ b/services/registration/invalid_others_pin.vis @@ -0,0 +1,5 @@ +MOUT retry 1 +MOUT quit 9 +HALT +INCMP enter_others_new_pin 1 +INCMP quit 9 diff --git a/services/registration/no_admin_privilege b/services/registration/no_admin_privilege new file mode 100644 index 0000000..27901dc --- /dev/null +++ b/services/registration/no_admin_privilege @@ -0,0 +1 @@ +You do not have privileges to perform this action diff --git a/services/registration/no_admin_privilege.vis b/services/registration/no_admin_privilege.vis new file mode 100644 index 0000000..3cf1e4c --- /dev/null +++ b/services/registration/no_admin_privilege.vis @@ -0,0 +1,5 @@ +MOUT quit 9 +MOUT back 0 +HALT +INCMP pin_management 0 +INCMP quit 9 diff --git a/services/registration/others_pin_mismatch b/services/registration/others_pin_mismatch new file mode 100644 index 0000000..deb9fe5 --- /dev/null +++ b/services/registration/others_pin_mismatch @@ -0,0 +1 @@ +The PIN you have entered is not a match diff --git a/services/registration/others_pin_mismatch.vis b/services/registration/others_pin_mismatch.vis new file mode 100644 index 0000000..37b3deb --- /dev/null +++ b/services/registration/others_pin_mismatch.vis @@ -0,0 +1,5 @@ +MOUT retry 1 +MOUT quit 9 +HALT +INCMP _ 1 +INCMP quit 9 diff --git a/services/registration/pin_management.vis b/services/registration/pin_management.vis index 3b33dad..b196a50 100644 --- a/services/registration/pin_management.vis +++ b/services/registration/pin_management.vis @@ -1,8 +1,7 @@ MOUT change_pin 1 MOUT reset_pin 2 -MOUT guard_pin 3 MOUT back 0 HALT INCMP _ 0 INCMP old_pin 1 - +INCMP enter_other_number 2 diff --git a/services/registration/pin_reset_result b/services/registration/pin_reset_result new file mode 100644 index 0000000..60554b9 --- /dev/null +++ b/services/registration/pin_reset_result @@ -0,0 +1 @@ +PIN reset request for {{.retrieve_blocked_number}} was successful \ No newline at end of file diff --git a/services/registration/pin_reset_result.vis b/services/registration/pin_reset_result.vis new file mode 100644 index 0000000..ed71200 --- /dev/null +++ b/services/registration/pin_reset_result.vis @@ -0,0 +1,7 @@ +LOAD retrieve_blocked_number 0 +MAP retrieve_blocked_number +MOUT back 0 +MOUT quit 9 +HALT +INCMP pin_management 0 +INCMP quit 9 From 3de46cef5e2758b228ea49bf597d2627185f3aa1 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 28 Oct 2024 15:45:08 +0300 Subject: [PATCH 117/289] setup pin reset nodes --- services/registration/confirm_others_new_pin | 1 + services/registration/confirm_others_new_pin.vis | 13 +++++++++++++ services/registration/confirm_pin_change.vis | 2 -- services/registration/enter_other_number | 1 + services/registration/enter_other_number.vis | 9 +++++++++ 5 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 services/registration/confirm_others_new_pin create mode 100644 services/registration/confirm_others_new_pin.vis create mode 100644 services/registration/enter_other_number create mode 100644 services/registration/enter_other_number.vis diff --git a/services/registration/confirm_others_new_pin b/services/registration/confirm_others_new_pin new file mode 100644 index 0000000..46c3275 --- /dev/null +++ b/services/registration/confirm_others_new_pin @@ -0,0 +1 @@ +Please confirm new PIN for: {{.retrieve_blocked_number}} \ No newline at end of file diff --git a/services/registration/confirm_others_new_pin.vis b/services/registration/confirm_others_new_pin.vis new file mode 100644 index 0000000..be6734f --- /dev/null +++ b/services/registration/confirm_others_new_pin.vis @@ -0,0 +1,13 @@ +LOAD retrieve_blocked_number 0 +MAP retrieve_blocked_number +CATCH invalid_others_pin flag_valid_pin 0 +LOAD save_temporary_pin 6 +RELOAD save_temporary_pin +CATCH pin_reset_result flag_account_authorized 1 +MOUT back 0 +HALT +INCMP _ 0 +LOAD check_pin_mismatch 0 +RELOAD check_pin_mismatch +CATCH others_pin_mismatch flag_pin_mismatch 1 +INCMP pin_entry * diff --git a/services/registration/confirm_pin_change.vis b/services/registration/confirm_pin_change.vis index 7691e01..cf485a1 100644 --- a/services/registration/confirm_pin_change.vis +++ b/services/registration/confirm_pin_change.vis @@ -3,5 +3,3 @@ MOUT back 0 HALT INCMP _ 0 INCMP * pin_reset_success - - diff --git a/services/registration/enter_other_number b/services/registration/enter_other_number new file mode 100644 index 0000000..1c4a481 --- /dev/null +++ b/services/registration/enter_other_number @@ -0,0 +1 @@ +Enter other's phone number: \ No newline at end of file diff --git a/services/registration/enter_other_number.vis b/services/registration/enter_other_number.vis new file mode 100644 index 0000000..41c711a --- /dev/null +++ b/services/registration/enter_other_number.vis @@ -0,0 +1,9 @@ +CATCH no_admin_privilege flag_admin_privilege 0 +LOAD reset_account_authorized 6 +RELOAD reset_account_authorized +MOUT back 0 +HALT +INCMP _ 0 +LOAD validate_blocked_number 0 +RELOAD validate_blocked_number +INCMP enter_others_new_pin * From e4c2f644f378ffc15429a2614aebdcb12ce142f4 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 28 Oct 2024 15:47:56 +0300 Subject: [PATCH 118/289] define a key to hold number during pin reset --- internal/utils/db.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/utils/db.go b/internal/utils/db.go index 45e7681..57f3289 100644 --- a/internal/utils/db.go +++ b/internal/utils/db.go @@ -28,6 +28,7 @@ const ( DATA_ACTIVE_SYM DATA_TEMPORARY_BAL DATA_ACTIVE_BAL + DATA_BLOCKED_NUMBER ) func typToBytes(typ DataTyp) []byte { From 26073c8000c030cb6d03766bac6dffe851aca88f Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 28 Oct 2024 15:49:20 +0300 Subject: [PATCH 119/289] define handler functions required to reset others pin --- internal/handlers/handlerservice.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/internal/handlers/handlerservice.go b/internal/handlers/handlerservice.go index 311e694..a30f1b2 100644 --- a/internal/handlers/handlerservice.go +++ b/internal/handlers/handlerservice.go @@ -54,7 +54,7 @@ func (ls *LocalHandlerService) SetDataStore(db *db.Db) { } func (ls *LocalHandlerService) GetHandler(accountService server.AccountServiceInterface) (*ussd.Handlers, error) { - ussdHandlers, err := ussd.NewHandlers(ls.Parser, *ls.UserdataStore,accountService) + ussdHandlers, err := ussd.NewHandlers(ls.Parser, *ls.UserdataStore, accountService) if err != nil { return nil, err } @@ -98,6 +98,10 @@ func (ls *LocalHandlerService) GetHandler(accountService server.AccountServiceIn ls.DbRs.AddLocalFunc("get_vouchers", ussdHandlers.GetVoucherList) ls.DbRs.AddLocalFunc("view_voucher", ussdHandlers.ViewVoucher) ls.DbRs.AddLocalFunc("set_voucher", ussdHandlers.SetVoucher) + ls.DbRs.AddLocalFunc("reset_valid_pin", ussdHandlers.ResetValidPin) + ls.DbRs.AddLocalFunc("check_pin_mismatch", ussdHandlers.CheckPinMisMatch) + ls.DbRs.AddLocalFunc("validate_blocked_number", ussdHandlers.ValidateBlockedNumber) + ls.DbRs.AddLocalFunc("retrieve_blocked_number", ussdHandlers.RetrieveBlockedNumber) return ussdHandlers, nil } From 5d294b663cc1fc3621eaba97b9622f41b44021a5 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Mon, 28 Oct 2024 16:21:31 +0300 Subject: [PATCH 120/289] Added the PrefixDb interface --- internal/storage/db.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/internal/storage/db.go b/internal/storage/db.go index 060f0c0..8c9ff35 100644 --- a/internal/storage/db.go +++ b/internal/storage/db.go @@ -10,6 +10,14 @@ const ( DATATYPE_USERSUB = 64 ) +// PrefixDb interface abstracts the database operations. +type PrefixDb interface { + Get(ctx context.Context, key []byte) ([]byte, error) + Put(ctx context.Context, key []byte, val []byte) error +} + +var _ PrefixDb = (*SubPrefixDb)(nil) + type SubPrefixDb struct { store db.Db pfx []byte @@ -29,11 +37,7 @@ func (s *SubPrefixDb) toKey(k []byte) []byte { func (s *SubPrefixDb) Get(ctx context.Context, key []byte) ([]byte, error) { s.store.SetPrefix(DATATYPE_USERSUB) key = s.toKey(key) - v, err := s.store.Get(ctx, key) - if err != nil { - return nil, err - } - return v, nil + return s.store.Get(ctx, key) } func (s *SubPrefixDb) Put(ctx context.Context, key []byte, val []byte) error { From 520f5abdcdba081171b2ed2cdc835a91603c38d3 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Mon, 28 Oct 2024 16:23:44 +0300 Subject: [PATCH 121/289] Added the subPrefixDb mock --- internal/mocks/subprefixdbmock.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 internal/mocks/subprefixdbmock.go diff --git a/internal/mocks/subprefixdbmock.go b/internal/mocks/subprefixdbmock.go new file mode 100644 index 0000000..e98bcb6 --- /dev/null +++ b/internal/mocks/subprefixdbmock.go @@ -0,0 +1,21 @@ +package mocks + +import ( + "context" + + "github.com/stretchr/testify/mock" +) + +type MockSubPrefixDb struct { + mock.Mock +} + +func (m *MockSubPrefixDb) Get(ctx context.Context, key []byte) ([]byte, error) { + args := m.Called(ctx, key) + return args.Get(0).([]byte), args.Error(1) +} + +func (m *MockSubPrefixDb) Put(ctx context.Context, key, val []byte) error { + args := m.Called(ctx, key, val) + return args.Error(0) +} From 131f3bcf46861d5424246b26ddb9f60515eba65a Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Mon, 28 Oct 2024 16:27:24 +0300 Subject: [PATCH 122/289] Added the prefixDb to the Handlers struct~ --- internal/handlers/ussd/menuhandler.go | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index f04b3f8..59377d4 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -72,6 +72,7 @@ type Handlers struct { userdataStore utils.DataStore flagManager *asm.FlagParser accountService server.AccountServiceInterface + prefixDb storage.PrefixDb } func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db, accountService server.AccountServiceInterface) (*Handlers, error) { @@ -81,10 +82,14 @@ func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db, accountService s userDb := &utils.UserDataStore{ Db: userdataStore, } + // Instantiate the SubPrefixDb with "vouchers" prefix + prefixDb := storage.NewSubPrefixDb(userdataStore, []byte("vouchers")) + h := &Handlers{ userdataStore: userDb, flagManager: appFlags, accountService: accountService, + prefixDb: prefixDb, } return h, nil } @@ -1102,7 +1107,6 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) return res, nil } - prefixdb := storage.NewSubPrefixDb(store, []byte("vouchers")) data := processVouchers(vouchersResp.Result.Holdings) // Store all voucher data @@ -1114,7 +1118,7 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) } for key, value := range dataMap { - if err := prefixdb.Put(ctx, []byte(key), []byte(value)); err != nil { + if err := h.prefixDb.Put(ctx, []byte(key), []byte(value)); err != nil { return res, nil } } @@ -1152,12 +1156,9 @@ func (h *Handlers) GetVoucherList(ctx context.Context, sym string, input []byte) var res resource.Result // Read vouchers from the store - store := h.userdataStore - prefixdb := storage.NewSubPrefixDb(store, []byte("vouchers")) - - voucherData, err := prefixdb.Get(ctx, []byte("sym")) + voucherData, err := h.prefixDb.Get(ctx, []byte("sym")) if err != nil { - return res, nil + return res, err } res.Content = string(voucherData) @@ -1168,8 +1169,6 @@ func (h *Handlers) GetVoucherList(ctx context.Context, sym string, input []byte) // ViewVoucher retrieves the token holding and balance from the subprefixDB func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result - store := h.userdataStore - sessionId, ok := ctx.Value("SessionId").(string) if !ok { return res, fmt.Errorf("missing session") @@ -1183,10 +1182,8 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r return res, nil } - prefixdb := storage.NewSubPrefixDb(store, []byte("vouchers")) - - // Retrieve the voucher metadata - metadata, err := getVoucherData(ctx, prefixdb, inputStr) + // Retrieve the voucher metadata using the PrefixDb interface + metadata, err := getVoucherData(ctx, h.prefixDb, inputStr) if err != nil { return res, fmt.Errorf("failed to retrieve voucher data: %v", err) } @@ -1207,7 +1204,7 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r } // getVoucherData retrieves and matches voucher data -func getVoucherData(ctx context.Context, db *storage.SubPrefixDb, input string) (*VoucherMetadata, error) { +func getVoucherData(ctx context.Context, db storage.PrefixDb, input string) (*VoucherMetadata, error) { keys := []string{"sym", "bal", "deci", "addr"} data := make(map[string]string) From 2c361e5b96fe98e5c64964676cb2e6d4b57b8aac Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Mon, 28 Oct 2024 16:30:13 +0300 Subject: [PATCH 123/289] Added tests related to the vouchers list --- internal/handlers/ussd/menuhandler_test.go | 518 ++++++++++++++++++--- 1 file changed, 455 insertions(+), 63 deletions(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index b53a289..801e44c 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -1480,8 +1480,8 @@ func TestValidateAmount(t *testing.T) { }, }, { - name: "Test with invalid amount format", - input: []byte("0.02ms"), + name: "Test with invalid amount format", + input: []byte("0.02ms"), activeBal: []byte("5"), expectedResult: resource.Result{ FlagSet: []uint32{flag_invalid_amount}, @@ -1810,67 +1810,6 @@ func TestConfirmPin(t *testing.T) { } } -func TestSetVoucher(t *testing.T) { - mockDataStore := new(mocks.MockUserDataStore) - - sessionId := "session123" - ctx := context.WithValue(context.Background(), "SessionId", sessionId) - - // Define the temporary voucher data - temporarySym := []byte("tempSym") - temporaryBal := []byte("tempBal") - temporaryDecimal := []byte("2") - temporaryAddress := []byte("0x123456") - - // Define the expected active entries - activeEntries := map[utils.DataTyp][]byte{ - utils.DATA_ACTIVE_SYM: temporarySym, - utils.DATA_ACTIVE_BAL: temporaryBal, - utils.DATA_ACTIVE_DECIMAL: temporaryDecimal, - utils.DATA_ACTIVE_ADDRESS: temporaryAddress, - } - - // Define the temporary entries to be cleared - tempEntries := map[utils.DataTyp][]byte{ - utils.DATA_TEMPORARY_SYM: []byte(""), - utils.DATA_TEMPORARY_BAL: []byte(""), - utils.DATA_TEMPORARY_DECIMAL: []byte(""), - utils.DATA_TEMPORARY_ADDRESS: []byte(""), - } - - // Mocking ReadEntry calls for temporary data retrieval - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_SYM).Return(temporarySym, nil) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_BAL).Return(temporaryBal, nil) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_DECIMAL).Return(temporaryDecimal, nil) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_ADDRESS).Return(temporaryAddress, nil) - - // Mocking WriteEntry calls for setting active data - for key, value := range activeEntries { - mockDataStore.On("WriteEntry", ctx, sessionId, key, value).Return(nil) - } - - // Mocking WriteEntry calls for clearing temporary data - for key, value := range tempEntries { - mockDataStore.On("WriteEntry", ctx, sessionId, key, value).Return(nil) - } - - h := &Handlers{ - userdataStore: mockDataStore, - } - - // Call the method under test - res, err := h.SetVoucher(ctx, "someSym", []byte{}) - - // Assert that no errors occurred - assert.NoError(t, err) - - // Assert that the result content is correct - assert.Equal(t, string(temporarySym), res.Content) - - // Assert that expectations were met - mockDataStore.AssertExpectations(t) -} - func TestFetchCustodialBalances(t *testing.T) { fm, err := NewFlagManager(flagsPath) if err != nil { @@ -1952,3 +1891,456 @@ func TestFetchCustodialBalances(t *testing.T) { }) } } + +func TestSetDefaultVoucher(t *testing.T) { + fm, err := NewFlagManager(flagsPath) + if err != nil { + t.Logf(err.Error()) + } + + flag_no_active_voucher, err := fm.GetFlag("flag_no_active_voucher") + if err != nil { + t.Logf(err.Error()) + } + + // Define session ID and mock data + sessionId := "session123" + publicKey := "0X13242618721" + notFoundErr := db.ErrNotFound{} + ctx := context.WithValue(context.Background(), "SessionId", sessionId) + + tests := []struct { + name string + vouchersResp *models.VoucherHoldingResponse + expectedResult resource.Result + }{ + { + name: "Test set default voucher when no active voucher exists", + vouchersResp: &models.VoucherHoldingResponse{ + Ok: true, + Description: "Vouchers fetched successfully", + Result: struct { + Holdings []struct { + ContractAddress string `json:"contractAddress"` + TokenSymbol string `json:"tokenSymbol"` + TokenDecimals string `json:"tokenDecimals"` + Balance string `json:"balance"` + } `json:"holdings"` + }{ + Holdings: []struct { + ContractAddress string `json:"contractAddress"` + TokenSymbol string `json:"tokenSymbol"` + TokenDecimals string `json:"tokenDecimals"` + Balance string `json:"balance"` + }{ + { + ContractAddress: "0x123", + TokenSymbol: "TOKEN1", + TokenDecimals: "18", + Balance: "100", + }, + }, + }, + }, + expectedResult: resource.Result{}, + }, + { + name: "Test no vouchers available", + vouchersResp: &models.VoucherHoldingResponse{ + Ok: true, + Description: "No vouchers available", + Result: struct { + Holdings []struct { + ContractAddress string `json:"contractAddress"` + TokenSymbol string `json:"tokenSymbol"` + TokenDecimals string `json:"tokenDecimals"` + Balance string `json:"balance"` + } `json:"holdings"` + }{ + Holdings: []struct { + ContractAddress string `json:"contractAddress"` + TokenSymbol string `json:"tokenSymbol"` + TokenDecimals string `json:"tokenDecimals"` + Balance string `json:"balance"` + }{}, + }, + }, + expectedResult: resource.Result{ + FlagSet: []uint32{flag_no_active_voucher}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockDataStore := new(mocks.MockUserDataStore) + mockAccountService := new(mocks.MockAccountService) + + h := &Handlers{ + userdataStore: mockDataStore, + accountService: mockAccountService, + flagManager: fm.parser, + } + + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM).Return([]byte(""), notFoundErr) + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil) + + mockAccountService.On("FetchVouchers", string(publicKey)).Return(tt.vouchersResp, nil) + + if len(tt.vouchersResp.Result.Holdings) > 0 { + firstVoucher := tt.vouchersResp.Result.Holdings[0] + mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM, []byte(firstVoucher.TokenSymbol)).Return(nil) + mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_BAL, []byte(firstVoucher.Balance)).Return(nil) + } + + res, err := h.SetDefaultVoucher(ctx, "set_default_voucher", []byte("some-input")) + + assert.NoError(t, err) + + assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") + + mockDataStore.AssertExpectations(t) + mockAccountService.AssertExpectations(t) + }) + } +} + +func TestCheckVouchers(t *testing.T) { + mockDataStore := new(mocks.MockUserDataStore) + mockAccountService := new(mocks.MockAccountService) + mockSubPrefixDb := new(mocks.MockSubPrefixDb) + + sessionId := "session123" + publicKey := "0X13242618721" + + h := &Handlers{ + userdataStore: mockDataStore, + accountService: mockAccountService, + prefixDb: mockSubPrefixDb, + } + + ctx := context.WithValue(context.Background(), "SessionId", sessionId) + + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil) + + mockVouchersResponse := &models.VoucherHoldingResponse{} + mockVouchersResponse.Result.Holdings = []struct { + ContractAddress string `json:"contractAddress"` + TokenSymbol string `json:"tokenSymbol"` + TokenDecimals string `json:"tokenDecimals"` + Balance string `json:"balance"` + }{ + {ContractAddress: "0xd4c288865Ce", TokenSymbol: "SRF", TokenDecimals: "6", Balance: "100"}, + {ContractAddress: "0x41c188d63Qa", TokenSymbol: "MILO", TokenDecimals: "4", Balance: "200"}, + } + + mockAccountService.On("FetchVouchers", string(publicKey)).Return(mockVouchersResponse, nil) + + mockSubPrefixDb.On("Put", ctx, []byte("sym"), []byte("1:SRF\n2:MILO")).Return(nil) + mockSubPrefixDb.On("Put", ctx, []byte("bal"), []byte("1:100\n2:200")).Return(nil) + mockSubPrefixDb.On("Put", ctx, []byte("deci"), []byte("1:6\n2:4")).Return(nil) + mockSubPrefixDb.On("Put", ctx, []byte("addr"), []byte("1:0xd4c288865Ce\n2:0x41c188d63Qa")).Return(nil) + + _, err := h.CheckVouchers(ctx, "check_vouchers", []byte("")) + + assert.NoError(t, err) + + mockDataStore.AssertExpectations(t) + mockAccountService.AssertExpectations(t) +} + +func TestProcessVouchers(t *testing.T) { + holdings := []struct { + ContractAddress string `json:"contractAddress"` + TokenSymbol string `json:"tokenSymbol"` + TokenDecimals string `json:"tokenDecimals"` + Balance string `json:"balance"` + }{ + {ContractAddress: "0xd4c288865Ce", TokenSymbol: "SRF", TokenDecimals: "6", Balance: "100"}, + {ContractAddress: "0x41c188d63Qa", TokenSymbol: "MILO", TokenDecimals: "4", Balance: "200"}, + } + + expectedResult := VoucherMetadata{ + Symbol: "1:SRF\n2:MILO", + Balance: "1:100\n2:200", + Decimal: "1:6\n2:4", + Address: "1:0xd4c288865Ce\n2:0x41c188d63Qa", + } + + result := processVouchers(holdings) + + assert.Equal(t, expectedResult, result) +} + +func TestGetVoucherList(t *testing.T) { + mockSubPrefixDb := new(mocks.MockSubPrefixDb) + + sessionId := "session123" + ctx := context.WithValue(context.Background(), "SessionId", sessionId) + + h := &Handlers{ + prefixDb: mockSubPrefixDb, + } + + mockSubPrefixDb.On("Get", ctx, []byte("sym")).Return([]byte("1:SRF\n2:MILO"), nil) + + res, err := h.GetVoucherList(ctx, "", []byte("")) + assert.NoError(t, err) + assert.Contains(t, res.Content, "1:SRF\n2:MILO") + + mockSubPrefixDb.AssertExpectations(t) +} + +func TestViewVoucher(t *testing.T) { + fm, err := NewFlagManager(flagsPath) + if err != nil { + t.Logf(err.Error()) + } + mockDataStore := new(mocks.MockUserDataStore) + mockSubPrefixDb := new(mocks.MockSubPrefixDb) + + sessionId := "session123" + ctx := context.WithValue(context.Background(), "SessionId", sessionId) + + h := &Handlers{ + userdataStore: mockDataStore, + flagManager: fm.parser, + prefixDb: mockSubPrefixDb, + } + + // Define mock voucher data + mockVoucherData := map[string]string{ + "sym": "1:SRF", + "bal": "1:100", + "deci": "1:6", + "addr": "1:0xd4c288865Ce", + } + + for key, value := range mockVoucherData { + mockSubPrefixDb.On("Get", ctx, []byte(key)).Return([]byte(value), nil) + } + + // Set up expectations for mockDataStore + expectedData := map[utils.DataTyp]string{ + utils.DATA_TEMPORARY_SYM: "SRF", + utils.DATA_TEMPORARY_BAL: "100", + utils.DATA_TEMPORARY_DECIMAL: "6", + utils.DATA_TEMPORARY_ADDRESS: "0xd4c288865Ce", + } + + for dataType, dataValue := range expectedData { + mockDataStore.On("WriteEntry", ctx, sessionId, dataType, []byte(dataValue)).Return(nil) + } + + res, err := h.ViewVoucher(ctx, "view_voucher", []byte("1")) + assert.NoError(t, err) + assert.Contains(t, res.Content, "SRF\n100") + + mockDataStore.AssertExpectations(t) + mockSubPrefixDb.AssertExpectations(t) +} + +func TestGetVoucherData(t *testing.T) { + mockSubPrefixDb := new(mocks.MockSubPrefixDb) + ctx := context.Background() + + // Mocked voucher data + mockData := map[string][]byte{ + "sym": []byte("1:SRF\n2:MILO"), + "bal": []byte("1:100\n2:200"), + "deci": []byte("1:6\n2:4"), + "addr": []byte("1:0xd4c288865Ce\n2:0x41c188d63Qa"), + } + + // Mock Get calls + for key, value := range mockData { + mockSubPrefixDb.On("Get", ctx, []byte(key)).Return(value, nil) + } + + result, err := getVoucherData(ctx, mockSubPrefixDb, "1") + + assert.NoError(t, err) + assert.Equal(t, "SRF", result.Symbol) + assert.Equal(t, "100", result.Balance) + assert.Equal(t, "6", result.Decimal) + assert.Equal(t, "0xd4c288865Ce", result.Address) + + mockSubPrefixDb.AssertExpectations(t) +} + +func TestMatchVoucher(t *testing.T) { + symbols := "1:SRF\n2:MILO" + balances := "1:100\n2:200" + decimals := "1:6\n2:4" + addresses := "1:0xd4c288865Ce\n2:0x41c188d63Qa" + + // Test for valid voucher + symbol, balance, decimal, address := matchVoucher("2", symbols, balances, decimals, addresses) + + // Assertions for valid voucher + assert.Equal(t, "MILO", symbol) + assert.Equal(t, "200", balance) + assert.Equal(t, "4", decimal) + assert.Equal(t, "0x41c188d63Qa", address) + + // Test for non-existent voucher + symbol, balance, decimal, address = matchVoucher("3", symbols, balances, decimals, addresses) + + // Assertions for non-match + assert.Equal(t, "", symbol) + assert.Equal(t, "", balance) + assert.Equal(t, "", decimal) + assert.Equal(t, "", address) +} + +func TestStoreTemporaryVoucher(t *testing.T) { + mockDataStore := new(mocks.MockUserDataStore) + ctx := context.Background() + sessionId := "session123" + + voucherData := &VoucherMetadata{ + Symbol: "SRF", + Balance: "200", + Decimal: "6", + Address: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", + } + + // Define expected entries to be written + expectedEntries := map[utils.DataTyp][]byte{ + utils.DATA_TEMPORARY_SYM: []byte("SRF"), + utils.DATA_TEMPORARY_BAL: []byte("200"), + utils.DATA_TEMPORARY_DECIMAL: []byte("6"), + utils.DATA_TEMPORARY_ADDRESS: []byte("0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9"), + } + + // Mock WriteEntry calls + for key, value := range expectedEntries { + mockDataStore.On("WriteEntry", ctx, sessionId, key, value).Return(nil) + } + + h := &Handlers{userdataStore: mockDataStore} + + err := h.storeTemporaryVoucher(ctx, sessionId, voucherData) + + assert.NoError(t, err) + mockDataStore.AssertExpectations(t) +} + +func TestSetVoucher(t *testing.T) { + mockDataStore := new(mocks.MockUserDataStore) + + sessionId := "session123" + ctx := context.WithValue(context.Background(), "SessionId", sessionId) + + // Define the temporary voucher data + tempData := &VoucherMetadata{ + Symbol: "SRF", + Balance: "200", + Decimal: "6", + Address: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", + } + + // Define the expected active entries + activeEntries := map[utils.DataTyp][]byte{ + utils.DATA_ACTIVE_SYM: []byte(tempData.Symbol), + utils.DATA_ACTIVE_BAL: []byte(tempData.Balance), + utils.DATA_ACTIVE_DECIMAL: []byte(tempData.Decimal), + utils.DATA_ACTIVE_ADDRESS: []byte(tempData.Address), + } + + // Define the temporary entries to be cleared + tempEntries := map[utils.DataTyp][]byte{ + utils.DATA_TEMPORARY_SYM: []byte(""), + utils.DATA_TEMPORARY_BAL: []byte(""), + utils.DATA_TEMPORARY_DECIMAL: []byte(""), + utils.DATA_TEMPORARY_ADDRESS: []byte(""), + } + + // Mocking ReadEntry calls for temporary data retrieval + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_SYM).Return([]byte(tempData.Symbol), nil) + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_BAL).Return([]byte(tempData.Balance), nil) + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_DECIMAL).Return([]byte(tempData.Decimal), nil) + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_ADDRESS).Return([]byte(tempData.Address), nil) + + // Mocking WriteEntry calls for setting active data + for key, value := range activeEntries { + mockDataStore.On("WriteEntry", ctx, sessionId, key, value).Return(nil) + } + + // Mocking WriteEntry calls for clearing temporary data + for key, value := range tempEntries { + mockDataStore.On("WriteEntry", ctx, sessionId, key, value).Return(nil) + } + + h := &Handlers{ + userdataStore: mockDataStore, + } + + res, err := h.SetVoucher(ctx, "someSym", []byte{}) + + assert.NoError(t, err) + + assert.Equal(t, string(tempData.Symbol), res.Content) + + mockDataStore.AssertExpectations(t) +} + +func TestGetTemporaryVoucherData(t *testing.T) { + mockDataStore := new(mocks.MockUserDataStore) + sessionId := "session123" + ctx := context.WithValue(context.Background(), "SessionId", sessionId) + + h := &Handlers{userdataStore: mockDataStore} + + // Mock temporary voucher data + tempData := &VoucherMetadata{ + Symbol: "SRF", + Balance: "100", + Decimal: "6", + Address: "0xd4c288865Ce", + } + + // Set up mocks for reading entries + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_SYM).Return([]byte(tempData.Symbol), nil) + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_BAL).Return([]byte(tempData.Balance), nil) + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_DECIMAL).Return([]byte(tempData.Decimal), nil) + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_ADDRESS).Return([]byte(tempData.Address), nil) + + data, err := h.getTemporaryVoucherData(ctx, sessionId) + assert.NoError(t, err) + assert.Equal(t, tempData, data) + + mockDataStore.AssertExpectations(t) +} + +func TestUpdateVoucherData(t *testing.T) { + mockDataStore := new(mocks.MockUserDataStore) + ctx := context.Background() + sessionId := "session123" + + h := &Handlers{userdataStore: mockDataStore} + + data := &VoucherMetadata{ + Symbol: "SRF", + Balance: "100", + Decimal: "6", + Address: "0xd4c288865Ce", + } + + // Mock WriteEntry for active data + mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM, []byte(data.Symbol)).Return(nil) + mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_BAL, []byte(data.Balance)).Return(nil) + mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_DECIMAL, []byte(data.Decimal)).Return(nil) + mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_ADDRESS, []byte(data.Address)).Return(nil) + + // Mock WriteEntry for clearing temporary data + mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_SYM, []byte("")).Return(nil) + mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_BAL, []byte("")).Return(nil) + mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_DECIMAL, []byte("")).Return(nil) + mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_ADDRESS, []byte("")).Return(nil) + + err := h.updateVoucherData(ctx, sessionId, data) + assert.NoError(t, err) + + mockDataStore.AssertExpectations(t) +} From aec0abb2b632af7cda2296a8eb8bcb8b5e6aaac6 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 28 Oct 2024 16:34:33 +0300 Subject: [PATCH 124/289] setup an admin flag --- cmd/main.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/main.go b/cmd/main.go index 21ca0c3..e79176c 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -33,10 +33,12 @@ func main() { var size uint var sessionId string var database string + var isAdmin bool var engineDebug bool flag.StringVar(&sessionId, "session-id", "075xx2123", "session id") flag.StringVar(&database, "db", "gdbm", "database to be used") flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from") + flag.BoolVar(&isAdmin, "admin", false, "if user has admin previleges") flag.BoolVar(&engineDebug, "d", false, "use engine debug output") flag.UintVar(&size, "s", 160, "max size of output") flag.Parse() @@ -46,6 +48,7 @@ func main() { ctx := context.Background() ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "Database", database) + ctx = context.WithValue(ctx, "Admin", isAdmin) pfp := path.Join(scriptDir, "pp.csv") cfg := engine.Config{ From b97965193bb53185221a77d846e3d40e6d7ca005 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 28 Oct 2024 16:37:23 +0300 Subject: [PATCH 125/289] add pin reset for others handling --- internal/handlers/ussd/menuhandler.go | 118 ++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 9 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index f4d279b..ae50724 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -27,11 +27,12 @@ import ( ) var ( - logg = logging.NewVanilla().WithDomain("ussdmenuhandler") - scriptDir = path.Join("services", "registration") - translationDir = path.Join(scriptDir, "locale") - okResponse *api.OKResponse - errResponse *api.ErrResponse + logg = logging.NewVanilla().WithDomain("ussdmenuhandler") + scriptDir = path.Join("services", "registration") + translationDir = path.Join(scriptDir, "locale") + PINChangePrivilege byte = 1 + okResponse *api.OKResponse + errResponse *api.ErrResponse ) // FlagManager handles centralized flag management @@ -98,20 +99,41 @@ func (h *Handlers) WithPersister(pe *persist.Persister) *Handlers { return h } +func setAdminPrevilege(ctx context.Context, store utils.DataStore) error { + var err error + + sessionId, ok := ctx.Value("SessionId").(string) + if !ok { + return fmt.Errorf("missing session") + } + prefixdb := storage.NewSubPrefixDb(store, []byte("acl")) + err = prefixdb.Put(ctx, []byte(sessionId), []byte("1")) + if err != nil { + return err + } + return nil +} + func (h *Handlers) Init(ctx context.Context, sym string, input []byte) (resource.Result, error) { var r resource.Result - if h.pe == nil { logg.WarnCtxf(ctx, "handler init called before it is ready or more than once", "state", h.st, "cache", h.ca) return r, nil } + h.st = h.pe.GetState() h.ca = h.pe.GetMemory() + if h.st == nil || h.ca == nil { logg.ErrorCtxf(ctx, "perister fail in handler", "state", h.st, "cache", h.ca) return r, fmt.Errorf("cannot get state and memory for handler") } h.pe = nil + store := h.userdataStore + err := setAdminPrevilege(ctx, store) + if err != nil { + return r, fmt.Errorf("failed to set previlege level") + } logg.DebugCtxf(ctx, "handler has been initialized", "state", h.st, "cache", h.ca) @@ -189,6 +211,26 @@ func (h *Handlers) CreateAccount(ctx context.Context, sym string, input []byte) return res, nil } +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") + } + store := h.userdataStore + temporaryPin, err := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_PIN) + if err != nil { + return res, err + } + if bytes.Equal(temporaryPin, input) { + res.FlagReset = append(res.FlagReset, flag_pin_mismatch) + } else { + res.FlagSet = append(res.FlagSet, flag_pin_mismatch) + } + return res, nil +} + func (h *Handlers) VerifyNewPin(ctx context.Context, sym string, input []byte) (resource.Result, error) { res := resource.Result{} _, ok := ctx.Value("SessionId").(string) @@ -284,7 +326,6 @@ func (h *Handlers) VerifyCreatePin(ctx context.Context, sym string, input []byte if err != nil { return res, err } - if bytes.Equal(input, temporaryPin) { res.FlagSet = []uint32{flag_valid_pin} res.FlagReset = []uint32{flag_pin_mismatch} @@ -444,6 +485,14 @@ func (h *Handlers) ResetAllowUpdate(ctx context.Context, sym string, input []byt return res, nil } +// ResetAllowUpdate resets the allowupdate flag that allows a user to update profile data. +func (h *Handlers) ResetValidPin(ctx context.Context, sym string, input []byte) (resource.Result, error) { + var res resource.Result + flag_valid_pin, _ := h.flagManager.GetFlag("flag_valid_pin") + res.FlagReset = append(res.FlagReset, flag_valid_pin) + return res, nil +} + // ResetAccountAuthorized resets the account authorization flag after a successful PIN entry. func (h *Handlers) ResetAccountAuthorized(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result @@ -501,6 +550,7 @@ func (h *Handlers) Authorize(ctx context.Context, sym string, input []byte) (res return res, nil } } else { + fmt.Println("Authorizing the account else") return res, nil } return res, nil @@ -522,17 +572,37 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b flag_account_success, _ := h.flagManager.GetFlag("flag_account_success") flag_account_pending, _ := h.flagManager.GetFlag("flag_account_pending") flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") + flag_admin_privilege, _ := h.flagManager.GetFlag("flag_admin_privilege") sessionId, ok := ctx.Value("SessionId").(string) if !ok { return res, fmt.Errorf("missing session") } + isAdmin, _ := ctx.Value("Admin").(bool) store := h.userdataStore publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) if err != nil { return res, err } + if isAdmin { + setAdminPrevilege(ctx, store) + } + prefixdb := storage.NewSubPrefixDb(store, []byte("acl")) + accessLevel, err := prefixdb.Get(ctx, []byte(sessionId)) + if err != nil { + if !db.IsNotFound(err) { + return res, nil + } + } + isPrevileged := bytes.Equal(accessLevel, []byte("1")) + + if isPrevileged { + //Set Admin privilege Flag + res.FlagSet = append(res.FlagSet, flag_admin_privilege) + } + okResponse, err = h.accountService.TrackAccountStatus(ctx, string(publicKey)) + if err != nil { res.FlagSet = append(res.FlagSet, flag_api_error) return res, err @@ -588,7 +658,6 @@ func (h *Handlers) VerifyYob(ctx context.Context, sym string, input []byte) (res var err error flag_incorrect_date_format, _ := h.flagManager.GetFlag("flag_incorrect_date_format") - date := string(input) _, err = strconv.Atoi(date) if err != nil { @@ -694,6 +763,22 @@ func (h *Handlers) FetchCustodialBalances(ctx context.Context, sym string, input return res, nil } +func (h *Handlers) ValidateBlockedNumber(ctx context.Context, sym string, input []byte) (resource.Result, error) { + var res resource.Result + var err error + store := h.userdataStore + sessionId, ok := ctx.Value("SessionId").(string) + if !ok { + return res, fmt.Errorf("missing session") + } + blockedNumber := string(input) + err = store.WriteEntry(ctx, sessionId, utils.DATA_BLOCKED_NUMBER, []byte(blockedNumber)) + if err != nil { + return res, nil + } + return res, nil +} + // ValidateRecipient validates that the given input is a valid phone number. func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result @@ -865,6 +950,22 @@ func (h *Handlers) GetRecipient(ctx context.Context, sym string, input []byte) ( return res, nil } +// RetrieveBlockedNumber gets the current number during the pin reset for other's is in progress. +func (h *Handlers) RetrieveBlockedNumber(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 + blockedNumber, _ := store.ReadEntry(ctx, sessionId, utils.DATA_BLOCKED_NUMBER) + + res.Content = string(blockedNumber) + + return res, nil +} + // GetSender returns the sessionId (phoneNumber) func (h *Handlers) GetSender(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result @@ -1102,7 +1203,6 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) if err != nil { return res, nil } - err = prefixdb.Put(ctx, []byte("bal"), []byte(voucherBalanceList)) if err != nil { return res, nil From e338ce00257316f6a9d107d81bfde9043bdea0e7 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 29 Oct 2024 13:14:49 +0300 Subject: [PATCH 126/289] load and reload only after input --- services/registration/enter_familyname.vis | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services/registration/enter_familyname.vis b/services/registration/enter_familyname.vis index b9fe7b0..5a684ed 100644 --- a/services/registration/enter_familyname.vis +++ b/services/registration/enter_familyname.vis @@ -1,9 +1,8 @@ CATCH incorrect_pin flag_incorrect_pin 1 CATCH profile_update_success flag_allow_update 1 -LOAD save_familyname 0 -RELOAD save_familyname MOUT back 0 HALT +LOAD save_familyname 0 RELOAD save_familyname INCMP _ 0 INCMP pin_entry * From ca13d9155c000a615a89fb6d0fce44765e67c12d Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 29 Oct 2024 13:15:22 +0300 Subject: [PATCH 127/289] replace _ with explicit back node --- services/registration/pin_management.vis | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/registration/pin_management.vis b/services/registration/pin_management.vis index b196a50..c0adc5c 100644 --- a/services/registration/pin_management.vis +++ b/services/registration/pin_management.vis @@ -2,6 +2,6 @@ MOUT change_pin 1 MOUT reset_pin 2 MOUT back 0 HALT -INCMP _ 0 +INCMP my_account 0 INCMP old_pin 1 INCMP enter_other_number 2 From c9bb93ede6c0deaba60868c4eb2f39a717371f59 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 29 Oct 2024 13:15:41 +0300 Subject: [PATCH 128/289] create a simple admin store for phone numbers --- internal/utils/adminstore.go | 68 ++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 internal/utils/adminstore.go diff --git a/internal/utils/adminstore.go b/internal/utils/adminstore.go new file mode 100644 index 0000000..98241a6 --- /dev/null +++ b/internal/utils/adminstore.go @@ -0,0 +1,68 @@ +package utils + +import ( + "bufio" + "os" + "strconv" +) + +type AdminStore struct { + filePath string +} + +// Creates a new Admin store +func NewAdminStore(filePath string) *AdminStore { + return &AdminStore{filePath: filePath} +} + +// Seed saves a list of phonumbers with admin privileges +func (as *AdminStore) Seed() error { + adminNumbers := []int64{254705136690, 123456789012, 987654321098} + file, err := os.Create(as.filePath) + if err != nil { + return err + } + defer file.Close() + + writer := bufio.NewWriter(file) + for _, num := range adminNumbers { + _, err := writer.WriteString(strconv.FormatInt(num, 10) + "\n") + if err != nil { + return err + } + } + return writer.Flush() +} + + +func (as *AdminStore) load() ([]int64, error) { + file, err := os.Open(as.filePath) + if err != nil { + return nil, err + } + defer file.Close() + + var numbers []int64 + scanner := bufio.NewScanner(file) + for scanner.Scan() { + num, err := strconv.ParseInt(scanner.Text(), 10, 64) + if err != nil { + return nil, err + } + numbers = append(numbers, num) + } + return numbers, scanner.Err() +} + +func (as *AdminStore) IsAdmin(phoneNumber int64) (bool, error) { + phoneNumbers, err := as.load() + if err != nil { + return false, err + } + for _, phonenumber := range phoneNumbers { + if phonenumber == phoneNumber { + return true, nil + } + } + return false, nil +} From 41da099933a9ee36605258179c305bc5965720d8 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 29 Oct 2024 13:24:13 +0300 Subject: [PATCH 129/289] remove the admin flag,setup an admin store --- cmd/main.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index e79176c..4d23011 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -15,6 +15,7 @@ import ( "git.grassecon.net/urdt/ussd/internal/handlers" "git.grassecon.net/urdt/ussd/internal/handlers/server" "git.grassecon.net/urdt/ussd/internal/storage" + "git.grassecon.net/urdt/ussd/internal/utils" ) var ( @@ -33,12 +34,10 @@ func main() { var size uint var sessionId string var database string - var isAdmin bool var engineDebug bool flag.StringVar(&sessionId, "session-id", "075xx2123", "session id") flag.StringVar(&database, "db", "gdbm", "database to be used") flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from") - flag.BoolVar(&isAdmin, "admin", false, "if user has admin previleges") flag.BoolVar(&engineDebug, "d", false, "use engine debug output") flag.UintVar(&size, "s", 160, "max size of output") flag.Parse() @@ -48,9 +47,11 @@ func main() { ctx := context.Background() ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "Database", database) - ctx = context.WithValue(ctx, "Admin", isAdmin) pfp := path.Join(scriptDir, "pp.csv") + as := utils.NewAdminStore("admin_numbers.txt") + as.Seed() + cfg := engine.Config{ Root: "root", SessionId: sessionId, From d83962c0ba7481327d529f612df96288f09327ff Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 29 Oct 2024 14:26:24 +0300 Subject: [PATCH 130/289] load admin numbers defined in the .env --- internal/utils/adminstore.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/internal/utils/adminstore.go b/internal/utils/adminstore.go index 98241a6..ddd6bd9 100644 --- a/internal/utils/adminstore.go +++ b/internal/utils/adminstore.go @@ -2,8 +2,12 @@ package utils import ( "bufio" + "log" "os" "strconv" + "strings" + + "git.grassecon.net/urdt/ussd/initializers" ) type AdminStore struct { @@ -15,9 +19,18 @@ func NewAdminStore(filePath string) *AdminStore { return &AdminStore{filePath: filePath} } -// Seed saves a list of phonumbers with admin privileges +// Seed initializes a list of phonenumbers with admin privileges func (as *AdminStore) Seed() error { - adminNumbers := []int64{254705136690, 123456789012, 987654321098} + var adminNumbers []int64 + + numbersEnv := initializers.GetEnv("ADMIN_NUMBERS", "") + for _, numStr := range strings.Split(numbersEnv, ",") { + if num, err := strconv.ParseInt(strings.TrimSpace(numStr), 10, 64); err == nil { + adminNumbers = append(adminNumbers, num) + } else { + log.Printf("Skipping invalid number: %s", numStr) + } + } file, err := os.Create(as.filePath) if err != nil { return err @@ -34,7 +47,6 @@ func (as *AdminStore) Seed() error { return writer.Flush() } - func (as *AdminStore) load() ([]int64, error) { file, err := os.Open(as.filePath) if err != nil { From 5fd3eb3c292f5640cd556a1063e1ab5f220d3e23 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 29 Oct 2024 14:28:58 +0300 Subject: [PATCH 131/289] set admin privilege flag --- internal/handlers/ussd/menuhandler.go | 55 ++++++++------------------- 1 file changed, 15 insertions(+), 40 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index ae50724..d397eff 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -99,21 +99,6 @@ func (h *Handlers) WithPersister(pe *persist.Persister) *Handlers { return h } -func setAdminPrevilege(ctx context.Context, store utils.DataStore) error { - var err error - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return fmt.Errorf("missing session") - } - prefixdb := storage.NewSubPrefixDb(store, []byte("acl")) - err = prefixdb.Put(ctx, []byte(sessionId), []byte("1")) - if err != nil { - return err - } - return nil -} - func (h *Handlers) Init(ctx context.Context, sym string, input []byte) (resource.Result, error) { var r resource.Result if h.pe == nil { @@ -124,16 +109,24 @@ func (h *Handlers) Init(ctx context.Context, sym string, input []byte) (resource h.st = h.pe.GetState() h.ca = h.pe.GetMemory() + sessionId, _ := ctx.Value("SessionId").(string) + flag_admin_privilege, _ := h.flagManager.GetFlag("flag_admin_privilege") + + number, _ := strconv.ParseInt(sessionId, 10, 64) + as := utils.NewAdminStore("admin_numbers.txt") + isAdmin, _ := as.IsAdmin(number) + + if isAdmin { + r.FlagSet = append(r.FlagSet, flag_admin_privilege) + } else { + r.FlagReset = append(r.FlagReset, flag_admin_privilege) + } + if h.st == nil || h.ca == nil { logg.ErrorCtxf(ctx, "perister fail in handler", "state", h.st, "cache", h.ca) return r, fmt.Errorf("cannot get state and memory for handler") } h.pe = nil - store := h.userdataStore - err := setAdminPrevilege(ctx, store) - if err != nil { - return r, fmt.Errorf("failed to set previlege level") - } logg.DebugCtxf(ctx, "handler has been initialized", "state", h.st, "cache", h.ca) @@ -403,6 +396,7 @@ func (h *Handlers) SaveYob(ctx context.Context, sym string, input []byte) (resou if !ok { return res, fmt.Errorf("missing session") } + if len(input) == 4 { yob := string(input) store := h.userdataStore @@ -550,7 +544,6 @@ func (h *Handlers) Authorize(ctx context.Context, sym string, input []byte) (res return res, nil } } else { - fmt.Println("Authorizing the account else") return res, nil } return res, nil @@ -572,37 +565,19 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b flag_account_success, _ := h.flagManager.GetFlag("flag_account_success") flag_account_pending, _ := h.flagManager.GetFlag("flag_account_pending") flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") - flag_admin_privilege, _ := h.flagManager.GetFlag("flag_admin_privilege") sessionId, ok := ctx.Value("SessionId").(string) if !ok { return res, fmt.Errorf("missing session") } - isAdmin, _ := ctx.Value("Admin").(bool) + store := h.userdataStore publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) if err != nil { return res, err } - if isAdmin { - setAdminPrevilege(ctx, store) - } - prefixdb := storage.NewSubPrefixDb(store, []byte("acl")) - accessLevel, err := prefixdb.Get(ctx, []byte(sessionId)) - if err != nil { - if !db.IsNotFound(err) { - return res, nil - } - } - isPrevileged := bytes.Equal(accessLevel, []byte("1")) - - if isPrevileged { - //Set Admin privilege Flag - res.FlagSet = append(res.FlagSet, flag_admin_privilege) - } okResponse, err = h.accountService.TrackAccountStatus(ctx, string(publicKey)) - if err != nil { res.FlagSet = append(res.FlagSet, flag_api_error) return res, err From 124049c92453ff6db90f91b2fe0fce4554a2061a Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 29 Oct 2024 14:32:17 +0300 Subject: [PATCH 132/289] add admin number defination in env --- .env.example | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.env.example b/.env.example index ab370a7..4d86f8b 100644 --- a/.env.example +++ b/.env.example @@ -16,3 +16,7 @@ CREATE_ACCOUNT_URL=http://localhost:5003/api/v2/account/create TRACK_STATUS_URL=https://custodial.sarafu.africa/api/track/ BALANCE_URL=https://custodial.sarafu.africa/api/account/status/ TRACK_URL=http://localhost:5003/api/v2/account/status + + +#numbers with privileges to reset others pin +ADMIN_NUMBERS=254051722XXX,255012221XXX \ No newline at end of file From e96c8743004550e0738494b9cd3d0899d7be7885 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 29 Oct 2024 15:02:40 +0300 Subject: [PATCH 133/289] repeat same node on invalid option input --- services/registration/pin_management.vis | 1 + 1 file changed, 1 insertion(+) diff --git a/services/registration/pin_management.vis b/services/registration/pin_management.vis index c0adc5c..5eb7d5a 100644 --- a/services/registration/pin_management.vis +++ b/services/registration/pin_management.vis @@ -5,3 +5,4 @@ HALT INCMP my_account 0 INCMP old_pin 1 INCMP enter_other_number 2 +INCMP . * From 449f90c95b6a4f41bd2d8c1501a99ae39d052fc7 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 29 Oct 2024 17:17:03 +0300 Subject: [PATCH 134/289] add flag to catch unregistred numbers --- services/registration/pp.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/registration/pp.csv b/services/registration/pp.csv index cee8d13..406cc22 100644 --- a/services/registration/pp.csv +++ b/services/registration/pp.csv @@ -18,4 +18,4 @@ flag,flag_incorrect_voucher,24,this is set when the selected voucher is invalid flag,flag_api_call_error,25,this is set when communication to an external service fails flag,flag_no_active_voucher,26,this is set when a user does not have an active voucher flag,flag_admin_privilege,27,this is set when a user has admin privileges. - +flag,flag_unregistered_number,28,this is set when an unregistered phonenumber tries to perform an action From 6998c30dd1614077ddcf36ac5d1fb4ab3a4ff338 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 29 Oct 2024 17:18:01 +0300 Subject: [PATCH 135/289] add node to handle unregistered phone numbers --- services/registration/unregistered_number | 1 + services/registration/unregistered_number.vis | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 services/registration/unregistered_number create mode 100644 services/registration/unregistered_number.vis diff --git a/services/registration/unregistered_number b/services/registration/unregistered_number new file mode 100644 index 0000000..9cc33d7 --- /dev/null +++ b/services/registration/unregistered_number @@ -0,0 +1 @@ +The number you have entered is either not registered with Sarafu or is invalid. \ No newline at end of file diff --git a/services/registration/unregistered_number.vis b/services/registration/unregistered_number.vis new file mode 100644 index 0000000..f7a6a9c --- /dev/null +++ b/services/registration/unregistered_number.vis @@ -0,0 +1,7 @@ +LOAD reset_unregistered_number 0 +RELOAD reset_unregistered_number +MOUT retry 1 +MOUT quit 9 +HALT +INCMP enter_other_number 1 +INCMP quit 9 From 534d75631836a50bf00ebe194b33c6d061726853 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 29 Oct 2024 17:18:39 +0300 Subject: [PATCH 136/289] catch unregistred phone numbers --- services/registration/enter_others_new_pin.vis | 1 + 1 file changed, 1 insertion(+) diff --git a/services/registration/enter_others_new_pin.vis b/services/registration/enter_others_new_pin.vis index aa2818d..1577ff1 100644 --- a/services/registration/enter_others_new_pin.vis +++ b/services/registration/enter_others_new_pin.vis @@ -1,3 +1,4 @@ +CATCH unregistered_number flag_unregistered_number 1 LOAD retrieve_blocked_number 0 MAP retrieve_blocked_number MOUT back 0 From 91b85af11a223cb66de5b6cc2af900296556b3b0 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 29 Oct 2024 17:34:34 +0300 Subject: [PATCH 137/289] add reset unregistered number --- internal/handlers/handlerservice.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/handlers/handlerservice.go b/internal/handlers/handlerservice.go index a30f1b2..b4cd592 100644 --- a/internal/handlers/handlerservice.go +++ b/internal/handlers/handlerservice.go @@ -102,6 +102,7 @@ func (ls *LocalHandlerService) GetHandler(accountService server.AccountServiceIn 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) return ussdHandlers, nil } From 106983a3940fc0b2066e0486fd1b47dcd1239345 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 29 Oct 2024 17:35:01 +0300 Subject: [PATCH 138/289] use explicit back to node --- services/registration/enter_other_number.vis | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/registration/enter_other_number.vis b/services/registration/enter_other_number.vis index 41c711a..7f413da 100644 --- a/services/registration/enter_other_number.vis +++ b/services/registration/enter_other_number.vis @@ -3,7 +3,7 @@ LOAD reset_account_authorized 6 RELOAD reset_account_authorized MOUT back 0 HALT -INCMP _ 0 LOAD validate_blocked_number 0 RELOAD validate_blocked_number +INCMP pin_management 0 INCMP enter_others_new_pin * From d0ad6395b5670501b543e61e2a5ef2c8c5acf2ca Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 29 Oct 2024 17:35:42 +0300 Subject: [PATCH 139/289] add check for unregistered phone numbers --- internal/handlers/ussd/menuhandler.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index d395a8b..715a654 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -748,15 +748,35 @@ func (h *Handlers) FetchCustodialBalances(ctx context.Context, sym string, input return res, nil } +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") + res.FlagReset = append(res.FlagReset, flag_unregistered_number) + return res, nil +} + func (h *Handlers) ValidateBlockedNumber(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result var err error + + flag_unregistered_number, _ := h.flagManager.GetFlag("flag_unregistered_number") + store := h.userdataStore sessionId, ok := ctx.Value("SessionId").(string) if !ok { return res, fmt.Errorf("missing session") } blockedNumber := string(input) + _, err = store.ReadEntry(ctx, blockedNumber, utils.DATA_PUBLIC_KEY) + if err != nil { + if db.IsNotFound(err) { + logg.Printf(logging.LVL_INFO, "Invalid or unregistered number") + res.FlagSet = append(res.FlagSet, flag_unregistered_number) + return res, nil + } else { + return res, err + } + } err = store.WriteEntry(ctx, sessionId, utils.DATA_BLOCKED_NUMBER, []byte(blockedNumber)) if err != nil { return res, nil From f37483e2f04d4fa4ead95223ff2c0acc33518ff8 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 29 Oct 2024 22:15:31 +0300 Subject: [PATCH 140/289] use _ for back navigation --- services/registration/unregistered_number.vis | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/registration/unregistered_number.vis b/services/registration/unregistered_number.vis index f7a6a9c..114113f 100644 --- a/services/registration/unregistered_number.vis +++ b/services/registration/unregistered_number.vis @@ -3,5 +3,5 @@ RELOAD reset_unregistered_number MOUT retry 1 MOUT quit 9 HALT -INCMP enter_other_number 1 +INCMP _ 1 INCMP quit 9 From 7597b96daec3367a8a09dff0ee24f95a616107a2 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 29 Oct 2024 22:16:34 +0300 Subject: [PATCH 141/289] remove catch for unregistered number --- services/registration/enter_others_new_pin.vis | 1 - 1 file changed, 1 deletion(-) diff --git a/services/registration/enter_others_new_pin.vis b/services/registration/enter_others_new_pin.vis index 1577ff1..aa2818d 100644 --- a/services/registration/enter_others_new_pin.vis +++ b/services/registration/enter_others_new_pin.vis @@ -1,4 +1,3 @@ -CATCH unregistered_number flag_unregistered_number 1 LOAD retrieve_blocked_number 0 MAP retrieve_blocked_number MOUT back 0 From 5a0563df94b67fade2498e8f37eef91f82a95da4 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 29 Oct 2024 22:17:43 +0300 Subject: [PATCH 142/289] group regex,check for valid number against the regex --- internal/handlers/ussd/menuhandler.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 715a654..70510ee 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -35,6 +35,12 @@ var ( backOption = []byte("0") ) +// Define the regex patterns as constants +const ( + phoneRegex = `(\(\d{3}\)\s?|\d{3}[-.\s]?)?\d{3}[-.\s]?\d{4}` + pinPattern = `^\d{4}$` +) + // FlagManager handles centralized flag management type FlagManager struct { parser *asm.FlagParser @@ -82,15 +88,17 @@ func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db, accountService s return h, nil } -// Define the regex pattern as a constant -const pinPattern = `^\d{4}$` - // isValidPIN checks whether the given input is a 4 digit number func isValidPIN(pin string) bool { match, _ := regexp.MatchString(pinPattern, pin) return match } +func isValidPhoneNumber(phonenumber string) bool { + match, _ := regexp.MatchString(phoneRegex, phonenumber) + return match +} + func (h *Handlers) WithPersister(pe *persist.Persister) *Handlers { if h.pe != nil { panic("persister already set") @@ -255,7 +263,6 @@ 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 @@ -768,6 +775,9 @@ func (h *Handlers) ValidateBlockedNumber(ctx context.Context, sym string, input } blockedNumber := string(input) _, err = store.ReadEntry(ctx, blockedNumber, utils.DATA_PUBLIC_KEY) + if !isValidPhoneNumber(blockedNumber) { + return res, nil + } if err != nil { if db.IsNotFound(err) { logg.Printf(logging.LVL_INFO, "Invalid or unregistered number") From 0a97f610a47746c25cc7748ebbf29937e3bc11a2 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 29 Oct 2024 22:23:22 +0300 Subject: [PATCH 143/289] catch unregistred number --- services/registration/enter_other_number.vis | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/services/registration/enter_other_number.vis b/services/registration/enter_other_number.vis index 7f413da..e2fa243 100644 --- a/services/registration/enter_other_number.vis +++ b/services/registration/enter_other_number.vis @@ -1,9 +1,10 @@ CATCH no_admin_privilege flag_admin_privilege 0 -LOAD reset_account_authorized 6 +LOAD reset_account_authorized 0 RELOAD reset_account_authorized MOUT back 0 HALT -LOAD validate_blocked_number 0 +INCMP _ 0 +LOAD validate_blocked_number 20 RELOAD validate_blocked_number -INCMP pin_management 0 +CATCH unregistered_number flag_unregistered_number 1 INCMP enter_others_new_pin * From 0480c02633067fa5638217327fb24b9d1fc62869 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 30 Oct 2024 00:52:23 +0300 Subject: [PATCH 144/289] Moved voucher related functions to the utils package --- internal/handlers/ussd/menuhandler.go | 179 +------------------------ internal/utils/vouchers.go | 184 ++++++++++++++++++++++++++ 2 files changed, 191 insertions(+), 172 deletions(-) create mode 100644 internal/utils/vouchers.go diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 98f6c9d..d4ed992 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -1118,7 +1118,7 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) return res, nil } - data := processVouchers(vouchersResp.Result.Holdings) + data := utils.ProcessVouchers(vouchersResp.Result.Holdings) // Store all voucher data dataMap := map[string]string{ @@ -1137,31 +1137,6 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) return res, nil } -// processVouchers converts holdings into formatted strings -func processVouchers(holdings []struct { - ContractAddress string `json:"contractAddress"` - TokenSymbol string `json:"tokenSymbol"` - TokenDecimals string `json:"tokenDecimals"` - Balance string `json:"balance"` -}) VoucherMetadata { - var data VoucherMetadata - var symbols, balances, decimals, addresses []string - - for i, h := range holdings { - symbols = append(symbols, fmt.Sprintf("%d:%s", i+1, h.TokenSymbol)) - balances = append(balances, fmt.Sprintf("%d:%s", i+1, h.Balance)) - decimals = append(decimals, fmt.Sprintf("%d:%s", i+1, h.TokenDecimals)) - addresses = append(addresses, fmt.Sprintf("%d:%s", i+1, h.ContractAddress)) - } - - data.Symbol = strings.Join(symbols, "\n") - data.Balance = strings.Join(balances, "\n") - data.Decimal = strings.Join(decimals, "\n") - data.Address = strings.Join(addresses, "\n") - - return data -} - // 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 @@ -1193,8 +1168,7 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r return res, nil } - // Retrieve the voucher metadata using the PrefixDb interface - metadata, err := getVoucherData(ctx, h.prefixDb, inputStr) + metadata, err := utils.GetVoucherData(ctx, h.prefixDb, inputStr) if err != nil { return res, fmt.Errorf("failed to retrieve voucher data: %v", err) } @@ -1204,7 +1178,7 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r return res, nil } - if err := h.storeTemporaryVoucher(ctx, sessionId, metadata); err != nil { + if err := utils.StoreTemporaryVoucher(ctx, h.userdataStore, sessionId, metadata); err != nil { return res, err } @@ -1214,86 +1188,9 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r return res, nil } -// getVoucherData retrieves and matches voucher data -func getVoucherData(ctx context.Context, db storage.PrefixDb, input string) (*VoucherMetadata, error) { - keys := []string{"sym", "bal", "deci", "addr"} - data := make(map[string]string) - - for _, key := range keys { - value, err := db.Get(ctx, []byte(key)) - if err != nil { - return nil, fmt.Errorf("failed to get %s: %v", key, err) - } - data[key] = string(value) - } - - symbol, balance, decimal, address := matchVoucher(input, - data["sym"], - data["bal"], - data["deci"], - data["addr"]) - - if symbol == "" { - return nil, nil - } - - return &VoucherMetadata{ - Symbol: symbol, - Balance: balance, - Decimal: decimal, - Address: address, - }, nil -} - -// MatchVoucher finds the matching voucher symbol, balance, decimals and contract address based on the input. -func matchVoucher(input, symbols, balances, decimals, addresses string) (symbol, balance, decimal, address string) { - symList := strings.Split(symbols, "\n") - balList := strings.Split(balances, "\n") - decList := strings.Split(decimals, "\n") - addrList := strings.Split(addresses, "\n") - - for i, sym := range symList { - parts := strings.SplitN(sym, ":", 2) - if len(parts) != 2 { - continue - } - - if input == parts[0] || strings.EqualFold(input, parts[1]) { - symbol = parts[1] - if i < len(balList) { - balance = strings.SplitN(balList[i], ":", 2)[1] - } - if i < len(decList) { - decimal = strings.SplitN(decList[i], ":", 2)[1] - } - if i < len(addrList) { - address = strings.SplitN(addrList[i], ":", 2)[1] - } - break - } - } - return -} - -func (h *Handlers) storeTemporaryVoucher(ctx context.Context, sessionId string, data *VoucherMetadata) error { - entries := map[utils.DataTyp][]byte{ - utils.DATA_TEMPORARY_SYM: []byte(data.Symbol), - utils.DATA_TEMPORARY_BAL: []byte(data.Balance), - utils.DATA_TEMPORARY_DECIMAL: []byte(data.Decimal), - utils.DATA_TEMPORARY_ADDRESS: []byte(data.Address), - } - - for key, value := range entries { - if err := h.userdataStore.WriteEntry(ctx, sessionId, key, value); err != nil { - return err - } - } - return nil -} - +// 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 - var err error sessionId, ok := ctx.Value("SessionId").(string) if !ok { @@ -1301,78 +1198,16 @@ func (h *Handlers) SetVoucher(ctx context.Context, sym string, input []byte) (re } // Get temporary data - tempData, err := h.getTemporaryVoucherData(ctx, sessionId) + tempData, err := utils.GetTemporaryVoucherData(ctx, h.userdataStore, sessionId) if err != nil { return res, err } - // Set as active and clear temporary - if err := h.updateVoucherData(ctx, sessionId, tempData); err != nil { + // Set as active and clear temporary data + if err := utils.UpdateVoucherData(ctx, h.userdataStore, sessionId, tempData); err != nil { return res, err } res.Content = tempData.Symbol return res, nil } - -func (h *Handlers) getTemporaryVoucherData(ctx context.Context, sessionId string) (*VoucherMetadata, error) { - store := h.userdataStore - - keys := []utils.DataTyp{ - utils.DATA_TEMPORARY_SYM, - utils.DATA_TEMPORARY_BAL, - utils.DATA_TEMPORARY_DECIMAL, - utils.DATA_TEMPORARY_ADDRESS, - } - - data := &VoucherMetadata{} - values := make([][]byte, len(keys)) - - for i, key := range keys { - value, err := store.ReadEntry(ctx, sessionId, key) - if err != nil { - return nil, err - } - values[i] = value - } - - data.Symbol = string(values[0]) - data.Balance = string(values[1]) - data.Decimal = string(values[2]) - data.Address = string(values[3]) - - return data, nil -} - -func (h *Handlers) updateVoucherData(ctx context.Context, sessionId string, data *VoucherMetadata) error { - // Set active voucher data - activeEntries := map[utils.DataTyp][]byte{ - utils.DATA_ACTIVE_SYM: []byte(data.Symbol), - utils.DATA_ACTIVE_BAL: []byte(data.Balance), - utils.DATA_ACTIVE_DECIMAL: []byte(data.Decimal), - utils.DATA_ACTIVE_ADDRESS: []byte(data.Address), - } - - // Clear temporary voucher data - tempEntries := map[utils.DataTyp][]byte{ - utils.DATA_TEMPORARY_SYM: []byte(""), - utils.DATA_TEMPORARY_BAL: []byte(""), - utils.DATA_TEMPORARY_DECIMAL: []byte(""), - utils.DATA_TEMPORARY_ADDRESS: []byte(""), - } - - // Write all entries - for key, value := range activeEntries { - if err := h.userdataStore.WriteEntry(ctx, sessionId, key, value); err != nil { - return err - } - } - - for key, value := range tempEntries { - if err := h.userdataStore.WriteEntry(ctx, sessionId, key, value); err != nil { - return err - } - } - - return nil -} diff --git a/internal/utils/vouchers.go b/internal/utils/vouchers.go new file mode 100644 index 0000000..11fd7d1 --- /dev/null +++ b/internal/utils/vouchers.go @@ -0,0 +1,184 @@ +package utils + +import ( + "fmt" + "strings" + "context" + + + "git.grassecon.net/urdt/ussd/internal/storage" +) + +// VoucherMetadata helps organize voucher data fields +type VoucherMetadata struct { + Symbol string + Balance string + Decimal string + Address string +} + +// ProcessVouchers converts holdings into formatted strings +func ProcessVouchers(holdings []struct { + ContractAddress string `json:"contractAddress"` + TokenSymbol string `json:"tokenSymbol"` + TokenDecimals string `json:"tokenDecimals"` + Balance string `json:"balance"` +}) VoucherMetadata { + var data VoucherMetadata + var symbols, balances, decimals, addresses []string + + for i, h := range holdings { + symbols = append(symbols, fmt.Sprintf("%d:%s", i+1, h.TokenSymbol)) + balances = append(balances, fmt.Sprintf("%d:%s", i+1, h.Balance)) + decimals = append(decimals, fmt.Sprintf("%d:%s", i+1, h.TokenDecimals)) + addresses = append(addresses, fmt.Sprintf("%d:%s", i+1, h.ContractAddress)) + } + + data.Symbol = strings.Join(symbols, "\n") + data.Balance = strings.Join(balances, "\n") + data.Decimal = strings.Join(decimals, "\n") + data.Address = strings.Join(addresses, "\n") + + return data +} + +// GetVoucherData retrieves and matches voucher data +func GetVoucherData(ctx context.Context, db storage.PrefixDb, input string) (*VoucherMetadata, error) { + keys := []string{"sym", "bal", "deci", "addr"} + data := make(map[string]string) + + for _, key := range keys { + value, err := db.Get(ctx, []byte(key)) + if err != nil { + return nil, fmt.Errorf("failed to get %s: %v", key, err) + } + data[key] = string(value) + } + + symbol, balance, decimal, address := MatchVoucher(input, + data["sym"], + data["bal"], + data["deci"], + data["addr"]) + + if symbol == "" { + return nil, nil + } + + return &VoucherMetadata{ + Symbol: symbol, + Balance: balance, + Decimal: decimal, + Address: address, + }, nil +} + +// MatchVoucher finds the matching voucher symbol, balance, decimals and contract address based on the input. +func MatchVoucher(input, symbols, balances, decimals, addresses string) (symbol, balance, decimal, address string) { + symList := strings.Split(symbols, "\n") + balList := strings.Split(balances, "\n") + decList := strings.Split(decimals, "\n") + addrList := strings.Split(addresses, "\n") + + for i, sym := range symList { + parts := strings.SplitN(sym, ":", 2) + if len(parts) != 2 { + continue + } + + if input == parts[0] || strings.EqualFold(input, parts[1]) { + symbol = parts[1] + if i < len(balList) { + balance = strings.SplitN(balList[i], ":", 2)[1] + } + if i < len(decList) { + decimal = strings.SplitN(decList[i], ":", 2)[1] + } + if i < len(addrList) { + address = strings.SplitN(addrList[i], ":", 2)[1] + } + break + } + } + return +} + +// StoreTemporaryVoucher saves voucher metadata as temporary entries in the DataStore. +func StoreTemporaryVoucher(ctx context.Context, store DataStore, sessionId string, data *VoucherMetadata) error { + entries := map[DataTyp][]byte{ + DATA_TEMPORARY_SYM: []byte(data.Symbol), + DATA_TEMPORARY_BAL: []byte(data.Balance), + DATA_TEMPORARY_DECIMAL: []byte(data.Decimal), + DATA_TEMPORARY_ADDRESS: []byte(data.Address), + } + + for key, value := range entries { + if err := store.WriteEntry(ctx, sessionId, key, value); err != nil { + return err + } + } + return nil +} + +// GetTemporaryVoucherData retrieves temporary voucher metadata from the DataStore. +func GetTemporaryVoucherData(ctx context.Context, store DataStore, sessionId string) (*VoucherMetadata, error) { + keys := []DataTyp{ + DATA_TEMPORARY_SYM, + DATA_TEMPORARY_BAL, + DATA_TEMPORARY_DECIMAL, + DATA_TEMPORARY_ADDRESS, + } + + data := &VoucherMetadata{} + values := make([][]byte, len(keys)) + + for i, key := range keys { + value, err := store.ReadEntry(ctx, sessionId, key) + if err != nil { + return nil, err + } + values[i] = value + } + + data.Symbol = string(values[0]) + data.Balance = string(values[1]) + data.Decimal = string(values[2]) + data.Address = string(values[3]) + + return data, nil +} + +// UpdateVoucherData sets the active voucher data and clears the temporary voucher data in the DataStore. +func UpdateVoucherData(ctx context.Context, store DataStore, sessionId string, data *VoucherMetadata) error { + // Active voucher data entries + activeEntries := map[DataTyp][]byte{ + DATA_ACTIVE_SYM: []byte(data.Symbol), + DATA_ACTIVE_BAL: []byte(data.Balance), + DATA_ACTIVE_DECIMAL: []byte(data.Decimal), + DATA_ACTIVE_ADDRESS: []byte(data.Address), + } + + // Clear temporary voucher data entries + tempEntries := map[DataTyp][]byte{ + DATA_TEMPORARY_SYM: []byte(""), + DATA_TEMPORARY_BAL: []byte(""), + DATA_TEMPORARY_DECIMAL: []byte(""), + DATA_TEMPORARY_ADDRESS: []byte(""), + } + + // Write active data + for key, value := range activeEntries { + if err := store.WriteEntry(ctx, sessionId, key, value); err != nil { + return err + } + } + + // Clear temporary data + for key, value := range tempEntries { + if err := store.WriteEntry(ctx, sessionId, key, value); err != nil { + return err + } + } + + return nil +} From 7241cdbfcbd92155a354c678f1044127c1a15aeb Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 30 Oct 2024 00:53:13 +0300 Subject: [PATCH 145/289] Updated the tests --- internal/handlers/ussd/menuhandler_test.go | 169 --------------- internal/utils/vouchers_test.go | 240 +++++++++++++++++++++ 2 files changed, 240 insertions(+), 169 deletions(-) create mode 100644 internal/utils/vouchers_test.go diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index c6ee8cf..6ea44a0 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -2050,29 +2050,6 @@ func TestCheckVouchers(t *testing.T) { mockAccountService.AssertExpectations(t) } -func TestProcessVouchers(t *testing.T) { - holdings := []struct { - ContractAddress string `json:"contractAddress"` - TokenSymbol string `json:"tokenSymbol"` - TokenDecimals string `json:"tokenDecimals"` - Balance string `json:"balance"` - }{ - {ContractAddress: "0xd4c288865Ce", TokenSymbol: "SRF", TokenDecimals: "6", Balance: "100"}, - {ContractAddress: "0x41c188d63Qa", TokenSymbol: "MILO", TokenDecimals: "4", Balance: "200"}, - } - - expectedResult := VoucherMetadata{ - Symbol: "1:SRF\n2:MILO", - Balance: "1:100\n2:200", - Decimal: "1:6\n2:4", - Address: "1:0xd4c288865Ce\n2:0x41c188d63Qa", - } - - result := processVouchers(holdings) - - assert.Equal(t, expectedResult, result) -} - func TestGetVoucherList(t *testing.T) { mockSubPrefixDb := new(mocks.MockSubPrefixDb) @@ -2141,92 +2118,6 @@ func TestViewVoucher(t *testing.T) { mockSubPrefixDb.AssertExpectations(t) } -func TestGetVoucherData(t *testing.T) { - mockSubPrefixDb := new(mocks.MockSubPrefixDb) - ctx := context.Background() - - // Mocked voucher data - mockData := map[string][]byte{ - "sym": []byte("1:SRF\n2:MILO"), - "bal": []byte("1:100\n2:200"), - "deci": []byte("1:6\n2:4"), - "addr": []byte("1:0xd4c288865Ce\n2:0x41c188d63Qa"), - } - - // Mock Get calls - for key, value := range mockData { - mockSubPrefixDb.On("Get", ctx, []byte(key)).Return(value, nil) - } - - result, err := getVoucherData(ctx, mockSubPrefixDb, "1") - - assert.NoError(t, err) - assert.Equal(t, "SRF", result.Symbol) - assert.Equal(t, "100", result.Balance) - assert.Equal(t, "6", result.Decimal) - assert.Equal(t, "0xd4c288865Ce", result.Address) - - mockSubPrefixDb.AssertExpectations(t) -} - -func TestMatchVoucher(t *testing.T) { - symbols := "1:SRF\n2:MILO" - balances := "1:100\n2:200" - decimals := "1:6\n2:4" - addresses := "1:0xd4c288865Ce\n2:0x41c188d63Qa" - - // Test for valid voucher - symbol, balance, decimal, address := matchVoucher("2", symbols, balances, decimals, addresses) - - // Assertions for valid voucher - assert.Equal(t, "MILO", symbol) - assert.Equal(t, "200", balance) - assert.Equal(t, "4", decimal) - assert.Equal(t, "0x41c188d63Qa", address) - - // Test for non-existent voucher - symbol, balance, decimal, address = matchVoucher("3", symbols, balances, decimals, addresses) - - // Assertions for non-match - assert.Equal(t, "", symbol) - assert.Equal(t, "", balance) - assert.Equal(t, "", decimal) - assert.Equal(t, "", address) -} - -func TestStoreTemporaryVoucher(t *testing.T) { - mockDataStore := new(mocks.MockUserDataStore) - ctx := context.Background() - sessionId := "session123" - - voucherData := &VoucherMetadata{ - Symbol: "SRF", - Balance: "200", - Decimal: "6", - Address: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", - } - - // Define expected entries to be written - expectedEntries := map[utils.DataTyp][]byte{ - utils.DATA_TEMPORARY_SYM: []byte("SRF"), - utils.DATA_TEMPORARY_BAL: []byte("200"), - utils.DATA_TEMPORARY_DECIMAL: []byte("6"), - utils.DATA_TEMPORARY_ADDRESS: []byte("0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9"), - } - - // Mock WriteEntry calls - for key, value := range expectedEntries { - mockDataStore.On("WriteEntry", ctx, sessionId, key, value).Return(nil) - } - - h := &Handlers{userdataStore: mockDataStore} - - err := h.storeTemporaryVoucher(ctx, sessionId, voucherData) - - assert.NoError(t, err) - mockDataStore.AssertExpectations(t) -} - func TestSetVoucher(t *testing.T) { mockDataStore := new(mocks.MockUserDataStore) @@ -2285,63 +2176,3 @@ func TestSetVoucher(t *testing.T) { mockDataStore.AssertExpectations(t) } - -func TestGetTemporaryVoucherData(t *testing.T) { - mockDataStore := new(mocks.MockUserDataStore) - sessionId := "session123" - ctx := context.WithValue(context.Background(), "SessionId", sessionId) - - h := &Handlers{userdataStore: mockDataStore} - - // Mock temporary voucher data - tempData := &VoucherMetadata{ - Symbol: "SRF", - Balance: "100", - Decimal: "6", - Address: "0xd4c288865Ce", - } - - // Set up mocks for reading entries - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_SYM).Return([]byte(tempData.Symbol), nil) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_BAL).Return([]byte(tempData.Balance), nil) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_DECIMAL).Return([]byte(tempData.Decimal), nil) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_ADDRESS).Return([]byte(tempData.Address), nil) - - data, err := h.getTemporaryVoucherData(ctx, sessionId) - assert.NoError(t, err) - assert.Equal(t, tempData, data) - - mockDataStore.AssertExpectations(t) -} - -func TestUpdateVoucherData(t *testing.T) { - mockDataStore := new(mocks.MockUserDataStore) - ctx := context.Background() - sessionId := "session123" - - h := &Handlers{userdataStore: mockDataStore} - - data := &VoucherMetadata{ - Symbol: "SRF", - Balance: "100", - Decimal: "6", - Address: "0xd4c288865Ce", - } - - // Mock WriteEntry for active data - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM, []byte(data.Symbol)).Return(nil) - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_BAL, []byte(data.Balance)).Return(nil) - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_DECIMAL, []byte(data.Decimal)).Return(nil) - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_ADDRESS, []byte(data.Address)).Return(nil) - - // Mock WriteEntry for clearing temporary data - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_SYM, []byte("")).Return(nil) - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_BAL, []byte("")).Return(nil) - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_DECIMAL, []byte("")).Return(nil) - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_ADDRESS, []byte("")).Return(nil) - - err := h.updateVoucherData(ctx, sessionId, data) - assert.NoError(t, err) - - mockDataStore.AssertExpectations(t) -} diff --git a/internal/utils/vouchers_test.go b/internal/utils/vouchers_test.go new file mode 100644 index 0000000..75ae563 --- /dev/null +++ b/internal/utils/vouchers_test.go @@ -0,0 +1,240 @@ +package utils + +import ( + "context" + "testing" + + "git.grassecon.net/urdt/ussd/internal/storage" + "github.com/alecthomas/assert/v2" + "github.com/stretchr/testify/require" + + memdb "git.defalsify.org/vise.git/db/mem" +) + +// AssertEmptyValue checks if a value is empty/nil/zero +func AssertEmptyValue(t *testing.T, value []byte, msgAndArgs ...interface{}) { + assert.Equal(t, len(value), 0, msgAndArgs...) +} + +func TestMatchVoucher(t *testing.T) { + symbols := "1:SRF\n2:MILO" + balances := "1:100\n2:200" + decimals := "1:6\n2:4" + addresses := "1:0xd4c288865Ce\n2:0x41c188d63Qa" + + // Test for valid voucher + symbol, balance, decimal, address := MatchVoucher("2", symbols, balances, decimals, addresses) + + // Assertions for valid voucher + assert.Equal(t, "MILO", symbol) + assert.Equal(t, "200", balance) + assert.Equal(t, "4", decimal) + assert.Equal(t, "0x41c188d63Qa", address) + + // Test for non-existent voucher + symbol, balance, decimal, address = MatchVoucher("3", symbols, balances, decimals, addresses) + + // Assertions for non-match + assert.Equal(t, "", symbol) + assert.Equal(t, "", balance) + assert.Equal(t, "", decimal) + assert.Equal(t, "", address) +} + +func TestProcessVouchers(t *testing.T) { + holdings := []struct { + ContractAddress string `json:"contractAddress"` + TokenSymbol string `json:"tokenSymbol"` + TokenDecimals string `json:"tokenDecimals"` + Balance string `json:"balance"` + }{ + {ContractAddress: "0xd4c288865Ce", TokenSymbol: "SRF", TokenDecimals: "6", Balance: "100"}, + {ContractAddress: "0x41c188d63Qa", TokenSymbol: "MILO", TokenDecimals: "4", Balance: "200"}, + } + + expectedResult := VoucherMetadata{ + Symbol: "1:SRF\n2:MILO", + Balance: "1:100\n2:200", + Decimal: "1:6\n2:4", + Address: "1:0xd4c288865Ce\n2:0x41c188d63Qa", + } + + result := ProcessVouchers(holdings) + + assert.Equal(t, expectedResult, result) +} + +func TestGetVoucherData(t *testing.T) { + ctx := context.Background() + + db := memdb.NewMemDb() + err := db.Connect(ctx, "") + if err != nil { + t.Fatal(err) + } + spdb := storage.NewSubPrefixDb(db, []byte("vouchers")) + + // Test voucher data + mockData := map[string][]byte{ + "sym": []byte("1:SRF\n2:MILO"), + "bal": []byte("1:100\n2:200"), + "deci": []byte("1:6\n2:4"), + "addr": []byte("1:0xd4c288865Ce\n2:0x41c188d63Qa"), + } + + // Put the data + for key, value := range mockData { + err = spdb.Put(ctx, []byte(key), []byte(value)) + if err != nil { + t.Fatal(err) + } + } + + result, err := GetVoucherData(ctx, spdb, "1") + + assert.NoError(t, err) + assert.Equal(t, "SRF", result.Symbol) + assert.Equal(t, "100", result.Balance) + assert.Equal(t, "6", result.Decimal) + assert.Equal(t, "0xd4c288865Ce", result.Address) +} + +func TestStoreTemporaryVoucher(t *testing.T) { + ctx := context.Background() + sessionId := "session123" + + // Initialize memDb + db := memdb.NewMemDb() + err := db.Connect(ctx, "") + require.NoError(t, err) + defer db.Close() + + // Create UserDataStore with memDb + store := &UserDataStore{ + Db: db, + } + + // Test data + voucherData := &VoucherMetadata{ + Symbol: "SRF", + Balance: "200", + Decimal: "6", + Address: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", + } + + // Execute the function being tested + err = StoreTemporaryVoucher(ctx, store, sessionId, voucherData) + assert.NoError(t, err) + + // Verify stored data + expectedEntries := map[DataTyp][]byte{ + DATA_TEMPORARY_SYM: []byte("SRF"), + DATA_TEMPORARY_BAL: []byte("200"), + DATA_TEMPORARY_DECIMAL: []byte("6"), + DATA_TEMPORARY_ADDRESS: []byte("0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9"), + } + + for key, expectedValue := range expectedEntries { + storedValue, err := store.ReadEntry(ctx, sessionId, key) + assert.NoError(t, err) + assert.Equal(t, expectedValue, storedValue, "Mismatch for key %v", key) + } +} + +func TestGetTemporaryVoucherData(t *testing.T) { + sessionId := "session123" + ctx := context.WithValue(context.Background(), "SessionId", sessionId) + + // Initialize memDb + db := memdb.NewMemDb() + err := db.Connect(ctx, "") + require.NoError(t, err) + defer db.Close() + + // Create UserDataStore with memDb + store := &UserDataStore{ + Db: db, + } + + // Test voucher data + tempData := &VoucherMetadata{ + Symbol: "SRF", + Balance: "200", + Decimal: "6", + Address: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", + } + + // store the data + err = StoreTemporaryVoucher(ctx, store, sessionId, tempData) + assert.NoError(t, err) + + // Execute the function being tested + data, err := GetTemporaryVoucherData(ctx, store, sessionId) + assert.NoError(t, err) + assert.Equal(t, tempData, data) +} + +func TestUpdateVoucherData(t *testing.T) { + sessionId := "session123" + ctx := context.WithValue(context.Background(), "SessionId", sessionId) + + // Initialize memDb + db := memdb.NewMemDb() + err := db.Connect(ctx, "") + require.NoError(t, err) + defer db.Close() + + store := &UserDataStore{ + Db: db, + } + + // Test data + data := &VoucherMetadata{ + Symbol: "SRF", + Balance: "200", + Decimal: "6", + Address: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", + } + + // First store some temporary data to verify it gets cleared + tempData := &VoucherMetadata{ + Symbol: "OLD", + Balance: "100", + Decimal: "8", + Address: "0xold", + } + err = StoreTemporaryVoucher(ctx, store, sessionId, tempData) + require.NoError(t, err) + + // Execute update + err = UpdateVoucherData(ctx, store, sessionId, data) + assert.NoError(t, err) + + // Verify active data was stored correctly + activeEntries := map[DataTyp][]byte{ + DATA_ACTIVE_SYM: []byte(data.Symbol), + DATA_ACTIVE_BAL: []byte(data.Balance), + DATA_ACTIVE_DECIMAL: []byte(data.Decimal), + DATA_ACTIVE_ADDRESS: []byte(data.Address), + } + + for key, expectedValue := range activeEntries { + storedValue, err := store.ReadEntry(ctx, sessionId, key) + assert.NoError(t, err) + assert.Equal(t, expectedValue, storedValue, "Active data mismatch for key %v", key) + } + + // Verify temporary data was cleared + tempKeys := []DataTyp{ + DATA_TEMPORARY_SYM, + DATA_TEMPORARY_BAL, + DATA_TEMPORARY_DECIMAL, + DATA_TEMPORARY_ADDRESS, + } + + for _, key := range tempKeys { + storedValue, err := store.ReadEntry(ctx, sessionId, key) + assert.NoError(t, err) + AssertEmptyValue(t, storedValue, "Temporary data not cleared for key %v", key) + } +} \ No newline at end of file From cb997159f785e796f9d2bdb1ab7f58cae46d99f7 Mon Sep 17 00:00:00 2001 From: lash Date: Wed, 30 Oct 2024 00:59:59 +0000 Subject: [PATCH 146/289] Add reverse sessionid address lookup --- common/hex.go | 18 ++++++++++++++++++ internal/handlers/ussd/menuhandler.go | 13 +++++++++++-- internal/handlers/ussd/menuhandler_test.go | 12 ++++++++++-- internal/utils/db.go | 1 + 4 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 common/hex.go diff --git a/common/hex.go b/common/hex.go new file mode 100644 index 0000000..f5aa7ed --- /dev/null +++ b/common/hex.go @@ -0,0 +1,18 @@ +package common + +import ( + "encoding/hex" +) + +func NormalizeHex(s string) (string, error) { + if len(s) >= 2 { + if s[:2] == "0x" { + s = s[2:] + } + } + r, err := hex.DecodeString(s) + if err != nil { + return "", err + } + return hex.EncodeToString(r), nil +} diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 7bc8250..dae4236 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -21,6 +21,7 @@ import ( "git.defalsify.org/vise.git/state" "git.grassecon.net/urdt/ussd/internal/handlers/server" "git.grassecon.net/urdt/ussd/internal/utils" + "git.grassecon.net/urdt/ussd/common" "gopkg.in/leonelquinteros/gotext.v1" "git.grassecon.net/urdt/ussd/internal/storage" @@ -154,13 +155,21 @@ func (h *Handlers) createAccountNoExist(ctx context.Context, sessionId string, r utils.DATA_TRACKING_ID: trackingId, utils.DATA_PUBLIC_KEY: publicKey, } + store := h.userdataStore for key, value := range data { - store := h.userdataStore - err := store.WriteEntry(ctx, sessionId, key, []byte(value)) + err = store.WriteEntry(ctx, sessionId, key, []byte(value)) if err != nil { return err } } + publicKeyNormalized, err := common.NormalizeHex(publicKey) + if err != nil { + return err + } + err = store.WriteEntry(ctx, publicKeyNormalized, utils.DATA_PUBLIC_KEY_REVERSE, []byte(sessionId)) + if err != nil { + return err + } res.FlagSet = append(res.FlagSet, flag_account_created) return nil diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 28d25e8..0b70e80 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -20,6 +20,7 @@ import ( "git.grassecon.net/urdt/ussd/internal/testutil/testservice" "git.grassecon.net/urdt/ussd/internal/utils" + "git.grassecon.net/urdt/ussd/common" "github.com/alecthomas/assert/v2" "github.com/grassrootseconomics/eth-custodial/pkg/api" testdataloader "github.com/peteole/testdata-loader" @@ -96,7 +97,7 @@ func TestCreateAccount(t *testing.T) { Description: "Account creation successed", Result: map[string]any{ "trackingId": "1234567890", - "publicKey": "1235QERYU", + "publicKey": "0xD3adB33f", }, }, expectedResult: resource.Result{ @@ -117,9 +118,10 @@ func TestCreateAccount(t *testing.T) { flagManager: fm.parser, } + publicKey := tt.serverResponse.Result["publicKey"].(string) data := map[utils.DataTyp]string{ utils.DATA_TRACKING_ID: tt.serverResponse.Result["trackingId"].(string), - utils.DATA_PUBLIC_KEY: tt.serverResponse.Result["publicKey"].(string), + utils.DATA_PUBLIC_KEY: publicKey, } mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACCOUNT_CREATED).Return([]byte(""), notFoundErr) @@ -128,6 +130,12 @@ func TestCreateAccount(t *testing.T) { for key, value := range data { mockDataStore.On("WriteEntry", ctx, sessionId, key, []byte(value)).Return(nil) } + publicKeyNormalized, err := common.NormalizeHex(publicKey) + if err != nil { + t.Fatal(err) + } + + mockDataStore.On("WriteEntry", ctx, publicKeyNormalized, utils.DATA_PUBLIC_KEY_REVERSE, []byte(sessionId)).Return(nil) // Call the method you want to test res, err := h.CreateAccount(ctx, "create_account", []byte("some-input")) diff --git a/internal/utils/db.go b/internal/utils/db.go index 45e7681..2c1e6fa 100644 --- a/internal/utils/db.go +++ b/internal/utils/db.go @@ -28,6 +28,7 @@ const ( DATA_ACTIVE_SYM DATA_TEMPORARY_BAL DATA_ACTIVE_BAL + DATA_PUBLIC_KEY_REVERSE ) func typToBytes(typ DataTyp) []byte { From dd764a2e24514b9799e78973c7ccb80c510f1593 Mon Sep 17 00:00:00 2001 From: lash Date: Wed, 30 Oct 2024 01:28:55 +0000 Subject: [PATCH 147/289] Export db datatypes,tools --- {internal/utils => common}/db.go | 2 +- internal/handlers/ussd/menuhandler.go | 108 ++++++++++----------- internal/handlers/ussd/menuhandler_test.go | 97 +++++++++--------- internal/testutil/mocks/userdbmock.go | 6 +- internal/utils/userStore.go | 14 +-- 5 files changed, 114 insertions(+), 113 deletions(-) rename {internal/utils => common}/db.go (97%) diff --git a/internal/utils/db.go b/common/db.go similarity index 97% rename from internal/utils/db.go rename to common/db.go index 2c1e6fa..349d3aa 100644 --- a/internal/utils/db.go +++ b/common/db.go @@ -1,4 +1,4 @@ -package utils +package common import ( "encoding/binary" diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index dae4236..e2bcfaf 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -151,9 +151,9 @@ func (h *Handlers) createAccountNoExist(ctx context.Context, sessionId string, r trackingId := okResponse.Result["trackingId"].(string) publicKey := okResponse.Result["publicKey"].(string) - data := map[utils.DataTyp]string{ - utils.DATA_TRACKING_ID: trackingId, - utils.DATA_PUBLIC_KEY: publicKey, + data := map[common.DataTyp]string{ + common.DATA_TRACKING_ID: trackingId, + common.DATA_PUBLIC_KEY: publicKey, } store := h.userdataStore for key, value := range data { @@ -166,7 +166,7 @@ func (h *Handlers) createAccountNoExist(ctx context.Context, sessionId string, r if err != nil { return err } - err = store.WriteEntry(ctx, publicKeyNormalized, utils.DATA_PUBLIC_KEY_REVERSE, []byte(sessionId)) + err = store.WriteEntry(ctx, publicKeyNormalized, common.DATA_PUBLIC_KEY_REVERSE, []byte(sessionId)) if err != nil { return err } @@ -186,7 +186,7 @@ func (h *Handlers) CreateAccount(ctx context.Context, sym string, input []byte) return res, fmt.Errorf("missing session") } store := h.userdataStore - _, err = store.ReadEntry(ctx, sessionId, utils.DATA_ACCOUNT_CREATED) + _, err = store.ReadEntry(ctx, sessionId, common.DATA_ACCOUNT_CREATED) if err != nil { if db.IsNotFound(err) { logg.Printf(logging.LVL_INFO, "Creating an account because it doesn't exist") @@ -242,7 +242,7 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt res.FlagReset = append(res.FlagReset, flag_incorrect_pin) store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_PIN, []byte(accountPIN)) + err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_PIN, []byte(accountPIN)) if err != nil { return res, err } @@ -259,7 +259,7 @@ func (h *Handlers) ConfirmPinChange(ctx context.Context, sym string, input []byt flag_pin_mismatch, _ := h.flagManager.GetFlag("flag_pin_mismatch") store := h.userdataStore - temporaryPin, err := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_PIN) + temporaryPin, err := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_PIN) if err != nil { return res, err } @@ -268,7 +268,7 @@ func (h *Handlers) ConfirmPinChange(ctx context.Context, sym string, input []byt } else { res.FlagSet = append(res.FlagSet, flag_pin_mismatch) } - err = store.WriteEntry(ctx, sessionId, utils.DATA_ACCOUNT_PIN, []byte(temporaryPin)) + err = store.WriteEntry(ctx, sessionId, common.DATA_ACCOUNT_PIN, []byte(temporaryPin)) if err != nil { return res, err } @@ -290,7 +290,7 @@ func (h *Handlers) VerifyCreatePin(ctx context.Context, sym string, input []byte return res, fmt.Errorf("missing session") } store := h.userdataStore - temporaryPin, err := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_PIN) + temporaryPin, err := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_PIN) if err != nil { return res, err } @@ -303,7 +303,7 @@ func (h *Handlers) VerifyCreatePin(ctx context.Context, sym string, input []byte res.FlagSet = []uint32{flag_pin_mismatch} } - err = store.WriteEntry(ctx, sessionId, utils.DATA_ACCOUNT_PIN, []byte(temporaryPin)) + err = store.WriteEntry(ctx, sessionId, common.DATA_ACCOUNT_PIN, []byte(temporaryPin)) if err != nil { return res, err } @@ -335,7 +335,7 @@ func (h *Handlers) SaveFirstname(ctx context.Context, sym string, input []byte) } firstName := string(input) store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_FIRST_NAME, []byte(firstName)) + err = store.WriteEntry(ctx, sessionId, common.DATA_FIRST_NAME, []byte(firstName)) if err != nil { return res, err } @@ -358,7 +358,7 @@ func (h *Handlers) SaveFamilyname(ctx context.Context, sym string, input []byte) } familyName := string(input) store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_FAMILY_NAME, []byte(familyName)) + err = store.WriteEntry(ctx, sessionId, common.DATA_FAMILY_NAME, []byte(familyName)) if err != nil { return res, err } @@ -380,7 +380,7 @@ func (h *Handlers) SaveYob(ctx context.Context, sym string, input []byte) (resou if len(input) == 4 { yob := string(input) store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_YOB, []byte(yob)) + err = store.WriteEntry(ctx, sessionId, common.DATA_YOB, []byte(yob)) if err != nil { return res, err } @@ -403,7 +403,7 @@ func (h *Handlers) SaveLocation(ctx context.Context, sym string, input []byte) ( } location := string(input) store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_LOCATION, []byte(location)) + err = store.WriteEntry(ctx, sessionId, common.DATA_LOCATION, []byte(location)) if err != nil { return res, err } @@ -426,7 +426,7 @@ func (h *Handlers) SaveGender(ctx context.Context, sym string, input []byte) (re } gender := strings.Split(symbol, "_")[1] store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_GENDER, []byte(gender)) + err = store.WriteEntry(ctx, sessionId, common.DATA_GENDER, []byte(gender)) if err != nil { return res, nil } @@ -445,7 +445,7 @@ func (h *Handlers) SaveOfferings(ctx context.Context, sym string, input []byte) if len(input) > 0 { offerings := string(input) store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_OFFERINGS, []byte(offerings)) + err = store.WriteEntry(ctx, sessionId, common.DATA_OFFERINGS, []byte(offerings)) if err != nil { return res, nil } @@ -481,7 +481,7 @@ func (h *Handlers) CheckIdentifier(ctx context.Context, sym string, input []byte return res, fmt.Errorf("missing session") } store := h.userdataStore - publicKey, _ := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) + publicKey, _ := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) res.Content = string(publicKey) @@ -502,7 +502,7 @@ func (h *Handlers) Authorize(ctx context.Context, sym string, input []byte) (res flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") store := h.userdataStore - AccountPin, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACCOUNT_PIN) + AccountPin, err := store.ReadEntry(ctx, sessionId, common.DATA_ACCOUNT_PIN) if err != nil { return res, err } @@ -548,7 +548,7 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b return res, fmt.Errorf("missing session") } store := h.userdataStore - publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) + publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) if err != nil { return res, err } @@ -654,7 +654,7 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) ( store := h.userdataStore // get the active sym and active balance - activeSym, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM) + activeSym, err := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_SYM) if err != nil { if db.IsNotFound(err) { balance := "0.00" @@ -665,7 +665,7 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) ( return res, err } - activeBal, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_BAL) + activeBal, err := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_BAL) if err != nil { return res, err } @@ -687,7 +687,7 @@ func (h *Handlers) FetchCustodialBalances(ctx context.Context, sym string, input balanceType := strings.Split(symbol, "_")[0] store := h.userdataStore - publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) + publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) if err != nil { return res, err } @@ -737,7 +737,7 @@ func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []by return res, nil } store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_RECIPIENT, []byte(recipient)) + err = store.WriteEntry(ctx, sessionId, common.DATA_RECIPIENT, []byte(recipient)) if err != nil { return res, nil } @@ -760,12 +760,12 @@ func (h *Handlers) TransactionReset(ctx context.Context, sym string, input []byt flag_invalid_recipient, _ := h.flagManager.GetFlag("flag_invalid_recipient") flag_invalid_recipient_with_invite, _ := h.flagManager.GetFlag("flag_invalid_recipient_with_invite") store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_AMOUNT, []byte("")) + err = store.WriteEntry(ctx, sessionId, common.DATA_AMOUNT, []byte("")) if err != nil { return res, nil } - err = store.WriteEntry(ctx, sessionId, utils.DATA_RECIPIENT, []byte("")) + err = store.WriteEntry(ctx, sessionId, common.DATA_RECIPIENT, []byte("")) if err != nil { return res, nil } @@ -787,7 +787,7 @@ func (h *Handlers) ResetTransactionAmount(ctx context.Context, sym string, input flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount") store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_AMOUNT, []byte("")) + err = store.WriteEntry(ctx, sessionId, common.DATA_AMOUNT, []byte("")) if err != nil { return res, nil } @@ -809,7 +809,7 @@ func (h *Handlers) MaxAmount(ctx context.Context, sym string, input []byte) (res } store := h.userdataStore - activeBal, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_BAL) + activeBal, err := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_BAL) if err != nil { return res, err } @@ -834,7 +834,7 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte) var balanceValue float64 // retrieve the active balance - activeBal, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_BAL) + activeBal, err := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_BAL) if err != nil { return res, err } @@ -860,7 +860,7 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte) // Format the amount with 2 decimal places before saving formattedAmount := fmt.Sprintf("%.2f", inputAmount) - err = store.WriteEntry(ctx, sessionId, utils.DATA_AMOUNT, []byte(formattedAmount)) + err = store.WriteEntry(ctx, sessionId, common.DATA_AMOUNT, []byte(formattedAmount)) if err != nil { return res, err } @@ -878,7 +878,7 @@ func (h *Handlers) GetRecipient(ctx context.Context, sym string, input []byte) ( return res, fmt.Errorf("missing session") } store := h.userdataStore - recipient, _ := store.ReadEntry(ctx, sessionId, utils.DATA_RECIPIENT) + recipient, _ := store.ReadEntry(ctx, sessionId, common.DATA_RECIPIENT) res.Content = string(recipient) @@ -910,12 +910,12 @@ func (h *Handlers) GetAmount(ctx context.Context, sym string, input []byte) (res store := h.userdataStore // retrieve the active symbol - activeSym, err := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM) + activeSym, err := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_SYM) if err != nil { return res, err } - amount, _ := store.ReadEntry(ctx, sessionId, utils.DATA_AMOUNT) + amount, _ := store.ReadEntry(ctx, sessionId, common.DATA_AMOUNT) res.Content = fmt.Sprintf("%s %s", string(amount), string(activeSym)) @@ -939,11 +939,11 @@ func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input [] // Use the amount, recipient and sender to call the API and initialize the transaction store := h.userdataStore - amount, _ := store.ReadEntry(ctx, sessionId, utils.DATA_AMOUNT) + amount, _ := store.ReadEntry(ctx, sessionId, common.DATA_AMOUNT) - recipient, _ := store.ReadEntry(ctx, sessionId, utils.DATA_RECIPIENT) + recipient, _ := store.ReadEntry(ctx, sessionId, common.DATA_RECIPIENT) - activeSym, _ := store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM) + activeSym, _ := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_SYM) res.Content = l.Get("Your request has been sent. %s will receive %s %s from %s.", string(recipient), string(amount), string(activeSym), string(sessionId)) @@ -983,12 +983,12 @@ func (h *Handlers) GetProfileInfo(ctx context.Context, sym string, input []byte) } store := h.userdataStore // Retrieve user data as strings with fallback to defaultValue - firstName := getEntryOrDefault(store.ReadEntry(ctx, sessionId, utils.DATA_FIRST_NAME)) - familyName := getEntryOrDefault(store.ReadEntry(ctx, sessionId, utils.DATA_FAMILY_NAME)) - yob := getEntryOrDefault(store.ReadEntry(ctx, sessionId, utils.DATA_YOB)) - gender := getEntryOrDefault(store.ReadEntry(ctx, sessionId, utils.DATA_GENDER)) - location := getEntryOrDefault(store.ReadEntry(ctx, sessionId, utils.DATA_LOCATION)) - offerings := getEntryOrDefault(store.ReadEntry(ctx, sessionId, utils.DATA_OFFERINGS)) + firstName := getEntryOrDefault(store.ReadEntry(ctx, sessionId, common.DATA_FIRST_NAME)) + familyName := getEntryOrDefault(store.ReadEntry(ctx, sessionId, common.DATA_FAMILY_NAME)) + yob := getEntryOrDefault(store.ReadEntry(ctx, sessionId, common.DATA_YOB)) + gender := getEntryOrDefault(store.ReadEntry(ctx, sessionId, common.DATA_GENDER)) + location := getEntryOrDefault(store.ReadEntry(ctx, sessionId, common.DATA_LOCATION)) + offerings := getEntryOrDefault(store.ReadEntry(ctx, sessionId, common.DATA_OFFERINGS)) // Construct the full name name := defaultValue @@ -1045,11 +1045,11 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by flag_no_active_voucher, _ := h.flagManager.GetFlag("flag_no_active_voucher") // check if the user has an active sym - _, err = store.ReadEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM) + _, err = store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_SYM) if err != nil { if db.IsNotFound(err) { - publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) + publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) if err != nil { return res, nil } @@ -1072,12 +1072,12 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by defaultBal := firstVoucher.Balance // set the active symbol - err = store.WriteEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM, []byte(defaultSym)) + err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_SYM, []byte(defaultSym)) if err != nil { return res, err } // set the active balance - err = store.WriteEntry(ctx, sessionId, utils.DATA_ACTIVE_BAL, []byte(defaultBal)) + err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_BAL, []byte(defaultBal)) if err != nil { return res, err } @@ -1103,7 +1103,7 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) } store := h.userdataStore - publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) + publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) if err != nil { return res, nil } @@ -1207,11 +1207,11 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r // If a match is found, write the temporary sym and balance if matchedSymbol != "" && matchedBalance != "" { - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_SYM, []byte(matchedSymbol)) + err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_SYM, []byte(matchedSymbol)) if err != nil { return res, err } - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_BAL, []byte(matchedBalance)) + err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_BAL, []byte(matchedBalance)) if err != nil { return res, err } @@ -1269,34 +1269,34 @@ func (h *Handlers) SetVoucher(ctx context.Context, sym string, input []byte) (re } // get the current temporary symbol - temporarySym, err := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_SYM) + temporarySym, err := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_SYM) if err != nil { return res, err } // get the current temporary balance - temporaryBal, err := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_BAL) + temporaryBal, err := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_BAL) if err != nil { return res, err } // set the active symbol - err = store.WriteEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM, []byte(temporarySym)) + err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_SYM, []byte(temporarySym)) if err != nil { return res, err } // set the active balance - err = store.WriteEntry(ctx, sessionId, utils.DATA_ACTIVE_BAL, []byte(temporaryBal)) + err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_BAL, []byte(temporaryBal)) if err != nil { return res, err } // reset the temporary symbol - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_SYM, []byte("")) + err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_SYM, []byte("")) if err != nil { return res, err } // reset the temporary balance - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_BAL, []byte("")) + err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_BAL, []byte("")) if err != nil { return res, err } diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 0b70e80..b83fa61 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -19,7 +19,6 @@ import ( "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/common" "github.com/alecthomas/assert/v2" "github.com/grassrootseconomics/eth-custodial/pkg/api" @@ -119,12 +118,12 @@ func TestCreateAccount(t *testing.T) { } publicKey := tt.serverResponse.Result["publicKey"].(string) - data := map[utils.DataTyp]string{ - utils.DATA_TRACKING_ID: tt.serverResponse.Result["trackingId"].(string), - utils.DATA_PUBLIC_KEY: publicKey, + data := map[common.DataTyp]string{ + common.DATA_TRACKING_ID: tt.serverResponse.Result["trackingId"].(string), + common.DATA_PUBLIC_KEY: publicKey, } - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACCOUNT_CREATED).Return([]byte(""), notFoundErr) + mockDataStore.On("ReadEntry", ctx, sessionId, common.DATA_ACCOUNT_CREATED).Return([]byte(""), notFoundErr) mockCreateAccountService.On("CreateAccount").Return(tt.serverResponse, nil) for key, value := range data { @@ -135,7 +134,7 @@ func TestCreateAccount(t *testing.T) { t.Fatal(err) } - mockDataStore.On("WriteEntry", ctx, publicKeyNormalized, utils.DATA_PUBLIC_KEY_REVERSE, []byte(sessionId)).Return(nil) + mockDataStore.On("WriteEntry", ctx, publicKeyNormalized, common.DATA_PUBLIC_KEY_REVERSE, []byte(sessionId)).Return(nil) // Call the method you want to test res, err := h.CreateAccount(ctx, "create_account", []byte("some-input")) @@ -181,7 +180,7 @@ func TestSaveFirstname(t *testing.T) { 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) + mockStore.On("WriteEntry", ctx, sessionId, common.DATA_FIRST_NAME, []byte(firstName)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ @@ -209,7 +208,7 @@ func TestSaveFamilyname(t *testing.T) { 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) + mockStore.On("WriteEntry", ctx, sessionId, common.DATA_FAMILY_NAME, []byte(familyName)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ @@ -269,7 +268,7 @@ func TestSaveTemporaryPin(t *testing.T) { t.Run(tt.name, func(t *testing.T) { // Set up the expected behavior of the mock - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_PIN, []byte(tt.input)).Return(nil) + mockStore.On("WriteEntry", ctx, sessionId, common.DATA_TEMPORARY_PIN, []byte(tt.input)).Return(nil) // Call the method res, err := h.SaveTemporaryPin(ctx, "save_pin", tt.input) @@ -295,7 +294,7 @@ func TestSaveYoB(t *testing.T) { 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) + mockStore.On("WriteEntry", ctx, sessionId, common.DATA_YOB, []byte(yob)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ @@ -323,7 +322,7 @@ func TestSaveLocation(t *testing.T) { 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) + mockStore.On("WriteEntry", ctx, sessionId, common.DATA_LOCATION, []byte(yob)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ @@ -351,7 +350,7 @@ func TestSaveOfferings(t *testing.T) { ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Set up the expected behavior of the mock - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_OFFERINGS, []byte(offerings)).Return(nil) + mockStore.On("WriteEntry", ctx, sessionId, common.DATA_OFFERINGS, []byte(offerings)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ @@ -413,10 +412,10 @@ func TestSaveGender(t *testing.T) { t.Run(tt.name, func(t *testing.T) { // Set up expectations for the mock database if tt.expectCall { - expectedKey := utils.DATA_GENDER + expectedKey := common.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) + mockStore.On("WriteEntry", ctx, sessionId, common.DATA_GENDER, []byte(tt.expectedGender)).Return(nil) } mockState.ExecPath = append(mockState.ExecPath, tt.executingSymbol) // Create the Handlers instance with the mock store @@ -433,9 +432,9 @@ func TestSaveGender(t *testing.T) { // Verify expectations if tt.expectCall { - mockStore.AssertCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_GENDER, []byte(tt.expectedGender)) + mockStore.AssertCalled(t, "WriteEntry", ctx, sessionId, common.DATA_GENDER, []byte(tt.expectedGender)) } else { - mockStore.AssertNotCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_GENDER, []byte(tt.expectedGender)) + mockStore.AssertNotCalled(t, "WriteEntry", ctx, sessionId, common.DATA_GENDER, []byte(tt.expectedGender)) } }) } @@ -469,7 +468,7 @@ func TestCheckIdentifier(t *testing.T) { 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) + mockStore.On("ReadEntry", ctx, sessionId, common.DATA_PUBLIC_KEY).Return(tt.mockPublicKey, tt.mockErr) // Create the Handlers instance with the mock store h := &Handlers{ @@ -519,8 +518,8 @@ func TestGetAmount(t *testing.T) { activeSym := "SRF" // Set up the expected behavior of the mock - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM).Return([]byte(activeSym), nil) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_AMOUNT).Return([]byte(amount), nil) + mockDataStore.On("ReadEntry", ctx, sessionId, common.DATA_ACTIVE_SYM).Return([]byte(activeSym), nil) + mockDataStore.On("ReadEntry", ctx, sessionId, common.DATA_AMOUNT).Return([]byte(amount), nil) // Create the Handlers instance with the mock store h := &Handlers{ @@ -546,7 +545,7 @@ func TestGetRecipient(t *testing.T) { recepient := "0xcasgatweksalw1018221" // Set up the expected behavior of the mock - mockStore.On("ReadEntry", ctx, sessionId, utils.DATA_RECIPIENT).Return([]byte(recepient), nil) + mockStore.On("ReadEntry", ctx, sessionId, common.DATA_RECIPIENT).Return([]byte(recepient), nil) // Create the Handlers instance with the mock store h := &Handlers{ @@ -828,7 +827,7 @@ func TestAuthorize(t *testing.T) { // Define session ID and mock data sessionId := "session123" - typ := utils.DATA_ACCOUNT_PIN + typ := common.DATA_ACCOUNT_PIN h := &Handlers{ userdataStore: mockDataStore, @@ -1011,7 +1010,7 @@ func TestVerifyCreatePin(t *testing.T) { }, } - typ := utils.DATA_TEMPORARY_PIN + typ := common.DATA_TEMPORARY_PIN for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -1020,7 +1019,7 @@ func TestVerifyCreatePin(t *testing.T) { mockDataStore.On("ReadEntry", ctx, sessionId, typ).Return([]byte(firstSetPin), nil) // Set up the expected behavior of the mock - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACCOUNT_PIN, []byte(firstSetPin)).Return(nil) + mockDataStore.On("WriteEntry", ctx, sessionId, common.DATA_ACCOUNT_PIN, []byte(firstSetPin)).Return(nil) // Call the method under test res, err := h.VerifyCreatePin(ctx, "verify_create_pin", []byte(tt.input)) @@ -1141,11 +1140,11 @@ func TestCheckAccountStatus(t *testing.T) { status := tt.response.Result.Transaction.Status // Define expected interactions with the mock - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return(tt.input, nil) + mockDataStore.On("ReadEntry", ctx, sessionId, common.DATA_PUBLIC_KEY).Return(tt.input, nil) mockCreateAccountService.On("CheckAccountStatus", string(tt.input)).Return(tt.response, nil) mockCreateAccountService.On("TrackAccountStatus", string(tt.input)).Return(tt.serverResponse, nil) - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACCOUNT_STATUS, []byte(status)).Return(nil).Maybe() + mockDataStore.On("WriteEntry", ctx, sessionId, common.DATA_ACCOUNT_STATUS, []byte(status)).Return(nil).Maybe() // Call the method under test res, _ := h.CheckAccountStatus(ctx, "check_account_status", tt.input) @@ -1201,8 +1200,8 @@ func TestTransactionReset(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_AMOUNT, []byte("")).Return(nil) - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_RECIPIENT, []byte("")).Return(nil) + mockDataStore.On("WriteEntry", ctx, sessionId, common.DATA_AMOUNT, []byte("")).Return(nil) + mockDataStore.On("WriteEntry", ctx, sessionId, common.DATA_RECIPIENT, []byte("")).Return(nil) // Call the method under test res, _ := h.TransactionReset(ctx, "transaction_reset", tt.input) @@ -1257,7 +1256,7 @@ func TestResetInvalidAmount(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_AMOUNT, []byte("")).Return(nil) + mockDataStore.On("WriteEntry", ctx, sessionId, common.DATA_AMOUNT, []byte("")).Return(nil) // Call the method under test res, _ := h.ResetTransactionAmount(ctx, "transaction_reset_amount", tt.input) @@ -1320,9 +1319,9 @@ func TestInitiateTransaction(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Define expected interactions with the mock - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_AMOUNT).Return(tt.Amount, nil) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_RECIPIENT).Return(tt.Recipient, nil) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM).Return(tt.ActiveSym, nil) + mockDataStore.On("ReadEntry", ctx, sessionId, common.DATA_AMOUNT).Return(tt.Amount, nil) + mockDataStore.On("ReadEntry", ctx, sessionId, common.DATA_RECIPIENT).Return(tt.Recipient, nil) + mockDataStore.On("ReadEntry", ctx, sessionId, common.DATA_ACTIVE_SYM).Return(tt.ActiveSym, nil) // Call the method under test res, _ := h.InitiateTransaction(ctx, "transaction_reset_amount", tt.input) @@ -1502,10 +1501,10 @@ func TestValidateAmount(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Mock behavior for active balance retrieval - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACTIVE_BAL).Return(tt.activeBal, nil) + mockDataStore.On("ReadEntry", ctx, sessionId, common.DATA_ACTIVE_BAL).Return(tt.activeBal, nil) // Mock behavior for storing the amount (if valid) - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_AMOUNT, tt.input).Return(nil).Maybe() + mockDataStore.On("WriteEntry", ctx, sessionId, common.DATA_AMOUNT, tt.input).Return(nil).Maybe() // Call the method under test res, _ := h.ValidateAmount(ctx, "test_validate_amount", tt.input) @@ -1559,7 +1558,7 @@ func TestValidateRecipient(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_RECIPIENT, tt.input).Return(nil) + mockDataStore.On("WriteEntry", ctx, sessionId, common.DATA_RECIPIENT, tt.input).Return(nil) // Create the Handlers instance with the mock flag manager h := &Handlers{ @@ -1613,8 +1612,8 @@ func TestCheckBalance(t *testing.T) { } // Mock for user with active sym - mockDataStore.On("ReadEntry", ctx, tt.sessionId, utils.DATA_ACTIVE_SYM).Return([]byte(tt.activeSym), nil) - mockDataStore.On("ReadEntry", ctx, tt.sessionId, utils.DATA_ACTIVE_BAL).Return([]byte(tt.activeBal), nil) + mockDataStore.On("ReadEntry", ctx, tt.sessionId, common.DATA_ACTIVE_SYM).Return([]byte(tt.activeSym), nil) + mockDataStore.On("ReadEntry", ctx, tt.sessionId, common.DATA_ACTIVE_BAL).Return([]byte(tt.activeBal), nil) res, err := h.CheckBalance(ctx, "check_balance", []byte("")) @@ -1648,13 +1647,13 @@ func TestGetProfile(t *testing.T) { tests := []struct { name string languageCode string - keys []utils.DataTyp + keys []common.DataTyp profileInfo []string result resource.Result }{ { name: "Test with full profile information in eng", - keys: []utils.DataTyp{utils.DATA_FAMILY_NAME, utils.DATA_FIRST_NAME, utils.DATA_GENDER, utils.DATA_OFFERINGS, utils.DATA_LOCATION, utils.DATA_YOB}, + keys: []common.DataTyp{common.DATA_FAMILY_NAME, common.DATA_FIRST_NAME, common.DATA_GENDER, common.DATA_OFFERINGS, common.DATA_LOCATION, common.DATA_YOB}, profileInfo: []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976"}, languageCode: "eng", result: resource.Result{ @@ -1666,7 +1665,7 @@ func TestGetProfile(t *testing.T) { }, { name: "Test with with profile information in swa ", - keys: []utils.DataTyp{utils.DATA_FAMILY_NAME, utils.DATA_FIRST_NAME, utils.DATA_GENDER, utils.DATA_OFFERINGS, utils.DATA_LOCATION, utils.DATA_YOB}, + keys: []common.DataTyp{common.DATA_FAMILY_NAME, common.DATA_FIRST_NAME, common.DATA_GENDER, common.DATA_OFFERINGS, common.DATA_LOCATION, common.DATA_YOB}, profileInfo: []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976"}, languageCode: "swa", result: resource.Result{ @@ -1678,7 +1677,7 @@ func TestGetProfile(t *testing.T) { }, { name: "Test with with profile information with language that is not yet supported", - keys: []utils.DataTyp{utils.DATA_FAMILY_NAME, utils.DATA_FIRST_NAME, utils.DATA_GENDER, utils.DATA_OFFERINGS, utils.DATA_LOCATION, utils.DATA_YOB}, + keys: []common.DataTyp{common.DATA_FAMILY_NAME, common.DATA_FIRST_NAME, common.DATA_GENDER, common.DATA_OFFERINGS, common.DATA_LOCATION, common.DATA_YOB}, profileInfo: []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976"}, languageCode: "nor", result: resource.Result{ @@ -1802,9 +1801,9 @@ func TestConfirmPin(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Set up the expected behavior of the mock - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACCOUNT_PIN, []byte(tt.temporarypin)).Return(nil) + mockDataStore.On("WriteEntry", ctx, sessionId, common.DATA_ACCOUNT_PIN, []byte(tt.temporarypin)).Return(nil) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_PIN).Return(tt.temporarypin, nil) + mockDataStore.On("ReadEntry", ctx, sessionId, common.DATA_TEMPORARY_PIN).Return(tt.temporarypin, nil) //Call the function under test res, _ := h.ConfirmPinChange(ctx, "confirm_pin_change", tt.temporarypin) @@ -1829,12 +1828,12 @@ func TestSetVoucher(t *testing.T) { temporaryBal := []byte("tempBal") // Set expectations for the mock data store - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_SYM).Return(temporarySym, nil) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_BAL).Return(temporaryBal, nil) - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM, temporarySym).Return(nil) - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_BAL, temporaryBal).Return(nil) - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_SYM, []byte("")).Return(nil) - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_BAL, []byte("")).Return(nil) + mockDataStore.On("ReadEntry", ctx, sessionId, common.DATA_TEMPORARY_SYM).Return(temporarySym, nil) + mockDataStore.On("ReadEntry", ctx, sessionId, common.DATA_TEMPORARY_BAL).Return(temporaryBal, nil) + mockDataStore.On("WriteEntry", ctx, sessionId, common.DATA_ACTIVE_SYM, temporarySym).Return(nil) + mockDataStore.On("WriteEntry", ctx, sessionId, common.DATA_ACTIVE_BAL, temporaryBal).Return(nil) + mockDataStore.On("WriteEntry", ctx, sessionId, common.DATA_TEMPORARY_SYM, []byte("")).Return(nil) + mockDataStore.On("WriteEntry", ctx, sessionId, common.DATA_TEMPORARY_BAL, []byte("")).Return(nil) h := &Handlers{ userdataStore: mockDataStore, @@ -1919,7 +1918,7 @@ func TestFetchCustodialBalances(t *testing.T) { } // Set up the expected behavior of the mock - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil) + mockDataStore.On("ReadEntry", ctx, sessionId, common.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil) mockCreateAccountService.On("CheckBalance", string(publicKey)).Return(tt.balanceResonse, nil) // Call the method diff --git a/internal/testutil/mocks/userdbmock.go b/internal/testutil/mocks/userdbmock.go index ff3f18d..7892179 100644 --- a/internal/testutil/mocks/userdbmock.go +++ b/internal/testutil/mocks/userdbmock.go @@ -4,7 +4,7 @@ import ( "context" "git.defalsify.org/vise.git/db" - "git.grassecon.net/urdt/ussd/internal/utils" + "git.grassecon.net/urdt/ussd/common" "github.com/stretchr/testify/mock" ) @@ -13,12 +13,12 @@ type MockUserDataStore struct { mock.Mock } -func (m *MockUserDataStore) ReadEntry(ctx context.Context, sessionId string, typ utils.DataTyp) ([]byte, error) { +func (m *MockUserDataStore) ReadEntry(ctx context.Context, sessionId string, typ common.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 { +func (m *MockUserDataStore) WriteEntry(ctx context.Context, sessionId string, typ common.DataTyp, value []byte) error { args := m.Called(ctx, sessionId, typ, value) return args.Error(0) } diff --git a/internal/utils/userStore.go b/internal/utils/userStore.go index a1485b1..13682b7 100644 --- a/internal/utils/userStore.go +++ b/internal/utils/userStore.go @@ -3,13 +3,15 @@ package utils import ( "context" + "git.grassecon.net/urdt/ussd/common" + "git.defalsify.org/vise.git/db" ) type DataStore interface { db.Db - ReadEntry(ctx context.Context, sessionId string, typ DataTyp) ([]byte, error) - WriteEntry(ctx context.Context, sessionId string, typ DataTyp, value []byte) error + ReadEntry(ctx context.Context, sessionId string, typ common.DataTyp) ([]byte, error) + WriteEntry(ctx context.Context, sessionId string, typ common.DataTyp, value []byte) error } type UserDataStore struct { @@ -17,16 +19,16 @@ type UserDataStore struct { } // ReadEntry retrieves an entry from the store based on the provided parameters. -func (store *UserDataStore) ReadEntry(ctx context.Context, sessionId string, typ DataTyp) ([]byte, error) { +func (store *UserDataStore) ReadEntry(ctx context.Context, sessionId string, typ common.DataTyp) ([]byte, error) { store.SetPrefix(db.DATATYPE_USERDATA) store.SetSession(sessionId) - k := PackKey(typ, []byte(sessionId)) + k := common.PackKey(typ, []byte(sessionId)) return store.Get(ctx, k) } -func (store *UserDataStore) WriteEntry(ctx context.Context, sessionId string, typ DataTyp, value []byte) error { +func (store *UserDataStore) WriteEntry(ctx context.Context, sessionId string, typ common.DataTyp, value []byte) error { store.SetPrefix(db.DATATYPE_USERDATA) store.SetSession(sessionId) - k := PackKey(typ, []byte(sessionId)) + k := common.PackKey(typ, []byte(sessionId)) return store.Put(ctx, k, value) } From c95b97cb148114aed46a8aa84da8ec9faf2dcaee Mon Sep 17 00:00:00 2001 From: lash Date: Wed, 30 Oct 2024 01:45:38 +0000 Subject: [PATCH 148/289] Export user data store --- .../utils/userStore.go => common/user_store.go | 16 +++++++--------- internal/handlers/ussd/menuhandler.go | 4 ++-- 2 files changed, 9 insertions(+), 11 deletions(-) rename internal/utils/userStore.go => common/user_store.go (55%) diff --git a/internal/utils/userStore.go b/common/user_store.go similarity index 55% rename from internal/utils/userStore.go rename to common/user_store.go index 13682b7..8d982ab 100644 --- a/internal/utils/userStore.go +++ b/common/user_store.go @@ -1,17 +1,15 @@ -package utils +package common import ( "context" - "git.grassecon.net/urdt/ussd/common" - "git.defalsify.org/vise.git/db" ) type DataStore interface { db.Db - ReadEntry(ctx context.Context, sessionId string, typ common.DataTyp) ([]byte, error) - WriteEntry(ctx context.Context, sessionId string, typ common.DataTyp, value []byte) error + ReadEntry(ctx context.Context, sessionId string, typ DataTyp) ([]byte, error) + WriteEntry(ctx context.Context, sessionId string, typ DataTyp, value []byte) error } type UserDataStore struct { @@ -19,16 +17,16 @@ type UserDataStore struct { } // ReadEntry retrieves an entry from the store based on the provided parameters. -func (store *UserDataStore) ReadEntry(ctx context.Context, sessionId string, typ common.DataTyp) ([]byte, error) { +func (store *UserDataStore) ReadEntry(ctx context.Context, sessionId string, typ DataTyp) ([]byte, error) { store.SetPrefix(db.DATATYPE_USERDATA) store.SetSession(sessionId) - k := common.PackKey(typ, []byte(sessionId)) + k := PackKey(typ, []byte(sessionId)) return store.Get(ctx, k) } -func (store *UserDataStore) WriteEntry(ctx context.Context, sessionId string, typ common.DataTyp, value []byte) error { +func (store *UserDataStore) WriteEntry(ctx context.Context, sessionId string, typ DataTyp, value []byte) error { store.SetPrefix(db.DATATYPE_USERDATA) store.SetSession(sessionId) - k := common.PackKey(typ, []byte(sessionId)) + k := PackKey(typ, []byte(sessionId)) return store.Put(ctx, k, value) } diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index e2bcfaf..303bea9 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -63,7 +63,7 @@ type Handlers struct { pe *persist.Persister st *state.State ca cache.Memory - userdataStore utils.DataStore + userdataStore common.DataStore flagManager *asm.FlagParser accountService server.AccountServiceInterface } @@ -72,7 +72,7 @@ func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db, accountService s if userdataStore == nil { return nil, fmt.Errorf("cannot create handler with nil userdata store") } - userDb := &utils.UserDataStore{ + userDb := &common.UserDataStore{ Db: userdataStore, } h := &Handlers{ From adaa0c63ef78486223ec5e9646640599ceda685d Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 30 Oct 2024 14:12:42 +0300 Subject: [PATCH 149/289] Extract common db operations for the test --- internal/utils/vouchers_test.go | 138 ++++++++++++++------------------ 1 file changed, 62 insertions(+), 76 deletions(-) diff --git a/internal/utils/vouchers_test.go b/internal/utils/vouchers_test.go index 75ae563..f26ee01 100644 --- a/internal/utils/vouchers_test.go +++ b/internal/utils/vouchers_test.go @@ -11,6 +11,25 @@ import ( memdb "git.defalsify.org/vise.git/db/mem" ) +// InitializeTestDb sets up and returns an in-memory database and store. +func InitializeTestDb(t *testing.T) (context.Context, *UserDataStore) { + ctx := context.Background() + + // Initialize memDb + db := memdb.NewMemDb() + err := db.Connect(ctx, "") + require.NoError(t, err, "Failed to connect to memDb") + + // Create UserDataStore with memDb + store := &UserDataStore{Db: db} + + t.Cleanup(func() { + db.Close() // Ensure the DB is closed after each test + }) + + return ctx, store +} + // AssertEmptyValue checks if a value is empty/nil/zero func AssertEmptyValue(t *testing.T, value []byte, msgAndArgs ...interface{}) { assert.Equal(t, len(value), 0, msgAndArgs...) @@ -100,31 +119,20 @@ func TestGetVoucherData(t *testing.T) { } func TestStoreTemporaryVoucher(t *testing.T) { - ctx := context.Background() + ctx, store := InitializeTestDb(t) sessionId := "session123" - - // Initialize memDb - db := memdb.NewMemDb() - err := db.Connect(ctx, "") - require.NoError(t, err) - defer db.Close() - - // Create UserDataStore with memDb - store := &UserDataStore{ - Db: db, - } // Test data voucherData := &VoucherMetadata{ - Symbol: "SRF", - Balance: "200", - Decimal: "6", - Address: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", + Symbol: "SRF", + Balance: "200", + Decimal: "6", + Address: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", } // Execute the function being tested - err = StoreTemporaryVoucher(ctx, store, sessionId, voucherData) - assert.NoError(t, err) + err := StoreTemporaryVoucher(ctx, store, sessionId, voucherData) + require.NoError(t, err) // Verify stored data expectedEntries := map[DataTyp][]byte{ @@ -136,92 +144,70 @@ func TestStoreTemporaryVoucher(t *testing.T) { for key, expectedValue := range expectedEntries { storedValue, err := store.ReadEntry(ctx, sessionId, key) - assert.NoError(t, err) - assert.Equal(t, expectedValue, storedValue, "Mismatch for key %v", key) + require.NoError(t, err) + require.Equal(t, expectedValue, storedValue, "Mismatch for key %v", key) } } func TestGetTemporaryVoucherData(t *testing.T) { + ctx, store := InitializeTestDb(t) sessionId := "session123" - ctx := context.WithValue(context.Background(), "SessionId", sessionId) - - // Initialize memDb - db := memdb.NewMemDb() - err := db.Connect(ctx, "") - require.NoError(t, err) - defer db.Close() - - // Create UserDataStore with memDb - store := &UserDataStore{ - Db: db, - } // Test voucher data tempData := &VoucherMetadata{ - Symbol: "SRF", - Balance: "200", - Decimal: "6", - Address: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", + Symbol: "SRF", + Balance: "200", + Decimal: "6", + Address: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", } - // store the data - err = StoreTemporaryVoucher(ctx, store, sessionId, tempData) - assert.NoError(t, err) - + // Store the data + err := StoreTemporaryVoucher(ctx, store, sessionId, tempData) + require.NoError(t, err) + // Execute the function being tested data, err := GetTemporaryVoucherData(ctx, store, sessionId) - assert.NoError(t, err) - assert.Equal(t, tempData, data) + require.NoError(t, err) + require.Equal(t, tempData, data) } func TestUpdateVoucherData(t *testing.T) { + ctx, store := InitializeTestDb(t) sessionId := "session123" - ctx := context.WithValue(context.Background(), "SessionId", sessionId) - // Initialize memDb - db := memdb.NewMemDb() - err := db.Connect(ctx, "") - require.NoError(t, err) - defer db.Close() - - store := &UserDataStore{ - Db: db, + // New voucher data + newData := &VoucherMetadata{ + Symbol: "SRF", + Balance: "200", + Decimal: "6", + Address: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", } - // Test data - data := &VoucherMetadata{ - Symbol: "SRF", - Balance: "200", - Decimal: "6", - Address: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", - } - - // First store some temporary data to verify it gets cleared + // Old temporary data tempData := &VoucherMetadata{ - Symbol: "OLD", - Balance: "100", - Decimal: "8", - Address: "0xold", + Symbol: "OLD", + Balance: "100", + Decimal: "8", + Address: "0xold", } - err = StoreTemporaryVoucher(ctx, store, sessionId, tempData) - require.NoError(t, err) + require.NoError(t, StoreTemporaryVoucher(ctx, store, sessionId, tempData)) // Execute update - err = UpdateVoucherData(ctx, store, sessionId, data) - assert.NoError(t, err) + err := UpdateVoucherData(ctx, store, sessionId, newData) + require.NoError(t, err) // Verify active data was stored correctly activeEntries := map[DataTyp][]byte{ - DATA_ACTIVE_SYM: []byte(data.Symbol), - DATA_ACTIVE_BAL: []byte(data.Balance), - DATA_ACTIVE_DECIMAL: []byte(data.Decimal), - DATA_ACTIVE_ADDRESS: []byte(data.Address), + DATA_ACTIVE_SYM: []byte(newData.Symbol), + DATA_ACTIVE_BAL: []byte(newData.Balance), + DATA_ACTIVE_DECIMAL: []byte(newData.Decimal), + DATA_ACTIVE_ADDRESS: []byte(newData.Address), } for key, expectedValue := range activeEntries { storedValue, err := store.ReadEntry(ctx, sessionId, key) - assert.NoError(t, err) - assert.Equal(t, expectedValue, storedValue, "Active data mismatch for key %v", key) + require.NoError(t, err) + require.Equal(t, expectedValue, storedValue, "Active data mismatch for key %v", key) } // Verify temporary data was cleared @@ -234,7 +220,7 @@ func TestUpdateVoucherData(t *testing.T) { for _, key := range tempKeys { storedValue, err := store.ReadEntry(ctx, sessionId, key) - assert.NoError(t, err) + require.NoError(t, err) AssertEmptyValue(t, storedValue, "Temporary data not cleared for key %v", key) } -} \ No newline at end of file +} From b404ae95fbfa4fdec0b7c84e7c7486618a754eca Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 30 Oct 2024 14:30:38 +0300 Subject: [PATCH 150/289] setup an admin store based on fs --- internal/utils/adminstore.go | 111 ++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 53 deletions(-) diff --git a/internal/utils/adminstore.go b/internal/utils/adminstore.go index ddd6bd9..43a3bfd 100644 --- a/internal/utils/adminstore.go +++ b/internal/utils/adminstore.go @@ -1,80 +1,85 @@ package utils import ( - "bufio" - "log" + "context" + "encoding/json" "os" - "strconv" - "strings" - "git.grassecon.net/urdt/ussd/initializers" + "git.defalsify.org/vise.git/db" + fsdb "git.defalsify.org/vise.git/db/fs" + "git.defalsify.org/vise.git/logging" ) -type AdminStore struct { - filePath string +var ( + logg = logging.NewVanilla().WithDomain("adminstore") +) + +type Admin struct { + PhoneNumber string `json:"phonenumber"` } -// Creates a new Admin store -func NewAdminStore(filePath string) *AdminStore { - return &AdminStore{filePath: filePath} +type Config struct { + Admins []Admin `json:"admins"` +} + +type AdminStore struct { + ctx context.Context + fsStore db.Db +} + +func NewAdminStore(ctx context.Context, fileName string) (*AdminStore, error) { + fsStore, err := getFsStore(ctx, fileName) + if err != nil { + return nil, err + } + return &AdminStore{ctx: ctx, fsStore: fsStore}, nil +} + +func getFsStore(ctx context.Context, connectStr string) (db.Db, error) { + fsStore := fsdb.NewFsDb() + err := fsStore.Connect(ctx, connectStr) + fsStore.SetPrefix(db.DATATYPE_USERDATA) + if err != nil { + return nil, err + } + return fsStore, nil } // Seed initializes a list of phonenumbers with admin privileges func (as *AdminStore) Seed() error { - var adminNumbers []int64 + var config Config - numbersEnv := initializers.GetEnv("ADMIN_NUMBERS", "") - for _, numStr := range strings.Split(numbersEnv, ",") { - if num, err := strconv.ParseInt(strings.TrimSpace(numStr), 10, 64); err == nil { - adminNumbers = append(adminNumbers, num) - } else { - log.Printf("Skipping invalid number: %s", numStr) - } - } - file, err := os.Create(as.filePath) + store := as.fsStore + defer store.Close() + + data, err := os.ReadFile("admin_numbers.json") if err != nil { return err } - defer file.Close() - - writer := bufio.NewWriter(file) - for _, num := range adminNumbers { - _, err := writer.WriteString(strconv.FormatInt(num, 10) + "\n") + if err := json.Unmarshal(data, &config); err != nil { + return err + } + for _, admin := range config.Admins { + err := store.Put(as.ctx, []byte(admin.PhoneNumber), []byte("1")) if err != nil { + logg.Printf(logging.LVL_DEBUG, "Failed to insert admin number", admin.PhoneNumber) return err } } - return writer.Flush() + return nil } -func (as *AdminStore) load() ([]int64, error) { - file, err := os.Open(as.filePath) +// Checks if the given sessionId is listed as an admin. +func (as *AdminStore) IsAdmin(sessionId string) (bool, error) { + _, err := as.fsStore.Get(as.ctx, []byte(sessionId)) if err != nil { - return nil, err - } - defer file.Close() - - var numbers []int64 - scanner := bufio.NewScanner(file) - for scanner.Scan() { - num, err := strconv.ParseInt(scanner.Text(), 10, 64) - if err != nil { - return nil, err - } - numbers = append(numbers, num) - } - return numbers, scanner.Err() -} - -func (as *AdminStore) IsAdmin(phoneNumber int64) (bool, error) { - phoneNumbers, err := as.load() - if err != nil { - return false, err - } - for _, phonenumber := range phoneNumbers { - if phonenumber == phoneNumber { - return true, nil + if db.IsNotFound(err) { + logg.Printf(logging.LVL_INFO, "Returning false because session id was not found") + return false, nil + } else { + return false, err } } - return false, nil + + return true, nil } From c42b1cd66b9dd63b5f31ca5c60bc483d2230bee1 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 30 Oct 2024 14:32:01 +0300 Subject: [PATCH 151/289] provide required handler functions and admin store --- internal/handlers/handlerservice.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/internal/handlers/handlerservice.go b/internal/handlers/handlerservice.go index b4cd592..247e6c5 100644 --- a/internal/handlers/handlerservice.go +++ b/internal/handlers/handlerservice.go @@ -8,6 +8,7 @@ import ( "git.defalsify.org/vise.git/resource" "git.grassecon.net/urdt/ussd/internal/handlers/server" "git.grassecon.net/urdt/ussd/internal/handlers/ussd" + "git.grassecon.net/urdt/ussd/internal/utils" ) type HandlerService interface { @@ -28,6 +29,7 @@ type LocalHandlerService struct { DbRs *resource.DbResource Pe *persist.Persister UserdataStore *db.Db + AdminStore *utils.AdminStore Cfg engine.Config Rs resource.Resource } @@ -53,8 +55,12 @@ func (ls *LocalHandlerService) SetDataStore(db *db.Db) { ls.UserdataStore = db } +func (ls *LocalHandlerService) SetAdminStore(adminstore *utils.AdminStore) { + ls.AdminStore = adminstore +} + func (ls *LocalHandlerService) GetHandler(accountService server.AccountServiceInterface) (*ussd.Handlers, error) { - ussdHandlers, err := ussd.NewHandlers(ls.Parser, *ls.UserdataStore, accountService) + ussdHandlers, err := ussd.NewHandlers(ls.Parser, *ls.UserdataStore, ls.AdminStore, accountService) if err != nil { return nil, err } @@ -103,6 +109,8 @@ func (ls *LocalHandlerService) GetHandler(accountService server.AccountServiceIn ls.DbRs.AddLocalFunc("validate_blocked_number", ussdHandlers.ValidateBlockedNumber) ls.DbRs.AddLocalFunc("retrieve_blocked_number", ussdHandlers.RetrieveBlockedNumber) ls.DbRs.AddLocalFunc("reset_unregistered_number", ussdHandlers.ResetUnregisteredNumber) + ls.DbRs.AddLocalFunc("reset_others_pin", ussdHandlers.ResetOthersPin) + ls.DbRs.AddLocalFunc("save_others_temporary_pin", ussdHandlers.SaveOthersTemporaryPin) return ussdHandlers, nil } From c2068db050a931b6f6b9e75bdf876f612d072087 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 30 Oct 2024 14:33:22 +0300 Subject: [PATCH 152/289] update handler functions --- services/registration/confirm_others_new_pin.vis | 4 ++-- services/registration/enter_others_new_pin.vis | 4 ++-- services/registration/pin_reset_result.vis | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/services/registration/confirm_others_new_pin.vis b/services/registration/confirm_others_new_pin.vis index be6734f..319346a 100644 --- a/services/registration/confirm_others_new_pin.vis +++ b/services/registration/confirm_others_new_pin.vis @@ -1,9 +1,9 @@ LOAD retrieve_blocked_number 0 MAP retrieve_blocked_number CATCH invalid_others_pin flag_valid_pin 0 -LOAD save_temporary_pin 6 -RELOAD save_temporary_pin CATCH pin_reset_result flag_account_authorized 1 +LOAD save_others_temporary_pin 6 +RELOAD save_others_temporary_pin MOUT back 0 HALT INCMP _ 0 diff --git a/services/registration/enter_others_new_pin.vis b/services/registration/enter_others_new_pin.vis index aa2818d..16db41c 100644 --- a/services/registration/enter_others_new_pin.vis +++ b/services/registration/enter_others_new_pin.vis @@ -2,7 +2,7 @@ LOAD retrieve_blocked_number 0 MAP retrieve_blocked_number MOUT back 0 HALT -INCMP _ 0 -LOAD verify_new_pin 0 +LOAD verify_new_pin 6 RELOAD verify_new_pin +INCMP _ 0 INCMP * confirm_others_new_pin diff --git a/services/registration/pin_reset_result.vis b/services/registration/pin_reset_result.vis index ed71200..34b9789 100644 --- a/services/registration/pin_reset_result.vis +++ b/services/registration/pin_reset_result.vis @@ -1,5 +1,6 @@ LOAD retrieve_blocked_number 0 MAP retrieve_blocked_number +LOAD reset_others_pin 6 MOUT back 0 MOUT quit 9 HALT From dc418771a79dbb8653fc3251554b0d1591574d4d Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 30 Oct 2024 14:33:48 +0300 Subject: [PATCH 153/289] attach an admin store for phone numbers --- cmd/main.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/main.go b/cmd/main.go index 4d23011..7dd3cd6 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -49,7 +49,7 @@ func main() { ctx = context.WithValue(ctx, "Database", database) pfp := path.Join(scriptDir, "pp.csv") - as := utils.NewAdminStore("admin_numbers.txt") + as, _ := utils.NewAdminStore(ctx, "admin_numbers") as.Seed() cfg := engine.Config{ @@ -94,6 +94,7 @@ func main() { lhs, err := handlers.NewLocalHandlerService(pfp, true, dbResource, cfg, rs) lhs.SetDataStore(&userdatastore) + lhs.SetAdminStore(as) lhs.SetPersister(pe) if err != nil { From 017691a40cac3bab37121d875a3da914eca8bd53 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 30 Oct 2024 14:41:14 +0300 Subject: [PATCH 154/289] define structure for admin numbers --- admin_numbers.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 admin_numbers.json diff --git a/admin_numbers.json b/admin_numbers.json new file mode 100644 index 0000000..ca58a23 --- /dev/null +++ b/admin_numbers.json @@ -0,0 +1,7 @@ +{ + "admins": [ + { + "phonenumber" : "" + } + ] +} \ No newline at end of file From 888d3befe99437be89ade4cd60915ca3730899c4 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 30 Oct 2024 14:50:12 +0300 Subject: [PATCH 155/289] add actual pin reset functionality --- internal/handlers/ussd/menuhandler.go | 61 ++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 70510ee..8b0c385 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -69,11 +69,12 @@ type Handlers struct { st *state.State ca cache.Memory userdataStore utils.DataStore + adminstore *utils.AdminStore flagManager *asm.FlagParser accountService server.AccountServiceInterface } -func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db, accountService server.AccountServiceInterface) (*Handlers, error) { +func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db, adminstore *utils.AdminStore, accountService server.AccountServiceInterface) (*Handlers, error) { if userdataStore == nil { return nil, fmt.Errorf("cannot create handler with nil userdata store") } @@ -83,6 +84,7 @@ func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db, accountService s h := &Handlers{ userdataStore: userDb, flagManager: appFlags, + adminstore: adminstore, accountService: accountService, } return h, nil @@ -120,9 +122,7 @@ func (h *Handlers) Init(ctx context.Context, sym string, input []byte) (resource sessionId, _ := ctx.Value("SessionId").(string) flag_admin_privilege, _ := h.flagManager.GetFlag("flag_admin_privilege") - number, _ := strconv.ParseInt(sessionId, 10, 64) - as := utils.NewAdminStore("admin_numbers.txt") - isAdmin, _ := as.IsAdmin(number) + isAdmin, _ := h.adminstore.IsAdmin(sessionId) if isAdmin { r.FlagSet = append(r.FlagSet, flag_admin_privilege) @@ -220,7 +220,11 @@ func (h *Handlers) CheckPinMisMatch(ctx context.Context, sym string, input []byt return res, fmt.Errorf("missing session") } store := h.userdataStore - temporaryPin, err := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_PIN) + blockedNumber, err := store.ReadEntry(ctx, sessionId, utils.DATA_BLOCKED_NUMBER) + if err != nil { + return res, err + } + temporaryPin, err := store.ReadEntry(ctx, string(blockedNumber), utils.DATA_TEMPORARY_PIN) if err != nil { return res, err } @@ -272,6 +276,7 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt } res.FlagReset = append(res.FlagReset, flag_incorrect_pin) + fmt.Println("Saving:", string(accountPIN)) store := h.userdataStore err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_PIN, []byte(accountPIN)) @@ -282,6 +287,29 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt return res, nil } +func (h *Handlers) SaveOthersTemporaryPin(ctx context.Context, sym string, input []byte) (resource.Result, error) { + var res resource.Result + var err error + + store := h.userdataStore + sessionId, ok := ctx.Value("SessionId").(string) + if !ok { + return res, fmt.Errorf("missing session") + } + temporaryPin := string(input) + blockedNumber, err := store.ReadEntry(ctx, sessionId, utils.DATA_BLOCKED_NUMBER) + + if err != nil { + return res, err + } + err = store.WriteEntry(ctx, string(blockedNumber), utils.DATA_TEMPORARY_PIN, []byte(temporaryPin)) + 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) @@ -672,7 +700,6 @@ func (h *Handlers) ResetIncorrectYob(ctx context.Context, sym string, input []by var res resource.Result flag_incorrect_date_format, _ := h.flagManager.GetFlag("flag_incorrect_date_format") - res.FlagReset = append(res.FlagReset, flag_incorrect_date_format) return res, nil } @@ -755,6 +782,28 @@ func (h *Handlers) FetchCustodialBalances(ctx context.Context, sym string, input return res, nil } +func (h *Handlers) ResetOthersPin(ctx context.Context, sym string, input []byte) (resource.Result, error) { + var res resource.Result + store := h.userdataStore + sessionId, ok := ctx.Value("SessionId").(string) + if !ok { + return res, fmt.Errorf("missing session") + } + blockedPhonenumber, err := store.ReadEntry(ctx, sessionId, utils.DATA_BLOCKED_NUMBER) + if err != nil { + return res, err + } + temporaryPin, err := store.ReadEntry(ctx, string(blockedPhonenumber), utils.DATA_TEMPORARY_PIN) + if err != nil { + return res, err + } + err = store.WriteEntry(ctx, string(blockedPhonenumber), utils.DATA_ACCOUNT_PIN, []byte(temporaryPin)) + if err != nil { + return res, nil + } + return res, nil +} + 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") From cf523e30f89571ed58c933bbd2b0162034947cdc Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 30 Oct 2024 14:50:31 +0300 Subject: [PATCH 156/289] update handler in test --- internal/handlers/ussd/menuhandler_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 28d25e8..d23408a 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -39,7 +39,7 @@ func TestNewHandlers(t *testing.T) { } t.Run("Valid UserDataStore", func(t *testing.T) { mockStore := &mocks.MockUserDataStore{} - handlers, err := NewHandlers(fm.parser, mockStore, &accountService) + handlers, err := NewHandlers(fm.parser, mockStore, nil, &accountService) if err != nil { t.Fatalf("expected no error, got %v", err) } @@ -55,7 +55,7 @@ func TestNewHandlers(t *testing.T) { t.Run("Nil UserDataStore", func(t *testing.T) { appFlags := &asm.FlagParser{} - handlers, err := NewHandlers(appFlags, nil, &accountService) + handlers, err := NewHandlers(appFlags, nil, nil, &accountService) if err == nil { t.Fatal("expected an error, got none") @@ -1481,8 +1481,8 @@ func TestValidateAmount(t *testing.T) { }, }, { - name: "Test with invalid amount format", - input: []byte("0.02ms"), + name: "Test with invalid amount format", + input: []byte("0.02ms"), activeBal: []byte("5"), expectedResult: resource.Result{ FlagSet: []uint32{flag_invalid_amount}, From 14648fec6cfcc348bf5e38ff6e0eb17a53cc015e Mon Sep 17 00:00:00 2001 From: lash Date: Wed, 30 Oct 2024 12:02:16 +0000 Subject: [PATCH 157/289] Edit comment --- common/user_store.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/user_store.go b/common/user_store.go index 8d982ab..4b8409f 100644 --- a/common/user_store.go +++ b/common/user_store.go @@ -16,7 +16,7 @@ type UserDataStore struct { db.Db } -// ReadEntry retrieves an entry from the store based on the provided parameters. +// ReadEntry retrieves an entry to the userdata store. func (store *UserDataStore) ReadEntry(ctx context.Context, sessionId string, typ DataTyp) ([]byte, error) { store.SetPrefix(db.DATATYPE_USERDATA) store.SetSession(sessionId) @@ -24,6 +24,7 @@ func (store *UserDataStore) ReadEntry(ctx context.Context, sessionId string, typ return store.Get(ctx, k) } +// WriteEntry adds an entry to the userdata store. func (store *UserDataStore) WriteEntry(ctx context.Context, sessionId string, typ DataTyp, value []byte) error { store.SetPrefix(db.DATATYPE_USERDATA) store.SetSession(sessionId) From ff26ccc545d1b09456a1875d8e59ef290a15f349 Mon Sep 17 00:00:00 2001 From: lash Date: Wed, 30 Oct 2024 13:09:15 +0000 Subject: [PATCH 158/289] Expose api interface --- cmd/africastalking/main.go | 4 ++-- cmd/async/main.go | 4 ++-- cmd/http/main.go | 4 ++-- cmd/main.go | 4 ++-- internal/handlers/handlerservice.go | 5 +++-- internal/handlers/ussd/menuhandler.go | 6 +++--- internal/testutil/TestEngine.go | 6 +++--- internal/testutil/testtag/offlinetest.go | 4 ++-- {internal/handlers/server => remote}/accountservice.go | 2 +- 9 files changed, 20 insertions(+), 19 deletions(-) rename {internal/handlers/server => remote}/accountservice.go (99%) diff --git a/cmd/africastalking/main.go b/cmd/africastalking/main.go index 79fb091..7c98f38 100644 --- a/cmd/africastalking/main.go +++ b/cmd/africastalking/main.go @@ -19,9 +19,9 @@ import ( "git.grassecon.net/urdt/ussd/config" "git.grassecon.net/urdt/ussd/initializers" "git.grassecon.net/urdt/ussd/internal/handlers" - "git.grassecon.net/urdt/ussd/internal/handlers/server" httpserver "git.grassecon.net/urdt/ussd/internal/http" "git.grassecon.net/urdt/ussd/internal/storage" + "git.grassecon.net/urdt/ussd/remote" ) var ( @@ -139,7 +139,7 @@ func main() { os.Exit(1) } - accountService := server.AccountService{} + accountService := remote.AccountService{} hl, err := lhs.GetHandler(&accountService) if err != nil { fmt.Fprintf(os.Stderr, err.Error()) diff --git a/cmd/async/main.go b/cmd/async/main.go index 902dfc7..b879c68 100644 --- a/cmd/async/main.go +++ b/cmd/async/main.go @@ -16,8 +16,8 @@ import ( "git.grassecon.net/urdt/ussd/config" "git.grassecon.net/urdt/ussd/initializers" "git.grassecon.net/urdt/ussd/internal/handlers" - "git.grassecon.net/urdt/ussd/internal/handlers/server" "git.grassecon.net/urdt/ussd/internal/storage" + "git.grassecon.net/urdt/ussd/remote" ) var ( @@ -106,7 +106,7 @@ func main() { lhs, err := handlers.NewLocalHandlerService(pfp, true, dbResource, cfg, rs) lhs.SetDataStore(&userdataStore) - accountService := server.AccountService{} + accountService := remote.AccountService{} hl, err := lhs.GetHandler(&accountService) if err != nil { diff --git a/cmd/http/main.go b/cmd/http/main.go index ece882e..638ca87 100644 --- a/cmd/http/main.go +++ b/cmd/http/main.go @@ -18,9 +18,9 @@ import ( "git.grassecon.net/urdt/ussd/config" "git.grassecon.net/urdt/ussd/initializers" "git.grassecon.net/urdt/ussd/internal/handlers" - "git.grassecon.net/urdt/ussd/internal/handlers/server" httpserver "git.grassecon.net/urdt/ussd/internal/http" "git.grassecon.net/urdt/ussd/internal/storage" + "git.grassecon.net/urdt/ussd/remote" ) var ( @@ -99,7 +99,7 @@ func main() { fmt.Fprintf(os.Stderr, err.Error()) os.Exit(1) } - accountService := server.AccountService{} + accountService := remote.AccountService{} hl, err := lhs.GetHandler(&accountService) if err != nil { fmt.Fprintf(os.Stderr, err.Error()) diff --git a/cmd/main.go b/cmd/main.go index 21ca0c3..13ceb3c 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -13,8 +13,8 @@ import ( "git.grassecon.net/urdt/ussd/config" "git.grassecon.net/urdt/ussd/initializers" "git.grassecon.net/urdt/ussd/internal/handlers" - "git.grassecon.net/urdt/ussd/internal/handlers/server" "git.grassecon.net/urdt/ussd/internal/storage" + "git.grassecon.net/urdt/ussd/remote" ) var ( @@ -97,7 +97,7 @@ func main() { os.Exit(1) } - accountService := server.AccountService{} + accountService := remote.AccountService{} hl, err := lhs.GetHandler(&accountService) if err != nil { fmt.Fprintf(os.Stderr, err.Error()) diff --git a/internal/handlers/handlerservice.go b/internal/handlers/handlerservice.go index 311e694..b409fa6 100644 --- a/internal/handlers/handlerservice.go +++ b/internal/handlers/handlerservice.go @@ -6,8 +6,9 @@ import ( "git.defalsify.org/vise.git/engine" "git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/resource" - "git.grassecon.net/urdt/ussd/internal/handlers/server" + "git.grassecon.net/urdt/ussd/internal/handlers/ussd" + "git.grassecon.net/urdt/ussd/remote" ) type HandlerService interface { @@ -53,7 +54,7 @@ func (ls *LocalHandlerService) SetDataStore(db *db.Db) { ls.UserdataStore = db } -func (ls *LocalHandlerService) GetHandler(accountService server.AccountServiceInterface) (*ussd.Handlers, error) { +func (ls *LocalHandlerService) GetHandler(accountService remote.AccountServiceInterface) (*ussd.Handlers, error) { ussdHandlers, err := ussd.NewHandlers(ls.Parser, *ls.UserdataStore,accountService) if err != nil { return nil, err diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 303bea9..aa5c1aa 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -19,9 +19,9 @@ import ( "git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/state" - "git.grassecon.net/urdt/ussd/internal/handlers/server" "git.grassecon.net/urdt/ussd/internal/utils" "git.grassecon.net/urdt/ussd/common" + "git.grassecon.net/urdt/ussd/remote" "gopkg.in/leonelquinteros/gotext.v1" "git.grassecon.net/urdt/ussd/internal/storage" @@ -65,10 +65,10 @@ type Handlers struct { ca cache.Memory userdataStore common.DataStore flagManager *asm.FlagParser - accountService server.AccountServiceInterface + accountService remote.AccountServiceInterface } -func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db, accountService server.AccountServiceInterface) (*Handlers, error) { +func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db, accountService remote.AccountServiceInterface) (*Handlers, error) { if userdataStore == nil { return nil, fmt.Errorf("cannot create handler with nil userdata store") } diff --git a/internal/testutil/TestEngine.go b/internal/testutil/TestEngine.go index bd6bc7f..fa585ae 100644 --- a/internal/testutil/TestEngine.go +++ b/internal/testutil/TestEngine.go @@ -11,11 +11,11 @@ import ( "git.defalsify.org/vise.git/logging" "git.defalsify.org/vise.git/resource" "git.grassecon.net/urdt/ussd/internal/handlers" - "git.grassecon.net/urdt/ussd/internal/handlers/server" "git.grassecon.net/urdt/ussd/internal/storage" "git.grassecon.net/urdt/ussd/internal/testutil/testservice" "git.grassecon.net/urdt/ussd/internal/testutil/testtag" testdataloader "github.com/peteole/testdata-loader" + "git.grassecon.net/urdt/ussd/remote" ) var ( @@ -83,7 +83,7 @@ func TestEngine(sessionId string) (engine.Engine, func(), chan bool) { } if testtag.AccountService == nil { - testtag.AccountService = &server.AccountService{} + testtag.AccountService = &remote.AccountService{} } switch testtag.AccountService.(type) { @@ -91,7 +91,7 @@ func TestEngine(sessionId string) (engine.Engine, func(), chan bool) { go func() { eventChannel <- false }() - case *server.AccountService: + case *remote.AccountService: go func() { time.Sleep(5 * time.Second) // Wait for 5 seconds eventChannel <- true diff --git a/internal/testutil/testtag/offlinetest.go b/internal/testutil/testtag/offlinetest.go index 70e2e80..831bf09 100644 --- a/internal/testutil/testtag/offlinetest.go +++ b/internal/testutil/testtag/offlinetest.go @@ -3,10 +3,10 @@ package testtag import ( - "git.grassecon.net/urdt/ussd/internal/handlers/server" + "git.grassecon.net/urdt/ussd/remote" accountservice "git.grassecon.net/urdt/ussd/internal/testutil/testservice" ) var ( - AccountService server.AccountServiceInterface = &accountservice.TestAccountService{} + AccountService remote.AccountServiceInterface = &accountservice.TestAccountService{} ) diff --git a/internal/handlers/server/accountservice.go b/remote/accountservice.go similarity index 99% rename from internal/handlers/server/accountservice.go rename to remote/accountservice.go index 890d1db..236ccf4 100644 --- a/internal/handlers/server/accountservice.go +++ b/remote/accountservice.go @@ -1,4 +1,4 @@ -package server +package remote import ( "context" From d93a26f9b0d2ae02c9798825efac879d09630cf0 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 30 Oct 2024 17:58:52 +0300 Subject: [PATCH 159/289] remove function exec after HALT --- services/registration/enter_other_number.vis | 3 --- 1 file changed, 3 deletions(-) diff --git a/services/registration/enter_other_number.vis b/services/registration/enter_other_number.vis index e2fa243..0957165 100644 --- a/services/registration/enter_other_number.vis +++ b/services/registration/enter_other_number.vis @@ -4,7 +4,4 @@ RELOAD reset_account_authorized MOUT back 0 HALT INCMP _ 0 -LOAD validate_blocked_number 20 -RELOAD validate_blocked_number -CATCH unregistered_number flag_unregistered_number 1 INCMP enter_others_new_pin * From 41585f831c3e38978c99d34a20859e4ab8ef6e71 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 30 Oct 2024 18:00:38 +0300 Subject: [PATCH 160/289] move catch and load to next node --- services/registration/enter_others_new_pin.vis | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/registration/enter_others_new_pin.vis b/services/registration/enter_others_new_pin.vis index 16db41c..49c2426 100644 --- a/services/registration/enter_others_new_pin.vis +++ b/services/registration/enter_others_new_pin.vis @@ -1,3 +1,6 @@ +LOAD validate_blocked_number 20 +RELOAD validate_blocked_number +CATCH unregistered_number flag_unregistered_number 1 LOAD retrieve_blocked_number 0 MAP retrieve_blocked_number MOUT back 0 From 7c823e07ca6c4f0175e58902522f1de97a104599 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 30 Oct 2024 18:01:20 +0300 Subject: [PATCH 161/289] move to root node after on back --- services/registration/unregistered_number.vis | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/registration/unregistered_number.vis b/services/registration/unregistered_number.vis index 114113f..0c66912 100644 --- a/services/registration/unregistered_number.vis +++ b/services/registration/unregistered_number.vis @@ -1,7 +1,7 @@ LOAD reset_unregistered_number 0 RELOAD reset_unregistered_number -MOUT retry 1 +MOUT back 1 MOUT quit 9 HALT -INCMP _ 1 +INCMP ^ 1 INCMP quit 9 From ea4c6d9314158ecb7a6625b9c6544285da4a7bd1 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 30 Oct 2024 18:01:43 +0300 Subject: [PATCH 162/289] check for phone number validity --- internal/handlers/ussd/menuhandler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 8b0c385..4d6f724 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -816,7 +816,6 @@ func (h *Handlers) ValidateBlockedNumber(ctx context.Context, sym string, input var err error flag_unregistered_number, _ := h.flagManager.GetFlag("flag_unregistered_number") - store := h.userdataStore sessionId, ok := ctx.Value("SessionId").(string) if !ok { @@ -825,6 +824,7 @@ func (h *Handlers) ValidateBlockedNumber(ctx context.Context, sym string, input blockedNumber := string(input) _, err = store.ReadEntry(ctx, blockedNumber, utils.DATA_PUBLIC_KEY) if !isValidPhoneNumber(blockedNumber) { + res.FlagSet = append(res.FlagSet, flag_unregistered_number) return res, nil } if err != nil { From 66b34eaea4f83147e6f4e3296636eee0bf21e812 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 30 Oct 2024 18:21:49 +0300 Subject: [PATCH 163/289] get the ussd-data-service package --- go.mod | 2 ++ go.sum | 2 ++ 2 files changed, 4 insertions(+) diff --git a/go.mod b/go.mod index 0b30354..391c1a5 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,8 @@ require ( gopkg.in/leonelquinteros/gotext.v1 v1.3.1 ) +require github.com/grassrootseconomics/ussd-data-service v0.0.0-20241003123429-4904b4438a3a // indirect + require ( github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect diff --git a/go.sum b/go.sum index d566e2c..0ba38c1 100644 --- a/go.sum +++ b/go.sum @@ -18,6 +18,8 @@ github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1 github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/grassrootseconomics/eth-custodial v1.3.0-beta h1:twrMBhl89GqDUL9PlkzQxMP/6OST1BByrNDj+rqXDmU= github.com/grassrootseconomics/eth-custodial v1.3.0-beta/go.mod h1:7uhRcdnJplX4t6GKCEFkbeDhhjlcaGJeJqevbcvGLZo= +github.com/grassrootseconomics/ussd-data-service v0.0.0-20241003123429-4904b4438a3a h1:q/YH7nE2j8epNmFnTu0tU1vwtCxtQ6nH+d7hRVV5krU= +github.com/grassrootseconomics/ussd-data-service v0.0.0-20241003123429-4904b4438a3a/go.mod h1:hdKaKwqiW6/kphK4j/BhmuRlZDLo1+DYo3gYw5O0siw= github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 h1:U4kkNYryi/qfbBF8gh7Vsbuz+cVmhf5kt6pE9bYYyLo= github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4/go.mod h1:zpZDgZFzeq9s0MIeB1P50NIEWDFFHSFBohI/NbaTD/Y= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= From caafe495be8d60a04e36d4306d4c2509adce8a22 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 30 Oct 2024 18:30:55 +0300 Subject: [PATCH 164/289] use the dataserviceapi structs --- internal/handlers/ussd/menuhandler.go | 8 +-- internal/handlers/ussd/menuhandler_test.go | 43 +++---------- internal/models/vouchersresponse.go | 21 ++++--- .../testservice/TestAccountService.go | 17 +----- internal/utils/vouchers.go | 49 +++++++-------- internal/utils/vouchers_test.go | 60 +++++++++---------- 6 files changed, 74 insertions(+), 124 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index d4ed992..231da95 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -1055,13 +1055,13 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by if db.IsNotFound(err) { publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) if err != nil { - return res, nil + return res, err } // Fetch vouchers from the API using the public key vouchersResp, err := h.accountService.FetchVouchers(ctx, string(publicKey)) if err != nil { - return res, nil + return res, err } // Return if there is no voucher @@ -1183,7 +1183,7 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r } res.FlagReset = append(res.FlagReset, flag_incorrect_voucher) - res.Content = fmt.Sprintf("%s\n%s", metadata.Symbol, metadata.Balance) + res.Content = fmt.Sprintf("%s\n%s", metadata.TokenSymbol, metadata.Balance) return res, nil } @@ -1208,6 +1208,6 @@ func (h *Handlers) SetVoucher(ctx context.Context, sym string, input []byte) (re return res, err } - res.Content = tempData.Symbol + res.Content = tempData.TokenSymbol return res, nil } diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 6ea44a0..2b76bf1 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -24,6 +24,8 @@ import ( "github.com/grassrootseconomics/eth-custodial/pkg/api" testdataloader "github.com/peteole/testdata-loader" "github.com/stretchr/testify/require" + + dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" ) var ( @@ -1898,12 +1900,10 @@ func TestSetDefaultVoucher(t *testing.T) { if err != nil { t.Logf(err.Error()) } - flag_no_active_voucher, err := fm.GetFlag("flag_no_active_voucher") if err != nil { t.Logf(err.Error()) } - // Define session ID and mock data sessionId := "session123" publicKey := "0X13242618721" @@ -1920,20 +1920,8 @@ func TestSetDefaultVoucher(t *testing.T) { vouchersResp: &models.VoucherHoldingResponse{ Ok: true, Description: "Vouchers fetched successfully", - Result: struct { - Holdings []struct { - ContractAddress string `json:"contractAddress"` - TokenSymbol string `json:"tokenSymbol"` - TokenDecimals string `json:"tokenDecimals"` - Balance string `json:"balance"` - } `json:"holdings"` - }{ - Holdings: []struct { - ContractAddress string `json:"contractAddress"` - TokenSymbol string `json:"tokenSymbol"` - TokenDecimals string `json:"tokenDecimals"` - Balance string `json:"balance"` - }{ + Result: models.VoucherResult{ + Holdings: []dataserviceapi.TokenHoldings{ { ContractAddress: "0x123", TokenSymbol: "TOKEN1", @@ -1950,20 +1938,8 @@ func TestSetDefaultVoucher(t *testing.T) { vouchersResp: &models.VoucherHoldingResponse{ Ok: true, Description: "No vouchers available", - Result: struct { - Holdings []struct { - ContractAddress string `json:"contractAddress"` - TokenSymbol string `json:"tokenSymbol"` - TokenDecimals string `json:"tokenDecimals"` - Balance string `json:"balance"` - } `json:"holdings"` - }{ - Holdings: []struct { - ContractAddress string `json:"contractAddress"` - TokenSymbol string `json:"tokenSymbol"` - TokenDecimals string `json:"tokenDecimals"` - Balance string `json:"balance"` - }{}, + Result: models.VoucherResult{ + Holdings: []dataserviceapi.TokenHoldings{}, }, }, expectedResult: resource.Result{ @@ -2025,12 +2001,7 @@ func TestCheckVouchers(t *testing.T) { mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil) mockVouchersResponse := &models.VoucherHoldingResponse{} - mockVouchersResponse.Result.Holdings = []struct { - ContractAddress string `json:"contractAddress"` - TokenSymbol string `json:"tokenSymbol"` - TokenDecimals string `json:"tokenDecimals"` - Balance string `json:"balance"` - }{ + mockVouchersResponse.Result.Holdings = []dataserviceapi.TokenHoldings{ {ContractAddress: "0xd4c288865Ce", TokenSymbol: "SRF", TokenDecimals: "6", Balance: "100"}, {ContractAddress: "0x41c188d63Qa", TokenSymbol: "MILO", TokenDecimals: "4", Balance: "200"}, } diff --git a/internal/models/vouchersresponse.go b/internal/models/vouchersresponse.go index 010730f..09b085d 100644 --- a/internal/models/vouchersresponse.go +++ b/internal/models/vouchersresponse.go @@ -1,15 +1,14 @@ package models -// VoucherHoldingResponse represents a single voucher holding +import dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" + type VoucherHoldingResponse struct { - Ok bool `json:"ok"` - Description string `json:"description"` - Result struct { - Holdings []struct { - ContractAddress string `json:"contractAddress"` - TokenSymbol string `json:"tokenSymbol"` - TokenDecimals string `json:"tokenDecimals"` - Balance string `json:"balance"` - } `json:"holdings"` - } `json:"result"` + Ok bool `json:"ok"` + Description string `json:"description"` + Result VoucherResult `json:"result"` +} + +// VoucherResult holds the list of token holdings +type VoucherResult struct { + Holdings []dataserviceapi.TokenHoldings `json:"holdings"` } diff --git a/internal/testutil/testservice/TestAccountService.go b/internal/testutil/testservice/TestAccountService.go index 6332345..745b80d 100644 --- a/internal/testutil/testservice/TestAccountService.go +++ b/internal/testutil/testservice/TestAccountService.go @@ -7,6 +7,7 @@ import ( "git.grassecon.net/urdt/ussd/internal/models" "github.com/grassrootseconomics/eth-custodial/pkg/api" + dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" ) type TestAccountService struct { @@ -75,20 +76,8 @@ func (tas *TestAccountService) TrackAccountStatus(ctx context.Context, publicKey func (tas *TestAccountService) FetchVouchers(ctx context.Context, publicKey string) (*models.VoucherHoldingResponse, error) { return &models.VoucherHoldingResponse{ Ok: true, - Result: struct { - Holdings []struct { - ContractAddress string `json:"contractAddress"` - TokenSymbol string `json:"tokenSymbol"` - TokenDecimals string `json:"tokenDecimals"` - Balance string `json:"balance"` - } `json:"holdings"` - }{ - Holdings: []struct { - ContractAddress string `json:"contractAddress"` - TokenSymbol string `json:"tokenSymbol"` - TokenDecimals string `json:"tokenDecimals"` - Balance string `json:"balance"` - }{ + Result: models.VoucherResult{ + Holdings: []dataserviceapi.TokenHoldings{ { ContractAddress: "0x6CC75A06ac72eB4Db2eE22F781F5D100d8ec03ee", TokenSymbol: "SRF", diff --git a/internal/utils/vouchers.go b/internal/utils/vouchers.go index 11fd7d1..2aed42a 100644 --- a/internal/utils/vouchers.go +++ b/internal/utils/vouchers.go @@ -1,12 +1,12 @@ package utils import ( + "context" "fmt" "strings" - "context" - "git.grassecon.net/urdt/ussd/internal/storage" + dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" ) // VoucherMetadata helps organize voucher data fields @@ -18,12 +18,7 @@ type VoucherMetadata struct { } // ProcessVouchers converts holdings into formatted strings -func ProcessVouchers(holdings []struct { - ContractAddress string `json:"contractAddress"` - TokenSymbol string `json:"tokenSymbol"` - TokenDecimals string `json:"tokenDecimals"` - Balance string `json:"balance"` -}) VoucherMetadata { +func ProcessVouchers(holdings []dataserviceapi.TokenHoldings) VoucherMetadata { var data VoucherMetadata var symbols, balances, decimals, addresses []string @@ -43,7 +38,7 @@ func ProcessVouchers(holdings []struct { } // GetVoucherData retrieves and matches voucher data -func GetVoucherData(ctx context.Context, db storage.PrefixDb, input string) (*VoucherMetadata, error) { +func GetVoucherData(ctx context.Context, db storage.PrefixDb, input string) (*dataserviceapi.TokenHoldings, error) { keys := []string{"sym", "bal", "deci", "addr"} data := make(map[string]string) @@ -65,11 +60,11 @@ func GetVoucherData(ctx context.Context, db storage.PrefixDb, input string) (*Vo return nil, nil } - return &VoucherMetadata{ - Symbol: symbol, - Balance: balance, - Decimal: decimal, - Address: address, + return &dataserviceapi.TokenHoldings{ + TokenSymbol: string(symbol), + Balance: string(balance), + TokenDecimals: string(decimal), + ContractAddress: string(address), }, nil } @@ -104,12 +99,12 @@ func MatchVoucher(input, symbols, balances, decimals, addresses string) (symbol, } // StoreTemporaryVoucher saves voucher metadata as temporary entries in the DataStore. -func StoreTemporaryVoucher(ctx context.Context, store DataStore, sessionId string, data *VoucherMetadata) error { +func StoreTemporaryVoucher(ctx context.Context, store DataStore, sessionId string, data *dataserviceapi.TokenHoldings) error { entries := map[DataTyp][]byte{ - DATA_TEMPORARY_SYM: []byte(data.Symbol), + DATA_TEMPORARY_SYM: []byte(data.TokenSymbol), DATA_TEMPORARY_BAL: []byte(data.Balance), - DATA_TEMPORARY_DECIMAL: []byte(data.Decimal), - DATA_TEMPORARY_ADDRESS: []byte(data.Address), + DATA_TEMPORARY_DECIMAL: []byte(data.TokenDecimals), + DATA_TEMPORARY_ADDRESS: []byte(data.ContractAddress), } for key, value := range entries { @@ -121,7 +116,7 @@ func StoreTemporaryVoucher(ctx context.Context, store DataStore, sessionId strin } // GetTemporaryVoucherData retrieves temporary voucher metadata from the DataStore. -func GetTemporaryVoucherData(ctx context.Context, store DataStore, sessionId string) (*VoucherMetadata, error) { +func GetTemporaryVoucherData(ctx context.Context, store DataStore, sessionId string) (*dataserviceapi.TokenHoldings, error) { keys := []DataTyp{ DATA_TEMPORARY_SYM, DATA_TEMPORARY_BAL, @@ -129,7 +124,7 @@ func GetTemporaryVoucherData(ctx context.Context, store DataStore, sessionId str DATA_TEMPORARY_ADDRESS, } - data := &VoucherMetadata{} + data := &dataserviceapi.TokenHoldings{} values := make([][]byte, len(keys)) for i, key := range keys { @@ -140,22 +135,22 @@ func GetTemporaryVoucherData(ctx context.Context, store DataStore, sessionId str values[i] = value } - data.Symbol = string(values[0]) + data.TokenSymbol = string(values[0]) data.Balance = string(values[1]) - data.Decimal = string(values[2]) - data.Address = string(values[3]) + data.TokenDecimals = string(values[2]) + data.ContractAddress = string(values[3]) return data, nil } // UpdateVoucherData sets the active voucher data and clears the temporary voucher data in the DataStore. -func UpdateVoucherData(ctx context.Context, store DataStore, sessionId string, data *VoucherMetadata) error { +func UpdateVoucherData(ctx context.Context, store DataStore, sessionId string, data *dataserviceapi.TokenHoldings) error { // Active voucher data entries activeEntries := map[DataTyp][]byte{ - DATA_ACTIVE_SYM: []byte(data.Symbol), + DATA_ACTIVE_SYM: []byte(data.TokenSymbol), DATA_ACTIVE_BAL: []byte(data.Balance), - DATA_ACTIVE_DECIMAL: []byte(data.Decimal), - DATA_ACTIVE_ADDRESS: []byte(data.Address), + DATA_ACTIVE_DECIMAL: []byte(data.TokenDecimals), + DATA_ACTIVE_ADDRESS: []byte(data.ContractAddress), } // Clear temporary voucher data entries diff --git a/internal/utils/vouchers_test.go b/internal/utils/vouchers_test.go index f26ee01..8f8f18e 100644 --- a/internal/utils/vouchers_test.go +++ b/internal/utils/vouchers_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/require" memdb "git.defalsify.org/vise.git/db/mem" + dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" ) // InitializeTestDb sets up and returns an in-memory database and store. @@ -61,12 +62,7 @@ func TestMatchVoucher(t *testing.T) { } func TestProcessVouchers(t *testing.T) { - holdings := []struct { - ContractAddress string `json:"contractAddress"` - TokenSymbol string `json:"tokenSymbol"` - TokenDecimals string `json:"tokenDecimals"` - Balance string `json:"balance"` - }{ + holdings := []dataserviceapi.TokenHoldings{ {ContractAddress: "0xd4c288865Ce", TokenSymbol: "SRF", TokenDecimals: "6", Balance: "100"}, {ContractAddress: "0x41c188d63Qa", TokenSymbol: "MILO", TokenDecimals: "4", Balance: "200"}, } @@ -112,10 +108,10 @@ func TestGetVoucherData(t *testing.T) { result, err := GetVoucherData(ctx, spdb, "1") assert.NoError(t, err) - assert.Equal(t, "SRF", result.Symbol) + assert.Equal(t, "SRF", result.TokenSymbol) assert.Equal(t, "100", result.Balance) - assert.Equal(t, "6", result.Decimal) - assert.Equal(t, "0xd4c288865Ce", result.Address) + assert.Equal(t, "6", result.TokenDecimals) + assert.Equal(t, "0xd4c288865Ce", result.ContractAddress) } func TestStoreTemporaryVoucher(t *testing.T) { @@ -123,11 +119,11 @@ func TestStoreTemporaryVoucher(t *testing.T) { sessionId := "session123" // Test data - voucherData := &VoucherMetadata{ - Symbol: "SRF", - Balance: "200", - Decimal: "6", - Address: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", + voucherData := &dataserviceapi.TokenHoldings{ + TokenSymbol: "SRF", + Balance: "200", + TokenDecimals: "6", + ContractAddress: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", } // Execute the function being tested @@ -154,11 +150,11 @@ func TestGetTemporaryVoucherData(t *testing.T) { sessionId := "session123" // Test voucher data - tempData := &VoucherMetadata{ - Symbol: "SRF", - Balance: "200", - Decimal: "6", - Address: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", + tempData := &dataserviceapi.TokenHoldings{ + TokenSymbol: "SRF", + Balance: "200", + TokenDecimals: "6", + ContractAddress: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", } // Store the data @@ -176,19 +172,19 @@ func TestUpdateVoucherData(t *testing.T) { sessionId := "session123" // New voucher data - newData := &VoucherMetadata{ - Symbol: "SRF", - Balance: "200", - Decimal: "6", - Address: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", + newData := &dataserviceapi.TokenHoldings{ + TokenSymbol: "SRF", + Balance: "200", + TokenDecimals: "6", + ContractAddress: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", } // Old temporary data - tempData := &VoucherMetadata{ - Symbol: "OLD", - Balance: "100", - Decimal: "8", - Address: "0xold", + tempData := &dataserviceapi.TokenHoldings{ + TokenSymbol: "OLD", + Balance: "100", + TokenDecimals: "8", + ContractAddress: "0xold", } require.NoError(t, StoreTemporaryVoucher(ctx, store, sessionId, tempData)) @@ -198,10 +194,10 @@ func TestUpdateVoucherData(t *testing.T) { // Verify active data was stored correctly activeEntries := map[DataTyp][]byte{ - DATA_ACTIVE_SYM: []byte(newData.Symbol), + DATA_ACTIVE_SYM: []byte(newData.TokenSymbol), DATA_ACTIVE_BAL: []byte(newData.Balance), - DATA_ACTIVE_DECIMAL: []byte(newData.Decimal), - DATA_ACTIVE_ADDRESS: []byte(newData.Address), + DATA_ACTIVE_DECIMAL: []byte(newData.TokenDecimals), + DATA_ACTIVE_ADDRESS: []byte(newData.ContractAddress), } for key, expectedValue := range activeEntries { From 8b399781e893ab6b678b0d38b7b960f0b60a9a4a Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 30 Oct 2024 18:40:03 +0300 Subject: [PATCH 165/289] make the VoucherMetadata more descriptive --- internal/handlers/ussd/menuhandler.go | 16 ++++----------- internal/handlers/ussd/menuhandler_test.go | 24 +++++++++++----------- internal/utils/vouchers.go | 18 ++++++++-------- internal/utils/vouchers_test.go | 8 ++++---- 4 files changed, 29 insertions(+), 37 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 231da95..3de4590 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -58,14 +58,6 @@ func (fm *FlagManager) GetFlag(label string) (uint32, error) { return fm.parser.GetFlag(label) } -// VoucherMetadata helps organize voucher data fields -type VoucherMetadata struct { - Symbol string - Balance string - Decimal string - Address string -} - type Handlers struct { pe *persist.Persister st *state.State @@ -1122,10 +1114,10 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) // Store all voucher data dataMap := map[string]string{ - "sym": data.Symbol, - "bal": data.Balance, - "deci": data.Decimal, - "addr": data.Address, + "sym": data.Symbols, + "bal": data.Balances, + "deci": data.Decimals, + "addr": data.Addresses, } for key, value := range dataMap { diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 2b76bf1..12f155e 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -2096,19 +2096,19 @@ func TestSetVoucher(t *testing.T) { ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Define the temporary voucher data - tempData := &VoucherMetadata{ - Symbol: "SRF", - Balance: "200", - Decimal: "6", - Address: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", + tempData := &dataserviceapi.TokenHoldings{ + TokenSymbol: "SRF", + Balance: "200", + TokenDecimals: "6", + ContractAddress: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", } // Define the expected active entries activeEntries := map[utils.DataTyp][]byte{ - utils.DATA_ACTIVE_SYM: []byte(tempData.Symbol), + utils.DATA_ACTIVE_SYM: []byte(tempData.TokenSymbol), utils.DATA_ACTIVE_BAL: []byte(tempData.Balance), - utils.DATA_ACTIVE_DECIMAL: []byte(tempData.Decimal), - utils.DATA_ACTIVE_ADDRESS: []byte(tempData.Address), + utils.DATA_ACTIVE_DECIMAL: []byte(tempData.TokenDecimals), + utils.DATA_ACTIVE_ADDRESS: []byte(tempData.ContractAddress), } // Define the temporary entries to be cleared @@ -2120,10 +2120,10 @@ func TestSetVoucher(t *testing.T) { } // Mocking ReadEntry calls for temporary data retrieval - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_SYM).Return([]byte(tempData.Symbol), nil) + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_SYM).Return([]byte(tempData.TokenSymbol), nil) mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_BAL).Return([]byte(tempData.Balance), nil) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_DECIMAL).Return([]byte(tempData.Decimal), nil) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_ADDRESS).Return([]byte(tempData.Address), nil) + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_DECIMAL).Return([]byte(tempData.TokenDecimals), nil) + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_ADDRESS).Return([]byte(tempData.ContractAddress), nil) // Mocking WriteEntry calls for setting active data for key, value := range activeEntries { @@ -2143,7 +2143,7 @@ func TestSetVoucher(t *testing.T) { assert.NoError(t, err) - assert.Equal(t, string(tempData.Symbol), res.Content) + assert.Equal(t, string(tempData.TokenSymbol), res.Content) mockDataStore.AssertExpectations(t) } diff --git a/internal/utils/vouchers.go b/internal/utils/vouchers.go index 2aed42a..73a95a6 100644 --- a/internal/utils/vouchers.go +++ b/internal/utils/vouchers.go @@ -9,12 +9,12 @@ import ( dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" ) -// VoucherMetadata helps organize voucher data fields +// VoucherMetadata helps organize data fields type VoucherMetadata struct { - Symbol string - Balance string - Decimal string - Address string + Symbols string + Balances string + Decimals string + Addresses string } // ProcessVouchers converts holdings into formatted strings @@ -29,10 +29,10 @@ func ProcessVouchers(holdings []dataserviceapi.TokenHoldings) VoucherMetadata { addresses = append(addresses, fmt.Sprintf("%d:%s", i+1, h.ContractAddress)) } - data.Symbol = strings.Join(symbols, "\n") - data.Balance = strings.Join(balances, "\n") - data.Decimal = strings.Join(decimals, "\n") - data.Address = strings.Join(addresses, "\n") + data.Symbols = strings.Join(symbols, "\n") + data.Balances = strings.Join(balances, "\n") + data.Decimals = strings.Join(decimals, "\n") + data.Addresses = strings.Join(addresses, "\n") return data } diff --git a/internal/utils/vouchers_test.go b/internal/utils/vouchers_test.go index 8f8f18e..953182e 100644 --- a/internal/utils/vouchers_test.go +++ b/internal/utils/vouchers_test.go @@ -68,10 +68,10 @@ func TestProcessVouchers(t *testing.T) { } expectedResult := VoucherMetadata{ - Symbol: "1:SRF\n2:MILO", - Balance: "1:100\n2:200", - Decimal: "1:6\n2:4", - Address: "1:0xd4c288865Ce\n2:0x41c188d63Qa", + Symbols: "1:SRF\n2:MILO", + Balances: "1:100\n2:200", + Decimals: "1:6\n2:4", + Addresses: "1:0xd4c288865Ce\n2:0x41c188d63Qa", } result := ProcessVouchers(holdings) From 833d52a558b2e20359ebe4beeb482dd7e2757397 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 30 Oct 2024 21:26:11 +0300 Subject: [PATCH 166/289] remove print message --- internal/handlers/ussd/menuhandler.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index bbcfd58..3ffa61b 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -19,9 +19,9 @@ import ( "git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/state" + "git.grassecon.net/urdt/ussd/common" "git.grassecon.net/urdt/ussd/internal/handlers/server" "git.grassecon.net/urdt/ussd/internal/utils" - "git.grassecon.net/urdt/ussd/common" "gopkg.in/leonelquinteros/gotext.v1" "git.grassecon.net/urdt/ussd/internal/storage" @@ -283,10 +283,7 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt res.FlagSet = append(res.FlagSet, flag_incorrect_pin) return res, nil } - res.FlagReset = append(res.FlagReset, flag_incorrect_pin) - fmt.Println("Saving:", string(accountPIN)) - store := h.userdataStore err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_PIN, []byte(accountPIN)) if err != nil { From 8093eae61aeb35e0a76fce275fca04fb950adedb Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 30 Oct 2024 21:26:52 +0300 Subject: [PATCH 167/289] use 0 instead of 1 for back --- services/registration/unregistered_number.vis | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/registration/unregistered_number.vis b/services/registration/unregistered_number.vis index 0c66912..0ff96be 100644 --- a/services/registration/unregistered_number.vis +++ b/services/registration/unregistered_number.vis @@ -1,7 +1,7 @@ LOAD reset_unregistered_number 0 RELOAD reset_unregistered_number -MOUT back 1 +MOUT back 0 MOUT quit 9 HALT -INCMP ^ 1 +INCMP ^ 0 INCMP quit 9 From c6ca3f6be4fb405ebf0a620a26adc677242d8d8f Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 30 Oct 2024 22:32:38 +0300 Subject: [PATCH 168/289] fix sink error --- services/registration/confirm_others_new_pin.vis | 2 +- services/registration/enter_others_new_pin.vis | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/services/registration/confirm_others_new_pin.vis b/services/registration/confirm_others_new_pin.vis index 319346a..f63d7ae 100644 --- a/services/registration/confirm_others_new_pin.vis +++ b/services/registration/confirm_others_new_pin.vis @@ -1,4 +1,4 @@ -LOAD retrieve_blocked_number 0 +RELOAD retrieve_blocked_number MAP retrieve_blocked_number CATCH invalid_others_pin flag_valid_pin 0 CATCH pin_reset_result flag_account_authorized 1 diff --git a/services/registration/enter_others_new_pin.vis b/services/registration/enter_others_new_pin.vis index 49c2426..7711c97 100644 --- a/services/registration/enter_others_new_pin.vis +++ b/services/registration/enter_others_new_pin.vis @@ -1,7 +1,8 @@ -LOAD validate_blocked_number 20 +LOAD validate_blocked_number 6 RELOAD validate_blocked_number CATCH unregistered_number flag_unregistered_number 1 LOAD retrieve_blocked_number 0 +RELOAD retrieve_blocked_number MAP retrieve_blocked_number MOUT back 0 HALT From d4341940218dc1b24795ccdb10165fc3098242a0 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 30 Oct 2024 23:21:15 +0300 Subject: [PATCH 169/289] catch incorrect pin entry --- services/registration/confirm_others_new_pin.vis | 1 + 1 file changed, 1 insertion(+) diff --git a/services/registration/confirm_others_new_pin.vis b/services/registration/confirm_others_new_pin.vis index f63d7ae..9132dc4 100644 --- a/services/registration/confirm_others_new_pin.vis +++ b/services/registration/confirm_others_new_pin.vis @@ -1,3 +1,4 @@ +CATCH pin_entry flag_incorrect_pin 1 RELOAD retrieve_blocked_number MAP retrieve_blocked_number CATCH invalid_others_pin flag_valid_pin 0 From 1e638238ed368319fb84ed9deb8d90d0df55b28d Mon Sep 17 00:00:00 2001 From: lash Date: Thu, 31 Oct 2024 01:28:37 +0000 Subject: [PATCH 170/289] WIP refactor models usage --- config/config.go | 67 ++++++-- internal/handlers/ussd/menuhandler.go | 20 +-- internal/handlers/ussd/menuhandler_test.go | 1 - internal/models/accountresponse.go | 10 +- internal/models/balanceresponse.go | 17 +- internal/models/trackstatusresponse.go | 23 ++- internal/models/vouchersresponse.go | 13 -- internal/testutil/mocks/servicemock.go | 27 ++-- .../testservice/TestAccountService.go | 78 +++------ remote/accountservice.go | 149 ++++++++++++------ 10 files changed, 229 insertions(+), 176 deletions(-) diff --git a/config/config.go b/config/config.go index 43466c3..a5c89a7 100644 --- a/config/config.go +++ b/config/config.go @@ -1,18 +1,67 @@ package config -import "git.grassecon.net/urdt/ussd/initializers" +import ( + "net/url" + + "git.grassecon.net/urdt/ussd/initializers" +) + +const ( + createAccountPath = "/api/v2/account/create" + trackStatusPath = "/api/track" + balancePathPrefix = "/api/account" + trackPath = "/api/v2/account/status" + voucherHoldingsPathPrefix = "/api/v1/holdings" + voucherTransfersPathPrefix = "/api/v1/transfers/last10" +) + +var ( + custodialURLBase string + dataURLBase string + CustodialAPIKey string + DataAPIKey string +) var ( CreateAccountURL string TrackStatusURL string - BalanceURL string - TrackURL string + BalanceURL string + TrackURL string + VoucherHoldingsURL string + VoucherTransfersURL string ) -// LoadConfig initializes the configuration values after environment variables are loaded. -func LoadConfig() { - CreateAccountURL = initializers.GetEnv("CREATE_ACCOUNT_URL", "http://localhost:5003/api/v2/account/create") - TrackStatusURL = initializers.GetEnv("TRACK_STATUS_URL", "https://custodial.sarafu.africa/api/track/") - BalanceURL = initializers.GetEnv("BALANCE_URL", "https://custodial.sarafu.africa/api/account/status/") - TrackURL = initializers.GetEnv("TRACK_URL", "http://localhost:5003/api/v2/account/status") +func setBase() error { + var err error + + custodialURLBase = initializers.GetEnv("CUSTODIAL_URL_BASE", "http://localhost:5003") + dataURLBase = initializers.GetEnv("DATA_URL_BASE", "http://localhost:5006") + CustodialAPIKey = initializers.GetEnv("CUSTODIAL_API_KEY", "xd") + DataAPIKey = initializers.GetEnv("DATA_API_KEY", "xd") + + _, err = url.JoinPath(custodialURLBase, "/foo") + if err != nil { + return err + } + _, err = url.JoinPath(dataURLBase, "/bar") + if err != nil { + return err + } + return nil +} + +// LoadConfig initializes the configuration values after environment variables are loaded. +func LoadConfig() error { + err := setBase() + if err != nil { + return err + } + CreateAccountURL, _ = url.JoinPath(custodialURLBase, createAccountPath) + TrackStatusURL, _ = url.JoinPath(custodialURLBase, trackStatusPath) + BalanceURL, _ = url.JoinPath(custodialURLBase, balancePathPrefix) + TrackURL, _ = url.JoinPath(custodialURLBase, trackPath) + VoucherHoldingsURL, _ = url.JoinPath(dataURLBase, voucherHoldingsPathPrefix) + VoucherTransfersURL, _ = url.JoinPath(dataURLBase, voucherTransfersPathPrefix) + + return nil } diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index f568e6a..5f6f81a 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -149,12 +149,12 @@ func (h *Handlers) SetLanguage(ctx context.Context, sym string, input []byte) (r func (h *Handlers) createAccountNoExist(ctx context.Context, sessionId string, res *resource.Result) error { flag_account_created, _ := h.flagManager.GetFlag("flag_account_created") - okResponse, err := h.accountService.CreateAccount(ctx) + r, err := h.accountService.CreateAccount(ctx) if err != nil { return err } - trackingId := okResponse.Result["trackingId"].(string) - publicKey := okResponse.Result["publicKey"].(string) + trackingId := r.TrackingId + publicKey := r.PublicKey data := map[common.DataTyp]string{ common.DATA_TRACKING_ID: trackingId, @@ -682,6 +682,7 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) ( func (h *Handlers) FetchCustodialBalances(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result + flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") sessionId, ok := ctx.Value("SessionId").(string) @@ -699,14 +700,13 @@ func (h *Handlers) FetchCustodialBalances(ctx context.Context, sym string, input balanceResponse, err := h.accountService.CheckBalance(ctx, string(publicKey)) if err != nil { - return res, nil - } - if !balanceResponse.Ok { res.FlagSet = append(res.FlagSet, flag_api_error) return res, nil } res.FlagReset = append(res.FlagReset, flag_api_error) - balance := balanceResponse.Result.Balance + + //balance := balanceResponse.Result.Balance + balance := balanceResponse.Balance switch balanceType { case "my": @@ -1066,13 +1066,13 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by } // Return if there is no voucher - if len(vouchersResp.Result.Holdings) == 0 { + if len(vouchersResp) == 0 { res.FlagSet = append(res.FlagSet, flag_no_active_voucher) return res, nil } // Use only the first voucher - firstVoucher := vouchersResp.Result.Holdings[0] + firstVoucher := vouchersResp[0] defaultSym := firstVoucher.TokenSymbol defaultBal := firstVoucher.Balance @@ -1119,7 +1119,7 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) return res, nil } - data := utils.ProcessVouchers(vouchersResp.Result.Holdings) + data := utils.ProcessVouchers(vouchersResp) // Store all voucher data dataMap := map[string]string{ diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index bae95a8..5f3c953 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -1159,7 +1159,6 @@ func TestCheckAccountStatus(t *testing.T) { // Assert that expectations were met mockDataStore.AssertExpectations(t) - }) } diff --git a/internal/models/accountresponse.go b/internal/models/accountresponse.go index efcc30b..278e0e9 100644 --- a/internal/models/accountresponse.go +++ b/internal/models/accountresponse.go @@ -1,10 +1,6 @@ package models -type AccountResponse struct { - Ok bool `json:"ok"` - Description string `json:"description"` // Include the description field - Result struct { - PublicKey string `json:"publicKey"` - TrackingId string `json:"trackingId"` - } `json:"result"` +type AccountResult struct { + PublicKey string `json:"publicKey"` + TrackingId string `json:"trackingId"` } diff --git a/internal/models/balanceresponse.go b/internal/models/balanceresponse.go index 57c8e5a..3d57c95 100644 --- a/internal/models/balanceresponse.go +++ b/internal/models/balanceresponse.go @@ -3,10 +3,15 @@ package models import "encoding/json" -type BalanceResponse struct { - Ok bool `json:"ok"` - Result struct { - Balance string `json:"balance"` - Nonce json.Number `json:"nonce"` - } `json:"result"` +//type BalanceResponse struct { +// Ok bool `json:"ok"` +// Result struct { +// Balance string `json:"balance"` +// Nonce json.Number `json:"nonce"` +// } `json:"result"` +//} +// +type BalanceResult struct { + Balance string `json:"balance"` + Nonce json.Number `json:"nonce"` } diff --git a/internal/models/trackstatusresponse.go b/internal/models/trackstatusresponse.go index 6b96d90..6130c6e 100644 --- a/internal/models/trackstatusresponse.go +++ b/internal/models/trackstatusresponse.go @@ -4,23 +4,18 @@ import ( "encoding/json" "time" ) -type Transaction struct { +//type Transaction struct { +// CreatedAt time.Time `json:"createdAt"` +// Status string `json:"status"` +// TransferValue json.Number `json:"transferValue"` +// TxHash string `json:"txHash"` +// TxType string `json:"txType"` +//} + +type TrackStatusResult struct { CreatedAt time.Time `json:"createdAt"` Status string `json:"status"` TransferValue json.Number `json:"transferValue"` TxHash string `json:"txHash"` TxType string `json:"txType"` } - -type TrackStatusResponse struct { - Ok bool `json:"ok"` - Result struct { - Transaction struct { - CreatedAt time.Time `json:"createdAt"` - Status string `json:"status"` - TransferValue json.Number `json:"transferValue"` - TxHash string `json:"txHash"` - TxType string `json:"txType"` - } - } `json:"result"` -} diff --git a/internal/models/vouchersresponse.go b/internal/models/vouchersresponse.go index 09b085d..2640e7f 100644 --- a/internal/models/vouchersresponse.go +++ b/internal/models/vouchersresponse.go @@ -1,14 +1 @@ package models - -import dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" - -type VoucherHoldingResponse struct { - Ok bool `json:"ok"` - Description string `json:"description"` - Result VoucherResult `json:"result"` -} - -// VoucherResult holds the list of token holdings -type VoucherResult struct { - Holdings []dataserviceapi.TokenHoldings `json:"holdings"` -} diff --git a/internal/testutil/mocks/servicemock.go b/internal/testutil/mocks/servicemock.go index de0e99a..3b36ba7 100644 --- a/internal/testutil/mocks/servicemock.go +++ b/internal/testutil/mocks/servicemock.go @@ -5,6 +5,7 @@ import ( "git.grassecon.net/urdt/ussd/internal/models" "github.com/grassrootseconomics/eth-custodial/pkg/api" + dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" "github.com/stretchr/testify/mock" ) @@ -13,28 +14,28 @@ type MockAccountService struct { mock.Mock } -func (m *MockAccountService) CreateAccount(ctx context.Context) (*api.OKResponse, error) { +func (m *MockAccountService) CreateAccount(ctx context.Context) (*models.AccountResult, error) { args := m.Called() - return args.Get(0).(*api.OKResponse), args.Error(1) + return args.Get(0).(*models.AccountResult), args.Error(1) } -func (m *MockAccountService) CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResponse, error) { +func (m *MockAccountService) CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResult, error) { args := m.Called(publicKey) - return args.Get(0).(*models.BalanceResponse), args.Error(1) + return args.Get(0).(*models.BalanceResult), args.Error(1) } -func (m *MockAccountService) CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResponse, error) { +func (m *MockAccountService) TrackAccountStatus(ctx context.Context, trackingId string) (*api.OKResponse, error) { args := m.Called(trackingId) - return args.Get(0).(*models.TrackStatusResponse), args.Error(1) -} - -func (m *MockAccountService) TrackAccountStatus(ctx context.Context,publicKey string) (*api.OKResponse, error) { - args := m.Called(publicKey) return args.Get(0).(*api.OKResponse), args.Error(1) } - -func (m *MockAccountService) FetchVouchers(ctx context.Context, publicKey string) (*models.VoucherHoldingResponse, error) { +func (m *MockAccountService) CheckAccountStatus(ctx context.Context,publicKey string) (*models.TrackStatusResult, error) { args := m.Called(publicKey) - return args.Get(0).(*models.VoucherHoldingResponse), args.Error(1) + return args.Get(0).(*models.TrackStatusResult), args.Error(1) +} + + +func (m *MockAccountService) FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) { + args := m.Called(publicKey) + return args.Get(0).([]dataserviceapi.TokenHoldings), args.Error(1) } diff --git a/internal/testutil/testservice/TestAccountService.go b/internal/testutil/testservice/TestAccountService.go index 745b80d..885e63f 100644 --- a/internal/testutil/testservice/TestAccountService.go +++ b/internal/testutil/testservice/TestAccountService.go @@ -13,54 +13,29 @@ import ( type TestAccountService struct { } -func (tas *TestAccountService) CreateAccount(ctx context.Context) (*api.OKResponse, error) { - return &api.OKResponse{ - Ok: true, - Description: "Account creation succeeded", - Result: map[string]any{ - "trackingId": "075ccc86-f6ef-4d33-97d5-e91cfb37aa0d", - "publicKey": "0x623EFAFa8868df4B934dd12a8B26CB3Dd75A7AdD", - }, +func (tas *TestAccountService) CreateAccount(ctx context.Context) (*models.AccountResult, error) { + return &models.AccountResult { + TrackingId: "075ccc86-f6ef-4d33-97d5-e91cfb37aa0d", + PublicKey: "0x623EFAFa8868df4B934dd12a8B26CB3Dd75A7AdD", }, nil } -func (tas *TestAccountService) CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResponse, error) { - balanceResponse := &models.BalanceResponse{ - Ok: true, - Result: struct { - Balance string `json:"balance"` - Nonce json.Number `json:"nonce"` - }{ - Balance: "0.003 CELO", - Nonce: json.Number("0"), - }, +func (tas *TestAccountService) CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResult, error) { + balanceResponse := &models.BalanceResult { + Balance: "0.003 CELO", + Nonce: json.Number("0"), } - return balanceResponse, nil } -func (tas *TestAccountService) CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResponse, error) { - trackResponse := &models.TrackStatusResponse{ - Ok: true, - Result: struct { - Transaction struct { - CreatedAt time.Time "json:\"createdAt\"" - Status string "json:\"status\"" - TransferValue json.Number "json:\"transferValue\"" - TxHash string "json:\"txHash\"" - TxType string "json:\"txType\"" - } - }{ - Transaction: models.Transaction{ - CreatedAt: time.Now(), - Status: "SUCCESS", - TransferValue: json.Number("0.5"), - TxHash: "0x123abc456def", - TxType: "transfer", - }, - }, - } - return trackResponse, nil +func (tas *TestAccountService) CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResult, error) { + return &models.TrackStatusResult { + CreatedAt: time.Now(), + Status: "SUCCESS", + TransferValue: json.Number("0.5"), + TxHash: "0x123abc456def", + TxType: "transfer", + }, nil } func (tas *TestAccountService) TrackAccountStatus(ctx context.Context, publicKey string) (*api.OKResponse, error) { @@ -73,18 +48,13 @@ func (tas *TestAccountService) TrackAccountStatus(ctx context.Context, publicKey }, nil } -func (tas *TestAccountService) FetchVouchers(ctx context.Context, publicKey string) (*models.VoucherHoldingResponse, error) { - return &models.VoucherHoldingResponse{ - Ok: true, - Result: models.VoucherResult{ - Holdings: []dataserviceapi.TokenHoldings{ - { - ContractAddress: "0x6CC75A06ac72eB4Db2eE22F781F5D100d8ec03ee", - TokenSymbol: "SRF", - TokenDecimals: "6", - Balance: "2745987", - }, - }, +func (tas *TestAccountService) FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) { + return []dataserviceapi.TokenHoldings { + dataserviceapi.TokenHoldings { + ContractAddress: "0x6CC75A06ac72eB4Db2eE22F781F5D100d8ec03ee", + TokenSymbol: "SRF", + TokenDecimals: "6", + Balance: "2745987", }, - }, nil + }, nil } diff --git a/remote/accountservice.go b/remote/accountservice.go index 236ccf4..c11910f 100644 --- a/remote/accountservice.go +++ b/remote/accountservice.go @@ -4,27 +4,29 @@ import ( "context" "encoding/json" "errors" - "fmt" "io" "net/http" - "os" + "net/url" + dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" + "github.com/grassrootseconomics/eth-custodial/pkg/api" "git.grassecon.net/urdt/ussd/config" "git.grassecon.net/urdt/ussd/internal/models" - "github.com/grassrootseconomics/eth-custodial/pkg/api" ) var ( - okResponse api.OKResponse - errResponse api.ErrResponse ) type AccountServiceInterface interface { - CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResponse, error) - CreateAccount(ctx context.Context) (*api.OKResponse, error) - CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResponse, error) + //CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResponse, error) + CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResult, error) + CreateAccount(ctx context.Context) (*models.AccountResult, error) + //CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResponse, error) + // TODO: poorly named method seems to be checking transaction + CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResult, error) TrackAccountStatus(ctx context.Context, publicKey string) (*api.OKResponse, error) - FetchVouchers(ctx context.Context, publicKey string) (*models.VoucherHoldingResponse, error) + FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) + //FetchVouchers(ctx context.Context, publicKey string) (*api.OKResponse, error) } type AccountService struct { @@ -39,32 +41,38 @@ type AccountService struct { // - 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(ctx context.Context, trackingId string) (*models.TrackStatusResponse, error) { - resp, err := http.Get(config.BalanceURL + trackingId) - if err != nil { - return nil, err - } - defer resp.Body.Close() +func (as *AccountService) CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResult, error) { + var r models.TrackStatusResult - body, err := io.ReadAll(resp.Body) + ep, err := url.JoinPath(config.TrackURL, trackingId) if err != nil { return nil, err } - var trackResp models.TrackStatusResponse - err = json.Unmarshal(body, &trackResp) + req, err := http.NewRequest("GET", ep, nil) if err != nil { return nil, err } - return &trackResp, nil + _, err = doCustodialRequest(ctx, req, &r) + if err != nil { + return nil, err + } + + return &r, nil } func (as *AccountService) TrackAccountStatus(ctx context.Context, publicKey string) (*api.OKResponse, error) { + var okResponse api.OKResponse + var errResponse api.ErrResponse var err error - // Construct the URL with the path parameter - url := fmt.Sprintf("%s/%s", config.TrackURL, publicKey) - req, err := http.NewRequest("GET", url, nil) + + ep, err := url.JoinPath(config.TrackURL, publicKey) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", ep, nil) if err != nil { return nil, err } @@ -104,41 +112,83 @@ func (as *AccountService) TrackAccountStatus(ctx context.Context, publicKey stri // 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(ctx context.Context, publicKey string) (*models.BalanceResponse, error) { - resp, err := http.Get(config.BalanceURL + publicKey) +func (as *AccountService) CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResult, error) { + var balanceResult models.BalanceResult + + ep, err := url.JoinPath(config.BalanceURL, publicKey) if err != nil { return nil, err } - defer resp.Body.Close() - body, err := io.ReadAll(resp.Body) + + req, err := http.NewRequest("GET", ep, nil) if err != nil { return nil, err } - var balanceResp models.BalanceResponse - err = json.Unmarshal(body, &balanceResp) - if err != nil { - return nil, err - } - return &balanceResp, nil + + _, err = doCustodialRequest(ctx, req, &balanceResult) + return &balanceResult, err } + // 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(ctx context.Context) (*api.OKResponse, error) { - var err error - +func (as *AccountService) CreateAccount(ctx context.Context) (*models.AccountResult, error) { + var r models.AccountResult // Create a new request req, err := http.NewRequest("POST", config.CreateAccountURL, nil) if err != nil { return nil, err } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-GE-KEY", "xd") + _, err = doCustodialRequest(ctx, req, &r) + if err != nil { + return nil, err + } + + return &r, nil +} + +// FetchVouchers retrieves the token holdings for a given public key from the custodial holdings API endpoint +// Parameters: +// - publicKey: The public key associated with the account. +func (as *AccountService) FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) { + var r []dataserviceapi.TokenHoldings + + req, err := http.NewRequest("GET", config.VoucherHoldingsURL, nil) + if err != nil { + return nil, err + } + + _, err = doDataRequest(ctx, req, r) + if err != nil { + return nil, err + } + + return r, nil + +// +// file, err := os.Open("sample_tokens.json") +// if err != nil { +// return nil, err +// } +// defer file.Close() +// var holdings models.VoucherHoldingResponse +// +// if err := json.NewDecoder(file).Decode(&holdings); err != nil { +// return nil, err +// } +// return &holdings, nil +} + +func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { + var okResponse api.OKResponse + var errResponse api.ErrResponse + + req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { errResponse.Description = err.Error() @@ -165,21 +215,22 @@ func (as *AccountService) CreateAccount(ctx context.Context) (*api.OKResponse, e return nil, errors.New("Empty api result") } return &okResponse, nil -} -// FetchVouchers retrieves the token holdings for a given public key from the custodial holdings API endpoint -// Parameters: -// - publicKey: The public key associated with the account. -func (as *AccountService) FetchVouchers(ctx context.Context, publicKey string) (*models.VoucherHoldingResponse, error) { - file, err := os.Open("sample_tokens.json") + v, err := json.Marshal(okResponse.Result) if err != nil { return nil, err } - defer file.Close() - var holdings models.VoucherHoldingResponse - if err := json.NewDecoder(file).Decode(&holdings); err != nil { - return nil, err - } - return &holdings, nil + err = json.Unmarshal(v, &rcpt) + return &okResponse, err +} + +func doCustodialRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { + req.Header.Set("X-GE-KEY", config.CustodialAPIKey) + return doRequest(ctx, req, rcpt) +} + +func doDataRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { + req.Header.Set("X-GE-KEY", config.DataAPIKey) + return doRequest(ctx, req, rcpt) } From a48170321c03aa232aabf7065f98c08c947e6e9f Mon Sep 17 00:00:00 2001 From: lash Date: Thu, 31 Oct 2024 01:51:36 +0000 Subject: [PATCH 171/289] Finish refactor result models --- internal/handlers/ussd/menuhandler_test.go | 136 ++++++--------------- 1 file changed, 36 insertions(+), 100 deletions(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 5f3c953..77447ca 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -88,18 +88,14 @@ func TestCreateAccount(t *testing.T) { tests := []struct { name string - serverResponse *api.OKResponse + serverResponse *models.AccountResult expectedResult resource.Result }{ { name: "Test account creation success", - serverResponse: &api.OKResponse{ - Ok: true, - Description: "Account creation successed", - Result: map[string]any{ - "trackingId": "1234567890", - "publicKey": "0xD3adB33f", - }, + serverResponse: &models.AccountResult{ + TrackingId: "1234567890", + PublicKey: "0xD3adB33f", }, expectedResult: resource.Result{ FlagSet: []uint32{flag_account_created}, @@ -119,9 +115,9 @@ func TestCreateAccount(t *testing.T) { flagManager: fm.parser, } - publicKey := tt.serverResponse.Result["publicKey"].(string) + publicKey := tt.serverResponse.PublicKey data := map[common.DataTyp]string{ - common.DATA_TRACKING_ID: tt.serverResponse.Result["trackingId"].(string), + common.DATA_TRACKING_ID: tt.serverResponse.TrackingId, common.DATA_PUBLIC_KEY: publicKey, } @@ -1055,7 +1051,7 @@ func TestCheckAccountStatus(t *testing.T) { name string input []byte serverResponse *api.OKResponse - response *models.TrackStatusResponse + response *models.TrackStatusResult expectedResult resource.Result }{ { @@ -1068,25 +1064,12 @@ func TestCheckAccountStatus(t *testing.T) { "active": true, }, }, - response: &models.TrackStatusResponse{ - Ok: true, - Result: struct { - Transaction struct { - CreatedAt time.Time "json:\"createdAt\"" - Status string "json:\"status\"" - TransferValue json.Number "json:\"transferValue\"" - TxHash string "json:\"txHash\"" - TxType string "json:\"txType\"" - } - }{ - Transaction: models.Transaction{ - CreatedAt: time.Now(), - Status: "SUCCESS", - TransferValue: json.Number("0.5"), - TxHash: "0x123abc456def", - TxType: "transfer", - }, - }, + response: &models.TrackStatusResult { + CreatedAt: time.Now(), + Status: "SUCCESS", + TransferValue: json.Number("0.5"), + TxHash: "0x123abc456def", + TxType: "transfer", }, expectedResult: resource.Result{ FlagSet: []uint32{flag_account_success}, @@ -1096,25 +1079,12 @@ func TestCheckAccountStatus(t *testing.T) { { name: "Test when the account is not yet on the sarafu network", input: []byte("TrackingId1234"), - response: &models.TrackStatusResponse{ - Ok: true, - Result: struct { - Transaction struct { - CreatedAt time.Time "json:\"createdAt\"" - Status string "json:\"status\"" - TransferValue json.Number "json:\"transferValue\"" - TxHash string "json:\"txHash\"" - TxType string "json:\"txType\"" - } - }{ - Transaction: models.Transaction{ - CreatedAt: time.Now(), - Status: "SUCCESS", - TransferValue: json.Number("0.5"), - TxHash: "0x123abc456def", - TxType: "transfer", - }, - }, + response: &models.TrackStatusResult{ + CreatedAt: time.Now(), + Status: "SUCCESS", + TransferValue: json.Number("0.5"), + TxHash: "0x123abc456def", + TxType: "transfer", }, serverResponse: &api.OKResponse{ Ok: true, @@ -1140,7 +1110,7 @@ func TestCheckAccountStatus(t *testing.T) { flagManager: fm.parser, } - status := tt.response.Result.Transaction.Status + status := tt.response.Status // Define expected interactions with the mock mockDataStore.On("ReadEntry", ctx, sessionId, common.DATA_PUBLIC_KEY).Return(tt.input, nil) @@ -1833,36 +1803,14 @@ func TestFetchCustodialBalances(t *testing.T) { tests := []struct { name string - balanceResonse *models.BalanceResponse + balanceResponse *models.BalanceResult expectedResult resource.Result }{ { name: "Test when fetch custodial balances is not a success", - balanceResonse: &models.BalanceResponse{ - Ok: false, - Result: struct { - Balance string `json:"balance"` - Nonce json.Number `json:"nonce"` - }{ - Balance: "0.003 CELO", - Nonce: json.Number("0"), - }, - }, - expectedResult: resource.Result{ - FlagSet: []uint32{flag_api_error}, - }, - }, - { - name: "Test when fetch custodial balances is a success", - balanceResonse: &models.BalanceResponse{ - Ok: true, - Result: struct { - Balance string `json:"balance"` - Nonce json.Number `json:"nonce"` - }{ - Balance: "0.003 CELO", - Nonce: json.Number("0"), - }, + balanceResponse: &models.BalanceResult{ + Balance: "0.003 CELO", + Nonce: json.Number("0"), }, expectedResult: resource.Result{ FlagReset: []uint32{flag_api_error}, @@ -1886,7 +1834,7 @@ func TestFetchCustodialBalances(t *testing.T) { // Set up the expected behavior of the mock mockDataStore.On("ReadEntry", ctx, sessionId, common.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil) - mockCreateAccountService.On("CheckBalance", string(publicKey)).Return(tt.balanceResonse, nil) + mockCreateAccountService.On("CheckBalance", string(publicKey)).Return(tt.balanceResponse, nil) // Call the method res, _ := h.FetchCustodialBalances(ctx, "fetch_custodial_balances", []byte("")) @@ -1918,35 +1866,24 @@ func TestSetDefaultVoucher(t *testing.T) { tests := []struct { name string - vouchersResp *models.VoucherHoldingResponse + vouchersResp []dataserviceapi.TokenHoldings expectedResult resource.Result }{ { name: "Test set default voucher when no active voucher exists", - vouchersResp: &models.VoucherHoldingResponse{ - Ok: true, - Description: "Vouchers fetched successfully", - Result: models.VoucherResult{ - Holdings: []dataserviceapi.TokenHoldings{ - { - ContractAddress: "0x123", - TokenSymbol: "TOKEN1", - TokenDecimals: "18", - Balance: "100", - }, - }, + vouchersResp: []dataserviceapi.TokenHoldings { + dataserviceapi.TokenHoldings{ + ContractAddress: "0x123", + TokenSymbol: "TOKEN1", + TokenDecimals: "18", + Balance: "100", }, }, expectedResult: resource.Result{}, }, { name: "Test no vouchers available", - vouchersResp: &models.VoucherHoldingResponse{ - Ok: true, - Description: "No vouchers available", - Result: models.VoucherResult{ - Holdings: []dataserviceapi.TokenHoldings{}, - }, + vouchersResp: []dataserviceapi.TokenHoldings { }, expectedResult: resource.Result{ FlagSet: []uint32{flag_no_active_voucher}, @@ -1970,8 +1907,8 @@ func TestSetDefaultVoucher(t *testing.T) { mockAccountService.On("FetchVouchers", string(publicKey)).Return(tt.vouchersResp, nil) - if len(tt.vouchersResp.Result.Holdings) > 0 { - firstVoucher := tt.vouchersResp.Result.Holdings[0] + if len(tt.vouchersResp) > 0 { + firstVoucher := tt.vouchersResp[0] mockDataStore.On("WriteEntry", ctx, sessionId, common.DATA_ACTIVE_SYM, []byte(firstVoucher.TokenSymbol)).Return(nil) mockDataStore.On("WriteEntry", ctx, sessionId, common.DATA_ACTIVE_BAL, []byte(firstVoucher.Balance)).Return(nil) } @@ -2006,8 +1943,7 @@ func TestCheckVouchers(t *testing.T) { mockDataStore.On("ReadEntry", ctx, sessionId, common.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil) - mockVouchersResponse := &models.VoucherHoldingResponse{} - mockVouchersResponse.Result.Holdings = []dataserviceapi.TokenHoldings{ + mockVouchersResponse := []dataserviceapi.TokenHoldings{ {ContractAddress: "0xd4c288865Ce", TokenSymbol: "SRF", TokenDecimals: "6", Balance: "100"}, {ContractAddress: "0x41c188d63Qa", TokenSymbol: "MILO", TokenDecimals: "4", Balance: "200"}, } From dc198215b1272f5f745babe3e3319295572fac3c Mon Sep 17 00:00:00 2001 From: lash Date: Thu, 31 Oct 2024 02:03:29 +0000 Subject: [PATCH 172/289] Remove commented code --- internal/handlers/ussd/menuhandler.go | 1 - internal/handlers/ussd/menuhandler_test.go | 1 - internal/models/balanceresponse.go | 8 -------- internal/models/trackstatusresponse.go | 7 ------- internal/models/vouchersresponse.go | 1 - remote/accountservice.go | 16 ---------------- 6 files changed, 34 deletions(-) delete mode 100644 internal/models/vouchersresponse.go diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 5f6f81a..98a633c 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -705,7 +705,6 @@ func (h *Handlers) FetchCustodialBalances(ctx context.Context, sym string, input } res.FlagReset = append(res.FlagReset, flag_api_error) - //balance := balanceResponse.Result.Balance balance := balanceResponse.Balance switch balanceType { diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 77447ca..8708145 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -815,7 +815,6 @@ func TestAuthorize(t *testing.T) { // Create required mocks mockDataStore := new(mocks.MockUserDataStore) mockCreateAccountService := new(mocks.MockAccountService) - //expectedResult := resource.Result{} mockState := state.NewState(16) flag_incorrect_pin, _ := fm.GetFlag("flag_incorrect_pin") flag_account_authorized, _ := fm.GetFlag("flag_account_authorized") diff --git a/internal/models/balanceresponse.go b/internal/models/balanceresponse.go index 3d57c95..b2baa41 100644 --- a/internal/models/balanceresponse.go +++ b/internal/models/balanceresponse.go @@ -3,14 +3,6 @@ package models import "encoding/json" -//type BalanceResponse struct { -// Ok bool `json:"ok"` -// Result struct { -// Balance string `json:"balance"` -// Nonce json.Number `json:"nonce"` -// } `json:"result"` -//} -// type BalanceResult struct { Balance string `json:"balance"` Nonce json.Number `json:"nonce"` diff --git a/internal/models/trackstatusresponse.go b/internal/models/trackstatusresponse.go index 6130c6e..202b69b 100644 --- a/internal/models/trackstatusresponse.go +++ b/internal/models/trackstatusresponse.go @@ -4,13 +4,6 @@ import ( "encoding/json" "time" ) -//type Transaction struct { -// CreatedAt time.Time `json:"createdAt"` -// Status string `json:"status"` -// TransferValue json.Number `json:"transferValue"` -// TxHash string `json:"txHash"` -// TxType string `json:"txType"` -//} type TrackStatusResult struct { CreatedAt time.Time `json:"createdAt"` diff --git a/internal/models/vouchersresponse.go b/internal/models/vouchersresponse.go deleted file mode 100644 index 2640e7f..0000000 --- a/internal/models/vouchersresponse.go +++ /dev/null @@ -1 +0,0 @@ -package models diff --git a/remote/accountservice.go b/remote/accountservice.go index c11910f..bc98cf1 100644 --- a/remote/accountservice.go +++ b/remote/accountservice.go @@ -18,15 +18,12 @@ var ( ) type AccountServiceInterface interface { - //CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResponse, error) CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResult, error) CreateAccount(ctx context.Context) (*models.AccountResult, error) - //CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResponse, error) // TODO: poorly named method seems to be checking transaction CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResult, error) TrackAccountStatus(ctx context.Context, publicKey string) (*api.OKResponse, error) FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) - //FetchVouchers(ctx context.Context, publicKey string) (*api.OKResponse, error) } type AccountService struct { @@ -169,19 +166,6 @@ func (as *AccountService) FetchVouchers(ctx context.Context, publicKey string) ( } return r, nil - -// -// file, err := os.Open("sample_tokens.json") -// if err != nil { -// return nil, err -// } -// defer file.Close() -// var holdings models.VoucherHoldingResponse -// -// if err := json.NewDecoder(file).Decode(&holdings); err != nil { -// return nil, err -// } -// return &holdings, nil } func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { From c4078c528005012a6f3053ff55a6e7cbbc108c0b Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 31 Oct 2024 09:21:46 +0300 Subject: [PATCH 173/289] remove extra spaces --- services/registration/confirm_others_new_pin | 2 +- services/registration/pin_reset_success.vis | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/services/registration/confirm_others_new_pin b/services/registration/confirm_others_new_pin index 46c3275..d345a0a 100644 --- a/services/registration/confirm_others_new_pin +++ b/services/registration/confirm_others_new_pin @@ -1 +1 @@ -Please confirm new PIN for: {{.retrieve_blocked_number}} \ No newline at end of file +Please confirm new PIN for:{{.retrieve_blocked_number}} \ No newline at end of file diff --git a/services/registration/pin_reset_success.vis b/services/registration/pin_reset_success.vis index c942519..96dee73 100644 --- a/services/registration/pin_reset_success.vis +++ b/services/registration/pin_reset_success.vis @@ -6,5 +6,3 @@ MOUT quit 9 HALT INCMP main 0 INCMP quit 9 - - From 767a3cd64c700b59c1a54b42c57df7c0a1dd6c2b Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 31 Oct 2024 09:38:51 +0300 Subject: [PATCH 174/289] remove pin guard menu option --- services/registration/guard_pin_menu | 1 - services/registration/guard_pin_menu_swa | 1 - 2 files changed, 2 deletions(-) delete mode 100644 services/registration/guard_pin_menu delete mode 100644 services/registration/guard_pin_menu_swa diff --git a/services/registration/guard_pin_menu b/services/registration/guard_pin_menu deleted file mode 100644 index 9de0ba0..0000000 --- a/services/registration/guard_pin_menu +++ /dev/null @@ -1 +0,0 @@ -Guard my PIN \ No newline at end of file diff --git a/services/registration/guard_pin_menu_swa b/services/registration/guard_pin_menu_swa deleted file mode 100644 index c6b126f..0000000 --- a/services/registration/guard_pin_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Linda PIN yangu \ No newline at end of file From bab3f673ebb028d4ad2c174aa7f86a6721b80067 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 31 Oct 2024 14:13:21 +0300 Subject: [PATCH 175/289] Removed unused model --- internal/models/tokenresponse.go | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 internal/models/tokenresponse.go diff --git a/internal/models/tokenresponse.go b/internal/models/tokenresponse.go deleted file mode 100644 index d243d93..0000000 --- a/internal/models/tokenresponse.go +++ /dev/null @@ -1,18 +0,0 @@ -package models - -type ApiResponse struct { - OK bool `json:"ok"` - Description string `json:"description"` - Result Result `json:"result"` -} - -type Result struct { - Holdings []Holding `json:"holdings"` -} - -type Holding struct { - ContractAddress string `json:"contractAddress"` - TokenSymbol string `json:"tokenSymbol"` - TokenDecimals string `json:"tokenDecimals"` - Balance string `json:"balance"` -} From 05ed236e03b48de4500fd3fd482ad42c60aa65ae Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 31 Oct 2024 14:14:10 +0300 Subject: [PATCH 176/289] add node to update individual profile information --- services/registration/update_age | 2 ++ services/registration/update_familyname.vis | 2 ++ services/registration/update_firstname.vis | 2 ++ services/registration/update_gender.vis | 2 ++ services/registration/update_location.vis | 2 ++ services/registration/update_offerings.vis | 2 ++ services/registration/update_yob.vis | 2 ++ 7 files changed, 14 insertions(+) create mode 100644 services/registration/update_age create mode 100644 services/registration/update_familyname.vis create mode 100644 services/registration/update_firstname.vis create mode 100644 services/registration/update_gender.vis create mode 100644 services/registration/update_location.vis create mode 100644 services/registration/update_offerings.vis create mode 100644 services/registration/update_yob.vis diff --git a/services/registration/update_age b/services/registration/update_age new file mode 100644 index 0000000..76ca306 --- /dev/null +++ b/services/registration/update_age @@ -0,0 +1,2 @@ +RELOAD save_yob +CATCH profile_update_success flag_allow_update 1 \ No newline at end of file diff --git a/services/registration/update_familyname.vis b/services/registration/update_familyname.vis new file mode 100644 index 0000000..7cd4d9f --- /dev/null +++ b/services/registration/update_familyname.vis @@ -0,0 +1,2 @@ +RELOAD save_familyname +CATCH profile_update_success flag_allow_update 1 diff --git a/services/registration/update_firstname.vis b/services/registration/update_firstname.vis new file mode 100644 index 0000000..dca7036 --- /dev/null +++ b/services/registration/update_firstname.vis @@ -0,0 +1,2 @@ +RELOAD save_firstname +CATCH profile_update_success flag_allow_update 1 diff --git a/services/registration/update_gender.vis b/services/registration/update_gender.vis new file mode 100644 index 0000000..506a56a --- /dev/null +++ b/services/registration/update_gender.vis @@ -0,0 +1,2 @@ +RELOAD save_gender +CATCH profile_update_success flag_allow_update 1 diff --git a/services/registration/update_location.vis b/services/registration/update_location.vis new file mode 100644 index 0000000..16c4ea2 --- /dev/null +++ b/services/registration/update_location.vis @@ -0,0 +1,2 @@ +RELOAD save_location +CATCH profile_update_success flag_allow_update 1 diff --git a/services/registration/update_offerings.vis b/services/registration/update_offerings.vis new file mode 100644 index 0000000..4aeed74 --- /dev/null +++ b/services/registration/update_offerings.vis @@ -0,0 +1,2 @@ +RELOAD save_offerings +CATCH profile_update_success flag_allow_update 1 diff --git a/services/registration/update_yob.vis b/services/registration/update_yob.vis new file mode 100644 index 0000000..a9388ae --- /dev/null +++ b/services/registration/update_yob.vis @@ -0,0 +1,2 @@ +RELOAD save_yob +CATCH profile_update_success flag_allow_update 1 From 981f7ca4f6a68d55429ce8efc99c0aee53d217d8 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 31 Oct 2024 14:14:50 +0300 Subject: [PATCH 177/289] add keys to for holding temporary profile info --- internal/utils/db.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/internal/utils/db.go b/internal/utils/db.go index 2c1e6fa..e8e7fbc 100644 --- a/internal/utils/db.go +++ b/internal/utils/db.go @@ -14,11 +14,17 @@ const ( DATA_CUSTODIAL_ID DATA_ACCOUNT_PIN DATA_ACCOUNT_STATUS + DATA_TEMPORARY_FIRST_NAME DATA_FIRST_NAME + DATA_TEMPORARY_FAMILY_NAME DATA_FAMILY_NAME + DATA_TEMPORARY_YOB DATA_YOB + DATA_TEMPORARY_LOCATION DATA_LOCATION + DATA_TEMPORARY_GENDER DATA_GENDER + DATA_TEMPORARY_OFFERINGS DATA_OFFERINGS DATA_RECIPIENT DATA_AMOUNT @@ -29,6 +35,7 @@ const ( DATA_TEMPORARY_BAL DATA_ACTIVE_BAL DATA_PUBLIC_KEY_REVERSE + ) func typToBytes(typ DataTyp) []byte { From 211cc1f7751b64b9c70e52d80697ec6c056def10 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 31 Oct 2024 14:19:12 +0300 Subject: [PATCH 178/289] perform profile update in individual update node --- services/registration/set_female.vis | 2 +- services/registration/set_male.vis | 2 +- services/registration/set_unspecified.vis | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/services/registration/set_female.vis b/services/registration/set_female.vis index 723b080..e211ada 100644 --- a/services/registration/set_female.vis +++ b/services/registration/set_female.vis @@ -1,4 +1,4 @@ LOAD save_gender 0 CATCH incorrect_pin flag_incorrect_pin 1 -CATCH profile_update_success flag_allow_update 1 +CATCH update_gender flag_allow_update 1 MOVE pin_entry diff --git a/services/registration/set_male.vis b/services/registration/set_male.vis index 723b080..e211ada 100644 --- a/services/registration/set_male.vis +++ b/services/registration/set_male.vis @@ -1,4 +1,4 @@ LOAD save_gender 0 CATCH incorrect_pin flag_incorrect_pin 1 -CATCH profile_update_success flag_allow_update 1 +CATCH update_gender flag_allow_update 1 MOVE pin_entry diff --git a/services/registration/set_unspecified.vis b/services/registration/set_unspecified.vis index 723b080..e211ada 100644 --- a/services/registration/set_unspecified.vis +++ b/services/registration/set_unspecified.vis @@ -1,4 +1,4 @@ LOAD save_gender 0 CATCH incorrect_pin flag_incorrect_pin 1 -CATCH profile_update_success flag_allow_update 1 +CATCH update_gender flag_allow_update 1 MOVE pin_entry From c45fcda2f16e30df9297e0604905ae40839b17f1 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 31 Oct 2024 14:20:04 +0300 Subject: [PATCH 179/289] remove back option check,protect profile data update --- internal/handlers/ussd/menuhandler.go | 118 +++++++++++++++++--------- 1 file changed, 80 insertions(+), 38 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index dae4236..36d8a4a 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -19,9 +19,9 @@ import ( "git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/state" + "git.grassecon.net/urdt/ussd/common" "git.grassecon.net/urdt/ussd/internal/handlers/server" "git.grassecon.net/urdt/ussd/internal/utils" - "git.grassecon.net/urdt/ussd/common" "gopkg.in/leonelquinteros/gotext.v1" "git.grassecon.net/urdt/ussd/internal/storage" @@ -33,7 +33,6 @@ var ( translationDir = path.Join(scriptDir, "locale") okResponse *api.OKResponse errResponse *api.ErrResponse - backOption = []byte("0") ) // FlagManager handles centralized flag management @@ -329,13 +328,18 @@ func (h *Handlers) SaveFirstname(ctx context.Context, sym string, input []byte) if !ok { return res, fmt.Errorf("missing session") } - if len(input) > 0 { - if bytes.Equal(input, backOption) { - return res, nil + firstName := string(input) + store := h.userdataStore + flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") + allowUpdate := h.st.MatchFlag(flag_allow_update, true) + if allowUpdate { + temporaryFirstName, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_FIRST_NAME) + err = store.WriteEntry(ctx, sessionId, utils.DATA_FIRST_NAME, []byte(temporaryFirstName)) + if err != nil { + return res, err } - firstName := string(input) - store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_FIRST_NAME, []byte(firstName)) + } else { + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_FIRST_NAME, []byte(firstName)) if err != nil { return res, err } @@ -352,20 +356,24 @@ func (h *Handlers) SaveFamilyname(ctx context.Context, sym string, input []byte) if !ok { return res, fmt.Errorf("missing session") } - if len(input) > 0 { - if bytes.Equal(input, backOption) { - return res, nil - } - familyName := string(input) - store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_FAMILY_NAME, []byte(familyName)) + store := h.userdataStore + familyName := string(input) + + flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") + allowUpdate := h.st.MatchFlag(flag_allow_update, true) + + if allowUpdate { + temporaryFamilyName, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_FAMILY_NAME) + err = store.WriteEntry(ctx, sessionId, utils.DATA_FAMILY_NAME, []byte(temporaryFamilyName)) if err != nil { return res, err } } else { - return res, fmt.Errorf("a family name cannot be less than one character") + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_FAMILY_NAME, []byte(familyName)) + if err != nil { + return res, err + } } - return res, nil } @@ -377,10 +385,19 @@ func (h *Handlers) SaveYob(ctx context.Context, sym string, input []byte) (resou if !ok { return res, fmt.Errorf("missing session") } - if len(input) == 4 { - yob := string(input) - store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_YOB, []byte(yob)) + yob := string(input) + store := h.userdataStore + flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") + allowUpdate := h.st.MatchFlag(flag_allow_update, true) + + if allowUpdate { + temporaryYob, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_YOB) + err = store.WriteEntry(ctx, sessionId, utils.DATA_YOB, []byte(temporaryYob)) + if err != nil { + return res, err + } + } else { + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_YOB, []byte(yob)) if err != nil { return res, err } @@ -397,13 +414,20 @@ func (h *Handlers) SaveLocation(ctx context.Context, sym string, input []byte) ( if !ok { return res, fmt.Errorf("missing session") } - if len(input) > 0 { - if bytes.Equal(input, backOption) { - return res, nil + location := string(input) + store := h.userdataStore + + flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") + allowUpdate := h.st.MatchFlag(flag_allow_update, true) + + if allowUpdate { + temporaryLocation, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_LOCATION) + err = store.WriteEntry(ctx, sessionId, utils.DATA_LOCATION, []byte(temporaryLocation)) + if err != nil { + return res, err } - location := string(input) - store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_LOCATION, []byte(location)) + } else { + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_LOCATION, []byte(location)) if err != nil { return res, err } @@ -421,14 +445,22 @@ func (h *Handlers) SaveGender(ctx context.Context, sym string, input []byte) (re if !ok { return res, fmt.Errorf("missing session") } - if bytes.Equal(input, backOption) { - return res, nil - } gender := strings.Split(symbol, "_")[1] store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_GENDER, []byte(gender)) - if err != nil { - return res, nil + flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") + allowUpdate := h.st.MatchFlag(flag_allow_update, true) + + if allowUpdate { + temporaryGender, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_GENDER) + err = store.WriteEntry(ctx, sessionId, utils.DATA_GENDER, []byte(temporaryGender)) + if err != nil { + return res, err + } + } else { + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_GENDER, []byte(gender)) + if err != nil { + return res, err + } } return res, nil @@ -442,12 +474,22 @@ func (h *Handlers) SaveOfferings(ctx context.Context, sym string, input []byte) if !ok { return res, fmt.Errorf("missing session") } - if len(input) > 0 { - offerings := string(input) - store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_OFFERINGS, []byte(offerings)) + offerings := string(input) + store := h.userdataStore + + flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") + allowUpdate := h.st.MatchFlag(flag_allow_update, true) + + if allowUpdate { + temporaryOfferings, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_OFFERINGS) + err = store.WriteEntry(ctx, sessionId, utils.DATA_OFFERINGS, []byte(temporaryOfferings)) if err != nil { - return res, nil + return res, err + } + } else { + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_OFFERINGS, []byte(offerings)) + if err != nil { + return res, err } } From d25128287e5644f89a2199a619a87dcbb654df90 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 31 Oct 2024 14:21:22 +0300 Subject: [PATCH 180/289] update profile information on individual node --- services/registration/enter_familyname.vis | 2 +- services/registration/enter_location.vis | 2 +- services/registration/enter_name.vis | 2 +- services/registration/enter_offerings.vis | 2 +- services/registration/enter_yob.vis | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/services/registration/enter_familyname.vis b/services/registration/enter_familyname.vis index 5a684ed..5db4c17 100644 --- a/services/registration/enter_familyname.vis +++ b/services/registration/enter_familyname.vis @@ -1,5 +1,5 @@ CATCH incorrect_pin flag_incorrect_pin 1 -CATCH profile_update_success flag_allow_update 1 +CATCH update_familyname flag_allow_update 1 MOUT back 0 HALT LOAD save_familyname 0 diff --git a/services/registration/enter_location.vis b/services/registration/enter_location.vis index c8da2dd..8966872 100644 --- a/services/registration/enter_location.vis +++ b/services/registration/enter_location.vis @@ -1,5 +1,5 @@ CATCH incorrect_pin flag_incorrect_pin 1 -CATCH profile_update_success flag_allow_update 1 +CATCH update_location flag_allow_update 1 MOUT back 0 HALT LOAD save_location 0 diff --git a/services/registration/enter_name.vis b/services/registration/enter_name.vis index 799b2a1..f853d0a 100644 --- a/services/registration/enter_name.vis +++ b/services/registration/enter_name.vis @@ -1,5 +1,5 @@ CATCH incorrect_pin flag_incorrect_pin 1 -CATCH profile_update_success flag_allow_update 1 +CATCH update_firstname flag_allow_update 1 MOUT back 0 HALT LOAD save_firstname 0 diff --git a/services/registration/enter_offerings.vis b/services/registration/enter_offerings.vis index 26e4b61..5cc7977 100644 --- a/services/registration/enter_offerings.vis +++ b/services/registration/enter_offerings.vis @@ -1,5 +1,5 @@ CATCH incorrect_pin flag_incorrect_pin 1 -CATCH profile_update_success flag_allow_update 1 +CATCH update_offerings flag_allow_update 1 LOAD save_offerings 0 MOUT back 0 HALT diff --git a/services/registration/enter_yob.vis b/services/registration/enter_yob.vis index 40bf3f4..c74aeed 100644 --- a/services/registration/enter_yob.vis +++ b/services/registration/enter_yob.vis @@ -1,10 +1,10 @@ CATCH incorrect_pin flag_incorrect_pin 1 -CATCH profile_update_success flag_allow_update 1 -LOAD save_yob 0 +CATCH update_yob flag_allow_update 1 MOUT back 0 HALT LOAD verify_yob 0 CATCH incorrect_date_format flag_incorrect_date_format 1 +LOAD save_yob 0 RELOAD save_yob INCMP _ 0 INCMP pin_entry * From b8bbd88078356e007809b0576200e7dad942d462 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 31 Oct 2024 14:26:28 +0300 Subject: [PATCH 181/289] retain the temporary data for it to be overwritten --- internal/utils/vouchers.go | 17 +---------------- internal/utils/vouchers_test.go | 19 ------------------- 2 files changed, 1 insertion(+), 35 deletions(-) diff --git a/internal/utils/vouchers.go b/internal/utils/vouchers.go index 73a95a6..dc6cc4a 100644 --- a/internal/utils/vouchers.go +++ b/internal/utils/vouchers.go @@ -143,7 +143,7 @@ func GetTemporaryVoucherData(ctx context.Context, store DataStore, sessionId str return data, nil } -// UpdateVoucherData sets the active voucher data and clears the temporary voucher data in the DataStore. +// UpdateVoucherData sets the active voucher data in the DataStore. func UpdateVoucherData(ctx context.Context, store DataStore, sessionId string, data *dataserviceapi.TokenHoldings) error { // Active voucher data entries activeEntries := map[DataTyp][]byte{ @@ -153,14 +153,6 @@ func UpdateVoucherData(ctx context.Context, store DataStore, sessionId string, d DATA_ACTIVE_ADDRESS: []byte(data.ContractAddress), } - // Clear temporary voucher data entries - tempEntries := map[DataTyp][]byte{ - DATA_TEMPORARY_SYM: []byte(""), - DATA_TEMPORARY_BAL: []byte(""), - DATA_TEMPORARY_DECIMAL: []byte(""), - DATA_TEMPORARY_ADDRESS: []byte(""), - } - // Write active data for key, value := range activeEntries { if err := store.WriteEntry(ctx, sessionId, key, value); err != nil { @@ -168,12 +160,5 @@ func UpdateVoucherData(ctx context.Context, store DataStore, sessionId string, d } } - // Clear temporary data - for key, value := range tempEntries { - if err := store.WriteEntry(ctx, sessionId, key, value); err != nil { - return err - } - } - return nil } diff --git a/internal/utils/vouchers_test.go b/internal/utils/vouchers_test.go index 953182e..a609d27 100644 --- a/internal/utils/vouchers_test.go +++ b/internal/utils/vouchers_test.go @@ -31,11 +31,6 @@ func InitializeTestDb(t *testing.T) (context.Context, *UserDataStore) { return ctx, store } -// AssertEmptyValue checks if a value is empty/nil/zero -func AssertEmptyValue(t *testing.T, value []byte, msgAndArgs ...interface{}) { - assert.Equal(t, len(value), 0, msgAndArgs...) -} - func TestMatchVoucher(t *testing.T) { symbols := "1:SRF\n2:MILO" balances := "1:100\n2:200" @@ -205,18 +200,4 @@ func TestUpdateVoucherData(t *testing.T) { require.NoError(t, err) require.Equal(t, expectedValue, storedValue, "Active data mismatch for key %v", key) } - - // Verify temporary data was cleared - tempKeys := []DataTyp{ - DATA_TEMPORARY_SYM, - DATA_TEMPORARY_BAL, - DATA_TEMPORARY_DECIMAL, - DATA_TEMPORARY_ADDRESS, - } - - for _, key := range tempKeys { - storedValue, err := store.ReadEntry(ctx, sessionId, key) - require.NoError(t, err) - AssertEmptyValue(t, storedValue, "Temporary data not cleared for key %v", key) - } } From b9c56b04ce3f1eee05cfcc20a55eb38ee769a4ab Mon Sep 17 00:00:00 2001 From: lash Date: Thu, 31 Oct 2024 11:43:27 +0000 Subject: [PATCH 182/289] Remove obsolete track account status code --- internal/handlers/ussd/menuhandler_test.go | 17 ++++------------- internal/models/trackstatusresponse.go | 6 +++++- .../testutil/testservice/TestAccountService.go | 7 +------ 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 8708145..8c3867a 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -7,7 +7,6 @@ import ( "log" "path" "testing" - "time" "git.defalsify.org/vise.git/asm" "git.defalsify.org/vise.git/db" @@ -1064,11 +1063,7 @@ func TestCheckAccountStatus(t *testing.T) { }, }, response: &models.TrackStatusResult { - CreatedAt: time.Now(), - Status: "SUCCESS", - TransferValue: json.Number("0.5"), - TxHash: "0x123abc456def", - TxType: "transfer", + Active: true, }, expectedResult: resource.Result{ FlagSet: []uint32{flag_account_success}, @@ -1079,11 +1074,7 @@ func TestCheckAccountStatus(t *testing.T) { name: "Test when the account is not yet on the sarafu network", input: []byte("TrackingId1234"), response: &models.TrackStatusResult{ - CreatedAt: time.Now(), - Status: "SUCCESS", - TransferValue: json.Number("0.5"), - TxHash: "0x123abc456def", - TxType: "transfer", + Active: false, }, serverResponse: &api.OKResponse{ Ok: true, @@ -1109,13 +1100,13 @@ func TestCheckAccountStatus(t *testing.T) { flagManager: fm.parser, } - status := tt.response.Status + status := tt.response.Active // Define expected interactions with the mock mockDataStore.On("ReadEntry", ctx, sessionId, common.DATA_PUBLIC_KEY).Return(tt.input, nil) mockCreateAccountService.On("CheckAccountStatus", string(tt.input)).Return(tt.response, nil) mockCreateAccountService.On("TrackAccountStatus", string(tt.input)).Return(tt.serverResponse, nil) - mockDataStore.On("WriteEntry", ctx, sessionId, common.DATA_ACCOUNT_STATUS, []byte(status)).Return(nil).Maybe() + mockDataStore.On("WriteEntry", ctx, sessionId, common.DATA_ACCOUNT_STATUS, status).Return(nil).Maybe() // Call the method under test res, _ := h.CheckAccountStatus(ctx, "check_account_status", tt.input) diff --git a/internal/models/trackstatusresponse.go b/internal/models/trackstatusresponse.go index 202b69b..47d757d 100644 --- a/internal/models/trackstatusresponse.go +++ b/internal/models/trackstatusresponse.go @@ -5,10 +5,14 @@ import ( "time" ) -type TrackStatusResult struct { +type Transaction struct { CreatedAt time.Time `json:"createdAt"` Status string `json:"status"` TransferValue json.Number `json:"transferValue"` TxHash string `json:"txHash"` TxType string `json:"txType"` } + +type TrackStatusResult struct { + Active bool `json:"active"` +} diff --git a/internal/testutil/testservice/TestAccountService.go b/internal/testutil/testservice/TestAccountService.go index 885e63f..78a2798 100644 --- a/internal/testutil/testservice/TestAccountService.go +++ b/internal/testutil/testservice/TestAccountService.go @@ -3,7 +3,6 @@ package testservice import ( "context" "encoding/json" - "time" "git.grassecon.net/urdt/ussd/internal/models" "github.com/grassrootseconomics/eth-custodial/pkg/api" @@ -30,11 +29,7 @@ func (tas *TestAccountService) CheckBalance(ctx context.Context, publicKey strin func (tas *TestAccountService) CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResult, error) { return &models.TrackStatusResult { - CreatedAt: time.Now(), - Status: "SUCCESS", - TransferValue: json.Number("0.5"), - TxHash: "0x123abc456def", - TxType: "transfer", + Active: true, }, nil } From e6a369dcddea338d04717babc1503fde10181368 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 31 Oct 2024 14:44:42 +0300 Subject: [PATCH 183/289] remove unused code --- internal/utils/vouchers.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/internal/utils/vouchers.go b/internal/utils/vouchers.go index dc6cc4a..b027cc1 100644 --- a/internal/utils/vouchers.go +++ b/internal/utils/vouchers.go @@ -77,10 +77,7 @@ func MatchVoucher(input, symbols, balances, decimals, addresses string) (symbol, for i, sym := range symList { parts := strings.SplitN(sym, ":", 2) - if len(parts) != 2 { - continue - } - + if input == parts[0] || strings.EqualFold(input, parts[1]) { symbol = parts[1] if i < len(balList) { From b2d180e8ebc0d353a6939d78e8f965fa6b405b89 Mon Sep 17 00:00:00 2001 From: lash Date: Thu, 31 Oct 2024 12:15:07 +0000 Subject: [PATCH 184/289] WIP Trying to clean up account status check --- internal/handlers/ussd/menuhandler.go | 5 +- internal/handlers/ussd/menuhandler_test.go | 35 +++--------- internal/testutil/mocks/servicemock.go | 8 +-- .../testservice/TestAccountService.go | 13 +---- remote/accountservice.go | 55 +------------------ 5 files changed, 15 insertions(+), 101 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 98a633c..ed5f466 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -557,17 +557,16 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b if err != nil { return res, err } - okResponse, err = h.accountService.TrackAccountStatus(ctx, string(publicKey)) + r, err := h.accountService.TrackAccountStatus(ctx, string(publicKey)) if err != nil { res.FlagSet = append(res.FlagSet, flag_api_error) return res, err } res.FlagReset = append(res.FlagReset, flag_api_error) - isActive := okResponse.Result["active"].(bool) if !ok { return res, err } - if isActive { + if r.Active { res.FlagSet = append(res.FlagSet, flag_account_success) res.FlagReset = append(res.FlagReset, flag_account_pending) } else { diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 8c3867a..7940704 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -1053,36 +1053,18 @@ func TestCheckAccountStatus(t *testing.T) { expectedResult resource.Result }{ { - name: "Test when account is on the Sarafu network", - input: []byte("TrackingId1234"), - serverResponse: &api.OKResponse{ - Ok: true, - Description: "Account creation succeeded", - Result: map[string]any{ - "active": true, - }, - }, - response: &models.TrackStatusResult { - Active: true, - }, - expectedResult: resource.Result{ - FlagSet: []uint32{flag_account_success}, - FlagReset: []uint32{flag_api_error, flag_account_pending}, - }, - }, - { - name: "Test when the account is not yet on the sarafu network", + name: "Test when the account is not yet on the sarafu network", input: []byte("TrackingId1234"), response: &models.TrackStatusResult{ Active: false, }, - serverResponse: &api.OKResponse{ - Ok: true, - Description: "Account creation succeeded", - Result: map[string]any{ - "active": false, - }, - }, +// serverResponse: &api.OKResponse{ +// Ok: true, +// Description: "Account creation succeeded", +// Result: map[string]any{ +// "active": false, +// }, +// }, expectedResult: resource.Result{ FlagSet: []uint32{flag_account_pending}, FlagReset: []uint32{flag_api_error, flag_account_success}, @@ -1104,7 +1086,6 @@ func TestCheckAccountStatus(t *testing.T) { // Define expected interactions with the mock mockDataStore.On("ReadEntry", ctx, sessionId, common.DATA_PUBLIC_KEY).Return(tt.input, nil) - mockCreateAccountService.On("CheckAccountStatus", string(tt.input)).Return(tt.response, nil) mockCreateAccountService.On("TrackAccountStatus", string(tt.input)).Return(tt.serverResponse, nil) mockDataStore.On("WriteEntry", ctx, sessionId, common.DATA_ACCOUNT_STATUS, status).Return(nil).Maybe() diff --git a/internal/testutil/mocks/servicemock.go b/internal/testutil/mocks/servicemock.go index 3b36ba7..bec48fd 100644 --- a/internal/testutil/mocks/servicemock.go +++ b/internal/testutil/mocks/servicemock.go @@ -4,7 +4,6 @@ import ( "context" "git.grassecon.net/urdt/ussd/internal/models" - "github.com/grassrootseconomics/eth-custodial/pkg/api" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" "github.com/stretchr/testify/mock" ) @@ -24,13 +23,8 @@ func (m *MockAccountService) CheckBalance(ctx context.Context, publicKey string) return args.Get(0).(*models.BalanceResult), args.Error(1) } -func (m *MockAccountService) TrackAccountStatus(ctx context.Context, trackingId string) (*api.OKResponse, error) { +func (m *MockAccountService) TrackAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResult, error) { args := m.Called(trackingId) - return args.Get(0).(*api.OKResponse), args.Error(1) -} - -func (m *MockAccountService) CheckAccountStatus(ctx context.Context,publicKey string) (*models.TrackStatusResult, error) { - args := m.Called(publicKey) return args.Get(0).(*models.TrackStatusResult), args.Error(1) } diff --git a/internal/testutil/testservice/TestAccountService.go b/internal/testutil/testservice/TestAccountService.go index 78a2798..a9a3085 100644 --- a/internal/testutil/testservice/TestAccountService.go +++ b/internal/testutil/testservice/TestAccountService.go @@ -5,7 +5,6 @@ import ( "encoding/json" "git.grassecon.net/urdt/ussd/internal/models" - "github.com/grassrootseconomics/eth-custodial/pkg/api" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" ) @@ -27,22 +26,12 @@ func (tas *TestAccountService) CheckBalance(ctx context.Context, publicKey strin return balanceResponse, nil } -func (tas *TestAccountService) CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResult, error) { +func (tas *TestAccountService) TrackAccountStatus(ctx context.Context, publicKey string) (*models.TrackStatusResult, error) { return &models.TrackStatusResult { Active: true, }, nil } -func (tas *TestAccountService) TrackAccountStatus(ctx context.Context, publicKey string) (*api.OKResponse, error) { - return &api.OKResponse{ - Ok: true, - Description: "Account creation succeeded", - Result: map[string]any{ - "active": true, - }, - }, nil -} - func (tas *TestAccountService) FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) { return []dataserviceapi.TokenHoldings { dataserviceapi.TokenHoldings { diff --git a/remote/accountservice.go b/remote/accountservice.go index bc98cf1..24a469e 100644 --- a/remote/accountservice.go +++ b/remote/accountservice.go @@ -20,9 +20,7 @@ var ( type AccountServiceInterface interface { CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResult, error) CreateAccount(ctx context.Context) (*models.AccountResult, error) - // TODO: poorly named method seems to be checking transaction - CheckAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResult, error) - TrackAccountStatus(ctx context.Context, publicKey string) (*api.OKResponse, error) + TrackAccountStatus(ctx context.Context, publicKey string) (*models.TrackStatusResult, error) FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) } @@ -38,7 +36,7 @@ type AccountService struct { // - 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(ctx context.Context, trackingId string) (*models.TrackStatusResult, error) { +func (as *AccountService) TrackAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResult, error) { var r models.TrackStatusResult ep, err := url.JoinPath(config.TrackURL, trackingId) @@ -59,60 +57,13 @@ func (as *AccountService) CheckAccountStatus(ctx context.Context, trackingId str return &r, nil } -func (as *AccountService) TrackAccountStatus(ctx context.Context, publicKey string) (*api.OKResponse, error) { - var okResponse api.OKResponse - var errResponse api.ErrResponse - var err error - - ep, err := url.JoinPath(config.TrackURL, publicKey) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", ep, nil) - if err != nil { - return nil, err - } - - req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-GE-KEY", "xd") - - resp, err := http.DefaultClient.Do(req) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - body, err := io.ReadAll(resp.Body) - if err != nil { - errResponse.Description = err.Error() - return nil, err - } - if resp.StatusCode >= http.StatusBadRequest { - err := json.Unmarshal([]byte(body), &errResponse) - if err != nil { - return nil, err - } - return nil, errors.New(errResponse.Description) - } - err = json.Unmarshal([]byte(body), &okResponse) - if err != nil { - return nil, err - } - if len(okResponse.Result) == 0 { - return nil, errors.New("Empty api result") - } - return &okResponse, 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(ctx context.Context, publicKey string) (*models.BalanceResult, error) { var balanceResult models.BalanceResult - ep, err := url.JoinPath(config.BalanceURL, publicKey) + ep, err := url.JoinPath(config.BalanceURL, publicKey) if err != nil { return nil, err } From 3ae75b27a5cfa10726f2dcf3b2a7afe5a7807cfe Mon Sep 17 00:00:00 2001 From: lash Date: Thu, 31 Oct 2024 12:38:31 +0000 Subject: [PATCH 185/289] WIP replaced check account method but traversal crashes --- internal/handlers/ussd/menuhandler_test.go | 7 ++++--- remote/accountservice.go | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 7940704..6105657 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -20,7 +20,7 @@ import ( "git.grassecon.net/urdt/ussd/common" "github.com/alecthomas/assert/v2" - "github.com/grassrootseconomics/eth-custodial/pkg/api" +// "github.com/grassrootseconomics/eth-custodial/pkg/api" testdataloader "github.com/peteole/testdata-loader" "github.com/stretchr/testify/require" @@ -1048,7 +1048,7 @@ func TestCheckAccountStatus(t *testing.T) { tests := []struct { name string input []byte - serverResponse *api.OKResponse + //serverResponse *api.OKResponse response *models.TrackStatusResult expectedResult resource.Result }{ @@ -1086,7 +1086,8 @@ func TestCheckAccountStatus(t *testing.T) { // Define expected interactions with the mock mockDataStore.On("ReadEntry", ctx, sessionId, common.DATA_PUBLIC_KEY).Return(tt.input, nil) - mockCreateAccountService.On("TrackAccountStatus", string(tt.input)).Return(tt.serverResponse, nil) + //mockCreateAccountService.On("TrackAccountStatus", string(tt.input)).Return(tt.serverResponse, nil) + mockCreateAccountService.On("TrackAccountStatus", string(tt.input)).Return(tt.response, nil) mockDataStore.On("WriteEntry", ctx, sessionId, common.DATA_ACCOUNT_STATUS, status).Return(nil).Maybe() // Call the method under test diff --git a/remote/accountservice.go b/remote/accountservice.go index 24a469e..bc6a448 100644 --- a/remote/accountservice.go +++ b/remote/accountservice.go @@ -36,10 +36,10 @@ type AccountService struct { // - 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) TrackAccountStatus(ctx context.Context, trackingId string) (*models.TrackStatusResult, error) { +func (as *AccountService) TrackAccountStatus(ctx context.Context, publicKey string) (*models.TrackStatusResult, error) { var r models.TrackStatusResult - ep, err := url.JoinPath(config.TrackURL, trackingId) + ep, err := url.JoinPath(config.TrackURL, publicKey) if err != nil { return nil, err } From 4bf56c525f5b0e9ac90e2c22fc68805327d03108 Mon Sep 17 00:00:00 2001 From: lash Date: Thu, 31 Oct 2024 13:19:44 +0000 Subject: [PATCH 186/289] Export voucher related code --- {internal/utils => common}/vouchers.go | 45 ++++++++++----------- {internal/utils => common}/vouchers_test.go | 2 +- internal/handlers/ussd/menuhandler.go | 10 ++--- 3 files changed, 28 insertions(+), 29 deletions(-) rename {internal/utils => common}/vouchers.go (74%) rename {internal/utils => common}/vouchers_test.go (99%) diff --git a/internal/utils/vouchers.go b/common/vouchers.go similarity index 74% rename from internal/utils/vouchers.go rename to common/vouchers.go index 0372700..291f28d 100644 --- a/internal/utils/vouchers.go +++ b/common/vouchers.go @@ -1,4 +1,4 @@ -package utils +package common import ( "context" @@ -6,7 +6,6 @@ import ( "strings" "git.grassecon.net/urdt/ussd/internal/storage" - "git.grassecon.net/urdt/ussd/common" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" ) @@ -96,13 +95,13 @@ func MatchVoucher(input, symbols, balances, decimals, addresses string) (symbol, return } -// StoreTemporaryVoucher saves voucher metadata as temporary entries in the common.DataStore. -func StoreTemporaryVoucher(ctx context.Context, store common.DataStore, sessionId string, data *dataserviceapi.TokenHoldings) error { - entries := map[common.DataTyp][]byte{ - common.DATA_TEMPORARY_SYM: []byte(data.TokenSymbol), - common.DATA_TEMPORARY_BAL: []byte(data.Balance), - common.DATA_TEMPORARY_DECIMAL: []byte(data.TokenDecimals), - common.DATA_TEMPORARY_ADDRESS: []byte(data.ContractAddress), +// StoreTemporaryVoucher saves voucher metadata as temporary entries in the DataStore. +func StoreTemporaryVoucher(ctx context.Context, store DataStore, sessionId string, data *dataserviceapi.TokenHoldings) error { + entries := map[DataTyp][]byte{ + DATA_TEMPORARY_SYM: []byte(data.TokenSymbol), + DATA_TEMPORARY_BAL: []byte(data.Balance), + DATA_TEMPORARY_DECIMAL: []byte(data.TokenDecimals), + DATA_TEMPORARY_ADDRESS: []byte(data.ContractAddress), } for key, value := range entries { @@ -113,13 +112,13 @@ func StoreTemporaryVoucher(ctx context.Context, store common.DataStore, sessionI return nil } -// GetTemporaryVoucherData retrieves temporary voucher metadata from the common.DataStore. -func GetTemporaryVoucherData(ctx context.Context, store common.DataStore, sessionId string) (*dataserviceapi.TokenHoldings, error) { - keys := []common.DataTyp{ - common.DATA_TEMPORARY_SYM, - common.DATA_TEMPORARY_BAL, - common.DATA_TEMPORARY_DECIMAL, - common.DATA_TEMPORARY_ADDRESS, +// GetTemporaryVoucherData retrieves temporary voucher metadata from the DataStore. +func GetTemporaryVoucherData(ctx context.Context, store DataStore, sessionId string) (*dataserviceapi.TokenHoldings, error) { + keys := []DataTyp{ + DATA_TEMPORARY_SYM, + DATA_TEMPORARY_BAL, + DATA_TEMPORARY_DECIMAL, + DATA_TEMPORARY_ADDRESS, } data := &dataserviceapi.TokenHoldings{} @@ -141,14 +140,14 @@ func GetTemporaryVoucherData(ctx context.Context, store common.DataStore, sessio return data, nil } -// UpdateVoucherData sets the active voucher data and clears the temporary voucher data in the common.DataStore. -func UpdateVoucherData(ctx context.Context, store common.DataStore, sessionId string, data *dataserviceapi.TokenHoldings) error { +// UpdateVoucherData sets the active voucher data and clears the temporary voucher data in the DataStore. +func UpdateVoucherData(ctx context.Context, store DataStore, sessionId string, data *dataserviceapi.TokenHoldings) error { // Active voucher data entries - activeEntries := map[common.DataTyp][]byte{ - common.DATA_ACTIVE_SYM: []byte(data.TokenSymbol), - common.DATA_ACTIVE_BAL: []byte(data.Balance), - common.DATA_ACTIVE_DECIMAL: []byte(data.TokenDecimals), - common.DATA_ACTIVE_ADDRESS: []byte(data.ContractAddress), + activeEntries := map[DataTyp][]byte{ + DATA_ACTIVE_SYM: []byte(data.TokenSymbol), + DATA_ACTIVE_BAL: []byte(data.Balance), + DATA_ACTIVE_DECIMAL: []byte(data.TokenDecimals), + DATA_ACTIVE_ADDRESS: []byte(data.ContractAddress), } // Write active data diff --git a/internal/utils/vouchers_test.go b/common/vouchers_test.go similarity index 99% rename from internal/utils/vouchers_test.go rename to common/vouchers_test.go index c59037e..401d4d7 100644 --- a/internal/utils/vouchers_test.go +++ b/common/vouchers_test.go @@ -1,4 +1,4 @@ -package utils +package common import ( "context" diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index ed5f466..2e075d7 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -1117,7 +1117,7 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) return res, nil } - data := utils.ProcessVouchers(vouchersResp) + data := common.ProcessVouchers(vouchersResp) // Store all voucher data dataMap := map[string]string{ @@ -1167,7 +1167,7 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r return res, nil } - metadata, err := utils.GetVoucherData(ctx, h.prefixDb, inputStr) + metadata, err := common.GetVoucherData(ctx, h.prefixDb, inputStr) if err != nil { return res, fmt.Errorf("failed to retrieve voucher data: %v", err) } @@ -1177,7 +1177,7 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r return res, nil } - if err := utils.StoreTemporaryVoucher(ctx, h.userdataStore, sessionId, metadata); err != nil { + if err := common.StoreTemporaryVoucher(ctx, h.userdataStore, sessionId, metadata); err != nil { return res, err } @@ -1198,13 +1198,13 @@ func (h *Handlers) SetVoucher(ctx context.Context, sym string, input []byte) (re // Get temporary data - tempData, err := utils.GetTemporaryVoucherData(ctx, h.userdataStore, sessionId) + tempData, err := common.GetTemporaryVoucherData(ctx, h.userdataStore, sessionId) if err != nil { return res, err } // Set as active and clear temporary data - if err := utils.UpdateVoucherData(ctx, h.userdataStore, sessionId, tempData); err != nil { + if err := common.UpdateVoucherData(ctx, h.userdataStore, sessionId, tempData); err != nil { return res, err } From 0b4bf58107cdbcc1c826eb3d8f0e63073335c0f1 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 31 Oct 2024 16:31:29 +0300 Subject: [PATCH 187/289] resolved failing tests due to tempData --- internal/handlers/ussd/menuhandler_test.go | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index a960cfc..6672ab1 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -2119,14 +2119,6 @@ func TestSetVoucher(t *testing.T) { utils.DATA_ACTIVE_ADDRESS: []byte(tempData.ContractAddress), } - // Define the temporary entries to be cleared - tempEntries := map[utils.DataTyp][]byte{ - utils.DATA_TEMPORARY_SYM: []byte(""), - utils.DATA_TEMPORARY_BAL: []byte(""), - utils.DATA_TEMPORARY_DECIMAL: []byte(""), - utils.DATA_TEMPORARY_ADDRESS: []byte(""), - } - // Mocking ReadEntry calls for temporary data retrieval mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_SYM).Return([]byte(tempData.TokenSymbol), nil) mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_BAL).Return([]byte(tempData.Balance), nil) @@ -2138,11 +2130,6 @@ func TestSetVoucher(t *testing.T) { mockDataStore.On("WriteEntry", ctx, sessionId, key, value).Return(nil) } - // Mocking WriteEntry calls for clearing temporary data - for key, value := range tempEntries { - mockDataStore.On("WriteEntry", ctx, sessionId, key, value).Return(nil) - } - h := &Handlers{ userdataStore: mockDataStore, } From ce917d9e89b1591aff9fe1a181c29286957355fd Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 31 Oct 2024 17:05:06 +0300 Subject: [PATCH 188/289] update tests --- internal/handlers/ussd/menuhandler_test.go | 54 ++++++++++++++++------ 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index a960cfc..7c0689f 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -19,8 +19,8 @@ import ( "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/common" + "git.grassecon.net/urdt/ussd/internal/utils" "github.com/alecthomas/assert/v2" "github.com/grassrootseconomics/eth-custodial/pkg/api" testdataloader "github.com/peteole/testdata-loader" @@ -174,8 +174,11 @@ func TestWithPersister_PanicWhenAlreadySet(t *testing.T) { } func TestSaveFirstname(t *testing.T) { - // Create a new instance of MockMyDataStore + // Create new mocks mockStore := new(mocks.MockUserDataStore) + mockState := state.NewState(16) + + fm, err := NewFlagManager(flagsPath) // Define test data sessionId := "session123" @@ -183,11 +186,13 @@ func TestSaveFirstname(t *testing.T) { 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) + mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_FIRST_NAME, []byte(firstName)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, + flagManager: fm.parser, + st: mockState, } // Call the method @@ -204,6 +209,9 @@ func TestSaveFirstname(t *testing.T) { func TestSaveFamilyname(t *testing.T) { // Create a new instance of UserDataStore mockStore := new(mocks.MockUserDataStore) + mockState := state.NewState(16) + + fm, err := NewFlagManager(flagsPath) // Define test data sessionId := "session123" @@ -211,11 +219,13 @@ func TestSaveFamilyname(t *testing.T) { 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) + mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_FAMILY_NAME, []byte(familyName)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, + st: mockState, + flagManager: fm.parser, } // Call the method @@ -288,8 +298,11 @@ func TestSaveTemporaryPin(t *testing.T) { } func TestSaveYoB(t *testing.T) { - // Create a new instance of MockMyDataStore + // Create new instances mockStore := new(mocks.MockUserDataStore) + mockState := state.NewState(16) + + fm, err := NewFlagManager(flagsPath) // Define test data sessionId := "session123" @@ -297,11 +310,13 @@ func TestSaveYoB(t *testing.T) { 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) + mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_YOB, []byte(yob)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, + st: mockState, + flagManager: fm.parser, } // Call the method @@ -318,6 +333,9 @@ func TestSaveYoB(t *testing.T) { func TestSaveLocation(t *testing.T) { // Create a new instance of MockMyDataStore mockStore := new(mocks.MockUserDataStore) + mockState := state.NewState(16) + + fm, err := NewFlagManager(flagsPath) // Define test data sessionId := "session123" @@ -325,11 +343,13 @@ func TestSaveLocation(t *testing.T) { 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) + mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_LOCATION, []byte(yob)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, + st: mockState, + flagManager: fm.parser, } // Call the method @@ -346,6 +366,9 @@ func TestSaveLocation(t *testing.T) { func TestSaveOfferings(t *testing.T) { // Create a new instance of MockUserDataStore mockStore := new(mocks.MockUserDataStore) + mockState := state.NewState(16) + + fm, err := NewFlagManager(flagsPath) // Define test data sessionId := "session123" @@ -353,11 +376,13 @@ func TestSaveOfferings(t *testing.T) { ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Set up the expected behavior of the mock - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_OFFERINGS, []byte(offerings)).Return(nil) + mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_OFFERINGS, []byte(offerings)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, + st: mockState, + flagManager: fm.parser, } // Call the method @@ -372,10 +397,12 @@ func TestSaveOfferings(t *testing.T) { } func TestSaveGender(t *testing.T) { - // Create a new instance of MockMyDataStore + // Create a new mock instances mockStore := new(mocks.MockUserDataStore) mockState := state.NewState(16) + fm, _ := NewFlagManager(flagsPath) + // Define the session ID and context sessionId := "session123" ctx := context.WithValue(context.Background(), "SessionId", sessionId) @@ -415,16 +442,17 @@ func TestSaveGender(t *testing.T) { t.Run(tt.name, func(t *testing.T) { // Set up expectations for the mock database if tt.expectCall { - expectedKey := utils.DATA_GENDER + expectedKey := utils.DATA_TEMPORARY_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) + mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_GENDER, []byte(tt.expectedGender)).Return(nil) } mockState.ExecPath = append(mockState.ExecPath, tt.executingSymbol) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, st: mockState, + flagManager: fm.parser, } // Call the method @@ -435,9 +463,9 @@ func TestSaveGender(t *testing.T) { // Verify expectations if tt.expectCall { - mockStore.AssertCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_GENDER, []byte(tt.expectedGender)) + mockStore.AssertCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_GENDER, []byte(tt.expectedGender)) } else { - mockStore.AssertNotCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_GENDER, []byte(tt.expectedGender)) + mockStore.AssertNotCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_GENDER, []byte(tt.expectedGender)) } }) } From ac0b4b2ed1de7ab609441b67feaba1c5a58fcafe Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 31 Oct 2024 20:08:30 +0300 Subject: [PATCH 189/289] pass context --- internal/testutil/TestEngine.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/testutil/TestEngine.go b/internal/testutil/TestEngine.go index bd6bc7f..26b889e 100644 --- a/internal/testutil/TestEngine.go +++ b/internal/testutil/TestEngine.go @@ -73,7 +73,7 @@ func TestEngine(sessionId string) (engine.Engine, func(), chan bool) { os.Exit(1) } - lhs, err := handlers.NewLocalHandlerService(pfp, true, dbResource, cfg, rs) + lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs) lhs.SetDataStore(&userDataStore) lhs.SetPersister(pe) From 12825ae08a268db47ce105271c41807d1130913a Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 31 Oct 2024 20:10:46 +0300 Subject: [PATCH 190/289] setup adminstore in the local handler service --- internal/handlers/handlerservice.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/internal/handlers/handlerservice.go b/internal/handlers/handlerservice.go index 247e6c5..5990dc8 100644 --- a/internal/handlers/handlerservice.go +++ b/internal/handlers/handlerservice.go @@ -1,6 +1,8 @@ package handlers import ( + "context" + "git.defalsify.org/vise.git/asm" "git.defalsify.org/vise.git/db" "git.defalsify.org/vise.git/engine" @@ -34,16 +36,21 @@ type LocalHandlerService struct { Rs resource.Resource } -func NewLocalHandlerService(fp string, debug bool, dbResource *resource.DbResource, cfg engine.Config, rs resource.Resource) (*LocalHandlerService, error) { +func NewLocalHandlerService(ctx context.Context, fp string, debug bool, dbResource *resource.DbResource, cfg engine.Config, rs resource.Resource) (*LocalHandlerService, error) { parser, err := getParser(fp, debug) if err != nil { return nil, err } + adminstore, err := utils.NewAdminStore(ctx, "admin_numbers") + if err != nil { + return nil, err + } return &LocalHandlerService{ - Parser: parser, - DbRs: dbResource, - Cfg: cfg, - Rs: rs, + Parser: parser, + DbRs: dbResource, + AdminStore: adminstore, + Cfg: cfg, + Rs: rs, }, nil } From 5abe9b78cc66181271cc4fdacfd305df558474b3 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 31 Oct 2024 20:11:26 +0300 Subject: [PATCH 191/289] attach an admin store for the phone numbers --- cmd/africastalking/main.go | 8 +++++++- cmd/async/main.go | 9 ++++++++- cmd/http/main.go | 9 ++++++++- cmd/main.go | 13 +++++++------ 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/cmd/africastalking/main.go b/cmd/africastalking/main.go index 79fb091..ad56467 100644 --- a/cmd/africastalking/main.go +++ b/cmd/africastalking/main.go @@ -131,7 +131,7 @@ func main() { os.Exit(1) } - lhs, err := handlers.NewLocalHandlerService(pfp, true, dbResource, cfg, rs) + lhs, err := handlers.NewLocalHandlerService(ctx,pfp, true, dbResource, cfg, rs) lhs.SetDataStore(&userdataStore) if err != nil { @@ -139,6 +139,12 @@ func main() { os.Exit(1) } + err = lhs.AdminStore.Seed() + if err != nil { + fmt.Fprintf(os.Stderr, err.Error()) + os.Exit(1) + } + accountService := server.AccountService{} hl, err := lhs.GetHandler(&accountService) if err != nil { diff --git a/cmd/async/main.go b/cmd/async/main.go index 902dfc7..bdb17a6 100644 --- a/cmd/async/main.go +++ b/cmd/async/main.go @@ -104,8 +104,15 @@ func main() { os.Exit(1) } - lhs, err := handlers.NewLocalHandlerService(pfp, true, dbResource, cfg, rs) + lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs) lhs.SetDataStore(&userdataStore) + + err = lhs.AdminStore.Seed() + if err != nil { + fmt.Fprintf(os.Stderr, err.Error()) + os.Exit(1) + } + accountService := server.AccountService{} hl, err := lhs.GetHandler(&accountService) diff --git a/cmd/http/main.go b/cmd/http/main.go index ece882e..39e311e 100644 --- a/cmd/http/main.go +++ b/cmd/http/main.go @@ -92,13 +92,20 @@ func main() { os.Exit(1) } - lhs, err := handlers.NewLocalHandlerService(pfp, true, dbResource, cfg, rs) + lhs, err := handlers.NewLocalHandlerService(ctx,pfp, true, dbResource, cfg, rs) lhs.SetDataStore(&userdataStore) if err != nil { fmt.Fprintf(os.Stderr, err.Error()) os.Exit(1) } + + err = lhs.AdminStore.Seed() + if err != nil { + fmt.Fprintf(os.Stderr, err.Error()) + os.Exit(1) + } + accountService := server.AccountService{} hl, err := lhs.GetHandler(&accountService) if err != nil { diff --git a/cmd/main.go b/cmd/main.go index 7dd3cd6..95b84c9 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -15,7 +15,6 @@ import ( "git.grassecon.net/urdt/ussd/internal/handlers" "git.grassecon.net/urdt/ussd/internal/handlers/server" "git.grassecon.net/urdt/ussd/internal/storage" - "git.grassecon.net/urdt/ussd/internal/utils" ) var ( @@ -49,9 +48,6 @@ func main() { ctx = context.WithValue(ctx, "Database", database) pfp := path.Join(scriptDir, "pp.csv") - as, _ := utils.NewAdminStore(ctx, "admin_numbers") - as.Seed() - cfg := engine.Config{ Root: "root", SessionId: sessionId, @@ -92,9 +88,8 @@ func main() { os.Exit(1) } - lhs, err := handlers.NewLocalHandlerService(pfp, true, dbResource, cfg, rs) + lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs) lhs.SetDataStore(&userdatastore) - lhs.SetAdminStore(as) lhs.SetPersister(pe) if err != nil { @@ -102,6 +97,12 @@ func main() { os.Exit(1) } + err = lhs.AdminStore.Seed() + if err != nil { + fmt.Fprintf(os.Stderr, err.Error()) + os.Exit(1) + } + accountService := server.AccountService{} hl, err := lhs.GetHandler(&accountService) if err != nil { From b2655b7f117fa5e0c34d5be2e474d902d31df596 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 31 Oct 2024 20:59:11 +0300 Subject: [PATCH 192/289] remove seed from executable --- cmd/africastalking/main.go | 8 +------- cmd/async/main.go | 6 ------ cmd/http/main.go | 8 +------- cmd/main.go | 6 ------ 4 files changed, 2 insertions(+), 26 deletions(-) diff --git a/cmd/africastalking/main.go b/cmd/africastalking/main.go index ad56467..891301a 100644 --- a/cmd/africastalking/main.go +++ b/cmd/africastalking/main.go @@ -131,7 +131,7 @@ func main() { os.Exit(1) } - lhs, err := handlers.NewLocalHandlerService(ctx,pfp, true, dbResource, cfg, rs) + lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs) lhs.SetDataStore(&userdataStore) if err != nil { @@ -139,12 +139,6 @@ func main() { os.Exit(1) } - err = lhs.AdminStore.Seed() - if err != nil { - fmt.Fprintf(os.Stderr, err.Error()) - os.Exit(1) - } - accountService := server.AccountService{} hl, err := lhs.GetHandler(&accountService) if err != nil { diff --git a/cmd/async/main.go b/cmd/async/main.go index bdb17a6..df11dac 100644 --- a/cmd/async/main.go +++ b/cmd/async/main.go @@ -107,12 +107,6 @@ func main() { lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs) lhs.SetDataStore(&userdataStore) - err = lhs.AdminStore.Seed() - if err != nil { - fmt.Fprintf(os.Stderr, err.Error()) - os.Exit(1) - } - accountService := server.AccountService{} hl, err := lhs.GetHandler(&accountService) diff --git a/cmd/http/main.go b/cmd/http/main.go index 39e311e..df37878 100644 --- a/cmd/http/main.go +++ b/cmd/http/main.go @@ -92,7 +92,7 @@ func main() { os.Exit(1) } - lhs, err := handlers.NewLocalHandlerService(ctx,pfp, true, dbResource, cfg, rs) + lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs) lhs.SetDataStore(&userdataStore) if err != nil { @@ -100,12 +100,6 @@ func main() { os.Exit(1) } - err = lhs.AdminStore.Seed() - if err != nil { - fmt.Fprintf(os.Stderr, err.Error()) - os.Exit(1) - } - accountService := server.AccountService{} hl, err := lhs.GetHandler(&accountService) if err != nil { diff --git a/cmd/main.go b/cmd/main.go index 95b84c9..848068f 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -97,12 +97,6 @@ func main() { os.Exit(1) } - err = lhs.AdminStore.Seed() - if err != nil { - fmt.Fprintf(os.Stderr, err.Error()) - os.Exit(1) - } - accountService := server.AccountService{} hl, err := lhs.GetHandler(&accountService) if err != nil { From 299534ccf1701bf2cbddc7cb68ac34d846745e33 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 31 Oct 2024 20:59:51 +0300 Subject: [PATCH 193/289] define seed as a command in the devtool --- devtools/commands/seed.go | 47 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 devtools/commands/seed.go diff --git a/devtools/commands/seed.go b/devtools/commands/seed.go new file mode 100644 index 0000000..8abd50f --- /dev/null +++ b/devtools/commands/seed.go @@ -0,0 +1,47 @@ +package commands + +import ( + "context" + "encoding/json" + "os" + + "git.defalsify.org/vise.git/logging" + "git.grassecon.net/urdt/ussd/internal/utils" +) + +var ( + logg = logging.NewVanilla().WithDomain("adminstore") +) + +type Admin struct { + PhoneNumber string `json:"phonenumber"` +} + +type Config struct { + Admins []Admin `json:"admins"` +} + +func Seed(ctx context.Context) error { + var config Config + adminstore, err := utils.NewAdminStore(ctx, "admin_numbers") + store := adminstore.FsStore + if err != nil { + return err + } + defer store.Close() + data, err := os.ReadFile("admin_numbers.json") + if err != nil { + return err + } + if err := json.Unmarshal(data, &config); err != nil { + return err + } + for _, admin := range config.Admins { + err := store.Put(ctx, []byte(admin.PhoneNumber), []byte("1")) + if err != nil { + logg.Printf(logging.LVL_DEBUG, "Failed to insert admin number", admin.PhoneNumber) + return err + } + } + return nil +} From 7aab3cff8ca8dda7feafb2fba15d71bf601f8894 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 31 Oct 2024 21:00:16 +0300 Subject: [PATCH 194/289] remove seed --- internal/utils/adminstore.go | 40 +++--------------------------------- 1 file changed, 3 insertions(+), 37 deletions(-) diff --git a/internal/utils/adminstore.go b/internal/utils/adminstore.go index 43a3bfd..a492479 100644 --- a/internal/utils/adminstore.go +++ b/internal/utils/adminstore.go @@ -2,8 +2,6 @@ package utils import ( "context" - "encoding/json" - "os" "git.defalsify.org/vise.git/db" fsdb "git.defalsify.org/vise.git/db/fs" @@ -14,17 +12,9 @@ var ( logg = logging.NewVanilla().WithDomain("adminstore") ) -type Admin struct { - PhoneNumber string `json:"phonenumber"` -} - -type Config struct { - Admins []Admin `json:"admins"` -} - type AdminStore struct { ctx context.Context - fsStore db.Db + FsStore db.Db } func NewAdminStore(ctx context.Context, fileName string) (*AdminStore, error) { @@ -32,7 +22,7 @@ func NewAdminStore(ctx context.Context, fileName string) (*AdminStore, error) { if err != nil { return nil, err } - return &AdminStore{ctx: ctx, fsStore: fsStore}, nil + return &AdminStore{ctx: ctx, FsStore: fsStore}, nil } func getFsStore(ctx context.Context, connectStr string) (db.Db, error) { @@ -45,33 +35,9 @@ func getFsStore(ctx context.Context, connectStr string) (db.Db, error) { return fsStore, nil } -// Seed initializes a list of phonenumbers with admin privileges -func (as *AdminStore) Seed() error { - var config Config - - store := as.fsStore - defer store.Close() - - data, err := os.ReadFile("admin_numbers.json") - if err != nil { - return err - } - if err := json.Unmarshal(data, &config); err != nil { - return err - } - for _, admin := range config.Admins { - err := store.Put(as.ctx, []byte(admin.PhoneNumber), []byte("1")) - if err != nil { - logg.Printf(logging.LVL_DEBUG, "Failed to insert admin number", admin.PhoneNumber) - return err - } - } - return nil -} - // Checks if the given sessionId is listed as an admin. func (as *AdminStore) IsAdmin(sessionId string) (bool, error) { - _, err := as.fsStore.Get(as.ctx, []byte(sessionId)) + _, err := as.FsStore.Get(as.ctx, []byte(sessionId)) if err != nil { if db.IsNotFound(err) { logg.Printf(logging.LVL_INFO, "Returning false because session id was not found") From 7fa38340ddf3cfaab0207506d048db32bf82dc52 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 31 Oct 2024 21:00:41 +0300 Subject: [PATCH 195/289] add command to initialize a list of admin numbers --- devtools/main.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 devtools/main.go diff --git a/devtools/main.go b/devtools/main.go new file mode 100644 index 0000000..d0d4632 --- /dev/null +++ b/devtools/main.go @@ -0,0 +1,17 @@ +package main + +import ( + "context" + "log" + + "git.grassecon.net/urdt/ussd/devtools/commands" +) + +func main() { + ctx := context.Background() + err := commands.Seed(ctx) + if err != nil { + log.Fatalf("Failed to initialize a list of admins with error %s", err) + } + +} From 53fa6f64ce209bac95129a1815f1edcd01ff369e Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 31 Oct 2024 21:01:01 +0300 Subject: [PATCH 196/289] define structure of json --- devtools/admin_numbers.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 devtools/admin_numbers.json diff --git a/devtools/admin_numbers.json b/devtools/admin_numbers.json new file mode 100644 index 0000000..ca58a23 --- /dev/null +++ b/devtools/admin_numbers.json @@ -0,0 +1,7 @@ +{ + "admins": [ + { + "phonenumber" : "" + } + ] +} \ No newline at end of file From 7d1a04f089547c90b04d328a99298cb2bc24de99 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 31 Oct 2024 21:01:24 +0300 Subject: [PATCH 197/289] remove from root --- admin_numbers.json | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 admin_numbers.json diff --git a/admin_numbers.json b/admin_numbers.json deleted file mode 100644 index ca58a23..0000000 --- a/admin_numbers.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "admins": [ - { - "phonenumber" : "" - } - ] -} \ No newline at end of file From f4ca4454ea2f61aa798f13253b011dcd414a94ab Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 1 Nov 2024 00:42:23 +0300 Subject: [PATCH 198/289] use a single DATA_TEMPORARY_VALUE for the PIN and voucher data --- internal/handlers/ussd/menuhandler.go | 8 ++-- internal/handlers/ussd/menuhandler_test.go | 26 +++++-------- internal/utils/db.go | 6 +-- internal/utils/vouchers.go | 43 +++++++--------------- internal/utils/vouchers_test.go | 17 +++------ 5 files changed, 34 insertions(+), 66 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index dd3efdb..aaa1530 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -222,7 +222,7 @@ func (h *Handlers) VerifyNewPin(ctx context.Context, sym string, input []byte) ( return res, nil } -// SaveTemporaryPin saves the valid PIN input to the DATA_TEMPORARY_PIN +// SaveTemporaryPin saves the valid PIN input to the DATA_TEMPORARY_VALUE // during the account creation process // and during the change PIN process func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byte) (resource.Result, error) { @@ -247,7 +247,7 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt res.FlagReset = append(res.FlagReset, flag_incorrect_pin) store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_PIN, []byte(accountPIN)) + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(accountPIN)) if err != nil { return res, err } @@ -264,7 +264,7 @@ func (h *Handlers) ConfirmPinChange(ctx context.Context, sym string, input []byt flag_pin_mismatch, _ := h.flagManager.GetFlag("flag_pin_mismatch") store := h.userdataStore - temporaryPin, err := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_PIN) + temporaryPin, err := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE) if err != nil { return res, err } @@ -295,7 +295,7 @@ func (h *Handlers) VerifyCreatePin(ctx context.Context, sym string, input []byte return res, fmt.Errorf("missing session") } store := h.userdataStore - temporaryPin, err := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_PIN) + temporaryPin, err := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE) if err != nil { return res, err } diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 6672ab1..bf29926 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -19,8 +19,8 @@ import ( "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/common" + "git.grassecon.net/urdt/ussd/internal/utils" "github.com/alecthomas/assert/v2" "github.com/grassrootseconomics/eth-custodial/pkg/api" testdataloader "github.com/peteole/testdata-loader" @@ -271,7 +271,7 @@ func TestSaveTemporaryPin(t *testing.T) { t.Run(tt.name, func(t *testing.T) { // Set up the expected behavior of the mock - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_PIN, []byte(tt.input)).Return(nil) + mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(tt.input)).Return(nil) // Call the method res, err := h.SaveTemporaryPin(ctx, "save_pin", tt.input) @@ -1013,7 +1013,7 @@ func TestVerifyCreatePin(t *testing.T) { }, } - typ := utils.DATA_TEMPORARY_PIN + typ := utils.DATA_TEMPORARY_VALUE for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -1806,7 +1806,7 @@ func TestConfirmPin(t *testing.T) { // Set up the expected behavior of the mock mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACCOUNT_PIN, []byte(tt.temporarypin)).Return(nil) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_PIN).Return(tt.temporarypin, nil) + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE).Return(tt.temporarypin, nil) //Call the function under test res, _ := h.ConfirmPinChange(ctx, "confirm_pin_change", tt.temporarypin) @@ -2078,16 +2078,9 @@ func TestViewVoucher(t *testing.T) { } // Set up expectations for mockDataStore - expectedData := map[utils.DataTyp]string{ - utils.DATA_TEMPORARY_SYM: "SRF", - utils.DATA_TEMPORARY_BAL: "100", - utils.DATA_TEMPORARY_DECIMAL: "6", - utils.DATA_TEMPORARY_ADDRESS: "0xd4c288865Ce", - } + expectedData := fmt.Sprintf("%s,%s,%s,%s", "SRF", "100", "6", "0xd4c288865Ce") - for dataType, dataValue := range expectedData { - mockDataStore.On("WriteEntry", ctx, sessionId, dataType, []byte(dataValue)).Return(nil) - } + mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(expectedData)).Return(nil) res, err := h.ViewVoucher(ctx, "view_voucher", []byte("1")) assert.NoError(t, err) @@ -2111,6 +2104,8 @@ func TestSetVoucher(t *testing.T) { ContractAddress: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", } + expectedData := fmt.Sprintf("%s,%s,%s,%s", "SRF", "200", "6", "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9") + // Define the expected active entries activeEntries := map[utils.DataTyp][]byte{ utils.DATA_ACTIVE_SYM: []byte(tempData.TokenSymbol), @@ -2120,10 +2115,7 @@ func TestSetVoucher(t *testing.T) { } // Mocking ReadEntry calls for temporary data retrieval - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_SYM).Return([]byte(tempData.TokenSymbol), nil) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_BAL).Return([]byte(tempData.Balance), nil) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_DECIMAL).Return([]byte(tempData.TokenDecimals), nil) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_ADDRESS).Return([]byte(tempData.ContractAddress), nil) + mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE).Return([]byte(expectedData), nil) // Mocking WriteEntry calls for setting active data for key, value := range activeEntries { diff --git a/internal/utils/db.go b/internal/utils/db.go index 802e092..df96dfa 100644 --- a/internal/utils/db.go +++ b/internal/utils/db.go @@ -22,16 +22,12 @@ const ( DATA_OFFERINGS DATA_RECIPIENT DATA_AMOUNT - DATA_TEMPORARY_PIN + DATA_TEMPORARY_VALUE DATA_VOUCHER_LIST - DATA_TEMPORARY_SYM DATA_ACTIVE_SYM - DATA_TEMPORARY_BAL DATA_ACTIVE_BAL DATA_PUBLIC_KEY_REVERSE - DATA_TEMPORARY_DECIMAL DATA_ACTIVE_DECIMAL - DATA_TEMPORARY_ADDRESS DATA_ACTIVE_ADDRESS ) diff --git a/internal/utils/vouchers.go b/internal/utils/vouchers.go index b027cc1..1c20492 100644 --- a/internal/utils/vouchers.go +++ b/internal/utils/vouchers.go @@ -77,7 +77,7 @@ func MatchVoucher(input, symbols, balances, decimals, addresses string) (symbol, for i, sym := range symList { parts := strings.SplitN(sym, ":", 2) - + if input == parts[0] || strings.EqualFold(input, parts[1]) { symbol = parts[1] if i < len(balList) { @@ -97,45 +97,30 @@ func MatchVoucher(input, symbols, balances, decimals, addresses string) (symbol, // StoreTemporaryVoucher saves voucher metadata as temporary entries in the DataStore. func StoreTemporaryVoucher(ctx context.Context, store DataStore, sessionId string, data *dataserviceapi.TokenHoldings) error { - entries := map[DataTyp][]byte{ - DATA_TEMPORARY_SYM: []byte(data.TokenSymbol), - DATA_TEMPORARY_BAL: []byte(data.Balance), - DATA_TEMPORARY_DECIMAL: []byte(data.TokenDecimals), - DATA_TEMPORARY_ADDRESS: []byte(data.ContractAddress), + tempData := fmt.Sprintf("%s,%s,%s,%s", data.TokenSymbol, data.Balance, data.TokenDecimals, data.ContractAddress) + + if err := store.WriteEntry(ctx, sessionId, DATA_TEMPORARY_VALUE, []byte(tempData)); err != nil { + return err } - for key, value := range entries { - if err := store.WriteEntry(ctx, sessionId, key, value); err != nil { - return err - } - } return nil } // GetTemporaryVoucherData retrieves temporary voucher metadata from the DataStore. func GetTemporaryVoucherData(ctx context.Context, store DataStore, sessionId string) (*dataserviceapi.TokenHoldings, error) { - keys := []DataTyp{ - DATA_TEMPORARY_SYM, - DATA_TEMPORARY_BAL, - DATA_TEMPORARY_DECIMAL, - DATA_TEMPORARY_ADDRESS, + temp_data, err := store.ReadEntry(ctx, sessionId, DATA_TEMPORARY_VALUE) + if err != nil { + return nil, err } + values := strings.SplitN(string(temp_data), ",", 4) + data := &dataserviceapi.TokenHoldings{} - values := make([][]byte, len(keys)) - for i, key := range keys { - value, err := store.ReadEntry(ctx, sessionId, key) - if err != nil { - return nil, err - } - values[i] = value - } - - data.TokenSymbol = string(values[0]) - data.Balance = string(values[1]) - data.TokenDecimals = string(values[2]) - data.ContractAddress = string(values[3]) + data.TokenSymbol = values[0] + data.Balance = values[1] + data.TokenDecimals = values[2] + data.ContractAddress = values[3] return data, nil } diff --git a/internal/utils/vouchers_test.go b/internal/utils/vouchers_test.go index a609d27..c2ff4e3 100644 --- a/internal/utils/vouchers_test.go +++ b/internal/utils/vouchers_test.go @@ -2,6 +2,7 @@ package utils import ( "context" + "fmt" "testing" "git.grassecon.net/urdt/ussd/internal/storage" @@ -126,18 +127,12 @@ func TestStoreTemporaryVoucher(t *testing.T) { require.NoError(t, err) // Verify stored data - expectedEntries := map[DataTyp][]byte{ - DATA_TEMPORARY_SYM: []byte("SRF"), - DATA_TEMPORARY_BAL: []byte("200"), - DATA_TEMPORARY_DECIMAL: []byte("6"), - DATA_TEMPORARY_ADDRESS: []byte("0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9"), - } + expectedData := fmt.Sprintf("%s,%s,%s,%s", "SRF", "200", "6", "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9") + + storedValue, err := store.ReadEntry(ctx, sessionId, DATA_TEMPORARY_VALUE) + require.NoError(t, err) + require.Equal(t, expectedData, string(storedValue), "Mismatch for key %v", DATA_TEMPORARY_VALUE) - for key, expectedValue := range expectedEntries { - storedValue, err := store.ReadEntry(ctx, sessionId, key) - require.NoError(t, err) - require.Equal(t, expectedValue, storedValue, "Mismatch for key %v", key) - } } func TestGetTemporaryVoucherData(t *testing.T) { From 63eed81d3d5ccb0c9433eda7b9fd289463c6d4f0 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 1 Nov 2024 00:44:15 +0300 Subject: [PATCH 199/289] Merge branch 'master' into consolidate-temp-data-storage --- internal/handlers/ussd/menuhandler.go | 118 +++++++++++++------- internal/handlers/ussd/menuhandler_test.go | 52 +++++++-- internal/utils/db.go | 7 ++ services/registration/enter_familyname.vis | 2 +- services/registration/enter_location.vis | 2 +- services/registration/enter_name.vis | 2 +- services/registration/enter_offerings.vis | 2 +- services/registration/enter_yob.vis | 4 +- services/registration/set_female.vis | 2 +- services/registration/set_male.vis | 2 +- services/registration/set_unspecified.vis | 2 +- services/registration/update_age | 2 + services/registration/update_familyname.vis | 2 + services/registration/update_firstname.vis | 2 + services/registration/update_gender.vis | 2 + services/registration/update_location.vis | 2 + services/registration/update_offerings.vis | 2 + services/registration/update_yob.vis | 2 + 18 files changed, 150 insertions(+), 59 deletions(-) create mode 100644 services/registration/update_age create mode 100644 services/registration/update_familyname.vis create mode 100644 services/registration/update_firstname.vis create mode 100644 services/registration/update_gender.vis create mode 100644 services/registration/update_location.vis create mode 100644 services/registration/update_offerings.vis create mode 100644 services/registration/update_yob.vis diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index aaa1530..60dd11c 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -19,9 +19,9 @@ import ( "git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/state" + "git.grassecon.net/urdt/ussd/common" "git.grassecon.net/urdt/ussd/internal/handlers/server" "git.grassecon.net/urdt/ussd/internal/utils" - "git.grassecon.net/urdt/ussd/common" "gopkg.in/leonelquinteros/gotext.v1" "git.grassecon.net/urdt/ussd/internal/storage" @@ -33,7 +33,6 @@ var ( translationDir = path.Join(scriptDir, "locale") okResponse *api.OKResponse errResponse *api.ErrResponse - backOption = []byte("0") ) // FlagManager handles centralized flag management @@ -334,13 +333,18 @@ func (h *Handlers) SaveFirstname(ctx context.Context, sym string, input []byte) if !ok { return res, fmt.Errorf("missing session") } - if len(input) > 0 { - if bytes.Equal(input, backOption) { - return res, nil + firstName := string(input) + store := h.userdataStore + flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") + allowUpdate := h.st.MatchFlag(flag_allow_update, true) + if allowUpdate { + temporaryFirstName, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_FIRST_NAME) + err = store.WriteEntry(ctx, sessionId, utils.DATA_FIRST_NAME, []byte(temporaryFirstName)) + if err != nil { + return res, err } - firstName := string(input) - store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_FIRST_NAME, []byte(firstName)) + } else { + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_FIRST_NAME, []byte(firstName)) if err != nil { return res, err } @@ -357,20 +361,24 @@ func (h *Handlers) SaveFamilyname(ctx context.Context, sym string, input []byte) if !ok { return res, fmt.Errorf("missing session") } - if len(input) > 0 { - if bytes.Equal(input, backOption) { - return res, nil - } - familyName := string(input) - store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_FAMILY_NAME, []byte(familyName)) + store := h.userdataStore + familyName := string(input) + + flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") + allowUpdate := h.st.MatchFlag(flag_allow_update, true) + + if allowUpdate { + temporaryFamilyName, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_FAMILY_NAME) + err = store.WriteEntry(ctx, sessionId, utils.DATA_FAMILY_NAME, []byte(temporaryFamilyName)) if err != nil { return res, err } } else { - return res, fmt.Errorf("a family name cannot be less than one character") + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_FAMILY_NAME, []byte(familyName)) + if err != nil { + return res, err + } } - return res, nil } @@ -382,10 +390,19 @@ func (h *Handlers) SaveYob(ctx context.Context, sym string, input []byte) (resou if !ok { return res, fmt.Errorf("missing session") } - if len(input) == 4 { - yob := string(input) - store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_YOB, []byte(yob)) + yob := string(input) + store := h.userdataStore + flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") + allowUpdate := h.st.MatchFlag(flag_allow_update, true) + + if allowUpdate { + temporaryYob, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_YOB) + err = store.WriteEntry(ctx, sessionId, utils.DATA_YOB, []byte(temporaryYob)) + if err != nil { + return res, err + } + } else { + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_YOB, []byte(yob)) if err != nil { return res, err } @@ -402,13 +419,20 @@ func (h *Handlers) SaveLocation(ctx context.Context, sym string, input []byte) ( if !ok { return res, fmt.Errorf("missing session") } - if len(input) > 0 { - if bytes.Equal(input, backOption) { - return res, nil + location := string(input) + store := h.userdataStore + + flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") + allowUpdate := h.st.MatchFlag(flag_allow_update, true) + + if allowUpdate { + temporaryLocation, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_LOCATION) + err = store.WriteEntry(ctx, sessionId, utils.DATA_LOCATION, []byte(temporaryLocation)) + if err != nil { + return res, err } - location := string(input) - store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_LOCATION, []byte(location)) + } else { + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_LOCATION, []byte(location)) if err != nil { return res, err } @@ -426,14 +450,22 @@ func (h *Handlers) SaveGender(ctx context.Context, sym string, input []byte) (re if !ok { return res, fmt.Errorf("missing session") } - if bytes.Equal(input, backOption) { - return res, nil - } gender := strings.Split(symbol, "_")[1] store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_GENDER, []byte(gender)) - if err != nil { - return res, nil + flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") + allowUpdate := h.st.MatchFlag(flag_allow_update, true) + + if allowUpdate { + temporaryGender, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_GENDER) + err = store.WriteEntry(ctx, sessionId, utils.DATA_GENDER, []byte(temporaryGender)) + if err != nil { + return res, err + } + } else { + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_GENDER, []byte(gender)) + if err != nil { + return res, err + } } return res, nil @@ -447,12 +479,22 @@ func (h *Handlers) SaveOfferings(ctx context.Context, sym string, input []byte) if !ok { return res, fmt.Errorf("missing session") } - if len(input) > 0 { - offerings := string(input) - store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_OFFERINGS, []byte(offerings)) + offerings := string(input) + store := h.userdataStore + + flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") + allowUpdate := h.st.MatchFlag(flag_allow_update, true) + + if allowUpdate { + temporaryOfferings, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_OFFERINGS) + err = store.WriteEntry(ctx, sessionId, utils.DATA_OFFERINGS, []byte(temporaryOfferings)) if err != nil { - return res, nil + return res, err + } + } else { + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_OFFERINGS, []byte(offerings)) + if err != nil { + return res, err } } diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index bf29926..f6f1069 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -174,8 +174,11 @@ func TestWithPersister_PanicWhenAlreadySet(t *testing.T) { } func TestSaveFirstname(t *testing.T) { - // Create a new instance of MockMyDataStore + // Create new mocks mockStore := new(mocks.MockUserDataStore) + mockState := state.NewState(16) + + fm, err := NewFlagManager(flagsPath) // Define test data sessionId := "session123" @@ -183,11 +186,13 @@ func TestSaveFirstname(t *testing.T) { 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) + mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_FIRST_NAME, []byte(firstName)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, + flagManager: fm.parser, + st: mockState, } // Call the method @@ -204,6 +209,9 @@ func TestSaveFirstname(t *testing.T) { func TestSaveFamilyname(t *testing.T) { // Create a new instance of UserDataStore mockStore := new(mocks.MockUserDataStore) + mockState := state.NewState(16) + + fm, err := NewFlagManager(flagsPath) // Define test data sessionId := "session123" @@ -211,11 +219,13 @@ func TestSaveFamilyname(t *testing.T) { 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) + mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_FAMILY_NAME, []byte(familyName)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, + st: mockState, + flagManager: fm.parser, } // Call the method @@ -288,8 +298,11 @@ func TestSaveTemporaryPin(t *testing.T) { } func TestSaveYoB(t *testing.T) { - // Create a new instance of MockMyDataStore + // Create new instances mockStore := new(mocks.MockUserDataStore) + mockState := state.NewState(16) + + fm, err := NewFlagManager(flagsPath) // Define test data sessionId := "session123" @@ -297,11 +310,13 @@ func TestSaveYoB(t *testing.T) { 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) + mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_YOB, []byte(yob)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, + st: mockState, + flagManager: fm.parser, } // Call the method @@ -318,6 +333,9 @@ func TestSaveYoB(t *testing.T) { func TestSaveLocation(t *testing.T) { // Create a new instance of MockMyDataStore mockStore := new(mocks.MockUserDataStore) + mockState := state.NewState(16) + + fm, err := NewFlagManager(flagsPath) // Define test data sessionId := "session123" @@ -325,11 +343,13 @@ func TestSaveLocation(t *testing.T) { 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) + mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_LOCATION, []byte(yob)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, + st: mockState, + flagManager: fm.parser, } // Call the method @@ -346,6 +366,9 @@ func TestSaveLocation(t *testing.T) { func TestSaveOfferings(t *testing.T) { // Create a new instance of MockUserDataStore mockStore := new(mocks.MockUserDataStore) + mockState := state.NewState(16) + + fm, err := NewFlagManager(flagsPath) // Define test data sessionId := "session123" @@ -353,11 +376,13 @@ func TestSaveOfferings(t *testing.T) { ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Set up the expected behavior of the mock - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_OFFERINGS, []byte(offerings)).Return(nil) + mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_OFFERINGS, []byte(offerings)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, + st: mockState, + flagManager: fm.parser, } // Call the method @@ -372,10 +397,12 @@ func TestSaveOfferings(t *testing.T) { } func TestSaveGender(t *testing.T) { - // Create a new instance of MockMyDataStore + // Create a new mock instances mockStore := new(mocks.MockUserDataStore) mockState := state.NewState(16) + fm, _ := NewFlagManager(flagsPath) + // Define the session ID and context sessionId := "session123" ctx := context.WithValue(context.Background(), "SessionId", sessionId) @@ -415,16 +442,17 @@ func TestSaveGender(t *testing.T) { t.Run(tt.name, func(t *testing.T) { // Set up expectations for the mock database if tt.expectCall { - expectedKey := utils.DATA_GENDER + expectedKey := utils.DATA_TEMPORARY_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) + mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_GENDER, []byte(tt.expectedGender)).Return(nil) } mockState.ExecPath = append(mockState.ExecPath, tt.executingSymbol) // Create the Handlers instance with the mock store h := &Handlers{ userdataStore: mockStore, st: mockState, + flagManager: fm.parser, } // Call the method @@ -435,9 +463,9 @@ func TestSaveGender(t *testing.T) { // Verify expectations if tt.expectCall { - mockStore.AssertCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_GENDER, []byte(tt.expectedGender)) + mockStore.AssertCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_GENDER, []byte(tt.expectedGender)) } else { - mockStore.AssertNotCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_GENDER, []byte(tt.expectedGender)) + mockStore.AssertNotCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_GENDER, []byte(tt.expectedGender)) } }) } diff --git a/internal/utils/db.go b/internal/utils/db.go index df96dfa..4d29c48 100644 --- a/internal/utils/db.go +++ b/internal/utils/db.go @@ -14,11 +14,17 @@ const ( DATA_CUSTODIAL_ID DATA_ACCOUNT_PIN DATA_ACCOUNT_STATUS + DATA_TEMPORARY_FIRST_NAME DATA_FIRST_NAME + DATA_TEMPORARY_FAMILY_NAME DATA_FAMILY_NAME + DATA_TEMPORARY_YOB DATA_YOB + DATA_TEMPORARY_LOCATION DATA_LOCATION + DATA_TEMPORARY_GENDER DATA_GENDER + DATA_TEMPORARY_OFFERINGS DATA_OFFERINGS DATA_RECIPIENT DATA_AMOUNT @@ -29,6 +35,7 @@ const ( DATA_PUBLIC_KEY_REVERSE DATA_ACTIVE_DECIMAL DATA_ACTIVE_ADDRESS + ) func typToBytes(typ DataTyp) []byte { diff --git a/services/registration/enter_familyname.vis b/services/registration/enter_familyname.vis index 5a684ed..5db4c17 100644 --- a/services/registration/enter_familyname.vis +++ b/services/registration/enter_familyname.vis @@ -1,5 +1,5 @@ CATCH incorrect_pin flag_incorrect_pin 1 -CATCH profile_update_success flag_allow_update 1 +CATCH update_familyname flag_allow_update 1 MOUT back 0 HALT LOAD save_familyname 0 diff --git a/services/registration/enter_location.vis b/services/registration/enter_location.vis index c8da2dd..8966872 100644 --- a/services/registration/enter_location.vis +++ b/services/registration/enter_location.vis @@ -1,5 +1,5 @@ CATCH incorrect_pin flag_incorrect_pin 1 -CATCH profile_update_success flag_allow_update 1 +CATCH update_location flag_allow_update 1 MOUT back 0 HALT LOAD save_location 0 diff --git a/services/registration/enter_name.vis b/services/registration/enter_name.vis index 799b2a1..f853d0a 100644 --- a/services/registration/enter_name.vis +++ b/services/registration/enter_name.vis @@ -1,5 +1,5 @@ CATCH incorrect_pin flag_incorrect_pin 1 -CATCH profile_update_success flag_allow_update 1 +CATCH update_firstname flag_allow_update 1 MOUT back 0 HALT LOAD save_firstname 0 diff --git a/services/registration/enter_offerings.vis b/services/registration/enter_offerings.vis index 26e4b61..5cc7977 100644 --- a/services/registration/enter_offerings.vis +++ b/services/registration/enter_offerings.vis @@ -1,5 +1,5 @@ CATCH incorrect_pin flag_incorrect_pin 1 -CATCH profile_update_success flag_allow_update 1 +CATCH update_offerings flag_allow_update 1 LOAD save_offerings 0 MOUT back 0 HALT diff --git a/services/registration/enter_yob.vis b/services/registration/enter_yob.vis index 40bf3f4..c74aeed 100644 --- a/services/registration/enter_yob.vis +++ b/services/registration/enter_yob.vis @@ -1,10 +1,10 @@ CATCH incorrect_pin flag_incorrect_pin 1 -CATCH profile_update_success flag_allow_update 1 -LOAD save_yob 0 +CATCH update_yob flag_allow_update 1 MOUT back 0 HALT LOAD verify_yob 0 CATCH incorrect_date_format flag_incorrect_date_format 1 +LOAD save_yob 0 RELOAD save_yob INCMP _ 0 INCMP pin_entry * diff --git a/services/registration/set_female.vis b/services/registration/set_female.vis index 723b080..e211ada 100644 --- a/services/registration/set_female.vis +++ b/services/registration/set_female.vis @@ -1,4 +1,4 @@ LOAD save_gender 0 CATCH incorrect_pin flag_incorrect_pin 1 -CATCH profile_update_success flag_allow_update 1 +CATCH update_gender flag_allow_update 1 MOVE pin_entry diff --git a/services/registration/set_male.vis b/services/registration/set_male.vis index 723b080..e211ada 100644 --- a/services/registration/set_male.vis +++ b/services/registration/set_male.vis @@ -1,4 +1,4 @@ LOAD save_gender 0 CATCH incorrect_pin flag_incorrect_pin 1 -CATCH profile_update_success flag_allow_update 1 +CATCH update_gender flag_allow_update 1 MOVE pin_entry diff --git a/services/registration/set_unspecified.vis b/services/registration/set_unspecified.vis index 723b080..e211ada 100644 --- a/services/registration/set_unspecified.vis +++ b/services/registration/set_unspecified.vis @@ -1,4 +1,4 @@ LOAD save_gender 0 CATCH incorrect_pin flag_incorrect_pin 1 -CATCH profile_update_success flag_allow_update 1 +CATCH update_gender flag_allow_update 1 MOVE pin_entry diff --git a/services/registration/update_age b/services/registration/update_age new file mode 100644 index 0000000..76ca306 --- /dev/null +++ b/services/registration/update_age @@ -0,0 +1,2 @@ +RELOAD save_yob +CATCH profile_update_success flag_allow_update 1 \ No newline at end of file diff --git a/services/registration/update_familyname.vis b/services/registration/update_familyname.vis new file mode 100644 index 0000000..7cd4d9f --- /dev/null +++ b/services/registration/update_familyname.vis @@ -0,0 +1,2 @@ +RELOAD save_familyname +CATCH profile_update_success flag_allow_update 1 diff --git a/services/registration/update_firstname.vis b/services/registration/update_firstname.vis new file mode 100644 index 0000000..dca7036 --- /dev/null +++ b/services/registration/update_firstname.vis @@ -0,0 +1,2 @@ +RELOAD save_firstname +CATCH profile_update_success flag_allow_update 1 diff --git a/services/registration/update_gender.vis b/services/registration/update_gender.vis new file mode 100644 index 0000000..506a56a --- /dev/null +++ b/services/registration/update_gender.vis @@ -0,0 +1,2 @@ +RELOAD save_gender +CATCH profile_update_success flag_allow_update 1 diff --git a/services/registration/update_location.vis b/services/registration/update_location.vis new file mode 100644 index 0000000..16c4ea2 --- /dev/null +++ b/services/registration/update_location.vis @@ -0,0 +1,2 @@ +RELOAD save_location +CATCH profile_update_success flag_allow_update 1 diff --git a/services/registration/update_offerings.vis b/services/registration/update_offerings.vis new file mode 100644 index 0000000..4aeed74 --- /dev/null +++ b/services/registration/update_offerings.vis @@ -0,0 +1,2 @@ +RELOAD save_offerings +CATCH profile_update_success flag_allow_update 1 diff --git a/services/registration/update_yob.vis b/services/registration/update_yob.vis new file mode 100644 index 0000000..a9388ae --- /dev/null +++ b/services/registration/update_yob.vis @@ -0,0 +1,2 @@ +RELOAD save_yob +CATCH profile_update_success flag_allow_update 1 From d7ea8fa65196e1de6fd1c08f4f0a408de1166ba8 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 1 Nov 2024 01:10:58 +0300 Subject: [PATCH 200/289] Use the DATA_TEMPORARY_VALUE for the user data --- internal/handlers/ussd/menuhandler.go | 24 +++++++++++----------- internal/handlers/ussd/menuhandler_test.go | 18 ++++++++-------- internal/utils/db.go | 6 ------ 3 files changed, 21 insertions(+), 27 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 60dd11c..5f0c2d9 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -338,13 +338,13 @@ func (h *Handlers) SaveFirstname(ctx context.Context, sym string, input []byte) flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") allowUpdate := h.st.MatchFlag(flag_allow_update, true) if allowUpdate { - temporaryFirstName, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_FIRST_NAME) + temporaryFirstName, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE) err = store.WriteEntry(ctx, sessionId, utils.DATA_FIRST_NAME, []byte(temporaryFirstName)) if err != nil { return res, err } } else { - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_FIRST_NAME, []byte(firstName)) + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(firstName)) if err != nil { return res, err } @@ -368,13 +368,13 @@ func (h *Handlers) SaveFamilyname(ctx context.Context, sym string, input []byte) allowUpdate := h.st.MatchFlag(flag_allow_update, true) if allowUpdate { - temporaryFamilyName, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_FAMILY_NAME) + temporaryFamilyName, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE) err = store.WriteEntry(ctx, sessionId, utils.DATA_FAMILY_NAME, []byte(temporaryFamilyName)) if err != nil { return res, err } } else { - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_FAMILY_NAME, []byte(familyName)) + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(familyName)) if err != nil { return res, err } @@ -396,13 +396,13 @@ func (h *Handlers) SaveYob(ctx context.Context, sym string, input []byte) (resou allowUpdate := h.st.MatchFlag(flag_allow_update, true) if allowUpdate { - temporaryYob, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_YOB) + temporaryYob, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE) err = store.WriteEntry(ctx, sessionId, utils.DATA_YOB, []byte(temporaryYob)) if err != nil { return res, err } } else { - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_YOB, []byte(yob)) + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(yob)) if err != nil { return res, err } @@ -426,13 +426,13 @@ func (h *Handlers) SaveLocation(ctx context.Context, sym string, input []byte) ( allowUpdate := h.st.MatchFlag(flag_allow_update, true) if allowUpdate { - temporaryLocation, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_LOCATION) + temporaryLocation, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE) err = store.WriteEntry(ctx, sessionId, utils.DATA_LOCATION, []byte(temporaryLocation)) if err != nil { return res, err } } else { - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_LOCATION, []byte(location)) + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(location)) if err != nil { return res, err } @@ -456,13 +456,13 @@ func (h *Handlers) SaveGender(ctx context.Context, sym string, input []byte) (re allowUpdate := h.st.MatchFlag(flag_allow_update, true) if allowUpdate { - temporaryGender, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_GENDER) + temporaryGender, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE) err = store.WriteEntry(ctx, sessionId, utils.DATA_GENDER, []byte(temporaryGender)) if err != nil { return res, err } } else { - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_GENDER, []byte(gender)) + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(gender)) if err != nil { return res, err } @@ -486,13 +486,13 @@ func (h *Handlers) SaveOfferings(ctx context.Context, sym string, input []byte) allowUpdate := h.st.MatchFlag(flag_allow_update, true) if allowUpdate { - temporaryOfferings, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_OFFERINGS) + temporaryOfferings, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE) err = store.WriteEntry(ctx, sessionId, utils.DATA_OFFERINGS, []byte(temporaryOfferings)) if err != nil { return res, err } } else { - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_OFFERINGS, []byte(offerings)) + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(offerings)) if err != nil { return res, err } diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index f6f1069..77ae68c 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -186,7 +186,7 @@ func TestSaveFirstname(t *testing.T) { ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Set up the expected behavior of the mock - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_FIRST_NAME, []byte(firstName)).Return(nil) + mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(firstName)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ @@ -219,7 +219,7 @@ func TestSaveFamilyname(t *testing.T) { ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Set up the expected behavior of the mock - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_FAMILY_NAME, []byte(familyName)).Return(nil) + mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(familyName)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ @@ -310,7 +310,7 @@ func TestSaveYoB(t *testing.T) { ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Set up the expected behavior of the mock - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_YOB, []byte(yob)).Return(nil) + mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(yob)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ @@ -343,7 +343,7 @@ func TestSaveLocation(t *testing.T) { ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Set up the expected behavior of the mock - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_LOCATION, []byte(yob)).Return(nil) + mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(yob)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ @@ -376,7 +376,7 @@ func TestSaveOfferings(t *testing.T) { ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Set up the expected behavior of the mock - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_OFFERINGS, []byte(offerings)).Return(nil) + mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(offerings)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ @@ -442,10 +442,10 @@ func TestSaveGender(t *testing.T) { t.Run(tt.name, func(t *testing.T) { // Set up expectations for the mock database if tt.expectCall { - expectedKey := utils.DATA_TEMPORARY_GENDER + expectedKey := utils.DATA_TEMPORARY_VALUE mockStore.On("WriteEntry", ctx, sessionId, expectedKey, []byte(tt.expectedGender)).Return(nil) } else { - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_GENDER, []byte(tt.expectedGender)).Return(nil) + mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(tt.expectedGender)).Return(nil) } mockState.ExecPath = append(mockState.ExecPath, tt.executingSymbol) // Create the Handlers instance with the mock store @@ -463,9 +463,9 @@ func TestSaveGender(t *testing.T) { // Verify expectations if tt.expectCall { - mockStore.AssertCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_GENDER, []byte(tt.expectedGender)) + mockStore.AssertCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(tt.expectedGender)) } else { - mockStore.AssertNotCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_GENDER, []byte(tt.expectedGender)) + mockStore.AssertNotCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(tt.expectedGender)) } }) } diff --git a/internal/utils/db.go b/internal/utils/db.go index 4d29c48..b37240d 100644 --- a/internal/utils/db.go +++ b/internal/utils/db.go @@ -14,17 +14,11 @@ const ( DATA_CUSTODIAL_ID DATA_ACCOUNT_PIN DATA_ACCOUNT_STATUS - DATA_TEMPORARY_FIRST_NAME DATA_FIRST_NAME - DATA_TEMPORARY_FAMILY_NAME DATA_FAMILY_NAME - DATA_TEMPORARY_YOB DATA_YOB - DATA_TEMPORARY_LOCATION DATA_LOCATION - DATA_TEMPORARY_GENDER DATA_GENDER - DATA_TEMPORARY_OFFERINGS DATA_OFFERINGS DATA_RECIPIENT DATA_AMOUNT From 9a528cfd1440f72d0678d318e847e7d10fbdee69 Mon Sep 17 00:00:00 2001 From: lash Date: Fri, 1 Nov 2024 03:17:01 +0000 Subject: [PATCH 201/289] Clean up messily failed conflict resolution --- common/vouchers_test.go | 17 +++-- internal/handlers/ussd/menuhandler.go | 44 ++++++------- internal/handlers/ussd/menuhandler_test.go | 74 ++++------------------ 3 files changed, 44 insertions(+), 91 deletions(-) diff --git a/common/vouchers_test.go b/common/vouchers_test.go index 95fce6e..8b9fa2a 100644 --- a/common/vouchers_test.go +++ b/common/vouchers_test.go @@ -9,13 +9,12 @@ import ( "github.com/stretchr/testify/require" "git.grassecon.net/urdt/ussd/internal/storage" - "git.grassecon.net/urdt/ussd/common" memdb "git.defalsify.org/vise.git/db/mem" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" ) // InitializeTestDb sets up and returns an in-memory database and store. -func InitializeTestDb(t *testing.T) (context.Context, *common.UserDataStore) { +func InitializeTestDb(t *testing.T) (context.Context, *UserDataStore) { ctx := context.Background() // Initialize memDb @@ -23,8 +22,8 @@ func InitializeTestDb(t *testing.T) (context.Context, *common.UserDataStore) { err := db.Connect(ctx, "") require.NoError(t, err, "Failed to connect to memDb") - // Create common.UserDataStore with memDb - store := &common.UserDataStore{Db: db} + // Create UserDataStore with memDb + store := &UserDataStore{Db: db} t.Cleanup(func() { db.Close() // Ensure the DB is closed after each test @@ -183,11 +182,11 @@ func TestUpdateVoucherData(t *testing.T) { require.NoError(t, err) // Verify active data was stored correctly - activeEntries := map[common.DataTyp][]byte{ - common.DATA_ACTIVE_SYM: []byte(newData.TokenSymbol), - common.DATA_ACTIVE_BAL: []byte(newData.Balance), - common.DATA_ACTIVE_DECIMAL: []byte(newData.TokenDecimals), - common.DATA_ACTIVE_ADDRESS: []byte(newData.ContractAddress), + activeEntries := map[DataTyp][]byte{ + DATA_ACTIVE_SYM: []byte(newData.TokenSymbol), + DATA_ACTIVE_BAL: []byte(newData.Balance), + DATA_ACTIVE_DECIMAL: []byte(newData.TokenDecimals), + DATA_ACTIVE_ADDRESS: []byte(newData.ContractAddress), } for key, expectedValue := range activeEntries { diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index db8d520..42785d7 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -20,7 +20,7 @@ import ( "git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/state" "git.grassecon.net/urdt/ussd/common" - "git.grassecon.net/urdt/ussd/internal/handlers/server" + "git.grassecon.net/urdt/ussd/remote" "git.grassecon.net/urdt/ussd/internal/utils" "gopkg.in/leonelquinteros/gotext.v1" @@ -246,7 +246,7 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt res.FlagReset = append(res.FlagReset, flag_incorrect_pin) store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(accountPIN)) + err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(accountPIN)) if err != nil { return res, err } @@ -263,7 +263,7 @@ func (h *Handlers) ConfirmPinChange(ctx context.Context, sym string, input []byt flag_pin_mismatch, _ := h.flagManager.GetFlag("flag_pin_mismatch") store := h.userdataStore - temporaryPin, err := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE) + temporaryPin, err := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) if err != nil { return res, err } @@ -294,7 +294,7 @@ func (h *Handlers) VerifyCreatePin(ctx context.Context, sym string, input []byte return res, fmt.Errorf("missing session") } store := h.userdataStore - temporaryPin, err := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE) + temporaryPin, err := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) if err != nil { return res, err } @@ -338,13 +338,13 @@ func (h *Handlers) SaveFirstname(ctx context.Context, sym string, input []byte) flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") allowUpdate := h.st.MatchFlag(flag_allow_update, true) if allowUpdate { - temporaryFirstName, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE) - err = store.WriteEntry(ctx, sessionId, utils.DATA_FIRST_NAME, []byte(temporaryFirstName)) + temporaryFirstName, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) + err = store.WriteEntry(ctx, sessionId, common.DATA_FIRST_NAME, []byte(temporaryFirstName)) if err != nil { return res, err } } else { - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(firstName)) + err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(firstName)) if err != nil { return res, err } @@ -369,13 +369,13 @@ func (h *Handlers) SaveFamilyname(ctx context.Context, sym string, input []byte) allowUpdate := h.st.MatchFlag(flag_allow_update, true) if allowUpdate { - temporaryFamilyName, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE) - err = store.WriteEntry(ctx, sessionId, utils.DATA_FAMILY_NAME, []byte(temporaryFamilyName)) + temporaryFamilyName, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) + err = store.WriteEntry(ctx, sessionId, common.DATA_FAMILY_NAME, []byte(temporaryFamilyName)) if err != nil { return res, err } } else { - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(familyName)) + err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(familyName)) if err != nil { return res, err } @@ -397,13 +397,13 @@ func (h *Handlers) SaveYob(ctx context.Context, sym string, input []byte) (resou allowUpdate := h.st.MatchFlag(flag_allow_update, true) if allowUpdate { - temporaryYob, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE) - err = store.WriteEntry(ctx, sessionId, utils.DATA_YOB, []byte(temporaryYob)) + temporaryYob, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) + err = store.WriteEntry(ctx, sessionId, common.DATA_YOB, []byte(temporaryYob)) if err != nil { return res, err } } else { - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(yob)) + err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(yob)) if err != nil { return res, err } @@ -427,13 +427,13 @@ func (h *Handlers) SaveLocation(ctx context.Context, sym string, input []byte) ( allowUpdate := h.st.MatchFlag(flag_allow_update, true) if allowUpdate { - temporaryLocation, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE) - err = store.WriteEntry(ctx, sessionId, utils.DATA_LOCATION, []byte(temporaryLocation)) + temporaryLocation, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) + err = store.WriteEntry(ctx, sessionId, common.DATA_LOCATION, []byte(temporaryLocation)) if err != nil { return res, err } } else { - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(location)) + err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(location)) if err != nil { return res, err } @@ -457,13 +457,13 @@ func (h *Handlers) SaveGender(ctx context.Context, sym string, input []byte) (re allowUpdate := h.st.MatchFlag(flag_allow_update, true) if allowUpdate { - temporaryGender, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE) - err = store.WriteEntry(ctx, sessionId, utils.DATA_GENDER, []byte(temporaryGender)) + temporaryGender, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) + err = store.WriteEntry(ctx, sessionId, common.DATA_GENDER, []byte(temporaryGender)) if err != nil { return res, err } } else { - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(gender)) + err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(gender)) if err != nil { return res, err } @@ -488,13 +488,13 @@ func (h *Handlers) SaveOfferings(ctx context.Context, sym string, input []byte) allowUpdate := h.st.MatchFlag(flag_allow_update, true) if allowUpdate { - temporaryOfferings, _ := store.ReadEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE) - err = store.WriteEntry(ctx, sessionId, utils.DATA_OFFERINGS, []byte(temporaryOfferings)) + temporaryOfferings, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) + err = store.WriteEntry(ctx, sessionId, common.DATA_OFFERINGS, []byte(temporaryOfferings)) if err != nil { return res, err } } else { - err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(offerings)) + err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(offerings)) if err != nil { return res, err } diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 30f84d9..2eb6519 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -19,7 +19,6 @@ import ( "git.grassecon.net/urdt/ussd/internal/testutil/testservice" "git.grassecon.net/urdt/ussd/common" - "git.grassecon.net/urdt/ussd/internal/utils" "github.com/alecthomas/assert/v2" // "github.com/grassrootseconomics/eth-custodial/pkg/api" testdataloader "github.com/peteole/testdata-loader" @@ -181,11 +180,7 @@ func TestSaveFirstname(t *testing.T) { ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Set up the expected behavior of the mock -<<<<<<< HEAD - mockStore.On("WriteEntry", ctx, sessionId, common.DATA_FIRST_NAME, []byte(firstName)).Return(nil) -======= - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(firstName)).Return(nil) ->>>>>>> master + mockStore.On("WriteEntry", ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(firstName)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ @@ -218,11 +213,7 @@ func TestSaveFamilyname(t *testing.T) { ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Set up the expected behavior of the mock -<<<<<<< HEAD - mockStore.On("WriteEntry", ctx, sessionId, common.DATA_FAMILY_NAME, []byte(familyName)).Return(nil) -======= - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(familyName)).Return(nil) ->>>>>>> master + mockStore.On("WriteEntry", ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(familyName)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ @@ -284,11 +275,7 @@ func TestSaveTemporaryPin(t *testing.T) { t.Run(tt.name, func(t *testing.T) { // Set up the expected behavior of the mock -<<<<<<< HEAD - mockStore.On("WriteEntry", ctx, sessionId, common.DATA_TEMPORARY_PIN, []byte(tt.input)).Return(nil) -======= - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(tt.input)).Return(nil) ->>>>>>> master + mockStore.On("WriteEntry", ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(tt.input)).Return(nil) // Call the method res, err := h.SaveTemporaryPin(ctx, "save_pin", tt.input) @@ -317,11 +304,7 @@ func TestSaveYoB(t *testing.T) { ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Set up the expected behavior of the mock -<<<<<<< HEAD - mockStore.On("WriteEntry", ctx, sessionId, common.DATA_YOB, []byte(yob)).Return(nil) -======= - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(yob)).Return(nil) ->>>>>>> master + mockStore.On("WriteEntry", ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(yob)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ @@ -354,11 +337,7 @@ func TestSaveLocation(t *testing.T) { ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Set up the expected behavior of the mock -<<<<<<< HEAD - mockStore.On("WriteEntry", ctx, sessionId, common.DATA_LOCATION, []byte(yob)).Return(nil) -======= - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(yob)).Return(nil) ->>>>>>> master + mockStore.On("WriteEntry", ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(yob)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ @@ -391,11 +370,7 @@ func TestSaveOfferings(t *testing.T) { ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Set up the expected behavior of the mock -<<<<<<< HEAD - mockStore.On("WriteEntry", ctx, sessionId, common.DATA_OFFERINGS, []byte(offerings)).Return(nil) -======= - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(offerings)).Return(nil) ->>>>>>> master + mockStore.On("WriteEntry", ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(offerings)).Return(nil) // Create the Handlers instance with the mock store h := &Handlers{ @@ -461,17 +436,10 @@ func TestSaveGender(t *testing.T) { t.Run(tt.name, func(t *testing.T) { // Set up expectations for the mock database if tt.expectCall { -<<<<<<< HEAD - expectedKey := common.DATA_GENDER + expectedKey := common.DATA_TEMPORARY_VALUE mockStore.On("WriteEntry", ctx, sessionId, expectedKey, []byte(tt.expectedGender)).Return(nil) } else { - mockStore.On("WriteEntry", ctx, sessionId, common.DATA_GENDER, []byte(tt.expectedGender)).Return(nil) -======= - expectedKey := utils.DATA_TEMPORARY_VALUE - mockStore.On("WriteEntry", ctx, sessionId, expectedKey, []byte(tt.expectedGender)).Return(nil) - } else { - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(tt.expectedGender)).Return(nil) ->>>>>>> master + mockStore.On("WriteEntry", ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(tt.expectedGender)).Return(nil) } mockState.ExecPath = append(mockState.ExecPath, tt.executingSymbol) // Create the Handlers instance with the mock store @@ -489,15 +457,9 @@ func TestSaveGender(t *testing.T) { // Verify expectations if tt.expectCall { -<<<<<<< HEAD - mockStore.AssertCalled(t, "WriteEntry", ctx, sessionId, common.DATA_GENDER, []byte(tt.expectedGender)) + mockStore.AssertCalled(t, "WriteEntry", ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(tt.expectedGender)) } else { - mockStore.AssertNotCalled(t, "WriteEntry", ctx, sessionId, common.DATA_GENDER, []byte(tt.expectedGender)) -======= - mockStore.AssertCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(tt.expectedGender)) - } else { - mockStore.AssertNotCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(tt.expectedGender)) ->>>>>>> master + mockStore.AssertNotCalled(t, "WriteEntry", ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(tt.expectedGender)) } }) } @@ -1072,11 +1034,7 @@ func TestVerifyCreatePin(t *testing.T) { }, } -<<<<<<< HEAD - typ := common.DATA_TEMPORARY_PIN -======= - typ := utils.DATA_TEMPORARY_VALUE ->>>>>>> master + typ := common.DATA_TEMPORARY_VALUE for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -1816,11 +1774,7 @@ func TestConfirmPin(t *testing.T) { // Set up the expected behavior of the mock mockDataStore.On("WriteEntry", ctx, sessionId, common.DATA_ACCOUNT_PIN, []byte(tt.temporarypin)).Return(nil) -<<<<<<< HEAD - mockDataStore.On("ReadEntry", ctx, sessionId, common.DATA_TEMPORARY_PIN).Return(tt.temporarypin, nil) -======= - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE).Return(tt.temporarypin, nil) ->>>>>>> master + mockDataStore.On("ReadEntry", ctx, sessionId, common.DATA_TEMPORARY_VALUE).Return(tt.temporarypin, nil) //Call the function under test res, _ := h.ConfirmPinChange(ctx, "confirm_pin_change", tt.temporarypin) @@ -2060,7 +2014,7 @@ func TestViewVoucher(t *testing.T) { // Set up expectations for mockDataStore expectedData := fmt.Sprintf("%s,%s,%s,%s", "SRF", "100", "6", "0xd4c288865Ce") - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(expectedData)).Return(nil) + mockDataStore.On("WriteEntry", ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(expectedData)).Return(nil) res, err := h.ViewVoucher(ctx, "view_voucher", []byte("1")) assert.NoError(t, err) @@ -2095,7 +2049,7 @@ func TestSetVoucher(t *testing.T) { } // Mocking ReadEntry calls for temporary data retrieval - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE).Return([]byte(expectedData), nil) + mockDataStore.On("ReadEntry", ctx, sessionId, common.DATA_TEMPORARY_VALUE).Return([]byte(expectedData), nil) // Mocking WriteEntry calls for setting active data for key, value := range activeEntries { From 0014693ba8b3b8f1545e59e3cf66bf6bf71caebb Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Fri, 1 Nov 2024 06:39:37 +0300 Subject: [PATCH 202/289] remove guard pin option --- menutraversal_test/group_test.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/menutraversal_test/group_test.json b/menutraversal_test/group_test.json index 8b765f5..a219a6c 100644 --- a/menutraversal_test/group_test.json +++ b/menutraversal_test/group_test.json @@ -13,7 +13,7 @@ }, { "input": "5", - "expectedContent": "PIN Management\n1:Change PIN\n2:Reset other's PIN\n3:Guard my PIN\n0:Back" + "expectedContent": "PIN Management\n1:Change PIN\n2:Reset other's PIN\n0:Back" }, { "input": "1", From 7e448f739ab0205b8e3bab16b0081344de573868 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Fri, 1 Nov 2024 09:35:48 +0300 Subject: [PATCH 203/289] change fs store path to root --- devtools/commands/seed.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devtools/commands/seed.go b/devtools/commands/seed.go index 8abd50f..e76c83d 100644 --- a/devtools/commands/seed.go +++ b/devtools/commands/seed.go @@ -23,7 +23,7 @@ type Config struct { func Seed(ctx context.Context) error { var config Config - adminstore, err := utils.NewAdminStore(ctx, "admin_numbers") + adminstore, err := utils.NewAdminStore(ctx, "../admin_numbers") store := adminstore.FsStore if err != nil { return err From eb2c73dce1478023a34e2d552a649a9c14339d41 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Fri, 1 Nov 2024 11:51:50 +0300 Subject: [PATCH 204/289] remove unused setadmin store --- internal/handlers/handlerservice.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/internal/handlers/handlerservice.go b/internal/handlers/handlerservice.go index 5990dc8..cbc2a29 100644 --- a/internal/handlers/handlerservice.go +++ b/internal/handlers/handlerservice.go @@ -62,10 +62,6 @@ func (ls *LocalHandlerService) SetDataStore(db *db.Db) { ls.UserdataStore = db } -func (ls *LocalHandlerService) SetAdminStore(adminstore *utils.AdminStore) { - ls.AdminStore = adminstore -} - func (ls *LocalHandlerService) GetHandler(accountService server.AccountServiceInterface) (*ussd.Handlers, error) { ussdHandlers, err := ussd.NewHandlers(ls.Parser, *ls.UserdataStore, ls.AdminStore, accountService) if err != nil { From cfe3e526dfb1793ab4977998ae730c834ac67d5e Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 1 Nov 2024 13:17:45 +0300 Subject: [PATCH 205/289] Remove the subprefixdbmock --- internal/handlers/ussd/menuhandler_test.go | 87 +++++++++++++++------- internal/testutil/mocks/subprefixdbmock.go | 21 ------ 2 files changed, 59 insertions(+), 49 deletions(-) delete mode 100644 internal/testutil/mocks/subprefixdbmock.go diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 77ae68c..6f70108 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -16,6 +16,7 @@ import ( "git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/state" "git.grassecon.net/urdt/ussd/internal/models" + "git.grassecon.net/urdt/ussd/internal/storage" "git.grassecon.net/urdt/ussd/internal/testutil/mocks" "git.grassecon.net/urdt/ussd/internal/testutil/testservice" @@ -26,6 +27,7 @@ import ( testdataloader "github.com/peteole/testdata-loader" "github.com/stretchr/testify/require" + memdb "git.defalsify.org/vise.git/db/mem" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" ) @@ -2021,19 +2023,24 @@ func TestSetDefaultVoucher(t *testing.T) { func TestCheckVouchers(t *testing.T) { mockDataStore := new(mocks.MockUserDataStore) mockAccountService := new(mocks.MockAccountService) - mockSubPrefixDb := new(mocks.MockSubPrefixDb) sessionId := "session123" publicKey := "0X13242618721" + ctx := context.WithValue(context.Background(), "SessionId", sessionId) + + db := memdb.NewMemDb() + err := db.Connect(ctx, "") + if err != nil { + t.Fatal(err) + } + spdb := storage.NewSubPrefixDb(db, []byte("vouchers")) h := &Handlers{ userdataStore: mockDataStore, accountService: mockAccountService, - prefixDb: mockSubPrefixDb, + prefixDb: spdb, } - ctx := context.WithValue(context.Background(), "SessionId", sessionId) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil) mockVouchersResponse := &models.VoucherHoldingResponse{} @@ -2042,38 +2049,53 @@ func TestCheckVouchers(t *testing.T) { {ContractAddress: "0x41c188d63Qa", TokenSymbol: "MILO", TokenDecimals: "4", Balance: "200"}, } + expectedSym := []byte("1:SRF\n2:MILO") + mockAccountService.On("FetchVouchers", string(publicKey)).Return(mockVouchersResponse, nil) - mockSubPrefixDb.On("Put", ctx, []byte("sym"), []byte("1:SRF\n2:MILO")).Return(nil) - mockSubPrefixDb.On("Put", ctx, []byte("bal"), []byte("1:100\n2:200")).Return(nil) - mockSubPrefixDb.On("Put", ctx, []byte("deci"), []byte("1:6\n2:4")).Return(nil) - mockSubPrefixDb.On("Put", ctx, []byte("addr"), []byte("1:0xd4c288865Ce\n2:0x41c188d63Qa")).Return(nil) - - _, err := h.CheckVouchers(ctx, "check_vouchers", []byte("")) - + _, err = h.CheckVouchers(ctx, "check_vouchers", []byte("")) assert.NoError(t, err) + // Read voucher sym data from the store + voucherData, err := spdb.Get(ctx, []byte("sym")) + if err != nil { + t.Fatal(err) + } + + // assert that the data is stored correctly + assert.Equal(t, expectedSym, voucherData) + mockDataStore.AssertExpectations(t) mockAccountService.AssertExpectations(t) } func TestGetVoucherList(t *testing.T) { - mockSubPrefixDb := new(mocks.MockSubPrefixDb) - sessionId := "session123" ctx := context.WithValue(context.Background(), "SessionId", sessionId) + db := memdb.NewMemDb() + err := db.Connect(ctx, "") + if err != nil { + t.Fatal(err) + } + spdb := storage.NewSubPrefixDb(db, []byte("vouchers")) + h := &Handlers{ - prefixDb: mockSubPrefixDb, + prefixDb: spdb, } - mockSubPrefixDb.On("Get", ctx, []byte("sym")).Return([]byte("1:SRF\n2:MILO"), nil) + expectedSym := []byte("1:SRF\n2:MILO") + + // Put voucher sym data from the store + err = spdb.Put(ctx, []byte("sym"), expectedSym) + if err != nil { + t.Fatal(err) + } res, err := h.GetVoucherList(ctx, "", []byte("")) - assert.NoError(t, err) - assert.Contains(t, res.Content, "1:SRF\n2:MILO") - mockSubPrefixDb.AssertExpectations(t) + assert.NoError(t, err) + assert.Equal(t, res.Content, string(expectedSym)) } func TestViewVoucher(t *testing.T) { @@ -2082,27 +2104,37 @@ func TestViewVoucher(t *testing.T) { t.Logf(err.Error()) } mockDataStore := new(mocks.MockUserDataStore) - mockSubPrefixDb := new(mocks.MockSubPrefixDb) sessionId := "session123" ctx := context.WithValue(context.Background(), "SessionId", sessionId) + db := memdb.NewMemDb() + err = db.Connect(ctx, "") + if err != nil { + t.Fatal(err) + } + spdb := storage.NewSubPrefixDb(db, []byte("vouchers")) + h := &Handlers{ userdataStore: mockDataStore, flagManager: fm.parser, - prefixDb: mockSubPrefixDb, + prefixDb: spdb, } // Define mock voucher data - mockVoucherData := map[string]string{ - "sym": "1:SRF", - "bal": "1:100", - "deci": "1:6", - "addr": "1:0xd4c288865Ce", + mockData := map[string][]byte{ + "sym": []byte("1:SRF\n2:MILO"), + "bal": []byte("1:100\n2:200"), + "deci": []byte("1:6\n2:4"), + "addr": []byte("1:0xd4c288865Ce\n2:0x41c188d63Qa"), } - for key, value := range mockVoucherData { - mockSubPrefixDb.On("Get", ctx, []byte(key)).Return([]byte(value), nil) + // Put the data + for key, value := range mockData { + err = spdb.Put(ctx, []byte(key), []byte(value)) + if err != nil { + t.Fatal(err) + } } // Set up expectations for mockDataStore @@ -2115,7 +2147,6 @@ func TestViewVoucher(t *testing.T) { assert.Contains(t, res.Content, "SRF\n100") mockDataStore.AssertExpectations(t) - mockSubPrefixDb.AssertExpectations(t) } func TestSetVoucher(t *testing.T) { diff --git a/internal/testutil/mocks/subprefixdbmock.go b/internal/testutil/mocks/subprefixdbmock.go deleted file mode 100644 index e98bcb6..0000000 --- a/internal/testutil/mocks/subprefixdbmock.go +++ /dev/null @@ -1,21 +0,0 @@ -package mocks - -import ( - "context" - - "github.com/stretchr/testify/mock" -) - -type MockSubPrefixDb struct { - mock.Mock -} - -func (m *MockSubPrefixDb) Get(ctx context.Context, key []byte) ([]byte, error) { - args := m.Called(ctx, key) - return args.Get(0).([]byte), args.Error(1) -} - -func (m *MockSubPrefixDb) Put(ctx context.Context, key, val []byte) error { - args := m.Called(ctx, key, val) - return args.Error(0) -} From 332074375aee0010d9cbf37f8738bf12e432810d Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Fri, 1 Nov 2024 16:44:54 +0300 Subject: [PATCH 206/289] wrap in devtools/admin --- devtools/{ => admin}/admin_numbers.json | 0 devtools/{ => admin}/commands/seed.go | 0 devtools/{ => admin}/main.go | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename devtools/{ => admin}/admin_numbers.json (100%) rename devtools/{ => admin}/commands/seed.go (100%) rename devtools/{ => admin}/main.go (79%) diff --git a/devtools/admin_numbers.json b/devtools/admin/admin_numbers.json similarity index 100% rename from devtools/admin_numbers.json rename to devtools/admin/admin_numbers.json diff --git a/devtools/commands/seed.go b/devtools/admin/commands/seed.go similarity index 100% rename from devtools/commands/seed.go rename to devtools/admin/commands/seed.go diff --git a/devtools/main.go b/devtools/admin/main.go similarity index 79% rename from devtools/main.go rename to devtools/admin/main.go index d0d4632..9a527f3 100644 --- a/devtools/main.go +++ b/devtools/admin/main.go @@ -4,7 +4,7 @@ import ( "context" "log" - "git.grassecon.net/urdt/ussd/devtools/commands" + "git.grassecon.net/urdt/ussd/devtools/admin/commands" ) func main() { From 6dbe74d12bc777285b68837fc9c4d0b470559607 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Fri, 1 Nov 2024 16:46:09 +0300 Subject: [PATCH 207/289] use single temporary value --- internal/handlers/ussd/menuhandler.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 198d45b..feb002e 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -237,7 +237,7 @@ func (h *Handlers) CheckPinMisMatch(ctx context.Context, sym string, input []byt if err != nil { return res, err } - temporaryPin, err := store.ReadEntry(ctx, string(blockedNumber), utils.DATA_TEMPORARY_PIN) + temporaryPin, err := store.ReadEntry(ctx, string(blockedNumber), utils.DATA_TEMPORARY_VALUE) if err != nil { return res, err } @@ -312,7 +312,7 @@ func (h *Handlers) SaveOthersTemporaryPin(ctx context.Context, sym string, input if err != nil { return res, err } - err = store.WriteEntry(ctx, string(blockedNumber), utils.DATA_TEMPORARY_PIN, []byte(temporaryPin)) + err = store.WriteEntry(ctx, string(blockedNumber), utils.DATA_TEMPORARY_VALUE, []byte(temporaryPin)) if err != nil { return res, err } @@ -845,7 +845,7 @@ func (h *Handlers) ResetOthersPin(ctx context.Context, sym string, input []byte) if err != nil { return res, err } - temporaryPin, err := store.ReadEntry(ctx, string(blockedPhonenumber), utils.DATA_TEMPORARY_PIN) + temporaryPin, err := store.ReadEntry(ctx, string(blockedPhonenumber), utils.DATA_TEMPORARY_VALUE) if err != nil { return res, err } From c52f8312e4641cb684cf9c206b91b89b5617a2ff Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Sat, 2 Nov 2024 03:21:38 +0300 Subject: [PATCH 208/289] Remove the dbmock and userdbmock --- internal/testutil/mocks/dbmock.go | 59 --------------------------- internal/testutil/mocks/userdbmock.go | 24 ----------- 2 files changed, 83 deletions(-) delete mode 100644 internal/testutil/mocks/dbmock.go delete mode 100644 internal/testutil/mocks/userdbmock.go diff --git a/internal/testutil/mocks/dbmock.go b/internal/testutil/mocks/dbmock.go deleted file mode 100644 index 0b40eab..0000000 --- a/internal/testutil/mocks/dbmock.go +++ /dev/null @@ -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) -} diff --git a/internal/testutil/mocks/userdbmock.go b/internal/testutil/mocks/userdbmock.go deleted file mode 100644 index ff3f18d..0000000 --- a/internal/testutil/mocks/userdbmock.go +++ /dev/null @@ -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) -} From 476a69fe1b7fcd67728a9eaf5f5526b4010d4a1e Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Sat, 2 Nov 2024 03:22:33 +0300 Subject: [PATCH 209/289] Update menuhandler tests to use the memdb instead of dbmocks --- internal/handlers/ussd/menuhandler_test.go | 1185 +++++++++----------- 1 file changed, 510 insertions(+), 675 deletions(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 6f70108..48eb81a 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -7,10 +7,7 @@ import ( "log" "path" "testing" - "time" - "git.defalsify.org/vise.git/asm" - "git.defalsify.org/vise.git/db" "git.defalsify.org/vise.git/lang" "git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/resource" @@ -20,7 +17,6 @@ import ( "git.grassecon.net/urdt/ussd/internal/testutil/mocks" "git.grassecon.net/urdt/ussd/internal/testutil/testservice" - "git.grassecon.net/urdt/ussd/common" "git.grassecon.net/urdt/ussd/internal/utils" "github.com/alecthomas/assert/v2" "github.com/grassrootseconomics/eth-custodial/pkg/api" @@ -36,15 +32,46 @@ var ( flagsPath = path.Join(baseDir, "services", "registration", "pp.csv") ) +// InitializeTestStore sets up and returns an in-memory database and store. +func InitializeTestStore(t *testing.T) (context.Context, *utils.UserDataStore) { + ctx := context.Background() + + // Initialize memDb + db := memdb.NewMemDb() + err := db.Connect(ctx, "") + require.NoError(t, err, "Failed to connect to memDb") + + // Create UserDataStore with memDb + store := &utils.UserDataStore{Db: db} + + t.Cleanup(func() { + db.Close() // Ensure the DB is closed after each test + }) + + return ctx, store +} + +func InitializeTestSubPrefixDb(t *testing.T, ctx context.Context) *storage.SubPrefixDb { + db := memdb.NewMemDb() + err := db.Connect(ctx, "") + if err != nil { + t.Fatal(err) + } + spdb := storage.NewSubPrefixDb(db, []byte("vouchers")) + + return spdb +} + func TestNewHandlers(t *testing.T) { + _, store := InitializeTestStore(t) + fm, err := NewFlagManager(flagsPath) accountService := testservice.TestAccountService{} if err != nil { t.Logf(err.Error()) } t.Run("Valid UserDataStore", func(t *testing.T) { - mockStore := &mocks.MockUserDataStore{} - handlers, err := NewHandlers(fm.parser, mockStore, &accountService) + handlers, err := NewHandlers(fm.parser, store, &accountService) if err != nil { t.Fatalf("expected no error, got %v", err) } @@ -58,10 +85,7 @@ func TestNewHandlers(t *testing.T) { // Test case for nil userdataStore t.Run("Nil UserDataStore", func(t *testing.T) { - appFlags := &asm.FlagParser{} - - handlers, err := NewHandlers(appFlags, nil, &accountService) - + handlers, err := NewHandlers(fm.parser, nil, &accountService) if err == nil { t.Fatal("expected an error, got none") } @@ -75,19 +99,19 @@ func TestNewHandlers(t *testing.T) { } func TestCreateAccount(t *testing.T) { + sessionId := "session123" + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) + fm, err := NewFlagManager(flagsPath) if err != nil { t.Logf(err.Error()) } - // Create required mocks + flag_account_created, err := fm.GetFlag("flag_account_created") if err != nil { t.Logf(err.Error()) } - // Define session ID and mock data - sessionId := "session123" - notFoundErr := db.ErrNotFound{} - ctx := context.WithValue(context.Background(), "SessionId", sessionId) tests := []struct { name string @@ -111,47 +135,24 @@ func TestCreateAccount(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + mockAccountService := new(mocks.MockAccountService) - mockDataStore := new(mocks.MockUserDataStore) - mockCreateAccountService := new(mocks.MockAccountService) - - // Create a Handlers instance with the mock data store h := &Handlers{ - userdataStore: mockDataStore, - accountService: mockCreateAccountService, + userdataStore: store, + accountService: mockAccountService, flagManager: fm.parser, } - publicKey := tt.serverResponse.Result["publicKey"].(string) - data := map[utils.DataTyp]string{ - utils.DATA_TRACKING_ID: tt.serverResponse.Result["trackingId"].(string), - utils.DATA_PUBLIC_KEY: publicKey, - } - - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACCOUNT_CREATED).Return([]byte(""), notFoundErr) - mockCreateAccountService.On("CreateAccount").Return(tt.serverResponse, nil) - - for key, value := range data { - mockDataStore.On("WriteEntry", ctx, sessionId, key, []byte(value)).Return(nil) - } - publicKeyNormalized, err := common.NormalizeHex(publicKey) - if err != nil { - t.Fatal(err) - } - - mockDataStore.On("WriteEntry", ctx, publicKeyNormalized, utils.DATA_PUBLIC_KEY_REVERSE, []byte(sessionId)).Return(nil) + mockAccountService.On("CreateAccount").Return(tt.serverResponse, nil) // Call the method you want to test - res, err := h.CreateAccount(ctx, "create_account", []byte("some-input")) + res, err := h.CreateAccount(ctx, "create_account", []byte("")) // Assert that no errors occurred assert.NoError(t, err) // Assert that the account created flag has been set to the result assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") - - // Assert that expectations were met - mockDataStore.AssertExpectations(t) }) } } @@ -176,23 +177,28 @@ func TestWithPersister_PanicWhenAlreadySet(t *testing.T) { } func TestSaveFirstname(t *testing.T) { - // Create new mocks - mockStore := new(mocks.MockUserDataStore) - mockState := state.NewState(16) + sessionId := "session123" + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) + + fm, _ := NewFlagManager(flagsPath) - fm, err := NewFlagManager(flagsPath) + flag_allow_update, _ := fm.GetFlag("flag_allow_update") + + // Set the flag in the State + mockState := state.NewState(16) + mockState.SetFlag(flag_allow_update) // 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_TEMPORARY_VALUE, []byte(firstName)).Return(nil) + if err := store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(firstName)); err != nil { + t.Fatal(err) + } // Create the Handlers instance with the mock store h := &Handlers{ - userdataStore: mockStore, + userdataStore: store, flagManager: fm.parser, st: mockState, } @@ -204,28 +210,34 @@ func TestSaveFirstname(t *testing.T) { assert.NoError(t, err) assert.Equal(t, resource.Result{}, res) - // Assert all expectations were met - mockStore.AssertExpectations(t) + // Verify that the DATA_FIRST_NAME entry has been updated with the temporary value + storedFirstName, _ := store.ReadEntry(ctx, sessionId, utils.DATA_FIRST_NAME) + assert.Equal(t, firstName, string(storedFirstName)) } func TestSaveFamilyname(t *testing.T) { - // Create a new instance of UserDataStore - mockStore := new(mocks.MockUserDataStore) - mockState := state.NewState(16) + sessionId := "session123" + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) + + fm, _ := NewFlagManager(flagsPath) - fm, err := NewFlagManager(flagsPath) + flag_allow_update, _ := fm.GetFlag("flag_allow_update") + + // Set the flag in the State + mockState := state.NewState(16) + mockState.SetFlag(flag_allow_update) // 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_TEMPORARY_VALUE, []byte(familyName)).Return(nil) + if err := store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(familyName)); err != nil { + t.Fatal(err) + } // Create the Handlers instance with the mock store h := &Handlers{ - userdataStore: mockStore, + userdataStore: store, st: mockState, flagManager: fm.parser, } @@ -237,25 +249,213 @@ func TestSaveFamilyname(t *testing.T) { assert.NoError(t, err) assert.Equal(t, resource.Result{}, res) - // Assert all expectations were met - mockStore.AssertExpectations(t) + // Verify that the DATA_FAMILY_NAME entry has been updated with the temporary value + storedFamilyName, _ := store.ReadEntry(ctx, sessionId, utils.DATA_FAMILY_NAME) + assert.Equal(t, familyName, string(storedFamilyName)) +} + +func TestSaveYoB(t *testing.T) { + sessionId := "session123" + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) + + fm, _ := NewFlagManager(flagsPath) + + flag_allow_update, _ := fm.GetFlag("flag_allow_update") + + // Set the flag in the State + mockState := state.NewState(16) + mockState.SetFlag(flag_allow_update) + + // Define test data + yob := "1980" + + if err := store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(yob)); err != nil { + t.Fatal(err) + } + + // Create the Handlers instance with the mock store + h := &Handlers{ + userdataStore: store, + flagManager: fm.parser, + st: mockState, + } + + // Call the method + res, err := h.SaveYob(ctx, "save_yob", []byte(yob)) + + // Assert results + assert.NoError(t, err) + assert.Equal(t, resource.Result{}, res) + + // Verify that the DATA_YOB entry has been updated with the temporary value + storedYob, _ := store.ReadEntry(ctx, sessionId, utils.DATA_YOB) + assert.Equal(t, yob, string(storedYob)) +} + +func TestSaveLocation(t *testing.T) { + sessionId := "session123" + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) + + fm, _ := NewFlagManager(flagsPath) + + flag_allow_update, _ := fm.GetFlag("flag_allow_update") + + // Set the flag in the State + mockState := state.NewState(16) + mockState.SetFlag(flag_allow_update) + + // Define test data + location := "Kilifi" + + if err := store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(location)); err != nil { + t.Fatal(err) + } + + // Create the Handlers instance with the mock store + h := &Handlers{ + userdataStore: store, + flagManager: fm.parser, + st: mockState, + } + + // Call the method + res, err := h.SaveLocation(ctx, "save_location", []byte(location)) + + // Assert results + assert.NoError(t, err) + assert.Equal(t, resource.Result{}, res) + + // Verify that the DATA_LOCATION entry has been updated with the temporary value + storedLocation, _ := store.ReadEntry(ctx, sessionId, utils.DATA_LOCATION) + assert.Equal(t, location, string(storedLocation)) +} + +func TestSaveOfferings(t *testing.T) { + sessionId := "session123" + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) + + fm, _ := NewFlagManager(flagsPath) + + flag_allow_update, _ := fm.GetFlag("flag_allow_update") + + // Set the flag in the State + mockState := state.NewState(16) + mockState.SetFlag(flag_allow_update) + + // Define test data + offerings := "Bananas" + + if err := store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(offerings)); err != nil { + t.Fatal(err) + } + + // Create the Handlers instance with the mock store + h := &Handlers{ + userdataStore: store, + flagManager: fm.parser, + st: mockState, + } + + // Call the method + res, err := h.SaveOfferings(ctx, "save_offerings", []byte(offerings)) + + // Assert results + assert.NoError(t, err) + assert.Equal(t, resource.Result{}, res) + + // Verify that the DATA_OFFERINGS entry has been updated with the temporary value + storedOfferings, _ := store.ReadEntry(ctx, sessionId, utils.DATA_OFFERINGS) + assert.Equal(t, offerings, string(storedOfferings)) +} + +func TestSaveGender(t *testing.T) { + sessionId := "session123" + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) + + fm, _ := NewFlagManager(flagsPath) + + flag_allow_update, _ := fm.GetFlag("flag_allow_update") + + // Set the flag in the State + mockState := state.NewState(16) + mockState.SetFlag(flag_allow_update) + + // Define test cases + tests := []struct { + name string + input []byte + expectedGender string + executingSymbol string + }{ + { + name: "Valid Male Input", + input: []byte("1"), + expectedGender: "male", + executingSymbol: "set_male", + }, + { + name: "Valid Female Input", + input: []byte("2"), + expectedGender: "female", + executingSymbol: "set_female", + }, + { + name: "Valid Unspecified Input", + input: []byte("3"), + executingSymbol: "set_unspecified", + expectedGender: "unspecified", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(tt.expectedGender)); err != nil { + t.Fatal(err) + } + + mockState.ExecPath = append(mockState.ExecPath, tt.executingSymbol) + // Create the Handlers instance with the mock store + h := &Handlers{ + userdataStore: store, + st: mockState, + flagManager: fm.parser, + } + + // Call the method + res, err := h.SaveGender(ctx, "save_gender", tt.input) + + // Assert results + assert.NoError(t, err) + assert.Equal(t, resource.Result{}, res) + + // Verify that the DATA_GENDER entry has been updated with the temporary value + storedGender, _ := store.ReadEntry(ctx, sessionId, utils.DATA_GENDER) + assert.Equal(t, tt.expectedGender, string(storedGender)) + }) + } } func TestSaveTemporaryPin(t *testing.T) { + sessionId := "session123" + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) + fm, err := NewFlagManager(flagsPath) - mockStore := new(mocks.MockUserDataStore) if err != nil { log.Fatal(err) } + flag_incorrect_pin, _ := fm.parser.GetFlag("flag_incorrect_pin") // Create the Handlers instance with the mock flag manager h := &Handlers{ flagManager: fm.parser, - userdataStore: mockStore, + userdataStore: store, } - sessionId := "session123" - ctx := context.WithValue(context.Background(), "SessionId", sessionId) // Define test cases tests := []struct { @@ -281,10 +481,6 @@ func TestSaveTemporaryPin(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - - // Set up the expected behavior of the mock - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(tt.input)).Return(nil) - // Call the method res, err := h.SaveTemporaryPin(ctx, "save_pin", tt.input) @@ -293,205 +489,27 @@ func TestSaveTemporaryPin(t *testing.T) { } // Assert that the Result FlagSet has the required flags after language switch - assert.Equal(t, res, tt.expectedResult, "Flags should be equal to account created") - - }) - } -} - -func TestSaveYoB(t *testing.T) { - // Create new instances - mockStore := new(mocks.MockUserDataStore) - mockState := state.NewState(16) - - fm, err := NewFlagManager(flagsPath) - - // 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_TEMPORARY_VALUE, []byte(yob)).Return(nil) - - // Create the Handlers instance with the mock store - h := &Handlers{ - userdataStore: mockStore, - st: mockState, - flagManager: fm.parser, - } - - // 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) - mockState := state.NewState(16) - - fm, err := NewFlagManager(flagsPath) - - // 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_TEMPORARY_VALUE, []byte(yob)).Return(nil) - - // Create the Handlers instance with the mock store - h := &Handlers{ - userdataStore: mockStore, - st: mockState, - flagManager: fm.parser, - } - - // 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 TestSaveOfferings(t *testing.T) { - // Create a new instance of MockUserDataStore - mockStore := new(mocks.MockUserDataStore) - mockState := state.NewState(16) - - fm, err := NewFlagManager(flagsPath) - - // Define test data - sessionId := "session123" - offerings := "Bananas" - ctx := context.WithValue(context.Background(), "SessionId", sessionId) - - // Set up the expected behavior of the mock - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(offerings)).Return(nil) - - // Create the Handlers instance with the mock store - h := &Handlers{ - userdataStore: mockStore, - st: mockState, - flagManager: fm.parser, - } - - // Call the method - res, err := h.SaveOfferings(ctx, "save_offerings", []byte(offerings)) - - // 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 mock instances - mockStore := new(mocks.MockUserDataStore) - mockState := state.NewState(16) - - fm, _ := NewFlagManager(flagsPath) - - // 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 - executingSymbol string - }{ - { - name: "Valid Male Input", - input: []byte("1"), - expectedGender: "male", - executingSymbol: "set_male", - expectCall: true, - }, - { - name: "Valid Female Input", - input: []byte("2"), - expectedGender: "female", - executingSymbol: "set_female", - expectCall: true, - }, - { - name: "Valid Unspecified Input", - input: []byte("3"), - executingSymbol: "set_unspecified", - expectedGender: "unspecified", - expectCall: true, - }, - } - - 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_TEMPORARY_VALUE - mockStore.On("WriteEntry", ctx, sessionId, expectedKey, []byte(tt.expectedGender)).Return(nil) - } else { - mockStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(tt.expectedGender)).Return(nil) - } - mockState.ExecPath = append(mockState.ExecPath, tt.executingSymbol) - // Create the Handlers instance with the mock store - h := &Handlers{ - userdataStore: mockStore, - st: mockState, - flagManager: fm.parser, - } - - // Call the method - _, err := h.SaveGender(ctx, "save_gender", tt.input) - - // Assert no error - assert.NoError(t, err) - - // Verify expectations - if tt.expectCall { - mockStore.AssertCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(tt.expectedGender)) - } else { - mockStore.AssertNotCalled(t, "WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(tt.expectedGender)) - } + assert.Equal(t, res, tt.expectedResult, "Result should match expected result") }) } } 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) + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) // Define test cases tests := []struct { name string - mockPublicKey []byte + publicKey []byte mockErr error expectedContent string expectError bool }{ { name: "Saved public Key", - mockPublicKey: []byte("0xa8363"), + publicKey: []byte("0xa8363"), mockErr: nil, expectedContent: "0xa8363", expectError: false, @@ -500,39 +518,33 @@ func TestCheckIdentifier(t *testing.T) { 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) + err := store.WriteEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY, []byte(tt.publicKey)) + if err != nil { + t.Fatal(err) + } // Create the Handlers instance with the mock store h := &Handlers{ - userdataStore: mockStore, + userdataStore: store, } // 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 TestGetSender(t *testing.T) { - mockStore := new(mocks.MockUserDataStore) + sessionId := "session123" + ctx, _ := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) - // Define test data - sessionId := "254712345678" - ctx := context.WithValue(context.Background(), "SessionId", sessionId) - - // Create the Handlers instance with the mock store - h := &Handlers{ - userdataStore: mockStore, - } + // Create the Handlers instance + h := &Handlers{} // Call the method res, _ := h.GetSender(ctx, "get_sender", []byte("")) @@ -542,21 +554,27 @@ func TestGetSender(t *testing.T) { } func TestGetAmount(t *testing.T) { - mockDataStore := new(mocks.MockUserDataStore) + sessionId := "session123" + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) // Define test data - sessionId := "session123" - ctx := context.WithValue(context.Background(), "SessionId", sessionId) amount := "0.03" activeSym := "SRF" - // Set up the expected behavior of the mock - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM).Return([]byte(activeSym), nil) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_AMOUNT).Return([]byte(amount), nil) + err := store.WriteEntry(ctx, sessionId, utils.DATA_AMOUNT, []byte(amount)) + if err != nil { + t.Fatal(err) + } + + err = store.WriteEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM, []byte(activeSym)) + if err != nil { + t.Fatal(err) + } // Create the Handlers instance with the mock store h := &Handlers{ - userdataStore: mockDataStore, + userdataStore: store, } // Call the method @@ -566,31 +584,30 @@ func TestGetAmount(t *testing.T) { //Assert that the retrieved amount is what was set as the content assert.Equal(t, formattedAmount, res.Content) - } func TestGetRecipient(t *testing.T) { - mockStore := new(mocks.MockUserDataStore) - - // Define test data sessionId := "session123" - ctx := context.WithValue(context.Background(), "SessionId", sessionId) + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) + recepient := "0xcasgatweksalw1018221" - // Set up the expected behavior of the mock - mockStore.On("ReadEntry", ctx, sessionId, utils.DATA_RECIPIENT).Return([]byte(recepient), nil) + err := store.WriteEntry(ctx, sessionId, utils.DATA_RECIPIENT, []byte(recepient)) + if err != nil { + t.Fatal(err) + } // Create the Handlers instance with the mock store h := &Handlers{ - userdataStore: mockStore, + userdataStore: store, } // Call the method - res, _ := h.GetRecipient(ctx, "get_recipient", []byte("Getting recipient...")) + res, _ := h.GetRecipient(ctx, "get_recipient", []byte("")) //Assert that the retrieved recepient is what was set as the content assert.Equal(t, recepient, res.Content) - } func TestGetFlag(t *testing.T) { @@ -608,12 +625,11 @@ func TestGetFlag(t *testing.T) { } func TestSetLanguage(t *testing.T) { - // Create a new instance of the Flag Manager fm, err := NewFlagManager(flagsPath) - if err != nil { log.Fatal(err) } + // Define test cases tests := []struct { name string @@ -652,25 +668,24 @@ func TestSetLanguage(t *testing.T) { // Call the method res, err := h.SetLanguage(context.Background(), "set_language", nil) - if err != nil { t.Error(err) } // Assert that the Result FlagSet has the required flags after language switch assert.Equal(t, res, tt.expectedResult, "Result should match expected result") - }) } } + func TestResetAllowUpdate(t *testing.T) { fm, err := NewFlagManager(flagsPath) - - flag_allow_update, _ := fm.parser.GetFlag("flag_allow_update") - if err != nil { log.Fatal(err) } + + flag_allow_update, _ := fm.parser.GetFlag("flag_allow_update") + // Define test cases tests := []struct { name string @@ -688,7 +703,6 @@ func TestResetAllowUpdate(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - // Create the Handlers instance with the mock flag manager h := &Handlers{ flagManager: fm.parser, @@ -696,13 +710,12 @@ func TestResetAllowUpdate(t *testing.T) { // Call the method res, err := h.ResetAllowUpdate(context.Background(), "reset_allow update", tt.input) - if err != nil { t.Error(err) } + // Assert that the Result FlagSet has the required flags after language switch assert.Equal(t, res, tt.expectedResult, "Flags should be equal to account created") - }) } } @@ -740,25 +753,24 @@ func TestResetAccountAuthorized(t *testing.T) { // Call the method res, err := h.ResetAccountAuthorized(context.Background(), "reset_account_authorized", tt.input) - if err != nil { t.Error(err) } + // Assert that the Result FlagSet has the required flags after language switch assert.Equal(t, res, tt.expectedResult, "Result should contain flag(s) that have been reset") - }) } } func TestIncorrectPinReset(t *testing.T) { fm, err := NewFlagManager(flagsPath) - - flag_incorrect_pin, _ := fm.parser.GetFlag("flag_incorrect_pin") - if err != nil { log.Fatal(err) } + + flag_incorrect_pin, _ := fm.parser.GetFlag("flag_incorrect_pin") + // Define test cases tests := []struct { name string @@ -776,7 +788,6 @@ func TestIncorrectPinReset(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - // Create the Handlers instance with the mock flag manager h := &Handlers{ flagManager: fm.parser, @@ -784,25 +795,24 @@ func TestIncorrectPinReset(t *testing.T) { // Call the method res, err := h.ResetIncorrectPin(context.Background(), "reset_incorrect_pin", tt.input) - if err != nil { t.Error(err) } + // Assert that the Result FlagSet has the required flags after language switch assert.Equal(t, res, tt.expectedResult, "Result should contain flag(s) that have been reset") - }) } } func TestResetIncorrectYob(t *testing.T) { fm, err := NewFlagManager(flagsPath) - - flag_incorrect_date_format, _ := fm.parser.GetFlag("flag_incorrect_date_format") - if err != nil { log.Fatal(err) } + + flag_incorrect_date_format, _ := fm.parser.GetFlag("flag_incorrect_date_format") + // Define test cases tests := []struct { name string @@ -820,7 +830,6 @@ func TestResetIncorrectYob(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - // Create the Handlers instance with the mock flag manager h := &Handlers{ flagManager: fm.parser, @@ -828,43 +837,39 @@ func TestResetIncorrectYob(t *testing.T) { // Call the method res, err := h.ResetIncorrectYob(context.Background(), "reset_incorrect_yob", tt.input) - if err != nil { t.Error(err) } + // Assert that the Result FlagSet has the required flags after language switch assert.Equal(t, res, tt.expectedResult, "Result should contain flag(s) that have been reset") - }) } } func TestAuthorize(t *testing.T) { + sessionId := "session123" + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) fm, err := NewFlagManager(flagsPath) - if err != nil { t.Logf(err.Error()) } // Create required mocks - mockDataStore := new(mocks.MockUserDataStore) - mockCreateAccountService := new(mocks.MockAccountService) - //expectedResult := resource.Result{} + mockAccountService := new(mocks.MockAccountService) mockState := state.NewState(16) flag_incorrect_pin, _ := fm.GetFlag("flag_incorrect_pin") flag_account_authorized, _ := fm.GetFlag("flag_account_authorized") flag_allow_update, _ := fm.GetFlag("flag_allow_update") - //Assuming 1234 is the correct account pin + + // Set 1234 is the correct account pin accountPIN := "1234" - // Define session ID and mock data - sessionId := "session123" - typ := utils.DATA_ACCOUNT_PIN - h := &Handlers{ - userdataStore: mockDataStore, - accountService: mockCreateAccountService, + userdataStore: store, + accountService: mockAccountService, flagManager: fm.parser, st: mockState, } @@ -899,14 +904,13 @@ func TestAuthorize(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - // Create context with session ID ctx := context.WithValue(context.Background(), "SessionId", sessionId) - // Define expected interactions with the mock - mockDataStore.On("ReadEntry", ctx, sessionId, typ).Return([]byte(accountPIN), nil) - - // Create a Handlers instance with the mock data store + err = store.WriteEntry(ctx, sessionId, utils.DATA_ACCOUNT_PIN, []byte(accountPIN)) + if err != nil { + t.Fatal(err) + } // Call the method under test res, err := h.Authorize(ctx, "authorize", []byte(tt.input)) @@ -916,33 +920,25 @@ func TestAuthorize(t *testing.T) { //Assert that the account created flag has been set to the result assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") - - // Assert that expectations were met - mockDataStore.AssertExpectations(t) - }) } - } func TestVerifyYob(t *testing.T) { fm, err := NewFlagManager(flagsPath) - if err != nil { t.Logf(err.Error()) } sessionId := "session123" // Create required mocks - mockDataStore := new(mocks.MockUserDataStore) - mockCreateAccountService := new(mocks.MockAccountService) + mockAccountService := new(mocks.MockAccountService) mockState := state.NewState(16) flag_incorrect_date_format, _ := fm.parser.GetFlag("flag_incorrect_date_format") ctx := context.WithValue(context.Background(), "SessionId", sessionId) h := &Handlers{ - userdataStore: mockDataStore, - accountService: mockCreateAccountService, + accountService: mockAccountService, flagManager: fm.parser, st: mockState, } @@ -977,7 +973,6 @@ func TestVerifyYob(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - // Call the method under test res, err := h.VerifyYob(ctx, "verify_yob", []byte(tt.input)) @@ -986,37 +981,31 @@ func TestVerifyYob(t *testing.T) { //Assert that the account created flag has been set to the result assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") - - // Assert that expectations were met - mockDataStore.AssertExpectations(t) - }) } } func TestVerifyCreatePin(t *testing.T) { - fm, err := NewFlagManager(flagsPath) + sessionId := "session123" + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) + fm, err := NewFlagManager(flagsPath) if err != nil { t.Logf(err.Error()) } - sessionId := "session123" // Create required mocks - mockDataStore := new(mocks.MockUserDataStore) - mockCreateAccountService := new(mocks.MockAccountService) + mockAccountService := new(mocks.MockAccountService) mockState := state.NewState(16) flag_valid_pin, _ := fm.parser.GetFlag("flag_valid_pin") flag_pin_mismatch, _ := fm.parser.GetFlag("flag_pin_mismatch") flag_pin_set, _ := fm.parser.GetFlag("flag_pin_set") - ctx := context.WithValue(context.Background(), "SessionId", sessionId) - //Assuming this was the first set PIN to verify against - firstSetPin := "1234" h := &Handlers{ - userdataStore: mockDataStore, - accountService: mockCreateAccountService, + userdataStore: store, + accountService: mockAccountService, flagManager: fm.parser, st: mockState, } @@ -1043,16 +1032,12 @@ func TestVerifyCreatePin(t *testing.T) { }, } - typ := utils.DATA_TEMPORARY_VALUE - for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - - // Define expected interactions with the mock - mockDataStore.On("ReadEntry", ctx, sessionId, typ).Return([]byte(firstSetPin), nil) - - // Set up the expected behavior of the mock - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACCOUNT_PIN, []byte(firstSetPin)).Return(nil) + err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte("1234")) + if err != nil { + t.Fatal(err) + } // Call the method under test res, err := h.VerifyCreatePin(ctx, "verify_create_pin", []byte(tt.input)) @@ -1062,36 +1047,32 @@ func TestVerifyCreatePin(t *testing.T) { //Assert that the account created flag has been set to the result assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") - - // Assert that expectations were met - mockDataStore.AssertExpectations(t) - }) } } func TestCheckAccountStatus(t *testing.T) { + sessionId := "session123" + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) + fm, err := NewFlagManager(flagsPath) if err != nil { t.Logf(err.Error()) } - sessionId := "session123" flag_account_success, _ := fm.GetFlag("flag_account_success") flag_account_pending, _ := fm.GetFlag("flag_account_pending") flag_api_error, _ := fm.GetFlag("flag_api_call_error") - ctx := context.WithValue(context.Background(), "SessionId", sessionId) - tests := []struct { name string - input []byte + publicKey []byte serverResponse *api.OKResponse - response *models.TrackStatusResponse expectedResult resource.Result }{ { - name: "Test when account is on the Sarafu network", - input: []byte("TrackingId1234"), + name: "Test when account is on the Sarafu network", + publicKey: []byte("TrackingId1234"), serverResponse: &api.OKResponse{ Ok: true, Description: "Account creation succeeded", @@ -1099,54 +1080,14 @@ func TestCheckAccountStatus(t *testing.T) { "active": true, }, }, - response: &models.TrackStatusResponse{ - Ok: true, - Result: struct { - Transaction struct { - CreatedAt time.Time "json:\"createdAt\"" - Status string "json:\"status\"" - TransferValue json.Number "json:\"transferValue\"" - TxHash string "json:\"txHash\"" - TxType string "json:\"txType\"" - } - }{ - Transaction: models.Transaction{ - CreatedAt: time.Now(), - Status: "SUCCESS", - TransferValue: json.Number("0.5"), - TxHash: "0x123abc456def", - TxType: "transfer", - }, - }, - }, expectedResult: resource.Result{ FlagSet: []uint32{flag_account_success}, FlagReset: []uint32{flag_api_error, flag_account_pending}, }, }, { - name: "Test when the account is not yet on the sarafu network", - input: []byte("TrackingId1234"), - response: &models.TrackStatusResponse{ - Ok: true, - Result: struct { - Transaction struct { - CreatedAt time.Time "json:\"createdAt\"" - Status string "json:\"status\"" - TransferValue json.Number "json:\"transferValue\"" - TxHash string "json:\"txHash\"" - TxType string "json:\"txType\"" - } - }{ - Transaction: models.Transaction{ - CreatedAt: time.Now(), - Status: "SUCCESS", - TransferValue: json.Number("0.5"), - TxHash: "0x123abc456def", - TxType: "transfer", - }, - }, - }, + name: "Test when the account is not yet on the sarafu network", + publicKey: []byte("TrackingId1234"), serverResponse: &api.OKResponse{ Ok: true, Description: "Account creation succeeded", @@ -1162,59 +1103,51 @@ func TestCheckAccountStatus(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - mockDataStore := new(mocks.MockUserDataStore) - mockCreateAccountService := new(mocks.MockAccountService) + mockAccountService := new(mocks.MockAccountService) h := &Handlers{ - userdataStore: mockDataStore, - accountService: mockCreateAccountService, + userdataStore: store, + accountService: mockAccountService, flagManager: fm.parser, } - status := tt.response.Result.Transaction.Status - // Define expected interactions with the mock - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return(tt.input, nil) + err = store.WriteEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY, []byte(tt.publicKey)) + if err != nil { + t.Fatal(err) + } - mockCreateAccountService.On("CheckAccountStatus", string(tt.input)).Return(tt.response, nil) - mockCreateAccountService.On("TrackAccountStatus", string(tt.input)).Return(tt.serverResponse, nil) - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACCOUNT_STATUS, []byte(status)).Return(nil).Maybe() + mockAccountService.On("TrackAccountStatus", string(tt.publicKey)).Return(tt.serverResponse, nil) // Call the method under test - res, _ := h.CheckAccountStatus(ctx, "check_account_status", tt.input) + res, _ := h.CheckAccountStatus(ctx, "check_account_status", []byte("")) // Assert that no errors occurred assert.NoError(t, err) //Assert that the account created flag has been set to the result assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") - - // Assert that expectations were met - mockDataStore.AssertExpectations(t) - }) } - } func TestTransactionReset(t *testing.T) { - fm, err := NewFlagManager(flagsPath) + sessionId := "session123" + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) + fm, err := NewFlagManager(flagsPath) if err != nil { t.Logf(err.Error()) } + flag_invalid_recipient, _ := fm.GetFlag("flag_invalid_recipient") flag_invalid_recipient_with_invite, _ := fm.GetFlag("flag_invalid_recipient_with_invite") - mockDataStore := new(mocks.MockUserDataStore) - mockCreateAccountService := new(mocks.MockAccountService) - - sessionId := "session123" - - ctx := context.WithValue(context.Background(), "SessionId", sessionId) + mockAccountService := new(mocks.MockAccountService) h := &Handlers{ - userdataStore: mockDataStore, - accountService: mockCreateAccountService, + userdataStore: store, + accountService: mockAccountService, flagManager: fm.parser, } tests := []struct { @@ -1233,9 +1166,6 @@ func TestTransactionReset(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_AMOUNT, []byte("")).Return(nil) - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_RECIPIENT, []byte("")).Return(nil) - // Call the method under test res, _ := h.TransactionReset(ctx, "transaction_reset", tt.input) @@ -1244,40 +1174,32 @@ func TestTransactionReset(t *testing.T) { //Assert that the account created flag has been set to the result assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") - - // Assert that expectations were met - mockDataStore.AssertExpectations(t) - }) } } -func TestResetInvalidAmount(t *testing.T) { +func TestResetTransactionAmount(t *testing.T) { sessionId := "session123" + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) fm, err := NewFlagManager(flagsPath) - if err != nil { t.Logf(err.Error()) } flag_invalid_amount, _ := fm.parser.GetFlag("flag_invalid_amount") - ctx := context.WithValue(context.Background(), "SessionId", sessionId) - - mockDataStore := new(mocks.MockUserDataStore) - mockCreateAccountService := new(mocks.MockAccountService) + mockAccountService := new(mocks.MockAccountService) h := &Handlers{ - userdataStore: mockDataStore, - accountService: mockCreateAccountService, + userdataStore: store, + accountService: mockAccountService, flagManager: fm.parser, } tests := []struct { name string - input []byte - status string expectedResult resource.Result }{ { @@ -1289,43 +1211,34 @@ func TestResetInvalidAmount(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_AMOUNT, []byte("")).Return(nil) - // Call the method under test - res, _ := h.ResetTransactionAmount(ctx, "transaction_reset_amount", tt.input) + res, _ := h.ResetTransactionAmount(ctx, "transaction_reset_amount", []byte("")) // Assert that no errors occurred assert.NoError(t, err) //Assert that the account created flag has been set to the result assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") - - // Assert that expectations were met - mockDataStore.AssertExpectations(t) - }) } - } func TestInitiateTransaction(t *testing.T) { sessionId := "254712345678" + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) fm, err := NewFlagManager(flagsPath) - if err != nil { t.Logf(err.Error()) } - account_authorized_flag, err := fm.parser.GetFlag("flag_account_authorized") + account_authorized_flag, _ := fm.parser.GetFlag("flag_account_authorized") - ctx := context.WithValue(context.Background(), "SessionId", sessionId) - - mockDataStore := new(mocks.MockUserDataStore) - mockCreateAccountService := new(mocks.MockAccountService) + mockAccountService := new(mocks.MockAccountService) h := &Handlers{ - userdataStore: mockDataStore, - accountService: mockCreateAccountService, + userdataStore: store, + accountService: mockAccountService, flagManager: fm.parser, } @@ -1351,10 +1264,18 @@ func TestInitiateTransaction(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - // Define expected interactions with the mock - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_AMOUNT).Return(tt.Amount, nil) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_RECIPIENT).Return(tt.Recipient, nil) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM).Return(tt.ActiveSym, nil) + err := store.WriteEntry(ctx, sessionId, utils.DATA_AMOUNT, []byte(tt.Amount)) + if err != nil { + t.Fatal(err) + } + err = store.WriteEntry(ctx, sessionId, utils.DATA_RECIPIENT, []byte(tt.Recipient)) + if err != nil { + t.Fatal(err) + } + err = store.WriteEntry(ctx, sessionId, utils.DATA_ACTIVE_SYM, []byte(tt.ActiveSym)) + if err != nil { + t.Fatal(err) + } // Call the method under test res, _ := h.InitiateTransaction(ctx, "transaction_reset_amount", tt.input) @@ -1364,31 +1285,25 @@ func TestInitiateTransaction(t *testing.T) { //Assert that the account created flag has been set to the result assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") - - // Assert that expectations were met - mockDataStore.AssertExpectations(t) }) } } func TestQuit(t *testing.T) { fm, err := NewFlagManager(flagsPath) - if err != nil { t.Logf(err.Error()) } flag_account_authorized, _ := fm.parser.GetFlag("flag_account_authorized") - mockDataStore := new(mocks.MockUserDataStore) - mockCreateAccountService := new(mocks.MockAccountService) + mockAccountService := new(mocks.MockAccountService) sessionId := "session123" ctx := context.WithValue(context.Background(), "SessionId", sessionId) h := &Handlers{ - userdataStore: mockDataStore, - accountService: mockCreateAccountService, + accountService: mockAccountService, flagManager: fm.parser, } tests := []struct { @@ -1417,13 +1332,10 @@ func TestQuit(t *testing.T) { //Assert that the account created flag has been set to the result assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") - - // Assert that expectations were met - mockDataStore.AssertExpectations(t) - }) } } + func TestIsValidPIN(t *testing.T) { tests := []struct { name string @@ -1479,21 +1391,22 @@ func TestIsValidPIN(t *testing.T) { func TestValidateAmount(t *testing.T) { fm, err := NewFlagManager(flagsPath) - if err != nil { t.Logf(err.Error()) } - flag_invalid_amount, _ := fm.parser.GetFlag("flag_invalid_amount") - mockDataStore := new(mocks.MockUserDataStore) - mockCreateAccountService := new(mocks.MockAccountService) sessionId := "session123" - ctx := context.WithValue(context.Background(), "SessionId", sessionId) + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) + + flag_invalid_amount, _ := fm.parser.GetFlag("flag_invalid_amount") + + mockAccountService := new(mocks.MockAccountService) h := &Handlers{ - userdataStore: mockDataStore, - accountService: mockCreateAccountService, + userdataStore: store, + accountService: mockAccountService, flagManager: fm.parser, } tests := []struct { @@ -1533,11 +1446,10 @@ func TestValidateAmount(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - // Mock behavior for active balance retrieval - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACTIVE_BAL).Return(tt.activeBal, nil) - - // Mock behavior for storing the amount (if valid) - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_AMOUNT, tt.input).Return(nil).Maybe() + err := store.WriteEntry(ctx, sessionId, utils.DATA_ACTIVE_BAL, []byte(tt.activeBal)) + if err != nil { + t.Fatal(err) + } // Call the method under test res, _ := h.ValidateAmount(ctx, "test_validate_amount", tt.input) @@ -1547,26 +1459,22 @@ func TestValidateAmount(t *testing.T) { // Assert the result matches the expected result assert.Equal(t, tt.expectedResult, res, "Expected result should match actual result") - - // Assert all expectations were met - mockDataStore.AssertExpectations(t) }) } } func TestValidateRecipient(t *testing.T) { fm, err := NewFlagManager(flagsPath) - - flag_invalid_recipient, _ := fm.parser.GetFlag("flag_invalid_recipient") - mockDataStore := new(mocks.MockUserDataStore) - - sessionId := "session123" - - ctx := context.WithValue(context.Background(), "SessionId", sessionId) - if err != nil { log.Fatal(err) } + + sessionId := "session123" + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) + + flag_invalid_recipient, _ := fm.parser.GetFlag("flag_invalid_recipient") + // Define test cases tests := []struct { name string @@ -1590,13 +1498,10 @@ func TestValidateRecipient(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_RECIPIENT, tt.input).Return(nil) - - // Create the Handlers instance with the mock flag manager + // Create the Handlers instance h := &Handlers{ flagManager: fm.parser, - userdataStore: mockDataStore, + userdataStore: store, } // Call the method @@ -1605,14 +1510,16 @@ func TestValidateRecipient(t *testing.T) { if err != nil { t.Error(err) } + // Assert that the Result FlagSet has the required flags after language switch assert.Equal(t, res, tt.expectedResult, "Result should contain flag(s) that have been reset") - }) } } func TestCheckBalance(t *testing.T) { + ctx, store := InitializeTestStore(t) + tests := []struct { name string sessionId string @@ -1624,7 +1531,7 @@ func TestCheckBalance(t *testing.T) { }{ { name: "User with active sym", - sessionId: "session456", + sessionId: "session123", publicKey: "0X98765432109", activeSym: "ETH", activeBal: "1.5", @@ -1635,18 +1542,22 @@ func TestCheckBalance(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - mockDataStore := new(mocks.MockUserDataStore) mockAccountService := new(mocks.MockAccountService) - ctx := context.WithValue(context.Background(), "SessionId", tt.sessionId) + ctx := context.WithValue(ctx, "SessionId", tt.sessionId) h := &Handlers{ - userdataStore: mockDataStore, + userdataStore: store, accountService: mockAccountService, } - // Mock for user with active sym - mockDataStore.On("ReadEntry", ctx, tt.sessionId, utils.DATA_ACTIVE_SYM).Return([]byte(tt.activeSym), nil) - mockDataStore.On("ReadEntry", ctx, tt.sessionId, utils.DATA_ACTIVE_BAL).Return([]byte(tt.activeBal), nil) + err := store.WriteEntry(ctx, tt.sessionId, utils.DATA_ACTIVE_SYM, []byte(tt.activeSym)) + if err != nil { + t.Fatal(err) + } + err = store.WriteEntry(ctx, tt.sessionId, utils.DATA_ACTIVE_BAL, []byte(tt.activeBal)) + if err != nil { + t.Fatal(err) + } res, err := h.CheckBalance(ctx, "check_balance", []byte("")) @@ -1657,23 +1568,21 @@ func TestCheckBalance(t *testing.T) { assert.Equal(t, tt.expectedResult, res, "Result should match expected output") } - mockDataStore.AssertExpectations(t) mockAccountService.AssertExpectations(t) }) } } func TestGetProfile(t *testing.T) { - sessionId := "session123" + ctx, store := InitializeTestStore(t) - mockDataStore := new(mocks.MockUserDataStore) - mockCreateAccountService := new(mocks.MockAccountService) + mockAccountService := new(mocks.MockAccountService) mockState := state.NewState(16) h := &Handlers{ - userdataStore: mockDataStore, - accountService: mockCreateAccountService, + userdataStore: store, + accountService: mockAccountService, st: mockState, } @@ -1697,7 +1606,7 @@ func TestGetProfile(t *testing.T) { }, }, { - name: "Test with with profile information in swa ", + name: "Test with with profile information in swa", keys: []utils.DataTyp{utils.DATA_FAMILY_NAME, utils.DATA_FIRST_NAME, utils.DATA_GENDER, utils.DATA_OFFERINGS, utils.DATA_LOCATION, utils.DATA_YOB}, profileInfo: []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976"}, languageCode: "swa", @@ -1723,22 +1632,21 @@ func TestGetProfile(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx := context.WithValue(context.Background(), "SessionId", sessionId) + ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "Language", lang.Language{ Code: tt.languageCode, }) for index, key := range tt.keys { - mockDataStore.On("ReadEntry", ctx, sessionId, key).Return([]byte(tt.profileInfo[index]), nil).Maybe() + err := store.WriteEntry(ctx, sessionId, key, []byte(tt.profileInfo[index])) + if err != nil { + t.Fatal(err) + } } res, _ := h.GetProfileInfo(ctx, "get_profile_info", []byte("")) - // Assert that expectations were met - mockDataStore.AssertExpectations(t) - //Assert that the result set to content is what was expected assert.Equal(t, res, tt.result, "Result should contain profile information served back to user") - }) } } @@ -1749,12 +1657,10 @@ func TestVerifyNewPin(t *testing.T) { fm, _ := NewFlagManager(flagsPath) flag_valid_pin, _ := fm.parser.GetFlag("flag_valid_pin") - mockDataStore := new(mocks.MockUserDataStore) - mockCreateAccountService := new(mocks.MockAccountService) + mockAccountService := new(mocks.MockAccountService) h := &Handlers{ - userdataStore: mockDataStore, flagManager: fm.parser, - accountService: mockCreateAccountService, + accountService: mockAccountService, } ctx := context.WithValue(context.Background(), "SessionId", sessionId) @@ -1777,44 +1683,32 @@ func TestVerifyNewPin(t *testing.T) { FlagReset: []uint32{flag_valid_pin}, }, }, - { - name: "Test with invalid pin", - input: []byte("12345"), - expectedResult: resource.Result{ - FlagReset: []uint32{flag_valid_pin}, - }, - }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - //Call the function under test res, _ := h.VerifyNewPin(ctx, "verify_new_pin", tt.input) - // Assert that expectations were met - mockDataStore.AssertExpectations(t) - //Assert that the result set to content is what was expected assert.Equal(t, res, tt.expectedResult, "Result should contain flags set according to user input") - }) } - } func TestConfirmPin(t *testing.T) { sessionId := "session123" + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) + fm, _ := NewFlagManager(flagsPath) flag_pin_mismatch, _ := fm.parser.GetFlag("flag_pin_mismatch") - mockDataStore := new(mocks.MockUserDataStore) - mockCreateAccountService := new(mocks.MockAccountService) + mockAccountService := new(mocks.MockAccountService) h := &Handlers{ - userdataStore: mockDataStore, + userdataStore: store, flagManager: fm.parser, - accountService: mockCreateAccountService, + accountService: mockAccountService, } - ctx := context.WithValue(context.Background(), "SessionId", sessionId) tests := []struct { name string @@ -1834,16 +1728,14 @@ func TestConfirmPin(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Set up the expected behavior of the mock - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACCOUNT_PIN, []byte(tt.temporarypin)).Return(nil) - - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE).Return(tt.temporarypin, nil) + err := store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(tt.temporarypin)) + if err != nil { + t.Fatal(err) + } //Call the function under test res, _ := h.ConfirmPinChange(ctx, "confirm_pin_change", tt.temporarypin) - // Assert that expectations were met - mockDataStore.AssertExpectations(t) - //Assert that the result set to content is what was expected assert.Equal(t, res, tt.expectedResult, "Result should contain flags set according to user input") @@ -1861,7 +1753,14 @@ func TestFetchCustodialBalances(t *testing.T) { // Define test data sessionId := "session123" publicKey := "0X13242618721" - ctx := context.WithValue(context.Background(), "SessionId", sessionId) + + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) + + err = store.WriteEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY, []byte(publicKey)) + if err != nil { + t.Fatal(err) + } tests := []struct { name string @@ -1903,50 +1802,39 @@ func TestFetchCustodialBalances(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - - mockDataStore := new(mocks.MockUserDataStore) - mockCreateAccountService := new(mocks.MockAccountService) + mockAccountService := new(mocks.MockAccountService) mockState := state.NewState(16) - // Create the Handlers instance with the mock store h := &Handlers{ - userdataStore: mockDataStore, + userdataStore: store, flagManager: fm.parser, st: mockState, - accountService: mockCreateAccountService, + accountService: mockAccountService, } // Set up the expected behavior of the mock - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil) - mockCreateAccountService.On("CheckBalance", string(publicKey)).Return(tt.balanceResonse, nil) + mockAccountService.On("CheckBalance", string(publicKey)).Return(tt.balanceResonse, nil) // Call the method res, _ := h.FetchCustodialBalances(ctx, "fetch_custodial_balances", []byte("")) - // Assert that expectations were met - mockDataStore.AssertExpectations(t) - //Assert that the result set to content is what was expected - assert.Equal(t, res, tt.expectedResult, "Result should contain flags set according to user input") - + assert.Equal(t, res, tt.expectedResult, "Result should match expected result") }) } } func TestSetDefaultVoucher(t *testing.T) { + sessionId := "session123" + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) + fm, err := NewFlagManager(flagsPath) if err != nil { t.Logf(err.Error()) } - flag_no_active_voucher, err := fm.GetFlag("flag_no_active_voucher") - if err != nil { - t.Logf(err.Error()) - } - // Define session ID and mock data - sessionId := "session123" + publicKey := "0X13242618721" - notFoundErr := db.ErrNotFound{} - ctx := context.WithValue(context.Background(), "SessionId", sessionId) tests := []struct { name string @@ -1954,7 +1842,7 @@ func TestSetDefaultVoucher(t *testing.T) { expectedResult resource.Result }{ { - name: "Test set default voucher when no active voucher exists", + name: "Test set default voucher when no active voucher is set", vouchersResp: &models.VoucherHoldingResponse{ Ok: true, Description: "Vouchers fetched successfully", @@ -1971,77 +1859,55 @@ func TestSetDefaultVoucher(t *testing.T) { }, expectedResult: resource.Result{}, }, - { - name: "Test no vouchers available", - vouchersResp: &models.VoucherHoldingResponse{ - Ok: true, - Description: "No vouchers available", - Result: models.VoucherResult{ - Holdings: []dataserviceapi.TokenHoldings{}, - }, - }, - expectedResult: resource.Result{ - FlagSet: []uint32{flag_no_active_voucher}, - }, - }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - mockDataStore := new(mocks.MockUserDataStore) mockAccountService := new(mocks.MockAccountService) h := &Handlers{ - userdataStore: mockDataStore, + userdataStore: store, accountService: mockAccountService, flagManager: fm.parser, } - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM).Return([]byte(""), notFoundErr) - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil) + err := store.WriteEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY, []byte(publicKey)) + if err != nil { + t.Fatal(err) + } mockAccountService.On("FetchVouchers", string(publicKey)).Return(tt.vouchersResp, nil) - if len(tt.vouchersResp.Result.Holdings) > 0 { - firstVoucher := tt.vouchersResp.Result.Holdings[0] - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_SYM, []byte(firstVoucher.TokenSymbol)).Return(nil) - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_ACTIVE_BAL, []byte(firstVoucher.Balance)).Return(nil) - } - - res, err := h.SetDefaultVoucher(ctx, "set_default_voucher", []byte("some-input")) + res, err := h.SetDefaultVoucher(ctx, "set_default_voucher", []byte("")) assert.NoError(t, err) assert.Equal(t, res, tt.expectedResult, "Expected result should be equal to the actual result") - mockDataStore.AssertExpectations(t) mockAccountService.AssertExpectations(t) }) } } func TestCheckVouchers(t *testing.T) { - mockDataStore := new(mocks.MockUserDataStore) mockAccountService := new(mocks.MockAccountService) - sessionId := "session123" publicKey := "0X13242618721" - ctx := context.WithValue(context.Background(), "SessionId", sessionId) - db := memdb.NewMemDb() - err := db.Connect(ctx, "") - if err != nil { - t.Fatal(err) - } - spdb := storage.NewSubPrefixDb(db, []byte("vouchers")) + ctx, store := InitializeTestStore(t) + ctx = context.WithValue(ctx, "SessionId", sessionId) + spdb := InitializeTestSubPrefixDb(t, ctx) h := &Handlers{ - userdataStore: mockDataStore, + userdataStore: store, accountService: mockAccountService, prefixDb: spdb, } - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_PUBLIC_KEY).Return([]byte(publicKey), nil) + err := store.WriteEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY, []byte(publicKey)) + if err != nil { + t.Fatal(err) + } mockVouchersResponse := &models.VoucherHoldingResponse{} mockVouchersResponse.Result.Holdings = []dataserviceapi.TokenHoldings{ @@ -2065,7 +1931,6 @@ func TestCheckVouchers(t *testing.T) { // assert that the data is stored correctly assert.Equal(t, expectedSym, voucherData) - mockDataStore.AssertExpectations(t) mockAccountService.AssertExpectations(t) } @@ -2073,12 +1938,7 @@ func TestGetVoucherList(t *testing.T) { sessionId := "session123" ctx := context.WithValue(context.Background(), "SessionId", sessionId) - db := memdb.NewMemDb() - err := db.Connect(ctx, "") - if err != nil { - t.Fatal(err) - } - spdb := storage.NewSubPrefixDb(db, []byte("vouchers")) + spdb := InitializeTestSubPrefixDb(t, ctx) h := &Handlers{ prefixDb: spdb, @@ -2087,7 +1947,7 @@ func TestGetVoucherList(t *testing.T) { expectedSym := []byte("1:SRF\n2:MILO") // Put voucher sym data from the store - err = spdb.Put(ctx, []byte("sym"), expectedSym) + err := spdb.Put(ctx, []byte("sym"), expectedSym) if err != nil { t.Fatal(err) } @@ -2103,20 +1963,15 @@ func TestViewVoucher(t *testing.T) { if err != nil { t.Logf(err.Error()) } - mockDataStore := new(mocks.MockUserDataStore) - + ctx, store := InitializeTestStore(t) sessionId := "session123" - ctx := context.WithValue(context.Background(), "SessionId", sessionId) - db := memdb.NewMemDb() - err = db.Connect(ctx, "") - if err != nil { - t.Fatal(err) - } - spdb := storage.NewSubPrefixDb(db, []byte("vouchers")) + ctx = context.WithValue(ctx, "SessionId", sessionId) + + spdb := InitializeTestSubPrefixDb(t, ctx) h := &Handlers{ - userdataStore: mockDataStore, + userdataStore: store, flagManager: fm.parser, prefixDb: spdb, } @@ -2137,23 +1992,20 @@ func TestViewVoucher(t *testing.T) { } } - // Set up expectations for mockDataStore - expectedData := fmt.Sprintf("%s,%s,%s,%s", "SRF", "100", "6", "0xd4c288865Ce") - - mockDataStore.On("WriteEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(expectedData)).Return(nil) - res, err := h.ViewVoucher(ctx, "view_voucher", []byte("1")) assert.NoError(t, err) - assert.Contains(t, res.Content, "SRF\n100") - - mockDataStore.AssertExpectations(t) + assert.Equal(t, res.Content, "SRF\n100") } func TestSetVoucher(t *testing.T) { - mockDataStore := new(mocks.MockUserDataStore) - + ctx, store := InitializeTestStore(t) sessionId := "session123" - ctx := context.WithValue(context.Background(), "SessionId", sessionId) + + ctx = context.WithValue(ctx, "SessionId", sessionId) + + h := &Handlers{ + userdataStore: store, + } // Define the temporary voucher data tempData := &dataserviceapi.TokenHoldings{ @@ -2163,33 +2015,16 @@ func TestSetVoucher(t *testing.T) { ContractAddress: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9", } - expectedData := fmt.Sprintf("%s,%s,%s,%s", "SRF", "200", "6", "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9") + expectedData := fmt.Sprintf("%s,%s,%s,%s", tempData.TokenSymbol, tempData.Balance, tempData.TokenDecimals, tempData.ContractAddress) - // Define the expected active entries - activeEntries := map[utils.DataTyp][]byte{ - utils.DATA_ACTIVE_SYM: []byte(tempData.TokenSymbol), - utils.DATA_ACTIVE_BAL: []byte(tempData.Balance), - utils.DATA_ACTIVE_DECIMAL: []byte(tempData.TokenDecimals), - utils.DATA_ACTIVE_ADDRESS: []byte(tempData.ContractAddress), + // store the expectedData + if err := store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(expectedData)); err != nil { + t.Fatal(err) } - // Mocking ReadEntry calls for temporary data retrieval - mockDataStore.On("ReadEntry", ctx, sessionId, utils.DATA_TEMPORARY_VALUE).Return([]byte(expectedData), nil) - - // Mocking WriteEntry calls for setting active data - for key, value := range activeEntries { - mockDataStore.On("WriteEntry", ctx, sessionId, key, value).Return(nil) - } - - h := &Handlers{ - userdataStore: mockDataStore, - } - - res, err := h.SetVoucher(ctx, "someSym", []byte{}) + res, err := h.SetVoucher(ctx, "set_voucher", []byte{}) assert.NoError(t, err) assert.Equal(t, string(tempData.TokenSymbol), res.Content) - - mockDataStore.AssertExpectations(t) } From e29a24b376cff982367fe2c00470ee1af8eea5cd Mon Sep 17 00:00:00 2001 From: lash Date: Sat, 2 Nov 2024 15:46:46 +0000 Subject: [PATCH 210/289] Add missing models files --- common/hex.go | 13 +++++++++++++ internal/handlers/handlerservice.go | 1 + internal/handlers/ussd/menuhandler.go | 20 ++++++++++---------- internal/models/tokenresponse.go | 18 ++++++++++++++++++ internal/models/vouchersresponse.go | 14 ++++++++++++++ 5 files changed, 56 insertions(+), 10 deletions(-) create mode 100644 internal/models/tokenresponse.go create mode 100644 internal/models/vouchersresponse.go diff --git a/common/hex.go b/common/hex.go index f5aa7ed..971ecf1 100644 --- a/common/hex.go +++ b/common/hex.go @@ -2,6 +2,7 @@ package common import ( "encoding/hex" + "strings" ) func NormalizeHex(s string) (string, error) { @@ -16,3 +17,15 @@ func NormalizeHex(s string) (string, error) { } return hex.EncodeToString(r), nil } + +func IsSameHex(left string, right string) bool { + bl, err := NormalizeHex(left) + if err != nil { + return false + } + br, err := NormalizeHex(left) + if err != nil { + return false + } + return strings.Compare(bl, br) == 0 +} diff --git a/internal/handlers/handlerservice.go b/internal/handlers/handlerservice.go index 9afba13..7d8325c 100644 --- a/internal/handlers/handlerservice.go +++ b/internal/handlers/handlerservice.go @@ -10,6 +10,7 @@ import ( "git.defalsify.org/vise.git/resource" "git.grassecon.net/urdt/ussd/internal/handlers/ussd" + "git.grassecon.net/urdt/ussd/internal/utils" "git.grassecon.net/urdt/ussd/remote" ) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index dc77660..a7e9d88 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -233,11 +233,11 @@ func (h *Handlers) CheckPinMisMatch(ctx context.Context, sym string, input []byt return res, fmt.Errorf("missing session") } store := h.userdataStore - blockedNumber, err := store.ReadEntry(ctx, sessionId, utils.DATA_BLOCKED_NUMBER) + blockedNumber, err := store.ReadEntry(ctx, sessionId, common.DATA_BLOCKED_NUMBER) if err != nil { return res, err } - temporaryPin, err := store.ReadEntry(ctx, string(blockedNumber), utils.DATA_TEMPORARY_VALUE) + temporaryPin, err := store.ReadEntry(ctx, string(blockedNumber), common.DATA_TEMPORARY_VALUE) if err != nil { return res, err } @@ -307,12 +307,12 @@ func (h *Handlers) SaveOthersTemporaryPin(ctx context.Context, sym string, input return res, fmt.Errorf("missing session") } temporaryPin := string(input) - blockedNumber, err := store.ReadEntry(ctx, sessionId, utils.DATA_BLOCKED_NUMBER) + blockedNumber, err := store.ReadEntry(ctx, sessionId, common.DATA_BLOCKED_NUMBER) if err != nil { return res, err } - err = store.WriteEntry(ctx, string(blockedNumber), utils.DATA_TEMPORARY_VALUE, []byte(temporaryPin)) + err = store.WriteEntry(ctx, string(blockedNumber), common.DATA_TEMPORARY_VALUE, []byte(temporaryPin)) if err != nil { return res, err } @@ -841,15 +841,15 @@ func (h *Handlers) ResetOthersPin(ctx context.Context, sym string, input []byte) if !ok { return res, fmt.Errorf("missing session") } - blockedPhonenumber, err := store.ReadEntry(ctx, sessionId, utils.DATA_BLOCKED_NUMBER) + blockedPhonenumber, err := store.ReadEntry(ctx, sessionId, common.DATA_BLOCKED_NUMBER) if err != nil { return res, err } - temporaryPin, err := store.ReadEntry(ctx, string(blockedPhonenumber), utils.DATA_TEMPORARY_VALUE) + temporaryPin, err := store.ReadEntry(ctx, string(blockedPhonenumber), common.DATA_TEMPORARY_VALUE) if err != nil { return res, err } - err = store.WriteEntry(ctx, string(blockedPhonenumber), utils.DATA_ACCOUNT_PIN, []byte(temporaryPin)) + err = store.WriteEntry(ctx, string(blockedPhonenumber), common.DATA_ACCOUNT_PIN, []byte(temporaryPin)) if err != nil { return res, nil } @@ -874,7 +874,7 @@ func (h *Handlers) ValidateBlockedNumber(ctx context.Context, sym string, input return res, fmt.Errorf("missing session") } blockedNumber := string(input) - _, err = store.ReadEntry(ctx, blockedNumber, utils.DATA_PUBLIC_KEY) + _, err = store.ReadEntry(ctx, blockedNumber, common.DATA_PUBLIC_KEY) if !isValidPhoneNumber(blockedNumber) { res.FlagSet = append(res.FlagSet, flag_unregistered_number) return res, nil @@ -888,7 +888,7 @@ func (h *Handlers) ValidateBlockedNumber(ctx context.Context, sym string, input return res, err } } - err = store.WriteEntry(ctx, sessionId, utils.DATA_BLOCKED_NUMBER, []byte(blockedNumber)) + err = store.WriteEntry(ctx, sessionId, common.DATA_BLOCKED_NUMBER, []byte(blockedNumber)) if err != nil { return res, nil } @@ -1075,7 +1075,7 @@ func (h *Handlers) RetrieveBlockedNumber(ctx context.Context, sym string, input return res, fmt.Errorf("missing session") } store := h.userdataStore - blockedNumber, _ := store.ReadEntry(ctx, sessionId, utils.DATA_BLOCKED_NUMBER) + blockedNumber, _ := store.ReadEntry(ctx, sessionId, common.DATA_BLOCKED_NUMBER) res.Content = string(blockedNumber) diff --git a/internal/models/tokenresponse.go b/internal/models/tokenresponse.go new file mode 100644 index 0000000..d243d93 --- /dev/null +++ b/internal/models/tokenresponse.go @@ -0,0 +1,18 @@ +package models + +type ApiResponse struct { + OK bool `json:"ok"` + Description string `json:"description"` + Result Result `json:"result"` +} + +type Result struct { + Holdings []Holding `json:"holdings"` +} + +type Holding struct { + ContractAddress string `json:"contractAddress"` + TokenSymbol string `json:"tokenSymbol"` + TokenDecimals string `json:"tokenDecimals"` + Balance string `json:"balance"` +} diff --git a/internal/models/vouchersresponse.go b/internal/models/vouchersresponse.go new file mode 100644 index 0000000..09b085d --- /dev/null +++ b/internal/models/vouchersresponse.go @@ -0,0 +1,14 @@ +package models + +import dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" + +type VoucherHoldingResponse struct { + Ok bool `json:"ok"` + Description string `json:"description"` + Result VoucherResult `json:"result"` +} + +// VoucherResult holds the list of token holdings +type VoucherResult struct { + Holdings []dataserviceapi.TokenHoldings `json:"holdings"` +} From 14bc11f4bd87574526b453339e4b079967216b83 Mon Sep 17 00:00:00 2001 From: lash Date: Sat, 2 Nov 2024 16:38:29 +0000 Subject: [PATCH 211/289] Add transaction getter --- common/db.go | 2 +- common/vouchers.go | 9 +++++++++ remote/accountservice.go | 36 ++++++++++++++++++++++++++++++++++-- 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/common/db.go b/common/db.go index 58fd3a1..06d9607 100644 --- a/common/db.go +++ b/common/db.go @@ -30,7 +30,7 @@ const ( DATA_PUBLIC_KEY_REVERSE DATA_ACTIVE_DECIMAL DATA_ACTIVE_ADDRESS - + DATA_TRANSACTIONS ) func typToBytes(typ DataTyp) []byte { diff --git a/common/vouchers.go b/common/vouchers.go index 9ca6277..cd76060 100644 --- a/common/vouchers.go +++ b/common/vouchers.go @@ -37,6 +37,15 @@ func ProcessVouchers(holdings []dataserviceapi.TokenHoldings) VoucherMetadata { return data } +//func StoreVouchers(db storage.PrefixDb, data VoucherMetadata) { +// value, err := db.Put(ctx, []byte(key)) +// if err != nil { +// return nil, fmt.Errorf("failed to get %s: %v", key, err) +// } +// data[key] = string(value) +// } +//} + // GetVoucherData retrieves and matches voucher data func GetVoucherData(ctx context.Context, db storage.PrefixDb, input string) (*dataserviceapi.TokenHoldings, error) { keys := []string{"sym", "bal", "deci", "addr"} diff --git a/remote/accountservice.go b/remote/accountservice.go index bc6a448..d0d7e9b 100644 --- a/remote/accountservice.go +++ b/remote/accountservice.go @@ -22,6 +22,7 @@ type AccountServiceInterface interface { CreateAccount(ctx context.Context) (*models.AccountResult, error) TrackAccountStatus(ctx context.Context, publicKey string) (*models.TrackStatusResult, error) FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) + FetchTransactions(ctx context.Context, publicKey string) ([]dataserviceapi.Last10TxResponse, error) } type AccountService struct { @@ -100,13 +101,18 @@ func (as *AccountService) CreateAccount(ctx context.Context) (*models.AccountRes return &r, nil } -// FetchVouchers retrieves the token holdings for a given public key from the custodial holdings API endpoint +// FetchVouchers retrieves the token holdings for a given public key from the data indexer API endpoint // Parameters: // - publicKey: The public key associated with the account. func (as *AccountService) FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) { var r []dataserviceapi.TokenHoldings - req, err := http.NewRequest("GET", config.VoucherHoldingsURL, nil) + ep, err := url.JoinPath(config.VoucherHoldingsURL, publicKey) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", ep, nil) if err != nil { return nil, err } @@ -119,6 +125,32 @@ func (as *AccountService) FetchVouchers(ctx context.Context, publicKey string) ( return r, nil } + +// FetchTransactions retrieves the last 10 transactions for a given public key from the data indexer API endpoint +// Parameters: +// - publicKey: The public key associated with the account. +func (as *AccountService) FetchTransactions(ctx context.Context, publicKey string) ([]dataserviceapi.Last10TxResponse, error) { + var r []dataserviceapi.Last10TxResponse + + ep, err := url.JoinPath(config.VoucherTransfersURL, publicKey) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", ep, nil) + if err != nil { + return nil, err + } + + _, err = doDataRequest(ctx, req, r) + if err != nil { + return nil, err + } + + return r, nil +} + + func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { var okResponse api.OKResponse var errResponse api.ErrResponse From 3a8a5f40baa56612e8435387542bbd2fcf16368b Mon Sep 17 00:00:00 2001 From: lash Date: Sat, 2 Nov 2024 16:42:50 +0000 Subject: [PATCH 212/289] Add test service placeholders for fetchtransactions --- internal/testutil/mocks/servicemock.go | 5 +++++ internal/testutil/testservice/TestAccountService.go | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/internal/testutil/mocks/servicemock.go b/internal/testutil/mocks/servicemock.go index bec48fd..78ee2b0 100644 --- a/internal/testutil/mocks/servicemock.go +++ b/internal/testutil/mocks/servicemock.go @@ -33,3 +33,8 @@ func (m *MockAccountService) FetchVouchers(ctx context.Context, publicKey string args := m.Called(publicKey) return args.Get(0).([]dataserviceapi.TokenHoldings), args.Error(1) } + +func (m *MockAccountService) FetchTransactions(ctx context.Context, publicKey string) ([]dataserviceapi.Last10TxResponse, error) { + args := m.Called(publicKey) + return args.Get(0).([]dataserviceapi.Last10TxResponse), args.Error(1) +} diff --git a/internal/testutil/testservice/TestAccountService.go b/internal/testutil/testservice/TestAccountService.go index a9a3085..3c104bd 100644 --- a/internal/testutil/testservice/TestAccountService.go +++ b/internal/testutil/testservice/TestAccountService.go @@ -42,3 +42,7 @@ func (tas *TestAccountService) FetchVouchers(ctx context.Context, publicKey stri }, }, nil } + +func (tas *TestAccountService) FetchTransactions(ctx context.Context, publicKey string) ([]dataserviceapi.Last10TxResponse, error) { + return []dataserviceapi.Last10TxResponse{}, nil +} From 1d77ad98dc6e4d7be4a3f63561815c06d07039b2 Mon Sep 17 00:00:00 2001 From: lash Date: Sat, 2 Nov 2024 23:33:52 +0000 Subject: [PATCH 213/289] Expose subprefix db --- common/storage.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 common/storage.go diff --git a/common/storage.go b/common/storage.go new file mode 100644 index 0000000..62a8a06 --- /dev/null +++ b/common/storage.go @@ -0,0 +1,13 @@ +package common + +import ( + "git.defalsify.org/vise.git/db" +) + +func StoreToDb(store *UserDataStore, prefix []byte) db.Db { + innerStore := store.Db + if pfx != nil { + innerStore = NewSubPrefixDb(innerStore, pfx) + } + return innerStore +} From dae12ac4989e40f64a48930b5348288c85af8369 Mon Sep 17 00:00:00 2001 From: lash Date: Sat, 2 Nov 2024 23:41:08 +0000 Subject: [PATCH 214/289] Separate subprefix db export --- common/storage.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/common/storage.go b/common/storage.go index 62a8a06..145382d 100644 --- a/common/storage.go +++ b/common/storage.go @@ -2,12 +2,14 @@ package common import ( "git.defalsify.org/vise.git/db" + + "git.grassecon.net/urdt/ussd/internal/storage" ) -func StoreToDb(store *UserDataStore, prefix []byte) db.Db { - innerStore := store.Db - if pfx != nil { - innerStore = NewSubPrefixDb(innerStore, pfx) - } - return innerStore +func StoreToDb(store *UserDataStore) db.Db { + return store.Db +} + +func StoreToPrefixDb(store *UserDataStore, pfx []byte) storage.PrefixDb { + return storage.NewSubPrefixDb(store.Db, pfx) } From a237b615f2ee3148146883e9267ac3c4f77f35e7 Mon Sep 17 00:00:00 2001 From: lash Date: Sun, 3 Nov 2024 01:44:57 +0000 Subject: [PATCH 215/289] Export models package --- common/user_store.go | 1 + internal/handlers/ussd/menuhandler_test.go | 2 +- internal/testutil/mocks/servicemock.go | 2 +- internal/testutil/testservice/TestAccountService.go | 2 +- {internal/models => models}/accountresponse.go | 0 {internal/models => models}/balanceresponse.go | 0 {internal/models => models}/tokenresponse.go | 0 {internal/models => models}/trackstatusresponse.go | 0 {internal/models => models}/vouchersresponse.go | 0 remote/accountservice.go | 2 +- 10 files changed, 5 insertions(+), 4 deletions(-) rename {internal/models => models}/accountresponse.go (100%) rename {internal/models => models}/balanceresponse.go (100%) rename {internal/models => models}/tokenresponse.go (100%) rename {internal/models => models}/trackstatusresponse.go (100%) rename {internal/models => models}/vouchersresponse.go (100%) diff --git a/common/user_store.go b/common/user_store.go index 4b8409f..29796e2 100644 --- a/common/user_store.go +++ b/common/user_store.go @@ -25,6 +25,7 @@ func (store *UserDataStore) ReadEntry(ctx context.Context, sessionId string, typ } // WriteEntry adds an entry to the userdata store. +// BUG: this uses sessionId twice func (store *UserDataStore) WriteEntry(ctx context.Context, sessionId string, typ DataTyp, value []byte) error { store.SetPrefix(db.DATATYPE_USERDATA) store.SetSession(sessionId) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 86c905d..74e9f53 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -14,7 +14,7 @@ import ( "git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/state" - "git.grassecon.net/urdt/ussd/internal/models" + "git.grassecon.net/urdt/ussd/models" "git.grassecon.net/urdt/ussd/internal/testutil/mocks" "git.grassecon.net/urdt/ussd/internal/testutil/testservice" diff --git a/internal/testutil/mocks/servicemock.go b/internal/testutil/mocks/servicemock.go index 78ee2b0..a24e459 100644 --- a/internal/testutil/mocks/servicemock.go +++ b/internal/testutil/mocks/servicemock.go @@ -3,7 +3,7 @@ package mocks import ( "context" - "git.grassecon.net/urdt/ussd/internal/models" + "git.grassecon.net/urdt/ussd/models" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" "github.com/stretchr/testify/mock" ) diff --git a/internal/testutil/testservice/TestAccountService.go b/internal/testutil/testservice/TestAccountService.go index 3c104bd..21f7a63 100644 --- a/internal/testutil/testservice/TestAccountService.go +++ b/internal/testutil/testservice/TestAccountService.go @@ -4,7 +4,7 @@ import ( "context" "encoding/json" - "git.grassecon.net/urdt/ussd/internal/models" + "git.grassecon.net/urdt/ussd/models" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" ) diff --git a/internal/models/accountresponse.go b/models/accountresponse.go similarity index 100% rename from internal/models/accountresponse.go rename to models/accountresponse.go diff --git a/internal/models/balanceresponse.go b/models/balanceresponse.go similarity index 100% rename from internal/models/balanceresponse.go rename to models/balanceresponse.go diff --git a/internal/models/tokenresponse.go b/models/tokenresponse.go similarity index 100% rename from internal/models/tokenresponse.go rename to models/tokenresponse.go diff --git a/internal/models/trackstatusresponse.go b/models/trackstatusresponse.go similarity index 100% rename from internal/models/trackstatusresponse.go rename to models/trackstatusresponse.go diff --git a/internal/models/vouchersresponse.go b/models/vouchersresponse.go similarity index 100% rename from internal/models/vouchersresponse.go rename to models/vouchersresponse.go diff --git a/remote/accountservice.go b/remote/accountservice.go index d0d7e9b..402add5 100644 --- a/remote/accountservice.go +++ b/remote/accountservice.go @@ -11,7 +11,7 @@ import ( dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" "github.com/grassrootseconomics/eth-custodial/pkg/api" "git.grassecon.net/urdt/ussd/config" - "git.grassecon.net/urdt/ussd/internal/models" + "git.grassecon.net/urdt/ussd/models" ) var ( From 0506a8c452f1c5daab3383d4c3248a0b0780dbdf Mon Sep 17 00:00:00 2001 From: lash Date: Sun, 3 Nov 2024 14:34:26 +0000 Subject: [PATCH 216/289] Add voucherdata endpoint --- common/db.go | 6 ++++++ common/vouchers.go | 2 ++ config/config.go | 3 +++ models/vouchersresponse.go | 17 ++++++++++++----- remote/accountservice.go | 21 +++++++++++++++++++++ 5 files changed, 44 insertions(+), 5 deletions(-) diff --git a/common/db.go b/common/db.go index 06d9607..91891d9 100644 --- a/common/db.go +++ b/common/db.go @@ -2,6 +2,8 @@ package common import ( "encoding/binary" + + "git.defalsify.org/vise.git/logging" ) type DataTyp uint16 @@ -33,6 +35,10 @@ const ( DATA_TRANSACTIONS ) +var ( + logg = logging.NewVanilla().WithDomain("urdt-common") +) + func typToBytes(typ DataTyp) []byte { var b [2]byte binary.BigEndian.PutUint16(b[:], uint16(typ)) diff --git a/common/vouchers.go b/common/vouchers.go index cd76060..2fed043 100644 --- a/common/vouchers.go +++ b/common/vouchers.go @@ -84,6 +84,7 @@ func MatchVoucher(input, symbols, balances, decimals, addresses string) (symbol, decList := strings.Split(decimals, "\n") addrList := strings.Split(addresses, "\n") + logg.Tracef("found" , "symlist", symList, "syms", symbols, "input", input) for i, sym := range symList { parts := strings.SplitN(sym, ":", 2) @@ -136,6 +137,7 @@ func GetTemporaryVoucherData(ctx context.Context, store DataStore, sessionId str // UpdateVoucherData sets the active voucher data and clears the temporary voucher data in the DataStore. func UpdateVoucherData(ctx context.Context, store DataStore, sessionId string, data *dataserviceapi.TokenHoldings) error { + logg.TraceCtxf(ctx, "dtal", "data", data) // Active voucher data entries activeEntries := map[DataTyp][]byte{ DATA_ACTIVE_SYM: []byte(data.TokenSymbol), diff --git a/config/config.go b/config/config.go index a5c89a7..fbf518b 100644 --- a/config/config.go +++ b/config/config.go @@ -13,6 +13,7 @@ const ( trackPath = "/api/v2/account/status" voucherHoldingsPathPrefix = "/api/v1/holdings" voucherTransfersPathPrefix = "/api/v1/transfers/last10" + voucherDataPathPrefix = "/api/v1/token" ) var ( @@ -29,6 +30,7 @@ var ( TrackURL string VoucherHoldingsURL string VoucherTransfersURL string + VoucherDataURL string ) func setBase() error { @@ -62,6 +64,7 @@ func LoadConfig() error { TrackURL, _ = url.JoinPath(custodialURLBase, trackPath) VoucherHoldingsURL, _ = url.JoinPath(dataURLBase, voucherHoldingsPathPrefix) VoucherTransfersURL, _ = url.JoinPath(dataURLBase, voucherTransfersPathPrefix) + VoucherDataURL, _ = url.JoinPath(dataURLBase, voucherDataPathPrefix) return nil } diff --git a/models/vouchersresponse.go b/models/vouchersresponse.go index 09b085d..8cf3ec6 100644 --- a/models/vouchersresponse.go +++ b/models/vouchersresponse.go @@ -2,13 +2,20 @@ package models import dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" -type VoucherHoldingResponse struct { - Ok bool `json:"ok"` - Description string `json:"description"` - Result VoucherResult `json:"result"` -} +//type VoucherHoldingResponse struct { +// Ok bool `json:"ok"` +// Description string `json:"description"` +// Result VoucherResult `json:"result"` +//} // VoucherResult holds the list of token holdings type VoucherResult struct { Holdings []dataserviceapi.TokenHoldings `json:"holdings"` } + +type VoucherDataResult struct { + TokenName string `json:"tokenName"` + TokenSymbol string `json:"tokenSymbol"` + TokenDecimals string `json:"tokenDecimals"` + SinkAddress string `json:"sinkAddress"` +} diff --git a/remote/accountservice.go b/remote/accountservice.go index 402add5..73052f6 100644 --- a/remote/accountservice.go +++ b/remote/accountservice.go @@ -23,6 +23,7 @@ type AccountServiceInterface interface { TrackAccountStatus(ctx context.Context, publicKey string) (*models.TrackStatusResult, error) FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) FetchTransactions(ctx context.Context, publicKey string) ([]dataserviceapi.Last10TxResponse, error) + VoucherData(ctx context.Context, address string) (*models.VoucherDataResult, error) } type AccountService struct { @@ -151,6 +152,26 @@ func (as *AccountService) FetchTransactions(ctx context.Context, publicKey strin } +// VoucherData retrieves voucher metadata from the data indexer API endpoint. +// Parameters: +// - address: The voucher address. +func (as *AccountService) VoucherData(ctx context.Context, address string) (*models.VoucherDataResult, error) { + var voucherDataResult models.VoucherDataResult + + ep, err := url.JoinPath(config.VoucherDataURL, address) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", ep, nil) + if err != nil { + return nil, err + } + + _, err = doCustodialRequest(ctx, req, &voucherDataResult) + return &voucherDataResult, err +} + func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { var okResponse api.OKResponse var errResponse api.ErrResponse From 7189235bee57b4fc703c5d7a2f43f0b4a660c397 Mon Sep 17 00:00:00 2001 From: lash Date: Sun, 3 Nov 2024 15:14:17 +0000 Subject: [PATCH 217/289] Remove unused data type --- common/db.go | 1 - 1 file changed, 1 deletion(-) diff --git a/common/db.go b/common/db.go index 91891d9..1992476 100644 --- a/common/db.go +++ b/common/db.go @@ -25,7 +25,6 @@ const ( DATA_RECIPIENT DATA_AMOUNT DATA_TEMPORARY_VALUE - DATA_VOUCHER_LIST DATA_ACTIVE_SYM DATA_ACTIVE_BAL DATA_BLOCKED_NUMBER From 2c30ccc4058f821f7996442963defced49e4146e Mon Sep 17 00:00:00 2001 From: lash Date: Mon, 4 Nov 2024 02:23:30 +0000 Subject: [PATCH 218/289] Add voucherdata call to test accountservices --- common/storage.go | 39 ++++++++++++++++++- internal/testutil/mocks/servicemock.go | 5 +++ .../testservice/TestAccountService.go | 4 ++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/common/storage.go b/common/storage.go index 145382d..dff4774 100644 --- a/common/storage.go +++ b/common/storage.go @@ -1,8 +1,12 @@ package common import ( - "git.defalsify.org/vise.git/db" + "context" + "errors" + "git.defalsify.org/vise.git/db" + "git.defalsify.org/vise.git/resource" + "git.defalsify.org/vise.git/persist" "git.grassecon.net/urdt/ussd/internal/storage" ) @@ -13,3 +17,36 @@ func StoreToDb(store *UserDataStore) db.Db { func StoreToPrefixDb(store *UserDataStore, pfx []byte) storage.PrefixDb { return storage.NewSubPrefixDb(store.Db, pfx) } + +type StorageServices interface { + GetPersister(ctx context.Context) (*persist.Persister, error) + GetUserdataDb(ctx context.Context) (db.Db, error) + GetResource(ctx context.Context) (resource.Resource, error) + EnsureDbDir() error +} + +type StorageService struct { + svc *storage.MenuStorageService +} + +func NewStorageService(dbDir string) *StorageService { + return &StorageService{ + svc: storage.NewMenuStorageService(dbDir, ""), + } +} + +func(ss *StorageService) GetPersister(ctx context.Context) (*persist.Persister, error) { + return ss.svc.GetPersister(ctx) +} + +func(ss *StorageService) GetUserdataDb(ctx context.Context) (db.Db, error) { + return ss.svc.GetUserdataDb(ctx) +} + +func(ss *StorageService) GetResource(ctx context.Context) (resource.Resource, error) { + return nil, errors.New("not implemented") +} + +func(ss *StorageService) EnsureDbDir() error { + return ss.svc.EnsureDbDir() +} diff --git a/internal/testutil/mocks/servicemock.go b/internal/testutil/mocks/servicemock.go index a24e459..76803ba 100644 --- a/internal/testutil/mocks/servicemock.go +++ b/internal/testutil/mocks/servicemock.go @@ -38,3 +38,8 @@ func (m *MockAccountService) FetchTransactions(ctx context.Context, publicKey st args := m.Called(publicKey) return args.Get(0).([]dataserviceapi.Last10TxResponse), args.Error(1) } + +func(m MockAccountService) VoucherData(ctx context.Context, address string) (*models.VoucherDataResult, error) { + args := m.Called(address) + return args.Get(0).(*models.VoucherDataResult), args.Error(1) +} diff --git a/internal/testutil/testservice/TestAccountService.go b/internal/testutil/testservice/TestAccountService.go index 21f7a63..8752d6f 100644 --- a/internal/testutil/testservice/TestAccountService.go +++ b/internal/testutil/testservice/TestAccountService.go @@ -46,3 +46,7 @@ func (tas *TestAccountService) FetchVouchers(ctx context.Context, publicKey stri func (tas *TestAccountService) FetchTransactions(ctx context.Context, publicKey string) ([]dataserviceapi.Last10TxResponse, error) { return []dataserviceapi.Last10TxResponse{}, nil } + +func(m TestAccountService) VoucherData(ctx context.Context, address string) (*models.VoucherDataResult, error) { + return &models.VoucherDataResult{}, nil +} From a9641fd70d85a653d0780c359e3cfaf617439501 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 4 Nov 2024 15:24:01 +0300 Subject: [PATCH 219/289] ensure swahili menu template --- services/registration/confirm_others_new_pin_swa | 1 + services/registration/enter_other_number_swa | 1 + services/registration/enter_others_new_pin_swa | 1 + services/registration/no_admin_privilege_swa | 1 + services/registration/others_pin_mismatch_swa | 1 + services/registration/pin_reset_mismatch_swa | 1 + services/registration/pin_reset_result_swa | 1 + services/registration/select_voucher_menu_swa | 1 + services/registration/voucher_details_menu_swa | 1 + 9 files changed, 9 insertions(+) create mode 100644 services/registration/confirm_others_new_pin_swa create mode 100644 services/registration/enter_other_number_swa create mode 100644 services/registration/enter_others_new_pin_swa create mode 100644 services/registration/no_admin_privilege_swa create mode 100644 services/registration/others_pin_mismatch_swa create mode 100644 services/registration/pin_reset_mismatch_swa create mode 100644 services/registration/pin_reset_result_swa create mode 100644 services/registration/select_voucher_menu_swa create mode 100644 services/registration/voucher_details_menu_swa diff --git a/services/registration/confirm_others_new_pin_swa b/services/registration/confirm_others_new_pin_swa new file mode 100644 index 0000000..f0b09c8 --- /dev/null +++ b/services/registration/confirm_others_new_pin_swa @@ -0,0 +1 @@ +Tafadhali thibitisha PIN mpya ya: {{.retrieve_blocked_number}} \ No newline at end of file diff --git a/services/registration/enter_other_number_swa b/services/registration/enter_other_number_swa new file mode 100644 index 0000000..214fc4a --- /dev/null +++ b/services/registration/enter_other_number_swa @@ -0,0 +1 @@ +Weka nambari ya simu ili kutuma ombi la kubadilisha nambari ya siri: \ No newline at end of file diff --git a/services/registration/enter_others_new_pin_swa b/services/registration/enter_others_new_pin_swa new file mode 100644 index 0000000..77ec2f3 --- /dev/null +++ b/services/registration/enter_others_new_pin_swa @@ -0,0 +1 @@ +Tafadhali weka PIN mpya ya: {{.retrieve_blocked_number}} \ No newline at end of file diff --git a/services/registration/no_admin_privilege_swa b/services/registration/no_admin_privilege_swa new file mode 100644 index 0000000..6c6d3dc --- /dev/null +++ b/services/registration/no_admin_privilege_swa @@ -0,0 +1 @@ +Huna mapendeleo ya kufanya kitendo hiki \ No newline at end of file diff --git a/services/registration/others_pin_mismatch_swa b/services/registration/others_pin_mismatch_swa new file mode 100644 index 0000000..5787790 --- /dev/null +++ b/services/registration/others_pin_mismatch_swa @@ -0,0 +1 @@ +PIN uliyoweka hailingani.Jaribu tena. \ No newline at end of file diff --git a/services/registration/pin_reset_mismatch_swa b/services/registration/pin_reset_mismatch_swa new file mode 100644 index 0000000..5787790 --- /dev/null +++ b/services/registration/pin_reset_mismatch_swa @@ -0,0 +1 @@ +PIN uliyoweka hailingani.Jaribu tena. \ No newline at end of file diff --git a/services/registration/pin_reset_result_swa b/services/registration/pin_reset_result_swa new file mode 100644 index 0000000..30de04e --- /dev/null +++ b/services/registration/pin_reset_result_swa @@ -0,0 +1 @@ +Ombi la kuweka upya PIN ya {{.retrieve_blocked_number}} limefanikiwa \ No newline at end of file diff --git a/services/registration/select_voucher_menu_swa b/services/registration/select_voucher_menu_swa new file mode 100644 index 0000000..2cb4daf --- /dev/null +++ b/services/registration/select_voucher_menu_swa @@ -0,0 +1 @@ +Chagua Sarafu \ No newline at end of file diff --git a/services/registration/voucher_details_menu_swa b/services/registration/voucher_details_menu_swa new file mode 100644 index 0000000..e84661b --- /dev/null +++ b/services/registration/voucher_details_menu_swa @@ -0,0 +1 @@ +Maelezo ya Sarafu \ No newline at end of file From c77558689a5d2ee7a11e314dd2bca0c365b3f1b3 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 4 Nov 2024 15:24:22 +0300 Subject: [PATCH 220/289] ensure swahlili menu template --- services/registration/address_swa | 1 + 1 file changed, 1 insertion(+) create mode 100644 services/registration/address_swa diff --git a/services/registration/address_swa b/services/registration/address_swa new file mode 100644 index 0000000..3e7a55e --- /dev/null +++ b/services/registration/address_swa @@ -0,0 +1 @@ +Anwani:{{.check_identifier}} \ No newline at end of file From 2b865a365bd4dc5f33442619414e526ba0d00fe5 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 4 Nov 2024 15:24:51 +0300 Subject: [PATCH 221/289] add back option to view address --- services/registration/address.vis | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/registration/address.vis b/services/registration/address.vis index f3ba04a..dfc46d1 100644 --- a/services/registration/address.vis +++ b/services/registration/address.vis @@ -1,6 +1,8 @@ LOAD check_identifier 0 RELOAD check_identifier MAP check_identifier +MOUT back 0 MOUT quit 9 HALT +INCMP _ 0 INCMP quit 9 From 88b50c5dd77852b2cd88097973162e1090cc2e89 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Mon, 4 Nov 2024 15:52:03 +0300 Subject: [PATCH 222/289] Remove admin number defination in env example --- .env.example | 4 --- internal/handlers/ussd/menuhandler.go | 3 +-- internal/handlers/ussd/menuhandler_test.go | 31 +++++++++++----------- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/.env.example b/.env.example index 4d86f8b..ab370a7 100644 --- a/.env.example +++ b/.env.example @@ -16,7 +16,3 @@ CREATE_ACCOUNT_URL=http://localhost:5003/api/v2/account/create TRACK_STATUS_URL=https://custodial.sarafu.africa/api/track/ BALANCE_URL=https://custodial.sarafu.africa/api/account/status/ TRACK_URL=http://localhost:5003/api/v2/account/status - - -#numbers with privileges to reset others pin -ADMIN_NUMBERS=254051722XXX,255012221XXX \ No newline at end of file diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index a7e9d88..6c1917d 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -20,8 +20,8 @@ import ( "git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/state" "git.grassecon.net/urdt/ussd/common" - "git.grassecon.net/urdt/ussd/remote" "git.grassecon.net/urdt/ussd/internal/utils" + "git.grassecon.net/urdt/ussd/remote" "gopkg.in/leonelquinteros/gotext.v1" "git.grassecon.net/urdt/ussd/internal/storage" @@ -1390,7 +1390,6 @@ func (h *Handlers) SetVoucher(ctx context.Context, sym string, input []byte) (re return res, fmt.Errorf("missing session") } - // Get temporary data tempData, err := common.GetTemporaryVoucherData(ctx, h.userdataStore, sessionId) if err != nil { diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index 2f2e94b..f4c9f7c 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -12,10 +12,10 @@ import ( "git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/state" - "git.grassecon.net/urdt/ussd/models" "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/models" "git.grassecon.net/urdt/ussd/common" "github.com/alecthomas/assert/v2" @@ -122,7 +122,7 @@ func TestCreateAccount(t *testing.T) { name: "Test account creation success", serverResponse: &models.AccountResult{ TrackingId: "1234567890", - PublicKey: "0xD3adB33f", + PublicKey: "0xD3adB33f", }, expectedResult: resource.Result{ FlagSet: []uint32{flag_account_created}, @@ -176,7 +176,7 @@ func TestSaveFirstname(t *testing.T) { sessionId := "session123" ctx, store := InitializeTestStore(t) ctx = context.WithValue(ctx, "SessionId", sessionId) - + fm, _ := NewFlagManager(flagsPath) flag_allow_update, _ := fm.GetFlag("flag_allow_update") @@ -215,7 +215,7 @@ func TestSaveFamilyname(t *testing.T) { sessionId := "session123" ctx, store := InitializeTestStore(t) ctx = context.WithValue(ctx, "SessionId", sessionId) - + fm, _ := NewFlagManager(flagsPath) flag_allow_update, _ := fm.GetFlag("flag_allow_update") @@ -254,7 +254,7 @@ func TestSaveYoB(t *testing.T) { sessionId := "session123" ctx, store := InitializeTestStore(t) ctx = context.WithValue(ctx, "SessionId", sessionId) - + fm, _ := NewFlagManager(flagsPath) flag_allow_update, _ := fm.GetFlag("flag_allow_update") @@ -265,7 +265,7 @@ func TestSaveYoB(t *testing.T) { // Define test data yob := "1980" - + if err := store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(yob)); err != nil { t.Fatal(err) } @@ -293,7 +293,7 @@ func TestSaveLocation(t *testing.T) { sessionId := "session123" ctx, store := InitializeTestStore(t) ctx = context.WithValue(ctx, "SessionId", sessionId) - + fm, _ := NewFlagManager(flagsPath) flag_allow_update, _ := fm.GetFlag("flag_allow_update") @@ -304,7 +304,7 @@ func TestSaveLocation(t *testing.T) { // Define test data location := "Kilifi" - + if err := store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(location)); err != nil { t.Fatal(err) } @@ -332,7 +332,7 @@ func TestSaveOfferings(t *testing.T) { sessionId := "session123" ctx, store := InitializeTestStore(t) ctx = context.WithValue(ctx, "SessionId", sessionId) - + fm, _ := NewFlagManager(flagsPath) flag_allow_update, _ := fm.GetFlag("flag_allow_update") @@ -371,7 +371,7 @@ func TestSaveGender(t *testing.T) { sessionId := "session123" ctx, store := InitializeTestStore(t) ctx = context.WithValue(ctx, "SessionId", sessionId) - + fm, _ := NewFlagManager(flagsPath) flag_allow_update, _ := fm.GetFlag("flag_allow_update") @@ -1746,9 +1746,9 @@ func TestFetchCustodialBalances(t *testing.T) { } tests := []struct { - name string + name string balanceResponse *models.BalanceResult - expectedResult resource.Result + expectedResult resource.Result }{ { name: "Test when fetch custodial balances is not a success", @@ -1807,16 +1807,15 @@ func TestSetDefaultVoucher(t *testing.T) { expectedResult resource.Result }{ { - name: "Test no vouchers available", - vouchersResp: []dataserviceapi.TokenHoldings { - }, + name: "Test no vouchers available", + vouchersResp: []dataserviceapi.TokenHoldings{}, expectedResult: resource.Result{ FlagSet: []uint32{flag_no_active_voucher}, }, }, { name: "Test set default voucher when no active voucher is set", - vouchersResp: []dataserviceapi.TokenHoldings { + vouchersResp: []dataserviceapi.TokenHoldings{ dataserviceapi.TokenHoldings{ ContractAddress: "0x123", TokenSymbol: "TOKEN1", From da91eed9d4559e3866a931574b827798dd832fd3 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 4 Nov 2024 15:55:58 +0300 Subject: [PATCH 223/289] add retry menu option --- services/registration/retry_menu | 1 + services/registration/retry_menu_swa | 1 + 2 files changed, 2 insertions(+) create mode 100644 services/registration/retry_menu create mode 100644 services/registration/retry_menu_swa diff --git a/services/registration/retry_menu b/services/registration/retry_menu new file mode 100644 index 0000000..ffde86c --- /dev/null +++ b/services/registration/retry_menu @@ -0,0 +1 @@ +Retry \ No newline at end of file diff --git a/services/registration/retry_menu_swa b/services/registration/retry_menu_swa new file mode 100644 index 0000000..c43b419 --- /dev/null +++ b/services/registration/retry_menu_swa @@ -0,0 +1 @@ +Jaribu tena \ No newline at end of file From c46c31ea36fd14b61d0defe23e640185024dfda8 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 4 Nov 2024 16:06:33 +0300 Subject: [PATCH 224/289] ensure swahili translation --- services/registration/unregistered_number_swa | 1 + 1 file changed, 1 insertion(+) create mode 100644 services/registration/unregistered_number_swa diff --git a/services/registration/unregistered_number_swa b/services/registration/unregistered_number_swa new file mode 100644 index 0000000..19810cb --- /dev/null +++ b/services/registration/unregistered_number_swa @@ -0,0 +1 @@ +Nambari uliyoingiza haijasajiliwa na Sarafu au sio sahihi. \ No newline at end of file From 92ea3df4aa149118e1ecebe729cc48d944b2d2dc Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Mon, 4 Nov 2024 17:38:55 +0300 Subject: [PATCH 225/289] Removeearly return statement --- remote/accountservice.go | 1 - 1 file changed, 1 deletion(-) diff --git a/remote/accountservice.go b/remote/accountservice.go index 73052f6..2e19de1 100644 --- a/remote/accountservice.go +++ b/remote/accountservice.go @@ -202,7 +202,6 @@ func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKRespons if len(okResponse.Result) == 0 { return nil, errors.New("Empty api result") } - return &okResponse, nil v, err := json.Marshal(okResponse.Result) if err != nil { From 266d3d06c3c86ec631b10011ca4e193ea1f367fe Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Mon, 4 Nov 2024 17:56:25 +0300 Subject: [PATCH 226/289] Check the flag_no_active_voucher before proceeding --- internal/handlers/ussd/menuhandler.go | 3 ++- services/registration/no_voucher | 2 +- services/registration/no_voucher_swa | 2 +- services/registration/select_voucher.vis | 1 + 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 6c1917d..ca4af09 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -1254,7 +1254,8 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by // Fetch vouchers from the API using the public key vouchersResp, err := h.accountService.FetchVouchers(ctx, string(publicKey)) if err != nil { - return res, err + res.FlagSet = append(res.FlagSet, flag_no_active_voucher) + return res, nil } // Return if there is no voucher diff --git a/services/registration/no_voucher b/services/registration/no_voucher index 332f00e..6303197 100644 --- a/services/registration/no_voucher +++ b/services/registration/no_voucher @@ -1 +1 @@ -You need a voucher to send \ No newline at end of file +You need a voucher to proceed \ No newline at end of file diff --git a/services/registration/no_voucher_swa b/services/registration/no_voucher_swa index 66e8f26..7291650 100644 --- a/services/registration/no_voucher_swa +++ b/services/registration/no_voucher_swa @@ -1 +1 @@ -Unahitaji sarafu kutuma \ No newline at end of file +Unahitaji sarafu kuendelea \ No newline at end of file diff --git a/services/registration/select_voucher.vis b/services/registration/select_voucher.vis index 08aa434..058d791 100644 --- a/services/registration/select_voucher.vis +++ b/services/registration/select_voucher.vis @@ -1,3 +1,4 @@ +CATCH no_voucher flag_no_active_voucher 1 LOAD get_vouchers 0 MAP get_vouchers MOUT back 0 From 4e350aa25a6d22d4b0296d4bc22c77645f742159 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 5 Nov 2024 10:49:08 +0300 Subject: [PATCH 227/289] update test data file --- menutraversal_test/group_test.json | 6 +++--- menutraversal_test/test_setup.json | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/menutraversal_test/group_test.json b/menutraversal_test/group_test.json index a219a6c..449c42f 100644 --- a/menutraversal_test/group_test.json +++ b/menutraversal_test/group_test.json @@ -54,7 +54,7 @@ }, { "input": "1235", - "expectedContent": "Incorrect pin\n1:retry\n9:Quit" + "expectedContent": "Incorrect pin\n1:Retry\n9:Quit" }, { "input": "1", @@ -95,7 +95,7 @@ }, { "input": "1235", - "expectedContent": "Incorrect pin\n1:retry\n9:Quit" + "expectedContent": "Incorrect pin\n1:Retry\n9:Quit" }, { "input": "1", @@ -141,7 +141,7 @@ }, { "input": "1235", - "expectedContent": "Incorrect pin\n1:retry\n9:Quit" + "expectedContent": "Incorrect pin\n1:Retry\n9:Quit" }, { "input": "1", diff --git a/menutraversal_test/test_setup.json b/menutraversal_test/test_setup.json index 13166a4..3acb889 100644 --- a/menutraversal_test/test_setup.json +++ b/menutraversal_test/test_setup.json @@ -23,7 +23,7 @@ }, { "input": "1111", - "expectedContent": "The PIN is not a match. Try again\n1:retry\n9:Quit" + "expectedContent": "The PIN is not a match. Try again\n1:Retry\n9:Quit" }, { "input": "1", @@ -65,7 +65,7 @@ }, { "input": "000", - "expectedContent": "000 is not registered or invalid, please try again:\n1:retry\n9:Quit" + "expectedContent": "000 is not registered or invalid, please try again:\n1:Retry\n9:Quit" }, { "input": "1", @@ -77,7 +77,7 @@ }, { "input": "10000000", - "expectedContent": "Amount 10000000 is invalid, please try again:\n1:retry\n9:Quit" + "expectedContent": "Amount 10000000 is invalid, please try again:\n1:Retry\n9:Quit" }, { "input": "1", @@ -89,7 +89,7 @@ }, { "input": "1222", - "expectedContent": "Incorrect pin\n1:retry\n9:Quit" + "expectedContent": "Incorrect pin\n1:Retry\n9:Quit" }, { "input": "1", @@ -140,7 +140,7 @@ }, { "input": "6", - "expectedContent": "Address: {public_key}\n9:Quit" + "expectedContent": "Address: {public_key}\n0:Back\n9:Quit" }, { "input": "9", From 308f3327d065b50d60257046438474078d98fa3b Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 6 Nov 2024 17:48:50 +0300 Subject: [PATCH 228/289] use edit prefix on each profile edit information --- services/registration/edit_familyname_menu | 1 - services/registration/edit_familyname_menu_swa | 1 - services/registration/edit_name_menu | 1 - services/registration/edit_name_menu_swa | 1 - services/registration/enter_familyname | 1 - services/registration/enter_familyname.vis | 8 -------- services/registration/enter_familyname_swa | 1 - services/registration/enter_location | 1 - services/registration/enter_location.vis | 8 -------- services/registration/enter_location_swa | 1 - services/registration/enter_name | 1 - services/registration/enter_name.vis | 8 -------- services/registration/enter_name_swa | 1 - services/registration/enter_offerings | 1 - services/registration/enter_offerings.vis | 8 -------- services/registration/enter_offerings_swa | 1 - services/registration/enter_yob | 1 - services/registration/enter_yob.vis | 10 ---------- services/registration/enter_yob_swa | 1 - 19 files changed, 56 deletions(-) delete mode 100644 services/registration/edit_familyname_menu delete mode 100644 services/registration/edit_familyname_menu_swa delete mode 100644 services/registration/edit_name_menu delete mode 100644 services/registration/edit_name_menu_swa delete mode 100644 services/registration/enter_familyname delete mode 100644 services/registration/enter_familyname.vis delete mode 100644 services/registration/enter_familyname_swa delete mode 100644 services/registration/enter_location delete mode 100644 services/registration/enter_location.vis delete mode 100644 services/registration/enter_location_swa delete mode 100644 services/registration/enter_name delete mode 100644 services/registration/enter_name.vis delete mode 100644 services/registration/enter_name_swa delete mode 100644 services/registration/enter_offerings delete mode 100644 services/registration/enter_offerings.vis delete mode 100644 services/registration/enter_offerings_swa delete mode 100644 services/registration/enter_yob delete mode 100644 services/registration/enter_yob.vis delete mode 100644 services/registration/enter_yob_swa diff --git a/services/registration/edit_familyname_menu b/services/registration/edit_familyname_menu deleted file mode 100644 index 21a9033..0000000 --- a/services/registration/edit_familyname_menu +++ /dev/null @@ -1 +0,0 @@ -Edit family name \ No newline at end of file diff --git a/services/registration/edit_familyname_menu_swa b/services/registration/edit_familyname_menu_swa deleted file mode 100644 index 48a38b2..0000000 --- a/services/registration/edit_familyname_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Weka jina la familia \ No newline at end of file diff --git a/services/registration/edit_name_menu b/services/registration/edit_name_menu deleted file mode 100644 index c7383b7..0000000 --- a/services/registration/edit_name_menu +++ /dev/null @@ -1 +0,0 @@ -Edit name \ No newline at end of file diff --git a/services/registration/edit_name_menu_swa b/services/registration/edit_name_menu_swa deleted file mode 100644 index 9395f7c..0000000 --- a/services/registration/edit_name_menu_swa +++ /dev/null @@ -1 +0,0 @@ -Weka jina \ No newline at end of file diff --git a/services/registration/enter_familyname b/services/registration/enter_familyname deleted file mode 100644 index 889915a..0000000 --- a/services/registration/enter_familyname +++ /dev/null @@ -1 +0,0 @@ -Enter family name: \ No newline at end of file diff --git a/services/registration/enter_familyname.vis b/services/registration/enter_familyname.vis deleted file mode 100644 index 5db4c17..0000000 --- a/services/registration/enter_familyname.vis +++ /dev/null @@ -1,8 +0,0 @@ -CATCH incorrect_pin flag_incorrect_pin 1 -CATCH update_familyname flag_allow_update 1 -MOUT back 0 -HALT -LOAD save_familyname 0 -RELOAD save_familyname -INCMP _ 0 -INCMP pin_entry * diff --git a/services/registration/enter_familyname_swa b/services/registration/enter_familyname_swa deleted file mode 100644 index 82f64cd..0000000 --- a/services/registration/enter_familyname_swa +++ /dev/null @@ -1 +0,0 @@ -Weka jina la familia diff --git a/services/registration/enter_location b/services/registration/enter_location deleted file mode 100644 index 675b835..0000000 --- a/services/registration/enter_location +++ /dev/null @@ -1 +0,0 @@ -Enter your location: \ No newline at end of file diff --git a/services/registration/enter_location.vis b/services/registration/enter_location.vis deleted file mode 100644 index 8966872..0000000 --- a/services/registration/enter_location.vis +++ /dev/null @@ -1,8 +0,0 @@ -CATCH incorrect_pin flag_incorrect_pin 1 -CATCH update_location flag_allow_update 1 -MOUT back 0 -HALT -LOAD save_location 0 -RELOAD save_location -INCMP _ 0 -INCMP pin_entry * diff --git a/services/registration/enter_location_swa b/services/registration/enter_location_swa deleted file mode 100644 index 41682a2..0000000 --- a/services/registration/enter_location_swa +++ /dev/null @@ -1 +0,0 @@ -Weka eneo: \ No newline at end of file diff --git a/services/registration/enter_name b/services/registration/enter_name deleted file mode 100644 index c6851cf..0000000 --- a/services/registration/enter_name +++ /dev/null @@ -1 +0,0 @@ -Enter your first names: \ No newline at end of file diff --git a/services/registration/enter_name.vis b/services/registration/enter_name.vis deleted file mode 100644 index f853d0a..0000000 --- a/services/registration/enter_name.vis +++ /dev/null @@ -1,8 +0,0 @@ -CATCH incorrect_pin flag_incorrect_pin 1 -CATCH update_firstname flag_allow_update 1 -MOUT back 0 -HALT -LOAD save_firstname 0 -RELOAD save_firstname -INCMP _ 0 -INCMP pin_entry * diff --git a/services/registration/enter_name_swa b/services/registration/enter_name_swa deleted file mode 100644 index b600b90..0000000 --- a/services/registration/enter_name_swa +++ /dev/null @@ -1 +0,0 @@ -Weka majina yako ya kwanza: \ No newline at end of file diff --git a/services/registration/enter_offerings b/services/registration/enter_offerings deleted file mode 100644 index a9333ba..0000000 --- a/services/registration/enter_offerings +++ /dev/null @@ -1 +0,0 @@ -Enter the services or goods you offer: \ No newline at end of file diff --git a/services/registration/enter_offerings.vis b/services/registration/enter_offerings.vis deleted file mode 100644 index 5cc7977..0000000 --- a/services/registration/enter_offerings.vis +++ /dev/null @@ -1,8 +0,0 @@ -CATCH incorrect_pin flag_incorrect_pin 1 -CATCH update_offerings flag_allow_update 1 -LOAD save_offerings 0 -MOUT back 0 -HALT -RELOAD save_offerings -INCMP _ 0 -INCMP pin_entry * diff --git a/services/registration/enter_offerings_swa b/services/registration/enter_offerings_swa deleted file mode 100644 index f37e125..0000000 --- a/services/registration/enter_offerings_swa +++ /dev/null @@ -1 +0,0 @@ -Weka unachouza \ No newline at end of file diff --git a/services/registration/enter_yob b/services/registration/enter_yob deleted file mode 100644 index 54e039e..0000000 --- a/services/registration/enter_yob +++ /dev/null @@ -1 +0,0 @@ -Enter your year of birth \ No newline at end of file diff --git a/services/registration/enter_yob.vis b/services/registration/enter_yob.vis deleted file mode 100644 index c74aeed..0000000 --- a/services/registration/enter_yob.vis +++ /dev/null @@ -1,10 +0,0 @@ -CATCH incorrect_pin flag_incorrect_pin 1 -CATCH update_yob flag_allow_update 1 -MOUT back 0 -HALT -LOAD verify_yob 0 -CATCH incorrect_date_format flag_incorrect_date_format 1 -LOAD save_yob 0 -RELOAD save_yob -INCMP _ 0 -INCMP pin_entry * diff --git a/services/registration/enter_yob_swa b/services/registration/enter_yob_swa deleted file mode 100644 index 9bb272a..0000000 --- a/services/registration/enter_yob_swa +++ /dev/null @@ -1 +0,0 @@ -Weka mwaka wa kuzaliwa \ No newline at end of file From 29e1e912d79f2bdedb4be556570740f145fb6149 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Wed, 6 Nov 2024 17:52:22 +0300 Subject: [PATCH 229/289] use edit prefix on each profile edit node --- services/registration/edit_first_name.vis | 11 +++++++++++ services/registration/edit_first_name_menu_swa | 1 + services/registration/edit_location | 1 + services/registration/edit_location.vis | 10 ++++++++++ services/registration/edit_location_swa | 1 + services/registration/edit_offerings | 1 + services/registration/edit_offerings.vis | 10 ++++++++++ services/registration/edit_offerings_swa | 1 + services/registration/edit_profile.vis | 14 +++++++------- services/registration/edit_yob | 1 + services/registration/edit_yob.vis | 12 ++++++++++++ services/registration/edit_yob_swa | 1 + 12 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 services/registration/edit_first_name.vis create mode 100644 services/registration/edit_first_name_menu_swa create mode 100644 services/registration/edit_location create mode 100644 services/registration/edit_location.vis create mode 100644 services/registration/edit_location_swa create mode 100644 services/registration/edit_offerings create mode 100644 services/registration/edit_offerings.vis create mode 100644 services/registration/edit_offerings_swa create mode 100644 services/registration/edit_yob create mode 100644 services/registration/edit_yob.vis create mode 100644 services/registration/edit_yob_swa diff --git a/services/registration/edit_first_name.vis b/services/registration/edit_first_name.vis new file mode 100644 index 0000000..b8dab5a --- /dev/null +++ b/services/registration/edit_first_name.vis @@ -0,0 +1,11 @@ +CATCH incorrect_pin flag_incorrect_pin 1 +CATCH update_firstname flag_allow_update 1 +LOAD get_current_profile_info 0 +RELOAD get_current_profile_info +MAP get_current_profile_info +MOUT back 0 +HALT +LOAD save_firstname 0 +RELOAD save_firstname +INCMP _ 0 +INCMP pin_entry * diff --git a/services/registration/edit_first_name_menu_swa b/services/registration/edit_first_name_menu_swa new file mode 100644 index 0000000..9395f7c --- /dev/null +++ b/services/registration/edit_first_name_menu_swa @@ -0,0 +1 @@ +Weka jina \ No newline at end of file diff --git a/services/registration/edit_location b/services/registration/edit_location new file mode 100644 index 0000000..675b835 --- /dev/null +++ b/services/registration/edit_location @@ -0,0 +1 @@ +Enter your location: \ No newline at end of file diff --git a/services/registration/edit_location.vis b/services/registration/edit_location.vis new file mode 100644 index 0000000..eaf248a --- /dev/null +++ b/services/registration/edit_location.vis @@ -0,0 +1,10 @@ +CATCH incorrect_pin flag_incorrect_pin 1 +CATCH update_location flag_allow_update 1 +LOAD get_current_profile_info 0 +RELOAD get_current_profile_info +MOUT back 0 +HALT +LOAD save_location 0 +RELOAD save_location +INCMP _ 0 +INCMP pin_entry * diff --git a/services/registration/edit_location_swa b/services/registration/edit_location_swa new file mode 100644 index 0000000..41682a2 --- /dev/null +++ b/services/registration/edit_location_swa @@ -0,0 +1 @@ +Weka eneo: \ No newline at end of file diff --git a/services/registration/edit_offerings b/services/registration/edit_offerings new file mode 100644 index 0000000..a9333ba --- /dev/null +++ b/services/registration/edit_offerings @@ -0,0 +1 @@ +Enter the services or goods you offer: \ No newline at end of file diff --git a/services/registration/edit_offerings.vis b/services/registration/edit_offerings.vis new file mode 100644 index 0000000..dad3193 --- /dev/null +++ b/services/registration/edit_offerings.vis @@ -0,0 +1,10 @@ +CATCH incorrect_pin flag_incorrect_pin 1 +CATCH update_offerings flag_allow_update 1 +LOAD get_current_profile_info 0 +RELOAD get_current_profile_info +LOAD save_offerings 0 +MOUT back 0 +HALT +RELOAD save_offerings +INCMP _ 0 +INCMP pin_entry * diff --git a/services/registration/edit_offerings_swa b/services/registration/edit_offerings_swa new file mode 100644 index 0000000..f37e125 --- /dev/null +++ b/services/registration/edit_offerings_swa @@ -0,0 +1 @@ +Weka unachouza \ No newline at end of file diff --git a/services/registration/edit_profile.vis b/services/registration/edit_profile.vis index 277f330..af20e0f 100644 --- a/services/registration/edit_profile.vis +++ b/services/registration/edit_profile.vis @@ -2,8 +2,8 @@ LOAD reset_account_authorized 16 RELOAD reset_account_authorized LOAD reset_allow_update 0 RELOAD reset_allow_update -MOUT edit_name 1 -MOUT edit_familyname 2 +MOUT edit_first_name 1 +MOUT edit_family_name 2 MOUT edit_gender 3 MOUT edit_yob 4 MOUT edit_location 5 @@ -12,10 +12,10 @@ MOUT view 7 MOUT back 0 HALT INCMP my_account 0 -INCMP enter_name 1 -INCMP enter_familyname 2 +INCMP edit_first_name 1 +INCMP edit_family_name 2 INCMP select_gender 3 -INCMP enter_yob 4 -INCMP enter_location 5 -INCMP enter_offerings 6 +INCMP edit_yob 4 +INCMP edit_location 5 +INCMP edit_offerings 6 INCMP view_profile 7 diff --git a/services/registration/edit_yob b/services/registration/edit_yob new file mode 100644 index 0000000..54e039e --- /dev/null +++ b/services/registration/edit_yob @@ -0,0 +1 @@ +Enter your year of birth \ No newline at end of file diff --git a/services/registration/edit_yob.vis b/services/registration/edit_yob.vis new file mode 100644 index 0000000..3cb7bd0 --- /dev/null +++ b/services/registration/edit_yob.vis @@ -0,0 +1,12 @@ +CATCH incorrect_pin flag_incorrect_pin 1 +CATCH update_yob flag_allow_update 1 +LOAD get_current_profile_info 0 +RELOAD get_current_profile_info +MOUT back 0 +HALT +LOAD verify_yob 0 +CATCH incorrect_date_format flag_incorrect_date_format 1 +LOAD save_yob 0 +RELOAD save_yob +INCMP _ 0 +INCMP pin_entry * diff --git a/services/registration/edit_yob_swa b/services/registration/edit_yob_swa new file mode 100644 index 0000000..9bb272a --- /dev/null +++ b/services/registration/edit_yob_swa @@ -0,0 +1 @@ +Weka mwaka wa kuzaliwa \ No newline at end of file From ebdc7b200a572a6fef4ce9cbf13467554bf82dec Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 7 Nov 2024 09:16:49 +0300 Subject: [PATCH 230/289] register handler for getting current profile information --- internal/handlers/handlerservice.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/handlers/handlerservice.go b/internal/handlers/handlerservice.go index 7d8325c..7a1e912 100644 --- a/internal/handlers/handlerservice.go +++ b/internal/handlers/handlerservice.go @@ -115,6 +115,7 @@ func (ls *LocalHandlerService) GetHandler(accountService remote.AccountServiceIn ls.DbRs.AddLocalFunc("reset_unregistered_number", ussdHandlers.ResetUnregisteredNumber) ls.DbRs.AddLocalFunc("reset_others_pin", ussdHandlers.ResetOthersPin) ls.DbRs.AddLocalFunc("save_others_temporary_pin", ussdHandlers.SaveOthersTemporaryPin) + ls.DbRs.AddLocalFunc("get_current_profile_info", ussdHandlers.GetCurrentProfileInfo) return ussdHandlers, nil } From f66609bbaeb5a31e3574bcbcb0796e1cc7fabde2 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 7 Nov 2024 09:18:11 +0300 Subject: [PATCH 231/289] add helper for getting db key from string --- common/db.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/common/db.go b/common/db.go index 1992476..e90fd47 100644 --- a/common/db.go +++ b/common/db.go @@ -2,6 +2,7 @@ package common import ( "encoding/binary" + "errors" "git.defalsify.org/vise.git/logging" ) @@ -48,3 +49,23 @@ func PackKey(typ DataTyp, data []byte) []byte { v := typToBytes(typ) return append(v, data...) } + +func StringToDataTyp(str string) (DataTyp, error) { + switch str { + case "DATA_FIRST_NAME": + return DATA_FIRST_NAME, nil + case "DATA_FAMILY_NAME": + return DATA_FAMILY_NAME, nil + case "DATA_YOB": + return DATA_YOB, nil + case "DATA_LOCATION": + return DATA_LOCATION, nil + case "DATA_GENDER": + return DATA_GENDER, nil + case "DATA_OFFERINGS": + return DATA_OFFERINGS, nil + + default: + return 0, errors.New("invalid DataTyp string") + } +} From 3e258a35fa851a2c84fe9d4bfd998a94e7c8b2a7 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 7 Nov 2024 11:58:25 +0300 Subject: [PATCH 232/289] show currently set profile information --- services/registration/edit_family_name | 2 ++ services/registration/edit_family_name.vis | 10 ++++++++++ services/registration/edit_family_name_menu | 1 + services/registration/edit_family_name_menu_swa | 1 + services/registration/edit_family_name_swa | 2 ++ services/registration/edit_first_name | 2 ++ services/registration/edit_first_name_menu | 1 + services/registration/edit_first_name_swa | 2 ++ services/registration/edit_location | 1 + services/registration/edit_location_swa | 1 + services/registration/edit_offerings | 1 + services/registration/edit_offerings_swa | 1 + services/registration/edit_yob | 1 + services/registration/edit_yob.vis | 1 + services/registration/edit_yob_swa | 1 + services/registration/select_gender | 1 + services/registration/select_gender.vis | 6 ++---- 17 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 services/registration/edit_family_name create mode 100644 services/registration/edit_family_name.vis create mode 100644 services/registration/edit_family_name_menu create mode 100644 services/registration/edit_family_name_menu_swa create mode 100644 services/registration/edit_family_name_swa create mode 100644 services/registration/edit_first_name create mode 100644 services/registration/edit_first_name_menu create mode 100644 services/registration/edit_first_name_swa diff --git a/services/registration/edit_family_name b/services/registration/edit_family_name new file mode 100644 index 0000000..2170a7e --- /dev/null +++ b/services/registration/edit_family_name @@ -0,0 +1,2 @@ +Current familyname: {{.get_current_profile_info}} +Enter family name: \ No newline at end of file diff --git a/services/registration/edit_family_name.vis b/services/registration/edit_family_name.vis new file mode 100644 index 0000000..1d71939 --- /dev/null +++ b/services/registration/edit_family_name.vis @@ -0,0 +1,10 @@ +CATCH incorrect_pin flag_incorrect_pin 1 +CATCH update_familyname flag_allow_update 1 +LOAD get_current_profile_info 0 +RELOAD get_current_profile_info +MOUT back 0 +HALT +LOAD save_familyname 0 +RELOAD save_familyname +INCMP _ 0 +INCMP pin_entry * diff --git a/services/registration/edit_family_name_menu b/services/registration/edit_family_name_menu new file mode 100644 index 0000000..21a9033 --- /dev/null +++ b/services/registration/edit_family_name_menu @@ -0,0 +1 @@ +Edit family name \ No newline at end of file diff --git a/services/registration/edit_family_name_menu_swa b/services/registration/edit_family_name_menu_swa new file mode 100644 index 0000000..48a38b2 --- /dev/null +++ b/services/registration/edit_family_name_menu_swa @@ -0,0 +1 @@ +Weka jina la familia \ No newline at end of file diff --git a/services/registration/edit_family_name_swa b/services/registration/edit_family_name_swa new file mode 100644 index 0000000..a1a1cab --- /dev/null +++ b/services/registration/edit_family_name_swa @@ -0,0 +1,2 @@ +Jina la familia la sasa: {{.get_current_profile_info}} +Weka jina la familia \ No newline at end of file diff --git a/services/registration/edit_first_name b/services/registration/edit_first_name new file mode 100644 index 0000000..3d141ee --- /dev/null +++ b/services/registration/edit_first_name @@ -0,0 +1,2 @@ +Current name: {{.get_current_profile_info}} +Enter your first names: \ No newline at end of file diff --git a/services/registration/edit_first_name_menu b/services/registration/edit_first_name_menu new file mode 100644 index 0000000..c7383b7 --- /dev/null +++ b/services/registration/edit_first_name_menu @@ -0,0 +1 @@ +Edit name \ No newline at end of file diff --git a/services/registration/edit_first_name_swa b/services/registration/edit_first_name_swa new file mode 100644 index 0000000..3fdd986 --- /dev/null +++ b/services/registration/edit_first_name_swa @@ -0,0 +1,2 @@ +Jina la kwanza la sasa {{.get_current_profile_info}} +Weka majina yako ya kwanza: \ No newline at end of file diff --git a/services/registration/edit_location b/services/registration/edit_location index 675b835..4e11d1a 100644 --- a/services/registration/edit_location +++ b/services/registration/edit_location @@ -1 +1,2 @@ +Current location: {{.get_current_profile_info}} Enter your location: \ No newline at end of file diff --git a/services/registration/edit_location_swa b/services/registration/edit_location_swa index 41682a2..0a3476e 100644 --- a/services/registration/edit_location_swa +++ b/services/registration/edit_location_swa @@ -1 +1,2 @@ +Eneo la sasa {{.get_current_profile_info}} Weka eneo: \ No newline at end of file diff --git a/services/registration/edit_offerings b/services/registration/edit_offerings index a9333ba..5bb0e7f 100644 --- a/services/registration/edit_offerings +++ b/services/registration/edit_offerings @@ -1 +1,2 @@ +Current offerings: {{.get_current_profile_info}} Enter the services or goods you offer: \ No newline at end of file diff --git a/services/registration/edit_offerings_swa b/services/registration/edit_offerings_swa index f37e125..cd81497 100644 --- a/services/registration/edit_offerings_swa +++ b/services/registration/edit_offerings_swa @@ -1 +1,2 @@ +Unachouza kwa sasa: {{.get_current_profile_info}} Weka unachouza \ No newline at end of file diff --git a/services/registration/edit_yob b/services/registration/edit_yob index 54e039e..105812b 100644 --- a/services/registration/edit_yob +++ b/services/registration/edit_yob @@ -1 +1,2 @@ +Current year of birth: {{.get_current_profile_info}} Enter your year of birth \ No newline at end of file diff --git a/services/registration/edit_yob.vis b/services/registration/edit_yob.vis index 3cb7bd0..a260531 100644 --- a/services/registration/edit_yob.vis +++ b/services/registration/edit_yob.vis @@ -2,6 +2,7 @@ CATCH incorrect_pin flag_incorrect_pin 1 CATCH update_yob flag_allow_update 1 LOAD get_current_profile_info 0 RELOAD get_current_profile_info +MAP get_current_profile_info MOUT back 0 HALT LOAD verify_yob 0 diff --git a/services/registration/edit_yob_swa b/services/registration/edit_yob_swa index 9bb272a..e0b5708 100644 --- a/services/registration/edit_yob_swa +++ b/services/registration/edit_yob_swa @@ -1 +1,2 @@ +Mwaka wa sasa wa kuzaliwa {{.get_current_profile_info}} Weka mwaka wa kuzaliwa \ No newline at end of file diff --git a/services/registration/select_gender b/services/registration/select_gender index f8a6f47..22b9be9 100644 --- a/services/registration/select_gender +++ b/services/registration/select_gender @@ -1 +1,2 @@ +Current gender: {{.get_current_profile_info}} Select gender: \ No newline at end of file diff --git a/services/registration/select_gender.vis b/services/registration/select_gender.vis index 1082cef..c1a00f5 100644 --- a/services/registration/select_gender.vis +++ b/services/registration/select_gender.vis @@ -1,5 +1,7 @@ CATCH incorrect_pin flag_incorrect_pin 1 CATCH profile_update_success flag_allow_update 1 +LOAD get_current_profile_info 0 +RELOAD get_current_profile_info MOUT male 1 MOUT female 2 MOUT unspecified 3 @@ -9,7 +11,3 @@ INCMP _ 0 INCMP set_male 1 INCMP set_female 2 INCMP set_unspecified 3 - - - - From 4e170b25e23fa396d9317e9aebdd64ea23593b2d Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 7 Nov 2024 11:58:58 +0300 Subject: [PATCH 233/289] show currently set profile information --- services/registration/select_gender_swa | 1 + 1 file changed, 1 insertion(+) diff --git a/services/registration/select_gender_swa b/services/registration/select_gender_swa index 2b3a748..b077a0b 100644 --- a/services/registration/select_gender_swa +++ b/services/registration/select_gender_swa @@ -1 +1,2 @@ +Jinsia ya sasa {{.get_current_profile_info}} Chagua jinsia \ No newline at end of file From f3388aef31a122420aee22934c182f1b6c4b0302 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 7 Nov 2024 11:59:12 +0300 Subject: [PATCH 234/289] use _ for back --- services/registration/incorrect_date_format.vis | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/registration/incorrect_date_format.vis b/services/registration/incorrect_date_format.vis index e94db5d..f4a8a2b 100644 --- a/services/registration/incorrect_date_format.vis +++ b/services/registration/incorrect_date_format.vis @@ -2,5 +2,5 @@ LOAD reset_incorrect_date_format 8 MOUT retry 1 MOUT quit 9 HALT -INCMP enter_yob 1 +INCMP _ 1 INCMP quit 9 From cc36ddcb6de9eeaec9ffb530e972658b533b5818 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 7 Nov 2024 12:02:03 +0300 Subject: [PATCH 235/289] add handler for showing the currently set profile information --- internal/handlers/ussd/menuhandler.go | 89 +++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index ca4af09..db710d2 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -1153,6 +1153,95 @@ func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input [] return res, nil } +func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input []byte) (resource.Result, error) { + var res resource.Result + var profileInfo []byte + var err error + sessionId, ok := ctx.Value("SessionId").(string) + if !ok { + return res, fmt.Errorf("missing session") + } + sm, _ := h.st.Where() + parts := strings.SplitN(sm, "_", 2) + filename := parts[1] + dbKeyStr := "DATA_" + strings.ToUpper(filename) + dbKey, err := common.StringToDataTyp(dbKeyStr) + + if err != nil { + return res, err + } + store := h.userdataStore + + switch dbKey { + case common.DATA_FIRST_NAME: + profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_FIRST_NAME) + if err != nil { + if db.IsNotFound(err) { + res.Content = "-" + break + } + return res, err + } + res.Content = string(profileInfo) + case common.DATA_FAMILY_NAME: + profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_FAMILY_NAME) + if err != nil { + if db.IsNotFound(err) { + res.Content = "-" + break + } + return res, err + } + res.Content = string(profileInfo) + + case common.DATA_GENDER: + profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_GENDER) + if err != nil { + if db.IsNotFound(err) { + res.Content = "-" + break + } + return res, err + } + res.Content = string(profileInfo) + case common.DATA_YOB: + profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_YOB) + if err != nil { + if db.IsNotFound(err) { + res.Content = "-" + break + } + return res, err + } + res.Content = string(profileInfo) + + case common.DATA_LOCATION: + profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_LOCATION) + if err != nil { + if db.IsNotFound(err) { + res.Content = "-" + break + } + return res, err + } + res.Content = string(profileInfo) + case common.DATA_OFFERINGS: + profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_OFFERINGS) + if err != nil { + if db.IsNotFound(err) { + res.Content = "-" + break + } + return res, err + } + res.Content = string(profileInfo) + default: + break + } + + return res, nil +} + func (h *Handlers) GetProfileInfo(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result var defaultValue string From fc8915ea33a1dee0b0e3c4afc7cfa58dfee414e5 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 7 Nov 2024 16:35:58 +0300 Subject: [PATCH 236/289] add http logging --- remote/accountservice.go | 44 +++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/remote/accountservice.go b/remote/accountservice.go index 2e19de1..92fd9df 100644 --- a/remote/accountservice.go +++ b/remote/accountservice.go @@ -1,20 +1,26 @@ package remote import ( + "bytes" "context" "encoding/json" "errors" "io" + "log" "net/http" "net/url" + "os" - dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" - "github.com/grassrootseconomics/eth-custodial/pkg/api" "git.grassecon.net/urdt/ussd/config" "git.grassecon.net/urdt/ussd/models" + "github.com/grassrootseconomics/eth-custodial/pkg/api" + dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" ) var ( + DebugLogger = log.New(os.Stdout, "DEBUG: ", log.Ldate|log.Ltime|log.Lshortfile) + InfoLogger = log.New(os.Stdout, "INFO: ", log.Ldate|log.Ltime) + ErrorLogger = log.New(os.Stderr, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) ) type AccountServiceInterface interface { @@ -51,7 +57,7 @@ func (as *AccountService) TrackAccountStatus(ctx context.Context, publicKey stri return nil, err } - _, err = doCustodialRequest(ctx, req, &r) + _, err = doCustodialRequest(ctx, req, &r) if err != nil { return nil, err } @@ -79,7 +85,6 @@ func (as *AccountService) CheckBalance(ctx context.Context, publicKey string) (* return &balanceResult, err } - // 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. @@ -94,7 +99,7 @@ func (as *AccountService) CreateAccount(ctx context.Context) (*models.AccountRes return nil, err } - _, err = doCustodialRequest(ctx, req, &r) + _, err = doCustodialRequest(ctx, req, &r) if err != nil { return nil, err } @@ -118,7 +123,7 @@ func (as *AccountService) FetchVouchers(ctx context.Context, publicKey string) ( return nil, err } - _, err = doDataRequest(ctx, req, r) + _, err = doDataRequest(ctx, req, r) if err != nil { return nil, err } @@ -126,7 +131,6 @@ func (as *AccountService) FetchVouchers(ctx context.Context, publicKey string) ( return r, nil } - // FetchTransactions retrieves the last 10 transactions for a given public key from the data indexer API endpoint // Parameters: // - publicKey: The public key associated with the account. @@ -143,7 +147,7 @@ func (as *AccountService) FetchTransactions(ctx context.Context, publicKey strin return nil, err } - _, err = doDataRequest(ctx, req, r) + _, err = doDataRequest(ctx, req, r) if err != nil { return nil, err } @@ -151,7 +155,6 @@ func (as *AccountService) FetchTransactions(ctx context.Context, publicKey strin return r, nil } - // VoucherData retrieves voucher metadata from the data indexer API endpoint. // Parameters: // - address: The voucher address. @@ -173,7 +176,7 @@ func (as *AccountService) VoucherData(ctx context.Context, address string) (*mod } func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { - var okResponse api.OKResponse + var okResponse api.OKResponse var errResponse api.ErrResponse req.Header.Set("Content-Type", "application/json") @@ -184,6 +187,7 @@ func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKRespons } defer resp.Body.Close() + InfoLogger.Printf("Received response for %s: Status Code: %d | Content-Type: %s", req.URL, resp.StatusCode, resp.Header.Get("Content-Type")) body, err := io.ReadAll(resp.Body) if err != nil { return nil, err @@ -214,10 +218,30 @@ func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKRespons func doCustodialRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { req.Header.Set("X-GE-KEY", config.CustodialAPIKey) + logRequestDetails(req, config.CustodialAPIKey) return doRequest(ctx, req, rcpt) } func doDataRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { req.Header.Set("X-GE-KEY", config.DataAPIKey) + logRequestDetails(req, config.CustodialAPIKey) return doRequest(ctx, req, rcpt) } + +func logRequestDetails(req *http.Request, apiKey string) { + var bodyBytes []byte + contentType := req.Header.Get("Content-Type") + if req.Body != nil { + bodyBytes, err := io.ReadAll(req.Body) + if err != nil { + ErrorLogger.Printf("Error reading request body: %s", err) + return + } + req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) + } else { + bodyBytes = []byte("-") + } + + InfoLogger.Printf("URL: %s | Content-Type: %s | Method: %s| Request Body: %s", req.URL, contentType, req.Method, string(bodyBytes)) + +} From 6ac9ac29d835dfe32c3f65e423798cbd7df5195b Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 7 Nov 2024 16:41:08 +0300 Subject: [PATCH 237/289] add simple http logging --- remote/accountservice.go | 44 +++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/remote/accountservice.go b/remote/accountservice.go index 2e19de1..92fd9df 100644 --- a/remote/accountservice.go +++ b/remote/accountservice.go @@ -1,20 +1,26 @@ package remote import ( + "bytes" "context" "encoding/json" "errors" "io" + "log" "net/http" "net/url" + "os" - dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" - "github.com/grassrootseconomics/eth-custodial/pkg/api" "git.grassecon.net/urdt/ussd/config" "git.grassecon.net/urdt/ussd/models" + "github.com/grassrootseconomics/eth-custodial/pkg/api" + dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" ) var ( + DebugLogger = log.New(os.Stdout, "DEBUG: ", log.Ldate|log.Ltime|log.Lshortfile) + InfoLogger = log.New(os.Stdout, "INFO: ", log.Ldate|log.Ltime) + ErrorLogger = log.New(os.Stderr, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) ) type AccountServiceInterface interface { @@ -51,7 +57,7 @@ func (as *AccountService) TrackAccountStatus(ctx context.Context, publicKey stri return nil, err } - _, err = doCustodialRequest(ctx, req, &r) + _, err = doCustodialRequest(ctx, req, &r) if err != nil { return nil, err } @@ -79,7 +85,6 @@ func (as *AccountService) CheckBalance(ctx context.Context, publicKey string) (* return &balanceResult, err } - // 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. @@ -94,7 +99,7 @@ func (as *AccountService) CreateAccount(ctx context.Context) (*models.AccountRes return nil, err } - _, err = doCustodialRequest(ctx, req, &r) + _, err = doCustodialRequest(ctx, req, &r) if err != nil { return nil, err } @@ -118,7 +123,7 @@ func (as *AccountService) FetchVouchers(ctx context.Context, publicKey string) ( return nil, err } - _, err = doDataRequest(ctx, req, r) + _, err = doDataRequest(ctx, req, r) if err != nil { return nil, err } @@ -126,7 +131,6 @@ func (as *AccountService) FetchVouchers(ctx context.Context, publicKey string) ( return r, nil } - // FetchTransactions retrieves the last 10 transactions for a given public key from the data indexer API endpoint // Parameters: // - publicKey: The public key associated with the account. @@ -143,7 +147,7 @@ func (as *AccountService) FetchTransactions(ctx context.Context, publicKey strin return nil, err } - _, err = doDataRequest(ctx, req, r) + _, err = doDataRequest(ctx, req, r) if err != nil { return nil, err } @@ -151,7 +155,6 @@ func (as *AccountService) FetchTransactions(ctx context.Context, publicKey strin return r, nil } - // VoucherData retrieves voucher metadata from the data indexer API endpoint. // Parameters: // - address: The voucher address. @@ -173,7 +176,7 @@ func (as *AccountService) VoucherData(ctx context.Context, address string) (*mod } func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { - var okResponse api.OKResponse + var okResponse api.OKResponse var errResponse api.ErrResponse req.Header.Set("Content-Type", "application/json") @@ -184,6 +187,7 @@ func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKRespons } defer resp.Body.Close() + InfoLogger.Printf("Received response for %s: Status Code: %d | Content-Type: %s", req.URL, resp.StatusCode, resp.Header.Get("Content-Type")) body, err := io.ReadAll(resp.Body) if err != nil { return nil, err @@ -214,10 +218,30 @@ func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKRespons func doCustodialRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { req.Header.Set("X-GE-KEY", config.CustodialAPIKey) + logRequestDetails(req, config.CustodialAPIKey) return doRequest(ctx, req, rcpt) } func doDataRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { req.Header.Set("X-GE-KEY", config.DataAPIKey) + logRequestDetails(req, config.CustodialAPIKey) return doRequest(ctx, req, rcpt) } + +func logRequestDetails(req *http.Request, apiKey string) { + var bodyBytes []byte + contentType := req.Header.Get("Content-Type") + if req.Body != nil { + bodyBytes, err := io.ReadAll(req.Body) + if err != nil { + ErrorLogger.Printf("Error reading request body: %s", err) + return + } + req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) + } else { + bodyBytes = []byte("-") + } + + InfoLogger.Printf("URL: %s | Content-Type: %s | Method: %s| Request Body: %s", req.URL, contentType, req.Method, string(bodyBytes)) + +} From a11776e1b38c20092e4e8d9307993b51acf82cc4 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 7 Nov 2024 16:41:38 +0300 Subject: [PATCH 238/289] ignore .log files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ddccccf..b523c77 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ go.work* cmd/.state/ id_* *.gdbm +*.log From 9c972ffa6bb0faf851c4c6e607178e905e3937a9 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 7 Nov 2024 16:46:12 +0300 Subject: [PATCH 239/289] add specific log files per binary --- cmd/africastalking/main.go | 42 ++++++++++++++++++++++++++++++++++++++ cmd/async/main.go | 19 ++++++++++++++++- cmd/http/main.go | 18 ++++++++++++++++ cmd/main.go | 18 ++++++++++++++++ remote/accountservice.go | 22 +++++++++++--------- 5 files changed, 108 insertions(+), 11 deletions(-) diff --git a/cmd/africastalking/main.go b/cmd/africastalking/main.go index db66a2e..15a13ee 100644 --- a/cmd/africastalking/main.go +++ b/cmd/africastalking/main.go @@ -1,9 +1,13 @@ package main import ( + "bytes" "context" + "encoding/json" "flag" "fmt" + "io" + "log" "net/http" "os" "os/signal" @@ -27,10 +31,27 @@ import ( var ( logg = logging.NewVanilla() scriptDir = path.Join("services", "registration") + WarningLogger *log.Logger + InfoLogger *log.Logger + ErrorLogger *log.Logger ) func init() { initializers.LoadEnvVariables() + + logFile := "urdt-ussd-africastalking.log" + + file, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666) + if err != nil { + log.Fatal(err) + } + + InfoLogger = log.New(file, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile) + ErrorLogger = log.New(file, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) + + // Inject into remote package + remote.InfoLogger = InfoLogger + remote.ErrorLogger = ErrorLogger } type atRequestParser struct{} @@ -38,9 +59,30 @@ type atRequestParser struct{} func (arp *atRequestParser) GetSessionId(rq any) (string, error) { rqv, ok := rq.(*http.Request) if !ok { + ErrorLogger.Println("got an invalid request:", rq) return "", handlers.ErrInvalidRequest } + + // Capture body (if any) for logging + body, err := io.ReadAll(rqv.Body) + if err != nil { + ErrorLogger.Println("failed to read request body:", err) + return "", fmt.Errorf("failed to read request body: %v", err) + } + // Reset the body for further reading + rqv.Body = io.NopCloser(bytes.NewReader(body)) + + // Log the body as JSON + bodyLog := map[string]string{"body": string(body)} + logBytes, err := json.Marshal(bodyLog) + if err != nil { + ErrorLogger.Println("failed to marshal request body:", err) + } else { + InfoLogger.Println("Received request:", string(logBytes)) + } + if err := rqv.ParseForm(); err != nil { + ErrorLogger.Println("failed to parse form data: %v", err) return "", fmt.Errorf("failed to parse form data: %v", err) } diff --git a/cmd/async/main.go b/cmd/async/main.go index e4c94b0..0dd7c2c 100644 --- a/cmd/async/main.go +++ b/cmd/async/main.go @@ -4,6 +4,7 @@ import ( "context" "flag" "fmt" + "log" "os" "os/signal" "path" @@ -23,12 +24,28 @@ import ( var ( logg = logging.NewVanilla() scriptDir = path.Join("services", "registration") + WarningLogger *log.Logger + InfoLogger *log.Logger + ErrorLogger *log.Logger ) func init() { initializers.LoadEnvVariables() -} + logFile := "urdt-ussd-async.log" + + file, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666) + if err != nil { + log.Fatal(err) + } + + InfoLogger = log.New(file, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile) + ErrorLogger = log.New(file, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) + + // Inject into remote package + remote.InfoLogger = InfoLogger + remote.ErrorLogger = ErrorLogger +} type asyncRequestParser struct { sessionId string input []byte diff --git a/cmd/http/main.go b/cmd/http/main.go index 96e2688..ffb4109 100644 --- a/cmd/http/main.go +++ b/cmd/http/main.go @@ -4,6 +4,7 @@ import ( "context" "flag" "fmt" + "log" "net/http" "os" "os/signal" @@ -26,10 +27,27 @@ import ( var ( logg = logging.NewVanilla() scriptDir = path.Join("services", "registration") + WarningLogger *log.Logger + InfoLogger *log.Logger + ErrorLogger *log.Logger ) func init() { initializers.LoadEnvVariables() + + logFile := "urdt-ussd-http.log" + + file, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666) + if err != nil { + log.Fatal(err) + } + + InfoLogger = log.New(file, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile) + ErrorLogger = log.New(file, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) + + // Inject into remote package + remote.InfoLogger = InfoLogger + remote.ErrorLogger = ErrorLogger } func main() { diff --git a/cmd/main.go b/cmd/main.go index 9599eb7..a623cbe 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -4,6 +4,7 @@ import ( "context" "flag" "fmt" + "log" "os" "path" @@ -20,10 +21,27 @@ import ( var ( logg = logging.NewVanilla() scriptDir = path.Join("services", "registration") + WarningLogger *log.Logger + InfoLogger *log.Logger + ErrorLogger *log.Logger ) func init() { initializers.LoadEnvVariables() + + logFile := "urdt-ussd-cli.log" + + file, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666) + if err != nil { + log.Fatal(err) + } + + InfoLogger = log.New(file, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile) + ErrorLogger = log.New(file, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) + + // Inject into remote package + remote.InfoLogger = InfoLogger + remote.ErrorLogger = ErrorLogger } func main() { diff --git a/remote/accountservice.go b/remote/accountservice.go index 2e19de1..6e222e7 100644 --- a/remote/accountservice.go +++ b/remote/accountservice.go @@ -5,16 +5,19 @@ import ( "encoding/json" "errors" "io" + "log" "net/http" "net/url" - dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" - "github.com/grassrootseconomics/eth-custodial/pkg/api" "git.grassecon.net/urdt/ussd/config" "git.grassecon.net/urdt/ussd/models" + "github.com/grassrootseconomics/eth-custodial/pkg/api" + dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" ) var ( + InfoLogger *log.Logger + ErrorLogger *log.Logger ) type AccountServiceInterface interface { @@ -51,7 +54,7 @@ func (as *AccountService) TrackAccountStatus(ctx context.Context, publicKey stri return nil, err } - _, err = doCustodialRequest(ctx, req, &r) + _, err = doCustodialRequest(ctx, req, &r) if err != nil { return nil, err } @@ -79,7 +82,6 @@ func (as *AccountService) CheckBalance(ctx context.Context, publicKey string) (* return &balanceResult, err } - // 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. @@ -94,7 +96,7 @@ func (as *AccountService) CreateAccount(ctx context.Context) (*models.AccountRes return nil, err } - _, err = doCustodialRequest(ctx, req, &r) + _, err = doCustodialRequest(ctx, req, &r) if err != nil { return nil, err } @@ -118,7 +120,7 @@ func (as *AccountService) FetchVouchers(ctx context.Context, publicKey string) ( return nil, err } - _, err = doDataRequest(ctx, req, r) + _, err = doDataRequest(ctx, req, r) if err != nil { return nil, err } @@ -126,7 +128,6 @@ func (as *AccountService) FetchVouchers(ctx context.Context, publicKey string) ( return r, nil } - // FetchTransactions retrieves the last 10 transactions for a given public key from the data indexer API endpoint // Parameters: // - publicKey: The public key associated with the account. @@ -143,7 +144,7 @@ func (as *AccountService) FetchTransactions(ctx context.Context, publicKey strin return nil, err } - _, err = doDataRequest(ctx, req, r) + _, err = doDataRequest(ctx, req, r) if err != nil { return nil, err } @@ -151,7 +152,6 @@ func (as *AccountService) FetchTransactions(ctx context.Context, publicKey strin return r, nil } - // VoucherData retrieves voucher metadata from the data indexer API endpoint. // Parameters: // - address: The voucher address. @@ -173,9 +173,11 @@ func (as *AccountService) VoucherData(ctx context.Context, address string) (*mod } func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { - var okResponse api.OKResponse + var okResponse api.OKResponse var errResponse api.ErrResponse + InfoLogger.Printf("Outgoing request:", req.URL, req.Body) + req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { From 1bcbb2079e81243e00198002cf8ae4f08303d570 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 8 Nov 2024 00:17:02 +0300 Subject: [PATCH 240/289] Removed unused variable --- remote/accountservice.go | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/remote/accountservice.go b/remote/accountservice.go index ef0d4ae..ae1fab7 100644 --- a/remote/accountservice.go +++ b/remote/accountservice.go @@ -9,7 +9,6 @@ import ( "log" "net/http" "net/url" - "os" "git.grassecon.net/urdt/ussd/config" "git.grassecon.net/urdt/ussd/models" @@ -178,8 +177,6 @@ func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKRespons var okResponse api.OKResponse var errResponse api.ErrResponse - InfoLogger.Printf("Outgoing request:", req.URL, req.Body) - req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { @@ -219,17 +216,17 @@ func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKRespons func doCustodialRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { req.Header.Set("X-GE-KEY", config.CustodialAPIKey) - logRequestDetails(req, config.CustodialAPIKey) + logRequestDetails(req) return doRequest(ctx, req, rcpt) } func doDataRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { req.Header.Set("X-GE-KEY", config.DataAPIKey) - logRequestDetails(req, config.CustodialAPIKey) + logRequestDetails(req) return doRequest(ctx, req, rcpt) } -func logRequestDetails(req *http.Request, apiKey string) { +func logRequestDetails(req *http.Request) { var bodyBytes []byte contentType := req.Header.Get("Content-Type") if req.Body != nil { @@ -244,5 +241,4 @@ func logRequestDetails(req *http.Request, apiKey string) { } InfoLogger.Printf("URL: %s | Content-Type: %s | Method: %s| Request Body: %s", req.URL, contentType, req.Method, string(bodyBytes)) - } From 64a7b492186384b4b6e6a71e99de76069f7bf880 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 8 Nov 2024 00:21:11 +0300 Subject: [PATCH 241/289] Remove unused Warning logger --- cmd/africastalking/main.go | 1 - cmd/async/main.go | 1 - cmd/http/main.go | 1 - cmd/main.go | 1 - 4 files changed, 4 deletions(-) diff --git a/cmd/africastalking/main.go b/cmd/africastalking/main.go index 15a13ee..7616473 100644 --- a/cmd/africastalking/main.go +++ b/cmd/africastalking/main.go @@ -31,7 +31,6 @@ import ( var ( logg = logging.NewVanilla() scriptDir = path.Join("services", "registration") - WarningLogger *log.Logger InfoLogger *log.Logger ErrorLogger *log.Logger ) diff --git a/cmd/async/main.go b/cmd/async/main.go index 0dd7c2c..afc0bca 100644 --- a/cmd/async/main.go +++ b/cmd/async/main.go @@ -24,7 +24,6 @@ import ( var ( logg = logging.NewVanilla() scriptDir = path.Join("services", "registration") - WarningLogger *log.Logger InfoLogger *log.Logger ErrorLogger *log.Logger ) diff --git a/cmd/http/main.go b/cmd/http/main.go index ffb4109..0565c45 100644 --- a/cmd/http/main.go +++ b/cmd/http/main.go @@ -27,7 +27,6 @@ import ( var ( logg = logging.NewVanilla() scriptDir = path.Join("services", "registration") - WarningLogger *log.Logger InfoLogger *log.Logger ErrorLogger *log.Logger ) diff --git a/cmd/main.go b/cmd/main.go index a623cbe..857ccb9 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -21,7 +21,6 @@ import ( var ( logg = logging.NewVanilla() scriptDir = path.Join("services", "registration") - WarningLogger *log.Logger InfoLogger *log.Logger ErrorLogger *log.Logger ) From dcd8fce59a81bca56961e94fb1625ce601e06e95 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Fri, 8 Nov 2024 10:07:06 +0300 Subject: [PATCH 242/289] add log on create account --- remote/accountservice.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/remote/accountservice.go b/remote/accountservice.go index ae1fab7..e6a5556 100644 --- a/remote/accountservice.go +++ b/remote/accountservice.go @@ -96,9 +96,9 @@ func (as *AccountService) CreateAccount(ctx context.Context) (*models.AccountRes if err != nil { return nil, err } - _, err = doCustodialRequest(ctx, req, &r) if err != nil { + log.Printf("Failed to make custodial %s request to endpoint: %s with reason: %s", req.Method, req.URL, err.Error()) return nil, err } @@ -176,7 +176,6 @@ func (as *AccountService) VoucherData(ctx context.Context, address string) (*mod func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { var okResponse api.OKResponse var errResponse api.ErrResponse - req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { From 574807d25465cd1919d4ccf9a8ecd36ee8a0b889 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 8 Nov 2024 16:52:19 +0300 Subject: [PATCH 243/289] set the africastalking POST route using env --- .env.example | 3 +++ cmd/africastalking/main.go | 14 +++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.env.example b/.env.example index ab370a7..29b935e 100644 --- a/.env.example +++ b/.env.example @@ -16,3 +16,6 @@ CREATE_ACCOUNT_URL=http://localhost:5003/api/v2/account/create TRACK_STATUS_URL=https://custodial.sarafu.africa/api/track/ BALANCE_URL=https://custodial.sarafu.africa/api/account/status/ TRACK_URL=http://localhost:5003/api/v2/account/status + +#AfricasTalking USSD POST endpoint +AT_ENDPOINT=/ussd/africastalking diff --git a/cmd/africastalking/main.go b/cmd/africastalking/main.go index 7616473..bae83b9 100644 --- a/cmd/africastalking/main.go +++ b/cmd/africastalking/main.go @@ -29,10 +29,10 @@ import ( ) var ( - logg = logging.NewVanilla() - scriptDir = path.Join("services", "registration") - InfoLogger *log.Logger - ErrorLogger *log.Logger + logg = logging.NewVanilla() + scriptDir = path.Join("services", "registration") + InfoLogger *log.Logger + ErrorLogger *log.Logger ) func init() { @@ -197,9 +197,13 @@ func main() { rp := &atRequestParser{} bsh := handlers.NewBaseSessionHandler(cfg, rs, stateStore, userdataStore, rp, hl) sh := httpserver.NewATSessionHandler(bsh) + + mux := http.NewServeMux() + mux.Handle(initializers.GetEnv("AT_ENDPOINT", "/"), sh) + s := &http.Server{ Addr: fmt.Sprintf("%s:%s", host, strconv.Itoa(int(port))), - Handler: sh, + Handler: mux, } s.RegisterOnShutdown(sh.Shutdown) From f4f95b32926cc6c1407505c33964902c16cfb6ee Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Fri, 8 Nov 2024 17:15:27 +0300 Subject: [PATCH 244/289] add some spacing --- services/registration/edit_family_name | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/registration/edit_family_name b/services/registration/edit_family_name index 2170a7e..1d637be 100644 --- a/services/registration/edit_family_name +++ b/services/registration/edit_family_name @@ -1,2 +1,2 @@ -Current familyname: {{.get_current_profile_info}} +Current family name: {{.get_current_profile_info}} Enter family name: \ No newline at end of file From 68d162854614e9ae8b111f0a5d9bc440172b74f5 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Fri, 8 Nov 2024 17:19:41 +0300 Subject: [PATCH 245/289] replace - with: Not provided --- internal/handlers/ussd/menuhandler.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index db710d2..d59b1e9 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -1177,7 +1177,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 = "-" + res.Content = "Not provided" break } return res, err @@ -1187,7 +1187,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 = "-" + res.Content = "Not provided" break } return res, err @@ -1198,7 +1198,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 = "-" + res.Content = "Not provided" break } return res, err @@ -1208,7 +1208,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 = "-" + res.Content = "Not provided" break } return res, err @@ -1219,7 +1219,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 = "-" + res.Content = "Not provided" break } return res, err @@ -1229,7 +1229,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 = "-" + res.Content = "Not provided" break } return res, err From 9ebfb643aaa67d8379fb5051e688de9f47c94795 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Fri, 8 Nov 2024 17:28:20 +0300 Subject: [PATCH 246/289] remove unused import --- remote/accountservice.go | 1 - 1 file changed, 1 deletion(-) diff --git a/remote/accountservice.go b/remote/accountservice.go index 3a51e45..e6a5556 100644 --- a/remote/accountservice.go +++ b/remote/accountservice.go @@ -9,7 +9,6 @@ import ( "log" "net/http" "net/url" - "os" "git.grassecon.net/urdt/ussd/config" "git.grassecon.net/urdt/ussd/models" From 1d07d7fb1d014acf084e0834f7be0bec3c7091be Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 8 Nov 2024 20:35:17 +0300 Subject: [PATCH 247/289] updated README --- README.md | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 35ef7f1..493dd96 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,91 @@ -# ussd +# URDT USSD service -> USSD +This is a USSD service built using the [go-vise](https://github.com/nolash/go-vise) engine. -USSD service. +## Prerequisites +### 1. [go-vise](https://github.com/nolash/go-vise) + +Set up `go-vise` by cloning the repository into a separate directory. The main upstream repository is hosted at: `https://git.defalsify.org/vise.git` +``` +git clone https://git.defalsify.org/vise.git +``` + +## Setup +1. Clone the ussd repo in its own directory + + ``` + git clone https://git.grassecon.net/urdt/ussd.git + ``` + +2. Navigate to the project directory. +3. Enter the `services/registration` subfolder: + ``` + cd services/registration + ``` +4. make the .bin files from the .vis files + ``` + make VISE_PATH=/var/path/to/your/go-vise -B + ``` +5. Return to the project root (`cd ../..`) +6. Run the USSD menu + ``` + go run cmd/main.go -session-id=0712345678 + ``` +## Running the different binaries +1. ### CLI: + ``` + go run cmd/main.go -session-id=0712345678 + ``` +2. ### Africastalking: + ``` + go run cmd/africastalking/main.go + ``` +3. ### Async: + ``` + go run cmd/async/main.go + ``` +4. ### Http: + ``` + go run cmd/http/main.go + ``` + +## Flags +Below are the supported flags: + +1. `-session-id`: + + Specifies the session ID. (CLI only). + + Default: `075xx2123`. + + Example: + ``` + go run cmd/main.go -session-id=0712345678 + ``` + +2. `-d`: + + Enables engine debug output. + + Default: `false`. + + Example: + ``` + go run cmd/main.go -session-id=0712345678 -d + ``` + +3. `-db`: + + Specifies the database type. + + Default: `gdbm`. + + Example: + ``` + go run cmd/main.go -session-id=0712345678 -d -db=postgres + ``` + + >Note: If using `-db=postgres`, ensure PostgreSQL is running with the connection details specified in your `.env` file. ## License From 9af7b775a78cddcf0ba0ea33517daf2d0fb3542a Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Mon, 11 Nov 2024 16:32:17 +0300 Subject: [PATCH 248/289] log directly to the terminal --- cmd/africastalking/main.go | 26 +++++--------------------- cmd/async/main.go | 18 +----------------- cmd/http/main.go | 17 ----------------- cmd/main.go | 17 ----------------- remote/accountservice.go | 13 ++++--------- 5 files changed, 10 insertions(+), 81 deletions(-) diff --git a/cmd/africastalking/main.go b/cmd/africastalking/main.go index bae83b9..5a523e7 100644 --- a/cmd/africastalking/main.go +++ b/cmd/africastalking/main.go @@ -31,26 +31,10 @@ import ( var ( logg = logging.NewVanilla() scriptDir = path.Join("services", "registration") - InfoLogger *log.Logger - ErrorLogger *log.Logger ) func init() { initializers.LoadEnvVariables() - - logFile := "urdt-ussd-africastalking.log" - - file, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666) - if err != nil { - log.Fatal(err) - } - - InfoLogger = log.New(file, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile) - ErrorLogger = log.New(file, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) - - // Inject into remote package - remote.InfoLogger = InfoLogger - remote.ErrorLogger = ErrorLogger } type atRequestParser struct{} @@ -58,14 +42,14 @@ type atRequestParser struct{} func (arp *atRequestParser) GetSessionId(rq any) (string, error) { rqv, ok := rq.(*http.Request) if !ok { - ErrorLogger.Println("got an invalid request:", rq) + log.Println("got an invalid request:", rq) return "", handlers.ErrInvalidRequest } // Capture body (if any) for logging body, err := io.ReadAll(rqv.Body) if err != nil { - ErrorLogger.Println("failed to read request body:", err) + log.Println("failed to read request body:", err) return "", fmt.Errorf("failed to read request body: %v", err) } // Reset the body for further reading @@ -75,13 +59,13 @@ func (arp *atRequestParser) GetSessionId(rq any) (string, error) { bodyLog := map[string]string{"body": string(body)} logBytes, err := json.Marshal(bodyLog) if err != nil { - ErrorLogger.Println("failed to marshal request body:", err) + log.Println("failed to marshal request body:", err) } else { - InfoLogger.Println("Received request:", string(logBytes)) + log.Println("Received request:", string(logBytes)) } if err := rqv.ParseForm(); err != nil { - ErrorLogger.Println("failed to parse form data: %v", err) + log.Println("failed to parse form data: %v", err) return "", fmt.Errorf("failed to parse form data: %v", err) } diff --git a/cmd/async/main.go b/cmd/async/main.go index afc0bca..e4c94b0 100644 --- a/cmd/async/main.go +++ b/cmd/async/main.go @@ -4,7 +4,6 @@ import ( "context" "flag" "fmt" - "log" "os" "os/signal" "path" @@ -24,27 +23,12 @@ import ( var ( logg = logging.NewVanilla() scriptDir = path.Join("services", "registration") - InfoLogger *log.Logger - ErrorLogger *log.Logger ) func init() { initializers.LoadEnvVariables() - - logFile := "urdt-ussd-async.log" - - file, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666) - if err != nil { - log.Fatal(err) - } - - InfoLogger = log.New(file, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile) - ErrorLogger = log.New(file, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) - - // Inject into remote package - remote.InfoLogger = InfoLogger - remote.ErrorLogger = ErrorLogger } + type asyncRequestParser struct { sessionId string input []byte diff --git a/cmd/http/main.go b/cmd/http/main.go index 0565c45..96e2688 100644 --- a/cmd/http/main.go +++ b/cmd/http/main.go @@ -4,7 +4,6 @@ import ( "context" "flag" "fmt" - "log" "net/http" "os" "os/signal" @@ -27,26 +26,10 @@ import ( var ( logg = logging.NewVanilla() scriptDir = path.Join("services", "registration") - InfoLogger *log.Logger - ErrorLogger *log.Logger ) func init() { initializers.LoadEnvVariables() - - logFile := "urdt-ussd-http.log" - - file, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666) - if err != nil { - log.Fatal(err) - } - - InfoLogger = log.New(file, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile) - ErrorLogger = log.New(file, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) - - // Inject into remote package - remote.InfoLogger = InfoLogger - remote.ErrorLogger = ErrorLogger } func main() { diff --git a/cmd/main.go b/cmd/main.go index 857ccb9..9599eb7 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -4,7 +4,6 @@ import ( "context" "flag" "fmt" - "log" "os" "path" @@ -21,26 +20,10 @@ import ( var ( logg = logging.NewVanilla() scriptDir = path.Join("services", "registration") - InfoLogger *log.Logger - ErrorLogger *log.Logger ) func init() { initializers.LoadEnvVariables() - - logFile := "urdt-ussd-cli.log" - - file, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666) - if err != nil { - log.Fatal(err) - } - - InfoLogger = log.New(file, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile) - ErrorLogger = log.New(file, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) - - // Inject into remote package - remote.InfoLogger = InfoLogger - remote.ErrorLogger = ErrorLogger } func main() { diff --git a/remote/accountservice.go b/remote/accountservice.go index e6a5556..388fd9c 100644 --- a/remote/accountservice.go +++ b/remote/accountservice.go @@ -16,11 +16,6 @@ import ( dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" ) -var ( - InfoLogger *log.Logger - ErrorLogger *log.Logger -) - type AccountServiceInterface interface { CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResult, error) CreateAccount(ctx context.Context) (*models.AccountResult, error) @@ -98,7 +93,6 @@ func (as *AccountService) CreateAccount(ctx context.Context) (*models.AccountRes } _, err = doCustodialRequest(ctx, req, &r) if err != nil { - log.Printf("Failed to make custodial %s request to endpoint: %s with reason: %s", req.Method, req.URL, err.Error()) return nil, err } @@ -179,12 +173,13 @@ func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKRespons req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { + log.Printf("Failed to make %s request to endpoint: %s with reason: %s", req.Method, req.URL, err.Error()) errResponse.Description = err.Error() return nil, err } defer resp.Body.Close() - InfoLogger.Printf("Received response for %s: Status Code: %d | Content-Type: %s", req.URL, resp.StatusCode, resp.Header.Get("Content-Type")) + log.Printf("Received response for %s: Status Code: %d | Content-Type: %s", req.URL, resp.StatusCode, resp.Header.Get("Content-Type")) body, err := io.ReadAll(resp.Body) if err != nil { return nil, err @@ -231,7 +226,7 @@ func logRequestDetails(req *http.Request) { if req.Body != nil { bodyBytes, err := io.ReadAll(req.Body) if err != nil { - ErrorLogger.Printf("Error reading request body: %s", err) + log.Printf("Error reading request body: %s", err) return } req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) @@ -239,5 +234,5 @@ func logRequestDetails(req *http.Request) { bodyBytes = []byte("-") } - InfoLogger.Printf("URL: %s | Content-Type: %s | Method: %s| Request Body: %s", req.URL, contentType, req.Method, string(bodyBytes)) + log.Printf("URL: %s | Content-Type: %s | Method: %s| Request Body: %s", req.URL, contentType, req.Method, string(bodyBytes)) } From abdb17640b22e6fbdd6e860f1169557acafb60e2 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Tue, 12 Nov 2024 10:36:08 +0300 Subject: [PATCH 249/289] add terminal logs --- internal/handlers/ussd/menuhandler.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index ca4af09..6fcb865 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -239,6 +239,7 @@ func (h *Handlers) CheckPinMisMatch(ctx context.Context, sym string, input []byt } temporaryPin, err := store.ReadEntry(ctx, string(blockedNumber), common.DATA_TEMPORARY_VALUE) if err != nil { + return res, err } if bytes.Equal(temporaryPin, input) { @@ -291,6 +292,7 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt store := h.userdataStore err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(accountPIN)) if err != nil { + logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", accountPIN, "error", err) return res, err } @@ -310,10 +312,12 @@ func (h *Handlers) SaveOthersTemporaryPin(ctx context.Context, sym string, input blockedNumber, err := store.ReadEntry(ctx, sessionId, common.DATA_BLOCKED_NUMBER) if err != nil { + logg.ErrorCtxf(ctx, "failed to read entry with", "key", common.DATA_BLOCKED_NUMBER, "error", err) return res, err } err = store.WriteEntry(ctx, string(blockedNumber), common.DATA_TEMPORARY_VALUE, []byte(temporaryPin)) if err != nil { + logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", temporaryPin, "error", err) return res, err } @@ -331,6 +335,7 @@ func (h *Handlers) ConfirmPinChange(ctx context.Context, sym string, input []byt store := h.userdataStore temporaryPin, err := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) if err != nil { + logg.ErrorCtxf(ctx, "failed to read entry with", "key", common.DATA_TEMPORARY_VALUE, "error", err) return res, err } if bytes.Equal(temporaryPin, input) { @@ -340,6 +345,7 @@ func (h *Handlers) ConfirmPinChange(ctx context.Context, sym string, input []byt } err = store.WriteEntry(ctx, sessionId, common.DATA_ACCOUNT_PIN, []byte(temporaryPin)) if err != nil { + logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_ACCOUNT_PIN, "value", temporaryPin, "error", err) return res, err } return res, nil @@ -374,6 +380,7 @@ func (h *Handlers) VerifyCreatePin(ctx context.Context, sym string, input []byte err = store.WriteEntry(ctx, sessionId, common.DATA_ACCOUNT_PIN, []byte(temporaryPin)) if err != nil { + logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_ACCOUNT_PIN, "value", temporaryPin, "error", err) return res, err } @@ -406,11 +413,13 @@ func (h *Handlers) SaveFirstname(ctx context.Context, sym string, input []byte) temporaryFirstName, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) err = store.WriteEntry(ctx, sessionId, common.DATA_FIRST_NAME, []byte(temporaryFirstName)) if err != nil { + logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_FIRST_NAME, "value", temporaryFirstName, "error", err) return res, err } } else { err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(firstName)) if err != nil { + logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", firstName, "error", err) return res, err } } @@ -465,11 +474,13 @@ func (h *Handlers) SaveYob(ctx context.Context, sym string, input []byte) (resou temporaryYob, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) err = store.WriteEntry(ctx, sessionId, common.DATA_YOB, []byte(temporaryYob)) if err != nil { + logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", temporaryYob, "error", err) return res, err } } else { err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(yob)) if err != nil { + logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", yob, "error", err) return res, err } } @@ -495,11 +506,13 @@ func (h *Handlers) SaveLocation(ctx context.Context, sym string, input []byte) ( temporaryLocation, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) err = store.WriteEntry(ctx, sessionId, common.DATA_LOCATION, []byte(temporaryLocation)) if err != nil { + logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_LOCATION, "value", temporaryLocation, "error", err) return res, err } } else { err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(location)) if err != nil { + logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", location, "error", err) return res, err } } @@ -525,11 +538,13 @@ func (h *Handlers) SaveGender(ctx context.Context, sym string, input []byte) (re temporaryGender, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) err = store.WriteEntry(ctx, sessionId, common.DATA_GENDER, []byte(temporaryGender)) if err != nil { + logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_GENDER, "value", gender, "error", err) return res, err } } else { err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(gender)) if err != nil { + logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", gender, "error", err) return res, err } } @@ -556,11 +571,13 @@ func (h *Handlers) SaveOfferings(ctx context.Context, sym string, input []byte) temporaryOfferings, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) err = store.WriteEntry(ctx, sessionId, common.DATA_OFFERINGS, []byte(temporaryOfferings)) if err != nil { + logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", offerings, "error", err) return res, err } } else { err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(offerings)) if err != nil { + logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", offerings, "error", err) return res, err } } From 09f61eb64d07c852011e54b1eeec02374e3922a5 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 13 Nov 2024 15:19:45 +0300 Subject: [PATCH 250/289] log all errors from the hander --- internal/handlers/ussd/menuhandler.go | 50 ++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 6fcb865..58df521 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "log" "path" "regexp" "strconv" @@ -161,6 +162,7 @@ func (h *Handlers) SetLanguage(ctx context.Context, sym string, input []byte) (r languageSetFlag, err := h.flagManager.GetFlag("flag_language_set") if err != nil { + log.Printf("Error: %s", err) return res, err } res.FlagSet = append(res.FlagSet, languageSetFlag) @@ -198,7 +200,6 @@ func (h *Handlers) createAccountNoExist(ctx context.Context, sessionId string, r } res.FlagSet = append(res.FlagSet, flag_account_created) return nil - } // CreateAccount checks if any account exists on the JSON data file, and if not @@ -218,10 +219,12 @@ func (h *Handlers) CreateAccount(ctx context.Context, sym string, input []byte) logg.Printf(logging.LVL_INFO, "Creating an account because it doesn't exist") err = h.createAccountNoExist(ctx, sessionId, &res) if err != nil { + log.Printf("Error: %s", err) return res, err } } } + return res, nil } @@ -235,11 +238,13 @@ func (h *Handlers) CheckPinMisMatch(ctx context.Context, sym string, input []byt store := h.userdataStore blockedNumber, err := store.ReadEntry(ctx, sessionId, common.DATA_BLOCKED_NUMBER) if err != nil { + log.Printf("Error: %s", err) return res, err } temporaryPin, err := store.ReadEntry(ctx, string(blockedNumber), common.DATA_TEMPORARY_VALUE) if err != nil { + log.Printf("Error: %s", err) return res, err } if bytes.Equal(temporaryPin, input) { @@ -293,6 +298,7 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(accountPIN)) if err != nil { logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", accountPIN, "error", err) + log.Printf("Error: %s", err) return res, err } @@ -313,11 +319,13 @@ func (h *Handlers) SaveOthersTemporaryPin(ctx context.Context, sym string, input if err != nil { logg.ErrorCtxf(ctx, "failed to read entry with", "key", common.DATA_BLOCKED_NUMBER, "error", err) + log.Printf("Error: %s", err) return res, err } err = store.WriteEntry(ctx, string(blockedNumber), common.DATA_TEMPORARY_VALUE, []byte(temporaryPin)) if err != nil { logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", temporaryPin, "error", err) + log.Printf("Error: %s", err) return res, err } @@ -336,6 +344,7 @@ func (h *Handlers) ConfirmPinChange(ctx context.Context, sym string, input []byt temporaryPin, err := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) if err != nil { logg.ErrorCtxf(ctx, "failed to read entry with", "key", common.DATA_TEMPORARY_VALUE, "error", err) + log.Printf("Error: %s", err) return res, err } if bytes.Equal(temporaryPin, input) { @@ -346,6 +355,7 @@ func (h *Handlers) ConfirmPinChange(ctx context.Context, sym string, input []byt err = store.WriteEntry(ctx, sessionId, common.DATA_ACCOUNT_PIN, []byte(temporaryPin)) if err != nil { logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_ACCOUNT_PIN, "value", temporaryPin, "error", err) + log.Printf("Error: %s", err) return res, err } return res, nil @@ -368,6 +378,7 @@ func (h *Handlers) VerifyCreatePin(ctx context.Context, sym string, input []byte store := h.userdataStore temporaryPin, err := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) if err != nil { + log.Printf("Error: %s", err) return res, err } if bytes.Equal(input, temporaryPin) { @@ -381,6 +392,7 @@ func (h *Handlers) VerifyCreatePin(ctx context.Context, sym string, input []byte err = store.WriteEntry(ctx, sessionId, common.DATA_ACCOUNT_PIN, []byte(temporaryPin)) if err != nil { logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_ACCOUNT_PIN, "value", temporaryPin, "error", err) + log.Printf("Error: %s", err) return res, err } @@ -414,12 +426,14 @@ func (h *Handlers) SaveFirstname(ctx context.Context, sym string, input []byte) err = store.WriteEntry(ctx, sessionId, common.DATA_FIRST_NAME, []byte(temporaryFirstName)) if err != nil { logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_FIRST_NAME, "value", temporaryFirstName, "error", err) + log.Printf("Error: %s", err) return res, err } } else { err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(firstName)) if err != nil { logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", firstName, "error", err) + log.Printf("Error: %s", err) return res, err } } @@ -446,11 +460,13 @@ func (h *Handlers) SaveFamilyname(ctx context.Context, sym string, input []byte) temporaryFamilyName, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) err = store.WriteEntry(ctx, sessionId, common.DATA_FAMILY_NAME, []byte(temporaryFamilyName)) if err != nil { + log.Printf("Error: %s", err) return res, err } } else { err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(familyName)) if err != nil { + log.Printf("Error: %s", err) return res, err } } @@ -475,12 +491,14 @@ func (h *Handlers) SaveYob(ctx context.Context, sym string, input []byte) (resou err = store.WriteEntry(ctx, sessionId, common.DATA_YOB, []byte(temporaryYob)) if err != nil { logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", temporaryYob, "error", err) + log.Printf("Error: %s", err) return res, err } } else { err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(yob)) if err != nil { logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", yob, "error", err) + log.Printf("Error: %s", err) return res, err } } @@ -507,12 +525,14 @@ func (h *Handlers) SaveLocation(ctx context.Context, sym string, input []byte) ( err = store.WriteEntry(ctx, sessionId, common.DATA_LOCATION, []byte(temporaryLocation)) if err != nil { logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_LOCATION, "value", temporaryLocation, "error", err) + log.Printf("Error: %s", err) return res, err } } else { err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(location)) if err != nil { logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", location, "error", err) + log.Printf("Error: %s", err) return res, err } } @@ -539,12 +559,14 @@ func (h *Handlers) SaveGender(ctx context.Context, sym string, input []byte) (re err = store.WriteEntry(ctx, sessionId, common.DATA_GENDER, []byte(temporaryGender)) if err != nil { logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_GENDER, "value", gender, "error", err) + log.Printf("Error: %s", err) return res, err } } else { err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(gender)) if err != nil { logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", gender, "error", err) + log.Printf("Error: %s", err) return res, err } } @@ -572,12 +594,14 @@ func (h *Handlers) SaveOfferings(ctx context.Context, sym string, input []byte) err = store.WriteEntry(ctx, sessionId, common.DATA_OFFERINGS, []byte(temporaryOfferings)) if err != nil { logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", offerings, "error", err) + log.Printf("Error: %s", err) return res, err } } else { err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(offerings)) if err != nil { logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", offerings, "error", err) + log.Printf("Error: %s", err) return res, err } } @@ -643,6 +667,7 @@ func (h *Handlers) Authorize(ctx context.Context, sym string, input []byte) (res store := h.userdataStore AccountPin, err := store.ReadEntry(ctx, sessionId, common.DATA_ACCOUNT_PIN) if err != nil { + log.Printf("Error: %s", err) return res, err } if len(input) == 4 { @@ -690,16 +715,19 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b store := h.userdataStore publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) if err != nil { + log.Printf("Error: %s", err) return res, err } r, err := h.accountService.TrackAccountStatus(ctx, string(publicKey)) if err != nil { res.FlagSet = append(res.FlagSet, flag_api_error) + log.Printf("Error: %s", err) return res, err } res.FlagReset = append(res.FlagReset, flag_api_error) if !ok { + log.Printf("Error: %s", err) return res, err } if r.Active { @@ -800,11 +828,13 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) ( return res, nil } + log.Printf("Error: %s", err) return res, err } activeBal, err := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_BAL) if err != nil { + log.Printf("Error: %s", err) return res, err } @@ -828,6 +858,7 @@ func (h *Handlers) FetchCustodialBalances(ctx context.Context, sym string, input store := h.userdataStore publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) if err != nil { + log.Printf("Error: %s", err) return res, err } @@ -860,10 +891,12 @@ func (h *Handlers) ResetOthersPin(ctx context.Context, sym string, input []byte) } blockedPhonenumber, err := store.ReadEntry(ctx, sessionId, common.DATA_BLOCKED_NUMBER) if err != nil { + log.Printf("Error: %s", err) return res, err } temporaryPin, err := store.ReadEntry(ctx, string(blockedPhonenumber), common.DATA_TEMPORARY_VALUE) if err != nil { + log.Printf("Error: %s", err) return res, err } err = store.WriteEntry(ctx, string(blockedPhonenumber), common.DATA_ACCOUNT_PIN, []byte(temporaryPin)) @@ -902,6 +935,7 @@ func (h *Handlers) ValidateBlockedNumber(ctx context.Context, sym string, input res.FlagSet = append(res.FlagSet, flag_unregistered_number) return res, nil } else { + log.Printf("Error: %s", err) return res, err } } @@ -1009,6 +1043,7 @@ func (h *Handlers) MaxAmount(ctx context.Context, sym string, input []byte) (res activeBal, err := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_BAL) if err != nil { + log.Printf("Error: %s", err) return res, err } @@ -1034,10 +1069,12 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte) // retrieve the active balance activeBal, err := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_BAL) if err != nil { + log.Printf("Error: %s", err) return res, err } balanceValue, err = strconv.ParseFloat(string(activeBal), 64) if err != nil { + log.Printf("Error: %s", err) return res, err } @@ -1060,6 +1097,7 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte) formattedAmount := fmt.Sprintf("%.2f", inputAmount) err = store.WriteEntry(ctx, sessionId, common.DATA_AMOUNT, []byte(formattedAmount)) if err != nil { + log.Printf("Error: %s", err) return res, err } @@ -1126,6 +1164,7 @@ func (h *Handlers) GetAmount(ctx context.Context, sym string, input []byte) (res // retrieve the active symbol activeSym, err := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_SYM) if err != nil { + log.Printf("Error: %s", err) return res, err } @@ -1163,6 +1202,7 @@ func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input [] account_authorized_flag, err := h.flagManager.GetFlag("flag_account_authorized") if err != nil { + log.Printf("Error: %s", err) return res, err } @@ -1265,6 +1305,7 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by if db.IsNotFound(err) { publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) if err != nil { + log.Printf("Error: %s", err) return res, err } @@ -1289,17 +1330,20 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by // set the active symbol err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_SYM, []byte(defaultSym)) if err != nil { + log.Printf("Error: %s", err) return res, err } // set the active balance err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_BAL, []byte(defaultBal)) if err != nil { + log.Printf("Error: %s", err) return res, err } return res, nil } + log.Printf("Error: %s", err) return res, err } @@ -1355,6 +1399,7 @@ func (h *Handlers) GetVoucherList(ctx context.Context, sym string, input []byte) // Read vouchers from the store voucherData, err := h.prefixDb.Get(ctx, []byte("sym")) if err != nil { + log.Printf("Error: %s", err) return res, err } @@ -1390,6 +1435,7 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r } if err := common.StoreTemporaryVoucher(ctx, h.userdataStore, sessionId, metadata); err != nil { + log.Printf("Error: %s", err) return res, err } @@ -1411,11 +1457,13 @@ func (h *Handlers) SetVoucher(ctx context.Context, sym string, input []byte) (re // Get temporary data tempData, err := common.GetTemporaryVoucherData(ctx, h.userdataStore, sessionId) if err != nil { + log.Printf("Error: %s", err) return res, err } // Set as active and clear temporary data if err := common.UpdateVoucherData(ctx, h.userdataStore, sessionId, tempData); err != nil { + log.Printf("Error: %s", err) return res, err } From 047bf0e12ee59764e21829acb3aa7fe932f79694 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 13 Nov 2024 16:15:37 +0300 Subject: [PATCH 251/289] updated the env example --- .env.example | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.env.example b/.env.example index 29b935e..d392c9b 100644 --- a/.env.example +++ b/.env.example @@ -2,6 +2,9 @@ PORT=7123 HOST=127.0.0.1 +#AfricasTalking USSD POST endpoint +AT_ENDPOINT=/ussd/africastalking + #PostgreSQL DB_HOST=localhost DB_USER=postgres @@ -12,10 +15,7 @@ DB_SSLMODE=disable DB_TIMEZONE=Africa/Nairobi #External API Calls -CREATE_ACCOUNT_URL=http://localhost:5003/api/v2/account/create -TRACK_STATUS_URL=https://custodial.sarafu.africa/api/track/ -BALANCE_URL=https://custodial.sarafu.africa/api/account/status/ -TRACK_URL=http://localhost:5003/api/v2/account/status - -#AfricasTalking USSD POST endpoint -AT_ENDPOINT=/ussd/africastalking +CUSTODIAL_URL_BASE=http://localhost:5003 +CUSTODIAL_BEARER_TOKEN=eyJeSIsInRcCI6IkpXVCJ.yJwdWJsaWNLZXkiOiIwrrrrrr +DATA_URL_BASE=http://localhost:5006 +DATA_BEARER_TOKEN=eyJeSIsIRcCI6IXVCJ.yJwdWJsaLZXkiOiIwrrrrrr From d7232a53efab7acd5d9ba3bc378ccd42defc7add Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 13 Nov 2024 16:16:32 +0300 Subject: [PATCH 252/289] use the bearer token --- config/config.go | 40 ++++++++++++++++++++-------------------- remote/accountservice.go | 4 ++-- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/config/config.go b/config/config.go index fbf518b..c4445eb 100644 --- a/config/config.go +++ b/config/config.go @@ -7,30 +7,30 @@ import ( ) const ( - createAccountPath = "/api/v2/account/create" - trackStatusPath = "/api/track" - balancePathPrefix = "/api/account" - trackPath = "/api/v2/account/status" - voucherHoldingsPathPrefix = "/api/v1/holdings" + createAccountPath = "/api/v2/account/create" + trackStatusPath = "/api/track" + balancePathPrefix = "/api/account" + trackPath = "/api/v2/account/status" + voucherHoldingsPathPrefix = "/api/v1/holdings" voucherTransfersPathPrefix = "/api/v1/transfers/last10" - voucherDataPathPrefix = "/api/v1/token" + voucherDataPathPrefix = "/api/v1/token" ) var ( - custodialURLBase string - dataURLBase string - CustodialAPIKey string - DataAPIKey string + custodialURLBase string + dataURLBase string + CustodialBearerToken string + DataBearerToken string ) var ( - CreateAccountURL string - TrackStatusURL string - BalanceURL string - TrackURL string - VoucherHoldingsURL string - VoucherTransfersURL string - VoucherDataURL string + CreateAccountURL string + TrackStatusURL string + BalanceURL string + TrackURL string + VoucherHoldingsURL string + VoucherTransfersURL string + VoucherDataURL string ) func setBase() error { @@ -38,8 +38,8 @@ func setBase() error { custodialURLBase = initializers.GetEnv("CUSTODIAL_URL_BASE", "http://localhost:5003") dataURLBase = initializers.GetEnv("DATA_URL_BASE", "http://localhost:5006") - CustodialAPIKey = initializers.GetEnv("CUSTODIAL_API_KEY", "xd") - DataAPIKey = initializers.GetEnv("DATA_API_KEY", "xd") + CustodialBearerToken = initializers.GetEnv("CUSTODIAL_BEARER_TOKEN", "") + DataBearerToken = initializers.GetEnv("DATA_BEARER_TOKEN", "") _, err = url.JoinPath(custodialURLBase, "/foo") if err != nil { @@ -58,7 +58,7 @@ func LoadConfig() error { if err != nil { return err } - CreateAccountURL, _ = url.JoinPath(custodialURLBase, createAccountPath) + CreateAccountURL, _ = url.JoinPath(custodialURLBase, createAccountPath) TrackStatusURL, _ = url.JoinPath(custodialURLBase, trackStatusPath) BalanceURL, _ = url.JoinPath(custodialURLBase, balancePathPrefix) TrackURL, _ = url.JoinPath(custodialURLBase, trackPath) diff --git a/remote/accountservice.go b/remote/accountservice.go index 388fd9c..19914cd 100644 --- a/remote/accountservice.go +++ b/remote/accountservice.go @@ -209,13 +209,13 @@ func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKRespons } func doCustodialRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { - req.Header.Set("X-GE-KEY", config.CustodialAPIKey) + req.Header.Set("Authorization", "Bearer "+config.CustodialBearerToken) logRequestDetails(req) return doRequest(ctx, req, rcpt) } func doDataRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { - req.Header.Set("X-GE-KEY", config.DataAPIKey) + req.Header.Set("Authorization", "Bearer "+config.DataBearerToken) logRequestDetails(req) return doRequest(ctx, req, rcpt) } From b6b3ef83a466ce6ad7e357697e717dc96859d4d0 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 13 Nov 2024 18:02:02 +0300 Subject: [PATCH 253/289] updated the comment to match the functionality --- common/vouchers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/vouchers.go b/common/vouchers.go index 2fed043..dd8852e 100644 --- a/common/vouchers.go +++ b/common/vouchers.go @@ -135,7 +135,7 @@ func GetTemporaryVoucherData(ctx context.Context, store DataStore, sessionId str return data, nil } -// UpdateVoucherData sets the active voucher data and clears the temporary voucher data in the DataStore. +// UpdateVoucherData sets the active voucher data in the DataStore. func UpdateVoucherData(ctx context.Context, store DataStore, sessionId string, data *dataserviceapi.TokenHoldings) error { logg.TraceCtxf(ctx, "dtal", "data", data) // Active voucher data entries From f9f25d898b0ec435c7fef41a1ab32277c1914478 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 13 Nov 2024 19:00:27 +0300 Subject: [PATCH 254/289] use logg --- internal/handlers/ussd/menuhandler.go | 135 +++++++++++--------------- 1 file changed, 58 insertions(+), 77 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 58df521..1836833 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "fmt" - "log" "path" "regexp" "strconv" @@ -162,7 +161,7 @@ func (h *Handlers) SetLanguage(ctx context.Context, sym string, input []byte) (r languageSetFlag, err := h.flagManager.GetFlag("flag_language_set") if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "Error setting the languageSetFlag", "error", err) return res, err } res.FlagSet = append(res.FlagSet, languageSetFlag) @@ -216,10 +215,10 @@ func (h *Handlers) CreateAccount(ctx context.Context, sym string, input []byte) _, err = store.ReadEntry(ctx, sessionId, common.DATA_ACCOUNT_CREATED) if err != nil { if db.IsNotFound(err) { - logg.Printf(logging.LVL_INFO, "Creating an account because it doesn't exist") + logg.InfoCtxf(ctx, "Creating an account because it doesn't exist") err = h.createAccountNoExist(ctx, sessionId, &res) if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed on createAccountNoExist", "error", err) return res, err } } @@ -238,13 +237,12 @@ func (h *Handlers) CheckPinMisMatch(ctx context.Context, sym string, input []byt store := h.userdataStore blockedNumber, err := store.ReadEntry(ctx, sessionId, common.DATA_BLOCKED_NUMBER) if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to read blockedNumber entry with", "key", common.DATA_BLOCKED_NUMBER, "error", err) return res, err } temporaryPin, err := store.ReadEntry(ctx, string(blockedNumber), common.DATA_TEMPORARY_VALUE) if err != nil { - - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to read temporaryPin entry with", "key", common.DATA_TEMPORARY_VALUE, "error", err) return res, err } if bytes.Equal(temporaryPin, input) { @@ -297,8 +295,7 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt store := h.userdataStore err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(accountPIN)) if err != nil { - logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", accountPIN, "error", err) - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to write temporaryAccountPIN entry with", "key", common.DATA_TEMPORARY_VALUE, "value", accountPIN, "error", err) return res, err } @@ -316,16 +313,14 @@ func (h *Handlers) SaveOthersTemporaryPin(ctx context.Context, sym string, input } temporaryPin := string(input) blockedNumber, err := store.ReadEntry(ctx, sessionId, common.DATA_BLOCKED_NUMBER) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read entry with", "key", common.DATA_BLOCKED_NUMBER, "error", err) - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to read blockedNumber entry with", "key", common.DATA_BLOCKED_NUMBER, "error", err) return res, err } + err = store.WriteEntry(ctx, string(blockedNumber), common.DATA_TEMPORARY_VALUE, []byte(temporaryPin)) if err != nil { - logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", temporaryPin, "error", err) - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to write temporaryPin entry with", "key", common.DATA_TEMPORARY_VALUE, "value", temporaryPin, "error", err) return res, err } @@ -343,8 +338,7 @@ func (h *Handlers) ConfirmPinChange(ctx context.Context, sym string, input []byt store := h.userdataStore temporaryPin, err := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) if err != nil { - logg.ErrorCtxf(ctx, "failed to read entry with", "key", common.DATA_TEMPORARY_VALUE, "error", err) - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to read temporaryPin entry with", "key", common.DATA_TEMPORARY_VALUE, "error", err) return res, err } if bytes.Equal(temporaryPin, input) { @@ -354,8 +348,7 @@ func (h *Handlers) ConfirmPinChange(ctx context.Context, sym string, input []byt } err = store.WriteEntry(ctx, sessionId, common.DATA_ACCOUNT_PIN, []byte(temporaryPin)) if err != nil { - logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_ACCOUNT_PIN, "value", temporaryPin, "error", err) - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to write temporaryPin entry with", "key", common.DATA_ACCOUNT_PIN, "value", temporaryPin, "error", err) return res, err } return res, nil @@ -378,7 +371,7 @@ func (h *Handlers) VerifyCreatePin(ctx context.Context, sym string, input []byte store := h.userdataStore temporaryPin, err := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to read temporaryPin entry with", "key", common.DATA_TEMPORARY_VALUE, "error", err) return res, err } if bytes.Equal(input, temporaryPin) { @@ -391,8 +384,7 @@ func (h *Handlers) VerifyCreatePin(ctx context.Context, sym string, input []byte err = store.WriteEntry(ctx, sessionId, common.DATA_ACCOUNT_PIN, []byte(temporaryPin)) if err != nil { - logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_ACCOUNT_PIN, "value", temporaryPin, "error", err) - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to write temporaryPin entry with", "key", common.DATA_ACCOUNT_PIN, "value", temporaryPin, "error", err) return res, err } @@ -425,15 +417,13 @@ func (h *Handlers) SaveFirstname(ctx context.Context, sym string, input []byte) temporaryFirstName, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) err = store.WriteEntry(ctx, sessionId, common.DATA_FIRST_NAME, []byte(temporaryFirstName)) if err != nil { - logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_FIRST_NAME, "value", temporaryFirstName, "error", err) - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to write firstName entry with", "key", common.DATA_FIRST_NAME, "value", temporaryFirstName, "error", err) return res, err } } else { err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(firstName)) if err != nil { - logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", firstName, "error", err) - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to write temporaryFirstName entry with", "key", common.DATA_TEMPORARY_VALUE, "value", firstName, "error", err) return res, err } } @@ -460,16 +450,17 @@ func (h *Handlers) SaveFamilyname(ctx context.Context, sym string, input []byte) temporaryFamilyName, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) err = store.WriteEntry(ctx, sessionId, common.DATA_FAMILY_NAME, []byte(temporaryFamilyName)) if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to write familyName entry with", "key", common.DATA_FAMILY_NAME, "value", temporaryFamilyName, "error", err) return res, err } } else { err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(familyName)) if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to write temporaryFamilyName entry with", "key", common.DATA_TEMPORARY_VALUE, "value", familyName, "error", err) return res, err } } + return res, nil } @@ -490,15 +481,13 @@ func (h *Handlers) SaveYob(ctx context.Context, sym string, input []byte) (resou temporaryYob, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) err = store.WriteEntry(ctx, sessionId, common.DATA_YOB, []byte(temporaryYob)) if err != nil { - logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", temporaryYob, "error", err) - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to write yob entry with", "key", common.DATA_TEMPORARY_VALUE, "value", temporaryYob, "error", err) return res, err } } else { err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(yob)) if err != nil { - logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", yob, "error", err) - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to write temporaryYob entry with", "key", common.DATA_TEMPORARY_VALUE, "value", yob, "error", err) return res, err } } @@ -524,15 +513,13 @@ func (h *Handlers) SaveLocation(ctx context.Context, sym string, input []byte) ( temporaryLocation, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) err = store.WriteEntry(ctx, sessionId, common.DATA_LOCATION, []byte(temporaryLocation)) if err != nil { - logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_LOCATION, "value", temporaryLocation, "error", err) - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to write location entry with", "key", common.DATA_LOCATION, "value", temporaryLocation, "error", err) return res, err } } else { err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(location)) if err != nil { - logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", location, "error", err) - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to write temporaryLocation entry with", "key", common.DATA_TEMPORARY_VALUE, "value", location, "error", err) return res, err } } @@ -558,15 +545,13 @@ func (h *Handlers) SaveGender(ctx context.Context, sym string, input []byte) (re temporaryGender, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) err = store.WriteEntry(ctx, sessionId, common.DATA_GENDER, []byte(temporaryGender)) if err != nil { - logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_GENDER, "value", gender, "error", err) - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to write gender entry with", "key", common.DATA_GENDER, "value", gender, "error", err) return res, err } } else { err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(gender)) if err != nil { - logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", gender, "error", err) - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to write temporaryGender entry with", "key", common.DATA_TEMPORARY_VALUE, "value", gender, "error", err) return res, err } } @@ -593,15 +578,13 @@ func (h *Handlers) SaveOfferings(ctx context.Context, sym string, input []byte) temporaryOfferings, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) err = store.WriteEntry(ctx, sessionId, common.DATA_OFFERINGS, []byte(temporaryOfferings)) if err != nil { - logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", offerings, "error", err) - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to write offerings entry with", "key", common.DATA_TEMPORARY_VALUE, "value", offerings, "error", err) return res, err } } else { err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(offerings)) if err != nil { - logg.ErrorCtxf(ctx, "failed to write entry with", "key", common.DATA_TEMPORARY_VALUE, "value", offerings, "error", err) - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to write temporaryOfferings entry with", "key", common.DATA_TEMPORARY_VALUE, "value", offerings, "error", err) return res, err } } @@ -612,9 +595,7 @@ func (h *Handlers) SaveOfferings(ctx context.Context, sym string, input []byte) // ResetAllowUpdate resets the allowupdate flag that allows a user to update profile data. func (h *Handlers) ResetAllowUpdate(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result - flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update") - res.FlagReset = append(res.FlagReset, flag_allow_update) return res, nil } @@ -631,7 +612,6 @@ func (h *Handlers) ResetValidPin(ctx context.Context, sym string, input []byte) func (h *Handlers) ResetAccountAuthorized(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized") - res.FlagReset = append(res.FlagReset, flag_account_authorized) return res, nil } @@ -667,7 +647,7 @@ func (h *Handlers) Authorize(ctx context.Context, sym string, input []byte) (res store := h.userdataStore AccountPin, err := store.ReadEntry(ctx, sessionId, common.DATA_ACCOUNT_PIN) if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to read AccountPin entry with", "key", common.DATA_ACCOUNT_PIN, "error", err) return res, err } if len(input) == 4 { @@ -715,21 +695,19 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b store := h.userdataStore publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", common.DATA_PUBLIC_KEY, "error", err) return res, err } - r, err := h.accountService.TrackAccountStatus(ctx, string(publicKey)) + r, err := h.accountService.TrackAccountStatus(ctx, string(publicKey)) if err != nil { res.FlagSet = append(res.FlagSet, flag_api_error) - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed on TrackAccountStatus", err) return res, err } + res.FlagReset = append(res.FlagReset, flag_api_error) - if !ok { - log.Printf("Error: %s", err) - return res, err - } + if r.Active { res.FlagSet = append(res.FlagSet, flag_account_success) res.FlagReset = append(res.FlagReset, flag_account_pending) @@ -737,6 +715,7 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b res.FlagReset = append(res.FlagReset, flag_account_success) res.FlagSet = append(res.FlagSet, flag_account_pending) } + return res, nil } @@ -828,13 +807,13 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) ( return res, nil } - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to read activeSym entry with", "key", common.DATA_ACTIVE_SYM, "error", err) return res, err } activeBal, err := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_BAL) if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to read activeBal entry with", "key", common.DATA_ACTIVE_BAL, "error", err) return res, err } @@ -858,7 +837,7 @@ func (h *Handlers) FetchCustodialBalances(ctx context.Context, sym string, input store := h.userdataStore publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", common.DATA_PUBLIC_KEY, "error", err) return res, err } @@ -891,18 +870,19 @@ func (h *Handlers) ResetOthersPin(ctx context.Context, sym string, input []byte) } blockedPhonenumber, err := store.ReadEntry(ctx, sessionId, common.DATA_BLOCKED_NUMBER) if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to read blockedPhonenumber entry with", "key", common.DATA_BLOCKED_NUMBER, "error", err) return res, err } temporaryPin, err := store.ReadEntry(ctx, string(blockedPhonenumber), common.DATA_TEMPORARY_VALUE) if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to read temporaryPin entry with", "key", common.DATA_TEMPORARY_VALUE, "error", err) return res, err } err = store.WriteEntry(ctx, string(blockedPhonenumber), common.DATA_ACCOUNT_PIN, []byte(temporaryPin)) if err != nil { return res, nil } + return res, nil } @@ -931,11 +911,11 @@ func (h *Handlers) ValidateBlockedNumber(ctx context.Context, sym string, input } if err != nil { if db.IsNotFound(err) { - logg.Printf(logging.LVL_INFO, "Invalid or unregistered number") + logg.InfoCtxf(ctx, "Invalid or unregistered number") res.FlagSet = append(res.FlagSet, flag_unregistered_number) return res, nil } else { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "Error on ValidateBlockedNumber", "error", err) return res, err } } @@ -1043,7 +1023,7 @@ func (h *Handlers) MaxAmount(ctx context.Context, sym string, input []byte) (res activeBal, err := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_BAL) if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to read activeBal entry with", "key", common.DATA_ACTIVE_BAL, "error", err) return res, err } @@ -1069,12 +1049,12 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte) // retrieve the active balance activeBal, err := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_BAL) if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to read activeBal entry with", "key", common.DATA_ACTIVE_BAL, "error", err) return res, err } balanceValue, err = strconv.ParseFloat(string(activeBal), 64) if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "Failed to convert the activeBal to a float", "error", err) return res, err } @@ -1097,11 +1077,11 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte) formattedAmount := fmt.Sprintf("%.2f", inputAmount) err = store.WriteEntry(ctx, sessionId, common.DATA_AMOUNT, []byte(formattedAmount)) if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to write amount entry with", "key", common.DATA_AMOUNT, "value", formattedAmount, "error", err) return res, err } - res.Content = fmt.Sprintf("%s", formattedAmount) + res.Content = formattedAmount return res, nil } @@ -1164,7 +1144,7 @@ func (h *Handlers) GetAmount(ctx context.Context, sym string, input []byte) (res // retrieve the active symbol activeSym, err := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_SYM) if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to read activeSym entry with", "key", common.DATA_ACTIVE_SYM, "error", err) return res, err } @@ -1202,7 +1182,7 @@ func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input [] account_authorized_flag, err := h.flagManager.GetFlag("flag_account_authorized") if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "Failed to set the flag_account_authorized", "error", err) return res, err } @@ -1305,7 +1285,7 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by if db.IsNotFound(err) { publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", common.DATA_PUBLIC_KEY, "error", err) return res, err } @@ -1330,20 +1310,20 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by // set the active symbol err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_SYM, []byte(defaultSym)) if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to write defaultSym entry with", "key", common.DATA_ACTIVE_SYM, "value", defaultSym, "error", err) return res, err } // set the active balance err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_BAL, []byte(defaultBal)) if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to write defaultBal entry with", "key", common.DATA_ACTIVE_BAL, "value", defaultBal, "error", err) return res, err } return res, nil } - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed to read activeSym entry with", "key", common.DATA_ACTIVE_SYM, "error", err) return res, err } @@ -1364,7 +1344,8 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte) store := h.userdataStore publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) if err != nil { - return res, nil + logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", common.DATA_PUBLIC_KEY, "error", err) + return res, err } // Fetch vouchers from the API using the public key @@ -1399,7 +1380,7 @@ func (h *Handlers) GetVoucherList(ctx context.Context, sym string, input []byte) // Read vouchers from the store voucherData, err := h.prefixDb.Get(ctx, []byte("sym")) if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "Failed to read the voucherData from prefixDb", "error", err) return res, err } @@ -1435,7 +1416,7 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r } if err := common.StoreTemporaryVoucher(ctx, h.userdataStore, sessionId, metadata); err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed on StoreTemporaryVoucher", "error", err) return res, err } @@ -1457,13 +1438,13 @@ func (h *Handlers) SetVoucher(ctx context.Context, sym string, input []byte) (re // Get temporary data tempData, err := common.GetTemporaryVoucherData(ctx, h.userdataStore, sessionId) if err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed on GetTemporaryVoucherData", "error", err) return res, err } // Set as active and clear temporary data if err := common.UpdateVoucherData(ctx, h.userdataStore, sessionId, tempData); err != nil { - log.Printf("Error: %s", err) + logg.ErrorCtxf(ctx, "failed on UpdateVoucherData", "error", err) return res, err } From f97ad2a262ad326aeaf485787a490397013bbe64 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 14 Nov 2024 10:25:42 +0300 Subject: [PATCH 255/289] use 1 for retry --- services/registration/api_failure.vis | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/services/registration/api_failure.vis b/services/registration/api_failure.vis index e045355..78318f2 100644 --- a/services/registration/api_failure.vis +++ b/services/registration/api_failure.vis @@ -1,5 +1,6 @@ -MOUT retry 0 +MOUT retry 1 MOUT quit 9 HALT -INCMP _ 0 +INCMP _ 1 INCMP quit 9 + From f9e51618c5eb598632f3283da00a2132b7b122ef Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 14 Nov 2024 10:29:22 +0300 Subject: [PATCH 256/289] remove extra line --- services/registration/api_failure.vis | 1 - 1 file changed, 1 deletion(-) diff --git a/services/registration/api_failure.vis b/services/registration/api_failure.vis index 78318f2..37b3deb 100644 --- a/services/registration/api_failure.vis +++ b/services/registration/api_failure.vis @@ -3,4 +3,3 @@ MOUT quit 9 HALT INCMP _ 1 INCMP quit 9 - From 94d2e8203f9cb34c2451a320ac2514eb3469bfbe Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 14 Nov 2024 10:53:20 +0300 Subject: [PATCH 257/289] reload verify yob --- services/registration/edit_yob.vis | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/registration/edit_yob.vis b/services/registration/edit_yob.vis index a260531..6a5abe0 100644 --- a/services/registration/edit_yob.vis +++ b/services/registration/edit_yob.vis @@ -5,7 +5,8 @@ RELOAD get_current_profile_info MAP get_current_profile_info MOUT back 0 HALT -LOAD verify_yob 0 +LOAD verify_yob 6 +RELOAD verify_yob CATCH incorrect_date_format flag_incorrect_date_format 1 LOAD save_yob 0 RELOAD save_yob From 381e581e8ef855852d6aa909248c1934189f7b72 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Thu, 14 Nov 2024 11:00:12 +0300 Subject: [PATCH 258/289] add terminal logs --- internal/handlers/ussd/menuhandler.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 7d1db1e..31d0e30 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -1217,6 +1217,7 @@ func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input res.Content = "Not provided" break } + logg.ErrorCtxf(ctx, "Failed to read first name entry with", "key", "error", common.DATA_FIRST_NAME, err) return res, err } res.Content = string(profileInfo) @@ -1227,6 +1228,7 @@ func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input res.Content = "Not provided" break } + logg.ErrorCtxf(ctx, "Failed to read family name entry with", "key", "error", common.DATA_FAMILY_NAME, err) return res, err } res.Content = string(profileInfo) @@ -1238,6 +1240,7 @@ func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input res.Content = "Not provided" break } + logg.ErrorCtxf(ctx, "Failed to read gender entry with", "key", "error", common.DATA_GENDER, err) return res, err } res.Content = string(profileInfo) @@ -1248,6 +1251,7 @@ func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input res.Content = "Not provided" break } + logg.ErrorCtxf(ctx, "Failed to read year of birth(yob) entry with", "key", "error", common.DATA_YOB, err) return res, err } res.Content = string(profileInfo) @@ -1259,6 +1263,7 @@ func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input res.Content = "Not provided" break } + logg.ErrorCtxf(ctx, "Failed to read location entry with", "key", "error", common.DATA_LOCATION, err) return res, err } res.Content = string(profileInfo) @@ -1269,6 +1274,7 @@ func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input res.Content = "Not provided" break } + logg.ErrorCtxf(ctx, "Failed to read offerings entry with", "key", "error", common.DATA_OFFERINGS, err) return res, err } res.Content = string(profileInfo) From 93df6a6a08d5f6c21ee67c1848a4336a0f318465 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 14 Nov 2024 14:59:39 +0300 Subject: [PATCH 259/289] validate recipients and invite valid ones --- internal/handlers/handlerservice.go | 1 + internal/handlers/ussd/menuhandler.go | 58 +++++++++++++++++++-- services/registration/invalid_recipient | 2 +- services/registration/invalid_recipient_swa | 2 +- services/registration/invite_menu | 1 + services/registration/invite_menu_swa | 1 + services/registration/invite_recipient | 1 + services/registration/invite_recipient.vis | 8 +++ services/registration/invite_recipient_swa | 1 + services/registration/invite_result.vis | 2 + services/registration/locale/swa/default.po | 6 +++ services/registration/send.vis | 2 + 12 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 services/registration/invite_menu create mode 100644 services/registration/invite_menu_swa create mode 100644 services/registration/invite_recipient create mode 100644 services/registration/invite_recipient.vis create mode 100644 services/registration/invite_recipient_swa create mode 100644 services/registration/invite_result.vis diff --git a/internal/handlers/handlerservice.go b/internal/handlers/handlerservice.go index 7a1e912..358d492 100644 --- a/internal/handlers/handlerservice.go +++ b/internal/handlers/handlerservice.go @@ -80,6 +80,7 @@ func (ls *LocalHandlerService) GetHandler(accountService remote.AccountServiceIn ls.DbRs.AddLocalFunc("check_balance", ussdHandlers.CheckBalance) ls.DbRs.AddLocalFunc("validate_recipient", ussdHandlers.ValidateRecipient) ls.DbRs.AddLocalFunc("transaction_reset", ussdHandlers.TransactionReset) + ls.DbRs.AddLocalFunc("invite_valid_recipient", ussdHandlers.InviteValidRecipient) ls.DbRs.AddLocalFunc("max_amount", ussdHandlers.MaxAmount) ls.DbRs.AddLocalFunc("validate_amount", ussdHandlers.ValidateAmount) ls.DbRs.AddLocalFunc("reset_transaction_amount", ussdHandlers.ResetTransactionAmount) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 31d0e30..138ebca 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -929,7 +929,7 @@ func (h *Handlers) ValidateBlockedNumber(ctx context.Context, sym string, input // ValidateRecipient validates that the given input is a valid phone number. func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result - var err error + store := h.userdataStore sessionId, ok := ctx.Value("SessionId").(string) if !ok { @@ -939,18 +939,41 @@ func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []by recipient := string(input) flag_invalid_recipient, _ := h.flagManager.GetFlag("flag_invalid_recipient") + flag_invalid_recipient_with_invite, _ := h.flagManager.GetFlag("flag_invalid_recipient_with_invite") if recipient != "0" { - // mimic invalid number check - if recipient == "000" { + if !isValidPhoneNumber(recipient) { res.FlagSet = append(res.FlagSet, flag_invalid_recipient) res.Content = recipient return res, nil } - store := h.userdataStore - err = store.WriteEntry(ctx, sessionId, common.DATA_RECIPIENT, []byte(recipient)) + + publicKey, err := store.ReadEntry(ctx, recipient, common.DATA_PUBLIC_KEY) if err != nil { + if db.IsNotFound(err) { + logg.InfoCtxf(ctx, "Unregistered number") + + // save the recipient as the temporaryInvitedNumber + err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(recipient)) + if err != nil { + logg.ErrorCtxf(ctx, "failed to write temporaryInvitedNumber entry with", "key", common.DATA_TEMPORARY_VALUE, "value", recipient, "error", err) + return res, err + } + + res.FlagSet = append(res.FlagSet, flag_invalid_recipient_with_invite) + res.Content = recipient + + return res, nil + } + + logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", common.DATA_PUBLIC_KEY, "error", err) + return res, err + } + + err = store.WriteEntry(ctx, sessionId, common.DATA_RECIPIENT, publicKey) + if err != nil { + logg.ErrorCtxf(ctx, "failed to write recipient entry with", "key", common.DATA_RECIPIENT, "value", string(publicKey), "error", err) return res, nil } } @@ -987,6 +1010,31 @@ func (h *Handlers) TransactionReset(ctx context.Context, sym string, input []byt return res, nil } +// InviteValidRecipient sends an invitation to the valid phone number. +func (h *Handlers) InviteValidRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) { + var res resource.Result + store := h.userdataStore + + sessionId, ok := ctx.Value("SessionId").(string) + if !ok { + return res, fmt.Errorf("missing session") + } + + code := codeFromCtx(ctx) + l := gotext.NewLocale(translationDir, code) + l.AddDomain("default") + + recipient, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) + + // TODO + // send an invitation SMS + // if successful + // res.Content = l.Get("Your invitation to %s to join Sarafu Network has been sent.", string(recipient)) + + res.Content = l.Get("Your invite request for %s to Sarafu Network failed. Please try again later.", string(recipient)) + return res, nil +} + // 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 diff --git a/services/registration/invalid_recipient b/services/registration/invalid_recipient index 0be78bd..d9fcb1d 100644 --- a/services/registration/invalid_recipient +++ b/services/registration/invalid_recipient @@ -1 +1 @@ -{{.validate_recipient}} is not registered or invalid, please try again: \ No newline at end of file +{{.validate_recipient}} is invalid, please try again: \ No newline at end of file diff --git a/services/registration/invalid_recipient_swa b/services/registration/invalid_recipient_swa index 39e7804..13dda97 100644 --- a/services/registration/invalid_recipient_swa +++ b/services/registration/invalid_recipient_swa @@ -1 +1 @@ -{{.validate_recipient}} haijasajiliwa au sio sahihi, tafadhali weka tena: \ No newline at end of file +{{.validate_recipient}} sio sahihi, tafadhali weka tena: \ No newline at end of file diff --git a/services/registration/invite_menu b/services/registration/invite_menu new file mode 100644 index 0000000..e44862a --- /dev/null +++ b/services/registration/invite_menu @@ -0,0 +1 @@ +Invite to Sarafu Network \ No newline at end of file diff --git a/services/registration/invite_menu_swa b/services/registration/invite_menu_swa new file mode 100644 index 0000000..48c0ddf --- /dev/null +++ b/services/registration/invite_menu_swa @@ -0,0 +1 @@ +Karibisha kwa matandao wa Sarafu \ No newline at end of file diff --git a/services/registration/invite_recipient b/services/registration/invite_recipient new file mode 100644 index 0000000..aa3438d --- /dev/null +++ b/services/registration/invite_recipient @@ -0,0 +1 @@ +{{.validate_recipient}} is not registered, please try again: \ No newline at end of file diff --git a/services/registration/invite_recipient.vis b/services/registration/invite_recipient.vis new file mode 100644 index 0000000..1a4845f --- /dev/null +++ b/services/registration/invite_recipient.vis @@ -0,0 +1,8 @@ +MAP validate_recipient +MOUT retry 1 +MOUT invite 2 +MOUT quit 9 +HALT +INCMP _ 1 +INCMP invite_result 2 +INCMP quit 9 diff --git a/services/registration/invite_recipient_swa b/services/registration/invite_recipient_swa new file mode 100644 index 0000000..30cf599 --- /dev/null +++ b/services/registration/invite_recipient_swa @@ -0,0 +1 @@ +{{.validate_recipient}} haijasajiliwa, tafadhali weka tena: \ No newline at end of file diff --git a/services/registration/invite_result.vis b/services/registration/invite_result.vis new file mode 100644 index 0000000..5f31749 --- /dev/null +++ b/services/registration/invite_result.vis @@ -0,0 +1,2 @@ +LOAD invite_valid_recipient 0 +HALT diff --git a/services/registration/locale/swa/default.po b/services/registration/locale/swa/default.po index ba9a9bb..3e5213c 100644 --- a/services/registration/locale/swa/default.po +++ b/services/registration/locale/swa/default.po @@ -12,3 +12,9 @@ msgstr "Kwa usaidizi zaidi,piga: 0757628885" msgid "Balance: %s\n" msgstr "Salio: %s\n" + +msid "Your invite request for %s to Sarafu Network failed. Please try again later." +msgstr "Ombi lako la kumwalika %s kwa matandao wa Sarafu halikufaulu. Tafadhali jaribu tena baadaye." + +msgid "Your invitation to %s to join Sarafu Network has been sent." +msgstr "Ombi lako la kumwalika %s kwa matandao wa Sarafu limetumwa." diff --git a/services/registration/send.vis b/services/registration/send.vis index 0ff0927..8928725 100644 --- a/services/registration/send.vis +++ b/services/registration/send.vis @@ -1,9 +1,11 @@ LOAD transaction_reset 0 +RELOAD transaction_reset CATCH no_voucher flag_no_active_voucher 1 MOUT back 0 HALT LOAD validate_recipient 20 RELOAD validate_recipient CATCH invalid_recipient flag_invalid_recipient 1 +CATCH invite_recipient flag_invalid_recipient_with_invite 1 INCMP _ 0 INCMP amount * From 9d2d01e3e21e311195ec77bc370bf7bb8b29c21d Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 14 Nov 2024 17:30:13 +0300 Subject: [PATCH 260/289] save the recipient number in DATA_TEMPORARY_VALUE --- internal/handlers/ussd/menuhandler.go | 24 +++++++++++------------- services/registration/amount.vis | 4 ++-- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 138ebca..055a314 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -929,6 +929,7 @@ func (h *Handlers) ValidateBlockedNumber(ctx context.Context, sym string, input // ValidateRecipient validates that the given input is a valid phone number. func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result + var err error store := h.userdataStore sessionId, ok := ctx.Value("SessionId").(string) @@ -949,18 +950,18 @@ func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []by return res, nil } + // save the recipient as the temporaryRecipient + err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(recipient)) + if err != nil { + logg.ErrorCtxf(ctx, "failed to write temporaryRecipient entry with", "key", common.DATA_TEMPORARY_VALUE, "value", recipient, "error", err) + return res, err + } + publicKey, err := store.ReadEntry(ctx, recipient, common.DATA_PUBLIC_KEY) if err != nil { if db.IsNotFound(err) { logg.InfoCtxf(ctx, "Unregistered number") - // save the recipient as the temporaryInvitedNumber - err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(recipient)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write temporaryInvitedNumber entry with", "key", common.DATA_TEMPORARY_VALUE, "value", recipient, "error", err) - return res, err - } - res.FlagSet = append(res.FlagSet, flag_invalid_recipient_with_invite) res.Content = recipient @@ -1133,7 +1134,7 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte) return res, nil } -// GetRecipient returns the transaction recipient from the gdbm. +// GetRecipient returns the transaction recipient phone number from the gdbm. func (h *Handlers) GetRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result @@ -1142,7 +1143,7 @@ func (h *Handlers) GetRecipient(ctx context.Context, sym string, input []byte) ( return res, fmt.Errorf("missing session") } store := h.userdataStore - recipient, _ := store.ReadEntry(ctx, sessionId, common.DATA_RECIPIENT) + recipient, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) res.Content = string(recipient) @@ -1219,11 +1220,8 @@ func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input [] // TODO // Use the amount, recipient and sender to call the API and initialize the transaction store := h.userdataStore - amount, _ := store.ReadEntry(ctx, sessionId, common.DATA_AMOUNT) - - recipient, _ := store.ReadEntry(ctx, sessionId, common.DATA_RECIPIENT) - + recipient, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) activeSym, _ := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_SYM) res.Content = l.Get("Your request has been sent. %s will receive %s %s from %s.", string(recipient), string(amount), string(activeSym), string(sessionId)) diff --git a/services/registration/amount.vis b/services/registration/amount.vis index 82e1fd4..2266160 100644 --- a/services/registration/amount.vis +++ b/services/registration/amount.vis @@ -6,10 +6,10 @@ MOUT back 0 HALT LOAD validate_amount 64 RELOAD validate_amount -CATCH api_failure flag_api_call_error 1 +CATCH api_failure flag_api_call_error 1 CATCH invalid_amount flag_invalid_amount 1 INCMP _ 0 -LOAD get_recipient 12 +LOAD get_recipient 0 LOAD get_sender 64 LOAD get_amount 32 INCMP transaction_pin * From f3e3badff68044c04ac96badd8b33b49582bd1d4 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 14 Nov 2024 17:31:17 +0300 Subject: [PATCH 261/289] save the entire voucher data when setting the default voucher --- internal/handlers/ussd/menuhandler.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 055a314..68580c2 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -1447,6 +1447,8 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by firstVoucher := vouchersResp[0] defaultSym := firstVoucher.TokenSymbol defaultBal := firstVoucher.Balance + defaultDec := firstVoucher.TokenDecimals + defaultAddr := firstVoucher.ContractAddress // set the active symbol err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_SYM, []byte(defaultSym)) @@ -1460,6 +1462,18 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by logg.ErrorCtxf(ctx, "failed to write defaultBal entry with", "key", common.DATA_ACTIVE_BAL, "value", defaultBal, "error", err) return res, err } + // set the active decimals + err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_DECIMAL, []byte(defaultDec)) + if err != nil { + logg.ErrorCtxf(ctx, "failed to write defaultDec entry with", "key", common.DATA_ACTIVE_DECIMAL, "value", defaultDec, "error", err) + return res, err + } + // set the active contract address + err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_ADDRESS, []byte(defaultAddr)) + if err != nil { + logg.ErrorCtxf(ctx, "failed to write defaultAddr entry with", "key", common.DATA_ACTIVE_ADDRESS, "value", defaultAddr, "error", err) + return res, err + } return res, nil } From fabcccfa6048d5eeec89a094d5bec2b7c6807778 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 14 Nov 2024 19:35:44 +0300 Subject: [PATCH 262/289] added the tokenTransfer url --- config/config.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/config.go b/config/config.go index c4445eb..0d39e6e 100644 --- a/config/config.go +++ b/config/config.go @@ -11,6 +11,7 @@ const ( trackStatusPath = "/api/track" balancePathPrefix = "/api/account" trackPath = "/api/v2/account/status" + tokenTransferPrefix = "/api/v2/token/transfer" voucherHoldingsPathPrefix = "/api/v1/holdings" voucherTransfersPathPrefix = "/api/v1/transfers/last10" voucherDataPathPrefix = "/api/v1/token" @@ -28,6 +29,7 @@ var ( TrackStatusURL string BalanceURL string TrackURL string + TokenTransferURL string VoucherHoldingsURL string VoucherTransfersURL string VoucherDataURL string @@ -62,6 +64,7 @@ func LoadConfig() error { TrackStatusURL, _ = url.JoinPath(custodialURLBase, trackStatusPath) BalanceURL, _ = url.JoinPath(custodialURLBase, balancePathPrefix) TrackURL, _ = url.JoinPath(custodialURLBase, trackPath) + TokenTransferURL, _ = url.JoinPath(custodialURLBase, tokenTransferPrefix) VoucherHoldingsURL, _ = url.JoinPath(dataURLBase, voucherHoldingsPathPrefix) VoucherTransfersURL, _ = url.JoinPath(dataURLBase, voucherTransfersPathPrefix) VoucherDataURL, _ = url.JoinPath(dataURLBase, voucherDataPathPrefix) From c10e1a6a1ba6dde3d2bbcf674403faaad6d746ea Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 14 Nov 2024 19:36:30 +0300 Subject: [PATCH 263/289] added the TokenTransferResponse model --- models/token_transfer_response.go | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 models/token_transfer_response.go diff --git a/models/token_transfer_response.go b/models/token_transfer_response.go new file mode 100644 index 0000000..b4d6dc3 --- /dev/null +++ b/models/token_transfer_response.go @@ -0,0 +1,5 @@ +package models + +type TokenTransferResponse struct { + TrackingId string `json:"trackingId"` +} From c34906cb1f9fe4ec602a10819b4e7cef6110c539 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 14 Nov 2024 20:02:48 +0300 Subject: [PATCH 264/289] added the TokenTransfer functionality and mocks --- internal/testutil/mocks/servicemock.go | 8 +++-- .../testservice/TestAccountService.go | 18 ++++++---- remote/accountservice.go | 36 +++++++++++++++++++ 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/internal/testutil/mocks/servicemock.go b/internal/testutil/mocks/servicemock.go index 76803ba..a25f1ae 100644 --- a/internal/testutil/mocks/servicemock.go +++ b/internal/testutil/mocks/servicemock.go @@ -28,7 +28,6 @@ func (m *MockAccountService) TrackAccountStatus(ctx context.Context, trackingId return args.Get(0).(*models.TrackStatusResult), args.Error(1) } - func (m *MockAccountService) FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) { args := m.Called(publicKey) return args.Get(0).([]dataserviceapi.TokenHoldings), args.Error(1) @@ -39,7 +38,12 @@ func (m *MockAccountService) FetchTransactions(ctx context.Context, publicKey st return args.Get(0).([]dataserviceapi.Last10TxResponse), args.Error(1) } -func(m MockAccountService) VoucherData(ctx context.Context, address string) (*models.VoucherDataResult, error) { +func (m *MockAccountService) VoucherData(ctx context.Context, address string) (*models.VoucherDataResult, error) { args := m.Called(address) return args.Get(0).(*models.VoucherDataResult), args.Error(1) } + +func (m *MockAccountService) TokenTransfer(ctx context.Context, amount, from, to, tokenAddress string) (*models.TokenTransferResponse, error) { + args := m.Called() + return args.Get(0).(*models.TokenTransferResponse), args.Error(1) +} diff --git a/internal/testutil/testservice/TestAccountService.go b/internal/testutil/testservice/TestAccountService.go index 8752d6f..7c486f3 100644 --- a/internal/testutil/testservice/TestAccountService.go +++ b/internal/testutil/testservice/TestAccountService.go @@ -12,14 +12,14 @@ type TestAccountService struct { } func (tas *TestAccountService) CreateAccount(ctx context.Context) (*models.AccountResult, error) { - return &models.AccountResult { + return &models.AccountResult{ TrackingId: "075ccc86-f6ef-4d33-97d5-e91cfb37aa0d", - PublicKey: "0x623EFAFa8868df4B934dd12a8B26CB3Dd75A7AdD", + PublicKey: "0x623EFAFa8868df4B934dd12a8B26CB3Dd75A7AdD", }, nil } func (tas *TestAccountService) CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResult, error) { - balanceResponse := &models.BalanceResult { + balanceResponse := &models.BalanceResult{ Balance: "0.003 CELO", Nonce: json.Number("0"), } @@ -27,7 +27,7 @@ func (tas *TestAccountService) CheckBalance(ctx context.Context, publicKey strin } func (tas *TestAccountService) TrackAccountStatus(ctx context.Context, publicKey string) (*models.TrackStatusResult, error) { - return &models.TrackStatusResult { + return &models.TrackStatusResult{ Active: true, }, nil } @@ -40,13 +40,19 @@ func (tas *TestAccountService) FetchVouchers(ctx context.Context, publicKey stri TokenDecimals: "6", Balance: "2745987", }, - }, nil + }, nil } func (tas *TestAccountService) FetchTransactions(ctx context.Context, publicKey string) ([]dataserviceapi.Last10TxResponse, error) { return []dataserviceapi.Last10TxResponse{}, nil } -func(m TestAccountService) VoucherData(ctx context.Context, address string) (*models.VoucherDataResult, error) { +func (m TestAccountService) VoucherData(ctx context.Context, address string) (*models.VoucherDataResult, error) { return &models.VoucherDataResult{}, nil } + +func (tas *TestAccountService) TokenTransfer(ctx context.Context, amount, from, to, tokenAddress string) (*models.TokenTransferResponse, error) { + return &models.TokenTransferResponse{ + TrackingId: "e034d147-747d-42ea-928d-b5a7cb3426af", + }, nil +} diff --git a/remote/accountservice.go b/remote/accountservice.go index 19914cd..3af1ab1 100644 --- a/remote/accountservice.go +++ b/remote/accountservice.go @@ -23,6 +23,7 @@ type AccountServiceInterface interface { FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) FetchTransactions(ctx context.Context, publicKey string) ([]dataserviceapi.Last10TxResponse, error) VoucherData(ctx context.Context, address string) (*models.VoucherDataResult, error) + TokenTransfer(ctx context.Context, amount, from, to, tokenAddress string) (*models.TokenTransferResponse, error) } type AccountService struct { @@ -167,6 +168,41 @@ func (as *AccountService) VoucherData(ctx context.Context, address string) (*mod return &voucherDataResult, err } +// TokenTransfer creates a new token transfer in the custodial system. +// Returns: +// - *models.TokenTransferResponse: A pointer to an TokenTransferResponse struct containing the trackingId. +// 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) TokenTransfer(ctx context.Context, amount, from, to, tokenAddress string) (*models.TokenTransferResponse, error) { + var r models.TokenTransferResponse + + // Create request payload + payload := map[string]string{ + "amount": amount, + "from": from, + "to": to, + "tokenAddress": tokenAddress, + } + + payloadBytes, err := json.Marshal(payload) + if err != nil { + return nil, err + } + + // Create a new request + req, err := http.NewRequest("POST", config.TokenTransferURL, bytes.NewBuffer(payloadBytes)) + if err != nil { + return nil, err + } + _, err = doCustodialRequest(ctx, req, &r) + if err != nil { + return nil, err + } + + return &r, nil +} + func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { var okResponse api.OKResponse var errResponse api.ErrResponse From 7985b20200f34f75c494aaef4b7ca7730ffe32f0 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 14 Nov 2024 20:09:50 +0300 Subject: [PATCH 265/289] added message string for failed transaction --- services/registration/locale/swa/default.po | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/registration/locale/swa/default.po b/services/registration/locale/swa/default.po index 3e5213c..f933dde 100644 --- a/services/registration/locale/swa/default.po +++ b/services/registration/locale/swa/default.po @@ -18,3 +18,6 @@ msgstr "Ombi lako la kumwalika %s kwa matandao wa Sarafu halikufaulu. Tafadhali msgid "Your invitation to %s to join Sarafu Network has been sent." msgstr "Ombi lako la kumwalika %s kwa matandao wa Sarafu limetumwa." + +msgid "Your request failed. Please try again later." +msgstr "Ombi lako halikufaulu. Tafadhali jaribu tena baadaye." From 5773305785e9a761a8751965a961bae410961620 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 14 Nov 2024 20:10:48 +0300 Subject: [PATCH 266/289] parse data and initialize a transaction --- internal/handlers/ussd/menuhandler.go | 49 ++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 68580c2..00c6ad7 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "math/big" "path" "regexp" "strconv" @@ -702,7 +703,7 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b r, err := h.accountService.TrackAccountStatus(ctx, string(publicKey)) if err != nil { res.FlagSet = append(res.FlagSet, flag_api_error) - logg.ErrorCtxf(ctx, "failed on TrackAccountStatus", err) + logg.ErrorCtxf(ctx, "failed on TrackAccountStatus", "error", err) return res, err } @@ -1214,24 +1215,56 @@ func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input [] return res, fmt.Errorf("missing session") } + flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") + account_authorized_flag, _ := h.flagManager.GetFlag("flag_account_authorized") + code := codeFromCtx(ctx) l := gotext.NewLocale(translationDir, code) l.AddDomain("default") - // TODO - // Use the amount, recipient and sender to call the API and initialize the transaction + store := h.userdataStore - amount, _ := store.ReadEntry(ctx, sessionId, common.DATA_AMOUNT) - recipient, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) + recipientNumber, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) activeSym, _ := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_SYM) - res.Content = l.Get("Your request has been sent. %s will receive %s %s from %s.", string(recipient), string(amount), string(activeSym), string(sessionId)) + storedAmount, _ := store.ReadEntry(ctx, sessionId, common.DATA_AMOUNT) + fromAddress, _ := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) + toAddress, _ := store.ReadEntry(ctx, sessionId, common.DATA_RECIPIENT) + activeDecimal, _ := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_DECIMAL) + tokenAddress, _ := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_ADDRESS) - account_authorized_flag, err := h.flagManager.GetFlag("flag_account_authorized") + // Parse tokendecimal + tokenDecimal, err := strconv.Atoi(string(activeDecimal)) if err != nil { - logg.ErrorCtxf(ctx, "Failed to set the flag_account_authorized", "error", err) return res, err } + // Parse amount and scale it + amount, _, err := big.ParseFloat(string(storedAmount), 10, 0, big.ToZero) + if err != nil { + return res, err + } + + multiplier := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(tokenDecimal)), nil)) + finalAmount := new(big.Float).Mul(amount, multiplier) + + // Convert finalAmount to a string + finalAmountStr := new(big.Int) + finalAmount.Int(finalAmountStr) + + // Call TokenTransfer + r, err := h.accountService.TokenTransfer(ctx, finalAmountStr.String(), string(fromAddress), string(toAddress), string(tokenAddress)) + if err != nil { + res.Content = l.Get("Your request failed. Please try again later.") + res.FlagSet = append(res.FlagSet, flag_api_error) + logg.ErrorCtxf(ctx, "failed on TokenTransfer", "error", err) + return res, err + } + + trackingId := r.TrackingId + logg.InfoCtxf(ctx, "TokenTransfer", "trackingId", trackingId) + + res.Content = l.Get("Your request has been sent. %s will receive %s %s from %s.", string(recipientNumber), string(storedAmount), string(activeSym), string(sessionId)) + res.FlagReset = append(res.FlagReset, account_authorized_flag) return res, nil } From de5ecc5fe76fb9d0c07be99d21f1bb315d5a3cdb Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 14 Nov 2024 21:21:04 +0300 Subject: [PATCH 267/289] add the tokens functionality to the common package --- common/tokens.go | 54 +++++++++++++++++++++++++++ internal/handlers/ussd/menuhandler.go | 49 +++++++++--------------- 2 files changed, 71 insertions(+), 32 deletions(-) create mode 100644 common/tokens.go diff --git a/common/tokens.go b/common/tokens.go new file mode 100644 index 0000000..727cbea --- /dev/null +++ b/common/tokens.go @@ -0,0 +1,54 @@ +package common + +import ( + "context" + "math/big" + "strconv" +) + +func ParseAndScaleAmount(storedAmount, activeDecimal []byte) (string, error) { + // Parse token decimal + tokenDecimal, err := strconv.Atoi(string(activeDecimal)) + if err != nil { + + return "", err + } + + // Parse amount + amount, _, err := big.ParseFloat(string(storedAmount), 10, 0, big.ToZero) + if err != nil { + return "", err + } + + // Scale the amount + multiplier := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(tokenDecimal)), nil)) + finalAmount := new(big.Float).Mul(amount, multiplier) + + // Convert finalAmount to a string + finalAmountStr := new(big.Int) + finalAmount.Int(finalAmountStr) + + return finalAmountStr.String(), nil +} + +func ReadTransactionData(ctx context.Context, store DataStore, sessionId string) (map[DataTyp][]byte, error) { + dataKeys := []DataTyp{ + DATA_TEMPORARY_VALUE, + DATA_ACTIVE_SYM, + DATA_AMOUNT, + DATA_PUBLIC_KEY, + DATA_RECIPIENT, + DATA_ACTIVE_DECIMAL, + DATA_ACTIVE_ADDRESS, + } + + data := make(map[DataTyp][]byte) + for _, key := range dataKeys { + value, err := store.ReadEntry(ctx, sessionId, key) + if err != nil { + return nil, err + } + data[key] = value + } + return data, nil +} diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 00c6ad7..d2411bd 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "fmt" - "math/big" "path" "regexp" "strconv" @@ -1176,7 +1175,7 @@ func (h *Handlers) GetSender(ctx context.Context, sym string, input []byte) (res return res, fmt.Errorf("missing session") } - res.Content = string(sessionId) + res.Content = sessionId return res, nil } @@ -1205,8 +1204,7 @@ func (h *Handlers) GetAmount(ctx context.Context, sym string, input []byte) (res return res, nil } -// InitiateTransaction returns a confirmation and resets the transaction data -// on the gdbm store. +// 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 @@ -1215,57 +1213,44 @@ func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input [] return res, fmt.Errorf("missing session") } - flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") - account_authorized_flag, _ := h.flagManager.GetFlag("flag_account_authorized") + flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized") code := codeFromCtx(ctx) l := gotext.NewLocale(translationDir, code) l.AddDomain("default") - store := h.userdataStore - recipientNumber, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE) - activeSym, _ := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_SYM) - - storedAmount, _ := store.ReadEntry(ctx, sessionId, common.DATA_AMOUNT) - fromAddress, _ := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) - toAddress, _ := store.ReadEntry(ctx, sessionId, common.DATA_RECIPIENT) - activeDecimal, _ := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_DECIMAL) - tokenAddress, _ := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_ADDRESS) - - // Parse tokendecimal - tokenDecimal, err := strconv.Atoi(string(activeDecimal)) + data, err := common.ReadTransactionData(ctx, h.userdataStore, sessionId) if err != nil { return res, err } - // Parse amount and scale it - amount, _, err := big.ParseFloat(string(storedAmount), 10, 0, big.ToZero) + finalAmountStr, err := common.ParseAndScaleAmount(data[common.DATA_AMOUNT], data[common.DATA_ACTIVE_DECIMAL]) if err != nil { return res, err } - multiplier := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(tokenDecimal)), nil)) - finalAmount := new(big.Float).Mul(amount, multiplier) - - // Convert finalAmount to a string - finalAmountStr := new(big.Int) - finalAmount.Int(finalAmountStr) - // Call TokenTransfer - r, err := h.accountService.TokenTransfer(ctx, finalAmountStr.String(), string(fromAddress), string(toAddress), string(tokenAddress)) + r, err := h.accountService.TokenTransfer(ctx, finalAmountStr, string(data[common.DATA_PUBLIC_KEY]), string(data[common.DATA_RECIPIENT]), string(data[common.DATA_ACTIVE_ADDRESS])) if err != nil { - res.Content = l.Get("Your request failed. Please try again later.") + flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") res.FlagSet = append(res.FlagSet, flag_api_error) + res.Content = l.Get("Your request failed. Please try again later.") logg.ErrorCtxf(ctx, "failed on TokenTransfer", "error", err) - return res, err + return res, nil } trackingId := r.TrackingId logg.InfoCtxf(ctx, "TokenTransfer", "trackingId", trackingId) - res.Content = l.Get("Your request has been sent. %s will receive %s %s from %s.", string(recipientNumber), string(storedAmount), string(activeSym), string(sessionId)) + res.Content = l.Get( + "Your request has been sent. %s will receive %s %s from %s.", + string(data[common.DATA_TEMPORARY_VALUE]), + string(data[common.DATA_AMOUNT]), + string(data[common.DATA_ACTIVE_SYM]), + sessionId, + ) - res.FlagReset = append(res.FlagReset, account_authorized_flag) + res.FlagReset = append(res.FlagReset, flag_account_authorized) return res, nil } From cb13b0929192f6f5ad91304d5f52736111bd214f Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 15 Nov 2024 08:42:44 +0300 Subject: [PATCH 268/289] remove commented code --- common/vouchers.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/common/vouchers.go b/common/vouchers.go index dd8852e..54ace28 100644 --- a/common/vouchers.go +++ b/common/vouchers.go @@ -37,15 +37,6 @@ func ProcessVouchers(holdings []dataserviceapi.TokenHoldings) VoucherMetadata { return data } -//func StoreVouchers(db storage.PrefixDb, data VoucherMetadata) { -// value, err := db.Put(ctx, []byte(key)) -// if err != nil { -// return nil, fmt.Errorf("failed to get %s: %v", key, err) -// } -// data[key] = string(value) -// } -//} - // GetVoucherData retrieves and matches voucher data func GetVoucherData(ctx context.Context, db storage.PrefixDb, input string) (*dataserviceapi.TokenHoldings, error) { keys := []string{"sym", "bal", "deci", "addr"} From 1a0b4deab3aea25f7dbedb352fd6cf00af0b6476 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 15 Nov 2024 09:20:19 +0300 Subject: [PATCH 269/289] added the TransactionData struct to organiza the data --- common/tokens.go | 63 +++++++++++++++++++-------- internal/handlers/ussd/menuhandler.go | 10 ++--- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/common/tokens.go b/common/tokens.go index 727cbea..466f370 100644 --- a/common/tokens.go +++ b/common/tokens.go @@ -2,20 +2,32 @@ package common import ( "context" + "errors" "math/big" + "reflect" "strconv" ) -func ParseAndScaleAmount(storedAmount, activeDecimal []byte) (string, error) { +type TransactionData struct { + TemporaryValue string + ActiveSym string + Amount string + PublicKey string + Recipient string + ActiveDecimal string + ActiveAddress string +} + +func ParseAndScaleAmount(storedAmount, activeDecimal string) (string, error) { // Parse token decimal - tokenDecimal, err := strconv.Atoi(string(activeDecimal)) + tokenDecimal, err := strconv.Atoi(activeDecimal) if err != nil { return "", err } // Parse amount - amount, _, err := big.ParseFloat(string(storedAmount), 10, 0, big.ToZero) + amount, _, err := big.ParseFloat(storedAmount, 10, 0, big.ToZero) if err != nil { return "", err } @@ -31,24 +43,39 @@ func ParseAndScaleAmount(storedAmount, activeDecimal []byte) (string, error) { return finalAmountStr.String(), nil } -func ReadTransactionData(ctx context.Context, store DataStore, sessionId string) (map[DataTyp][]byte, error) { - dataKeys := []DataTyp{ - DATA_TEMPORARY_VALUE, - DATA_ACTIVE_SYM, - DATA_AMOUNT, - DATA_PUBLIC_KEY, - DATA_RECIPIENT, - DATA_ACTIVE_DECIMAL, - DATA_ACTIVE_ADDRESS, +func ReadTransactionData(ctx context.Context, store DataStore, sessionId string) (TransactionData, error) { + data := TransactionData{} + fieldToKey := map[string]DataTyp{ + "TemporaryValue": DATA_TEMPORARY_VALUE, + "ActiveSym": DATA_ACTIVE_SYM, + "Amount": DATA_AMOUNT, + "PublicKey": DATA_PUBLIC_KEY, + "Recipient": DATA_RECIPIENT, + "ActiveDecimal": DATA_ACTIVE_DECIMAL, + "ActiveAddress": DATA_ACTIVE_ADDRESS, } - data := make(map[DataTyp][]byte) - for _, key := range dataKeys { - value, err := store.ReadEntry(ctx, sessionId, key) - if err != nil { - return nil, err + v := reflect.ValueOf(&data).Elem() + for fieldName, key := range fieldToKey { + field := v.FieldByName(fieldName) + if !field.IsValid() || !field.CanSet() { + return data, errors.New("invalid struct field: " + fieldName) } - data[key] = value + + value, err := readStringEntry(ctx, store, sessionId, key) + if err != nil { + return data, err + } + field.SetString(value) } + return data, nil } + +func readStringEntry(ctx context.Context, store DataStore, sessionId string, key DataTyp) (string, error) { + entry, err := store.ReadEntry(ctx, sessionId, key) + if err != nil { + return "", err + } + return string(entry), nil +} diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index d2411bd..0b9360f 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -1224,13 +1224,13 @@ func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input [] return res, err } - finalAmountStr, err := common.ParseAndScaleAmount(data[common.DATA_AMOUNT], data[common.DATA_ACTIVE_DECIMAL]) + finalAmountStr, err := common.ParseAndScaleAmount(data.Amount, data.ActiveDecimal) if err != nil { return res, err } // Call TokenTransfer - r, err := h.accountService.TokenTransfer(ctx, finalAmountStr, string(data[common.DATA_PUBLIC_KEY]), string(data[common.DATA_RECIPIENT]), string(data[common.DATA_ACTIVE_ADDRESS])) + r, err := h.accountService.TokenTransfer(ctx, finalAmountStr, data.PublicKey, data.Recipient, data.ActiveAddress) if err != nil { flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") res.FlagSet = append(res.FlagSet, flag_api_error) @@ -1244,9 +1244,9 @@ func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input [] res.Content = l.Get( "Your request has been sent. %s will receive %s %s from %s.", - string(data[common.DATA_TEMPORARY_VALUE]), - string(data[common.DATA_AMOUNT]), - string(data[common.DATA_ACTIVE_SYM]), + data.TemporaryValue, + data.Amount, + data.ActiveSym, sessionId, ) From 222d801ecc454d60c3eec4f31148ff2763b3aff5 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 15 Nov 2024 11:49:47 +0300 Subject: [PATCH 270/289] added TestParseAndScaleAmount --- common/tokens_test.go | 88 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 common/tokens_test.go diff --git a/common/tokens_test.go b/common/tokens_test.go new file mode 100644 index 0000000..5634ab9 --- /dev/null +++ b/common/tokens_test.go @@ -0,0 +1,88 @@ +package common + +import ( + "testing" +) + +func TestParseAndScaleAmount(t *testing.T) { + tests := []struct { + name string + amount string + decimals string + want string + expectError bool + }{ + { + name: "whole number", + amount: "123", + decimals: "2", + want: "12300", + expectError: false, + }, + { + name: "decimal number", + amount: "123.45", + decimals: "2", + want: "12345", + expectError: false, + }, + { + name: "zero decimals", + amount: "123.45", + decimals: "0", + want: "123", + expectError: false, + }, + { + name: "large number", + amount: "1000000.01", + decimals: "6", + want: "1000000010000", + expectError: false, + }, + { + name: "invalid amount", + amount: "abc", + decimals: "2", + want: "", + expectError: true, + }, + { + name: "invalid decimals", + amount: "123.45", + decimals: "abc", + want: "", + expectError: true, + }, + { + name: "zero amount", + amount: "0", + decimals: "2", + want: "0", + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ParseAndScaleAmount(tt.amount, tt.decimals) + + // Check error cases + if tt.expectError { + if err == nil { + t.Errorf("ParseAndScaleAmount(%q, %q) expected error, got nil", tt.amount, tt.decimals) + } + return + } + + if err != nil { + t.Errorf("ParseAndScaleAmount(%q, %q) unexpected error: %v", tt.amount, tt.decimals, err) + return + } + + if got != tt.want { + t.Errorf("ParseAndScaleAmount(%q, %q) = %v, want %v", tt.amount, tt.decimals, got, tt.want) + } + }) + } +} From 36846c2587c830332d3d528af62c2e828b6b0a52 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 15 Nov 2024 12:13:09 +0300 Subject: [PATCH 271/289] added TestReadTransactionData --- common/tokens_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/common/tokens_test.go b/common/tokens_test.go index 5634ab9..06bd552 100644 --- a/common/tokens_test.go +++ b/common/tokens_test.go @@ -2,6 +2,8 @@ package common import ( "testing" + + "github.com/alecthomas/assert/v2" ) func TestParseAndScaleAmount(t *testing.T) { @@ -86,3 +88,42 @@ func TestParseAndScaleAmount(t *testing.T) { }) } } + +func TestReadTransactionData(t *testing.T) { + sessionId := "session123" + publicKey := "0X13242618721" + ctx, store := InitializeTestDb(t) + + // Test transaction data + transactionData := map[DataTyp]string{ + DATA_TEMPORARY_VALUE: "0712345678", + DATA_ACTIVE_SYM: "SRF", + DATA_AMOUNT: "1000000", + DATA_PUBLIC_KEY: publicKey, + DATA_RECIPIENT: "0x41c188d63Qa", + DATA_ACTIVE_DECIMAL: "6", + DATA_ACTIVE_ADDRESS: "0xd4c288865Ce", + } + + // Store the data + for key, value := range transactionData { + if err := store.WriteEntry(ctx, sessionId, key, []byte(value)); err != nil { + t.Fatal(err) + } + } + + expectedResult := TransactionData{ + TemporaryValue: "0712345678", + ActiveSym: "SRF", + Amount: "1000000", + PublicKey: publicKey, + Recipient: "0x41c188d63Qa", + ActiveDecimal: "6", + ActiveAddress: "0xd4c288865Ce", + } + + data, err := ReadTransactionData(ctx, store, sessionId) + + assert.NoError(t, err) + assert.Equal(t, expectedResult, data) +} From 1a77092ccbfd25d02d66c801cdb9166efcb889d1 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 15 Nov 2024 13:12:30 +0300 Subject: [PATCH 272/289] updated the menuhandler tests --- internal/handlers/ussd/menuhandler_test.go | 97 ++++++++++++++++------ 1 file changed, 72 insertions(+), 25 deletions(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index f4c9f7c..ff6f0ad 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -586,9 +586,9 @@ func TestGetRecipient(t *testing.T) { ctx, store := InitializeTestStore(t) ctx = context.WithValue(ctx, "SessionId", sessionId) - recepient := "0xcasgatweksalw1018221" + recepient := "0712345678" - err := store.WriteEntry(ctx, sessionId, common.DATA_RECIPIENT, []byte(recepient)) + err := store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(recepient)) if err != nil { t.Fatal(err) } @@ -1226,32 +1226,41 @@ func TestInitiateTransaction(t *testing.T) { } tests := []struct { - name string - input []byte - Recipient []byte - Amount []byte - ActiveSym []byte - status string - expectedResult resource.Result + name string + TemporaryValue []byte + ActiveSym []byte + StoredAmount []byte + TransferAmount string + PublicKey []byte + Recipient []byte + ActiveDecimal []byte + ActiveAddress []byte + TransferResponse *models.TokenTransferResponse + expectedResult resource.Result }{ { - name: "Test initiate transaction", - Amount: []byte("0.002"), - ActiveSym: []byte("SRF"), - Recipient: []byte("0x12415ass27192"), + name: "Test initiate transaction", + TemporaryValue: []byte("0711223344"), + ActiveSym: []byte("SRF"), + StoredAmount: []byte("1.00"), + TransferAmount: "1000000", + PublicKey: []byte("0X13242618721"), + Recipient: []byte("0x12415ass27192"), + ActiveDecimal: []byte("6"), + ActiveAddress: []byte("0xd4c288865Ce"), + TransferResponse: &models.TokenTransferResponse{ + TrackingId: "1234567890", + }, expectedResult: resource.Result{ FlagReset: []uint32{account_authorized_flag}, - Content: "Your request has been sent. 0x12415ass27192 will receive 0.002 SRF from 254712345678.", + Content: "Your request has been sent. 0711223344 will receive 1.00 SRF from 254712345678.", }, }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - err := store.WriteEntry(ctx, sessionId, common.DATA_AMOUNT, []byte(tt.Amount)) - if err != nil { - t.Fatal(err) - } - err = store.WriteEntry(ctx, sessionId, common.DATA_RECIPIENT, []byte(tt.Recipient)) + err := store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(tt.TemporaryValue)) if err != nil { t.Fatal(err) } @@ -1259,9 +1268,31 @@ func TestInitiateTransaction(t *testing.T) { if err != nil { t.Fatal(err) } + err = store.WriteEntry(ctx, sessionId, common.DATA_AMOUNT, []byte(tt.StoredAmount)) + if err != nil { + t.Fatal(err) + } + err = store.WriteEntry(ctx, sessionId, common.DATA_PUBLIC_KEY, []byte(tt.PublicKey)) + if err != nil { + t.Fatal(err) + } + err = store.WriteEntry(ctx, sessionId, common.DATA_RECIPIENT, []byte(tt.Recipient)) + if err != nil { + t.Fatal(err) + } + err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_DECIMAL, []byte(tt.ActiveDecimal)) + if err != nil { + t.Fatal(err) + } + err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_ADDRESS, []byte(tt.ActiveAddress)) + if err != nil { + t.Fatal(err) + } + + mockAccountService.On("TokenTransfer").Return(tt.TransferResponse, nil) // Call the method under test - res, _ := h.InitiateTransaction(ctx, "transaction_reset_amount", tt.input) + res, _ := h.InitiateTransaction(ctx, "transaction_reset_amount", []byte("")) // Assert that no errors occurred assert.NoError(t, err) @@ -1453,10 +1484,12 @@ func TestValidateRecipient(t *testing.T) { } sessionId := "session123" + publicKey := "0X13242618721" ctx, store := InitializeTestStore(t) ctx = context.WithValue(ctx, "SessionId", sessionId) flag_invalid_recipient, _ := fm.parser.GetFlag("flag_invalid_recipient") + flag_invalid_recipient_with_invite, _ := fm.parser.GetFlag("flag_invalid_recipient_with_invite") // Define test cases tests := []struct { @@ -1466,19 +1499,33 @@ func TestValidateRecipient(t *testing.T) { }{ { name: "Test with invalid recepient", - input: []byte("000"), + input: []byte("9234adf5"), expectedResult: resource.Result{ FlagSet: []uint32{flag_invalid_recipient}, - Content: "000", + Content: "9234adf5", }, }, { - name: "Test with valid recepient", - input: []byte("0705X2"), + name: "Test with valid unregistered recepient", + input: []byte("0712345678"), + expectedResult: resource.Result{ + FlagSet: []uint32{flag_invalid_recipient_with_invite}, + Content: "0712345678", + }, + }, + { + name: "Test with valid registered recepient", + input: []byte("0711223344"), expectedResult: resource.Result{}, }, } + // store a public key for the valid recipient + err = store.WriteEntry(ctx, "0711223344", common.DATA_PUBLIC_KEY, []byte(publicKey)) + if err != nil { + t.Fatal(err) + } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Create the Handlers instance @@ -1987,7 +2034,7 @@ func TestSetVoucher(t *testing.T) { t.Fatal(err) } - res, err := h.SetVoucher(ctx, "set_voucher", []byte{}) + res, err := h.SetVoucher(ctx, "set_voucher", []byte("")) assert.NoError(t, err) From d3fae34290049dc67d00f24575439b2f89b2fd4a Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 15 Nov 2024 13:24:54 +0300 Subject: [PATCH 273/289] modified the send node traversal --- menutraversal_test/test_setup.json | 32 ++++++------------------------ 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/menutraversal_test/test_setup.json b/menutraversal_test/test_setup.json index 3acb889..a554939 100644 --- a/menutraversal_test/test_setup.json +++ b/menutraversal_test/test_setup.json @@ -53,7 +53,7 @@ ] }, { - "name": "send_with_invalid_inputs", + "name": "send_with_invite", "steps": [ { "input": "", @@ -65,39 +65,19 @@ }, { "input": "000", - "expectedContent": "000 is not registered or invalid, please try again:\n1:Retry\n9:Quit" + "expectedContent": "000 is invalid, please try again:\n1:Retry\n9:Quit" }, { "input": "1", "expectedContent": "Enter recipient's phone number:\n0:Back" }, { - "input": "065656", - "expectedContent": "{max_amount}\nEnter amount:\n0:Back" + "input": "0712345678", + "expectedContent": "0712345678 is not registered, please try again:\n1:Retry\n2:Invite to Sarafu Network\n9:Quit" }, { - "input": "10000000", - "expectedContent": "Amount 10000000 is invalid, please try again:\n1:Retry\n9:Quit" - }, - { - "input": "1", - "expectedContent": "{max_amount}\nEnter amount:\n0:Back" - }, - { - "input": "1.00", - "expectedContent": "065656 will receive {send_amount} from {session_id}\nPlease enter your PIN to confirm:\n0:Back\n9:Quit" - }, - { - "input": "1222", - "expectedContent": "Incorrect pin\n1:Retry\n9:Quit" - }, - { - "input": "1", - "expectedContent": "065656 will receive {send_amount} from {session_id}\nPlease enter your PIN to confirm:\n0:Back\n9:Quit" - }, - { - "input": "1234", - "expectedContent": "Your request has been sent. 065656 will receive {send_amount} from {session_id}." + "input": "2", + "expectedContent": "Your invite request for 0712345678 to Sarafu Network failed. Please try again later." } ] }, From 51bf2534b87d1398202e8ec85410b1d21a95dd60 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 15 Nov 2024 18:35:49 +0300 Subject: [PATCH 274/289] use a single bearer token --- .env.example | 3 +-- config/config.go | 10 ++++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/.env.example b/.env.example index d392c9b..c636fa8 100644 --- a/.env.example +++ b/.env.example @@ -16,6 +16,5 @@ DB_TIMEZONE=Africa/Nairobi #External API Calls CUSTODIAL_URL_BASE=http://localhost:5003 -CUSTODIAL_BEARER_TOKEN=eyJeSIsInRcCI6IkpXVCJ.yJwdWJsaWNLZXkiOiIwrrrrrr +BEARER_TOKEN=eyJeSIsInRcCI6IkpXVCJ.yJwdWJsaWNLZXkiOiIwrrrrrr DATA_URL_BASE=http://localhost:5006 -DATA_BEARER_TOKEN=eyJeSIsIRcCI6IXVCJ.yJwdWJsaLZXkiOiIwrrrrrr diff --git a/config/config.go b/config/config.go index 0d39e6e..edb33fe 100644 --- a/config/config.go +++ b/config/config.go @@ -18,10 +18,9 @@ const ( ) var ( - custodialURLBase string - dataURLBase string - CustodialBearerToken string - DataBearerToken string + custodialURLBase string + dataURLBase string + BearerToken string ) var ( @@ -40,8 +39,7 @@ func setBase() error { custodialURLBase = initializers.GetEnv("CUSTODIAL_URL_BASE", "http://localhost:5003") dataURLBase = initializers.GetEnv("DATA_URL_BASE", "http://localhost:5006") - CustodialBearerToken = initializers.GetEnv("CUSTODIAL_BEARER_TOKEN", "") - DataBearerToken = initializers.GetEnv("DATA_BEARER_TOKEN", "") + BearerToken = initializers.GetEnv("BEARER_TOKEN", "") _, err = url.JoinPath(custodialURLBase, "/foo") if err != nil { From baeb5e0ccba55d937a985e4b5313ba573bfe4850 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 15 Nov 2024 18:37:20 +0300 Subject: [PATCH 275/289] use a single doRequest and updated the structs for TokenHoldings and Transfers --- remote/accountservice.go | 43 +++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/remote/accountservice.go b/remote/accountservice.go index 3af1ab1..6c94a28 100644 --- a/remote/accountservice.go +++ b/remote/accountservice.go @@ -51,7 +51,7 @@ func (as *AccountService) TrackAccountStatus(ctx context.Context, publicKey stri return nil, err } - _, err = doCustodialRequest(ctx, req, &r) + _, err = doRequest(ctx, req, &r) if err != nil { return nil, err } @@ -75,7 +75,7 @@ func (as *AccountService) CheckBalance(ctx context.Context, publicKey string) (* return nil, err } - _, err = doCustodialRequest(ctx, req, &balanceResult) + _, err = doRequest(ctx, req, &balanceResult) return &balanceResult, err } @@ -92,7 +92,7 @@ func (as *AccountService) CreateAccount(ctx context.Context) (*models.AccountRes if err != nil { return nil, err } - _, err = doCustodialRequest(ctx, req, &r) + _, err = doRequest(ctx, req, &r) if err != nil { return nil, err } @@ -104,7 +104,9 @@ func (as *AccountService) CreateAccount(ctx context.Context) (*models.AccountRes // Parameters: // - publicKey: The public key associated with the account. func (as *AccountService) FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) { - var r []dataserviceapi.TokenHoldings + var r struct { + Holdings []dataserviceapi.TokenHoldings `json:"holdings"` + } ep, err := url.JoinPath(config.VoucherHoldingsURL, publicKey) if err != nil { @@ -116,19 +118,21 @@ func (as *AccountService) FetchVouchers(ctx context.Context, publicKey string) ( return nil, err } - _, err = doDataRequest(ctx, req, r) + _, err = doRequest(ctx, req, &r) if err != nil { return nil, err } - return r, nil + return r.Holdings, nil } // FetchTransactions retrieves the last 10 transactions for a given public key from the data indexer API endpoint // Parameters: // - publicKey: The public key associated with the account. func (as *AccountService) FetchTransactions(ctx context.Context, publicKey string) ([]dataserviceapi.Last10TxResponse, error) { - var r []dataserviceapi.Last10TxResponse + var r struct { + Transfers []dataserviceapi.Last10TxResponse `json:"transfers"` + } ep, err := url.JoinPath(config.VoucherTransfersURL, publicKey) if err != nil { @@ -140,12 +144,12 @@ func (as *AccountService) FetchTransactions(ctx context.Context, publicKey strin return nil, err } - _, err = doDataRequest(ctx, req, r) + _, err = doRequest(ctx, req, &r) if err != nil { return nil, err } - return r, nil + return r.Transfers, nil } // VoucherData retrieves voucher metadata from the data indexer API endpoint. @@ -164,7 +168,7 @@ func (as *AccountService) VoucherData(ctx context.Context, address string) (*mod return nil, err } - _, err = doCustodialRequest(ctx, req, &voucherDataResult) + _, err = doRequest(ctx, req, &voucherDataResult) return &voucherDataResult, err } @@ -195,7 +199,7 @@ func (as *AccountService) TokenTransfer(ctx context.Context, amount, from, to, t if err != nil { return nil, err } - _, err = doCustodialRequest(ctx, req, &r) + _, err = doRequest(ctx, req, &r) if err != nil { return nil, err } @@ -206,7 +210,12 @@ func (as *AccountService) TokenTransfer(ctx context.Context, amount, from, to, t func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { var okResponse api.OKResponse var errResponse api.ErrResponse + + req.Header.Set("Authorization", "Bearer "+config.BearerToken) req.Header.Set("Content-Type", "application/json") + + logRequestDetails(req) + resp, err := http.DefaultClient.Do(req) if err != nil { log.Printf("Failed to make %s request to endpoint: %s with reason: %s", req.Method, req.URL, err.Error()) @@ -244,18 +253,6 @@ func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKRespons return &okResponse, err } -func doCustodialRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { - req.Header.Set("Authorization", "Bearer "+config.CustodialBearerToken) - logRequestDetails(req) - return doRequest(ctx, req, rcpt) -} - -func doDataRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { - req.Header.Set("Authorization", "Bearer "+config.DataBearerToken) - logRequestDetails(req) - return doRequest(ctx, req, rcpt) -} - func logRequestDetails(req *http.Request) { var bodyBytes []byte contentType := req.Header.Get("Content-Type") From c8fc32a4e7a618c5a55ddb96536251cfa0265a8e Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 15 Nov 2024 18:50:06 +0300 Subject: [PATCH 276/289] cleaned up models --- models/accountresponse.go | 2 +- models/balanceresponse.go | 1 - models/tokenresponse.go | 18 ------------------ models/trackstatusresponse.go | 2 +- models/voucher_data_result.go | 8 ++++++++ models/vouchersresponse.go | 21 --------------------- 6 files changed, 10 insertions(+), 42 deletions(-) delete mode 100644 models/tokenresponse.go create mode 100644 models/voucher_data_result.go delete mode 100644 models/vouchersresponse.go diff --git a/models/accountresponse.go b/models/accountresponse.go index 278e0e9..dc8e758 100644 --- a/models/accountresponse.go +++ b/models/accountresponse.go @@ -1,6 +1,6 @@ package models type AccountResult struct { - PublicKey string `json:"publicKey"` + PublicKey string `json:"publicKey"` TrackingId string `json:"trackingId"` } diff --git a/models/balanceresponse.go b/models/balanceresponse.go index b2baa41..88e9ce9 100644 --- a/models/balanceresponse.go +++ b/models/balanceresponse.go @@ -2,7 +2,6 @@ package models import "encoding/json" - type BalanceResult struct { Balance string `json:"balance"` Nonce json.Number `json:"nonce"` diff --git a/models/tokenresponse.go b/models/tokenresponse.go deleted file mode 100644 index d243d93..0000000 --- a/models/tokenresponse.go +++ /dev/null @@ -1,18 +0,0 @@ -package models - -type ApiResponse struct { - OK bool `json:"ok"` - Description string `json:"description"` - Result Result `json:"result"` -} - -type Result struct { - Holdings []Holding `json:"holdings"` -} - -type Holding struct { - ContractAddress string `json:"contractAddress"` - TokenSymbol string `json:"tokenSymbol"` - TokenDecimals string `json:"tokenDecimals"` - Balance string `json:"balance"` -} diff --git a/models/trackstatusresponse.go b/models/trackstatusresponse.go index 47d757d..0c3c230 100644 --- a/models/trackstatusresponse.go +++ b/models/trackstatusresponse.go @@ -14,5 +14,5 @@ type Transaction struct { } type TrackStatusResult struct { - Active bool `json:"active"` + Active bool `json:"active"` } diff --git a/models/voucher_data_result.go b/models/voucher_data_result.go new file mode 100644 index 0000000..f04aafe --- /dev/null +++ b/models/voucher_data_result.go @@ -0,0 +1,8 @@ +package models + +type VoucherDataResult struct { + TokenName string `json:"tokenName"` + TokenSymbol string `json:"tokenSymbol"` + TokenDecimals string `json:"tokenDecimals"` + SinkAddress string `json:"sinkAddress"` +} diff --git a/models/vouchersresponse.go b/models/vouchersresponse.go deleted file mode 100644 index 8cf3ec6..0000000 --- a/models/vouchersresponse.go +++ /dev/null @@ -1,21 +0,0 @@ -package models - -import dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" - -//type VoucherHoldingResponse struct { -// Ok bool `json:"ok"` -// Description string `json:"description"` -// Result VoucherResult `json:"result"` -//} - -// VoucherResult holds the list of token holdings -type VoucherResult struct { - Holdings []dataserviceapi.TokenHoldings `json:"holdings"` -} - -type VoucherDataResult struct { - TokenName string `json:"tokenName"` - TokenSymbol string `json:"tokenSymbol"` - TokenDecimals string `json:"tokenDecimals"` - SinkAddress string `json:"sinkAddress"` -} From 7d16b710d81f31c78480a0a4cf101c1e42dfd8b4 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 15 Nov 2024 20:50:07 +0300 Subject: [PATCH 277/289] set the TokenDecimals as int to match the API response --- models/voucher_data_result.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/voucher_data_result.go b/models/voucher_data_result.go index f04aafe..c9f0b74 100644 --- a/models/voucher_data_result.go +++ b/models/voucher_data_result.go @@ -3,6 +3,6 @@ package models type VoucherDataResult struct { TokenName string `json:"tokenName"` TokenSymbol string `json:"tokenSymbol"` - TokenDecimals string `json:"tokenDecimals"` + TokenDecimals int `json:"tokenDecimals"` SinkAddress string `json:"sinkAddress"` } From c0ccdce0a9e2d2a574a55b223b5ebab6d2008299 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 15 Nov 2024 21:02:44 +0300 Subject: [PATCH 278/289] add the voucher details node --- services/registration/my_vouchers.vis | 1 + services/registration/voucher_details | 1 + services/registration/voucher_details.vis | 6 ++++++ services/registration/voucher_details_swa | 1 + 4 files changed, 9 insertions(+) create mode 100644 services/registration/voucher_details create mode 100644 services/registration/voucher_details.vis create mode 100644 services/registration/voucher_details_swa diff --git a/services/registration/my_vouchers.vis b/services/registration/my_vouchers.vis index b59441a..e79438e 100644 --- a/services/registration/my_vouchers.vis +++ b/services/registration/my_vouchers.vis @@ -6,3 +6,4 @@ MOUT back 0 HALT INCMP _ 0 INCMP select_voucher 1 +INCMP voucher_details 2 diff --git a/services/registration/voucher_details b/services/registration/voucher_details new file mode 100644 index 0000000..d437681 --- /dev/null +++ b/services/registration/voucher_details @@ -0,0 +1 @@ +{{.get_voucher_details}} \ No newline at end of file diff --git a/services/registration/voucher_details.vis b/services/registration/voucher_details.vis new file mode 100644 index 0000000..1b009f1 --- /dev/null +++ b/services/registration/voucher_details.vis @@ -0,0 +1,6 @@ +CATCH no_voucher flag_no_active_voucher 1 +LOAD get_voucher_details 0 +MAP get_voucher_details +MOUT back 0 +HALT +INCMP _ 0 diff --git a/services/registration/voucher_details_swa b/services/registration/voucher_details_swa new file mode 100644 index 0000000..d437681 --- /dev/null +++ b/services/registration/voucher_details_swa @@ -0,0 +1 @@ +{{.get_voucher_details}} \ No newline at end of file From 11bb194f264d22eeda652035f744a77bfad9e325 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 15 Nov 2024 21:03:29 +0300 Subject: [PATCH 279/289] add a struct to access the tokenDetails --- remote/accountservice.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/remote/accountservice.go b/remote/accountservice.go index 6c94a28..23b62ca 100644 --- a/remote/accountservice.go +++ b/remote/accountservice.go @@ -156,7 +156,9 @@ func (as *AccountService) FetchTransactions(ctx context.Context, publicKey strin // Parameters: // - address: The voucher address. func (as *AccountService) VoucherData(ctx context.Context, address string) (*models.VoucherDataResult, error) { - var voucherDataResult models.VoucherDataResult + var r struct { + TokenDetails models.VoucherDataResult `json:"tokenDetails"` + } ep, err := url.JoinPath(config.VoucherDataURL, address) if err != nil { @@ -168,8 +170,8 @@ func (as *AccountService) VoucherData(ctx context.Context, address string) (*mod return nil, err } - _, err = doRequest(ctx, req, &voucherDataResult) - return &voucherDataResult, err + _, err = doRequest(ctx, req, &r) + return &r.TokenDetails, err } // TokenTransfer creates a new token transfer in the custodial system. From b40ad782949f682e02eb90f6347e6c122476a8f1 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Fri, 15 Nov 2024 21:03:57 +0300 Subject: [PATCH 280/289] add the GetVoucherDetails function --- internal/handlers/handlerservice.go | 1 + internal/handlers/ussd/menuhandler.go | 33 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/internal/handlers/handlerservice.go b/internal/handlers/handlerservice.go index 358d492..e0cad8f 100644 --- a/internal/handlers/handlerservice.go +++ b/internal/handlers/handlerservice.go @@ -109,6 +109,7 @@ func (ls *LocalHandlerService) GetHandler(accountService remote.AccountServiceIn ls.DbRs.AddLocalFunc("get_vouchers", ussdHandlers.GetVoucherList) ls.DbRs.AddLocalFunc("view_voucher", ussdHandlers.ViewVoucher) ls.DbRs.AddLocalFunc("set_voucher", ussdHandlers.SetVoucher) + ls.DbRs.AddLocalFunc("get_voucher_details", ussdHandlers.GetVoucherDetails) ls.DbRs.AddLocalFunc("reset_valid_pin", ussdHandlers.ResetValidPin) ls.DbRs.AddLocalFunc("check_pin_mismatch", ussdHandlers.CheckPinMisMatch) ls.DbRs.AddLocalFunc("validate_blocked_number", ussdHandlers.ValidateBlockedNumber) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 0b9360f..8a3e8cf 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -1624,3 +1624,36 @@ func (h *Handlers) SetVoucher(ctx context.Context, sym string, input []byte) (re res.Content = tempData.TokenSymbol return res, nil } + +// 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 + sessionId, ok := ctx.Value("SessionId").(string) + if !ok { + return res, fmt.Errorf("missing session") + } + + flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") + + // get the active address + activeAddress, err := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_ADDRESS) + if err != nil { + logg.ErrorCtxf(ctx, "failed to read activeAddress entry with", "key", common.DATA_ACTIVE_ADDRESS, "error", err) + return res, err + } + + // use the voucher contract address to get the data from the API + voucherData, err := h.accountService.VoucherData(ctx, string(activeAddress)) + if err != nil { + res.FlagSet = append(res.FlagSet, flag_api_error) + return res, nil + } + + tokenSymbol := voucherData.TokenSymbol + tokenName := voucherData.TokenName + + res.Content = fmt.Sprintf("%s %s", tokenSymbol, tokenName) + + return res, nil +} From 5dd4f2a3fbba946c5d16d710a5dd8e17dd68e9a9 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Sat, 16 Nov 2024 14:52:02 +0300 Subject: [PATCH 281/289] scale down the balance according to the decimals --- common/vouchers.go | 29 +++++++++++++++++++++++++-- internal/handlers/ussd/menuhandler.go | 8 ++++++-- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/common/vouchers.go b/common/vouchers.go index 54ace28..81ca55f 100644 --- a/common/vouchers.go +++ b/common/vouchers.go @@ -3,6 +3,7 @@ package common import ( "context" "fmt" + "math/big" "strings" "git.grassecon.net/urdt/ussd/internal/storage" @@ -24,7 +25,11 @@ func ProcessVouchers(holdings []dataserviceapi.TokenHoldings) VoucherMetadata { for i, h := range holdings { symbols = append(symbols, fmt.Sprintf("%d:%s", i+1, h.TokenSymbol)) - balances = append(balances, fmt.Sprintf("%d:%s", i+1, h.Balance)) + + // Scale down the balance + scaledBalance := ScaleDownBalance(h.Balance, h.TokenDecimals) + + balances = append(balances, fmt.Sprintf("%d:%s", i+1, scaledBalance)) decimals = append(decimals, fmt.Sprintf("%d:%s", i+1, h.TokenDecimals)) addresses = append(addresses, fmt.Sprintf("%d:%s", i+1, h.ContractAddress)) } @@ -37,6 +42,26 @@ func ProcessVouchers(holdings []dataserviceapi.TokenHoldings) VoucherMetadata { return data } +func ScaleDownBalance(balance, decimals string) string { + // Convert balance and decimals to big.Float + bal := new(big.Float) + bal.SetString(balance) + + dec, ok := new(big.Int).SetString(decimals, 10) + if !ok { + dec = big.NewInt(0) // Default to 0 decimals in case of conversion failure + } + + divisor := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), dec, nil)) + scaledBalance := new(big.Float).Quo(bal, divisor) + + // Return the scaled balance without trailing decimals if it's an integer + if scaledBalance.IsInt() { + return scaledBalance.Text('f', 0) + } + return scaledBalance.Text('f', -1) +} + // GetVoucherData retrieves and matches voucher data func GetVoucherData(ctx context.Context, db storage.PrefixDb, input string) (*dataserviceapi.TokenHoldings, error) { keys := []string{"sym", "bal", "deci", "addr"} @@ -75,7 +100,7 @@ func MatchVoucher(input, symbols, balances, decimals, addresses string) (symbol, decList := strings.Split(decimals, "\n") addrList := strings.Split(addresses, "\n") - logg.Tracef("found" , "symlist", symList, "syms", symbols, "input", input) + logg.Tracef("found", "symlist", symList, "syms", symbols, "input", input) for i, sym := range symList { parts := strings.SplitN(sym, ":", 2) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index 8a3e8cf..f2d3173 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -1468,6 +1468,9 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by defaultDec := firstVoucher.TokenDecimals defaultAddr := firstVoucher.ContractAddress + // Scale down the balance + scaledBalance := common.ScaleDownBalance(defaultBal, defaultDec) + // set the active symbol err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_SYM, []byte(defaultSym)) if err != nil { @@ -1475,9 +1478,9 @@ func (h *Handlers) SetDefaultVoucher(ctx context.Context, sym string, input []by return res, err } // set the active balance - err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_BAL, []byte(defaultBal)) + err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_BAL, []byte(scaledBalance)) if err != nil { - logg.ErrorCtxf(ctx, "failed to write defaultBal entry with", "key", common.DATA_ACTIVE_BAL, "value", defaultBal, "error", err) + logg.ErrorCtxf(ctx, "failed to write defaultBal entry with", "key", common.DATA_ACTIVE_BAL, "value", scaledBalance, "error", err) return res, err } // set the active decimals @@ -1563,6 +1566,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 func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result sessionId, ok := ctx.Value("SessionId").(string) From 1ba90a8b780bf109c68aad4e31fbefb616787e95 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Sat, 16 Nov 2024 14:52:24 +0300 Subject: [PATCH 282/289] updated the test --- common/vouchers_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/vouchers_test.go b/common/vouchers_test.go index 8b9fa2a..9f5bf85 100644 --- a/common/vouchers_test.go +++ b/common/vouchers_test.go @@ -59,13 +59,13 @@ func TestMatchVoucher(t *testing.T) { func TestProcessVouchers(t *testing.T) { holdings := []dataserviceapi.TokenHoldings{ - {ContractAddress: "0xd4c288865Ce", TokenSymbol: "SRF", TokenDecimals: "6", Balance: "100"}, - {ContractAddress: "0x41c188d63Qa", TokenSymbol: "MILO", TokenDecimals: "4", Balance: "200"}, + {ContractAddress: "0xd4c288865Ce", TokenSymbol: "SRF", TokenDecimals: "6", Balance: "100000000"}, + {ContractAddress: "0x41c188d63Qa", TokenSymbol: "MILO", TokenDecimals: "4", Balance: "200000000"}, } expectedResult := VoucherMetadata{ Symbols: "1:SRF\n2:MILO", - Balances: "1:100\n2:200", + Balances: "1:100\n2:20000", Decimals: "1:6\n2:4", Addresses: "1:0xd4c288865Ce\n2:0x41c188d63Qa", } From e1506a3dcf0ac6fa0e21494ea22b3e0648133754 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 18 Nov 2024 17:20:12 +0300 Subject: [PATCH 283/289] show a placehlolder community balance --- internal/handlers/ussd/menuhandler.go | 42 +++++---------------------- 1 file changed, 7 insertions(+), 35 deletions(-) diff --git a/internal/handlers/ussd/menuhandler.go b/internal/handlers/ussd/menuhandler.go index f2d3173..d8e6fa0 100644 --- a/internal/handlers/ussd/menuhandler.go +++ b/internal/handlers/ussd/menuhandler.go @@ -822,42 +822,14 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) ( return res, nil } -func (h *Handlers) FetchCustodialBalances(ctx context.Context, sym string, input []byte) (resource.Result, error) { +func (h *Handlers) FetchCommunityBalance(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result - - flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") - - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return res, fmt.Errorf("missing session") - } - symbol, _ := h.st.Where() - balanceType := strings.Split(symbol, "_")[0] - - store := h.userdataStore - publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) - if err != nil { - logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", common.DATA_PUBLIC_KEY, "error", err) - return res, err - } - - balanceResponse, err := h.accountService.CheckBalance(ctx, string(publicKey)) - if err != nil { - res.FlagSet = append(res.FlagSet, flag_api_error) - return res, nil - } - res.FlagReset = append(res.FlagReset, flag_api_error) - - balance := balanceResponse.Balance - - switch balanceType { - case "my": - res.Content = fmt.Sprintf("Your balance is %s", balance) - case "community": - res.Content = fmt.Sprintf("Your community balance is %s", balance) - default: - break - } + code := codeFromCtx(ctx) + l := gotext.NewLocale(translationDir, code) + l.AddDomain("default") + //TODO: + //Check if the address is a community account,if then,get the actual balance + res.Content = l.Get("Community Balance: 0.00") return res, nil } From 454f67b3177bce34cbd6448b2ef3263c645eec76 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 18 Nov 2024 17:21:04 +0300 Subject: [PATCH 284/289] show balance based on current voucher --- services/registration/my_balance | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/registration/my_balance b/services/registration/my_balance index f8f8318..afae8c1 100644 --- a/services/registration/my_balance +++ b/services/registration/my_balance @@ -1 +1 @@ -{{.fetch_custodial_balances}} \ No newline at end of file +{{.check_balance}} \ No newline at end of file From 44c52b6ed717f619d0912fd60f90653fed4a6782 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 18 Nov 2024 17:23:36 +0300 Subject: [PATCH 285/289] rename fetch_custodial_balances -> fetch_community_balance --- internal/handlers/handlerservice.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/handlers/handlerservice.go b/internal/handlers/handlerservice.go index e0cad8f..fe88c1f 100644 --- a/internal/handlers/handlerservice.go +++ b/internal/handlers/handlerservice.go @@ -103,7 +103,7 @@ func (ls *LocalHandlerService) GetHandler(accountService remote.AccountServiceIn ls.DbRs.AddLocalFunc("verify_new_pin", ussdHandlers.VerifyNewPin) ls.DbRs.AddLocalFunc("confirm_pin_change", ussdHandlers.ConfirmPinChange) ls.DbRs.AddLocalFunc("quit_with_help", ussdHandlers.QuitWithHelp) - ls.DbRs.AddLocalFunc("fetch_custodial_balances", ussdHandlers.FetchCustodialBalances) + ls.DbRs.AddLocalFunc("fetch_community_balance", ussdHandlers.FetchCommunityBalance) ls.DbRs.AddLocalFunc("set_default_voucher", ussdHandlers.SetDefaultVoucher) ls.DbRs.AddLocalFunc("check_vouchers", ussdHandlers.CheckVouchers) ls.DbRs.AddLocalFunc("get_vouchers", ussdHandlers.GetVoucherList) From 1d4f11607963437e46fa9145c22f17340193e679 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 18 Nov 2024 17:23:59 +0300 Subject: [PATCH 286/289] community balance str --- services/registration/locale/swa/default.po | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/registration/locale/swa/default.po b/services/registration/locale/swa/default.po index f933dde..aa033b5 100644 --- a/services/registration/locale/swa/default.po +++ b/services/registration/locale/swa/default.po @@ -21,3 +21,6 @@ msgstr "Ombi lako la kumwalika %s kwa matandao wa Sarafu limetumwa." msgid "Your request failed. Please try again later." msgstr "Ombi lako halikufaulu. Tafadhali jaribu tena baadaye." + +msgid "Community Balance: 0.00" +msgid "Salio la Kikundi: 0.00" From f2b17880bab2f45d4a4b9b03b8f25e1905c933ee Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 18 Nov 2024 17:30:09 +0300 Subject: [PATCH 287/289] check community and my balance separately --- services/registration/comminity_balance_swa | 2 +- services/registration/community_balance | 2 +- services/registration/community_balance.vis | 4 ++-- services/registration/my_balance.vis | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/services/registration/comminity_balance_swa b/services/registration/comminity_balance_swa index 726fc99..d9f1d6e 100644 --- a/services/registration/comminity_balance_swa +++ b/services/registration/comminity_balance_swa @@ -1 +1 @@ -Salio la kikundi \ No newline at end of file +{{.fetch_community_balance}} \ No newline at end of file diff --git a/services/registration/community_balance b/services/registration/community_balance index f8f8318..d9f1d6e 100644 --- a/services/registration/community_balance +++ b/services/registration/community_balance @@ -1 +1 @@ -{{.fetch_custodial_balances}} \ No newline at end of file +{{.fetch_community_balance}} \ No newline at end of file diff --git a/services/registration/community_balance.vis b/services/registration/community_balance.vis index 85ae93a..f3e0ae1 100644 --- a/services/registration/community_balance.vis +++ b/services/registration/community_balance.vis @@ -1,7 +1,7 @@ LOAD reset_incorrect 6 -LOAD fetch_custodial_balances 0 +LOAD fetch_community_balance 0 CATCH api_failure flag_api_call_error 1 -MAP fetch_custodial_balances +MAP fetch_community_balance CATCH incorrect_pin flag_incorrect_pin 1 CATCH pin_entry flag_account_authorized 0 MOUT back 0 diff --git a/services/registration/my_balance.vis b/services/registration/my_balance.vis index 85ae93a..9144da9 100644 --- a/services/registration/my_balance.vis +++ b/services/registration/my_balance.vis @@ -1,7 +1,7 @@ LOAD reset_incorrect 6 -LOAD fetch_custodial_balances 0 +LOAD check_balance 0 CATCH api_failure flag_api_call_error 1 -MAP fetch_custodial_balances +MAP check_balance CATCH incorrect_pin flag_incorrect_pin 1 CATCH pin_entry flag_account_authorized 0 MOUT back 0 From 01e75e92170cb26b81dbadd31fd2057f105972e6 Mon Sep 17 00:00:00 2001 From: Carlosokumu Date: Mon, 18 Nov 2024 17:30:34 +0300 Subject: [PATCH 288/289] update test --- internal/handlers/ussd/menuhandler_test.go | 42 +++++++--------------- 1 file changed, 13 insertions(+), 29 deletions(-) diff --git a/internal/handlers/ussd/menuhandler_test.go b/internal/handlers/ussd/menuhandler_test.go index ff6f0ad..51693df 100644 --- a/internal/handlers/ussd/menuhandler_test.go +++ b/internal/handlers/ussd/menuhandler_test.go @@ -2,7 +2,6 @@ package ussd import ( "context" - "encoding/json" "fmt" "log" "path" @@ -1773,58 +1772,43 @@ func TestConfirmPin(t *testing.T) { } } -func TestFetchCustodialBalances(t *testing.T) { - fm, err := NewFlagManager(flagsPath) - if err != nil { - t.Logf(err.Error()) - } - flag_api_error, _ := fm.GetFlag("flag_api_call_error") +func TestFetchCommunityBalance(t *testing.T) { // Define test data sessionId := "session123" - publicKey := "0X13242618721" - ctx, store := InitializeTestStore(t) - ctx = context.WithValue(ctx, "SessionId", sessionId) - - err = store.WriteEntry(ctx, sessionId, common.DATA_PUBLIC_KEY, []byte(publicKey)) - if err != nil { - t.Fatal(err) - } tests := []struct { - name string - balanceResponse *models.BalanceResult - expectedResult resource.Result + name string + languageCode string + expectedResult resource.Result }{ { - name: "Test when fetch custodial balances is not a success", - balanceResponse: &models.BalanceResult{ - Balance: "0.003 CELO", - Nonce: json.Number("0"), - }, + name: "Test community balance content when language is english", expectedResult: resource.Result{ - FlagReset: []uint32{flag_api_error}, + Content: "Community Balance: 0.00", }, + languageCode: "eng", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + mockAccountService := new(mocks.MockAccountService) mockState := state.NewState(16) h := &Handlers{ userdataStore: store, - flagManager: fm.parser, st: mockState, accountService: mockAccountService, } - - // Set up the expected behavior of the mock - mockAccountService.On("CheckBalance", string(publicKey)).Return(tt.balanceResponse, nil) + ctx = context.WithValue(ctx, "SessionId", sessionId) + ctx = context.WithValue(ctx, "Language", lang.Language{ + Code: tt.languageCode, + }) // Call the method - res, _ := h.FetchCustodialBalances(ctx, "fetch_custodial_balances", []byte("")) + res, _ := h.FetchCommunityBalance(ctx, "fetch_community_balance", []byte("")) //Assert that the result set to content is what was expected assert.Equal(t, res, tt.expectedResult, "Result should match expected result") From bc6d8098f3cc25b69d920b62663f1b72bdf251f8 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Tue, 19 Nov 2024 10:15:34 +0300 Subject: [PATCH 289/289] updated the failed test --- menutraversal_test/group_test.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/menutraversal_test/group_test.json b/menutraversal_test/group_test.json index 449c42f..52fab59 100644 --- a/menutraversal_test/group_test.json +++ b/menutraversal_test/group_test.json @@ -103,7 +103,7 @@ }, { "input": "1234", - "expectedContent": "Your balance is 0.003 CELO\n0:Back\n9:Quit" + "expectedContent": "Balance: {balance}\n\n0:Back\n9:Quit" }, { "input": "0", @@ -149,7 +149,7 @@ }, { "input": "1234", - "expectedContent": "Your community balance is 0.003 CELO\n0:Back\n9:Quit" + "expectedContent": "{balance}\n0:Back\n9:Quit" }, { "input": "0",