From cedd55fd3177b3bf61a9877456c6408def6a6d5e Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 26 Jun 2025 09:56:29 +0300 Subject: [PATCH 01/16] use updated sarafu-api that includes the UpdateAlias functionality --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 7836057..bcc38f5 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.23.4 require ( git.defalsify.org/vise.git v0.3.2-0.20250528124150-03bf7bfc1b66 git.grassecon.net/grassrootseconomics/common v0.9.0-beta.1.0.20250417111317-2953f4c2f32e - git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250624090744-339ba854c997 + git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250626065419-57ee409f9629 git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250408094335-e2d1f65bb306 git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694 github.com/alecthomas/assert/v2 v2.2.2 diff --git a/go.sum b/go.sum index 1064bb8..6af47fe 100644 --- a/go.sum +++ b/go.sum @@ -12,6 +12,8 @@ git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250624074830- git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250624074830-5aa032400c12/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250624090744-339ba854c997 h1:8bCKyYoV4YiVBvCZlRclc3aQlBYpWhgtM35mvniDFD8= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250624090744-339ba854c997/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8= +git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250626065419-57ee409f9629 h1:ew3vCFrLS/7/8uULTTPCbsHzFntQ6X68SScnBEy3pl0= +git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250626065419-57ee409f9629/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8= git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250408094335-e2d1f65bb306 h1:Jo+yWysWw/N5BJQtAyEMN8ePVvAyPHv+JG4lQti+1N4= git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250408094335-e2d1f65bb306/go.mod h1:FdLwYtzsjOIcDiW4uDgDYnB4Wdzq12uJUe0QHSSPbSo= git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694 h1:DjJlBSz0S13acft5XZDWk7ZYnzElym0xLMYEVgyNJ+E= From b497dde1e8c9d795d189a0b75469a7464bbe06bd Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Thu, 26 Jun 2025 10:02:55 +0300 Subject: [PATCH 02/16] remove unused 'constructAccountAlias' func --- handlers/application/menuhandler.go | 46 ------------ handlers/application/menuhandler_test.go | 91 ------------------------ 2 files changed, 137 deletions(-) diff --git a/handlers/application/menuhandler.go b/handlers/application/menuhandler.go index 8b4a30b..2a3dc5d 100644 --- a/handlers/application/menuhandler.go +++ b/handlers/application/menuhandler.go @@ -2561,52 +2561,6 @@ func (h *MenuHandlers) persistLanguageCode(ctx context.Context, code string) err return h.persistInitialLanguageCode(ctx, sessionId, code) } -// constructAccountAlias retrieves and alias based on the first and family name -// and writes the result in DATA_ACCOUNT_ALIAS -func (h *MenuHandlers) constructAccountAlias(ctx context.Context) error { - var alias string - store := h.userdataStore - sessionId, ok := ctx.Value("SessionId").(string) - if !ok { - return fmt.Errorf("missing session") - } - firstName, err := store.ReadEntry(ctx, sessionId, storedb.DATA_FIRST_NAME) - if err != nil { - if db.IsNotFound(err) { - return nil - } - return err - } - familyName, err := store.ReadEntry(ctx, sessionId, storedb.DATA_FAMILY_NAME) - if err != nil { - if db.IsNotFound(err) { - return nil - } - return err - } - pubKey, err := store.ReadEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY) - if err != nil { - if db.IsNotFound(err) { - return nil - } - return err - } - aliasInput := fmt.Sprintf("%s%s", firstName, familyName) - aliasResult, err := h.accountService.RequestAlias(ctx, string(pubKey), aliasInput) - if err != nil { - logg.ErrorCtxf(ctx, "failed to retrieve alias", "alias", aliasInput, "error_alias_request", err) - return fmt.Errorf("Failed to retrieve alias: %s", err.Error()) - } - alias = aliasResult.Alias - //Store the alias - err = store.WriteEntry(ctx, sessionId, storedb.DATA_ACCOUNT_ALIAS, []byte(alias)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write account alias", "key", storedb.DATA_ACCOUNT_ALIAS, "value", alias, "error", err) - return err - } - return nil -} - // RequestCustomAlias requests an ENS based alias name based on a user's input,then saves it as temporary value func (h *MenuHandlers) RequestCustomAlias(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result diff --git a/handlers/application/menuhandler_test.go b/handlers/application/menuhandler_test.go index a2485c0..ddff16e 100644 --- a/handlers/application/menuhandler_test.go +++ b/handlers/application/menuhandler_test.go @@ -3154,97 +3154,6 @@ func TestResetUnregisteredNumber(t *testing.T) { assert.Equal(t, expectedResult, res) } -func TestConstructAccountAlias(t *testing.T) { - ctx, store := InitializeTestStore(t) - sessionId := "session123" - mockAccountService := new(mocks.MockAccountService) - - ctx = context.WithValue(ctx, "SessionId", sessionId) - - h := &MenuHandlers{ - userdataStore: store, - accountService: mockAccountService, - } - - tests := []struct { - name string - firstName string - familyName string - publicKey string - expectedAlias string - aliasResponse *models.RequestAliasResult - aliasError error - expectedError error - }{ - { - name: "Valid alias construction", - firstName: "John", - familyName: "Doe", - publicKey: "pubkey123", - expectedAlias: "JohnDoeAlias", - aliasResponse: &models.RequestAliasResult{Alias: "JohnDoeAlias"}, - aliasError: nil, - expectedError: nil, - }, - { - name: "Account service fails to return alias", - firstName: "Jane", - familyName: "Smith", - publicKey: "pubkey456", - expectedAlias: "", - aliasResponse: nil, - aliasError: fmt.Errorf("service unavailable"), - expectedError: fmt.Errorf("Failed to retrieve alias: service unavailable"), - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if tt.firstName != "" { - err := store.WriteEntry(ctx, sessionId, storedb.DATA_FIRST_NAME, []byte(tt.firstName)) - require.NoError(t, err) - } - - if tt.familyName != "" { - err := store.WriteEntry(ctx, sessionId, storedb.DATA_FAMILY_NAME, []byte(tt.familyName)) - require.NoError(t, err) - } - - if tt.publicKey != "" { - err := store.WriteEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY, []byte(tt.publicKey)) - require.NoError(t, err) - } - - aliasInput := fmt.Sprintf("%s%s", tt.firstName, tt.familyName) - - // Mock service behavior - mockAccountService.On( - "RequestAlias", - tt.publicKey, - aliasInput, - ).Return(tt.aliasResponse, tt.aliasError) - - // Call the function under test - err := h.constructAccountAlias(ctx) - - // Assertions - if tt.expectedError != nil { - assert.EqualError(t, err, tt.expectedError.Error()) - } else { - assert.NoError(t, err) - if tt.expectedAlias != "" { - storedAlias, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACCOUNT_ALIAS) - require.NoError(t, err) - assert.Equal(t, tt.expectedAlias, string(storedAlias)) - } - } - - // Ensure mock expectations were met - mockAccountService.AssertExpectations(t) - }) - } -} - func TestInsertProfileItems(t *testing.T) { ctx, store := InitializeTestStore(t) sessionId := "session123" From a5435692365cdb0a7bd459a9a926d12528d7cdee Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Mon, 30 Jun 2025 13:14:34 +0300 Subject: [PATCH 03/16] add a helper function FormatVoucherList to combine the voucher symbols with their balances --- store/vouchers.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/store/vouchers.go b/store/vouchers.go index 120358c..a8f4504 100644 --- a/store/vouchers.go +++ b/store/vouchers.go @@ -182,3 +182,30 @@ func UpdateVoucherData(ctx context.Context, store DataStore, sessionId string, d return nil } + +// FormatVoucherList combines the voucher symbols with their balances (SRF 0.11) +func FormatVoucherList(ctx context.Context, symbolsData, balancesData string) []string { + symbols := strings.Split(symbolsData, "\n") + balances := strings.Split(balancesData, "\n") + + var combined []string + for i := 0; i < len(symbols) && i < len(balances); i++ { + symbolParts := strings.SplitN(symbols[i], ":", 2) + balanceParts := strings.SplitN(balances[i], ":", 2) + + if len(symbolParts) == 2 && len(balanceParts) == 2 { + index := strings.TrimSpace(symbolParts[0]) + symbol := strings.TrimSpace(symbolParts[1]) + rawBalance := strings.TrimSpace(balanceParts[1]) + + formattedBalance, err := TruncateDecimalString(rawBalance, 2) + if err != nil { + logg.ErrorCtxf(ctx, "failed to format balance", "balance", rawBalance, "error", err) + formattedBalance = rawBalance + } + + combined = append(combined, fmt.Sprintf("%s: %s %s", index, symbol, formattedBalance)) + } + } + return combined +} From 706b6fe6299bc7208916e781feb01dbbf435077a Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Mon, 30 Jun 2025 13:31:55 +0300 Subject: [PATCH 04/16] include the balance next to each voucher --- handlers/application/menuhandler.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/handlers/application/menuhandler.go b/handlers/application/menuhandler.go index 77abdd2..94748eb 100644 --- a/handlers/application/menuhandler.go +++ b/handlers/application/menuhandler.go @@ -2141,17 +2141,25 @@ func (h *MenuHandlers) GetVoucherList(ctx context.Context, sym string, input []b // Read vouchers from the store voucherData, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_VOUCHER_SYMBOLS) - logg.InfoCtxf(ctx, "reading GetVoucherList entries for sessionId: %s", sessionId, "key", storedb.DATA_VOUCHER_SYMBOLS, "voucherData", voucherData) + logg.InfoCtxf(ctx, "reading voucherData in GetVoucherList", "sessionId", sessionId, "key", storedb.DATA_VOUCHER_SYMBOLS, "voucherData", voucherData) if err != nil { logg.ErrorCtxf(ctx, "failed to read voucherData entires with", "key", storedb.DATA_VOUCHER_SYMBOLS, "error", err) return res, err } - formattedData := h.ReplaceSeparatorFunc(string(voucherData)) + voucherBalances, err := userStore.ReadEntry(ctx, sessionId, storedb.DATA_VOUCHER_BALANCES) + logg.InfoCtxf(ctx, "reading voucherBalances in GetVoucherList", "sessionId", sessionId, "key", storedb.DATA_VOUCHER_BALANCES, "voucherBalances", voucherBalances) + if err != nil { + logg.ErrorCtxf(ctx, "failed to read voucherData entires with", "key", storedb.DATA_VOUCHER_BALANCES, "error", err) + return res, err + } - logg.InfoCtxf(ctx, "final output for sessionId: %s", sessionId, "key", storedb.DATA_VOUCHER_SYMBOLS, "formattedData", formattedData) + formattedVoucherList := store.FormatVoucherList(ctx, string(voucherData), string(voucherBalances)) + finalOutput := strings.Join(formattedVoucherList, "\n") - res.Content = string(formattedData) + logg.InfoCtxf(ctx, "final output for GetVoucherList", "sessionId", sessionId, "finalOutput", finalOutput) + + res.Content = finalOutput return res, nil } From 9234bfd57982740fd39e1f4071ffdb13754e743a Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Mon, 30 Jun 2025 13:36:07 +0300 Subject: [PATCH 05/16] update the TestGetVoucherList to the expected content --- handlers/application/menuhandler_test.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/handlers/application/menuhandler_test.go b/handlers/application/menuhandler_test.go index f7a23ba..48ee27b 100644 --- a/handlers/application/menuhandler_test.go +++ b/handlers/application/menuhandler_test.go @@ -2208,20 +2208,25 @@ func TestGetVoucherList(t *testing.T) { ReplaceSeparatorFunc: mockReplaceSeparator, } - mockSyms := []byte("1:SRF\n2:MILO") + mockSymbols := []byte("1:SRF\n2:MILO") + mockBalances := []byte("1:10.099999\n2:40.7") - // Put voucher sym data from the store - err := store.WriteEntry(ctx, sessionId, storedb.DATA_VOUCHER_SYMBOLS, mockSyms) + // Put voucher symnols and balances data to the store + err := store.WriteEntry(ctx, sessionId, storedb.DATA_VOUCHER_SYMBOLS, mockSymbols) + if err != nil { + t.Fatal(err) + } + err = store.WriteEntry(ctx, sessionId, storedb.DATA_VOUCHER_BALANCES, mockBalances) if err != nil { t.Fatal(err) } - expectedSyms := []byte("1: SRF\n2: MILO") + expectedList := []byte("1: SRF 10.09\n2: MILO 40.70") res, err := h.GetVoucherList(ctx, "", []byte("")) assert.NoError(t, err) - assert.Equal(t, res.Content, string(expectedSyms)) + assert.Equal(t, res.Content, string(expectedList)) } func TestViewVoucher(t *testing.T) { From ea3a6d8382658e7c109c81a66026ba90f06f8cf7 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Mon, 30 Jun 2025 18:18:06 +0300 Subject: [PATCH 06/16] call the UpdateAlias if the account has an Aias --- handlers/application/menuhandler.go | 37 ++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/handlers/application/menuhandler.go b/handlers/application/menuhandler.go index 29148e0..55e9f19 100644 --- a/handlers/application/menuhandler.go +++ b/handlers/application/menuhandler.go @@ -2570,6 +2570,7 @@ func (h *MenuHandlers) persistLanguageCode(ctx context.Context, code string) err // RequestCustomAlias requests an ENS based alias name based on a user's input,then saves it as temporary value func (h *MenuHandlers) RequestCustomAlias(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result + var alias string sessionId, ok := ctx.Value("SessionId").(string) if !ok { return res, fmt.Errorf("missing session") @@ -2601,21 +2602,35 @@ func (h *MenuHandlers) RequestCustomAlias(ctx context.Context, sym string, input } } sanitizedInput := sanitizeAliasHint(string(input)) - aliasResult, err := h.accountService.RequestAlias(ctx, string(pubKey), sanitizedInput) - if err != nil { - res.FlagSet = append(res.FlagSet, flag_api_error) - logg.ErrorCtxf(ctx, "failed to retrieve alias", "alias", string(aliasHint), "error_alias_request", err) - return res, nil + // Check if an alias already exists + existingAlias, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACCOUNT_ALIAS) + if err == nil && len(existingAlias) > 0 { + // Update existing alias + aliasResult, err := h.accountService.UpdateAlias(ctx, sanitizedInput, string(pubKey)) + if err != nil { + res.FlagSet = append(res.FlagSet, flag_api_error) + logg.ErrorCtxf(ctx, "failed to update alias", "alias", sanitizedInput, "error", err) + return res, nil + } + alias := aliasResult.Alias + logg.InfoCtxf(ctx, "Updated alias", "alias", alias) + } else { + // Register a new alias + aliasResult, err := h.accountService.RequestAlias(ctx, string(pubKey), sanitizedInput) + if err != nil { + res.FlagSet = append(res.FlagSet, flag_api_error) + logg.ErrorCtxf(ctx, "failed to retrieve alias", "alias", sanitizedInput, "error_alias_request", err) + return res, nil + } + res.FlagReset = append(res.FlagReset, flag_api_error) + + alias := aliasResult.Alias + logg.InfoCtxf(ctx, "Suggested alias", "alias", alias) } - res.FlagReset = append(res.FlagReset, flag_api_error) - - alias := aliasResult.Alias - logg.InfoCtxf(ctx, "Suggested alias ", "alias", alias) - //Store the returned alias,wait for user to confirm it as new account alias err = store.WriteEntry(ctx, sessionId, storedb.DATA_SUGGESTED_ALIAS, []byte(alias)) if err != nil { - logg.ErrorCtxf(ctx, "failed to write account alias", "key", storedb.DATA_TEMPORARY_VALUE, "value", alias, "error", err) + logg.ErrorCtxf(ctx, "failed to write suggested alias", "key", storedb.DATA_SUGGESTED_ALIAS, "value", alias, "error", err) return res, err } } From b31a68ad8ebea68556a3cd195db7536598cd3881 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Tue, 1 Jul 2025 00:27:45 +0300 Subject: [PATCH 07/16] added logging --- handlers/application/menuhandler.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/handlers/application/menuhandler.go b/handlers/application/menuhandler.go index 55e9f19..1eefabd 100644 --- a/handlers/application/menuhandler.go +++ b/handlers/application/menuhandler.go @@ -2605,6 +2605,7 @@ func (h *MenuHandlers) RequestCustomAlias(ctx context.Context, sym string, input // Check if an alias already exists existingAlias, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACCOUNT_ALIAS) if err == nil && len(existingAlias) > 0 { + logg.InfoCtxf(ctx, "Current alias", "alias", string(existingAlias)) // Update existing alias aliasResult, err := h.accountService.UpdateAlias(ctx, sanitizedInput, string(pubKey)) if err != nil { @@ -2615,6 +2616,7 @@ func (h *MenuHandlers) RequestCustomAlias(ctx context.Context, sym string, input alias := aliasResult.Alias logg.InfoCtxf(ctx, "Updated alias", "alias", alias) } else { + logg.InfoCtxf(ctx, "Registering a new alias", "err", err) // Register a new alias aliasResult, err := h.accountService.RequestAlias(ctx, string(pubKey), sanitizedInput) if err != nil { From e1219354bbd32e829484b72d36fdcaf335c3a0e3 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Tue, 1 Jul 2025 00:32:42 +0300 Subject: [PATCH 08/16] use the correct AliasUpdateURL on sarafu-api --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index bcc38f5..3677115 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.23.4 require ( git.defalsify.org/vise.git v0.3.2-0.20250528124150-03bf7bfc1b66 git.grassecon.net/grassrootseconomics/common v0.9.0-beta.1.0.20250417111317-2953f4c2f32e - git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250626065419-57ee409f9629 + git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630213135-50ee455e7069 git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250408094335-e2d1f65bb306 git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694 github.com/alecthomas/assert/v2 v2.2.2 diff --git a/go.sum b/go.sum index 6af47fe..5ac8bfb 100644 --- a/go.sum +++ b/go.sum @@ -14,6 +14,8 @@ git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250624090744- git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250624090744-339ba854c997/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250626065419-57ee409f9629 h1:ew3vCFrLS/7/8uULTTPCbsHzFntQ6X68SScnBEy3pl0= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250626065419-57ee409f9629/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8= +git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630213135-50ee455e7069 h1:re+hdr5NAC6JqhyvjMCkgX17fFi0u3Mawc6RBnBJW8I= +git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630213135-50ee455e7069/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8= git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250408094335-e2d1f65bb306 h1:Jo+yWysWw/N5BJQtAyEMN8ePVvAyPHv+JG4lQti+1N4= git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250408094335-e2d1f65bb306/go.mod h1:FdLwYtzsjOIcDiW4uDgDYnB4Wdzq12uJUe0QHSSPbSo= git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694 h1:DjJlBSz0S13acft5XZDWk7ZYnzElym0xLMYEVgyNJ+E= From 2ad5c2e8df40ee49523f7a037e02fb8da5f46362 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Tue, 1 Jul 2025 00:37:15 +0300 Subject: [PATCH 09/16] use the correct PUT method in the update --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 3677115..b2f7959 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.23.4 require ( git.defalsify.org/vise.git v0.3.2-0.20250528124150-03bf7bfc1b66 git.grassecon.net/grassrootseconomics/common v0.9.0-beta.1.0.20250417111317-2953f4c2f32e - git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630213135-50ee455e7069 + git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630213606-12940bb5f284 git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250408094335-e2d1f65bb306 git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694 github.com/alecthomas/assert/v2 v2.2.2 diff --git a/go.sum b/go.sum index 5ac8bfb..6ab8df6 100644 --- a/go.sum +++ b/go.sum @@ -16,6 +16,8 @@ git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250626065419- git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250626065419-57ee409f9629/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630213135-50ee455e7069 h1:re+hdr5NAC6JqhyvjMCkgX17fFi0u3Mawc6RBnBJW8I= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630213135-50ee455e7069/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8= +git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630213606-12940bb5f284 h1:2zMU9jPd6xEO6oY9oxr84sdT9G3d09eyAkjVBAz9eco= +git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630213606-12940bb5f284/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8= git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250408094335-e2d1f65bb306 h1:Jo+yWysWw/N5BJQtAyEMN8ePVvAyPHv+JG4lQti+1N4= git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250408094335-e2d1f65bb306/go.mod h1:FdLwYtzsjOIcDiW4uDgDYnB4Wdzq12uJUe0QHSSPbSo= git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694 h1:DjJlBSz0S13acft5XZDWk7ZYnzElym0xLMYEVgyNJ+E= From 7d1951ec7ac220014f9cd9ba2fb9e0cb647cbf59 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Tue, 1 Jul 2025 00:51:05 +0300 Subject: [PATCH 10/16] use updated sarafu-api with correct order of variables --- go.mod | 2 +- go.sum | 2 ++ handlers/application/menuhandler.go | 6 +++--- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index b2f7959..1ce7f3c 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.23.4 require ( git.defalsify.org/vise.git v0.3.2-0.20250528124150-03bf7bfc1b66 git.grassecon.net/grassrootseconomics/common v0.9.0-beta.1.0.20250417111317-2953f4c2f32e - git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630213606-12940bb5f284 + git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630214912-814bef2b209a git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250408094335-e2d1f65bb306 git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694 github.com/alecthomas/assert/v2 v2.2.2 diff --git a/go.sum b/go.sum index 6ab8df6..c369628 100644 --- a/go.sum +++ b/go.sum @@ -18,6 +18,8 @@ git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630213135- git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630213135-50ee455e7069/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630213606-12940bb5f284 h1:2zMU9jPd6xEO6oY9oxr84sdT9G3d09eyAkjVBAz9eco= git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630213606-12940bb5f284/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8= +git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630214912-814bef2b209a h1:KuhJ/WY4RCGmrXUA680ciaponM4vM5zBOJfnCpUo2fc= +git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250630214912-814bef2b209a/go.mod h1:y/vsN8UO0wSxZk3gv0y5df4RPKMJI6TIxjVcVCPF8T8= git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250408094335-e2d1f65bb306 h1:Jo+yWysWw/N5BJQtAyEMN8ePVvAyPHv+JG4lQti+1N4= git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.2.0.20250408094335-e2d1f65bb306/go.mod h1:FdLwYtzsjOIcDiW4uDgDYnB4Wdzq12uJUe0QHSSPbSo= git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694 h1:DjJlBSz0S13acft5XZDWk7ZYnzElym0xLMYEVgyNJ+E= diff --git a/handlers/application/menuhandler.go b/handlers/application/menuhandler.go index 1eefabd..e1d80f1 100644 --- a/handlers/application/menuhandler.go +++ b/handlers/application/menuhandler.go @@ -2595,7 +2595,7 @@ func (h *MenuHandlers) RequestCustomAlias(ctx context.Context, sym string, input if err != nil { return res, err } - pubKey, err := store.ReadEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY) + publicKey, err := store.ReadEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY) if err != nil { if db.IsNotFound(err) { return res, nil @@ -2607,7 +2607,7 @@ func (h *MenuHandlers) RequestCustomAlias(ctx context.Context, sym string, input if err == nil && len(existingAlias) > 0 { logg.InfoCtxf(ctx, "Current alias", "alias", string(existingAlias)) // Update existing alias - aliasResult, err := h.accountService.UpdateAlias(ctx, sanitizedInput, string(pubKey)) + aliasResult, err := h.accountService.UpdateAlias(ctx, sanitizedInput, string(publicKey)) if err != nil { res.FlagSet = append(res.FlagSet, flag_api_error) logg.ErrorCtxf(ctx, "failed to update alias", "alias", sanitizedInput, "error", err) @@ -2618,7 +2618,7 @@ func (h *MenuHandlers) RequestCustomAlias(ctx context.Context, sym string, input } else { logg.InfoCtxf(ctx, "Registering a new alias", "err", err) // Register a new alias - aliasResult, err := h.accountService.RequestAlias(ctx, string(pubKey), sanitizedInput) + aliasResult, err := h.accountService.RequestAlias(ctx, string(publicKey), sanitizedInput) if err != nil { res.FlagSet = append(res.FlagSet, flag_api_error) logg.ErrorCtxf(ctx, "failed to retrieve alias", "alias", sanitizedInput, "error_alias_request", err) From a33ff7ffda1701acab177120b8b04c2f0ac4fbbb Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Tue, 1 Jul 2025 00:56:50 +0300 Subject: [PATCH 11/16] added logging --- handlers/application/menuhandler.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/handlers/application/menuhandler.go b/handlers/application/menuhandler.go index e1d80f1..523e76e 100644 --- a/handlers/application/menuhandler.go +++ b/handlers/application/menuhandler.go @@ -2630,6 +2630,7 @@ func (h *MenuHandlers) RequestCustomAlias(ctx context.Context, sym string, input logg.InfoCtxf(ctx, "Suggested alias", "alias", alias) } //Store the returned alias,wait for user to confirm it as new account alias + logg.InfoCtxf(ctx, "Final suggested alias", "alias", alias) err = store.WriteEntry(ctx, sessionId, storedb.DATA_SUGGESTED_ALIAS, []byte(alias)) if err != nil { logg.ErrorCtxf(ctx, "failed to write suggested alias", "key", storedb.DATA_SUGGESTED_ALIAS, "value", alias, "error", err) @@ -2660,7 +2661,8 @@ func (h *MenuHandlers) GetSuggestedAlias(ctx context.Context, sym string, input return res, fmt.Errorf("missing session") } suggestedAlias, err := store.ReadEntry(ctx, sessionId, storedb.DATA_SUGGESTED_ALIAS) - if err != nil { + if err != nil && len(suggestedAlias) <= 0 { + logg.ErrorCtxf(ctx, "failed to read suggested alias", "key", storedb.DATA_SUGGESTED_ALIAS, "error", err) return res, nil } res.Content = string(suggestedAlias) From 8416d4fddba3b6c4513551ee751df82ffaab4f4a Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Tue, 1 Jul 2025 01:18:03 +0300 Subject: [PATCH 12/16] use a single alias variable --- handlers/application/menuhandler.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/handlers/application/menuhandler.go b/handlers/application/menuhandler.go index 523e76e..2e51afb 100644 --- a/handlers/application/menuhandler.go +++ b/handlers/application/menuhandler.go @@ -2613,7 +2613,7 @@ func (h *MenuHandlers) RequestCustomAlias(ctx context.Context, sym string, input logg.ErrorCtxf(ctx, "failed to update alias", "alias", sanitizedInput, "error", err) return res, nil } - alias := aliasResult.Alias + alias = aliasResult.Alias logg.InfoCtxf(ctx, "Updated alias", "alias", alias) } else { logg.InfoCtxf(ctx, "Registering a new alias", "err", err) @@ -2626,7 +2626,7 @@ func (h *MenuHandlers) RequestCustomAlias(ctx context.Context, sym string, input } res.FlagReset = append(res.FlagReset, flag_api_error) - alias := aliasResult.Alias + alias = aliasResult.Alias logg.InfoCtxf(ctx, "Suggested alias", "alias", alias) } //Store the returned alias,wait for user to confirm it as new account alias From ba2cb4b81375034717bff6f93e3f05022b858776 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Tue, 1 Jul 2025 01:29:52 +0300 Subject: [PATCH 13/16] use the DATA_SUGGESTED_ALIAS to check the status --- handlers/application/menuhandler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handlers/application/menuhandler.go b/handlers/application/menuhandler.go index 2e51afb..3b6e3cf 100644 --- a/handlers/application/menuhandler.go +++ b/handlers/application/menuhandler.go @@ -2603,7 +2603,7 @@ func (h *MenuHandlers) RequestCustomAlias(ctx context.Context, sym string, input } sanitizedInput := sanitizeAliasHint(string(input)) // Check if an alias already exists - existingAlias, err := store.ReadEntry(ctx, sessionId, storedb.DATA_ACCOUNT_ALIAS) + existingAlias, err := store.ReadEntry(ctx, sessionId, storedb.DATA_SUGGESTED_ALIAS) if err == nil && len(existingAlias) > 0 { logg.InfoCtxf(ctx, "Current alias", "alias", string(existingAlias)) // Update existing alias From 57426b3565a9647b907fb430dbf17bb7c8775d88 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 2 Jul 2025 09:29:56 +0300 Subject: [PATCH 14/16] use the TruncateDecimalString to format the displayed balance --- handlers/application/menuhandler.go | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/handlers/application/menuhandler.go b/handlers/application/menuhandler.go index 0effbec..426fcef 100644 --- a/handlers/application/menuhandler.go +++ b/handlers/application/menuhandler.go @@ -3,7 +3,6 @@ package application import ( "bytes" "context" - "errors" "fmt" "path" "strconv" @@ -1504,17 +1503,14 @@ func loadUserContent(ctx context.Context, activeSym string, balance string, alia l := gotext.NewLocale(translationDir, code) l.AddDomain("default") - balFloat, err := strconv.ParseFloat(balance, 64) + // Format the balance to 2 decimal places or default to 0.00 + formattedAmount, err := store.TruncateDecimalString(balance, 2) if err != nil { - //Only exclude ErrSyntax error to avoid returning an error if the active bal is not available yet - if !errors.Is(err, strconv.ErrSyntax) { - logg.ErrorCtxf(ctx, "failed to parse activeBal as float", "value", balance, "error", err) - return "", err - } - balFloat = 0.00 + formattedAmount = "0.00" } - // Format to 2 decimal places - balStr := fmt.Sprintf("%.2f %s", balFloat, activeSym) + + // format the final output + balStr := fmt.Sprintf("%s %s", formattedAmount, activeSym) if alias != "" { content = l.Get("%s balance: %s\n", alias, balStr) } else { From a3dae12c7ad9a297a03fa39238077de0b18f4348 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 2 Jul 2025 09:30:30 +0300 Subject: [PATCH 15/16] update the TestCheckBalance and add more test cases --- handlers/application/menuhandler_test.go | 46 ++++++++++++++++++++---- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/handlers/application/menuhandler_test.go b/handlers/application/menuhandler_test.go index 0463e01..6161f41 100644 --- a/handlers/application/menuhandler_test.go +++ b/handlers/application/menuhandler_test.go @@ -1840,20 +1840,42 @@ func TestCheckBalance(t *testing.T) { name string sessionId string publicKey string + alias string activeSym string activeBal string expectedResult resource.Result expectError bool }{ + { + name: "User with no active sym", + sessionId: "session123", + publicKey: "0X98765432109", + alias: "", + activeSym: "", + activeBal: "", + expectedResult: resource.Result{Content: "Balance: 0.00 \n"}, + expectError: false, + }, { name: "User with active sym", sessionId: "session123", publicKey: "0X98765432109", + alias: "", activeSym: "ETH", activeBal: "1.5", expectedResult: resource.Result{Content: "Balance: 1.50 ETH\n"}, expectError: false, }, + { + name: "User with active sym and alias", + sessionId: "session123", + publicKey: "0X98765432109", + alias: "user72", + activeSym: "SRF", + activeBal: "10.967", + expectedResult: resource.Result{Content: "user72 balance: 10.96 SRF\n"}, + expectError: false, + }, } for _, tt := range tests { @@ -1866,13 +1888,25 @@ func TestCheckBalance(t *testing.T) { accountService: mockAccountService, } - err := store.WriteEntry(ctx, tt.sessionId, storedb.DATA_ACTIVE_SYM, []byte(tt.activeSym)) - if err != nil { - t.Fatal(err) + if tt.alias != "" { + err := store.WriteEntry(ctx, tt.sessionId, storedb.DATA_ACCOUNT_ALIAS, []byte(tt.alias)) + if err != nil { + t.Fatal(err) + } } - err = store.WriteEntry(ctx, tt.sessionId, storedb.DATA_ACTIVE_BAL, []byte(tt.activeBal)) - if err != nil { - t.Fatal(err) + + if tt.activeSym != "" { + err := store.WriteEntry(ctx, tt.sessionId, storedb.DATA_ACTIVE_SYM, []byte(tt.activeSym)) + if err != nil { + t.Fatal(err) + } + } + + if tt.activeBal != "" { + err := store.WriteEntry(ctx, tt.sessionId, storedb.DATA_ACTIVE_BAL, []byte(tt.activeBal)) + if err != nil { + t.Fatal(err) + } } res, err := h.CheckBalance(ctx, "check_balance", []byte("")) From 16dd0f6ebf312f24e5d8a3243fd36ba787eed807 Mon Sep 17 00:00:00 2001 From: alfred-mk Date: Wed, 2 Jul 2025 19:10:02 +0300 Subject: [PATCH 16/16] set the first voucher as the active voucher when the current active sym is not found in the vouchers response --- handlers/application/menuhandler.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/handlers/application/menuhandler.go b/handlers/application/menuhandler.go index 426fcef..e8f899b 100644 --- a/handlers/application/menuhandler.go +++ b/handlers/application/menuhandler.go @@ -2088,8 +2088,9 @@ func (h *MenuHandlers) ManageVouchers(ctx context.Context, sym string, input []b } if activeData == nil { - logg.ErrorCtxf(ctx, "activeSym not found in vouchers", "activeSym", activeSymStr) - return res, fmt.Errorf("activeSym %s not found in vouchers", activeSymStr) + logg.ErrorCtxf(ctx, "activeSym not found in vouchers, setting the first voucher as the default", "activeSym", activeSymStr) + firstVoucher := vouchersResp[0] + activeData = &firstVoucher } // Scale down the balance