2024-08-26 14:53:07 +02:00
package ussd
import (
"bytes"
"context"
"fmt"
2024-11-14 18:10:48 +01:00
"math/big"
2024-08-28 17:13:49 +02:00
"path"
2024-08-27 15:16:15 +02:00
"regexp"
2024-08-27 13:57:26 +02:00
"strconv"
2024-08-27 15:02:24 +02:00
"strings"
2024-08-26 14:53:07 +02:00
2024-08-31 09:21:20 +02:00
"git.defalsify.org/vise.git/asm"
2024-10-21 10:10:01 +02:00
"github.com/grassrootseconomics/eth-custodial/pkg/api"
2024-09-05 16:07:20 +02:00
"git.defalsify.org/vise.git/cache"
"git.defalsify.org/vise.git/db"
2024-08-26 14:53:07 +02:00
"git.defalsify.org/vise.git/lang"
2024-09-05 19:30:28 +02:00
"git.defalsify.org/vise.git/logging"
2024-09-05 16:07:20 +02:00
"git.defalsify.org/vise.git/persist"
2024-08-26 14:53:07 +02:00
"git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/state"
2024-10-30 01:59:59 +01:00
"git.grassecon.net/urdt/ussd/common"
2024-08-26 14:53:07 +02:00
"git.grassecon.net/urdt/ussd/internal/utils"
2024-11-04 13:52:03 +01:00
"git.grassecon.net/urdt/ussd/remote"
2024-08-28 17:13:49 +02:00
"gopkg.in/leonelquinteros/gotext.v1"
2024-10-07 12:49:12 +02:00
"git.grassecon.net/urdt/ussd/internal/storage"
2024-08-28 17:13:49 +02:00
)
var (
2024-09-05 19:30:28 +02:00
logg = logging . NewVanilla ( ) . WithDomain ( "ussdmenuhandler" )
2024-08-29 22:15:58 +02:00
scriptDir = path . Join ( "services" , "registration" )
2024-08-28 17:13:49 +02:00
translationDir = path . Join ( scriptDir , "locale" )
2024-10-21 10:10:01 +02:00
okResponse * api . OKResponse
errResponse * api . ErrResponse
2024-08-26 14:53:07 +02:00
)
2024-10-29 20:17:43 +01:00
// Define the regex patterns as constants
const (
phoneRegex = ` (\(\d { 3}\)\s?|\d { 3}[-.\s]?)?\d { 3}[-.\s]?\d { 4} `
pinPattern = ` ^\d { 4}$ `
)
2024-09-03 18:06:37 +02:00
// FlagManager handles centralized flag management
type FlagManager struct {
parser * asm . FlagParser
}
// NewFlagManager creates a new FlagManager instance
func NewFlagManager ( csvPath string ) ( * FlagManager , error ) {
parser := asm . NewFlagParser ( )
_ , err := parser . Load ( csvPath )
if err != nil {
return nil , fmt . Errorf ( "failed to load flag parser: %v" , err )
}
return & FlagManager {
parser : parser ,
} , nil
}
// GetFlag retrieves a flag value by its label
func ( fm * FlagManager ) GetFlag ( label string ) ( uint32 , error ) {
return fm . parser . GetFlag ( label )
}
2024-08-26 14:53:07 +02:00
type Handlers struct {
2024-09-09 16:18:07 +02:00
pe * persist . Persister
st * state . State
ca cache . Memory
2024-10-30 02:45:38 +01:00
userdataStore common . DataStore
2024-10-30 12:50:12 +01:00
adminstore * utils . AdminStore
2024-09-09 16:18:07 +02:00
flagManager * asm . FlagParser
2024-10-30 14:09:15 +01:00
accountService remote . AccountServiceInterface
2024-10-28 14:27:24 +01:00
prefixDb storage . PrefixDb
2024-08-26 14:53:07 +02:00
}
2024-11-02 15:00:16 +01:00
func NewHandlers ( appFlags * asm . FlagParser , userdataStore db . Db , adminstore * utils . AdminStore , accountService remote . AccountServiceInterface ) ( * Handlers , error ) {
2024-09-05 21:35:51 +02:00
if userdataStore == nil {
return nil , fmt . Errorf ( "cannot create handler with nil userdata store" )
}
2024-10-30 02:45:38 +01:00
userDb := & common . UserDataStore {
2024-09-06 01:40:57 +02:00
Db : userdataStore ,
}
2024-10-28 14:27:24 +01:00
// Instantiate the SubPrefixDb with "vouchers" prefix
prefixDb := storage . NewSubPrefixDb ( userdataStore , [ ] byte ( "vouchers" ) )
2024-09-05 16:07:20 +02:00
h := & Handlers {
2024-09-14 19:01:58 +02:00
userdataStore : userDb ,
flagManager : appFlags ,
2024-10-30 12:50:12 +01:00
adminstore : adminstore ,
2024-10-17 11:37:15 +02:00
accountService : accountService ,
2024-10-28 14:27:24 +01:00
prefixDb : prefixDb ,
2024-09-05 16:07:20 +02:00
}
return h , nil
2024-08-26 14:53:07 +02:00
}
2024-08-29 22:17:56 +02:00
// isValidPIN checks whether the given input is a 4 digit number
func isValidPIN ( pin string ) bool {
match , _ := regexp . MatchString ( pinPattern , pin )
return match
}
2024-10-29 20:17:43 +01:00
func isValidPhoneNumber ( phonenumber string ) bool {
match , _ := regexp . MatchString ( phoneRegex , phonenumber )
return match
}
2024-09-06 01:40:57 +02:00
func ( h * Handlers ) WithPersister ( pe * persist . Persister ) * Handlers {
if h . pe != nil {
panic ( "persister already set" )
}
h . pe = pe
return h
}
2024-09-05 21:35:51 +02:00
func ( h * Handlers ) Init ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
var r resource . Result
if h . pe == nil {
logg . WarnCtxf ( ctx , "handler init called before it is ready or more than once" , "state" , h . st , "cache" , h . ca )
return r , nil
}
2024-10-28 14:37:23 +01:00
2024-09-05 21:35:51 +02:00
h . st = h . pe . GetState ( )
h . ca = h . pe . GetMemory ( )
2024-10-28 14:37:23 +01:00
2024-10-29 12:28:58 +01:00
sessionId , _ := ctx . Value ( "SessionId" ) . ( string )
flag_admin_privilege , _ := h . flagManager . GetFlag ( "flag_admin_privilege" )
2024-10-30 12:50:12 +01:00
isAdmin , _ := h . adminstore . IsAdmin ( sessionId )
2024-10-29 12:28:58 +01:00
if isAdmin {
r . FlagSet = append ( r . FlagSet , flag_admin_privilege )
} else {
r . FlagReset = append ( r . FlagReset , flag_admin_privilege )
}
2024-09-05 21:35:51 +02:00
if h . st == nil || h . ca == nil {
logg . ErrorCtxf ( ctx , "perister fail in handler" , "state" , h . st , "cache" , h . ca )
return r , fmt . Errorf ( "cannot get state and memory for handler" )
2024-09-06 08:33:39 +02:00
}
2024-09-05 21:35:51 +02:00
h . pe = nil
2024-09-06 00:55:51 +02:00
logg . DebugCtxf ( ctx , "handler has been initialized" , "state" , h . st , "cache" , h . ca )
2024-09-05 21:35:51 +02:00
return r , nil
}
2024-08-28 15:23:52 +02:00
// SetLanguage sets the language across the menu
2024-08-26 14:53:07 +02:00
func ( h * Handlers ) SetLanguage ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-09-02 13:00:02 +02:00
2024-09-24 08:01:19 +02:00
symbol , _ := h . st . Where ( )
code := strings . Split ( symbol , "_" ) [ 1 ]
2024-09-17 14:26:50 +02:00
2024-09-24 08:01:19 +02:00
if ! utils . IsValidISO639 ( code ) {
return res , nil
2024-08-26 14:53:07 +02:00
}
2024-09-24 08:01:19 +02:00
res . FlagSet = append ( res . FlagSet , state . FLAG_LANG )
res . Content = code
2024-08-26 14:53:07 +02:00
2024-09-03 18:06:37 +02:00
languageSetFlag , err := h . flagManager . GetFlag ( "flag_language_set" )
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "Error setting the languageSetFlag" , "error" , err )
2024-09-03 18:06:37 +02:00
return res , err
}
res . FlagSet = append ( res . FlagSet , languageSetFlag )
2024-08-26 14:53:07 +02:00
return res , nil
}
2024-09-05 16:07:20 +02:00
func ( h * Handlers ) createAccountNoExist ( ctx context . Context , sessionId string , res * resource . Result ) error {
2024-10-21 10:10:01 +02:00
flag_account_created , _ := h . flagManager . GetFlag ( "flag_account_created" )
2024-10-31 02:28:37 +01:00
r , err := h . accountService . CreateAccount ( ctx )
2024-10-24 09:02:15 +02:00
if err != nil {
return err
2024-09-05 16:07:20 +02:00
}
2024-10-31 02:28:37 +01:00
trackingId := r . TrackingId
publicKey := r . PublicKey
2024-09-09 16:18:07 +02:00
2024-10-30 02:28:55 +01:00
data := map [ common . DataTyp ] string {
common . DATA_TRACKING_ID : trackingId ,
common . DATA_PUBLIC_KEY : publicKey ,
2024-09-05 16:07:20 +02:00
}
2024-10-30 01:59:59 +01:00
store := h . userdataStore
2024-09-05 16:07:20 +02:00
for key , value := range data {
2024-10-30 01:59:59 +01:00
err = store . WriteEntry ( ctx , sessionId , key , [ ] byte ( value ) )
2024-09-05 16:07:20 +02:00
if err != nil {
return err
}
}
2024-10-30 01:59:59 +01:00
publicKeyNormalized , err := common . NormalizeHex ( publicKey )
if err != nil {
return err
}
2024-10-30 02:28:55 +01:00
err = store . WriteEntry ( ctx , publicKeyNormalized , common . DATA_PUBLIC_KEY_REVERSE , [ ] byte ( sessionId ) )
2024-10-30 01:59:59 +01:00
if err != nil {
return err
}
2024-09-05 16:07:20 +02:00
res . FlagSet = append ( res . FlagSet , flag_account_created )
2024-10-18 16:03:48 +02:00
return nil
2024-09-05 16:07:20 +02:00
}
2024-08-28 15:23:52 +02:00
// CreateAccount checks if any account exists on the JSON data file, and if not
// creates an account on the API,
// sets the default values and flags
2024-08-26 14:53:07 +02:00
func ( h * Handlers ) CreateAccount ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
var err error
2024-09-05 16:07:20 +02:00
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-09-09 16:18:07 +02:00
store := h . userdataStore
2024-10-30 02:28:55 +01:00
_ , err = store . ReadEntry ( ctx , sessionId , common . DATA_ACCOUNT_CREATED )
2024-08-26 14:53:07 +02:00
if err != nil {
2024-09-05 16:07:20 +02:00
if db . IsNotFound ( err ) {
2024-11-13 17:00:27 +01:00
logg . InfoCtxf ( ctx , "Creating an account because it doesn't exist" )
2024-09-05 16:07:20 +02:00
err = h . createAccountNoExist ( ctx , sessionId , & res )
2024-09-03 12:19:32 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed on createAccountNoExist" , "error" , err )
2024-09-03 12:19:32 +02:00
return res , err
}
2024-09-07 15:22:08 +02:00
}
2024-08-26 14:53:07 +02:00
}
2024-11-13 13:19:45 +01:00
2024-09-05 16:07:20 +02:00
return res , nil
2024-08-26 14:53:07 +02:00
}
2024-10-28 14:37:23 +01:00
func ( h * Handlers ) CheckPinMisMatch ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
res := resource . Result { }
flag_pin_mismatch , _ := h . flagManager . GetFlag ( "flag_pin_mismatch" )
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
store := h . userdataStore
2024-11-02 16:46:46 +01:00
blockedNumber , err := store . ReadEntry ( ctx , sessionId , common . DATA_BLOCKED_NUMBER )
2024-10-30 12:50:12 +01:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to read blockedNumber entry with" , "key" , common . DATA_BLOCKED_NUMBER , "error" , err )
2024-10-30 12:50:12 +01:00
return res , err
}
2024-11-02 16:46:46 +01:00
temporaryPin , err := store . ReadEntry ( ctx , string ( blockedNumber ) , common . DATA_TEMPORARY_VALUE )
2024-10-28 14:37:23 +01:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to read temporaryPin entry with" , "key" , common . DATA_TEMPORARY_VALUE , "error" , err )
2024-10-28 14:37:23 +01:00
return res , err
}
if bytes . Equal ( temporaryPin , input ) {
res . FlagReset = append ( res . FlagReset , flag_pin_mismatch )
} else {
res . FlagSet = append ( res . FlagSet , flag_pin_mismatch )
}
return res , nil
}
2024-09-16 13:39:01 +02:00
func ( h * Handlers ) VerifyNewPin ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
res := resource . Result { }
_ , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
flag_valid_pin , _ := h . flagManager . GetFlag ( "flag_valid_pin" )
pinInput := string ( input )
// Validate that the PIN is a 4-digit number
if isValidPIN ( pinInput ) {
res . FlagSet = append ( res . FlagSet , flag_valid_pin )
} else {
res . FlagReset = append ( res . FlagReset , flag_valid_pin )
}
return res , nil
}
2024-10-31 22:42:23 +01:00
// SaveTemporaryPin saves the valid PIN input to the DATA_TEMPORARY_VALUE
2024-09-28 11:26:37 +02:00
// during the account creation process
// and during the change PIN process
2024-09-16 13:39:01 +02:00
func ( h * Handlers ) SaveTemporaryPin ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
var res resource . Result
var err error
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-09-28 11:26:37 +02:00
2024-09-16 13:39:01 +02:00
flag_incorrect_pin , _ := h . flagManager . GetFlag ( "flag_incorrect_pin" )
accountPIN := string ( input )
// Validate that the PIN is a 4-digit number
if ! isValidPIN ( accountPIN ) {
res . FlagSet = append ( res . FlagSet , flag_incorrect_pin )
return res , nil
}
2024-09-28 11:26:37 +02:00
res . FlagReset = append ( res . FlagReset , flag_incorrect_pin )
2024-09-16 13:39:01 +02:00
store := h . userdataStore
2024-11-01 04:17:01 +01:00
err = store . WriteEntry ( ctx , sessionId , common . DATA_TEMPORARY_VALUE , [ ] byte ( accountPIN ) )
2024-09-16 13:39:01 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to write temporaryAccountPIN entry with" , "key" , common . DATA_TEMPORARY_VALUE , "value" , accountPIN , "error" , err )
2024-09-16 13:39:01 +02:00
return res , err
}
2024-09-28 11:26:37 +02:00
2024-09-16 13:39:01 +02:00
return res , nil
}
2024-10-30 12:50:12 +01:00
func ( h * Handlers ) SaveOthersTemporaryPin ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
var res resource . Result
var err error
store := h . userdataStore
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
temporaryPin := string ( input )
2024-11-02 16:46:46 +01:00
blockedNumber , err := store . ReadEntry ( ctx , sessionId , common . DATA_BLOCKED_NUMBER )
2024-10-30 12:50:12 +01:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to read blockedNumber entry with" , "key" , common . DATA_BLOCKED_NUMBER , "error" , err )
2024-10-30 12:50:12 +01:00
return res , err
}
2024-11-13 17:00:27 +01:00
2024-11-02 16:46:46 +01:00
err = store . WriteEntry ( ctx , string ( blockedNumber ) , common . DATA_TEMPORARY_VALUE , [ ] byte ( temporaryPin ) )
2024-10-30 12:50:12 +01:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to write temporaryPin entry with" , "key" , common . DATA_TEMPORARY_VALUE , "value" , temporaryPin , "error" , err )
2024-10-30 12:50:12 +01:00
return res , err
}
return res , nil
}
2024-09-16 13:39:01 +02:00
func ( h * Handlers ) ConfirmPinChange ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
var res resource . Result
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
flag_pin_mismatch , _ := h . flagManager . GetFlag ( "flag_pin_mismatch" )
store := h . userdataStore
2024-11-01 04:17:01 +01:00
temporaryPin , err := store . ReadEntry ( ctx , sessionId , common . DATA_TEMPORARY_VALUE )
2024-09-16 13:39:01 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to read temporaryPin entry with" , "key" , common . DATA_TEMPORARY_VALUE , "error" , err )
2024-09-16 13:39:01 +02:00
return res , err
}
if bytes . Equal ( temporaryPin , input ) {
res . FlagReset = append ( res . FlagReset , flag_pin_mismatch )
} else {
res . FlagSet = append ( res . FlagSet , flag_pin_mismatch )
}
2024-10-30 02:28:55 +01:00
err = store . WriteEntry ( ctx , sessionId , common . DATA_ACCOUNT_PIN , [ ] byte ( temporaryPin ) )
2024-09-16 13:39:01 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to write temporaryPin entry with" , "key" , common . DATA_ACCOUNT_PIN , "value" , temporaryPin , "error" , err )
2024-09-16 13:39:01 +02:00
return res , err
}
return res , nil
}
2024-09-28 11:26:37 +02:00
// VerifyCreatePin checks whether the confirmation PIN is similar to the temporary PIN
// If similar, it sets the USERFLAG_PIN_SET flag and writes the account PIN allowing the user
2024-08-28 15:23:52 +02:00
// to access the main menu
2024-09-28 11:26:37 +02:00
func ( h * Handlers ) VerifyCreatePin ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-08-26 14:53:07 +02:00
2024-09-03 18:06:37 +02:00
flag_valid_pin , _ := h . flagManager . GetFlag ( "flag_valid_pin" )
flag_pin_mismatch , _ := h . flagManager . GetFlag ( "flag_pin_mismatch" )
flag_pin_set , _ := h . flagManager . GetFlag ( "flag_pin_set" )
2024-09-02 13:00:02 +02:00
2024-09-05 18:50:02 +02:00
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-09-10 10:23:25 +02:00
store := h . userdataStore
2024-11-01 04:17:01 +01:00
temporaryPin , err := store . ReadEntry ( ctx , sessionId , common . DATA_TEMPORARY_VALUE )
2024-09-09 16:18:07 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to read temporaryPin entry with" , "key" , common . DATA_TEMPORARY_VALUE , "error" , err )
2024-09-09 16:18:07 +02:00
return res , err
}
2024-09-28 11:26:37 +02:00
if bytes . Equal ( input , temporaryPin ) {
2024-09-03 18:06:37 +02:00
res . FlagSet = [ ] uint32 { flag_valid_pin }
res . FlagReset = [ ] uint32 { flag_pin_mismatch }
res . FlagSet = append ( res . FlagSet , flag_pin_set )
2024-08-26 14:53:07 +02:00
} else {
2024-09-03 18:06:37 +02:00
res . FlagSet = [ ] uint32 { flag_pin_mismatch }
2024-08-26 14:53:07 +02:00
}
2024-10-30 02:28:55 +01:00
err = store . WriteEntry ( ctx , sessionId , common . DATA_ACCOUNT_PIN , [ ] byte ( temporaryPin ) )
2024-09-28 11:26:37 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to write temporaryPin entry with" , "key" , common . DATA_ACCOUNT_PIN , "value" , temporaryPin , "error" , err )
2024-09-28 11:26:37 +02:00
return res , err
}
2024-08-26 14:53:07 +02:00
return res , nil
}
2024-08-31 09:21:20 +02:00
// codeFromCtx retrieves language codes from the context that can be used for handling translations
2024-08-26 14:53:07 +02:00
func codeFromCtx ( ctx context . Context ) string {
var code string
if ctx . Value ( "Language" ) != nil {
lang := ctx . Value ( "Language" ) . ( lang . Language )
code = lang . Code
}
return code
}
2024-09-06 08:33:39 +02:00
// SaveFirstname updates the first name in the gdbm with the provided input.
2024-09-05 21:35:51 +02:00
func ( h * Handlers ) SaveFirstname ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-09-06 08:33:39 +02:00
var err error
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-10-31 22:44:15 +01:00
firstName := string ( input )
store := h . userdataStore
flag_allow_update , _ := h . flagManager . GetFlag ( "flag_allow_update" )
allowUpdate := h . st . MatchFlag ( flag_allow_update , true )
if allowUpdate {
2024-11-01 04:17:01 +01:00
temporaryFirstName , _ := store . ReadEntry ( ctx , sessionId , common . DATA_TEMPORARY_VALUE )
err = store . WriteEntry ( ctx , sessionId , common . DATA_FIRST_NAME , [ ] byte ( temporaryFirstName ) )
2024-10-31 22:44:15 +01:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to write firstName entry with" , "key" , common . DATA_FIRST_NAME , "value" , temporaryFirstName , "error" , err )
2024-10-31 22:44:15 +01:00
return res , err
2024-10-22 19:36:58 +02:00
}
2024-10-31 22:44:15 +01:00
} else {
2024-11-01 04:17:01 +01:00
err = store . WriteEntry ( ctx , sessionId , common . DATA_TEMPORARY_VALUE , [ ] byte ( firstName ) )
2024-09-06 08:33:39 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to write temporaryFirstName entry with" , "key" , common . DATA_TEMPORARY_VALUE , "value" , firstName , "error" , err )
2024-09-09 16:18:07 +02:00
return res , err
2024-09-06 08:33:39 +02:00
}
2024-08-26 14:53:07 +02:00
}
return res , nil
}
2024-09-06 08:33:39 +02:00
// SaveFamilyname updates the family name in the gdbm with the provided input.
2024-09-05 21:35:51 +02:00
func ( h * Handlers ) SaveFamilyname ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-09-06 08:33:39 +02:00
var err error
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-10-31 23:58:36 +01:00
2024-10-31 22:44:15 +01:00
store := h . userdataStore
familyName := string ( input )
flag_allow_update , _ := h . flagManager . GetFlag ( "flag_allow_update" )
allowUpdate := h . st . MatchFlag ( flag_allow_update , true )
if allowUpdate {
2024-11-01 04:17:01 +01:00
temporaryFamilyName , _ := store . ReadEntry ( ctx , sessionId , common . DATA_TEMPORARY_VALUE )
err = store . WriteEntry ( ctx , sessionId , common . DATA_FAMILY_NAME , [ ] byte ( temporaryFamilyName ) )
2024-09-09 16:18:07 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to write familyName entry with" , "key" , common . DATA_FAMILY_NAME , "value" , temporaryFamilyName , "error" , err )
2024-09-09 16:18:07 +02:00
return res , err
}
2024-09-06 10:02:33 +02:00
} else {
2024-11-01 04:17:01 +01:00
err = store . WriteEntry ( ctx , sessionId , common . DATA_TEMPORARY_VALUE , [ ] byte ( familyName ) )
2024-10-31 22:44:15 +01:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to write temporaryFamilyName entry with" , "key" , common . DATA_TEMPORARY_VALUE , "value" , familyName , "error" , err )
2024-10-31 22:44:15 +01:00
return res , err
}
2024-08-26 14:53:07 +02:00
}
2024-11-13 17:00:27 +01:00
2024-08-26 14:53:07 +02:00
return res , nil
}
2024-09-06 08:33:39 +02:00
// SaveYOB updates the Year of Birth(YOB) in the gdbm with the provided input.
2024-09-05 21:35:51 +02:00
func ( h * Handlers ) SaveYob ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-09-06 08:33:39 +02:00
var err error
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-10-31 22:44:15 +01:00
yob := string ( input )
store := h . userdataStore
flag_allow_update , _ := h . flagManager . GetFlag ( "flag_allow_update" )
allowUpdate := h . st . MatchFlag ( flag_allow_update , true )
if allowUpdate {
2024-11-01 04:17:01 +01:00
temporaryYob , _ := store . ReadEntry ( ctx , sessionId , common . DATA_TEMPORARY_VALUE )
err = store . WriteEntry ( ctx , sessionId , common . DATA_YOB , [ ] byte ( temporaryYob ) )
2024-10-31 22:44:15 +01:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to write yob entry with" , "key" , common . DATA_TEMPORARY_VALUE , "value" , temporaryYob , "error" , err )
2024-10-31 22:44:15 +01:00
return res , err
}
} else {
2024-11-01 04:17:01 +01:00
err = store . WriteEntry ( ctx , sessionId , common . DATA_TEMPORARY_VALUE , [ ] byte ( yob ) )
2024-09-06 08:33:39 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to write temporaryYob entry with" , "key" , common . DATA_TEMPORARY_VALUE , "value" , yob , "error" , err )
2024-09-09 16:18:07 +02:00
return res , err
2024-09-06 08:33:39 +02:00
}
2024-08-26 14:53:07 +02:00
}
return res , nil
}
2024-09-06 08:33:39 +02:00
// SaveLocation updates the location in the gdbm with the provided input.
2024-09-05 21:35:51 +02:00
func ( h * Handlers ) SaveLocation ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-09-06 08:33:39 +02:00
var err error
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-10-31 22:44:15 +01:00
location := string ( input )
store := h . userdataStore
flag_allow_update , _ := h . flagManager . GetFlag ( "flag_allow_update" )
allowUpdate := h . st . MatchFlag ( flag_allow_update , true )
if allowUpdate {
2024-11-01 04:17:01 +01:00
temporaryLocation , _ := store . ReadEntry ( ctx , sessionId , common . DATA_TEMPORARY_VALUE )
err = store . WriteEntry ( ctx , sessionId , common . DATA_LOCATION , [ ] byte ( temporaryLocation ) )
2024-10-31 22:44:15 +01:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to write location entry with" , "key" , common . DATA_LOCATION , "value" , temporaryLocation , "error" , err )
2024-10-31 22:44:15 +01:00
return res , err
2024-10-22 19:36:58 +02:00
}
2024-10-31 22:44:15 +01:00
} else {
2024-11-01 04:17:01 +01:00
err = store . WriteEntry ( ctx , sessionId , common . DATA_TEMPORARY_VALUE , [ ] byte ( location ) )
2024-09-06 08:33:39 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to write temporaryLocation entry with" , "key" , common . DATA_TEMPORARY_VALUE , "value" , location , "error" , err )
2024-09-09 16:18:07 +02:00
return res , err
2024-09-06 08:33:39 +02:00
}
2024-08-26 14:53:07 +02:00
}
return res , nil
}
2024-09-06 08:33:39 +02:00
// SaveGender updates the gender in the gdbm with the provided input.
2024-08-26 14:53:07 +02:00
func ( h * Handlers ) SaveGender ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-24 08:01:19 +02:00
symbol , _ := h . st . Where ( )
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-09-06 08:33:39 +02:00
var err error
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-09-24 08:01:19 +02:00
gender := strings . Split ( symbol , "_" ) [ 1 ]
store := h . userdataStore
2024-10-31 22:44:15 +01:00
flag_allow_update , _ := h . flagManager . GetFlag ( "flag_allow_update" )
allowUpdate := h . st . MatchFlag ( flag_allow_update , true )
if allowUpdate {
2024-11-01 04:17:01 +01:00
temporaryGender , _ := store . ReadEntry ( ctx , sessionId , common . DATA_TEMPORARY_VALUE )
err = store . WriteEntry ( ctx , sessionId , common . DATA_GENDER , [ ] byte ( temporaryGender ) )
2024-10-31 22:44:15 +01:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to write gender entry with" , "key" , common . DATA_GENDER , "value" , gender , "error" , err )
2024-10-31 22:44:15 +01:00
return res , err
}
} else {
2024-11-01 04:17:01 +01:00
err = store . WriteEntry ( ctx , sessionId , common . DATA_TEMPORARY_VALUE , [ ] byte ( gender ) )
2024-10-31 22:44:15 +01:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to write temporaryGender entry with" , "key" , common . DATA_TEMPORARY_VALUE , "value" , gender , "error" , err )
2024-10-31 22:44:15 +01:00
return res , err
}
2024-08-26 14:53:07 +02:00
}
2024-09-06 08:33:39 +02:00
2024-08-26 14:53:07 +02:00
return res , nil
}
2024-09-06 08:33:39 +02:00
// SaveOfferings updates the offerings(goods and services provided by the user) in the gdbm with the provided input.
2024-08-26 14:53:07 +02:00
func ( h * Handlers ) SaveOfferings ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-09-06 08:33:39 +02:00
var err error
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-10-31 23:58:36 +01:00
2024-10-31 22:44:15 +01:00
offerings := string ( input )
store := h . userdataStore
flag_allow_update , _ := h . flagManager . GetFlag ( "flag_allow_update" )
allowUpdate := h . st . MatchFlag ( flag_allow_update , true )
if allowUpdate {
2024-11-01 04:17:01 +01:00
temporaryOfferings , _ := store . ReadEntry ( ctx , sessionId , common . DATA_TEMPORARY_VALUE )
err = store . WriteEntry ( ctx , sessionId , common . DATA_OFFERINGS , [ ] byte ( temporaryOfferings ) )
2024-09-06 08:33:39 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to write offerings entry with" , "key" , common . DATA_TEMPORARY_VALUE , "value" , offerings , "error" , err )
2024-10-31 22:44:15 +01:00
return res , err
}
} else {
2024-11-01 04:17:01 +01:00
err = store . WriteEntry ( ctx , sessionId , common . DATA_TEMPORARY_VALUE , [ ] byte ( offerings ) )
2024-09-06 08:33:39 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to write temporaryOfferings entry with" , "key" , common . DATA_TEMPORARY_VALUE , "value" , offerings , "error" , err )
2024-10-31 22:44:15 +01:00
return res , err
2024-09-06 08:33:39 +02:00
}
2024-08-26 14:53:07 +02:00
}
2024-09-06 08:33:39 +02:00
2024-08-26 14:53:07 +02:00
return res , nil
}
2024-08-29 22:15:58 +02:00
// ResetAllowUpdate resets the allowupdate flag that allows a user to update profile data.
func ( h * Handlers ) ResetAllowUpdate ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-09-03 18:06:37 +02:00
flag_allow_update , _ := h . flagManager . GetFlag ( "flag_allow_update" )
res . FlagReset = append ( res . FlagReset , flag_allow_update )
2024-08-26 14:53:07 +02:00
return res , nil
}
2024-10-28 14:37:23 +01:00
// ResetAllowUpdate resets the allowupdate flag that allows a user to update profile data.
func ( h * Handlers ) ResetValidPin ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
var res resource . Result
flag_valid_pin , _ := h . flagManager . GetFlag ( "flag_valid_pin" )
res . FlagReset = append ( res . FlagReset , flag_valid_pin )
return res , nil
}
2024-08-29 22:15:58 +02:00
// ResetAccountAuthorized resets the account authorization flag after a successful PIN entry.
func ( h * Handlers ) ResetAccountAuthorized ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-09-03 18:06:37 +02:00
flag_account_authorized , _ := h . flagManager . GetFlag ( "flag_account_authorized" )
res . FlagReset = append ( res . FlagReset , flag_account_authorized )
2024-08-26 14:53:07 +02:00
return res , nil
}
2024-08-28 15:23:52 +02:00
// CheckIdentifier retrieves the PublicKey from the JSON data file.
2024-08-26 14:53:07 +02:00
func ( h * Handlers ) CheckIdentifier ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-09-06 08:33:39 +02:00
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-09-09 16:18:07 +02:00
store := h . userdataStore
2024-10-30 02:28:55 +01:00
publicKey , _ := store . ReadEntry ( ctx , sessionId , common . DATA_PUBLIC_KEY )
2024-09-06 08:33:39 +02:00
res . Content = string ( publicKey )
2024-08-26 14:53:07 +02:00
return res , nil
}
2024-08-29 22:15:58 +02:00
// Authorize attempts to unlock the next sequential nodes by verifying the provided PIN against the already set PIN.
2024-08-28 11:19:38 +02:00
// It sets the required flags that control the flow.
2024-08-29 22:15:58 +02:00
func ( h * Handlers ) Authorize ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
var err error
2024-09-05 19:30:28 +02:00
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-09-06 08:33:39 +02:00
flag_incorrect_pin , _ := h . flagManager . GetFlag ( "flag_incorrect_pin" )
flag_account_authorized , _ := h . flagManager . GetFlag ( "flag_account_authorized" )
flag_allow_update , _ := h . flagManager . GetFlag ( "flag_allow_update" )
2024-09-09 16:18:07 +02:00
store := h . userdataStore
2024-10-30 02:28:55 +01:00
AccountPin , err := store . ReadEntry ( ctx , sessionId , common . DATA_ACCOUNT_PIN )
2024-09-09 16:18:07 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to read AccountPin entry with" , "key" , common . DATA_ACCOUNT_PIN , "error" , err )
2024-09-09 16:18:07 +02:00
return res , err
}
2024-09-16 13:39:01 +02:00
if len ( input ) == 4 {
if bytes . Equal ( input , AccountPin ) {
if h . st . MatchFlag ( flag_account_authorized , false ) {
res . FlagReset = append ( res . FlagReset , flag_incorrect_pin )
res . FlagSet = append ( res . FlagSet , flag_allow_update , flag_account_authorized )
2024-09-05 19:30:28 +02:00
} else {
2024-09-16 13:39:01 +02:00
res . FlagSet = append ( res . FlagSet , flag_allow_update )
2024-09-05 19:30:28 +02:00
res . FlagReset = append ( res . FlagReset , flag_account_authorized )
}
2024-09-16 13:39:01 +02:00
} else {
res . FlagSet = append ( res . FlagSet , flag_incorrect_pin )
res . FlagReset = append ( res . FlagReset , flag_account_authorized )
return res , nil
2024-09-05 19:30:28 +02:00
}
} else {
return res , nil
}
2024-08-26 14:53:07 +02:00
return res , nil
}
2024-08-29 22:15:58 +02:00
// ResetIncorrectPin resets the incorrect pin flag after a new PIN attempt.
2024-08-26 14:53:07 +02:00
func ( h * Handlers ) ResetIncorrectPin ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-09-03 18:06:37 +02:00
flag_incorrect_pin , _ := h . flagManager . GetFlag ( "flag_incorrect_pin" )
res . FlagReset = append ( res . FlagReset , flag_incorrect_pin )
2024-08-26 14:53:07 +02:00
return res , nil
}
2024-08-28 15:23:52 +02:00
// CheckAccountStatus queries the API using the TrackingId and sets flags
// based on the account status
2024-08-26 14:53:07 +02:00
func ( h * Handlers ) CheckAccountStatus ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-08-26 14:53:07 +02:00
2024-09-03 18:06:37 +02:00
flag_account_success , _ := h . flagManager . GetFlag ( "flag_account_success" )
flag_account_pending , _ := h . flagManager . GetFlag ( "flag_account_pending" )
2024-10-15 12:57:05 +02:00
flag_api_error , _ := h . flagManager . GetFlag ( "flag_api_call_error" )
2024-09-03 18:06:37 +02:00
2024-09-05 16:07:20 +02:00
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
2024-08-26 14:53:07 +02:00
}
2024-10-29 12:28:58 +01:00
2024-09-10 10:23:25 +02:00
store := h . userdataStore
2024-10-30 02:28:55 +01:00
publicKey , err := store . ReadEntry ( ctx , sessionId , common . DATA_PUBLIC_KEY )
2024-09-09 16:18:07 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to read publicKey entry with" , "key" , common . DATA_PUBLIC_KEY , "error" , err )
2024-09-09 16:18:07 +02:00
return res , err
}
2024-10-28 14:37:23 +01:00
2024-11-13 17:00:27 +01:00
r , err := h . accountService . TrackAccountStatus ( ctx , string ( publicKey ) )
2024-08-26 14:53:07 +02:00
if err != nil {
2024-10-15 12:57:05 +02:00
res . FlagSet = append ( res . FlagSet , flag_api_error )
2024-11-14 18:10:48 +01:00
logg . ErrorCtxf ( ctx , "failed on TrackAccountStatus" , "error" , err )
2024-10-15 12:57:05 +02:00
return res , err
}
2024-11-13 17:00:27 +01:00
2024-10-15 12:57:05 +02:00
res . FlagReset = append ( res . FlagReset , flag_api_error )
2024-11-13 17:00:27 +01:00
2024-10-31 13:15:07 +01:00
if r . Active {
2024-09-03 18:06:37 +02:00
res . FlagSet = append ( res . FlagSet , flag_account_success )
res . FlagReset = append ( res . FlagReset , flag_account_pending )
2024-08-26 14:53:07 +02:00
} else {
2024-09-03 18:06:37 +02:00
res . FlagReset = append ( res . FlagReset , flag_account_success )
res . FlagSet = append ( res . FlagSet , flag_account_pending )
2024-08-26 14:53:07 +02:00
}
2024-11-13 17:00:27 +01:00
2024-08-26 14:53:07 +02:00
return res , nil
}
2024-08-28 15:23:52 +02:00
// Quit displays the Thank you message and exits the menu
2024-08-26 14:53:07 +02:00
func ( h * Handlers ) Quit ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-08-29 22:05:41 +02:00
2024-09-03 18:06:37 +02:00
flag_account_authorized , _ := h . flagManager . GetFlag ( "flag_account_authorized" )
2024-09-02 13:00:02 +02:00
2024-08-29 22:05:41 +02:00
code := codeFromCtx ( ctx )
l := gotext . NewLocale ( translationDir , code )
l . AddDomain ( "default" )
2024-08-31 09:21:20 +02:00
2024-08-29 22:05:41 +02:00
res . Content = l . Get ( "Thank you for using Sarafu. Goodbye!" )
2024-09-03 18:06:37 +02:00
res . FlagReset = append ( res . FlagReset , flag_account_authorized )
2024-08-26 14:53:07 +02:00
return res , nil
}
2024-09-14 19:52:17 +02:00
// QuitWithHelp displays helpline information then exits the menu
func ( h * Handlers ) QuitWithHelp ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
var res resource . Result
flag_account_authorized , _ := h . flagManager . GetFlag ( "flag_account_authorized" )
code := codeFromCtx ( ctx )
l := gotext . NewLocale ( translationDir , code )
l . AddDomain ( "default" )
res . Content = l . Get ( "For more help,please call: 0757628885" )
res . FlagReset = append ( res . FlagReset , flag_account_authorized )
return res , nil
}
2024-08-28 15:23:52 +02:00
// VerifyYob verifies the length of the given input
2024-08-26 14:53:07 +02:00
func ( h * Handlers ) VerifyYob ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
var err error
2024-09-02 13:00:02 +02:00
2024-09-03 18:06:37 +02:00
flag_incorrect_date_format , _ := h . flagManager . GetFlag ( "flag_incorrect_date_format" )
2024-08-26 14:53:07 +02:00
date := string ( input )
2024-09-05 21:35:51 +02:00
_ , err = strconv . Atoi ( date )
2024-08-27 15:16:15 +02:00
if err != nil {
// If conversion fails, input is not numeric
2024-09-03 18:06:37 +02:00
res . FlagSet = append ( res . FlagSet , flag_incorrect_date_format )
2024-08-27 15:16:15 +02:00
return res , nil
}
2024-08-27 13:57:26 +02:00
if len ( date ) == 4 {
2024-09-03 18:06:37 +02:00
res . FlagReset = append ( res . FlagReset , flag_incorrect_date_format )
2024-08-27 13:57:26 +02:00
} else {
2024-09-03 18:06:37 +02:00
res . FlagSet = append ( res . FlagSet , flag_incorrect_date_format )
2024-08-26 14:53:07 +02:00
}
return res , nil
}
2024-09-02 09:03:57 +02:00
// ResetIncorrectYob resets the incorrect date format flag after a new attempt
2024-08-26 14:53:07 +02:00
func ( h * Handlers ) ResetIncorrectYob ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-09-02 13:00:02 +02:00
2024-09-03 18:06:37 +02:00
flag_incorrect_date_format , _ := h . flagManager . GetFlag ( "flag_incorrect_date_format" )
res . FlagReset = append ( res . FlagReset , flag_incorrect_date_format )
2024-08-26 14:53:07 +02:00
return res , nil
}
2024-10-18 17:31:40 +02:00
// CheckBalance retrieves the balance of the active voucher and sets
2024-08-28 15:23:52 +02:00
// the balance as the result content
2024-08-26 14:53:07 +02:00
func ( h * Handlers ) CheckBalance ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
var err error
2024-09-05 18:50:02 +02:00
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-10-24 14:12:57 +02:00
code := codeFromCtx ( ctx )
l := gotext . NewLocale ( translationDir , code )
l . AddDomain ( "default" )
2024-09-10 10:23:25 +02:00
store := h . userdataStore
2024-08-27 10:19:49 +02:00
2024-10-15 14:46:02 +02:00
// get the active sym and active balance
2024-10-30 02:28:55 +01:00
activeSym , err := store . ReadEntry ( ctx , sessionId , common . DATA_ACTIVE_SYM )
2024-09-09 16:18:07 +02:00
if err != nil {
2024-10-23 13:02:13 +02:00
if db . IsNotFound ( err ) {
2024-10-24 15:26:32 +02:00
balance := "0.00"
res . Content = l . Get ( "Balance: %s\n" , balance )
2024-10-23 13:02:13 +02:00
return res , nil
}
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to read activeSym entry with" , "key" , common . DATA_ACTIVE_SYM , "error" , err )
2024-09-09 16:18:07 +02:00
return res , err
}
2024-08-27 10:19:49 +02:00
2024-10-30 02:28:55 +01:00
activeBal , err := store . ReadEntry ( ctx , sessionId , common . DATA_ACTIVE_BAL )
2024-08-26 14:53:07 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to read activeBal entry with" , "key" , common . DATA_ACTIVE_BAL , "error" , err )
2024-10-24 15:26:32 +02:00
return res , err
2024-10-15 12:57:05 +02:00
}
2024-10-24 14:12:57 +02:00
2024-10-24 15:26:32 +02:00
res . Content = l . Get ( "Balance: %s\n" , fmt . Sprintf ( "%s %s" , activeBal , activeSym ) )
2024-08-26 14:53:07 +02:00
return res , nil
}
2024-10-15 12:57:05 +02:00
func ( h * Handlers ) FetchCustodialBalances ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
var res resource . Result
2024-10-31 02:28:37 +01:00
2024-10-15 12:57:05 +02:00
flag_api_error , _ := h . flagManager . GetFlag ( "flag_api_call_error" )
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
symbol , _ := h . st . Where ( )
balanceType := strings . Split ( symbol , "_" ) [ 0 ]
store := h . userdataStore
2024-10-30 02:28:55 +01:00
publicKey , err := store . ReadEntry ( ctx , sessionId , common . DATA_PUBLIC_KEY )
2024-10-15 12:57:05 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to read publicKey entry with" , "key" , common . DATA_PUBLIC_KEY , "error" , err )
2024-10-15 12:57:05 +02:00
return res , err
}
2024-10-24 16:32:08 +02:00
balanceResponse , err := h . accountService . CheckBalance ( ctx , string ( publicKey ) )
2024-10-15 12:57:05 +02:00
if err != nil {
res . FlagSet = append ( res . FlagSet , flag_api_error )
return res , nil
}
res . FlagReset = append ( res . FlagReset , flag_api_error )
2024-10-31 02:28:37 +01:00
balance := balanceResponse . Balance
2024-10-15 12:57:05 +02:00
switch balanceType {
case "my" :
res . Content = fmt . Sprintf ( "Your balance is %s" , balance )
case "community" :
res . Content = fmt . Sprintf ( "Your community balance is %s" , balance )
default :
break
}
return res , nil
}
2024-10-30 12:50:12 +01:00
func ( h * Handlers ) ResetOthersPin ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
var res resource . Result
store := h . userdataStore
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-11-02 16:46:46 +01:00
blockedPhonenumber , err := store . ReadEntry ( ctx , sessionId , common . DATA_BLOCKED_NUMBER )
2024-10-30 12:50:12 +01:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to read blockedPhonenumber entry with" , "key" , common . DATA_BLOCKED_NUMBER , "error" , err )
2024-10-30 12:50:12 +01:00
return res , err
}
2024-11-02 16:46:46 +01:00
temporaryPin , err := store . ReadEntry ( ctx , string ( blockedPhonenumber ) , common . DATA_TEMPORARY_VALUE )
2024-10-30 12:50:12 +01:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to read temporaryPin entry with" , "key" , common . DATA_TEMPORARY_VALUE , "error" , err )
2024-10-30 12:50:12 +01:00
return res , err
}
2024-11-02 16:46:46 +01:00
err = store . WriteEntry ( ctx , string ( blockedPhonenumber ) , common . DATA_ACCOUNT_PIN , [ ] byte ( temporaryPin ) )
2024-10-30 12:50:12 +01:00
if err != nil {
return res , nil
}
2024-11-13 17:00:27 +01:00
2024-10-30 12:50:12 +01:00
return res , nil
}
2024-10-29 15:35:42 +01:00
func ( h * Handlers ) ResetUnregisteredNumber ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
var res resource . Result
flag_unregistered_number , _ := h . flagManager . GetFlag ( "flag_unregistered_number" )
res . FlagReset = append ( res . FlagReset , flag_unregistered_number )
return res , nil
}
2024-10-28 14:37:23 +01:00
func ( h * Handlers ) ValidateBlockedNumber ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
var res resource . Result
var err error
2024-10-29 15:35:42 +01:00
flag_unregistered_number , _ := h . flagManager . GetFlag ( "flag_unregistered_number" )
2024-10-28 14:37:23 +01:00
store := h . userdataStore
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
blockedNumber := string ( input )
2024-11-02 16:46:46 +01:00
_ , err = store . ReadEntry ( ctx , blockedNumber , common . DATA_PUBLIC_KEY )
2024-10-29 20:17:43 +01:00
if ! isValidPhoneNumber ( blockedNumber ) {
2024-10-30 16:01:43 +01:00
res . FlagSet = append ( res . FlagSet , flag_unregistered_number )
2024-10-29 20:17:43 +01:00
return res , nil
}
2024-10-29 15:35:42 +01:00
if err != nil {
if db . IsNotFound ( err ) {
2024-11-13 17:00:27 +01:00
logg . InfoCtxf ( ctx , "Invalid or unregistered number" )
2024-10-29 15:35:42 +01:00
res . FlagSet = append ( res . FlagSet , flag_unregistered_number )
return res , nil
} else {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "Error on ValidateBlockedNumber" , "error" , err )
2024-10-29 15:35:42 +01:00
return res , err
}
}
2024-11-02 16:46:46 +01:00
err = store . WriteEntry ( ctx , sessionId , common . DATA_BLOCKED_NUMBER , [ ] byte ( blockedNumber ) )
2024-10-28 14:37:23 +01:00
if err != nil {
return res , nil
}
return res , nil
}
2024-08-28 15:23:52 +02:00
// ValidateRecipient validates that the given input is a valid phone number.
2024-08-26 14:53:07 +02:00
func ( h * Handlers ) ValidateRecipient ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-11-14 15:30:13 +01:00
var err error
2024-11-14 12:59:39 +01:00
store := h . userdataStore
2024-09-06 08:33:39 +02:00
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-09-06 00:55:51 +02:00
2024-08-26 14:53:07 +02:00
recipient := string ( input )
2024-09-03 18:06:37 +02:00
flag_invalid_recipient , _ := h . flagManager . GetFlag ( "flag_invalid_recipient" )
2024-11-14 12:59:39 +01:00
flag_invalid_recipient_with_invite , _ := h . flagManager . GetFlag ( "flag_invalid_recipient_with_invite" )
2024-08-26 14:53:07 +02:00
if recipient != "0" {
2024-11-14 12:59:39 +01:00
if ! isValidPhoneNumber ( recipient ) {
2024-09-03 18:06:37 +02:00
res . FlagSet = append ( res . FlagSet , flag_invalid_recipient )
2024-08-26 14:53:07 +02:00
res . Content = recipient
return res , nil
}
2024-11-14 12:59:39 +01:00
2024-11-14 15:30:13 +01:00
// save the recipient as the temporaryRecipient
err = store . WriteEntry ( ctx , sessionId , common . DATA_TEMPORARY_VALUE , [ ] byte ( recipient ) )
if err != nil {
logg . ErrorCtxf ( ctx , "failed to write temporaryRecipient entry with" , "key" , common . DATA_TEMPORARY_VALUE , "value" , recipient , "error" , err )
return res , err
}
2024-11-14 12:59:39 +01:00
publicKey , err := store . ReadEntry ( ctx , recipient , common . DATA_PUBLIC_KEY )
2024-09-06 08:33:39 +02:00
if err != nil {
2024-11-14 12:59:39 +01:00
if db . IsNotFound ( err ) {
logg . InfoCtxf ( ctx , "Unregistered number" )
res . FlagSet = append ( res . FlagSet , flag_invalid_recipient_with_invite )
res . Content = recipient
return res , nil
}
logg . ErrorCtxf ( ctx , "failed to read publicKey entry with" , "key" , common . DATA_PUBLIC_KEY , "error" , err )
return res , err
}
err = store . WriteEntry ( ctx , sessionId , common . DATA_RECIPIENT , publicKey )
if err != nil {
logg . ErrorCtxf ( ctx , "failed to write recipient entry with" , "key" , common . DATA_RECIPIENT , "value" , string ( publicKey ) , "error" , err )
2024-09-06 08:33:39 +02:00
return res , nil
}
2024-08-26 14:53:07 +02:00
}
return res , nil
}
2024-08-28 15:23:52 +02:00
// TransactionReset resets the previous transaction data (Recipient and Amount)
// as well as the invalid flags
2024-08-26 14:53:07 +02:00
func ( h * Handlers ) TransactionReset ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-09-06 08:33:39 +02:00
var err error
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-09-02 13:00:02 +02:00
2024-09-03 18:06:37 +02:00
flag_invalid_recipient , _ := h . flagManager . GetFlag ( "flag_invalid_recipient" )
flag_invalid_recipient_with_invite , _ := h . flagManager . GetFlag ( "flag_invalid_recipient_with_invite" )
2024-09-09 16:18:07 +02:00
store := h . userdataStore
2024-10-30 02:28:55 +01:00
err = store . WriteEntry ( ctx , sessionId , common . DATA_AMOUNT , [ ] byte ( "" ) )
2024-09-06 08:33:39 +02:00
if err != nil {
return res , nil
}
2024-10-30 02:28:55 +01:00
err = store . WriteEntry ( ctx , sessionId , common . DATA_RECIPIENT , [ ] byte ( "" ) )
2024-09-06 08:33:39 +02:00
if err != nil {
return res , nil
}
2024-08-26 14:53:07 +02:00
2024-09-03 18:06:37 +02:00
res . FlagReset = append ( res . FlagReset , flag_invalid_recipient , flag_invalid_recipient_with_invite )
2024-08-26 14:53:07 +02:00
return res , nil
}
2024-11-14 12:59:39 +01:00
// InviteValidRecipient sends an invitation to the valid phone number.
func ( h * Handlers ) InviteValidRecipient ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
var res resource . Result
store := h . userdataStore
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
code := codeFromCtx ( ctx )
l := gotext . NewLocale ( translationDir , code )
l . AddDomain ( "default" )
recipient , _ := store . ReadEntry ( ctx , sessionId , common . DATA_TEMPORARY_VALUE )
// TODO
// send an invitation SMS
// if successful
// res.Content = l.Get("Your invitation to %s to join Sarafu Network has been sent.", string(recipient))
res . Content = l . Get ( "Your invite request for %s to Sarafu Network failed. Please try again later." , string ( recipient ) )
return res , nil
}
2024-08-28 15:23:52 +02:00
// ResetTransactionAmount resets the transaction amount and invalid flag
2024-08-26 14:53:07 +02:00
func ( h * Handlers ) ResetTransactionAmount ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-09-06 08:33:39 +02:00
var err error
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-09-02 13:00:02 +02:00
2024-09-03 18:06:37 +02:00
flag_invalid_amount , _ := h . flagManager . GetFlag ( "flag_invalid_amount" )
2024-09-09 16:18:07 +02:00
store := h . userdataStore
2024-10-30 02:28:55 +01:00
err = store . WriteEntry ( ctx , sessionId , common . DATA_AMOUNT , [ ] byte ( "" ) )
2024-09-06 08:33:39 +02:00
if err != nil {
return res , nil
}
2024-08-26 14:53:07 +02:00
2024-09-03 18:06:37 +02:00
res . FlagReset = append ( res . FlagReset , flag_invalid_amount )
2024-08-26 14:53:07 +02:00
return res , nil
}
2024-08-29 22:15:58 +02:00
// MaxAmount gets the current balance from the API and sets it as
2024-08-28 15:23:52 +02:00
// the result content.
2024-08-26 14:53:07 +02:00
func ( h * Handlers ) MaxAmount ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
var err error
2024-09-06 08:33:39 +02:00
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-09-09 16:18:07 +02:00
store := h . userdataStore
2024-08-27 15:10:43 +02:00
2024-10-30 02:28:55 +01:00
activeBal , err := store . ReadEntry ( ctx , sessionId , common . DATA_ACTIVE_BAL )
2024-08-27 15:10:43 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to read activeBal entry with" , "key" , common . DATA_ACTIVE_BAL , "error" , err )
2024-10-24 16:50:37 +02:00
return res , err
2024-08-27 15:10:43 +02:00
}
2024-10-24 16:50:37 +02:00
res . Content = string ( activeBal )
2024-08-26 14:53:07 +02:00
return res , nil
}
2024-08-28 15:23:52 +02:00
// ValidateAmount ensures that the given input is a valid amount and that
// it is not more than the current balance.
2024-08-26 14:53:07 +02:00
func ( h * Handlers ) ValidateAmount ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-09-03 18:06:37 +02:00
2024-09-06 08:33:39 +02:00
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-09-03 18:06:37 +02:00
flag_invalid_amount , _ := h . flagManager . GetFlag ( "flag_invalid_amount" )
2024-09-14 19:01:58 +02:00
store := h . userdataStore
2024-08-27 15:16:15 +02:00
2024-10-15 15:17:33 +02:00
var balanceValue float64
2024-09-02 15:30:58 +02:00
2024-10-15 15:17:33 +02:00
// retrieve the active balance
2024-10-30 02:28:55 +01:00
activeBal , err := store . ReadEntry ( ctx , sessionId , common . DATA_ACTIVE_BAL )
2024-08-27 15:16:15 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to read activeBal entry with" , "key" , common . DATA_ACTIVE_BAL , "error" , err )
2024-08-27 15:16:15 +02:00
return res , err
}
2024-10-15 15:17:33 +02:00
balanceValue , err = strconv . ParseFloat ( string ( activeBal ) , 64 )
2024-08-27 15:16:15 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "Failed to convert the activeBal to a float" , "error" , err )
2024-10-15 15:17:33 +02:00
return res , err
2024-08-27 15:16:15 +02:00
}
2024-10-12 19:07:06 +02:00
// Extract numeric part from the input amount
amountStr := strings . TrimSpace ( string ( input ) )
inputAmount , err := strconv . ParseFloat ( amountStr , 64 )
2024-08-27 15:16:15 +02:00
if err != nil {
2024-09-03 18:06:37 +02:00
res . FlagSet = append ( res . FlagSet , flag_invalid_amount )
2024-08-27 15:16:15 +02:00
res . Content = amountStr
return res , nil
}
if inputAmount > balanceValue {
2024-09-03 18:06:37 +02:00
res . FlagSet = append ( res . FlagSet , flag_invalid_amount )
2024-08-27 15:16:15 +02:00
res . Content = amountStr
return res , nil
}
2024-10-24 16:50:37 +02:00
// Format the amount with 2 decimal places before saving
formattedAmount := fmt . Sprintf ( "%.2f" , inputAmount )
2024-10-30 02:28:55 +01:00
err = store . WriteEntry ( ctx , sessionId , common . DATA_AMOUNT , [ ] byte ( formattedAmount ) )
2024-08-27 15:16:15 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to write amount entry with" , "key" , common . DATA_AMOUNT , "value" , formattedAmount , "error" , err )
2024-08-27 15:16:15 +02:00
return res , err
}
2024-11-13 17:00:27 +01:00
res . Content = formattedAmount
2024-08-27 15:16:15 +02:00
return res , nil
}
2024-08-28 15:23:52 +02:00
2024-11-14 15:30:13 +01:00
// GetRecipient returns the transaction recipient phone number from the gdbm.
2024-08-26 14:53:07 +02:00
func ( h * Handlers ) GetRecipient ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-09-06 08:33:39 +02:00
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-09-09 16:18:07 +02:00
store := h . userdataStore
2024-11-14 15:30:13 +01:00
recipient , _ := store . ReadEntry ( ctx , sessionId , common . DATA_TEMPORARY_VALUE )
2024-08-26 14:53:07 +02:00
2024-09-06 08:33:39 +02:00
res . Content = string ( recipient )
2024-08-26 14:53:07 +02:00
return res , nil
}
2024-10-28 14:37:23 +01:00
// RetrieveBlockedNumber gets the current number during the pin reset for other's is in progress.
func ( h * Handlers ) RetrieveBlockedNumber ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
var res resource . Result
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
store := h . userdataStore
2024-11-02 16:46:46 +01:00
blockedNumber , _ := store . ReadEntry ( ctx , sessionId , common . DATA_BLOCKED_NUMBER )
2024-10-28 14:37:23 +01:00
res . Content = string ( blockedNumber )
return res , nil
}
2024-10-24 13:34:12 +02:00
// GetSender returns the sessionId (phoneNumber)
2024-08-26 14:53:07 +02:00
func ( h * Handlers ) GetSender ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-09-06 08:33:39 +02:00
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-10-24 13:34:12 +02:00
res . Content = string ( sessionId )
2024-08-26 14:53:07 +02:00
return res , nil
}
2024-09-03 16:59:03 +02:00
// GetAmount retrieves the amount from teh Gdbm Db
2024-08-28 13:11:20 +02:00
func ( h * Handlers ) GetAmount ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-09-06 08:33:39 +02:00
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-09-09 16:18:07 +02:00
store := h . userdataStore
2024-10-24 16:50:37 +02:00
// retrieve the active symbol
2024-10-30 02:28:55 +01:00
activeSym , err := store . ReadEntry ( ctx , sessionId , common . DATA_ACTIVE_SYM )
2024-10-24 16:50:37 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to read activeSym entry with" , "key" , common . DATA_ACTIVE_SYM , "error" , err )
2024-10-24 16:50:37 +02:00
return res , err
}
2024-10-30 02:28:55 +01:00
amount , _ := store . ReadEntry ( ctx , sessionId , common . DATA_AMOUNT )
2024-09-06 08:33:39 +02:00
2024-10-24 16:50:37 +02:00
res . Content = fmt . Sprintf ( "%s %s" , string ( amount ) , string ( activeSym ) )
2024-08-28 13:11:20 +02:00
return res , nil
}
2024-08-28 15:23:52 +02:00
// InitiateTransaction returns a confirmation and resets the transaction data
2024-09-06 08:33:39 +02:00
// on the gdbm store.
2024-08-28 13:11:20 +02:00
func ( h * Handlers ) InitiateTransaction ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
var err error
2024-09-06 08:33:39 +02:00
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-09-06 00:55:51 +02:00
2024-11-14 18:10:48 +01:00
flag_api_error , _ := h . flagManager . GetFlag ( "flag_api_call_error" )
account_authorized_flag , _ := h . flagManager . GetFlag ( "flag_account_authorized" )
2024-08-28 17:26:41 +02:00
code := codeFromCtx ( ctx )
l := gotext . NewLocale ( translationDir , code )
l . AddDomain ( "default" )
2024-11-14 18:10:48 +01:00
2024-09-09 16:18:07 +02:00
store := h . userdataStore
2024-11-14 18:10:48 +01:00
recipientNumber , _ := store . ReadEntry ( ctx , sessionId , common . DATA_TEMPORARY_VALUE )
2024-10-30 02:28:55 +01:00
activeSym , _ := store . ReadEntry ( ctx , sessionId , common . DATA_ACTIVE_SYM )
2024-10-24 16:50:37 +02:00
2024-11-14 18:10:48 +01:00
storedAmount , _ := store . ReadEntry ( ctx , sessionId , common . DATA_AMOUNT )
fromAddress , _ := store . ReadEntry ( ctx , sessionId , common . DATA_PUBLIC_KEY )
toAddress , _ := store . ReadEntry ( ctx , sessionId , common . DATA_RECIPIENT )
activeDecimal , _ := store . ReadEntry ( ctx , sessionId , common . DATA_ACTIVE_DECIMAL )
tokenAddress , _ := store . ReadEntry ( ctx , sessionId , common . DATA_ACTIVE_ADDRESS )
// Parse tokendecimal
tokenDecimal , err := strconv . Atoi ( string ( activeDecimal ) )
if err != nil {
return res , err
}
// Parse amount and scale it
amount , _ , err := big . ParseFloat ( string ( storedAmount ) , 10 , 0 , big . ToZero )
if err != nil {
return res , err
}
multiplier := new ( big . Float ) . SetInt ( new ( big . Int ) . Exp ( big . NewInt ( 10 ) , big . NewInt ( int64 ( tokenDecimal ) ) , nil ) )
finalAmount := new ( big . Float ) . Mul ( amount , multiplier )
2024-08-28 13:54:39 +02:00
2024-11-14 18:10:48 +01:00
// Convert finalAmount to a string
finalAmountStr := new ( big . Int )
finalAmount . Int ( finalAmountStr )
// Call TokenTransfer
r , err := h . accountService . TokenTransfer ( ctx , finalAmountStr . String ( ) , string ( fromAddress ) , string ( toAddress ) , string ( tokenAddress ) )
2024-08-31 16:16:57 +02:00
if err != nil {
2024-11-14 18:10:48 +01:00
res . Content = l . Get ( "Your request failed. Please try again later." )
res . FlagSet = append ( res . FlagSet , flag_api_error )
logg . ErrorCtxf ( ctx , "failed on TokenTransfer" , "error" , err )
2024-09-03 18:06:37 +02:00
return res , err
2024-08-31 16:16:57 +02:00
}
2024-11-14 18:10:48 +01:00
trackingId := r . TrackingId
logg . InfoCtxf ( ctx , "TokenTransfer" , "trackingId" , trackingId )
res . Content = l . Get ( "Your request has been sent. %s will receive %s %s from %s." , string ( recipientNumber ) , string ( storedAmount ) , string ( activeSym ) , string ( sessionId ) )
2024-09-03 14:02:31 +02:00
res . FlagReset = append ( res . FlagReset , account_authorized_flag )
2024-08-28 13:11:20 +02:00
return res , nil
}
2024-09-02 20:09:39 +02:00
2024-11-07 10:02:03 +01:00
func ( h * Handlers ) GetCurrentProfileInfo ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
var res resource . Result
var profileInfo [ ] byte
var err error
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
sm , _ := h . st . Where ( )
parts := strings . SplitN ( sm , "_" , 2 )
filename := parts [ 1 ]
dbKeyStr := "DATA_" + strings . ToUpper ( filename )
dbKey , err := common . StringToDataTyp ( dbKeyStr )
if err != nil {
return res , err
}
store := h . userdataStore
switch dbKey {
case common . DATA_FIRST_NAME :
profileInfo , err = store . ReadEntry ( ctx , sessionId , common . DATA_FIRST_NAME )
if err != nil {
if db . IsNotFound ( err ) {
2024-11-08 15:19:41 +01:00
res . Content = "Not provided"
2024-11-07 10:02:03 +01:00
break
}
2024-11-14 09:00:12 +01:00
logg . ErrorCtxf ( ctx , "Failed to read first name entry with" , "key" , "error" , common . DATA_FIRST_NAME , err )
2024-11-07 10:02:03 +01:00
return res , err
}
res . Content = string ( profileInfo )
case common . DATA_FAMILY_NAME :
profileInfo , err = store . ReadEntry ( ctx , sessionId , common . DATA_FAMILY_NAME )
if err != nil {
if db . IsNotFound ( err ) {
2024-11-08 15:19:41 +01:00
res . Content = "Not provided"
2024-11-07 10:02:03 +01:00
break
}
2024-11-14 09:00:12 +01:00
logg . ErrorCtxf ( ctx , "Failed to read family name entry with" , "key" , "error" , common . DATA_FAMILY_NAME , err )
2024-11-07 10:02:03 +01:00
return res , err
}
res . Content = string ( profileInfo )
case common . DATA_GENDER :
profileInfo , err = store . ReadEntry ( ctx , sessionId , common . DATA_GENDER )
if err != nil {
if db . IsNotFound ( err ) {
2024-11-08 15:19:41 +01:00
res . Content = "Not provided"
2024-11-07 10:02:03 +01:00
break
}
2024-11-14 09:00:12 +01:00
logg . ErrorCtxf ( ctx , "Failed to read gender entry with" , "key" , "error" , common . DATA_GENDER , err )
2024-11-07 10:02:03 +01:00
return res , err
}
res . Content = string ( profileInfo )
case common . DATA_YOB :
profileInfo , err = store . ReadEntry ( ctx , sessionId , common . DATA_YOB )
if err != nil {
if db . IsNotFound ( err ) {
2024-11-08 15:19:41 +01:00
res . Content = "Not provided"
2024-11-07 10:02:03 +01:00
break
}
2024-11-14 09:00:12 +01:00
logg . ErrorCtxf ( ctx , "Failed to read year of birth(yob) entry with" , "key" , "error" , common . DATA_YOB , err )
2024-11-07 10:02:03 +01:00
return res , err
}
res . Content = string ( profileInfo )
case common . DATA_LOCATION :
profileInfo , err = store . ReadEntry ( ctx , sessionId , common . DATA_LOCATION )
if err != nil {
if db . IsNotFound ( err ) {
2024-11-08 15:19:41 +01:00
res . Content = "Not provided"
2024-11-07 10:02:03 +01:00
break
}
2024-11-14 09:00:12 +01:00
logg . ErrorCtxf ( ctx , "Failed to read location entry with" , "key" , "error" , common . DATA_LOCATION , err )
2024-11-07 10:02:03 +01:00
return res , err
}
res . Content = string ( profileInfo )
case common . DATA_OFFERINGS :
profileInfo , err = store . ReadEntry ( ctx , sessionId , common . DATA_OFFERINGS )
if err != nil {
if db . IsNotFound ( err ) {
2024-11-08 15:19:41 +01:00
res . Content = "Not provided"
2024-11-07 10:02:03 +01:00
break
}
2024-11-14 09:00:12 +01:00
logg . ErrorCtxf ( ctx , "Failed to read offerings entry with" , "key" , "error" , common . DATA_OFFERINGS , err )
2024-11-07 10:02:03 +01:00
return res , err
}
res . Content = string ( profileInfo )
default :
break
}
return res , nil
}
2024-09-02 20:09:39 +02:00
func ( h * Handlers ) GetProfileInfo ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
2024-09-06 00:55:51 +02:00
var res resource . Result
2024-10-15 12:57:05 +02:00
var defaultValue string
2024-09-06 15:17:26 +02:00
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-10-15 12:57:05 +02:00
language , ok := ctx . Value ( "Language" ) . ( lang . Language )
if ! ok {
return res , fmt . Errorf ( "value for 'Language' is not of type lang.Language" )
}
code := language . Code
if code == "swa" {
defaultValue = "Haipo"
} else {
defaultValue = "Not Provided"
}
2024-09-06 15:17:26 +02:00
// Helper function to handle nil byte slices and convert them to string
getEntryOrDefault := func ( entry [ ] byte , err error ) string {
if err != nil || entry == nil {
return defaultValue
}
return string ( entry )
}
2024-09-09 16:18:07 +02:00
store := h . userdataStore
2024-09-06 15:17:26 +02:00
// Retrieve user data as strings with fallback to defaultValue
2024-10-30 02:28:55 +01:00
firstName := getEntryOrDefault ( store . ReadEntry ( ctx , sessionId , common . DATA_FIRST_NAME ) )
familyName := getEntryOrDefault ( store . ReadEntry ( ctx , sessionId , common . DATA_FAMILY_NAME ) )
yob := getEntryOrDefault ( store . ReadEntry ( ctx , sessionId , common . DATA_YOB ) )
gender := getEntryOrDefault ( store . ReadEntry ( ctx , sessionId , common . DATA_GENDER ) )
location := getEntryOrDefault ( store . ReadEntry ( ctx , sessionId , common . DATA_LOCATION ) )
offerings := getEntryOrDefault ( store . ReadEntry ( ctx , sessionId , common . DATA_OFFERINGS ) )
2024-09-02 20:09:39 +02:00
// Construct the full name
2024-09-06 15:17:26 +02:00
name := defaultValue
2024-09-02 20:09:39 +02:00
if familyName != defaultValue {
2024-09-06 15:17:26 +02:00
if firstName == defaultValue {
2024-09-02 20:09:39 +02:00
name = familyName
} else {
2024-09-06 15:17:26 +02:00
name = firstName + " " + familyName
2024-09-02 20:09:39 +02:00
}
}
// Calculate age from year of birth
2024-09-06 15:17:26 +02:00
age := defaultValue
2024-09-02 20:09:39 +02:00
if yob != defaultValue {
2024-09-06 15:17:26 +02:00
if yobInt , err := strconv . Atoi ( yob ) ; err == nil {
age = strconv . Itoa ( utils . CalculateAgeWithYOB ( yobInt ) )
} else {
2024-09-02 20:09:39 +02:00
return res , fmt . Errorf ( "invalid year of birth: %v" , err )
}
}
2024-10-15 12:57:05 +02:00
switch language . Code {
case "eng" :
res . Content = fmt . Sprintf (
"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n" ,
name , gender , age , location , offerings ,
)
case "swa" :
res . Content = fmt . Sprintf (
"Jina: %s\nJinsia: %s\nUmri: %s\nEneo: %s\nUnauza: %s\n" ,
name , gender , age , location , offerings ,
)
default :
res . Content = fmt . Sprintf (
"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n" ,
name , gender , age , location , offerings ,
)
}
2024-09-06 15:17:26 +02:00
2024-09-02 20:09:39 +02:00
return res , nil
}
2024-10-05 15:56:49 +02:00
2024-10-15 14:46:02 +02:00
// SetDefaultVoucher retrieves the current vouchers
// and sets the first as the default voucher, if no active voucher is set
func ( h * Handlers ) SetDefaultVoucher ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
var res resource . Result
var err error
store := h . userdataStore
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-10-18 17:31:40 +02:00
flag_no_active_voucher , _ := h . flagManager . GetFlag ( "flag_no_active_voucher" )
2024-10-15 14:46:02 +02:00
// check if the user has an active sym
2024-10-30 02:28:55 +01:00
_ , err = store . ReadEntry ( ctx , sessionId , common . DATA_ACTIVE_SYM )
2024-10-15 14:46:02 +02:00
if err != nil {
if db . IsNotFound ( err ) {
2024-10-30 02:28:55 +01:00
publicKey , err := store . ReadEntry ( ctx , sessionId , common . DATA_PUBLIC_KEY )
2024-10-15 14:46:02 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to read publicKey entry with" , "key" , common . DATA_PUBLIC_KEY , "error" , err )
2024-10-30 16:30:55 +01:00
return res , err
2024-10-15 14:46:02 +02:00
}
// Fetch vouchers from the API using the public key
2024-10-24 19:44:29 +02:00
vouchersResp , err := h . accountService . FetchVouchers ( ctx , string ( publicKey ) )
2024-10-15 14:46:02 +02:00
if err != nil {
2024-11-04 15:56:25 +01:00
res . FlagSet = append ( res . FlagSet , flag_no_active_voucher )
return res , nil
2024-10-15 14:46:02 +02:00
}
2024-10-18 17:31:40 +02:00
// Return if there is no voucher
2024-10-31 02:28:37 +01:00
if len ( vouchersResp ) == 0 {
2024-10-18 17:31:40 +02:00
res . FlagSet = append ( res . FlagSet , flag_no_active_voucher )
return res , nil
2024-10-15 14:46:02 +02:00
}
// Use only the first voucher
2024-10-31 02:28:37 +01:00
firstVoucher := vouchersResp [ 0 ]
2024-10-15 14:46:02 +02:00
defaultSym := firstVoucher . TokenSymbol
defaultBal := firstVoucher . Balance
2024-11-14 15:31:17 +01:00
defaultDec := firstVoucher . TokenDecimals
defaultAddr := firstVoucher . ContractAddress
2024-10-15 14:46:02 +02:00
// set the active symbol
2024-10-30 02:28:55 +01:00
err = store . WriteEntry ( ctx , sessionId , common . DATA_ACTIVE_SYM , [ ] byte ( defaultSym ) )
2024-10-15 14:46:02 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to write defaultSym entry with" , "key" , common . DATA_ACTIVE_SYM , "value" , defaultSym , "error" , err )
2024-10-15 14:46:02 +02:00
return res , err
}
// set the active balance
2024-10-30 02:28:55 +01:00
err = store . WriteEntry ( ctx , sessionId , common . DATA_ACTIVE_BAL , [ ] byte ( defaultBal ) )
2024-10-15 14:46:02 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to write defaultBal entry with" , "key" , common . DATA_ACTIVE_BAL , "value" , defaultBal , "error" , err )
2024-10-15 14:46:02 +02:00
return res , err
}
2024-11-14 15:31:17 +01:00
// set the active decimals
err = store . WriteEntry ( ctx , sessionId , common . DATA_ACTIVE_DECIMAL , [ ] byte ( defaultDec ) )
if err != nil {
logg . ErrorCtxf ( ctx , "failed to write defaultDec entry with" , "key" , common . DATA_ACTIVE_DECIMAL , "value" , defaultDec , "error" , err )
return res , err
}
// set the active contract address
err = store . WriteEntry ( ctx , sessionId , common . DATA_ACTIVE_ADDRESS , [ ] byte ( defaultAddr ) )
if err != nil {
logg . ErrorCtxf ( ctx , "failed to write defaultAddr entry with" , "key" , common . DATA_ACTIVE_ADDRESS , "value" , defaultAddr , "error" , err )
return res , err
}
2024-10-15 14:46:02 +02:00
return res , nil
}
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to read activeSym entry with" , "key" , common . DATA_ACTIVE_SYM , "error" , err )
2024-10-15 14:46:02 +02:00
return res , err
}
2024-10-18 17:31:40 +02:00
res . FlagReset = append ( res . FlagReset , flag_no_active_voucher )
2024-10-15 14:46:02 +02:00
return res , nil
}
2024-10-05 15:56:49 +02:00
// CheckVouchers retrieves the token holdings from the API using the "PublicKey" and stores
// them to gdbm
func ( h * Handlers ) CheckVouchers ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
var res resource . Result
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
store := h . userdataStore
2024-10-30 02:28:55 +01:00
publicKey , err := store . ReadEntry ( ctx , sessionId , common . DATA_PUBLIC_KEY )
2024-10-05 15:56:49 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed to read publicKey entry with" , "key" , common . DATA_PUBLIC_KEY , "error" , err )
return res , err
2024-10-05 15:56:49 +02:00
}
2024-10-07 07:59:15 +02:00
// Fetch vouchers from the API using the public key
2024-10-24 19:44:29 +02:00
vouchersResp , err := h . accountService . FetchVouchers ( ctx , string ( publicKey ) )
2024-10-05 15:56:49 +02:00
if err != nil {
return res , nil
}
2024-10-31 14:19:44 +01:00
data := common . ProcessVouchers ( vouchersResp )
2024-10-07 12:49:12 +02:00
2024-10-25 16:24:09 +02:00
// Store all voucher data
dataMap := map [ string ] string {
2024-10-30 16:40:03 +01:00
"sym" : data . Symbols ,
"bal" : data . Balances ,
"deci" : data . Decimals ,
"addr" : data . Addresses ,
2024-10-12 13:32:40 +02:00
}
2024-10-25 16:24:09 +02:00
for key , value := range dataMap {
2024-10-28 14:27:24 +01:00
if err := h . prefixDb . Put ( ctx , [ ] byte ( key ) , [ ] byte ( value ) ) ; err != nil {
2024-10-25 16:24:09 +02:00
return res , nil
}
2024-10-07 12:49:12 +02:00
}
2024-10-07 07:59:15 +02:00
2024-10-12 13:32:40 +02:00
return res , nil
}
// GetVoucherList fetches the list of vouchers and formats them
func ( h * Handlers ) GetVoucherList ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
var res resource . Result
// Read vouchers from the store
2024-10-28 14:27:24 +01:00
voucherData , err := h . prefixDb . Get ( ctx , [ ] byte ( "sym" ) )
2024-10-05 15:56:49 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "Failed to read the voucherData from prefixDb" , "error" , err )
2024-10-28 14:27:24 +01:00
return res , err
2024-10-05 15:56:49 +02:00
}
2024-10-12 13:32:40 +02:00
res . Content = string ( voucherData )
2024-10-05 15:56:49 +02:00
return res , nil
}
2024-10-07 15:16:57 +02:00
// ViewVoucher retrieves the token holding and balance from the subprefixDB
func ( h * Handlers ) ViewVoucher ( ctx context . Context , sym string , input [ ] byte ) ( resource . Result , error ) {
var res resource . Result
2024-10-09 14:39:06 +02:00
sessionId , ok := ctx . Value ( "SessionId" ) . ( string )
if ! ok {
return res , fmt . Errorf ( "missing session" )
}
2024-10-12 13:32:40 +02:00
flag_incorrect_voucher , _ := h . flagManager . GetFlag ( "flag_incorrect_voucher" )
2024-10-07 15:16:57 +02:00
inputStr := string ( input )
2024-10-09 14:05:59 +02:00
if inputStr == "0" || inputStr == "99" {
2024-10-12 13:32:40 +02:00
res . FlagReset = append ( res . FlagReset , flag_incorrect_voucher )
2024-10-07 15:16:57 +02:00
return res , nil
}
2024-10-31 14:19:44 +01:00
metadata , err := common . GetVoucherData ( ctx , h . prefixDb , inputStr )
2024-10-07 15:16:57 +02:00
if err != nil {
2024-10-25 16:24:09 +02:00
return res , fmt . Errorf ( "failed to retrieve voucher data: %v" , err )
2024-10-07 15:16:57 +02:00
}
2024-10-25 16:24:09 +02:00
if metadata == nil {
2024-10-15 16:02:51 +02:00
res . FlagSet = append ( res . FlagSet , flag_incorrect_voucher )
2024-10-25 16:24:09 +02:00
return res , nil
2024-10-15 16:02:51 +02:00
}
2024-10-31 14:19:44 +01:00
if err := common . StoreTemporaryVoucher ( ctx , h . userdataStore , sessionId , metadata ) ; err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed on StoreTemporaryVoucher" , "error" , err )
2024-10-28 09:20:06 +01:00
return res , err
2024-10-07 15:16:57 +02:00
}
2024-10-25 16:24:09 +02:00
res . FlagReset = append ( res . FlagReset , flag_incorrect_voucher )
2024-10-30 16:30:55 +01:00
res . Content = fmt . Sprintf ( "%s\n%s" , metadata . TokenSymbol , metadata . Balance )
2024-10-25 16:24:09 +02:00
return res , nil
2024-10-07 15:16:57 +02:00
}
2024-10-09 14:39:06 +02:00
2024-10-29 22:52:23 +01:00
// SetVoucher retrieves the temp voucher data and sets it as the active data
2024-10-09 14:39:06 +02:00
func ( h * Handlers ) SetVoucher ( 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" )
}
2024-10-25 16:24:09 +02:00
// Get temporary data
2024-10-31 14:19:44 +01:00
tempData , err := common . GetTemporaryVoucherData ( ctx , h . userdataStore , sessionId )
2024-10-10 13:48:23 +02:00
if err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed on GetTemporaryVoucherData" , "error" , err )
2024-10-10 13:48:23 +02:00
return res , err
}
2024-10-09 14:39:06 +02:00
2024-10-29 22:52:23 +01:00
// Set as active and clear temporary data
2024-10-31 14:19:44 +01:00
if err := common . UpdateVoucherData ( ctx , h . userdataStore , sessionId , tempData ) ; err != nil {
2024-11-13 17:00:27 +01:00
logg . ErrorCtxf ( ctx , "failed on UpdateVoucherData" , "error" , err )
2024-10-09 14:39:06 +02:00
return res , err
}
2024-10-30 16:30:55 +01:00
res . Content = tempData . TokenSymbol
2024-10-09 14:39:06 +02:00
return res , nil
}