Compare commits
85 Commits
alias-addr
...
master
Author | SHA1 | Date | |
---|---|---|---|
43892f0d8c | |||
8e6b1e6f52 | |||
9cbbdff993 | |||
316358765d | |||
14737b5f12 | |||
caff27b43d | |||
589a94216b | |||
a659fb06fa | |||
f733fe5636 | |||
18423fcd9c | |||
72a3681767 | |||
160ccbb220 | |||
22f96363ba | |||
3e7f90733e | |||
321f038c7c | |||
7a9de79aae | |||
862830e9de | |||
bc0e536d3d | |||
82884a75a3 | |||
93c44861e0 | |||
4ecfc9de38 | |||
a84c3e0852 | |||
8efed966a0 | |||
e7c4b5bca7 | |||
ed632248c5 | |||
5c202741d6 | |||
c5ebdbf85b | |||
c4282a870e | |||
91cd6077ce | |||
c0ed6fa9c8 | |||
22c9c3e0f0 | |||
a709d24520 | |||
e56138e416 | |||
|
d516584d90 | ||
b420a9bba0 | |||
a20ab79355 | |||
e0ec15b272 | |||
9e998f9a29 | |||
1c7c0af712 | |||
d40a4a171f | |||
ba430a5849 | |||
0f21b01813 | |||
10586baf0d | |||
e979742424 | |||
ff3f049226 | |||
13b45c49da | |||
a72fb08dc8 | |||
944fa89b3c | |||
48e1b02e0e | |||
3e0bbe5ffe | |||
fd586d09c3 | |||
b615c27cf6 | |||
22e870b3e5 | |||
da462346f9 | |||
|
406bd84875 | ||
419cd185fc | |||
7976e237ca | |||
19ec8f0817 | |||
ef3a3d6717 | |||
c2019267d1 | |||
0091fbcabb | |||
aa7497573e | |||
54c1fe51ef | |||
7a86b2ad3b | |||
6b23c284e5 | |||
aab6660edd | |||
c46f41e25f | |||
00c0445eed | |||
c8c6b05b8a | |||
08ff1056d7 | |||
a17cf78d29 | |||
9847433e0a | |||
7ce50398d1 | |||
e30bc177e9 | |||
b9ff467c0c | |||
1174500e3f | |||
07df450b3c | |||
b8d938d3aa | |||
d1e9340ea9 | |||
8925e26c4c | |||
9b89462797 | |||
7880294c6f | |||
451b15fb6b | |||
d20700ca74 | |||
9cf1cbe425 |
@ -20,6 +20,7 @@ import (
|
|||||||
"git.defalsify.org/vise.git/logging"
|
"git.defalsify.org/vise.git/logging"
|
||||||
"git.defalsify.org/vise.git/resource"
|
"git.defalsify.org/vise.git/resource"
|
||||||
|
|
||||||
|
"git.grassecon.net/urdt/ussd/common"
|
||||||
"git.grassecon.net/urdt/ussd/config"
|
"git.grassecon.net/urdt/ussd/config"
|
||||||
"git.grassecon.net/urdt/ussd/initializers"
|
"git.grassecon.net/urdt/ussd/initializers"
|
||||||
"git.grassecon.net/urdt/ussd/internal/handlers"
|
"git.grassecon.net/urdt/ussd/internal/handlers"
|
||||||
@ -76,7 +77,13 @@ func (arp *atRequestParser) GetSessionId(rq any) (string, error) {
|
|||||||
return "", fmt.Errorf("no phone number found")
|
return "", fmt.Errorf("no phone number found")
|
||||||
}
|
}
|
||||||
|
|
||||||
return phoneNumber, nil
|
formattedNumber, err := common.FormatPhoneNumber(phoneNumber)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error: %v\n", err)
|
||||||
|
return "", fmt.Errorf("failed to format number")
|
||||||
|
}
|
||||||
|
|
||||||
|
return formattedNumber, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (arp *atRequestParser) GetInput(rq any) ([]byte, error) {
|
func (arp *atRequestParser) GetInput(rq any) ([]byte, error) {
|
||||||
|
21
common/db.go
21
common/db.go
@ -32,7 +32,19 @@ const (
|
|||||||
DATA_PUBLIC_KEY_REVERSE
|
DATA_PUBLIC_KEY_REVERSE
|
||||||
DATA_ACTIVE_DECIMAL
|
DATA_ACTIVE_DECIMAL
|
||||||
DATA_ACTIVE_ADDRESS
|
DATA_ACTIVE_ADDRESS
|
||||||
DATA_TRANSACTIONS
|
// Start the sub prefix data at 256 (0x0100)
|
||||||
|
DATA_VOUCHER_SYMBOLS DataTyp = 256 + iota
|
||||||
|
DATA_VOUCHER_BALANCES
|
||||||
|
DATA_VOUCHER_DECIMALS
|
||||||
|
DATA_VOUCHER_ADDRESSES
|
||||||
|
DATA_TX_SENDERS
|
||||||
|
DATA_TX_RECIPIENTS
|
||||||
|
DATA_TX_VALUES
|
||||||
|
DATA_TX_ADDRESSES
|
||||||
|
DATA_TX_HASHES
|
||||||
|
DATA_TX_DATES
|
||||||
|
DATA_TX_SYMBOLS
|
||||||
|
DATA_TX_DECIMALS
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -69,3 +81,10 @@ func StringToDataTyp(str string) (DataTyp, error) {
|
|||||||
return 0, errors.New("invalid DataTyp string")
|
return 0, errors.New("invalid DataTyp string")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToBytes converts DataTyp or int to a byte slice
|
||||||
|
func ToBytes[T ~uint16 | int](value T) []byte {
|
||||||
|
bytes := make([]byte, 2)
|
||||||
|
binary.BigEndian.PutUint16(bytes, uint16(value))
|
||||||
|
return bytes
|
||||||
|
}
|
||||||
|
73
common/recipient.go
Normal file
73
common/recipient.go
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Define the regex patterns as constants
|
||||||
|
const (
|
||||||
|
phoneRegex = `^(?:\+254|254|0)?((?:7[0-9]{8})|(?:1[01][0-9]{7}))$`
|
||||||
|
addressRegex = `^0x[a-fA-F0-9]{40}$`
|
||||||
|
aliasRegex = `^[a-zA-Z0-9]+$`
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsValidPhoneNumber checks if the given number is a valid phone number
|
||||||
|
func IsValidPhoneNumber(phonenumber string) bool {
|
||||||
|
match, _ := regexp.MatchString(phoneRegex, phonenumber)
|
||||||
|
return match
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValidAddress checks if the given address is a valid Ethereum address
|
||||||
|
func IsValidAddress(address string) bool {
|
||||||
|
match, _ := regexp.MatchString(addressRegex, address)
|
||||||
|
return match
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValidAlias checks if the alias is a valid alias format
|
||||||
|
func IsValidAlias(alias string) bool {
|
||||||
|
match, _ := regexp.MatchString(aliasRegex, alias)
|
||||||
|
return match
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckRecipient validates the recipient format based on the criteria
|
||||||
|
func CheckRecipient(recipient string) (string, error) {
|
||||||
|
if IsValidPhoneNumber(recipient) {
|
||||||
|
return "phone number", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if IsValidAddress(recipient) {
|
||||||
|
return "address", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if IsValidAlias(recipient) {
|
||||||
|
return "alias", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("invalid recipient: must be a phone number, address or alias")
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatPhoneNumber formats a Kenyan phone number to "+254xxxxxxxx".
|
||||||
|
func FormatPhoneNumber(phone string) (string, error) {
|
||||||
|
if !IsValidPhoneNumber(phone) {
|
||||||
|
return "", errors.New("invalid phone number")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove any leading "+" and spaces
|
||||||
|
phone = strings.TrimPrefix(phone, "+")
|
||||||
|
phone = strings.ReplaceAll(phone, " ", "")
|
||||||
|
|
||||||
|
// Replace leading "0" with "254" if present
|
||||||
|
if strings.HasPrefix(phone, "0") {
|
||||||
|
phone = "254" + phone[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add "+" if not already present
|
||||||
|
if !strings.HasPrefix(phone, "254") {
|
||||||
|
return "", errors.New("unexpected format")
|
||||||
|
}
|
||||||
|
|
||||||
|
return "+" + phone, nil
|
||||||
|
}
|
@ -57,25 +57,25 @@ func ProcessTransfers(transfers []dataserviceapi.Last10TxResponse) TransferMetad
|
|||||||
// GetTransferData retrieves and matches transfer data
|
// GetTransferData retrieves and matches transfer data
|
||||||
// returns a formatted string of the full transaction/statement
|
// returns a formatted string of the full transaction/statement
|
||||||
func GetTransferData(ctx context.Context, db storage.PrefixDb, publicKey string, index int) (string, error) {
|
func GetTransferData(ctx context.Context, db storage.PrefixDb, publicKey string, index int) (string, error) {
|
||||||
keys := []string{"txfrom", "txto", "txval", "txaddr", "txhash", "txdate", "txsym"}
|
keys := []DataTyp{DATA_TX_SENDERS, DATA_TX_RECIPIENTS, DATA_TX_VALUES, DATA_TX_ADDRESSES, DATA_TX_HASHES, DATA_TX_DATES, DATA_TX_SYMBOLS}
|
||||||
data := make(map[string]string)
|
data := make(map[DataTyp]string)
|
||||||
|
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
value, err := db.Get(ctx, []byte(key))
|
value, err := db.Get(ctx, ToBytes(key))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to get %s: %v", key, err)
|
return "", fmt.Errorf("failed to get %s: %v", ToBytes(key), err)
|
||||||
}
|
}
|
||||||
data[key] = string(value)
|
data[key] = string(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Split the data
|
// Split the data
|
||||||
senders := strings.Split(string(data["txfrom"]), "\n")
|
senders := strings.Split(string(data[DATA_TX_SENDERS]), "\n")
|
||||||
recipients := strings.Split(string(data["txto"]), "\n")
|
recipients := strings.Split(string(data[DATA_TX_RECIPIENTS]), "\n")
|
||||||
values := strings.Split(string(data["txval"]), "\n")
|
values := strings.Split(string(data[DATA_TX_VALUES]), "\n")
|
||||||
addresses := strings.Split(string(data["txaddr"]), "\n")
|
addresses := strings.Split(string(data[DATA_TX_ADDRESSES]), "\n")
|
||||||
hashes := strings.Split(string(data["txhash"]), "\n")
|
hashes := strings.Split(string(data[DATA_TX_HASHES]), "\n")
|
||||||
dates := strings.Split(string(data["txdate"]), "\n")
|
dates := strings.Split(string(data[DATA_TX_DATES]), "\n")
|
||||||
syms := strings.Split(string(data["txsym"]), "\n")
|
syms := strings.Split(string(data[DATA_TX_SYMBOLS]), "\n")
|
||||||
|
|
||||||
// Check if index is within range
|
// Check if index is within range
|
||||||
if index < 1 || index > len(senders) {
|
if index < 1 || index > len(senders) {
|
||||||
|
@ -64,22 +64,23 @@ func ScaleDownBalance(balance, decimals string) string {
|
|||||||
|
|
||||||
// GetVoucherData retrieves and matches voucher data
|
// GetVoucherData retrieves and matches voucher data
|
||||||
func GetVoucherData(ctx context.Context, db storage.PrefixDb, input string) (*dataserviceapi.TokenHoldings, error) {
|
func GetVoucherData(ctx context.Context, db storage.PrefixDb, input string) (*dataserviceapi.TokenHoldings, error) {
|
||||||
keys := []string{"sym", "bal", "deci", "addr"}
|
keys := []DataTyp{DATA_VOUCHER_SYMBOLS, DATA_VOUCHER_BALANCES, DATA_VOUCHER_DECIMALS, DATA_VOUCHER_ADDRESSES}
|
||||||
data := make(map[string]string)
|
data := make(map[DataTyp]string)
|
||||||
|
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
value, err := db.Get(ctx, []byte(key))
|
value, err := db.Get(ctx, ToBytes(key))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get %s: %v", key, err)
|
return nil, fmt.Errorf("failed to get %s: %v", ToBytes(key), err)
|
||||||
}
|
}
|
||||||
data[key] = string(value)
|
data[key] = string(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
symbol, balance, decimal, address := MatchVoucher(input,
|
symbol, balance, decimal, address := MatchVoucher(input,
|
||||||
data["sym"],
|
data[DATA_VOUCHER_SYMBOLS],
|
||||||
data["bal"],
|
data[DATA_VOUCHER_BALANCES],
|
||||||
data["deci"],
|
data[DATA_VOUCHER_DECIMALS],
|
||||||
data["addr"])
|
data[DATA_VOUCHER_ADDRESSES],
|
||||||
|
)
|
||||||
|
|
||||||
if symbol == "" {
|
if symbol == "" {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@ -151,7 +152,7 @@ func GetTemporaryVoucherData(ctx context.Context, store DataStore, sessionId str
|
|||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateVoucherData sets the active voucher data in the DataStore.
|
// UpdateVoucherData updates 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
|
||||||
|
@ -8,8 +8,9 @@ import (
|
|||||||
"github.com/alecthomas/assert/v2"
|
"github.com/alecthomas/assert/v2"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"git.grassecon.net/urdt/ussd/internal/storage"
|
visedb "git.defalsify.org/vise.git/db"
|
||||||
memdb "git.defalsify.org/vise.git/db/mem"
|
memdb "git.defalsify.org/vise.git/db/mem"
|
||||||
|
"git.grassecon.net/urdt/ussd/internal/storage"
|
||||||
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
|
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -83,19 +84,21 @@ func TestGetVoucherData(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
spdb := storage.NewSubPrefixDb(db, []byte("vouchers"))
|
|
||||||
|
prefix := ToBytes(visedb.DATATYPE_USERDATA)
|
||||||
|
spdb := storage.NewSubPrefixDb(db, prefix)
|
||||||
|
|
||||||
// Test voucher data
|
// Test voucher data
|
||||||
mockData := map[string][]byte{
|
mockData := map[DataTyp][]byte{
|
||||||
"sym": []byte("1:SRF\n2:MILO"),
|
DATA_VOUCHER_SYMBOLS: []byte("1:SRF\n2:MILO"),
|
||||||
"bal": []byte("1:100\n2:200"),
|
DATA_VOUCHER_BALANCES: []byte("1:100\n2:200"),
|
||||||
"deci": []byte("1:6\n2:4"),
|
DATA_VOUCHER_DECIMALS: []byte("1:6\n2:4"),
|
||||||
"addr": []byte("1:0xd4c288865Ce\n2:0x41c188d63Qa"),
|
DATA_VOUCHER_ADDRESSES: []byte("1:0xd4c288865Ce\n2:0x41c188d63Qa"),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put the data
|
// Put the data
|
||||||
for key, value := range mockData {
|
for key, value := range mockData {
|
||||||
err = spdb.Put(ctx, []byte(key), []byte(value))
|
err = spdb.Put(ctx, []byte(ToBytes(key)), []byte(value))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ const (
|
|||||||
voucherHoldingsPathPrefix = "/api/v1/holdings"
|
voucherHoldingsPathPrefix = "/api/v1/holdings"
|
||||||
voucherTransfersPathPrefix = "/api/v1/transfers/last10"
|
voucherTransfersPathPrefix = "/api/v1/transfers/last10"
|
||||||
voucherDataPathPrefix = "/api/v1/token"
|
voucherDataPathPrefix = "/api/v1/token"
|
||||||
|
AliasPrefix = "api/v1/alias"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -32,6 +33,7 @@ var (
|
|||||||
VoucherHoldingsURL string
|
VoucherHoldingsURL string
|
||||||
VoucherTransfersURL string
|
VoucherTransfersURL string
|
||||||
VoucherDataURL string
|
VoucherDataURL string
|
||||||
|
CheckAliasURL string
|
||||||
)
|
)
|
||||||
|
|
||||||
func setBase() error {
|
func setBase() error {
|
||||||
@ -66,6 +68,7 @@ func LoadConfig() error {
|
|||||||
VoucherHoldingsURL, _ = url.JoinPath(dataURLBase, voucherHoldingsPathPrefix)
|
VoucherHoldingsURL, _ = url.JoinPath(dataURLBase, voucherHoldingsPathPrefix)
|
||||||
VoucherTransfersURL, _ = url.JoinPath(dataURLBase, voucherTransfersPathPrefix)
|
VoucherTransfersURL, _ = url.JoinPath(dataURLBase, voucherTransfersPathPrefix)
|
||||||
VoucherDataURL, _ = url.JoinPath(dataURLBase, voucherDataPathPrefix)
|
VoucherDataURL, _ = url.JoinPath(dataURLBase, voucherDataPathPrefix)
|
||||||
|
CheckAliasURL, _ = url.JoinPath(dataURLBase, AliasPrefix)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,9 @@ 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 {
|
||||||
|
@ -121,6 +121,8 @@ func (ls *LocalHandlerService) GetHandler(accountService remote.AccountServiceIn
|
|||||||
ls.DbRs.AddLocalFunc("check_transactions", ussdHandlers.CheckTransactions)
|
ls.DbRs.AddLocalFunc("check_transactions", ussdHandlers.CheckTransactions)
|
||||||
ls.DbRs.AddLocalFunc("get_transactions", ussdHandlers.GetTransactionsList)
|
ls.DbRs.AddLocalFunc("get_transactions", ussdHandlers.GetTransactionsList)
|
||||||
ls.DbRs.AddLocalFunc("view_statement", ussdHandlers.ViewTransactionStatement)
|
ls.DbRs.AddLocalFunc("view_statement", ussdHandlers.ViewTransactionStatement)
|
||||||
|
ls.DbRs.AddLocalFunc("update_all_profile_items", ussdHandlers.UpdateAllProfileItems)
|
||||||
|
ls.DbRs.AddLocalFunc("set_back", ussdHandlers.SetBack)
|
||||||
|
|
||||||
return ussdHandlers, nil
|
return ussdHandlers, nil
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ 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"
|
||||||
@ -21,26 +20,31 @@ import (
|
|||||||
"git.defalsify.org/vise.git/state"
|
"git.defalsify.org/vise.git/state"
|
||||||
"git.grassecon.net/urdt/ussd/common"
|
"git.grassecon.net/urdt/ussd/common"
|
||||||
"git.grassecon.net/urdt/ussd/internal/utils"
|
"git.grassecon.net/urdt/ussd/internal/utils"
|
||||||
|
"git.grassecon.net/urdt/ussd/models"
|
||||||
"git.grassecon.net/urdt/ussd/remote"
|
"git.grassecon.net/urdt/ussd/remote"
|
||||||
"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
|
||||||
const (
|
const (
|
||||||
phoneRegex = `(\(\d{3}\)\s?|\d{3}[-.\s]?)?\d{3}[-.\s]?\d{4}`
|
|
||||||
pinPattern = `^\d{4}$`
|
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
|
||||||
|
}
|
||||||
|
|
||||||
// FlagManager handles centralized flag management
|
// FlagManager handles centralized flag management
|
||||||
type FlagManager struct {
|
type FlagManager struct {
|
||||||
parser *asm.FlagParser
|
parser *asm.FlagParser
|
||||||
@ -73,6 +77,7 @@ type Handlers struct {
|
|||||||
flagManager *asm.FlagParser
|
flagManager *asm.FlagParser
|
||||||
accountService remote.AccountServiceInterface
|
accountService remote.AccountServiceInterface
|
||||||
prefixDb storage.PrefixDb
|
prefixDb storage.PrefixDb
|
||||||
|
profile *models.Profile
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db, adminstore *utils.AdminStore, accountService remote.AccountServiceInterface) (*Handlers, error) {
|
func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db, adminstore *utils.AdminStore, accountService remote.AccountServiceInterface) (*Handlers, error) {
|
||||||
@ -82,8 +87,10 @@ func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db, adminstore *util
|
|||||||
userDb := &common.UserDataStore{
|
userDb := &common.UserDataStore{
|
||||||
Db: userdataStore,
|
Db: userdataStore,
|
||||||
}
|
}
|
||||||
// Instantiate the SubPrefixDb with "vouchers" prefix
|
|
||||||
prefixDb := storage.NewSubPrefixDb(userdataStore, []byte("vouchers"))
|
// Instantiate the SubPrefixDb with "DATATYPE_USERDATA" prefix
|
||||||
|
prefix := common.ToBytes(db.DATATYPE_USERDATA)
|
||||||
|
prefixDb := storage.NewSubPrefixDb(userdataStore, prefix)
|
||||||
|
|
||||||
h := &Handlers{
|
h := &Handlers{
|
||||||
userdataStore: userDb,
|
userdataStore: userDb,
|
||||||
@ -91,21 +98,11 @@ func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db, adminstore *util
|
|||||||
adminstore: adminstore,
|
adminstore: adminstore,
|
||||||
accountService: accountService,
|
accountService: accountService,
|
||||||
prefixDb: prefixDb,
|
prefixDb: prefixDb,
|
||||||
|
profile: &models.Profile{Max: 6},
|
||||||
}
|
}
|
||||||
return h, nil
|
return h, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
func (h *Handlers) WithPersister(pe *persist.Persister) *Handlers {
|
||||||
if h.pe != nil {
|
if h.pe != nil {
|
||||||
panic("persister already set")
|
panic("persister already set")
|
||||||
@ -120,6 +117,9 @@ 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()
|
||||||
@ -139,13 +139,16 @@ 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
|
||||||
@ -154,7 +157,8 @@ 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) {
|
||||||
return res, nil
|
//Fallback to english instead?
|
||||||
|
code = "eng"
|
||||||
}
|
}
|
||||||
res.FlagSet = append(res.FlagSet, state.FLAG_LANG)
|
res.FlagSet = append(res.FlagSet, state.FLAG_LANG)
|
||||||
res.Content = code
|
res.Content = code
|
||||||
@ -412,7 +416,10 @@ func (h *Handlers) SaveFirstname(ctx context.Context, sym string, input []byte)
|
|||||||
firstName := string(input)
|
firstName := string(input)
|
||||||
store := h.userdataStore
|
store := h.userdataStore
|
||||||
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
|
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
|
||||||
|
flag_firstname_set, _ := h.flagManager.GetFlag("flag_firstname_set")
|
||||||
|
|
||||||
allowUpdate := h.st.MatchFlag(flag_allow_update, true)
|
allowUpdate := h.st.MatchFlag(flag_allow_update, true)
|
||||||
|
firstNameSet := h.st.MatchFlag(flag_firstname_set, true)
|
||||||
if allowUpdate {
|
if allowUpdate {
|
||||||
temporaryFirstName, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE)
|
temporaryFirstName, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE)
|
||||||
err = store.WriteEntry(ctx, sessionId, common.DATA_FIRST_NAME, []byte(temporaryFirstName))
|
err = store.WriteEntry(ctx, sessionId, common.DATA_FIRST_NAME, []byte(temporaryFirstName))
|
||||||
@ -420,11 +427,16 @@ func (h *Handlers) SaveFirstname(ctx context.Context, sym string, input []byte)
|
|||||||
logg.ErrorCtxf(ctx, "failed to write firstName entry with", "key", common.DATA_FIRST_NAME, "value", temporaryFirstName, "error", err)
|
logg.ErrorCtxf(ctx, "failed to write firstName entry with", "key", common.DATA_FIRST_NAME, "value", temporaryFirstName, "error", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
res.FlagSet = append(res.FlagSet, flag_firstname_set)
|
||||||
} else {
|
} else {
|
||||||
err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(firstName))
|
if firstNameSet {
|
||||||
if err != nil {
|
err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(firstName))
|
||||||
logg.ErrorCtxf(ctx, "failed to write temporaryFirstName entry with", "key", common.DATA_TEMPORARY_VALUE, "value", firstName, "error", err)
|
if err != nil {
|
||||||
return res, err
|
logg.ErrorCtxf(ctx, "failed to write temporaryFirstName entry with", "key", common.DATA_TEMPORARY_VALUE, "value", firstName, "error", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
h.profile.InsertOrShift(0, firstName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -444,7 +456,9 @@ func (h *Handlers) SaveFamilyname(ctx context.Context, sym string, input []byte)
|
|||||||
familyName := string(input)
|
familyName := string(input)
|
||||||
|
|
||||||
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
|
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
|
||||||
|
flag_familyname_set, _ := h.flagManager.GetFlag("flag_familyname_set")
|
||||||
allowUpdate := h.st.MatchFlag(flag_allow_update, true)
|
allowUpdate := h.st.MatchFlag(flag_allow_update, true)
|
||||||
|
familyNameSet := h.st.MatchFlag(flag_familyname_set, true)
|
||||||
|
|
||||||
if allowUpdate {
|
if allowUpdate {
|
||||||
temporaryFamilyName, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE)
|
temporaryFamilyName, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE)
|
||||||
@ -453,11 +467,16 @@ func (h *Handlers) SaveFamilyname(ctx context.Context, sym string, input []byte)
|
|||||||
logg.ErrorCtxf(ctx, "failed to write familyName entry with", "key", common.DATA_FAMILY_NAME, "value", temporaryFamilyName, "error", err)
|
logg.ErrorCtxf(ctx, "failed to write familyName entry with", "key", common.DATA_FAMILY_NAME, "value", temporaryFamilyName, "error", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
res.FlagSet = append(res.FlagSet, flag_familyname_set)
|
||||||
} else {
|
} else {
|
||||||
err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(familyName))
|
if familyNameSet {
|
||||||
if err != nil {
|
err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(familyName))
|
||||||
logg.ErrorCtxf(ctx, "failed to write temporaryFamilyName entry with", "key", common.DATA_TEMPORARY_VALUE, "value", familyName, "error", err)
|
if err != nil {
|
||||||
return res, err
|
logg.ErrorCtxf(ctx, "failed to write temporaryFamilyName entry with", "key", common.DATA_TEMPORARY_VALUE, "value", familyName, "error", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
h.profile.InsertOrShift(1, familyName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -475,7 +494,10 @@ func (h *Handlers) SaveYob(ctx context.Context, sym string, input []byte) (resou
|
|||||||
yob := string(input)
|
yob := string(input)
|
||||||
store := h.userdataStore
|
store := h.userdataStore
|
||||||
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
|
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
|
||||||
|
flag_yob_set, _ := h.flagManager.GetFlag("flag_yob_set")
|
||||||
|
|
||||||
allowUpdate := h.st.MatchFlag(flag_allow_update, true)
|
allowUpdate := h.st.MatchFlag(flag_allow_update, true)
|
||||||
|
yobSet := h.st.MatchFlag(flag_yob_set, true)
|
||||||
|
|
||||||
if allowUpdate {
|
if allowUpdate {
|
||||||
temporaryYob, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE)
|
temporaryYob, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE)
|
||||||
@ -484,11 +506,16 @@ func (h *Handlers) SaveYob(ctx context.Context, sym string, input []byte) (resou
|
|||||||
logg.ErrorCtxf(ctx, "failed to write yob entry with", "key", common.DATA_TEMPORARY_VALUE, "value", temporaryYob, "error", err)
|
logg.ErrorCtxf(ctx, "failed to write yob entry with", "key", common.DATA_TEMPORARY_VALUE, "value", temporaryYob, "error", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
res.FlagSet = append(res.FlagSet, flag_yob_set)
|
||||||
} else {
|
} else {
|
||||||
err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(yob))
|
if yobSet {
|
||||||
if err != nil {
|
err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(yob))
|
||||||
logg.ErrorCtxf(ctx, "failed to write temporaryYob entry with", "key", common.DATA_TEMPORARY_VALUE, "value", yob, "error", err)
|
if err != nil {
|
||||||
return res, err
|
logg.ErrorCtxf(ctx, "failed to write temporaryYob entry with", "key", common.DATA_TEMPORARY_VALUE, "value", yob, "error", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
h.profile.InsertOrShift(3, yob)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -507,7 +534,9 @@ func (h *Handlers) SaveLocation(ctx context.Context, sym string, input []byte) (
|
|||||||
store := h.userdataStore
|
store := h.userdataStore
|
||||||
|
|
||||||
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
|
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
|
||||||
|
flag_location_set, _ := h.flagManager.GetFlag("flag_location_set")
|
||||||
allowUpdate := h.st.MatchFlag(flag_allow_update, true)
|
allowUpdate := h.st.MatchFlag(flag_allow_update, true)
|
||||||
|
locationSet := h.st.MatchFlag(flag_location_set, true)
|
||||||
|
|
||||||
if allowUpdate {
|
if allowUpdate {
|
||||||
temporaryLocation, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE)
|
temporaryLocation, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE)
|
||||||
@ -516,11 +545,17 @@ func (h *Handlers) SaveLocation(ctx context.Context, sym string, input []byte) (
|
|||||||
logg.ErrorCtxf(ctx, "failed to write location entry with", "key", common.DATA_LOCATION, "value", temporaryLocation, "error", err)
|
logg.ErrorCtxf(ctx, "failed to write location entry with", "key", common.DATA_LOCATION, "value", temporaryLocation, "error", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
res.FlagSet = append(res.FlagSet, flag_location_set)
|
||||||
} else {
|
} else {
|
||||||
err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(location))
|
if locationSet {
|
||||||
if err != nil {
|
err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(location))
|
||||||
logg.ErrorCtxf(ctx, "failed to write temporaryLocation entry with", "key", common.DATA_TEMPORARY_VALUE, "value", location, "error", err)
|
if err != nil {
|
||||||
return res, err
|
logg.ErrorCtxf(ctx, "failed to write temporaryLocation entry with", "key", common.DATA_TEMPORARY_VALUE, "value", location, "error", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
res.FlagSet = append(res.FlagSet, flag_location_set)
|
||||||
|
} else {
|
||||||
|
h.profile.InsertOrShift(4, location)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -539,7 +574,10 @@ func (h *Handlers) SaveGender(ctx context.Context, sym string, input []byte) (re
|
|||||||
gender := strings.Split(symbol, "_")[1]
|
gender := strings.Split(symbol, "_")[1]
|
||||||
store := h.userdataStore
|
store := h.userdataStore
|
||||||
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
|
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
|
||||||
|
flag_gender_set, _ := h.flagManager.GetFlag("flag_gender_set")
|
||||||
|
|
||||||
allowUpdate := h.st.MatchFlag(flag_allow_update, true)
|
allowUpdate := h.st.MatchFlag(flag_allow_update, true)
|
||||||
|
genderSet := h.st.MatchFlag(flag_gender_set, true)
|
||||||
|
|
||||||
if allowUpdate {
|
if allowUpdate {
|
||||||
temporaryGender, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE)
|
temporaryGender, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE)
|
||||||
@ -548,11 +586,16 @@ func (h *Handlers) SaveGender(ctx context.Context, sym string, input []byte) (re
|
|||||||
logg.ErrorCtxf(ctx, "failed to write gender entry with", "key", common.DATA_GENDER, "value", gender, "error", err)
|
logg.ErrorCtxf(ctx, "failed to write gender entry with", "key", common.DATA_GENDER, "value", gender, "error", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
res.FlagSet = append(res.FlagSet, flag_gender_set)
|
||||||
} else {
|
} else {
|
||||||
err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(gender))
|
if genderSet {
|
||||||
if err != nil {
|
err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(gender))
|
||||||
logg.ErrorCtxf(ctx, "failed to write temporaryGender entry with", "key", common.DATA_TEMPORARY_VALUE, "value", gender, "error", err)
|
if err != nil {
|
||||||
return res, err
|
logg.ErrorCtxf(ctx, "failed to write temporaryGender entry with", "key", common.DATA_TEMPORARY_VALUE, "value", gender, "error", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
h.profile.InsertOrShift(2, gender)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,7 +615,10 @@ func (h *Handlers) SaveOfferings(ctx context.Context, sym string, input []byte)
|
|||||||
store := h.userdataStore
|
store := h.userdataStore
|
||||||
|
|
||||||
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
|
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
|
||||||
|
flag_offerings_set, _ := h.flagManager.GetFlag("flag_offerings_set")
|
||||||
|
|
||||||
allowUpdate := h.st.MatchFlag(flag_allow_update, true)
|
allowUpdate := h.st.MatchFlag(flag_allow_update, true)
|
||||||
|
offeringsSet := h.st.MatchFlag(flag_offerings_set, true)
|
||||||
|
|
||||||
if allowUpdate {
|
if allowUpdate {
|
||||||
temporaryOfferings, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE)
|
temporaryOfferings, _ := store.ReadEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE)
|
||||||
@ -581,11 +627,16 @@ func (h *Handlers) SaveOfferings(ctx context.Context, sym string, input []byte)
|
|||||||
logg.ErrorCtxf(ctx, "failed to write offerings entry with", "key", common.DATA_TEMPORARY_VALUE, "value", offerings, "error", err)
|
logg.ErrorCtxf(ctx, "failed to write offerings entry with", "key", common.DATA_TEMPORARY_VALUE, "value", offerings, "error", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
res.FlagSet = append(res.FlagSet, flag_offerings_set)
|
||||||
} else {
|
} else {
|
||||||
err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(offerings))
|
if offeringsSet {
|
||||||
if err != nil {
|
err = store.WriteEntry(ctx, sessionId, common.DATA_TEMPORARY_VALUE, []byte(offerings))
|
||||||
logg.ErrorCtxf(ctx, "failed to write temporaryOfferings entry with", "key", common.DATA_TEMPORARY_VALUE, "value", offerings, "error", err)
|
if err != nil {
|
||||||
return res, err
|
logg.ErrorCtxf(ctx, "failed to write temporaryOfferings entry with", "key", common.DATA_TEMPORARY_VALUE, "value", offerings, "error", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
h.profile.InsertOrShift(5, offerings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -678,6 +729,18 @@ func (h *Handlers) ResetIncorrectPin(ctx context.Context, sym string, input []by
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setback sets the flag_back_set flag when the navigation is back
|
||||||
|
func (h *Handlers) SetBack(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||||
|
var res resource.Result
|
||||||
|
//TODO:
|
||||||
|
//Add check if the navigation is lateral nav instead of checking the input.
|
||||||
|
if string(input) == "0" {
|
||||||
|
flag_back_set, _ := h.flagManager.GetFlag("flag_back_set")
|
||||||
|
res.FlagSet = append(res.FlagSet, flag_back_set)
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
// CheckAccountStatus queries the API using the TrackingId and sets flags
|
// CheckAccountStatus queries the API using the TrackingId and sets flags
|
||||||
// based on the account status
|
// based on the account status
|
||||||
func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||||
@ -763,12 +826,11 @@ func (h *Handlers) VerifyYob(ctx context.Context, sym string, input []byte) (res
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(date) == 4 {
|
if utils.IsValidYOb(date) {
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -817,7 +879,17 @@ func (h *Handlers) CheckBalance(ctx context.Context, sym string, input []byte) (
|
|||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
res.Content = l.Get("Balance: %s\n", fmt.Sprintf("%s %s", activeBal, activeSym))
|
// Convert activeBal from []byte to float64
|
||||||
|
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
|
||||||
}
|
}
|
||||||
@ -877,7 +949,7 @@ func (h *Handlers) ValidateBlockedNumber(ctx context.Context, sym string, input
|
|||||||
}
|
}
|
||||||
blockedNumber := string(input)
|
blockedNumber := string(input)
|
||||||
_, err = store.ReadEntry(ctx, blockedNumber, common.DATA_PUBLIC_KEY)
|
_, err = store.ReadEntry(ctx, blockedNumber, common.DATA_PUBLIC_KEY)
|
||||||
if !isValidPhoneNumber(blockedNumber) {
|
if !common.IsValidPhoneNumber(blockedNumber) {
|
||||||
res.FlagSet = append(res.FlagSet, flag_unregistered_number)
|
res.FlagSet = append(res.FlagSet, flag_unregistered_number)
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
@ -898,10 +970,9 @@ func (h *Handlers) ValidateBlockedNumber(ctx context.Context, sym string, input
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateRecipient validates that the given input is a valid phone number.
|
// ValidateRecipient validates that the given input is valid.
|
||||||
func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) {
|
||||||
var res resource.Result
|
var res resource.Result
|
||||||
var err error
|
|
||||||
store := h.userdataStore
|
store := h.userdataStore
|
||||||
|
|
||||||
sessionId, ok := ctx.Value("SessionId").(string)
|
sessionId, ok := ctx.Value("SessionId").(string)
|
||||||
@ -909,13 +980,16 @@ func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []by
|
|||||||
return res, fmt.Errorf("missing session")
|
return res, fmt.Errorf("missing session")
|
||||||
}
|
}
|
||||||
|
|
||||||
recipient := string(input)
|
|
||||||
|
|
||||||
flag_invalid_recipient, _ := h.flagManager.GetFlag("flag_invalid_recipient")
|
flag_invalid_recipient, _ := h.flagManager.GetFlag("flag_invalid_recipient")
|
||||||
flag_invalid_recipient_with_invite, _ := h.flagManager.GetFlag("flag_invalid_recipient_with_invite")
|
flag_invalid_recipient_with_invite, _ := h.flagManager.GetFlag("flag_invalid_recipient_with_invite")
|
||||||
|
flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error")
|
||||||
|
|
||||||
|
recipient := string(input)
|
||||||
|
|
||||||
if recipient != "0" {
|
if recipient != "0" {
|
||||||
if !isValidPhoneNumber(recipient) {
|
recipientType, err := common.CheckRecipient(recipient)
|
||||||
|
if err != nil {
|
||||||
|
// Invalid recipient format (not a phone number, address, or valid alias format)
|
||||||
res.FlagSet = append(res.FlagSet, flag_invalid_recipient)
|
res.FlagSet = append(res.FlagSet, flag_invalid_recipient)
|
||||||
res.Content = recipient
|
res.Content = recipient
|
||||||
|
|
||||||
@ -929,25 +1003,61 @@ func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []by
|
|||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
publicKey, err := store.ReadEntry(ctx, recipient, common.DATA_PUBLIC_KEY)
|
switch recipientType {
|
||||||
if err != nil {
|
case "phone number":
|
||||||
if db.IsNotFound(err) {
|
// format the phone number
|
||||||
logg.InfoCtxf(ctx, "Unregistered number")
|
formattedNumber, err := common.FormatPhoneNumber(recipient)
|
||||||
|
if err != nil {
|
||||||
res.FlagSet = append(res.FlagSet, flag_invalid_recipient_with_invite)
|
logg.ErrorCtxf(ctx, "Failed to format the phone number: %s", recipient, "error", err)
|
||||||
res.Content = recipient
|
return res, err
|
||||||
|
|
||||||
return res, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", common.DATA_PUBLIC_KEY, "error", err)
|
// Check if the phone number is registered
|
||||||
return res, err
|
publicKey, err := store.ReadEntry(ctx, formattedNumber, common.DATA_PUBLIC_KEY)
|
||||||
}
|
if err != nil {
|
||||||
|
if db.IsNotFound(err) {
|
||||||
|
logg.InfoCtxf(ctx, "Unregistered phone number: %s", recipient)
|
||||||
|
res.FlagSet = append(res.FlagSet, flag_invalid_recipient_with_invite)
|
||||||
|
res.Content = recipient
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
err = store.WriteEntry(ctx, sessionId, common.DATA_RECIPIENT, publicKey)
|
logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", common.DATA_PUBLIC_KEY, "error", err)
|
||||||
if err != nil {
|
return res, err
|
||||||
logg.ErrorCtxf(ctx, "failed to write recipient entry with", "key", common.DATA_RECIPIENT, "value", string(publicKey), "error", err)
|
}
|
||||||
return res, nil
|
|
||||||
|
// Save the publicKey as the recipient
|
||||||
|
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, err
|
||||||
|
}
|
||||||
|
|
||||||
|
case "address":
|
||||||
|
// Save the valid Ethereum address as the recipient
|
||||||
|
err = store.WriteEntry(ctx, sessionId, common.DATA_RECIPIENT, []byte(recipient))
|
||||||
|
if err != nil {
|
||||||
|
logg.ErrorCtxf(ctx, "failed to write recipient entry with", "key", common.DATA_RECIPIENT, "value", recipient, "error", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
case "alias":
|
||||||
|
// Call the API to validate and retrieve the address for the alias
|
||||||
|
r, aliasErr := h.accountService.CheckAliasAddress(ctx, recipient)
|
||||||
|
if aliasErr != nil {
|
||||||
|
res.FlagSet = append(res.FlagSet, flag_api_error)
|
||||||
|
res.Content = recipient
|
||||||
|
|
||||||
|
logg.ErrorCtxf(ctx, "failed on CheckAliasAddress", "error", aliasErr)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alias validation succeeded, save the Ethereum address
|
||||||
|
err = store.WriteEntry(ctx, sessionId, common.DATA_RECIPIENT, []byte(r.Address))
|
||||||
|
if err != nil {
|
||||||
|
logg.ErrorCtxf(ctx, "failed to write recipient entry with", "key", common.DATA_RECIPIENT, "value", r.Address, "error", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1230,6 +1340,17 @@ func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input
|
|||||||
var res resource.Result
|
var res resource.Result
|
||||||
var profileInfo []byte
|
var profileInfo []byte
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
flag_firstname_set, _ := h.flagManager.GetFlag("flag_firstname_set")
|
||||||
|
flag_familyname_set, _ := h.flagManager.GetFlag("flag_familyname_set")
|
||||||
|
flag_yob_set, _ := h.flagManager.GetFlag("flag_yob_set")
|
||||||
|
flag_gender_set, _ := h.flagManager.GetFlag("flag_gender_set")
|
||||||
|
flag_location_set, _ := h.flagManager.GetFlag("flag_location_set")
|
||||||
|
flag_offerings_set, _ := h.flagManager.GetFlag("flag_offerings_set")
|
||||||
|
flag_back_set, _ := h.flagManager.GetFlag("flag_back_set")
|
||||||
|
|
||||||
|
res.FlagReset = append(res.FlagReset, flag_back_set)
|
||||||
|
|
||||||
sessionId, ok := ctx.Value("SessionId").(string)
|
sessionId, ok := ctx.Value("SessionId").(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return res, fmt.Errorf("missing session")
|
return res, fmt.Errorf("missing session")
|
||||||
@ -1256,6 +1377,7 @@ func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input
|
|||||||
logg.ErrorCtxf(ctx, "Failed to read first name entry with", "key", "error", common.DATA_FIRST_NAME, err)
|
logg.ErrorCtxf(ctx, "Failed to read first name entry with", "key", "error", common.DATA_FIRST_NAME, err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
res.FlagSet = append(res.FlagSet, flag_firstname_set)
|
||||||
res.Content = string(profileInfo)
|
res.Content = string(profileInfo)
|
||||||
case common.DATA_FAMILY_NAME:
|
case common.DATA_FAMILY_NAME:
|
||||||
profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_FAMILY_NAME)
|
profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_FAMILY_NAME)
|
||||||
@ -1267,6 +1389,7 @@ func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input
|
|||||||
logg.ErrorCtxf(ctx, "Failed to read family name entry with", "key", "error", common.DATA_FAMILY_NAME, err)
|
logg.ErrorCtxf(ctx, "Failed to read family name entry with", "key", "error", common.DATA_FAMILY_NAME, err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
res.FlagSet = append(res.FlagSet, flag_familyname_set)
|
||||||
res.Content = string(profileInfo)
|
res.Content = string(profileInfo)
|
||||||
|
|
||||||
case common.DATA_GENDER:
|
case common.DATA_GENDER:
|
||||||
@ -1279,6 +1402,7 @@ func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input
|
|||||||
logg.ErrorCtxf(ctx, "Failed to read gender entry with", "key", "error", common.DATA_GENDER, err)
|
logg.ErrorCtxf(ctx, "Failed to read gender entry with", "key", "error", common.DATA_GENDER, err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
res.FlagSet = append(res.FlagSet, flag_gender_set)
|
||||||
res.Content = string(profileInfo)
|
res.Content = string(profileInfo)
|
||||||
case common.DATA_YOB:
|
case common.DATA_YOB:
|
||||||
profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_YOB)
|
profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_YOB)
|
||||||
@ -1290,8 +1414,8 @@ func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input
|
|||||||
logg.ErrorCtxf(ctx, "Failed to read year of birth(yob) entry with", "key", "error", common.DATA_YOB, err)
|
logg.ErrorCtxf(ctx, "Failed to read year of birth(yob) entry with", "key", "error", common.DATA_YOB, err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
res.FlagSet = append(res.FlagSet, flag_yob_set)
|
||||||
res.Content = string(profileInfo)
|
res.Content = string(profileInfo)
|
||||||
|
|
||||||
case common.DATA_LOCATION:
|
case common.DATA_LOCATION:
|
||||||
profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_LOCATION)
|
profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_LOCATION)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1302,6 +1426,7 @@ func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input
|
|||||||
logg.ErrorCtxf(ctx, "Failed to read location entry with", "key", "error", common.DATA_LOCATION, err)
|
logg.ErrorCtxf(ctx, "Failed to read location entry with", "key", "error", common.DATA_LOCATION, err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
res.FlagSet = append(res.FlagSet, flag_location_set)
|
||||||
res.Content = string(profileInfo)
|
res.Content = string(profileInfo)
|
||||||
case common.DATA_OFFERINGS:
|
case common.DATA_OFFERINGS:
|
||||||
profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_OFFERINGS)
|
profileInfo, err = store.ReadEntry(ctx, sessionId, common.DATA_OFFERINGS)
|
||||||
@ -1313,6 +1438,7 @@ func (h *Handlers) GetCurrentProfileInfo(ctx context.Context, sym string, input
|
|||||||
logg.ErrorCtxf(ctx, "Failed to read offerings entry with", "key", "error", common.DATA_OFFERINGS, err)
|
logg.ErrorCtxf(ctx, "Failed to read offerings entry with", "key", "error", common.DATA_OFFERINGS, err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
res.FlagSet = append(res.FlagSet, flag_offerings_set)
|
||||||
res.Content = string(profileInfo)
|
res.Content = string(profileInfo)
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
@ -1356,14 +1482,7 @@ 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 := defaultValue
|
name := utils.ConstructName(firstName, familyName, 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
|
||||||
@ -1502,18 +1621,50 @@ 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
|
||||||
dataMap := map[string]string{
|
dataMap := map[common.DataTyp]string{
|
||||||
"sym": data.Symbols,
|
common.DATA_VOUCHER_SYMBOLS: data.Symbols,
|
||||||
"bal": data.Balances,
|
common.DATA_VOUCHER_BALANCES: data.Balances,
|
||||||
"deci": data.Decimals,
|
common.DATA_VOUCHER_DECIMALS: data.Decimals,
|
||||||
"addr": data.Addresses,
|
common.DATA_VOUCHER_ADDRESSES: data.Addresses,
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, value := range dataMap {
|
for key, value := range dataMap {
|
||||||
if err := h.prefixDb.Put(ctx, []byte(key), []byte(value)); err != nil {
|
if err := h.prefixDb.Put(ctx, []byte(common.ToBytes(key)), []byte(value)); err != nil {
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1526,7 +1677,7 @@ func (h *Handlers) GetVoucherList(ctx context.Context, sym string, input []byte)
|
|||||||
var res resource.Result
|
var res resource.Result
|
||||||
|
|
||||||
// Read vouchers from the store
|
// Read vouchers from the store
|
||||||
voucherData, err := h.prefixDb.Get(ctx, []byte("sym"))
|
voucherData, err := h.prefixDb.Get(ctx, common.ToBytes(common.DATA_VOUCHER_SYMBOLS))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logg.ErrorCtxf(ctx, "Failed to read the voucherData from prefixDb", "error", err)
|
logg.ErrorCtxf(ctx, "Failed to read the voucherData from prefixDb", "error", err)
|
||||||
return res, err
|
return res, err
|
||||||
@ -1546,6 +1697,10 @@ 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)
|
||||||
@ -1570,7 +1725,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 = fmt.Sprintf("%s\n%s", metadata.TokenSymbol, metadata.Balance)
|
res.Content = l.Get("Symbol: %s\nBalance: %s", metadata.TokenSymbol, metadata.Balance)
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
@ -1626,10 +1781,9 @@ func (h *Handlers) GetVoucherDetails(ctx context.Context, sym string, input []by
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenSymbol := voucherData.TokenSymbol
|
res.Content = fmt.Sprintf(
|
||||||
tokenName := voucherData.TokenName
|
"Name: %s\nSymbol: %s\nCommodity: %s\nLocation: %s", voucherData.TokenName, voucherData.TokenSymbol, voucherData.TokenCommodity, voucherData.TokenLocation,
|
||||||
|
)
|
||||||
res.Content = fmt.Sprintf("%s %s", tokenSymbol, tokenName)
|
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
@ -1669,19 +1823,19 @@ func (h *Handlers) CheckTransactions(ctx context.Context, sym string, input []by
|
|||||||
data := common.ProcessTransfers(transactionsResp)
|
data := common.ProcessTransfers(transactionsResp)
|
||||||
|
|
||||||
// Store all transaction data
|
// Store all transaction data
|
||||||
dataMap := map[string]string{
|
dataMap := map[common.DataTyp]string{
|
||||||
"txfrom": data.Senders,
|
common.DATA_TX_SENDERS: data.Senders,
|
||||||
"txto": data.Recipients,
|
common.DATA_TX_RECIPIENTS: data.Recipients,
|
||||||
"txval": data.TransferValues,
|
common.DATA_TX_VALUES: data.TransferValues,
|
||||||
"txaddr": data.Addresses,
|
common.DATA_TX_ADDRESSES: data.Addresses,
|
||||||
"txhash": data.TxHashes,
|
common.DATA_TX_HASHES: data.TxHashes,
|
||||||
"txdate": data.Dates,
|
common.DATA_TX_DATES: data.Dates,
|
||||||
"txsym": data.Symbols,
|
common.DATA_TX_SYMBOLS: data.Symbols,
|
||||||
"txdeci": data.Decimals,
|
common.DATA_TX_DECIMALS: data.Decimals,
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, value := range dataMap {
|
for key, value := range dataMap {
|
||||||
if err := h.prefixDb.Put(ctx, []byte(key), []byte(value)); err != nil {
|
if err := h.prefixDb.Put(ctx, []byte(common.ToBytes(key)), []byte(value)); err != nil {
|
||||||
logg.ErrorCtxf(ctx, "failed to write to prefixDb", "error", err)
|
logg.ErrorCtxf(ctx, "failed to write to prefixDb", "error", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
@ -1707,22 +1861,22 @@ func (h *Handlers) GetTransactionsList(ctx context.Context, sym string, input []
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read transactions from the store and format them
|
// Read transactions from the store and format them
|
||||||
TransactionSenders, err := h.prefixDb.Get(ctx, []byte("txfrom"))
|
TransactionSenders, err := h.prefixDb.Get(ctx, common.ToBytes(common.DATA_TX_SENDERS))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logg.ErrorCtxf(ctx, "Failed to read the TransactionSenders from prefixDb", "error", err)
|
logg.ErrorCtxf(ctx, "Failed to read the TransactionSenders from prefixDb", "error", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
TransactionSyms, err := h.prefixDb.Get(ctx, []byte("txsym"))
|
TransactionSyms, err := h.prefixDb.Get(ctx, common.ToBytes(common.DATA_TX_SYMBOLS))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logg.ErrorCtxf(ctx, "Failed to read the TransactionSyms from prefixDb", "error", err)
|
logg.ErrorCtxf(ctx, "Failed to read the TransactionSyms from prefixDb", "error", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
TransactionValues, err := h.prefixDb.Get(ctx, []byte("txval"))
|
TransactionValues, err := h.prefixDb.Get(ctx, common.ToBytes(common.DATA_TX_VALUES))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logg.ErrorCtxf(ctx, "Failed to read the TransactionValues from prefixDb", "error", err)
|
logg.ErrorCtxf(ctx, "Failed to read the TransactionValues from prefixDb", "error", err)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
TransactionDates, err := h.prefixDb.Get(ctx, []byte("txdate"))
|
TransactionDates, err := h.prefixDb.Get(ctx, common.ToBytes(common.DATA_TX_DATES))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logg.ErrorCtxf(ctx, "Failed to read the TransactionDates from prefixDb", "error", err)
|
logg.ErrorCtxf(ctx, "Failed to read the TransactionDates from prefixDb", "error", err)
|
||||||
return res, err
|
return res, err
|
||||||
@ -1802,3 +1956,53 @@ func (h *Handlers) ViewTransactionStatement(ctx context.Context, sym string, inp
|
|||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Handlers) insertProfileItems(ctx context.Context, sessionId string, res *resource.Result) error {
|
||||||
|
var err error
|
||||||
|
store := h.userdataStore
|
||||||
|
profileFlagNames := []string{
|
||||||
|
"flag_firstname_set",
|
||||||
|
"flag_familyname_set",
|
||||||
|
"flag_yob_set",
|
||||||
|
"flag_gender_set",
|
||||||
|
"flag_location_set",
|
||||||
|
"flag_offerings_set",
|
||||||
|
}
|
||||||
|
profileDataKeys := []common.DataTyp{
|
||||||
|
common.DATA_FIRST_NAME,
|
||||||
|
common.DATA_FAMILY_NAME,
|
||||||
|
common.DATA_GENDER,
|
||||||
|
common.DATA_YOB,
|
||||||
|
common.DATA_LOCATION,
|
||||||
|
common.DATA_OFFERINGS,
|
||||||
|
}
|
||||||
|
for index, profileItem := range h.profile.ProfileItems {
|
||||||
|
// Ensure the profileItem is not "0"(is set)
|
||||||
|
if profileItem != "0" {
|
||||||
|
err = store.WriteEntry(ctx, sessionId, profileDataKeys[index], []byte(profileItem))
|
||||||
|
if err != nil {
|
||||||
|
logg.ErrorCtxf(ctx, "failed to write profile entry with", "key", profileDataKeys[index], "value", profileItem, "error", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the flag for the current index
|
||||||
|
flag, _ := h.flagManager.GetFlag(profileFlagNames[index])
|
||||||
|
res.FlagSet = append(res.FlagSet, flag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateAllProfileItems is used to persist all the new profile information and setup the required profile flags
|
||||||
|
func (h *Handlers) UpdateAllProfileItems(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")
|
||||||
|
}
|
||||||
|
err := h.insertProfileItems(ctx, sessionId, &res)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
testdataloader "github.com/peteole/testdata-loader"
|
testdataloader "github.com/peteole/testdata-loader"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
visedb "git.defalsify.org/vise.git/db"
|
||||||
memdb "git.defalsify.org/vise.git/db/mem"
|
memdb "git.defalsify.org/vise.git/db/mem"
|
||||||
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
|
dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api"
|
||||||
)
|
)
|
||||||
@ -56,7 +57,8 @@ func InitializeTestSubPrefixDb(t *testing.T, ctx context.Context) *storage.SubPr
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
spdb := storage.NewSubPrefixDb(db, []byte("vouchers"))
|
prefix := common.ToBytes(visedb.DATATYPE_USERDATA)
|
||||||
|
spdb := storage.NewSubPrefixDb(db, prefix)
|
||||||
|
|
||||||
return spdb
|
return spdb
|
||||||
}
|
}
|
||||||
@ -179,11 +181,14 @@ func TestSaveFirstname(t *testing.T) {
|
|||||||
fm, _ := NewFlagManager(flagsPath)
|
fm, _ := NewFlagManager(flagsPath)
|
||||||
|
|
||||||
flag_allow_update, _ := fm.GetFlag("flag_allow_update")
|
flag_allow_update, _ := fm.GetFlag("flag_allow_update")
|
||||||
|
flag_firstname_set, _ := fm.GetFlag("flag_firstname_set")
|
||||||
|
|
||||||
// Set the flag in the State
|
// Set the flag in the State
|
||||||
mockState := state.NewState(16)
|
mockState := state.NewState(128)
|
||||||
mockState.SetFlag(flag_allow_update)
|
mockState.SetFlag(flag_allow_update)
|
||||||
|
|
||||||
|
expectedResult := resource.Result{}
|
||||||
|
|
||||||
// Define test data
|
// Define test data
|
||||||
firstName := "John"
|
firstName := "John"
|
||||||
|
|
||||||
@ -191,6 +196,8 @@ func TestSaveFirstname(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expectedResult.FlagSet = []uint32{flag_firstname_set}
|
||||||
|
|
||||||
// Create the Handlers instance with the mock store
|
// Create the Handlers instance with the mock store
|
||||||
h := &Handlers{
|
h := &Handlers{
|
||||||
userdataStore: store,
|
userdataStore: store,
|
||||||
@ -203,7 +210,7 @@ func TestSaveFirstname(t *testing.T) {
|
|||||||
|
|
||||||
// Assert results
|
// Assert results
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, resource.Result{}, res)
|
assert.Equal(t, expectedResult, res)
|
||||||
|
|
||||||
// Verify that the DATA_FIRST_NAME entry has been updated with the temporary value
|
// Verify that the DATA_FIRST_NAME entry has been updated with the temporary value
|
||||||
storedFirstName, _ := store.ReadEntry(ctx, sessionId, common.DATA_FIRST_NAME)
|
storedFirstName, _ := store.ReadEntry(ctx, sessionId, common.DATA_FIRST_NAME)
|
||||||
@ -218,11 +225,16 @@ func TestSaveFamilyname(t *testing.T) {
|
|||||||
fm, _ := NewFlagManager(flagsPath)
|
fm, _ := NewFlagManager(flagsPath)
|
||||||
|
|
||||||
flag_allow_update, _ := fm.GetFlag("flag_allow_update")
|
flag_allow_update, _ := fm.GetFlag("flag_allow_update")
|
||||||
|
flag_firstname_set, _ := fm.GetFlag("flag_familyname_set")
|
||||||
|
|
||||||
// Set the flag in the State
|
// Set the flag in the State
|
||||||
mockState := state.NewState(16)
|
mockState := state.NewState(128)
|
||||||
mockState.SetFlag(flag_allow_update)
|
mockState.SetFlag(flag_allow_update)
|
||||||
|
|
||||||
|
expectedResult := resource.Result{}
|
||||||
|
|
||||||
|
expectedResult.FlagSet = []uint32{flag_firstname_set}
|
||||||
|
|
||||||
// Define test data
|
// Define test data
|
||||||
familyName := "Doeee"
|
familyName := "Doeee"
|
||||||
|
|
||||||
@ -242,7 +254,7 @@ func TestSaveFamilyname(t *testing.T) {
|
|||||||
|
|
||||||
// Assert results
|
// Assert results
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, resource.Result{}, res)
|
assert.Equal(t, expectedResult, res)
|
||||||
|
|
||||||
// Verify that the DATA_FAMILY_NAME entry has been updated with the temporary value
|
// Verify that the DATA_FAMILY_NAME entry has been updated with the temporary value
|
||||||
storedFamilyName, _ := store.ReadEntry(ctx, sessionId, common.DATA_FAMILY_NAME)
|
storedFamilyName, _ := store.ReadEntry(ctx, sessionId, common.DATA_FAMILY_NAME)
|
||||||
@ -257,11 +269,14 @@ func TestSaveYoB(t *testing.T) {
|
|||||||
fm, _ := NewFlagManager(flagsPath)
|
fm, _ := NewFlagManager(flagsPath)
|
||||||
|
|
||||||
flag_allow_update, _ := fm.GetFlag("flag_allow_update")
|
flag_allow_update, _ := fm.GetFlag("flag_allow_update")
|
||||||
|
flag_yob_set, _ := fm.GetFlag("flag_yob_set")
|
||||||
|
|
||||||
// Set the flag in the State
|
// Set the flag in the State
|
||||||
mockState := state.NewState(16)
|
mockState := state.NewState(108)
|
||||||
mockState.SetFlag(flag_allow_update)
|
mockState.SetFlag(flag_allow_update)
|
||||||
|
|
||||||
|
expectedResult := resource.Result{}
|
||||||
|
|
||||||
// Define test data
|
// Define test data
|
||||||
yob := "1980"
|
yob := "1980"
|
||||||
|
|
||||||
@ -269,6 +284,8 @@ func TestSaveYoB(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expectedResult.FlagSet = []uint32{flag_yob_set}
|
||||||
|
|
||||||
// Create the Handlers instance with the mock store
|
// Create the Handlers instance with the mock store
|
||||||
h := &Handlers{
|
h := &Handlers{
|
||||||
userdataStore: store,
|
userdataStore: store,
|
||||||
@ -281,7 +298,7 @@ func TestSaveYoB(t *testing.T) {
|
|||||||
|
|
||||||
// Assert results
|
// Assert results
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, resource.Result{}, res)
|
assert.Equal(t, expectedResult, res)
|
||||||
|
|
||||||
// Verify that the DATA_YOB entry has been updated with the temporary value
|
// Verify that the DATA_YOB entry has been updated with the temporary value
|
||||||
storedYob, _ := store.ReadEntry(ctx, sessionId, common.DATA_YOB)
|
storedYob, _ := store.ReadEntry(ctx, sessionId, common.DATA_YOB)
|
||||||
@ -296,11 +313,14 @@ func TestSaveLocation(t *testing.T) {
|
|||||||
fm, _ := NewFlagManager(flagsPath)
|
fm, _ := NewFlagManager(flagsPath)
|
||||||
|
|
||||||
flag_allow_update, _ := fm.GetFlag("flag_allow_update")
|
flag_allow_update, _ := fm.GetFlag("flag_allow_update")
|
||||||
|
flag_location_set, _ := fm.GetFlag("flag_location_set")
|
||||||
|
|
||||||
// Set the flag in the State
|
// Set the flag in the State
|
||||||
mockState := state.NewState(16)
|
mockState := state.NewState(108)
|
||||||
mockState.SetFlag(flag_allow_update)
|
mockState.SetFlag(flag_allow_update)
|
||||||
|
|
||||||
|
expectedResult := resource.Result{}
|
||||||
|
|
||||||
// Define test data
|
// Define test data
|
||||||
location := "Kilifi"
|
location := "Kilifi"
|
||||||
|
|
||||||
@ -308,6 +328,8 @@ func TestSaveLocation(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expectedResult.FlagSet = []uint32{flag_location_set}
|
||||||
|
|
||||||
// Create the Handlers instance with the mock store
|
// Create the Handlers instance with the mock store
|
||||||
h := &Handlers{
|
h := &Handlers{
|
||||||
userdataStore: store,
|
userdataStore: store,
|
||||||
@ -320,7 +342,7 @@ func TestSaveLocation(t *testing.T) {
|
|||||||
|
|
||||||
// Assert results
|
// Assert results
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, resource.Result{}, res)
|
assert.Equal(t, expectedResult, res)
|
||||||
|
|
||||||
// Verify that the DATA_LOCATION entry has been updated with the temporary value
|
// Verify that the DATA_LOCATION entry has been updated with the temporary value
|
||||||
storedLocation, _ := store.ReadEntry(ctx, sessionId, common.DATA_LOCATION)
|
storedLocation, _ := store.ReadEntry(ctx, sessionId, common.DATA_LOCATION)
|
||||||
@ -335,11 +357,14 @@ func TestSaveOfferings(t *testing.T) {
|
|||||||
fm, _ := NewFlagManager(flagsPath)
|
fm, _ := NewFlagManager(flagsPath)
|
||||||
|
|
||||||
flag_allow_update, _ := fm.GetFlag("flag_allow_update")
|
flag_allow_update, _ := fm.GetFlag("flag_allow_update")
|
||||||
|
flag_offerings_set, _ := fm.GetFlag("flag_offerings_set")
|
||||||
|
|
||||||
// Set the flag in the State
|
// Set the flag in the State
|
||||||
mockState := state.NewState(16)
|
mockState := state.NewState(108)
|
||||||
mockState.SetFlag(flag_allow_update)
|
mockState.SetFlag(flag_allow_update)
|
||||||
|
|
||||||
|
expectedResult := resource.Result{}
|
||||||
|
|
||||||
// Define test data
|
// Define test data
|
||||||
offerings := "Bananas"
|
offerings := "Bananas"
|
||||||
|
|
||||||
@ -347,6 +372,8 @@ func TestSaveOfferings(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expectedResult.FlagSet = []uint32{flag_offerings_set}
|
||||||
|
|
||||||
// Create the Handlers instance with the mock store
|
// Create the Handlers instance with the mock store
|
||||||
h := &Handlers{
|
h := &Handlers{
|
||||||
userdataStore: store,
|
userdataStore: store,
|
||||||
@ -359,7 +386,7 @@ func TestSaveOfferings(t *testing.T) {
|
|||||||
|
|
||||||
// Assert results
|
// Assert results
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, resource.Result{}, res)
|
assert.Equal(t, expectedResult, res)
|
||||||
|
|
||||||
// Verify that the DATA_OFFERINGS entry has been updated with the temporary value
|
// Verify that the DATA_OFFERINGS entry has been updated with the temporary value
|
||||||
storedOfferings, _ := store.ReadEntry(ctx, sessionId, common.DATA_OFFERINGS)
|
storedOfferings, _ := store.ReadEntry(ctx, sessionId, common.DATA_OFFERINGS)
|
||||||
@ -374,9 +401,10 @@ func TestSaveGender(t *testing.T) {
|
|||||||
fm, _ := NewFlagManager(flagsPath)
|
fm, _ := NewFlagManager(flagsPath)
|
||||||
|
|
||||||
flag_allow_update, _ := fm.GetFlag("flag_allow_update")
|
flag_allow_update, _ := fm.GetFlag("flag_allow_update")
|
||||||
|
flag_gender_set, _ := fm.GetFlag("flag_gender_set")
|
||||||
|
|
||||||
// Set the flag in the State
|
// Set the flag in the State
|
||||||
mockState := state.NewState(16)
|
mockState := state.NewState(108)
|
||||||
mockState.SetFlag(flag_allow_update)
|
mockState.SetFlag(flag_allow_update)
|
||||||
|
|
||||||
// Define test cases
|
// Define test cases
|
||||||
@ -420,12 +448,16 @@ func TestSaveGender(t *testing.T) {
|
|||||||
flagManager: fm.parser,
|
flagManager: fm.parser,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expectedResult := resource.Result{}
|
||||||
|
|
||||||
// Call the method
|
// Call the method
|
||||||
res, err := h.SaveGender(ctx, "save_gender", tt.input)
|
res, err := h.SaveGender(ctx, "save_gender", tt.input)
|
||||||
|
|
||||||
|
expectedResult.FlagSet = []uint32{flag_gender_set}
|
||||||
|
|
||||||
// Assert results
|
// Assert results
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, resource.Result{}, res)
|
assert.Equal(t, expectedResult, res)
|
||||||
|
|
||||||
// Verify that the DATA_GENDER entry has been updated with the temporary value
|
// Verify that the DATA_GENDER entry has been updated with the temporary value
|
||||||
storedGender, _ := store.ReadEntry(ctx, sessionId, common.DATA_GENDER)
|
storedGender, _ := store.ReadEntry(ctx, sessionId, common.DATA_GENDER)
|
||||||
@ -1498,10 +1530,10 @@ func TestValidateRecipient(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Test with invalid recepient",
|
name: "Test with invalid recepient",
|
||||||
input: []byte("9234adf5"),
|
input: []byte("7?1234"),
|
||||||
expectedResult: resource.Result{
|
expectedResult: resource.Result{
|
||||||
FlagSet: []uint32{flag_invalid_recipient},
|
FlagSet: []uint32{flag_invalid_recipient},
|
||||||
Content: "9234adf5",
|
Content: "7?1234",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -1517,22 +1549,40 @@ 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, "0711223344", common.DATA_PUBLIC_KEY, []byte(publicKey))
|
err = store.WriteEntry(ctx, "+254711223344", 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)
|
||||||
|
|
||||||
@ -1564,7 +1614,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.5 ETH\n"},
|
expectedResult: resource.Result{Content: "Balance: 1.50 ETH\n"},
|
||||||
expectError: false,
|
expectError: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -1919,7 +1969,7 @@ func TestCheckVouchers(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Read voucher sym data from the store
|
// Read voucher sym data from the store
|
||||||
voucherData, err := spdb.Get(ctx, []byte("sym"))
|
voucherData, err := spdb.Get(ctx, common.ToBytes(common.DATA_VOUCHER_SYMBOLS))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -1943,7 +1993,7 @@ func TestGetVoucherList(t *testing.T) {
|
|||||||
expectedSym := []byte("1:SRF\n2:MILO")
|
expectedSym := []byte("1:SRF\n2:MILO")
|
||||||
|
|
||||||
// Put voucher sym data from the store
|
// Put voucher sym data from the store
|
||||||
err := spdb.Put(ctx, []byte("sym"), expectedSym)
|
err := spdb.Put(ctx, common.ToBytes(common.DATA_VOUCHER_SYMBOLS), expectedSym)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -1973,16 +2023,16 @@ func TestViewVoucher(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Define mock voucher data
|
// Define mock voucher data
|
||||||
mockData := map[string][]byte{
|
mockData := map[common.DataTyp][]byte{
|
||||||
"sym": []byte("1:SRF\n2:MILO"),
|
common.DATA_VOUCHER_SYMBOLS: []byte("1:SRF\n2:MILO"),
|
||||||
"bal": []byte("1:100\n2:200"),
|
common.DATA_VOUCHER_BALANCES: []byte("1:100\n2:200"),
|
||||||
"deci": []byte("1:6\n2:4"),
|
common.DATA_VOUCHER_DECIMALS: []byte("1:6\n2:4"),
|
||||||
"addr": []byte("1:0xd4c288865Ce\n2:0x41c188d63Qa"),
|
common.DATA_VOUCHER_ADDRESSES: []byte("1:0xd4c288865Ce\n2:0x41c188d63Qa"),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put the data
|
// Put the data
|
||||||
for key, value := range mockData {
|
for key, value := range mockData {
|
||||||
err = spdb.Put(ctx, []byte(key), []byte(value))
|
err = spdb.Put(ctx, []byte(common.ToBytes(key)), []byte(value))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -1990,7 +2040,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, "SRF\n100")
|
assert.Equal(t, res.Content, "Symbol: SRF\nBalance: 100")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetVoucher(t *testing.T) {
|
func TestSetVoucher(t *testing.T) {
|
||||||
@ -2024,3 +2074,42 @@ 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)
|
||||||
|
}
|
||||||
|
@ -6,10 +6,6 @@ import (
|
|||||||
"git.defalsify.org/vise.git/db"
|
"git.defalsify.org/vise.git/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
DATATYPE_USERSUB = 64
|
|
||||||
)
|
|
||||||
|
|
||||||
// PrefixDb interface abstracts the database operations.
|
// PrefixDb interface abstracts the database operations.
|
||||||
type PrefixDb interface {
|
type PrefixDb interface {
|
||||||
Get(ctx context.Context, key []byte) ([]byte, error)
|
Get(ctx context.Context, key []byte) ([]byte, error)
|
||||||
@ -35,13 +31,13 @@ func (s *SubPrefixDb) toKey(k []byte) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *SubPrefixDb) Get(ctx context.Context, key []byte) ([]byte, error) {
|
func (s *SubPrefixDb) Get(ctx context.Context, key []byte) ([]byte, error) {
|
||||||
s.store.SetPrefix(DATATYPE_USERSUB)
|
s.store.SetPrefix(db.DATATYPE_USERDATA)
|
||||||
key = s.toKey(key)
|
key = s.toKey(key)
|
||||||
return s.store.Get(ctx, key)
|
return s.store.Get(ctx, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SubPrefixDb) Put(ctx context.Context, key []byte, val []byte) error {
|
func (s *SubPrefixDb) Put(ctx context.Context, key []byte, val []byte) error {
|
||||||
s.store.SetPrefix(DATATYPE_USERSUB)
|
s.store.SetPrefix(db.DATATYPE_USERDATA)
|
||||||
key = s.toKey(key)
|
key = s.toKey(key)
|
||||||
return s.store.Put(ctx, key, val)
|
return s.store.Put(ctx, key, val)
|
||||||
}
|
}
|
@ -47,3 +47,8 @@ func (m *MockAccountService) TokenTransfer(ctx context.Context, amount, from, to
|
|||||||
args := m.Called()
|
args := m.Called()
|
||||||
return args.Get(0).(*models.TokenTransferResponse), args.Error(1)
|
return args.Get(0).(*models.TokenTransferResponse), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MockAccountService) CheckAliasAddress(ctx context.Context, alias string) (*dataserviceapi.AliasAddress, error) {
|
||||||
|
args := m.Called(alias)
|
||||||
|
return args.Get(0).(*dataserviceapi.AliasAddress), args.Error(1)
|
||||||
|
}
|
||||||
|
@ -33,8 +33,8 @@ func (tas *TestAccountService) TrackAccountStatus(ctx context.Context, publicKey
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tas *TestAccountService) FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) {
|
func (tas *TestAccountService) FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) {
|
||||||
return []dataserviceapi.TokenHoldings {
|
return []dataserviceapi.TokenHoldings{
|
||||||
dataserviceapi.TokenHoldings {
|
dataserviceapi.TokenHoldings{
|
||||||
ContractAddress: "0x6CC75A06ac72eB4Db2eE22F781F5D100d8ec03ee",
|
ContractAddress: "0x6CC75A06ac72eB4Db2eE22F781F5D100d8ec03ee",
|
||||||
TokenSymbol: "SRF",
|
TokenSymbol: "SRF",
|
||||||
TokenDecimals: "6",
|
TokenDecimals: "6",
|
||||||
@ -56,3 +56,7 @@ func (tas *TestAccountService) TokenTransfer(ctx context.Context, amount, from,
|
|||||||
TrackingId: "e034d147-747d-42ea-928d-b5a7cb3426af",
|
TrackingId: "e034d147-747d-42ea-928d-b5a7cb3426af",
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m TestAccountService) CheckAliasAddress(ctx context.Context, alias string) (*dataserviceapi.AliasAddress, error) {
|
||||||
|
return &dataserviceapi.AliasAddress{}, nil
|
||||||
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"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.
|
||||||
@ -25,11 +28,29 @@ 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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
17
internal/utils/name.go
Normal file
17
internal/utils/name.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
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
|
||||||
|
}
|
@ -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",
|
||||||
@ -167,7 +167,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "menu_my_account_edit_firstname",
|
"name": "menu_my_account_edit_all_account_details_starting_from_firstname",
|
||||||
"steps": [
|
"steps": [
|
||||||
{
|
{
|
||||||
"input": "",
|
"input": "",
|
||||||
@ -187,6 +187,26 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"input": "foo",
|
"input": "foo",
|
||||||
|
"expectedContent": "Enter family name:\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "bar",
|
||||||
|
"expectedContent": "Select gender: \n1:Male\n2:Female\n3:Unspecified\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1",
|
||||||
|
"expectedContent": "Enter your year of birth\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1940",
|
||||||
|
"expectedContent": "Enter your location:\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "Kilifi",
|
||||||
|
"expectedContent": "Enter the services or goods you offer: \n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "Bananas",
|
||||||
"expectedContent": "Please enter your PIN:"
|
"expectedContent": "Please enter your PIN:"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -197,10 +217,6 @@
|
|||||||
"input": "0",
|
"input": "0",
|
||||||
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"input": "0",
|
|
||||||
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"input": "0",
|
"input": "0",
|
||||||
"expectedContent": "{balance}\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"
|
||||||
@ -208,7 +224,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "menu_my_account_edit_familyname",
|
"name": "menu_my_account_edit_familyname_when_all_account__details_have_been_set",
|
||||||
"steps": [
|
"steps": [
|
||||||
{
|
{
|
||||||
"input": "",
|
"input": "",
|
||||||
@ -238,10 +254,6 @@
|
|||||||
"input": "0",
|
"input": "0",
|
||||||
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"input": "0",
|
|
||||||
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"input": "0",
|
"input": "0",
|
||||||
"expectedContent": "{balance}\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"
|
||||||
@ -250,7 +262,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "menu_my_account_edit_gender",
|
"name": "menu_my_account_edit_gender_when_all_account__details_have_been_set",
|
||||||
"steps": [
|
"steps": [
|
||||||
{
|
{
|
||||||
"input": "",
|
"input": "",
|
||||||
@ -280,10 +292,6 @@
|
|||||||
"input": "0",
|
"input": "0",
|
||||||
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"input": "0",
|
|
||||||
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"input": "0",
|
"input": "0",
|
||||||
"expectedContent": "{balance}\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"
|
||||||
@ -291,7 +299,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "menu_my_account_edit_yob",
|
"name": "menu_my_account_edit_yob_when_all_account__details_have_been_set",
|
||||||
"steps": [
|
"steps": [
|
||||||
{
|
{
|
||||||
"input": "",
|
"input": "",
|
||||||
@ -321,10 +329,6 @@
|
|||||||
"input": "0",
|
"input": "0",
|
||||||
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"input": "0",
|
|
||||||
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"input": "0",
|
"input": "0",
|
||||||
"expectedContent": "{balance}\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"
|
||||||
@ -332,7 +336,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "menu_my_account_edit_location",
|
"name": "menu_my_account_edit_location_when_all_account_details_have_been_set",
|
||||||
"steps": [
|
"steps": [
|
||||||
{
|
{
|
||||||
"input": "",
|
"input": "",
|
||||||
@ -362,10 +366,6 @@
|
|||||||
"input": "0",
|
"input": "0",
|
||||||
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"input": "0",
|
|
||||||
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"input": "0",
|
"input": "0",
|
||||||
"expectedContent": "{balance}\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"
|
||||||
@ -373,7 +373,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "menu_my_account_edit_offerings",
|
"name": "menu_my_account_edit_offerings_when_all_account__details_have_been_set",
|
||||||
"steps": [
|
"steps": [
|
||||||
{
|
{
|
||||||
"input": "",
|
"input": "",
|
||||||
@ -403,10 +403,6 @@
|
|||||||
"input": "0",
|
"input": "0",
|
||||||
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"input": "0",
|
|
||||||
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"input": "0",
|
"input": "0",
|
||||||
"expectedContent": "{balance}\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"
|
||||||
@ -434,16 +430,12 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"input": "1234",
|
"input": "1234",
|
||||||
"expectedContent": "My profile:\nName: foo bar\nGender: male\nAge: 79\nLocation: Kilifi\nYou provide: Bananas\n\n0:Back"
|
"expectedContent": "My profile:\nName: foo bar\nGender: male\nAge: 84\nLocation: Kilifi\nYou provide: Bananas\n\n0:Back"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"input": "0",
|
"input": "0",
|
||||||
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"input": "0",
|
|
||||||
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"input": "0",
|
"input": "0",
|
||||||
"expectedContent": "{balance}\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"
|
||||||
|
@ -3,6 +3,7 @@ package menutraversaltest
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"flag"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
@ -15,14 +16,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
testData = driver.ReadData()
|
testData = driver.ReadData()
|
||||||
testStore = ".test_state"
|
testStore = ".test_state"
|
||||||
groupTestFile = "group_test.json"
|
sessionID string
|
||||||
sessionID string
|
src = rand.NewSource(42)
|
||||||
src = rand.NewSource(42)
|
g = rand.New(src)
|
||||||
g = rand.New(src)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var groupTestFile = flag.String("test-file", "group_test.json", "The test file to use for running the group tests")
|
||||||
|
|
||||||
func GenerateSessionId() string {
|
func GenerateSessionId() string {
|
||||||
uu := uuid.NewGenWithOptions(uuid.WithRandomReader(g))
|
uu := uuid.NewGenWithOptions(uuid.WithRandomReader(g))
|
||||||
v, err := uu.NewV4()
|
v, err := uu.NewV4()
|
||||||
@ -337,7 +339,7 @@ func TestMainMenuSend(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGroups(t *testing.T) {
|
func TestGroups(t *testing.T) {
|
||||||
groups, err := driver.LoadTestGroups(groupTestFile)
|
groups, err := driver.LoadTestGroups(*groupTestFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to load test groups: %v", err)
|
log.Fatalf("Failed to load test groups: %v", err)
|
||||||
}
|
}
|
||||||
|
68
menutraversal_test/profile_edit_start_familyname.json
Normal file
68
menutraversal_test/profile_edit_start_familyname.json
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"name": "menu_my_account_edit_all_account_details_starting_from_family_name",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"input": "",
|
||||||
|
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "3",
|
||||||
|
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1",
|
||||||
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "2",
|
||||||
|
"expectedContent": "Enter family name:\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "bar",
|
||||||
|
"expectedContent": "Select gender: \n1:Male\n2:Female\n3:Unspecified\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1",
|
||||||
|
"expectedContent": "Enter your year of birth\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1940",
|
||||||
|
"expectedContent": "Enter your location:\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "Kilifi",
|
||||||
|
"expectedContent": "Enter the services or goods you offer: \n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "Bananas",
|
||||||
|
"expectedContent": "Please enter your PIN:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1234",
|
||||||
|
"expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "0",
|
||||||
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "0",
|
||||||
|
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
61
menutraversal_test/profile_edit_start_firstname.json
Normal file
61
menutraversal_test/profile_edit_start_firstname.json
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"name": "menu_my_account_edit_all_account_details_starting_from_firstname",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"input": "",
|
||||||
|
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "3",
|
||||||
|
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1",
|
||||||
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1",
|
||||||
|
"expectedContent": "Enter your first names:\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "foo",
|
||||||
|
"expectedContent": "Enter family name:\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "bar",
|
||||||
|
"expectedContent": "Select gender: \n1:Male\n2:Female\n3:Unspecified\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1",
|
||||||
|
"expectedContent": "Enter your year of birth\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1940",
|
||||||
|
"expectedContent": "Enter your location:\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "Kilifi",
|
||||||
|
"expectedContent": "Enter the services or goods you offer: \n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "Bananas",
|
||||||
|
"expectedContent": "Please enter your PIN:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1234",
|
||||||
|
"expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "0",
|
||||||
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "0",
|
||||||
|
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
55
menutraversal_test/profile_edit_start_gender.json
Normal file
55
menutraversal_test/profile_edit_start_gender.json
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"name": "menu_my_account_edit_all_account_details_starting_from_gender",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"input": "",
|
||||||
|
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "3",
|
||||||
|
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1",
|
||||||
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "3",
|
||||||
|
"expectedContent": "Select gender: \n1:Male\n2:Female\n3:Unspecified\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1",
|
||||||
|
"expectedContent": "Enter your year of birth\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1940",
|
||||||
|
"expectedContent": "Enter your location:\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "Kilifi",
|
||||||
|
"expectedContent": "Enter the services or goods you offer: \n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "Bananas",
|
||||||
|
"expectedContent": "Please enter your PIN:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1234",
|
||||||
|
"expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "0",
|
||||||
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "0",
|
||||||
|
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
46
menutraversal_test/profile_edit_start_location.json
Normal file
46
menutraversal_test/profile_edit_start_location.json
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"name": "menu_my_account_edit_all_account_details_starting_from_location",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"input": "",
|
||||||
|
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "3",
|
||||||
|
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1",
|
||||||
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "5",
|
||||||
|
"expectedContent": "Enter your location:\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "Kilifi",
|
||||||
|
"expectedContent": "Enter the services or goods you offer: \n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "Bananas",
|
||||||
|
"expectedContent": "Please enter your PIN:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1234",
|
||||||
|
"expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "0",
|
||||||
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "0",
|
||||||
|
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
42
menutraversal_test/profile_edit_start_offerings.json
Normal file
42
menutraversal_test/profile_edit_start_offerings.json
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"name": "menu_my_account_edit_all_account_details_starting_from_offerings",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"input": "",
|
||||||
|
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "3",
|
||||||
|
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1",
|
||||||
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "6",
|
||||||
|
"expectedContent": "Enter the services or goods you offer: \n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "Bananas",
|
||||||
|
"expectedContent": "Please enter your PIN:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1234",
|
||||||
|
"expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "0",
|
||||||
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "0",
|
||||||
|
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
50
menutraversal_test/profile_edit_start_yob.json
Normal file
50
menutraversal_test/profile_edit_start_yob.json
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"name": "menu_my_account_edit_all_account_details_starting_from_yob",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"input": "",
|
||||||
|
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "3",
|
||||||
|
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1",
|
||||||
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "4",
|
||||||
|
"expectedContent": "Enter your year of birth\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1940",
|
||||||
|
"expectedContent": "Enter your location:\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "Kilifi",
|
||||||
|
"expectedContent": "Enter the services or goods you offer: \n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "Bananas",
|
||||||
|
"expectedContent": "Please enter your PIN:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1234",
|
||||||
|
"expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "0",
|
||||||
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "0",
|
||||||
|
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
70
menutraversal_test/profile_edit_when_adjacent_item_set.json
Normal file
70
menutraversal_test/profile_edit_when_adjacent_item_set.json
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
{
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"name": "menu_my_account_edit_familyname_when_adjacent_profile_information_set",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"input": "",
|
||||||
|
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "3",
|
||||||
|
"expectedContent": "My Account\n1:Profile\n2:Change language\n3:Check balances\n4:Check statement\n5:PIN options\n6:My Address\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1",
|
||||||
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "3",
|
||||||
|
"expectedContent": "Select gender: \n1:Male\n2:Female\n3:Unspecified\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1",
|
||||||
|
"expectedContent": "Enter your year of birth\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1940",
|
||||||
|
"expectedContent": "Enter your location:\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "Kilifi",
|
||||||
|
"expectedContent": "Enter the services or goods you offer: \n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "Bananas",
|
||||||
|
"expectedContent": "Please enter your PIN:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1234",
|
||||||
|
"expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "0",
|
||||||
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "2",
|
||||||
|
"expectedContent": "Enter family name:\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "foo2",
|
||||||
|
"expectedContent": "Please enter your PIN:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "1234",
|
||||||
|
"expectedContent": "Profile updated successfully\n\n0:Back\n9:Quit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "0",
|
||||||
|
"expectedContent": "My profile\n1:Edit name\n2:Edit family name\n3:Edit gender\n4:Edit year of birth\n5:Edit location\n6:Edit offerings\n7:View profile\n0:Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"input": "0",
|
||||||
|
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -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",
|
||||||
@ -61,7 +61,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"input": "1",
|
"input": "1",
|
||||||
"expectedContent": "Enter recipient's phone number:\n0:Back"
|
"expectedContent": "Enter recipient's phone number/address/alias:\n0:Back"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"input": "000",
|
"input": "000",
|
||||||
@ -69,7 +69,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"input": "1",
|
"input": "1",
|
||||||
"expectedContent": "Enter recipient's phone number:\n0:Back"
|
"expectedContent": "Enter recipient's phone number/address/alias:\n0:Back"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"input": "0712345678",
|
"input": "0712345678",
|
||||||
|
18
models/profile.go
Normal file
18
models/profile.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
type Profile struct {
|
||||||
|
ProfileItems []string
|
||||||
|
Max int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Profile) InsertOrShift(index int, value string) {
|
||||||
|
if index < len(p.ProfileItems) {
|
||||||
|
p.ProfileItems = append(p.ProfileItems[:index], value)
|
||||||
|
} else {
|
||||||
|
for len(p.ProfileItems) < index {
|
||||||
|
p.ProfileItems = append(p.ProfileItems, "0")
|
||||||
|
}
|
||||||
|
p.ProfileItems = append(p.ProfileItems, "0")
|
||||||
|
p.ProfileItems[index] = value
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,10 @@
|
|||||||
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"`
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ type AccountServiceInterface interface {
|
|||||||
FetchTransactions(ctx context.Context, publicKey string) ([]dataserviceapi.Last10TxResponse, error)
|
FetchTransactions(ctx context.Context, publicKey string) ([]dataserviceapi.Last10TxResponse, error)
|
||||||
VoucherData(ctx context.Context, address string) (*models.VoucherDataResult, error)
|
VoucherData(ctx context.Context, address string) (*models.VoucherDataResult, error)
|
||||||
TokenTransfer(ctx context.Context, amount, from, to, tokenAddress string) (*models.TokenTransferResponse, error)
|
TokenTransfer(ctx context.Context, amount, from, to, tokenAddress string) (*models.TokenTransferResponse, error)
|
||||||
|
CheckAliasAddress(ctx context.Context, alias string) (*dataserviceapi.AliasAddress, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type AccountService struct {
|
type AccountService struct {
|
||||||
@ -209,6 +210,26 @@ func (as *AccountService) TokenTransfer(ctx context.Context, amount, from, to, t
|
|||||||
return &r, nil
|
return &r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckAliasAddress retrieves the address of an alias from the API endpoint.
|
||||||
|
// Parameters:
|
||||||
|
// - alias: The alias of the user.
|
||||||
|
func (as *AccountService) CheckAliasAddress(ctx context.Context, alias string) (*dataserviceapi.AliasAddress, error) {
|
||||||
|
var r dataserviceapi.AliasAddress
|
||||||
|
|
||||||
|
ep, err := url.JoinPath(config.CheckAliasURL, alias)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", ep, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = doRequest(ctx, req, &r)
|
||||||
|
return &r, err
|
||||||
|
}
|
||||||
|
|
||||||
func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) {
|
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
|
var errResponse api.ErrResponse
|
||||||
|
1
services/registration/_catch_swa
Normal file
1
services/registration/_catch_swa
Normal file
@ -0,0 +1 @@
|
|||||||
|
Tatizo la kimtambo limetokea,tafadhali jaribu tena baadaye.
|
@ -2,9 +2,17 @@ CATCH incorrect_pin flag_incorrect_pin 1
|
|||||||
CATCH update_familyname flag_allow_update 1
|
CATCH update_familyname flag_allow_update 1
|
||||||
LOAD get_current_profile_info 0
|
LOAD get_current_profile_info 0
|
||||||
RELOAD get_current_profile_info
|
RELOAD get_current_profile_info
|
||||||
|
MAP get_current_profile_info
|
||||||
MOUT back 0
|
MOUT back 0
|
||||||
HALT
|
HALT
|
||||||
LOAD save_familyname 0
|
RELOAD set_back
|
||||||
|
CATCH _ flag_back_set 1
|
||||||
|
LOAD save_familyname 64
|
||||||
RELOAD save_familyname
|
RELOAD save_familyname
|
||||||
INCMP _ 0
|
CATCH pin_entry flag_familyname_set 1
|
||||||
INCMP pin_entry *
|
CATCH select_gender flag_gender_set 0
|
||||||
|
CATCH edit_yob flag_yob_set 0
|
||||||
|
CATCH edit_location flag_location_set 0
|
||||||
|
CATCH edit_offerings flag_offerings_set 0
|
||||||
|
CATCH pin_entry flag_familyname_set 0
|
||||||
|
INCMP select_gender *
|
||||||
|
@ -5,7 +5,14 @@ RELOAD get_current_profile_info
|
|||||||
MAP get_current_profile_info
|
MAP get_current_profile_info
|
||||||
MOUT back 0
|
MOUT back 0
|
||||||
HALT
|
HALT
|
||||||
LOAD save_firstname 0
|
RELOAD set_back
|
||||||
|
CATCH _ flag_back_set 1
|
||||||
|
LOAD save_firstname 128
|
||||||
RELOAD save_firstname
|
RELOAD save_firstname
|
||||||
INCMP _ 0
|
CATCH pin_entry flag_firstname_set 1
|
||||||
INCMP pin_entry *
|
CATCH edit_family_name flag_familyname_set 0
|
||||||
|
CATCH edit_gender flag_gender_set 0
|
||||||
|
CATCH edit_yob flag_yob_set 0
|
||||||
|
CATCH edit_location flag_location_set 0
|
||||||
|
CATCH edit_offerings flag_offerings_set 0
|
||||||
|
CATCH pin_entry flag_firstname_set 0
|
||||||
|
@ -2,9 +2,14 @@ CATCH incorrect_pin flag_incorrect_pin 1
|
|||||||
CATCH update_location flag_allow_update 1
|
CATCH update_location flag_allow_update 1
|
||||||
LOAD get_current_profile_info 0
|
LOAD get_current_profile_info 0
|
||||||
RELOAD get_current_profile_info
|
RELOAD get_current_profile_info
|
||||||
|
LOAD save_location 16
|
||||||
MOUT back 0
|
MOUT back 0
|
||||||
HALT
|
HALT
|
||||||
LOAD save_location 0
|
RELOAD set_back
|
||||||
|
CATCH _ flag_back_set 1
|
||||||
RELOAD save_location
|
RELOAD save_location
|
||||||
INCMP _ 0
|
INCMP _ 0
|
||||||
INCMP pin_entry *
|
CATCH pin_entry flag_location_set 1
|
||||||
|
CATCH edit_offerings flag_offerings_set 0
|
||||||
|
CATCH pin_entry flag_location_set 0
|
||||||
|
INCMP edit_offerings *
|
||||||
|
@ -2,9 +2,13 @@ CATCH incorrect_pin flag_incorrect_pin 1
|
|||||||
CATCH update_offerings flag_allow_update 1
|
CATCH update_offerings flag_allow_update 1
|
||||||
LOAD get_current_profile_info 0
|
LOAD get_current_profile_info 0
|
||||||
RELOAD get_current_profile_info
|
RELOAD get_current_profile_info
|
||||||
LOAD save_offerings 0
|
LOAD save_offerings 8
|
||||||
MOUT back 0
|
MOUT back 0
|
||||||
HALT
|
HALT
|
||||||
|
RELOAD set_back
|
||||||
|
CATCH _ flag_back_set 1
|
||||||
RELOAD save_offerings
|
RELOAD save_offerings
|
||||||
INCMP _ 0
|
INCMP _ 0
|
||||||
INCMP pin_entry *
|
CATCH pin_entry flag_offerings_set 1
|
||||||
|
CATCH pin_entry flag_offerings_set 0
|
||||||
|
INCMP update_profile_items *
|
||||||
|
@ -11,7 +11,8 @@ MOUT edit_offerings 6
|
|||||||
MOUT view 7
|
MOUT view 7
|
||||||
MOUT back 0
|
MOUT back 0
|
||||||
HALT
|
HALT
|
||||||
INCMP my_account 0
|
LOAD set_back 6
|
||||||
|
INCMP ^ 0
|
||||||
INCMP edit_first_name 1
|
INCMP edit_first_name 1
|
||||||
INCMP edit_family_name 2
|
INCMP edit_family_name 2
|
||||||
INCMP select_gender 3
|
INCMP select_gender 3
|
||||||
|
@ -5,10 +5,15 @@ RELOAD get_current_profile_info
|
|||||||
MAP get_current_profile_info
|
MAP get_current_profile_info
|
||||||
MOUT back 0
|
MOUT back 0
|
||||||
HALT
|
HALT
|
||||||
|
RELOAD set_back
|
||||||
|
CATCH _ flag_back_set 1
|
||||||
LOAD verify_yob 6
|
LOAD verify_yob 6
|
||||||
RELOAD verify_yob
|
RELOAD verify_yob
|
||||||
CATCH incorrect_date_format flag_incorrect_date_format 1
|
CATCH incorrect_date_format flag_incorrect_date_format 1
|
||||||
LOAD save_yob 0
|
LOAD save_yob 32
|
||||||
RELOAD save_yob
|
RELOAD save_yob
|
||||||
INCMP _ 0
|
CATCH pin_entry flag_yob_set 1
|
||||||
INCMP pin_entry *
|
CATCH edit_location flag_location_set 0
|
||||||
|
CATCH edit_offerings flag_offerings_set 0
|
||||||
|
CATCH pin_entry flag_yob_set 0
|
||||||
|
INCMP edit_location *
|
||||||
|
1
services/registration/english_menu
Normal file
1
services/registration/english_menu
Normal file
@ -0,0 +1 @@
|
|||||||
|
English
|
@ -1 +1 @@
|
|||||||
Incorrect pin
|
Incorrect PIN
|
@ -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.
|
||||||
|
1
services/registration/kiswahili_menu
Normal file
1
services/registration/kiswahili_menu
Normal file
@ -0,0 +1 @@
|
|||||||
|
Kiswahili
|
@ -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"
|
||||||
|
|
||||||
msid "Your invite request for %s to Sarafu Network failed. Please try again later."
|
msgid "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,4 +23,7 @@ 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"
|
||||||
msgid "Salio la Kikundi: 0.00"
|
msgstr "Salio la Kikundi: 0.00"
|
||||||
|
|
||||||
|
msgid "Symbol: %s\nBalance: %s"
|
||||||
|
msgstr "Sarafu: %s\nSalio: %s"
|
||||||
|
@ -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
|
||||||
CATCH api_failure flag_api_call_error 1
|
LOAD check_balance 128
|
||||||
|
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
|
||||||
|
@ -1 +1 @@
|
|||||||
Salio lako ni: 0.00 SRF
|
{{.check_balance}}
|
1
services/registration/next_menu
Normal file
1
services/registration/next_menu
Normal file
@ -0,0 +1 @@
|
|||||||
|
Next
|
1
services/registration/next_menu_swa
Normal file
1
services/registration/next_menu_swa
Normal file
@ -0,0 +1 @@
|
|||||||
|
Mbele
|
@ -1 +1 @@
|
|||||||
no
|
No
|
@ -1 +1 @@
|
|||||||
la
|
La
|
@ -21,3 +21,10 @@ 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
|
flag,flag_unregistered_number,28,this is set when an unregistered phonenumber tries to perform an action
|
||||||
flag,flag_no_transfers,29,this is set when a user does not have any transactions
|
flag,flag_no_transfers,29,this is set when a user does not have any transactions
|
||||||
flag,flag_incorrect_statement,30,this is set when the selected statement is invalid
|
flag,flag_incorrect_statement,30,this is set when the selected statement is invalid
|
||||||
|
flag,flag_firstname_set,31,this is set when the first name of the profile is set
|
||||||
|
flag,flag_familyname_set,32,this is set when the family name of the profile is set
|
||||||
|
flag,flag_yob_set,33,this is set when the yob of the profile is set
|
||||||
|
flag,flag_gender_set,34,this is set when the gender of the profile is set
|
||||||
|
flag,flag_location_set,35,this is set when the location of the profile is set
|
||||||
|
flag,flag_offerings_set,36,this is set when the offerings of the profile is set
|
||||||
|
flag,flag_back_set,37,this is set when it is a back navigation
|
||||||
|
|
1
services/registration/prev_menu
Normal file
1
services/registration/prev_menu
Normal file
@ -0,0 +1 @@
|
|||||||
|
Prev
|
1
services/registration/prev_menu_swa
Normal file
1
services/registration/prev_menu_swa
Normal file
@ -0,0 +1 @@
|
|||||||
|
Nyuma
|
@ -1,3 +1,5 @@
|
|||||||
|
LOAD update_all_profile_items 0
|
||||||
|
RELOAD update_all_profile_items
|
||||||
MOUT back 0
|
MOUT back 0
|
||||||
MOUT quit 9
|
MOUT quit 9
|
||||||
HALT
|
HALT
|
||||||
|
@ -1 +1 @@
|
|||||||
Enter recipient's phone number:
|
Enter recipient's phone number/address/alias:
|
@ -1,3 +1,4 @@
|
|||||||
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
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
LOAD save_gender 0
|
LOAD save_gender 32
|
||||||
|
RELOAD save_gender
|
||||||
CATCH incorrect_pin flag_incorrect_pin 1
|
CATCH incorrect_pin flag_incorrect_pin 1
|
||||||
CATCH update_gender flag_allow_update 1
|
CATCH update_gender flag_allow_update 1
|
||||||
MOVE pin_entry
|
CATCH pin_entry flag_gender_set 1
|
||||||
|
CATCH edit_yob flag_yob_set 0
|
||||||
|
CATCH edit_location flag_location_set 0
|
||||||
|
CATCH edit_offerings flag_offerings_set 0
|
||||||
|
CATCH pin_entry flag_gender_set 0
|
||||||
|
MOVE edit_yob
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
LOAD save_gender 0
|
LOAD save_gender 16
|
||||||
|
RELOAD save_gender
|
||||||
CATCH incorrect_pin flag_incorrect_pin 1
|
CATCH incorrect_pin flag_incorrect_pin 1
|
||||||
CATCH update_gender flag_allow_update 1
|
CATCH update_gender flag_allow_update 1
|
||||||
MOVE pin_entry
|
CATCH pin_entry flag_gender_set 1
|
||||||
|
CATCH edit_yob flag_yob_set 0
|
||||||
|
CATCH edit_location flag_location_set 0
|
||||||
|
CATCH edit_offerings flag_offerings_set 0
|
||||||
|
CATCH pin_entry flag_gender_set 0
|
||||||
|
MOVE edit_yob
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
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
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
LOAD save_gender 0
|
LOAD save_gender 8
|
||||||
|
RELOAD save_gender
|
||||||
CATCH incorrect_pin flag_incorrect_pin 1
|
CATCH incorrect_pin flag_incorrect_pin 1
|
||||||
CATCH update_gender flag_allow_update 1
|
CATCH update_gender flag_allow_update 1
|
||||||
MOVE pin_entry
|
CATCH pin_entry flag_gender_set 1
|
||||||
|
CATCH edit_yob flag_yob_set 0
|
||||||
|
CATCH edit_location flag_location_set 0
|
||||||
|
CATCH edit_offerings flag_offerings_set 0
|
||||||
|
CATCH pin_entry flag_gender_set 0
|
||||||
|
MOVE edit_yob
|
||||||
|
3
services/registration/update_profile_items.vis
Normal file
3
services/registration/update_profile_items.vis
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
CATCH incorrect_pin flag_incorrect_pin 1
|
||||||
|
CATCH profile_update_success flag_allow_update 1
|
||||||
|
MOVE pin_entry
|
@ -1 +1 @@
|
|||||||
yes
|
Yes
|
@ -1 +1 @@
|
|||||||
ndio
|
Ndio
|
Loading…
Reference in New Issue
Block a user