diff --git a/.env.example b/.env.example index f518d39..7287e7c 100644 --- a/.env.example +++ b/.env.example @@ -18,3 +18,6 @@ DATA_URL_BASE=http://localhost:5006 #Language DEFAULT_LANGUAGE=eng LANGUAGES=eng, swa + +#Alias search domains +ALIAS_SEARCH_DOMAINS=sarafu.local, sarafu.eth diff --git a/config/config.go b/config/config.go index a8e5b3a..863e418 100644 --- a/config/config.go +++ b/config/config.go @@ -1,6 +1,8 @@ package config import ( + "strings" + apiconfig "git.grassecon.net/grassrootseconomics/sarafu-api/config" viseconfig "git.grassecon.net/grassrootseconomics/visedriver/config" "git.grassecon.net/grassrootseconomics/visedriver/env" @@ -23,7 +25,8 @@ const ( defaultSSHHost string = "127.0.0.1" defaultSSHPort uint = 7122 defaultHTTPHost string = "127.0.0.1" - defaultHTTPPort uint = 7123 + defaultHTTPPort uint = 7123 + defaultDomain = "sarafu.local" ) func LoadConfig() error { @@ -39,6 +42,17 @@ func LoadConfig() error { return nil } +func SearchDomains() []string { + var ParsedDomains []string + SearchDomains := env.GetEnv("ALIAS_SEARCH_DOMAINS", defaultDomain) + SearchDomainList := strings.Split(env.GetEnv("ALIAS_SEARCH_DOMAINS", SearchDomains), ",") + for _, domain := range SearchDomainList { + ParsedDomains = append(ParsedDomains, strings.ReplaceAll(domain, " ", "")) + } + return ParsedDomains +} + + func Language() string { return viseconfig.DefaultLanguage } diff --git a/handlers/application/menuhandler.go b/handlers/application/menuhandler.go index 5679ecd..53ada39 100644 --- a/handlers/application/menuhandler.go +++ b/handlers/application/menuhandler.go @@ -23,7 +23,9 @@ import ( "git.grassecon.net/grassrootseconomics/common/person" "git.grassecon.net/grassrootseconomics/common/phone" "git.grassecon.net/grassrootseconomics/common/pin" + "git.grassecon.net/grassrootseconomics/sarafu-api/models" "git.grassecon.net/grassrootseconomics/sarafu-api/remote" + "git.grassecon.net/grassrootseconomics/sarafu-vise/config" "git.grassecon.net/grassrootseconomics/sarafu-vise/profile" "git.grassecon.net/grassrootseconomics/sarafu-vise/store" storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db" @@ -662,6 +664,10 @@ func (h *MenuHandlers) SaveFirstname(ctx context.Context, sym string, input []by logg.ErrorCtxf(ctx, "failed to write firstName entry with", "key", storedb.DATA_FIRST_NAME, "value", temporaryFirstName, "error", err) return res, err } + err := h.constructAccountAlias(ctx) + if err != nil { + return res, err + } res.FlagSet = append(res.FlagSet, flag_firstname_set) } else { if firstNameSet { @@ -1076,6 +1082,11 @@ func (h *MenuHandlers) GetProfileInfo(ctx context.Context, sym string, input []b gender := getEntryOrDefault(store.ReadEntry(ctx, sessionId, storedb.DATA_GENDER)) location := getEntryOrDefault(store.ReadEntry(ctx, sessionId, storedb.DATA_LOCATION)) offerings := getEntryOrDefault(store.ReadEntry(ctx, sessionId, storedb.DATA_OFFERINGS)) + alias := getEntryOrDefault(store.ReadEntry(ctx, sessionId, storedb.DATA_ACCOUNT_ALIAS)) + + if alias != defaultValue { + alias = strings.Split(alias, ".")[0] + } // Construct the full name name := person.ConstructName(firstName, familyName, defaultValue) @@ -1092,18 +1103,18 @@ func (h *MenuHandlers) GetProfileInfo(ctx context.Context, sym string, input []b 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, + "Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\nYour alias: %s\n", + name, gender, age, location, offerings, alias, ) case "swa": res.Content = fmt.Sprintf( - "Jina: %s\nJinsia: %s\nUmri: %s\nEneo: %s\nUnauza: %s\n", - name, gender, age, location, offerings, + "Jina: %s\nJinsia: %s\nUmri: %s\nEneo: %s\nUnauza: %s\nLakabu yako: %s\n", + name, gender, age, location, offerings, alias, ) default: res.Content = fmt.Sprintf( - "Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n", - name, gender, age, location, offerings, + "Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\nYour alias: %s\n", + name, gender, age, location, offerings, alias, ) } @@ -1159,6 +1170,10 @@ func (h *MenuHandlers) UpdateAllProfileItems(ctx context.Context, sym string, in if err != nil { return res, err } + err = h.constructAccountAlias(ctx) + if err != nil { + return res, err + } return res, nil } @@ -1399,16 +1414,16 @@ func (h *MenuHandlers) FetchCommunityBalance(ctx context.Context, sym string, in // TODO: split up functino func (h *MenuHandlers) ValidateRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) { var res resource.Result + var AliasAddressResult string + var AliasAddress *models.AliasAddress store := h.userdataStore sessionId, ok := ctx.Value("SessionId").(string) if !ok { return res, fmt.Errorf("missing session") } - flag_invalid_recipient, _ := h.flagManager.GetFlag("flag_invalid_recipient") 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) @@ -1468,21 +1483,32 @@ func (h *MenuHandlers) ValidateRecipient(ctx context.Context, sym string, input } 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 + if strings.Contains(recipient, ".") { + AliasAddress, err = h.accountService.CheckAliasAddress(ctx, recipient) + if err == nil { + AliasAddressResult = AliasAddress.Address + } + } else { + //Perform a search for each search domain,break on first match + for _, domain := range config.SearchDomains() { + fqdn := fmt.Sprintf("%s.%s", recipient, domain) + AliasAddress, err = h.accountService.CheckAliasAddress(ctx, fqdn) + if err == nil { + AliasAddressResult = AliasAddress.Address + continue + } + } } - - // Alias validation succeeded, save the Ethereum address - err = store.WriteEntry(ctx, sessionId, storedb.DATA_RECIPIENT, []byte(r.Address)) - if err != nil { - logg.ErrorCtxf(ctx, "failed to write recipient entry with", "key", storedb.DATA_RECIPIENT, "value", r.Address, "error", err) - return res, err + if AliasAddressResult == "" { + res.Content = recipient + res.FlagSet = append(res.FlagSet, flag_invalid_recipient) + return res, nil + } else { + err = store.WriteEntry(ctx, sessionId, storedb.DATA_RECIPIENT, []byte(AliasAddressResult)) + if err != nil { + logg.ErrorCtxf(ctx, "failed to write recipient entry with", "key", storedb.DATA_RECIPIENT, "value", AliasAddressResult, "error", err) + return res, err + } } } } @@ -2015,7 +2041,6 @@ func (h *MenuHandlers) GetVoucherDetails(ctx context.Context, sym string, input if !ok { return res, fmt.Errorf("missing session") } - flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error") // get the active address @@ -2242,3 +2267,46 @@ func (h *MenuHandlers) persistLanguageCode(ctx context.Context, code string) err } return h.persistInitialLanguageCode(ctx, sessionId, code) } + +func (h *MenuHandlers) constructAccountAlias(ctx context.Context) error { + var alias string + store := h.userdataStore + sessionId, ok := ctx.Value("SessionId").(string) + if !ok { + return fmt.Errorf("missing session") + } + firstName, err := store.ReadEntry(ctx, sessionId, storedb.DATA_FIRST_NAME) + if err != nil { + if db.IsNotFound(err) { + return nil + } + return err + } + familyName, err := store.ReadEntry(ctx, sessionId, storedb.DATA_FAMILY_NAME) + if err != nil { + if db.IsNotFound(err) { + return nil + } + return err + } + pubKey, err := store.ReadEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY) + if err != nil { + if db.IsNotFound(err) { + return nil + } + return err + } + aliasInput := fmt.Sprintf("%s%s", firstName, familyName) + aliasResult, err := h.accountService.RequestAlias(ctx, string(pubKey), aliasInput) + if err != nil { + return fmt.Errorf("Failed to retrieve alias: %s", err.Error()) + } + alias = aliasResult.Alias + //Store the alias + err = store.WriteEntry(ctx, sessionId, storedb.DATA_ACCOUNT_ALIAS, []byte(alias)) + if err != nil { + logg.ErrorCtxf(ctx, "failed to write account alias", "key", storedb.DATA_ACCOUNT_ALIAS, "value", alias, "error", err) + return err + } + return nil +} diff --git a/handlers/application/menuhandler_test.go b/handlers/application/menuhandler_test.go index 0d3b9ef..3bf66a4 100644 --- a/handlers/application/menuhandler_test.go +++ b/handlers/application/menuhandler_test.go @@ -1679,7 +1679,7 @@ func TestValidateRecipient(t *testing.T) { }, { name: "Test with alias recepient", - input: []byte("alias123"), + input: []byte("alias123.sarafu.local"), expectedResult: resource.Result{}, }, } @@ -1797,37 +1797,37 @@ func TestGetProfile(t *testing.T) { }{ { name: "Test with full profile information in eng", - keys: []storedb.DataTyp{storedb.DATA_FAMILY_NAME, storedb.DATA_FIRST_NAME, storedb.DATA_GENDER, storedb.DATA_OFFERINGS, storedb.DATA_LOCATION, storedb.DATA_YOB}, - profileInfo: []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976"}, + keys: []storedb.DataTyp{storedb.DATA_FAMILY_NAME, storedb.DATA_FIRST_NAME, storedb.DATA_GENDER, storedb.DATA_OFFERINGS, storedb.DATA_LOCATION, storedb.DATA_YOB, storedb.DATA_ACCOUNT_ALIAS}, + profileInfo: []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976", "DoeJohn"}, languageCode: "eng", result: resource.Result{ Content: fmt.Sprintf( - "Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n", - "John Doee", "Male", "49", "Kilifi", "Bananas", + "Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\nYour alias: %s\n", + "John Doee", "Male", "49", "Kilifi", "Bananas", "DoeJohn", ), }, }, { name: "Test with with profile information in swa", - keys: []storedb.DataTyp{storedb.DATA_FAMILY_NAME, storedb.DATA_FIRST_NAME, storedb.DATA_GENDER, storedb.DATA_OFFERINGS, storedb.DATA_LOCATION, storedb.DATA_YOB}, - profileInfo: []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976"}, + keys: []storedb.DataTyp{storedb.DATA_FAMILY_NAME, storedb.DATA_FIRST_NAME, storedb.DATA_GENDER, storedb.DATA_OFFERINGS, storedb.DATA_LOCATION, storedb.DATA_YOB, storedb.DATA_ACCOUNT_ALIAS}, + profileInfo: []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976", "DoeJohn"}, languageCode: "swa", result: resource.Result{ Content: fmt.Sprintf( - "Jina: %s\nJinsia: %s\nUmri: %s\nEneo: %s\nUnauza: %s\n", - "John Doee", "Male", "49", "Kilifi", "Bananas", + "Jina: %s\nJinsia: %s\nUmri: %s\nEneo: %s\nUnauza: %s\nLakabu yako: %s\n", + "John Doee", "Male", "49", "Kilifi", "Bananas", "DoeJohn", ), }, }, { name: "Test with with profile information with language that is not yet supported", - keys: []storedb.DataTyp{storedb.DATA_FAMILY_NAME, storedb.DATA_FIRST_NAME, storedb.DATA_GENDER, storedb.DATA_OFFERINGS, storedb.DATA_LOCATION, storedb.DATA_YOB}, - profileInfo: []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976"}, + keys: []storedb.DataTyp{storedb.DATA_FAMILY_NAME, storedb.DATA_FIRST_NAME, storedb.DATA_GENDER, storedb.DATA_OFFERINGS, storedb.DATA_LOCATION, storedb.DATA_YOB, storedb.DATA_ACCOUNT_ALIAS}, + profileInfo: []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976", "DoeJohn"}, languageCode: "nor", result: resource.Result{ Content: fmt.Sprintf( - "Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n", - "John Doee", "Male", "49", "Kilifi", "Bananas", + "Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\nYour alias: %s\n", + "John Doee", "Male", "49", "Kilifi", "Bananas", "DoeJohn", ), }, }, diff --git a/menutraversal_test/group_test.json b/menutraversal_test/group_test.json index 0ffb49f..635e91d 100644 --- a/menutraversal_test/group_test.json +++ b/menutraversal_test/group_test.json @@ -427,7 +427,7 @@ }, { "input": "1234", - "expectedContent": "My profile:\nName: foo bar\nGender: male\nAge: 80\nLocation: Kilifi\nYou provide: Bananas\n\n0:Back\n9:Quit" + "expectedContent": "My profile:\nName: foo bar\nGender: male\nAge: 80\nLocation: Kilifi\nYou provide: Bananas\nYour alias: \n\n0:Back\n9:Quit" }, { "input": "0", diff --git a/services/remote.go b/services/remote.go index 517d67d..baad08f 100644 --- a/services/remote.go +++ b/services/remote.go @@ -12,5 +12,8 @@ import ( ) func New(ctx context.Context, storageService storage.StorageService) remote.AccountService { - return &httpremote.HTTPAccountService{} + return &httpremote.HTTPAccountService{ + SS: storageService, + UseApi: false, + } } diff --git a/store/db/db.go b/store/db/db.go index 2ccd9e6..10f360a 100644 --- a/store/db/db.go +++ b/store/db/db.go @@ -61,6 +61,8 @@ const ( DATA_SELECTED_LANGUAGE_CODE //ISO 639 code for the language initially selected. DATA_INITIAL_LANGUAGE_CODE + //Fully qualified account alias string + DATA_ACCOUNT_ALIAS ) const (