Compare commits

..

14 Commits

28 changed files with 60 additions and 214 deletions

View File

@ -151,7 +151,7 @@ func GetTemporaryVoucherData(ctx context.Context, store DataStore, sessionId str
return data, nil return data, nil
} }
// UpdateVoucherData updates the active 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 { func UpdateVoucherData(ctx context.Context, store DataStore, sessionId string, data *dataserviceapi.TokenHoldings) error {
logg.TraceCtxf(ctx, "dtal", "data", data) logg.TraceCtxf(ctx, "dtal", "data", data)
// Active voucher data entries // Active voucher data entries

View File

@ -55,9 +55,6 @@ func(f *BaseSessionHandler) Process(rqs RequestSession) (RequestSession, error)
} }
f.hn = f.hn.WithPersister(rqs.Storage.Persister) f.hn = f.hn.WithPersister(rqs.Storage.Persister)
defer func() {
f.hn.Exit()
}()
eni := f.GetEngine(rqs.Config, f.rs, rqs.Storage.Persister) eni := f.GetEngine(rqs.Config, f.rs, rqs.Storage.Persister)
en, ok := eni.(*engine.DefaultEngine) en, ok := eni.(*engine.DefaultEngine)
if !ok { if !ok {

View File

@ -10,6 +10,7 @@ import (
"strings" "strings"
"git.defalsify.org/vise.git/asm" "git.defalsify.org/vise.git/asm"
"github.com/grassrootseconomics/eth-custodial/pkg/api"
"git.defalsify.org/vise.git/cache" "git.defalsify.org/vise.git/cache"
"git.defalsify.org/vise.git/db" "git.defalsify.org/vise.git/db"
@ -24,13 +25,14 @@ import (
"gopkg.in/leonelquinteros/gotext.v1" "gopkg.in/leonelquinteros/gotext.v1"
"git.grassecon.net/urdt/ussd/internal/storage" "git.grassecon.net/urdt/ussd/internal/storage"
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
) )
var ( var (
logg = logging.NewVanilla().WithDomain("ussdmenuhandler") logg = logging.NewVanilla().WithDomain("ussdmenuhandler")
scriptDir = path.Join("services", "registration") scriptDir = path.Join("services", "registration")
translationDir = path.Join(scriptDir, "locale") translationDir = path.Join(scriptDir, "locale")
okResponse *api.OKResponse
errResponse *api.ErrResponse
) )
// Define the regex patterns as constants // Define the regex patterns as constants
@ -112,9 +114,6 @@ func (h *Handlers) Init(ctx context.Context, sym string, input []byte) (resource
logg.WarnCtxf(ctx, "handler init called before it is ready or more than once", "state", h.st, "cache", h.ca) logg.WarnCtxf(ctx, "handler init called before it is ready or more than once", "state", h.st, "cache", h.ca)
return r, nil return r, nil
} }
defer func() {
h.Exit()
}()
h.st = h.pe.GetState() h.st = h.pe.GetState()
h.ca = h.pe.GetMemory() h.ca = h.pe.GetMemory()
@ -134,16 +133,13 @@ func (h *Handlers) Init(ctx context.Context, sym string, input []byte) (resource
logg.ErrorCtxf(ctx, "perister fail in handler", "state", h.st, "cache", h.ca) logg.ErrorCtxf(ctx, "perister fail in handler", "state", h.st, "cache", h.ca)
return r, fmt.Errorf("cannot get state and memory for handler") return r, fmt.Errorf("cannot get state and memory for handler")
} }
h.pe = nil
logg.DebugCtxf(ctx, "handler has been initialized", "state", h.st, "cache", h.ca) logg.DebugCtxf(ctx, "handler has been initialized", "state", h.st, "cache", h.ca)
return r, nil return r, nil
} }
func (h *Handlers) Exit() {
h.pe = nil
}
// SetLanguage sets the language across the menu // SetLanguage sets the language across the menu
func (h *Handlers) SetLanguage(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) SetLanguage(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
@ -152,8 +148,7 @@ func (h *Handlers) SetLanguage(ctx context.Context, sym string, input []byte) (r
code := strings.Split(symbol, "_")[1] code := strings.Split(symbol, "_")[1]
if !utils.IsValidISO639(code) { if !utils.IsValidISO639(code) {
//Fallback to english instead? return res, nil
code = "eng"
} }
res.FlagSet = append(res.FlagSet, state.FLAG_LANG) res.FlagSet = append(res.FlagSet, state.FLAG_LANG)
res.Content = code res.Content = code
@ -762,11 +757,12 @@ func (h *Handlers) VerifyYob(ctx context.Context, sym string, input []byte) (res
return res, nil return res, nil
} }
if utils.IsValidYOb(date) { if len(date) == 4 {
res.FlagReset = append(res.FlagReset, flag_incorrect_date_format) res.FlagReset = append(res.FlagReset, flag_incorrect_date_format)
} else { } else {
res.FlagSet = append(res.FlagSet, flag_incorrect_date_format) res.FlagSet = append(res.FlagSet, flag_incorrect_date_format)
} }
return res, nil return res, nil
} }
@ -815,17 +811,7 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) (
return res, err return res, err
} }
// Convert activeBal from []byte to float64 res.Content = l.Get("Balance: %s\n", fmt.Sprintf("%s %s", activeBal, activeSym))
balFloat, err := strconv.ParseFloat(string(activeBal), 64)
if err != nil {
logg.ErrorCtxf(ctx, "failed to parse activeBal as float", "value", string(activeBal), "error", err)
return res, err
}
// Format to 2 decimal places
balStr := fmt.Sprintf("%.2f %s", balFloat, activeSym)
res.Content = l.Get("Balance: %s\n", balStr)
return res, nil return res, nil
} }
@ -1402,7 +1388,14 @@ func (h *Handlers) GetProfileInfo(ctx context.Context, sym string, input []byte)
offerings := getEntryOrDefault(store.ReadEntry(ctx, sessionId, common.DATA_OFFERINGS)) offerings := getEntryOrDefault(store.ReadEntry(ctx, sessionId, common.DATA_OFFERINGS))
// Construct the full name // Construct the full name
name := utils.ConstructName(firstName, familyName, defaultValue) name := defaultValue
if familyName != defaultValue {
if firstName == defaultValue {
name = familyName
} else {
name = firstName + " " + familyName
}
}
// Calculate age from year of birth // Calculate age from year of birth
age := defaultValue age := defaultValue
@ -1541,38 +1534,6 @@ func (h *Handlers) CheckVouchers(ctx context.Context, sym string, input []byte)
return res, nil return res, nil
} }
// check the current active sym and update the data
activeSym, _ := store.ReadEntry(ctx, sessionId, common.DATA_ACTIVE_SYM)
if activeSym != nil {
activeSymStr := string(activeSym)
// Find the matching voucher data
var activeData *dataserviceapi.TokenHoldings
for _, voucher := range vouchersResp {
if voucher.TokenSymbol == activeSymStr {
activeData = &voucher
break
}
}
if activeData == nil {
logg.ErrorCtxf(ctx, "activeSym not found in vouchers", "activeSym", activeSymStr)
return res, fmt.Errorf("activeSym %s not found in vouchers", activeSymStr)
}
// Scale down the balance
scaledBalance := common.ScaleDownBalance(activeData.Balance, activeData.TokenDecimals)
// Update the balance field with the scaled value
activeData.Balance = scaledBalance
// Pass the matching voucher data to UpdateVoucherData
if err := common.UpdateVoucherData(ctx, h.userdataStore, sessionId, activeData); err != nil {
logg.ErrorCtxf(ctx, "failed on UpdateVoucherData", "error", err)
return res, err
}
}
data := common.ProcessVouchers(vouchersResp) data := common.ProcessVouchers(vouchersResp)
// Store all voucher data // Store all voucher data
@ -1617,10 +1578,6 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r
return res, fmt.Errorf("missing session") return res, fmt.Errorf("missing session")
} }
code := codeFromCtx(ctx)
l := gotext.NewLocale(translationDir, code)
l.AddDomain("default")
flag_incorrect_voucher, _ := h.flagManager.GetFlag("flag_incorrect_voucher") flag_incorrect_voucher, _ := h.flagManager.GetFlag("flag_incorrect_voucher")
inputStr := string(input) inputStr := string(input)
@ -1645,7 +1602,7 @@ func (h *Handlers) ViewVoucher(ctx context.Context, sym string, input []byte) (r
} }
res.FlagReset = append(res.FlagReset, flag_incorrect_voucher) res.FlagReset = append(res.FlagReset, flag_incorrect_voucher)
res.Content = l.Get("Symbol: %s\nBalance: %s", metadata.TokenSymbol, metadata.Balance) res.Content = fmt.Sprintf("%s\n%s", metadata.TokenSymbol, metadata.Balance)
return res, nil return res, nil
} }
@ -1701,9 +1658,10 @@ func (h *Handlers) GetVoucherDetails(ctx context.Context, sym string, input []by
return res, nil return res, nil
} }
res.Content = fmt.Sprintf( tokenSymbol := voucherData.TokenSymbol
"Name: %s\nSymbol: %s\nCommodity: %s\nLocation: %s", voucherData.TokenName, voucherData.TokenSymbol, voucherData.TokenCommodity, voucherData.TokenLocation, tokenName := voucherData.TokenName
)
res.Content = fmt.Sprintf("%s %s", tokenSymbol, tokenName)
return res, nil return res, nil
} }

View File

@ -1498,10 +1498,10 @@ func TestValidateRecipient(t *testing.T) {
}{ }{
{ {
name: "Test with invalid recepient", name: "Test with invalid recepient",
input: []byte("7?1234"), input: []byte("9234adf5"),
expectedResult: resource.Result{ expectedResult: resource.Result{
FlagSet: []uint32{flag_invalid_recipient}, FlagSet: []uint32{flag_invalid_recipient},
Content: "7?1234", Content: "9234adf5",
}, },
}, },
{ {
@ -1517,40 +1517,22 @@ func TestValidateRecipient(t *testing.T) {
input: []byte("0711223344"), input: []byte("0711223344"),
expectedResult: resource.Result{}, expectedResult: resource.Result{},
}, },
{
name: "Test with address",
input: []byte("0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9"),
expectedResult: resource.Result{},
},
{
name: "Test with alias recepient",
input: []byte("alias123"),
expectedResult: resource.Result{},
},
} }
// store a public key for the valid recipient // store a public key for the valid recipient
err = store.WriteEntry(ctx, "+254711223344", common.DATA_PUBLIC_KEY, []byte(publicKey)) err = store.WriteEntry(ctx, "0711223344", common.DATA_PUBLIC_KEY, []byte(publicKey))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
mockAccountService := new(mocks.MockAccountService)
// Create the Handlers instance // Create the Handlers instance
h := &Handlers{ h := &Handlers{
flagManager: fm.parser, flagManager: fm.parser,
userdataStore: store, userdataStore: store,
accountService: mockAccountService,
} }
aliasResponse := &dataserviceapi.AliasAddress{
Address: "0xd4c288865Ce0985a481Eef3be02443dF5E2e4Ea9",
}
mockAccountService.On("CheckAliasAddress", string(tt.input)).Return(aliasResponse, nil)
// Call the method // Call the method
res, err := h.ValidateRecipient(ctx, "validate_recepient", tt.input) res, err := h.ValidateRecipient(ctx, "validate_recepient", tt.input)
@ -1582,7 +1564,7 @@ func TestCheckBalance(t *testing.T) {
publicKey: "0X98765432109", publicKey: "0X98765432109",
activeSym: "ETH", activeSym: "ETH",
activeBal: "1.5", activeBal: "1.5",
expectedResult: resource.Result{Content: "Balance: 1.50 ETH\n"}, expectedResult: resource.Result{Content: "Balance: 1.5 ETH\n"},
expectError: false, expectError: false,
}, },
} }
@ -2008,7 +1990,7 @@ func TestViewVoucher(t *testing.T) {
res, err := h.ViewVoucher(ctx, "view_voucher", []byte("1")) res, err := h.ViewVoucher(ctx, "view_voucher", []byte("1"))
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, res.Content, "Symbol: SRF\nBalance: 100") assert.Equal(t, res.Content, "SRF\n100")
} }
func TestSetVoucher(t *testing.T) { func TestSetVoucher(t *testing.T) {
@ -2042,42 +2024,3 @@ func TestSetVoucher(t *testing.T) {
assert.Equal(t, string(tempData.TokenSymbol), res.Content) assert.Equal(t, string(tempData.TokenSymbol), res.Content)
} }
func TestGetVoucherDetails(t *testing.T) {
ctx, store := InitializeTestStore(t)
fm, err := NewFlagManager(flagsPath)
if err != nil {
t.Logf(err.Error())
}
mockAccountService := new(mocks.MockAccountService)
sessionId := "session123"
ctx = context.WithValue(ctx, "SessionId", sessionId)
expectedResult := resource.Result{}
tokA_AAddress := "0x0000000000000000000000000000000000000000"
h := &Handlers{
userdataStore: store,
flagManager: fm.parser,
accountService: mockAccountService,
}
err = store.WriteEntry(ctx, sessionId, common.DATA_ACTIVE_ADDRESS, []byte(tokA_AAddress))
if err != nil {
t.Fatal(err)
}
tokenDetails := &models.VoucherDataResult{
TokenName: "Token A",
TokenSymbol: "TOKA",
TokenLocation: "Kilifi,Kenya",
TokenCommodity: "Farming",
}
expectedResult.Content = fmt.Sprintf(
"Name: %s\nSymbol: %s\nCommodity: %s\nLocation: %s", tokenDetails.TokenName, tokenDetails.TokenSymbol, tokenDetails.TokenCommodity, tokenDetails.TokenLocation,
)
mockAccountService.On("VoucherData", string(tokA_AAddress)).Return(tokenDetails, nil)
res, err := h.GetVoucherDetails(ctx, "SessionId", []byte(""))
assert.NoError(t, err)
assert.Equal(t, expectedResult, res)
}

View File

@ -49,6 +49,6 @@ func (m *MockAccountService) TokenTransfer(ctx context.Context, amount, from, to
} }
func (m *MockAccountService) CheckAliasAddress(ctx context.Context, alias string) (*dataserviceapi.AliasAddress, error) { func (m *MockAccountService) CheckAliasAddress(ctx context.Context, alias string) (*dataserviceapi.AliasAddress, error) {
args := m.Called(alias) args := m.Called()
return args.Get(0).(*dataserviceapi.AliasAddress), args.Error(1) return args.Get(0).(*dataserviceapi.AliasAddress), args.Error(1)
} }

View File

@ -1,9 +1,6 @@
package utils package utils
import ( import "time"
"strconv"
"time"
)
// CalculateAge calculates the age based on a given birthdate and the current date in the format dd/mm/yy // CalculateAge calculates the age based on a given birthdate and the current date in the format dd/mm/yy
// It adjusts for cases where the current date is before the birthday in the current year. // It adjusts for cases where the current date is before the birthday in the current year.
@ -28,29 +25,11 @@ func CalculateAge(birthdate, today time.Time) int {
// It subtracts the YOB from the current year to determine the age. // It subtracts the YOB from the current year to determine the age.
// //
// Parameters: // Parameters:
// // yob: The year of birth as an integer.
// yob: The year of birth as an integer.
// //
// Returns: // Returns:
// // The calculated age as an integer.
// The calculated age as an integer.
func CalculateAgeWithYOB(yob int) int { func CalculateAgeWithYOB(yob int) int {
currentYear := time.Now().Year() currentYear := time.Now().Year()
return currentYear - yob return currentYear - yob
} }
//IsValidYob checks if the provided yob can be considered valid
func IsValidYOb(yob string) bool {
currentYear := time.Now().Year()
yearOfBirth, err := strconv.ParseInt(yob, 10, 64)
if err != nil {
return false
}
if yearOfBirth >= 1900 && int(yearOfBirth) <= currentYear {
return true
} else {
return false
}
}

View File

@ -1,17 +0,0 @@
package utils
func ConstructName(firstName, familyName, defaultValue string) string {
name := defaultValue
if familyName != defaultValue {
if firstName != defaultValue {
name = firstName + " " + familyName
} else {
name = familyName
}
} else {
if firstName != defaultValue {
name = firstName
}
}
return name
}

View File

@ -54,7 +54,7 @@
}, },
{ {
"input": "1235", "input": "1235",
"expectedContent": "Incorrect PIN\n1:Retry\n9:Quit" "expectedContent": "Incorrect pin\n1:Retry\n9:Quit"
}, },
{ {
"input": "1", "input": "1",
@ -62,7 +62,7 @@
}, },
{ {
"input": "1234", "input": "1234",
"expectedContent": "Select language:\n0:English\n1:Kiswahili" "expectedContent": "Select language:\n0:english\n1:kiswahili"
}, },
{ {
"input": "0", "input": "0",
@ -95,7 +95,7 @@
}, },
{ {
"input": "1235", "input": "1235",
"expectedContent": "Incorrect PIN\n1:Retry\n9:Quit" "expectedContent": "Incorrect pin\n1:Retry\n9:Quit"
}, },
{ {
"input": "1", "input": "1",
@ -141,7 +141,7 @@
}, },
{ {
"input": "1235", "input": "1235",
"expectedContent": "Incorrect PIN\n1:Retry\n9:Quit" "expectedContent": "Incorrect pin\n1:Retry\n9:Quit"
}, },
{ {
"input": "1", "input": "1",

View File

@ -7,11 +7,11 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "Welcome to Sarafu Network\nPlease select a language\n0:English\n1:Kiswahili" "expectedContent": "Welcome to Sarafu Network\nPlease select a language\n0:english\n1:kiswahili"
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "Do you agree to terms and conditions?\n0:Yes\n1:No" "expectedContent": "Do you agree to terms and conditions?\n0:yes\n1:no"
}, },
{ {
"input": "0", "input": "0",
@ -40,11 +40,11 @@
"steps": [ "steps": [
{ {
"input": "", "input": "",
"expectedContent": "Welcome to Sarafu Network\nPlease select a language\n0:English\n1:Kiswahili" "expectedContent": "Welcome to Sarafu Network\nPlease select a language\n0:english\n1:kiswahili"
}, },
{ {
"input": "0", "input": "0",
"expectedContent": "Do you agree to terms and conditions?\n0:Yes\n1:No" "expectedContent": "Do you agree to terms and conditions?\n0:yes\n1:no"
}, },
{ {
"input": "1", "input": "1",

View File

@ -1,10 +1,8 @@
package models package models
type VoucherDataResult struct { type VoucherDataResult struct {
TokenName string `json:"tokenName"` TokenName string `json:"tokenName"`
TokenSymbol string `json:"tokenSymbol"` TokenSymbol string `json:"tokenSymbol"`
TokenDecimals int `json:"tokenDecimals"` TokenDecimals int `json:"tokenDecimals"`
SinkAddress string `json:"sinkAddress"` SinkAddress string `json:"sinkAddress"`
TokenCommodity string `json:"tokenCommodity"`
TokenLocation string `json:"tokenLocation"`
} }

View File

@ -1 +0,0 @@
Tatizo la kimtambo limetokea,tafadhali jaribu tena baadaye.

View File

@ -1 +0,0 @@
English

View File

@ -1 +1 @@
Incorrect PIN Incorrect pin

View File

@ -1 +1 @@
PIN mpya na udhibitisho wa PIN mpya hazilingani.Tafadhali jaribu tena.Kwa usaidizi piga simu +254757628885. PIN mpya na udhibitisho wa pin mpya hazilingani.Tafadhali jaribu tena.Kwa usaidizi piga simu +254757628885.

View File

@ -1 +0,0 @@
Kiswahili

View File

@ -13,7 +13,7 @@ msgstr "Kwa usaidizi zaidi,piga: 0757628885"
msgid "Balance: %s\n" msgid "Balance: %s\n"
msgstr "Salio: %s\n" msgstr "Salio: %s\n"
msgid "Your invite request for %s to Sarafu Network failed. Please try again later." 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." 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." msgid "Your invitation to %s to join Sarafu Network has been sent."
@ -23,7 +23,4 @@ msgid "Your request failed. Please try again later."
msgstr "Ombi lako halikufaulu. Tafadhali jaribu tena baadaye." msgstr "Ombi lako halikufaulu. Tafadhali jaribu tena baadaye."
msgid "Community Balance: 0.00" msgid "Community Balance: 0.00"
msgstr "Salio la Kikundi: 0.00" msgid "Salio la Kikundi: 0.00"
msgid "Symbol: %s\nBalance: %s"
msgstr "Sarafu: %s\nSalio: %s"

View File

@ -1,10 +1,10 @@
LOAD set_default_voucher 8 LOAD set_default_voucher 8
RELOAD set_default_voucher RELOAD set_default_voucher
LOAD check_balance 64
RELOAD check_balance
LOAD check_vouchers 10 LOAD check_vouchers 10
RELOAD check_vouchers RELOAD check_vouchers
LOAD check_balance 128 CATCH api_failure flag_api_call_error 1
RELOAD check_balance
CATCH api_failure flag_api_call_error 1
MAP check_balance MAP check_balance
MOUT send 1 MOUT send 1
MOUT vouchers 2 MOUT vouchers 2

View File

@ -1 +1 @@
{{.check_balance}} Salio lako ni: 0.00 SRF

View File

@ -1 +0,0 @@
Next

View File

@ -1 +0,0 @@
Mbele

View File

@ -1 +1 @@
No no

View File

@ -1 +1 @@
La la

View File

@ -1 +0,0 @@
Prev

View File

@ -1 +0,0 @@
Nyuma

View File

@ -1,4 +1,3 @@
LOAD set_language 6 LOAD set_language 6
RELOAD set_language
CATCH terms flag_account_created 0 CATCH terms flag_account_created 0
MOVE language_changed MOVE language_changed

View File

@ -1,4 +1,3 @@
LOAD set_language 6 LOAD set_language 6
RELOAD set_language
CATCH terms flag_account_created 0 CATCH terms flag_account_created 0
MOVE language_changed MOVE language_changed

View File

@ -1 +1 @@
Yes yes

View File

@ -1 +1 @@
Ndio ndio