From e73da9b1431b053b2d8cd8261bbc05ff3e7ccaad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Thu, 25 Apr 2024 16:00:23 +0200 Subject: [PATCH 01/36] profile realm --- examples/gno.land/r/demo/profile/gno.mod | 2 + examples/gno.land/r/demo/profile/profile.gno | 312 +++++++++++++++++++ 2 files changed, 314 insertions(+) create mode 100644 examples/gno.land/r/demo/profile/gno.mod create mode 100644 examples/gno.land/r/demo/profile/profile.gno diff --git a/examples/gno.land/r/demo/profile/gno.mod b/examples/gno.land/r/demo/profile/gno.mod new file mode 100644 index 00000000000..0c56e34f8c1 --- /dev/null +++ b/examples/gno.land/r/demo/profile/gno.mod @@ -0,0 +1,2 @@ +module gno.land/r/demo/profile + diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno new file mode 100644 index 00000000000..f54e57eaee6 --- /dev/null +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -0,0 +1,312 @@ +package profile + +import ( + "bytes" + "gno.land/p/demo/avl" + "gno.land/p/demo/ufmt" + "std" + "time" +) + +type UserProfile struct { + Username string + Address std.Address + AvatarURL string + Age string + Gender string + Website string + Country string + City string + ModificationHistory map[string][]string +} + +var profiles *avl.Tree +var usernameIndex *avl.Tree // Index to quickly find a profile by username + +func init() { + profiles = avl.NewTree() + usernameIndex = avl.NewTree() +} + +func CreateProfile(username, avatarurl, age, gender, website, country, city string) { + caller := std.GetOrigCaller() + + // Check if a profile already exists for this address + if _, exists := profiles.Get(caller.String()); exists { + panic("A profile already exists for this address") + } + + // Check if the username is already taken + if username != "" { + _, exists := usernameIndex.Get(username) + if exists { + panic("Username is already taken") + } + } + + profile := UserProfile{ + Username: username, + Address: caller, + AvatarURL: avatarurl, + Age: age, + Gender: gender, + Website: website, + Country: country, + City: city, + } + + profiles.Set(caller.String(), profile) + + // Add the username to the index + if username != "" { + usernameIndex.Set(username, caller.String()) + } +} + +func UpdateProfile(username, avatarurl, age, gender, website, country, city string) { + caller := std.GetOrigCaller() + value, exists := profiles.Get(caller.String()) + if !exists { + panic("Profile not found") + } + + // Retrieve the existing profile + existingProfile := value.(UserProfile) + + // Initialize the ModificationHistory map if it's nil + if existingProfile.ModificationHistory == nil { + existingProfile.ModificationHistory = make(map[string][]string) + } + + // Function to update the profile field if changed + updateField := func(field *string, newValue, fieldName string, profile *UserProfile) { + if newValue != "" && *field != newValue { + changeDescription := time.Now().Format(time.RFC3339) + ": Changed from " + *field + " to " + newValue + if profile.ModificationHistory == nil { + profile.ModificationHistory = make(map[string][]string) + } + profile.ModificationHistory[fieldName] = append(profile.ModificationHistory[fieldName], changeDescription) + *field = newValue + } + } + + // Update fields and log changes + updateField(&existingProfile.Username, username, "Username", &existingProfile) + updateField(&existingProfile.AvatarURL, avatarurl, "AvatarURL", &existingProfile) + updateField(&existingProfile.Age, age, "Age", &existingProfile) + updateField(&existingProfile.Gender, gender, "Gender", &existingProfile) + updateField(&existingProfile.Website, website, "Website", &existingProfile) + updateField(&existingProfile.Country, country, "Country", &existingProfile) + updateField(&existingProfile.City, city, "City", &existingProfile) + + // Update the profile in the tree + profiles.Set(caller.String(), existingProfile) + + // Update the username index if the username is changed + if username != "" { + usernameIndex.Set(username, caller.String()) + } +} + +// Display complete Profile by Address +func DisplayProfileByAddress(address std.Address) (UserProfile, bool) { + if value, exists := profiles.Get(address.String()); exists { + return value.(UserProfile), true + } + return UserProfile{}, false +} + +// Get complete profile by username +func DisplayProfileByUsername(username string) (UserProfile, bool) { + if addr, exists := usernameIndex.Get(username); exists { + return DisplayProfileByAddress(std.Address(addr.(string))) + } + return UserProfile{}, false +} + +// Display username +func DisplayUsername(address std.Address) string { + if value, exists := profiles.Get(address.String()); exists { + return value.(UserProfile).Username + } + return "Address not found" +} + +// Display address from username +func DisplayAddress(username string) string { + if addr, exists := usernameIndex.Get(username); exists { + return addr.(string) + } + return "Username not found" +} + +// Display avatarurl from address or username +func DisplayAvatarURL(address std.Address, username string) string { + if address != "" { + if value, exists := profiles.Get(address.String()); exists { + return value.(UserProfile).AvatarURL + } + } else if username != "" { + if addr, exists := usernameIndex.Get(username); exists { + if value, exists := profiles.Get(addr.(string)); exists { + return value.(UserProfile).AvatarURL + } + } + } + return "Address or Username not found" +} + +// Display age from address or username +func DisplayAge(address std.Address, username string) string { + if address != "" { + if value, exists := profiles.Get(address.String()); exists { + return value.(UserProfile).Age + } + } else if username != "" { + if addr, exists := usernameIndex.Get(username); exists { + if value, exists := profiles.Get(addr.(string)); exists { + return value.(UserProfile).Age + } + } + } + return "Address or Username not found" +} + +// Display gender from address or username +func DisplayGender(address std.Address, username string) string { + if address != "" { + if value, exists := profiles.Get(address.String()); exists { + return value.(UserProfile).Gender + } + } else if username != "" { + if addr, exists := usernameIndex.Get(username); exists { + if value, exists := profiles.Get(addr.(string)); exists { + return value.(UserProfile).Gender + } + } + } + return "Address or Username not found" +} + +// Display website from address or username +func DisplayWebsite(address std.Address, username string) string { + if address != "" { + if value, exists := profiles.Get(address.String()); exists { + return value.(UserProfile).Website + } + } else if username != "" { + if addr, exists := usernameIndex.Get(username); exists { + if value, exists := profiles.Get(addr.(string)); exists { + return value.(UserProfile).Website + } + } + } + return "Address or Username not found" +} + +// Display country from address or username +func DisplayCountry(address std.Address, username string) string { + if address != "" { + if value, exists := profiles.Get(address.String()); exists { + return value.(UserProfile).Country + } + } else if username != "" { + if addr, exists := usernameIndex.Get(username); exists { + if value, exists := profiles.Get(addr.(string)); exists { + return value.(UserProfile).Country + } + } + } + return "Address or Username not found" +} + +// Display city from address or username +func DisplayCity(address std.Address, username string) string { + if address != "" { + if value, exists := profiles.Get(address.String()); exists { + return value.(UserProfile).City + } + } else if username != "" { + if addr, exists := usernameIndex.Get(username); exists { + if value, exists := profiles.Get(addr.(string)); exists { + return value.(UserProfile).City + } + } + } + return "Address or Username not found" +} + +// Display modification history specific to a field from address or username +func DisplayModificationHistory(address std.Address, username, field string) string { + if address != "" { + if value, exists := profiles.Get(address.String()); exists { + if value.(UserProfile).ModificationHistory != nil { + if changes, exists := value.(UserProfile).ModificationHistory[field]; exists { + var b bytes.Buffer + for _, change := range changes { + b.WriteString(ufmt.Sprintf("%s\n", change)) + } + return b.String() + } + } + } + } else if username != "" { + if addr, exists := usernameIndex.Get(username); exists { + if value, exists := profiles.Get(addr.(string)); exists { + if value.(UserProfile).ModificationHistory != nil { + if changes, exists := value.(UserProfile).ModificationHistory[field]; exists { + var b bytes.Buffer + for _, change := range changes { + b.WriteString(ufmt.Sprintf("%s\n", change)) + } + return b.String() + } + } + } + } + } + return "Address or Username not found or no modifications recorded for the field" +} + +func Render(path string) string { + if path == "" { + return renderHome() + } + + return "unknown path" +} + +func renderHome() string { + var b bytes.Buffer + + profiles.Iterate("", "", func(key string, value interface{}) bool { + profile := value.(UserProfile) + b.WriteString(ufmt.Sprintf("Username: %s\n\n", profile.Username)) + b.WriteString(ufmt.Sprintf("Address: %s\n\n", profile.Address)) + b.WriteString(ufmt.Sprintf("AvatarURL: %s\n\n", profile.AvatarURL)) + b.WriteString(ufmt.Sprintf("Age: %s\n\n", profile.Age)) + b.WriteString(ufmt.Sprintf("Gender: %s\n\n", profile.Gender)) + b.WriteString(ufmt.Sprintf("Website: %s\n\n", profile.Website)) + b.WriteString(ufmt.Sprintf("Country: %s\n\n", profile.Country)) + b.WriteString(ufmt.Sprintf("City: %s\n\n", profile.City)) + + // Properly iterate over the modification history map + if profile.ModificationHistory != nil { + b.WriteString("ModificationHistory:\n\n") + for key, changes := range profile.ModificationHistory { + b.WriteString(ufmt.Sprintf("%s:\n", key)) + for _, change := range changes { + b.WriteString(ufmt.Sprintf(" %s | \n", change)) + } + } + } else { + b.WriteString("No modifications recorded.\n") + } + + b.WriteString("\n") + + return false + }) + + return b.String() +} From f98cafa4e096f4eca8622fefb06f11bde232a63e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Wed, 8 May 2024 11:54:54 +0200 Subject: [PATCH 02/36] panic message start with lowercase letter --- examples/gno.land/r/demo/profile/profile.gno | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index f54e57eaee6..ecddc8d1ce6 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -33,7 +33,7 @@ func CreateProfile(username, avatarurl, age, gender, website, country, city stri // Check if a profile already exists for this address if _, exists := profiles.Get(caller.String()); exists { - panic("A profile already exists for this address") + panic("a profile already exists for this address") } // Check if the username is already taken From 9c6b7688f4bc76c56d9a02606d64d38cd15bbe99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Thu, 9 May 2024 17:42:39 +0200 Subject: [PATCH 03/36] add mapping comment --- examples/gno.land/r/demo/profile/profile.gno | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index ecddc8d1ce6..e7aba957e1a 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -20,8 +20,8 @@ type UserProfile struct { ModificationHistory map[string][]string } -var profiles *avl.Tree -var usernameIndex *avl.Tree // Index to quickly find a profile by username +var profiles *avl.Tree // address -> UserProfile +var usernameIndex *avl.Tree // username -> address func init() { profiles = avl.NewTree() From 5f294197a7d4f8302f068a4524c412ebcab84333 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Thu, 9 May 2024 17:55:29 +0200 Subject: [PATCH 04/36] modify comparison --- examples/gno.land/r/demo/profile/profile.gno | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index e7aba957e1a..8f6c91712ac 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -103,7 +103,7 @@ func UpdateProfile(username, avatarurl, age, gender, website, country, city stri profiles.Set(caller.String(), existingProfile) // Update the username index if the username is changed - if username != "" { + if username != existingProfile.Username { usernameIndex.Set(username, caller.String()) } } From bf3b0dd5a51a44331a1986f7f0bbb57de6e4b2e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Thu, 9 May 2024 18:09:12 +0200 Subject: [PATCH 05/36] replace return and bool by panic --- examples/gno.land/r/demo/profile/profile.gno | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index 8f6c91712ac..b0dcb20a093 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -109,19 +109,21 @@ func UpdateProfile(username, avatarurl, age, gender, website, country, city stri } // Display complete Profile by Address -func DisplayProfileByAddress(address std.Address) (UserProfile, bool) { +func DisplayProfileByAddress(address std.Address) UserProfile { if value, exists := profiles.Get(address.String()); exists { - return value.(UserProfile), true + return value.(UserProfile) } - return UserProfile{}, false + + panic("profile not found") } // Get complete profile by username -func DisplayProfileByUsername(username string) (UserProfile, bool) { +func DisplayProfileByUsername(username string) UserProfile { if addr, exists := usernameIndex.Get(username); exists { return DisplayProfileByAddress(std.Address(addr.(string))) } - return UserProfile{}, false + + panic("username not found") } // Display username From 3796c3c39b7b93cd4e15e409d1f6c2cf3e2f0efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Thu, 9 May 2024 18:20:45 +0200 Subject: [PATCH 06/36] modify name of function and replace return by panic --- examples/gno.land/r/demo/profile/profile.gno | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index b0dcb20a093..87616e31557 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -122,24 +122,26 @@ func DisplayProfileByUsername(username string) UserProfile { if addr, exists := usernameIndex.Get(username); exists { return DisplayProfileByAddress(std.Address(addr.(string))) } - + panic("username not found") } // Display username -func DisplayUsername(address std.Address) string { +func DisplayUsernameByAddress(address std.Address) string { if value, exists := profiles.Get(address.String()); exists { return value.(UserProfile).Username } - return "Address not found" + + panic("address not found") } // Display address from username -func DisplayAddress(username string) string { +func DisplayAddressByUsername(username string) string { if addr, exists := usernameIndex.Get(username); exists { return addr.(string) } - return "Username not found" + + panic("username not found") } // Display avatarurl from address or username From 4770d4b3fe4bfe874484a6c9fd18d46d97413fc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Thu, 9 May 2024 18:26:33 +0200 Subject: [PATCH 07/36] replace return by panic --- examples/gno.land/r/demo/profile/profile.gno | 21 +++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index 87616e31557..b936e8b925e 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -157,7 +157,8 @@ func DisplayAvatarURL(address std.Address, username string) string { } } } - return "Address or Username not found" + + panic("address or username not found") } // Display age from address or username @@ -173,7 +174,8 @@ func DisplayAge(address std.Address, username string) string { } } } - return "Address or Username not found" + + panic("address or username not found") } // Display gender from address or username @@ -189,7 +191,8 @@ func DisplayGender(address std.Address, username string) string { } } } - return "Address or Username not found" + + panic("address or username not found") } // Display website from address or username @@ -205,7 +208,8 @@ func DisplayWebsite(address std.Address, username string) string { } } } - return "Address or Username not found" + + panic("address or username not found") } // Display country from address or username @@ -221,7 +225,8 @@ func DisplayCountry(address std.Address, username string) string { } } } - return "Address or Username not found" + + panic("address or username not found") } // Display city from address or username @@ -237,7 +242,8 @@ func DisplayCity(address std.Address, username string) string { } } } - return "Address or Username not found" + + panic("address or username not found") } // Display modification history specific to a field from address or username @@ -269,7 +275,8 @@ func DisplayModificationHistory(address std.Address, username, field string) str } } } - return "Address or Username not found or no modifications recorded for the field" + + panic("address or username not found or no modifications recorded for the field") } func Render(path string) string { From f13d0d6cfcff8a8f64186443cd50cc798b52f7c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Sun, 12 May 2024 20:36:44 +0200 Subject: [PATCH 08/36] add emit --- examples/gno.land/r/demo/profile/profile.gno | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index b936e8b925e..1a5566c416f 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -20,7 +20,7 @@ type UserProfile struct { ModificationHistory map[string][]string } -var profiles *avl.Tree // address -> UserProfile +var profiles *avl.Tree // address -> UserProfile var usernameIndex *avl.Tree // username -> address func init() { @@ -60,6 +60,7 @@ func CreateProfile(username, avatarurl, age, gender, website, country, city stri // Add the username to the index if username != "" { usernameIndex.Set(username, caller.String()) + std.Emit("UserProfileCreated", "username", username, "address", caller.String()) } } @@ -242,7 +243,7 @@ func DisplayCity(address std.Address, username string) string { } } } - + panic("address or username not found") } From 38b5439a20dc4aa23b2970bd3f2cad2eebbf02bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Mon, 13 May 2024 17:07:47 +0200 Subject: [PATCH 09/36] remove unnecessary condition --- examples/gno.land/r/demo/profile/profile.gno | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index 1a5566c416f..e000898db4d 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -57,11 +57,9 @@ func CreateProfile(username, avatarurl, age, gender, website, country, city stri profiles.Set(caller.String(), profile) - // Add the username to the index - if username != "" { - usernameIndex.Set(username, caller.String()) - std.Emit("UserProfileCreated", "username", username, "address", caller.String()) - } + + usernameIndex.Set(username, caller.String()) + std.Emit("UserProfileCreated", "username", username, "address", caller.String()) } func UpdateProfile(username, avatarurl, age, gender, website, country, city string) { From d1c108ca8b481ae249567b5b24ed25db7f52a096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Tue, 14 May 2024 15:54:10 +0200 Subject: [PATCH 10/36] displaymodificationhistory simplified --- examples/gno.land/r/demo/profile/profile.gno | 59 ++++++++++---------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index e000898db4d..e151b19efff 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -247,35 +247,36 @@ func DisplayCity(address std.Address, username string) string { // Display modification history specific to a field from address or username func DisplayModificationHistory(address std.Address, username, field string) string { - if address != "" { - if value, exists := profiles.Get(address.String()); exists { - if value.(UserProfile).ModificationHistory != nil { - if changes, exists := value.(UserProfile).ModificationHistory[field]; exists { - var b bytes.Buffer - for _, change := range changes { - b.WriteString(ufmt.Sprintf("%s\n", change)) - } - return b.String() - } - } - } - } else if username != "" { - if addr, exists := usernameIndex.Get(username); exists { - if value, exists := profiles.Get(addr.(string)); exists { - if value.(UserProfile).ModificationHistory != nil { - if changes, exists := value.(UserProfile).ModificationHistory[field]; exists { - var b bytes.Buffer - for _, change := range changes { - b.WriteString(ufmt.Sprintf("%s\n", change)) - } - return b.String() - } - } - } - } - } - - panic("address or username not found or no modifications recorded for the field") + var value interface{} + var exists bool + + if address != "" { + value, exists = profiles.Get(address.String()) + } else if username != "" { + if addr, ok := usernameIndex.Get(username); ok { + value, exists = profiles.Get(addr.(string)) + } + } + + if !exists { + panic("address or username not found") + } + + profile, ok := value.(UserProfile) + if !ok || profile.ModificationHistory == nil { + panic("no modification history available") + } + + changes, found := profile.ModificationHistory[field] + if !found { + panic("no modifications recorded for the field") + } + + var b bytes.Buffer + for _, change := range changes { + b.WriteString(ufmt.Sprintf("%s\n", change)) + } + return b.String() } func Render(path string) string { From a0a10279605059f6e8af4abb5ea3b3ef212bf8ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Tue, 14 May 2024 23:11:27 +0200 Subject: [PATCH 11/36] add mux for routing --- examples/gno.land/r/demo/profile/gno.mod | 5 ++ examples/gno.land/r/demo/profile/profile.gno | 94 ++++++++++++-------- 2 files changed, 64 insertions(+), 35 deletions(-) diff --git a/examples/gno.land/r/demo/profile/gno.mod b/examples/gno.land/r/demo/profile/gno.mod index 0c56e34f8c1..1b505132279 100644 --- a/examples/gno.land/r/demo/profile/gno.mod +++ b/examples/gno.land/r/demo/profile/gno.mod @@ -1,2 +1,7 @@ module gno.land/r/demo/profile +require ( + gno.land/p/demo/mux v0.0.0-latest + gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest +) \ No newline at end of file diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index e151b19efff..e8efa768c66 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -4,6 +4,7 @@ import ( "bytes" "gno.land/p/demo/avl" "gno.land/p/demo/ufmt" + "gno.land/p/demo/mux" "std" "time" ) @@ -22,10 +23,16 @@ type UserProfile struct { var profiles *avl.Tree // address -> UserProfile var usernameIndex *avl.Tree // username -> address +var router *mux.Router func init() { profiles = avl.NewTree() usernameIndex = avl.NewTree() + router = mux.NewRouter() + + router.HandleFunc("", homeHandler) + router.HandleFunc("info/{username}", profileHandler) + router.HandleFunc("history/{username}", historyHandler) } func CreateProfile(username, avatarurl, age, gender, website, country, city string) { @@ -116,6 +123,8 @@ func DisplayProfileByAddress(address std.Address) UserProfile { panic("profile not found") } + + // Get complete profile by username func DisplayProfileByUsername(username string) UserProfile { if addr, exists := usernameIndex.Get(username); exists { @@ -279,45 +288,60 @@ func DisplayModificationHistory(address std.Address, username, field string) str return b.String() } -func Render(path string) string { - if path == "" { - return renderHome() - } - - return "unknown path" +func homeHandler(res *mux.ResponseWriter, req *mux.Request) { + var b bytes.Buffer + b.WriteString("
") + res.Write("Username: " + username + " [" + "View Profile]
") + return true + }) + b.WriteString("") + res.Write(b.String()) } -func renderHome() string { - var b bytes.Buffer +func profileHandler(res *mux.ResponseWriter, req *mux.Request) { + username := req.GetVar("username") + profile := DisplayProfileByUsername(username) - profiles.Iterate("", "", func(key string, value interface{}) bool { - profile := value.(UserProfile) - b.WriteString(ufmt.Sprintf("Username: %s\n\n", profile.Username)) - b.WriteString(ufmt.Sprintf("Address: %s\n\n", profile.Address)) - b.WriteString(ufmt.Sprintf("AvatarURL: %s\n\n", profile.AvatarURL)) - b.WriteString(ufmt.Sprintf("Age: %s\n\n", profile.Age)) - b.WriteString(ufmt.Sprintf("Gender: %s\n\n", profile.Gender)) - b.WriteString(ufmt.Sprintf("Website: %s\n\n", profile.Website)) - b.WriteString(ufmt.Sprintf("Country: %s\n\n", profile.Country)) - b.WriteString(ufmt.Sprintf("City: %s\n\n", profile.City)) - - // Properly iterate over the modification history map - if profile.ModificationHistory != nil { - b.WriteString("ModificationHistory:\n\n") - for key, changes := range profile.ModificationHistory { - b.WriteString(ufmt.Sprintf("%s:\n", key)) - for _, change := range changes { - b.WriteString(ufmt.Sprintf(" %s | \n", change)) - } - } - } else { - b.WriteString("No modifications recorded.\n") - } + var b bytes.Buffer - b.WriteString("\n") + b.WriteString("") + b.WriteString("Username: " + profile.Username + "
") + b.WriteString("Address: " + profile.Address.String() + "
") + b.WriteString("Avatar URL:
") + b.WriteString("") + b.WriteString("") - return false - }) + res.Write(b.String()) +} - return b.String() +func historyHandler(res *mux.ResponseWriter, req *mux.Request) { + username := req.GetVar("username") + profile := DisplayProfileByUsername(username) + + var b bytes.Buffer + + b.WriteString("") + b.WriteString("" + change + "
") + } + } + } else { + b.WriteString("No modifications recorded.
") + } + + b.WriteString("") + res.Write(b.String()) } + +func Render(path string) string { + return router.Render(path) +} \ No newline at end of file From 21f6ccbe0888ba8dfb7619aabf9640ceebe78020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Tue, 14 May 2024 23:44:09 +0200 Subject: [PATCH 12/36] remove old username in avl tree after update username --- examples/gno.land/r/demo/profile/profile.gno | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index e8efa768c66..e5ee129ec23 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -79,6 +79,22 @@ func UpdateProfile(username, avatarurl, age, gender, website, country, city stri // Retrieve the existing profile existingProfile := value.(UserProfile) + // update the username and manage index if changed + if username != "" && username != existingProfile.Username { + _, exists := usernameIndex.Get(username) + if exists { + panic("Username is already taken") + } + + // remove the old username from the index + if existingProfile.Username != "" { + usernameIndex.Remove(existingProfile.Username) + } + + // set the new username in the index + usernameIndex.Set(username, caller.String()) + } + // Initialize the ModificationHistory map if it's nil if existingProfile.ModificationHistory == nil { existingProfile.ModificationHistory = make(map[string][]string) @@ -109,9 +125,9 @@ func UpdateProfile(username, avatarurl, age, gender, website, country, city stri profiles.Set(caller.String(), existingProfile) // Update the username index if the username is changed - if username != existingProfile.Username { + /*if username != existingProfile.Username { usernameIndex.Set(username, caller.String()) - } + }*/ } // Display complete Profile by Address From e78e0bc1489307d61b5382f591a6197ecbb05562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Tue, 14 May 2024 23:49:11 +0200 Subject: [PATCH 13/36] make tidy --- examples/gno.land/r/demo/profile/gno.mod | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/gno.land/r/demo/profile/gno.mod b/examples/gno.land/r/demo/profile/gno.mod index 1b505132279..25c515ccf94 100644 --- a/examples/gno.land/r/demo/profile/gno.mod +++ b/examples/gno.land/r/demo/profile/gno.mod @@ -1,7 +1,7 @@ module gno.land/r/demo/profile require ( - gno.land/p/demo/mux v0.0.0-latest - gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/mux v0.0.0-latest gno.land/p/demo/ufmt v0.0.0-latest -) \ No newline at end of file +) From 9b87d5830c0548febb274c8e211e8693bf0d219e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Wed, 15 May 2024 00:14:13 +0200 Subject: [PATCH 14/36] add link in profile page and hisotry page --- examples/gno.land/r/demo/profile/profile.gno | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index e5ee129ec23..6cff28fd840 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -324,6 +324,8 @@ func profileHandler(res *mux.ResponseWriter, req *mux.Request) { var b bytes.Buffer b.WriteString("") + // Reteturn home link + b.WriteString("[Home]
") b.WriteString("Username: " + profile.Username + "
") b.WriteString("Address: " + profile.Address.String() + "
") @@ -341,6 +343,8 @@ func historyHandler(res *mux.ResponseWriter, req *mux.Request) { var b bytes.Buffer b.WriteString("") + + b.WriteString("[Home] | [Profile " + username + "]
") b.WriteString("Username: " + profile.Username + "
") b.WriteString("Address: " + profile.Address.String() + "
") b.WriteString("Avatar URL:
") + b.WriteString("Age: " + profile.Age + "
") + b.WriteString("Gender: " + profile.Gender + "
") + b.WriteString("Country: " + profile.Country + "
") + b.WriteString("City: " + profile.City + "
") + + b.WriteString("" + key + ": " + value.(string) + "
") + return true + }) + b.WriteString("") b.WriteString("") @@ -339,14 +391,14 @@ func profileHandler(res *mux.ResponseWriter, req *mux.Request) { func historyHandler(res *mux.ResponseWriter, req *mux.Request) { username := req.GetVar("username") profile := DisplayProfileByUsername(username) - + var b bytes.Buffer - + b.WriteString("") - + b.WriteString("[Home] | [Profile " + username + "]
") b.WriteString("No modifications recorded.
") } - + b.WriteString("") res.Write(b.String()) } func Render(path string) string { return router.Render(path) -} \ No newline at end of file +} From 8793a519183362fad25bbddb576e0511724d42bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Tue, 18 Jun 2024 12:04:46 +0200 Subject: [PATCH 16/36] add std.Emit with the changes made in UpdateProfile --- examples/gno.land/r/demo/profile/profile.gno | 126 ++++++++++--------- 1 file changed, 67 insertions(+), 59 deletions(-) diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index 3113a3fcc25..8c0db2ade2c 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -77,65 +77,73 @@ func CreateProfile(username, avatarurl, age, gender, websiteName, websiteURL, co } func UpdateProfile(username, avatarurl, age, gender, websiteName, websiteURL, country, city string) { - caller := std.GetOrigCaller() - value, exists := profiles.Get(caller.String()) - if !exists { - panic("Profile not found") - } - - // Retrieve the existing profile - existingProfile := value.(UserProfile) - - // update the username and manage index if changed - if username != "" && username != existingProfile.Username { - _, exists := usernameIndex.Get(username) - if exists { - panic("Username is already taken") - } - - // remove the old username from the index - if existingProfile.Username != "" { - usernameIndex.Remove(existingProfile.Username) - } - - // set the new username in the index - usernameIndex.Set(username, caller.String()) - } - - // Initialize the ModificationHistory map if it's nil - if existingProfile.ModificationHistory == nil { - existingProfile.ModificationHistory = make(map[string][]string) - } - - // Function to update the profile field if changed - updateField := func(field *string, newValue, fieldName string, profile *UserProfile) { - if newValue != "" && *field != newValue { - changeDescription := time.Now().Format(time.RFC3339) + ": Changed from " + *field + " to " + newValue - if profile.ModificationHistory == nil { - profile.ModificationHistory = make(map[string][]string) - } - profile.ModificationHistory[fieldName] = append(profile.ModificationHistory[fieldName], changeDescription) - *field = newValue - } - } - - // Update fields and log changes - updateField(&existingProfile.Username, username, "Username", &existingProfile) - updateField(&existingProfile.AvatarURL, avatarurl, "AvatarURL", &existingProfile) - updateField(&existingProfile.Age, age, "Age", &existingProfile) - updateField(&existingProfile.Gender, gender, "Gender", &existingProfile) - updateField(&existingProfile.Country, country, "Country", &existingProfile) - updateField(&existingProfile.City, city, "City", &existingProfile) - - // Update the website tree if a new website is provided - if websiteName != "" && websiteURL != "" { - existingProfile.Websites.Set(websiteName, websiteURL) - changeDescription := time.Now().Format(time.RFC3339) + ": Updated website " + websiteName + " to " + websiteURL - existingProfile.ModificationHistory["Websites"] = append(existingProfile.ModificationHistory["Websites"], changeDescription) - } - - // Update the profile in the tree - profiles.Set(caller.String(), existingProfile) + caller := std.GetOrigCaller() + value, exists := profiles.Get(caller.String()) + if !exists { + panic("Profile not found") + } + + // Retrieve the existing profile + existingProfile := value.(UserProfile) + changes := make(map[string]string) + + // update the username and manage index if changed + if username != "" && username != existingProfile.Username { + _, exists := usernameIndex.Get(username) + if exists { + panic("Username is already taken") + } + + if existingProfile.Username != "" { + usernameIndex.Remove(existingProfile.Username) + } + usernameIndex.Set(username, caller.String()) + + changes["Username"] = "Changed from " + existingProfile.Username + " to " + username + existingProfile.Username = username + } + + // Initialize the ModificationHistory map if it's nil + if existingProfile.ModificationHistory == nil { + existingProfile.ModificationHistory = make(map[string][]string) + } + + // Function to update the profile field if changed + updateField := func(field *string, newValue, fieldName string, profile *UserProfile) { + if newValue != "" && *field != newValue { + changeDescription := "Changed from " + *field + " to " + newValue + profile.ModificationHistory[fieldName] = append(profile.ModificationHistory[fieldName], time.Now().Format(time.RFC3339)+": "+changeDescription) + changes[fieldName] = changeDescription + *field = newValue + } + } + + // Update fields and log changes + updateField(&existingProfile.AvatarURL, avatarurl, "AvatarURL", &existingProfile) + updateField(&existingProfile.Age, age, "Age", &existingProfile) + updateField(&existingProfile.Gender, gender, "Gender", &existingProfile) + updateField(&existingProfile.Country, country, "Country", &existingProfile) + updateField(&existingProfile.City, city, "City", &existingProfile) + + // Update the website tree if a new website is provided + if websiteName != "" && websiteURL != "" { + existingProfile.Websites.Set(websiteName, websiteURL) + changeDescription := "Updated website " + websiteName + " to " + websiteURL + existingProfile.ModificationHistory["Websites"] = append(existingProfile.ModificationHistory["Websites"], time.Now().Format(time.RFC3339)+": "+changeDescription) + changes["Website"] = changeDescription + } + + // Update the profile in the tree + profiles.Set(caller.String(), existingProfile) + + // Emit the changes + if len(changes) > 0 { + emitArgs := []string{"address", caller.String()} + for key, value := range changes { + emitArgs = append(emitArgs, key, value) + } + std.Emit("UserProfileUpdated", emitArgs...) + } } // Display complete Profile by Address From 6fac7881cfdc63acd79640992b7405e1cc4fb295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Tue, 18 Jun 2024 13:11:39 +0200 Subject: [PATCH 17/36] renaming getter functions with the Get prefix --- examples/gno.land/r/demo/profile/profile.gno | 51 ++++++++++---------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index 8c0db2ade2c..84349cfcbaf 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -146,8 +146,8 @@ func UpdateProfile(username, avatarurl, age, gender, websiteName, websiteURL, co } } -// Display complete Profile by Address -func DisplayProfileByAddress(address std.Address) UserProfile { +// Get complete Profile by Address +func GetProfileByAddress(address std.Address) UserProfile { if value, exists := profiles.Get(address.String()); exists { return value.(UserProfile) } @@ -156,16 +156,16 @@ func DisplayProfileByAddress(address std.Address) UserProfile { } // Get complete profile by username -func DisplayProfileByUsername(username string) UserProfile { +func GetProfileByUsername(username string) UserProfile { if addr, exists := usernameIndex.Get(username); exists { - return DisplayProfileByAddress(std.Address(addr.(string))) + return GetProfileByAddress(std.Address(addr.(string))) } panic("username not found") } -// Display username -func DisplayUsernameByAddress(address std.Address) string { +// Get username +func GetUsernameByAddress(address std.Address) string { if value, exists := profiles.Get(address.String()); exists { return value.(UserProfile).Username } @@ -173,8 +173,8 @@ func DisplayUsernameByAddress(address std.Address) string { panic("address not found") } -// Display address from username -func DisplayAddressByUsername(username string) string { +// Get address from username +func GetAddressByUsername(username string) string { if addr, exists := usernameIndex.Get(username); exists { return addr.(string) } @@ -182,8 +182,8 @@ func DisplayAddressByUsername(username string) string { panic("username not found") } -// Display avatarurl from address or username -func DisplayAvatarURL(address std.Address, username string) string { +// Get avatarurl from address or username +func GetAvatarURL(address std.Address, username string) string { if address != "" { if value, exists := profiles.Get(address.String()); exists { return value.(UserProfile).AvatarURL @@ -199,8 +199,8 @@ func DisplayAvatarURL(address std.Address, username string) string { panic("address or username not found") } -// Display age from address or username -func DisplayAge(address std.Address, username string) string { +// Get age from address or username +func GetAge(address std.Address, username string) string { if address != "" { if value, exists := profiles.Get(address.String()); exists { return value.(UserProfile).Age @@ -216,8 +216,8 @@ func DisplayAge(address std.Address, username string) string { panic("address or username not found") } -// Display gender from address or username -func DisplayGender(address std.Address, username string) string { +// Get gender from address or username +func GetGender(address std.Address, username string) string { if address != "" { if value, exists := profiles.Get(address.String()); exists { return value.(UserProfile).Gender @@ -233,8 +233,8 @@ func DisplayGender(address std.Address, username string) string { panic("address or username not found") } -// Display website from address or username -func DisplayWebsite(address std.Address, username, websiteName string) string { +// Get website from address or username +func GetWebsite(address std.Address, username, websiteName string) string { if address != "" { if value, exists := profiles.Get(address.String()); exists { profile := value.(UserProfile) @@ -258,7 +258,8 @@ func DisplayWebsite(address std.Address, username, websiteName string) string { panic("address or username not found") } -func DisplayAllWebsites(address std.Address, username string) map[string]string { +// Get all websites from address or username +func GetAllWebsites(address std.Address, username string) map[string]string { if address != "" { if value, exists := profiles.Get(address.String()); exists { profile := value.(UserProfile) @@ -285,8 +286,8 @@ func DisplayAllWebsites(address std.Address, username string) map[string]string panic("address or username not found") } -// Display country from address or username -func DisplayCountry(address std.Address, username string) string { +// Get country from address or username +func GetCountry(address std.Address, username string) string { if address != "" { if value, exists := profiles.Get(address.String()); exists { return value.(UserProfile).Country @@ -302,8 +303,8 @@ func DisplayCountry(address std.Address, username string) string { panic("address or username not found") } -// Display city from address or username -func DisplayCity(address std.Address, username string) string { +// Get city from address or username +func GetCity(address std.Address, username string) string { if address != "" { if value, exists := profiles.Get(address.String()); exists { return value.(UserProfile).City @@ -319,8 +320,8 @@ func DisplayCity(address std.Address, username string) string { panic("address or username not found") } -// Display modification history specific to a field from address or username -func DisplayModificationHistory(address std.Address, username, field string) string { +// Get modification history specific to a field from address or username +func GetModificationHistory(address std.Address, username, field string) string { var value interface{} var exists bool @@ -368,7 +369,7 @@ func homeHandler(res *mux.ResponseWriter, req *mux.Request) { func profileHandler(res *mux.ResponseWriter, req *mux.Request) { username := req.GetVar("username") - profile := DisplayProfileByUsername(username) + profile := GetProfileByUsername(username) var b bytes.Buffer @@ -398,7 +399,7 @@ func profileHandler(res *mux.ResponseWriter, req *mux.Request) { func historyHandler(res *mux.ResponseWriter, req *mux.Request) { username := req.GetVar("username") - profile := DisplayProfileByUsername(username) + profile := GetProfileByUsername(username) var b bytes.Buffer From 19d5b2364ba3202227871a7bd95716cc78f59339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Fri, 21 Jun 2024 10:41:05 +0200 Subject: [PATCH 18/36] Refactoring v0.1 --- examples/gno.land/r/demo/profile/profile.gno | 430 +++++-------------- 1 file changed, 112 insertions(+), 318 deletions(-) diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index 84349cfcbaf..d93a4453619 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -3,27 +3,17 @@ package profile import ( "bytes" "gno.land/p/demo/avl" - "gno.land/p/demo/mux" "gno.land/p/demo/ufmt" + "gno.land/p/demo/mux" "std" - "time" ) -type WebsiteInfo struct { - Name string - URL string -} +type contextKey string type UserProfile struct { - Username string - Address std.Address - AvatarURL string - Age string - Gender string - Websites *avl.Tree // Name -> URL - Country string - City string - ModificationHistory map[string][]string + Username string + Address std.Address + Fields *avl.Tree } var profiles *avl.Tree // address -> UserProfile @@ -37,10 +27,10 @@ func init() { router.HandleFunc("", homeHandler) router.HandleFunc("info/{username}", profileHandler) - router.HandleFunc("history/{username}", historyHandler) } -func CreateProfile(username, avatarurl, age, gender, websiteName, websiteURL, country, city string) { +// CreateProfile creates a new user profile with a username and address +func CreateProfile(username string) { caller := std.GetOrigCaller() // Check if a profile already exists for this address @@ -50,323 +40,163 @@ func CreateProfile(username, avatarurl, age, gender, websiteName, websiteURL, co // Check if the username is already taken if username != "" { - _, exists := usernameIndex.Get(username) - if exists { - panic("Username is already taken") + if _, exists := usernameIndex.Get(username); exists { + panic("username is already taken") } } - websites := avl.NewTree() - websites.Set(websiteName, websiteURL) - profile := UserProfile{ - Username: username, - Address: caller, - AvatarURL: avatarurl, - Age: age, - Gender: gender, - Websites: websites, - Country: country, - City: city, + Username: username, + Address: caller, + Fields: avl.NewTree(), } profiles.Set(caller.String(), profile) - usernameIndex.Set(username, caller.String()) std.Emit("UserProfileCreated", "username", username, "address", caller.String()) } -func UpdateProfile(username, avatarurl, age, gender, websiteName, websiteURL, country, city string) { - caller := std.GetOrigCaller() - value, exists := profiles.Get(caller.String()) - if !exists { - panic("Profile not found") - } - - // Retrieve the existing profile - existingProfile := value.(UserProfile) - changes := make(map[string]string) - - // update the username and manage index if changed - if username != "" && username != existingProfile.Username { - _, exists := usernameIndex.Get(username) - if exists { - panic("Username is already taken") - } - - if existingProfile.Username != "" { - usernameIndex.Remove(existingProfile.Username) - } - usernameIndex.Set(username, caller.String()) - - changes["Username"] = "Changed from " + existingProfile.Username + " to " + username - existingProfile.Username = username - } - - // Initialize the ModificationHistory map if it's nil - if existingProfile.ModificationHistory == nil { - existingProfile.ModificationHistory = make(map[string][]string) - } - - // Function to update the profile field if changed - updateField := func(field *string, newValue, fieldName string, profile *UserProfile) { - if newValue != "" && *field != newValue { - changeDescription := "Changed from " + *field + " to " + newValue - profile.ModificationHistory[fieldName] = append(profile.ModificationHistory[fieldName], time.Now().Format(time.RFC3339)+": "+changeDescription) - changes[fieldName] = changeDescription - *field = newValue - } - } - - // Update fields and log changes - updateField(&existingProfile.AvatarURL, avatarurl, "AvatarURL", &existingProfile) - updateField(&existingProfile.Age, age, "Age", &existingProfile) - updateField(&existingProfile.Gender, gender, "Gender", &existingProfile) - updateField(&existingProfile.Country, country, "Country", &existingProfile) - updateField(&existingProfile.City, city, "City", &existingProfile) - - // Update the website tree if a new website is provided - if websiteName != "" && websiteURL != "" { - existingProfile.Websites.Set(websiteName, websiteURL) - changeDescription := "Updated website " + websiteName + " to " + websiteURL - existingProfile.ModificationHistory["Websites"] = append(existingProfile.ModificationHistory["Websites"], time.Now().Format(time.RFC3339)+": "+changeDescription) - changes["Website"] = changeDescription - } - - // Update the profile in the tree - profiles.Set(caller.String(), existingProfile) - - // Emit the changes - if len(changes) > 0 { - emitArgs := []string{"address", caller.String()} - for key, value := range changes { - emitArgs = append(emitArgs, key, value) - } - std.Emit("UserProfileUpdated", emitArgs...) - } -} - -// Get complete Profile by Address -func GetProfileByAddress(address std.Address) UserProfile { - if value, exists := profiles.Get(address.String()); exists { - return value.(UserProfile) - } - - panic("profile not found") -} - -// Get complete profile by username -func GetProfileByUsername(username string) UserProfile { - if addr, exists := usernameIndex.Get(username); exists { - return GetProfileByAddress(std.Address(addr.(string))) - } - - panic("username not found") -} - -// Get username -func GetUsernameByAddress(address std.Address) string { - if value, exists := profiles.Get(address.String()); exists { - return value.(UserProfile).Username - } - - panic("address not found") -} +func UpdateProfile(username string, fields ...interface{}) { + profile := GetProfileByUsername(username) -// Get address from username -func GetAddressByUsername(username string) string { - if addr, exists := usernameIndex.Get(username); exists { - return addr.(string) + // Check for username change + var newUsername string + for i := 0; i < len(fields); i += 2 { + if fields[i] == "Username" { + newUsername = fields[i+1].(string) + break + } } - panic("username not found") -} - -// Get avatarurl from address or username -func GetAvatarURL(address std.Address, username string) string { - if address != "" { - if value, exists := profiles.Get(address.String()); exists { - return value.(UserProfile).AvatarURL - } - } else if username != "" { - if addr, exists := usernameIndex.Get(username); exists { - if value, exists := profiles.Get(addr.(string)); exists { - return value.(UserProfile).AvatarURL - } + // Update username if it has changed + if newUsername != "" && newUsername != profile.Username { + if _, exists := usernameIndex.Get(newUsername); exists { + panic("username is already taken") } + usernameIndex.Remove(profile.Username) + profile.Username = newUsername + usernameIndex.Set(newUsername, profile.Address.String()) + std.Emit("UserProfileUpdated", "username", newUsername) } - panic("address or username not found") -} - -// Get age from address or username -func GetAge(address std.Address, username string) string { - if address != "" { - if value, exists := profiles.Get(address.String()); exists { - return value.(UserProfile).Age + // Update existing fields only + for i := 0; i < len(fields); i += 2 { + key := fields[i].(string) + value := fields[i+1] + if key == "Username" { + continue } - } else if username != "" { - if addr, exists := usernameIndex.Get(username); exists { - if value, exists := profiles.Get(addr.(string)); exists { - return value.(UserProfile).Age - } + if _, exists := profile.Fields.Get(key); exists { + profile.Fields.Set(key, value) + std.Emit("UserProfileUpdated", "username", profile.Username, "key", key, "value", ufmt.Sprintf("%v", value)) + } else { + panic(ufmt.Sprintf("field '%s' does not exist in profile", key)) } } - panic("address or username not found") + profiles.Set(profile.Address.String(), profile) } -// Get gender from address or username -func GetGender(address std.Address, username string) string { - if address != "" { - if value, exists := profiles.Get(address.String()); exists { - return value.(UserProfile).Gender - } - } else if username != "" { - if addr, exists := usernameIndex.Get(username); exists { - if value, exists := profiles.Get(addr.(string)); exists { - return value.(UserProfile).Gender - } - } +// AddFields adds multiple fields to a UserProfile using key-value pairs +func AddFields(profile UserProfile, fields ...interface{}) UserProfile { + if len(fields)%2 != 0 { + panic("fields must be in key-value pairs") } - panic("address or username not found") -} + for i := 0; i < len(fields); i += 2 { + key := fields[i].(string) + value := fields[i+1] -// Get website from address or username -func GetWebsite(address std.Address, username, websiteName string) string { - if address != "" { - if value, exists := profiles.Get(address.String()); exists { - profile := value.(UserProfile) - if url, exists := profile.Websites.Get(websiteName); exists { - return url.(string) - } - panic("website not found") - } - } else if username != "" { - if addr, exists := usernameIndex.Get(username); exists { - if value, exists := profiles.Get(addr.(string)); exists { - profile := value.(UserProfile) - if url, exists := profile.Websites.Get(websiteName); exists { - return url.(string) - } - panic("website not found") - } + // Get the current values + var values []interface{} + if existing, exists := profile.Fields.Get(key); exists { + values = existing.([]interface{}) } + + // Append the new value + values = append(values, value) + profile.Fields.Set(key, values) + std.Emit("UserProfileUpdated", "username", profile.Username, "key", key, "value", ufmt.Sprintf("%v", value)) } + profiles.Set(profile.Address.String(), profile) + return profile +} - panic("address or username not found") +// RemoveProfile deletes a user profile +func RemoveProfile(username string) { + profile := GetProfileByUsername(username) + profiles.Remove(profile.Address.String()) + usernameIndex.Remove(username) + std.Emit("UserProfileDeleted", "username", username, "address", profile.Address.String()) } -// Get all websites from address or username -func GetAllWebsites(address std.Address, username string) map[string]string { - if address != "" { - if value, exists := profiles.Get(address.String()); exists { - profile := value.(UserProfile) - websites := make(map[string]string) - profile.Websites.Iterate("", "", func(key string, value interface{}) bool { - websites[key] = value.(string) - return true - }) - return websites - } - } else if username != "" { - if addr, exists := usernameIndex.Get(username); exists { - if value, exists := profiles.Get(addr.(string)); exists { - profile := value.(UserProfile) - websites := make(map[string]string) - profile.Websites.Iterate("", "", func(key string, value interface{}) bool { - websites[key] = value.(string) - return true - }) - return websites - } - } +// GetField retrieves a field from a UserProfile +func GetField(profile UserProfile, key string) interface{} { + if value, exists := profile.Fields.Get(key); exists { + return value } - panic("address or username not found") + return nil } -// Get country from address or username -func GetCountry(address std.Address, username string) string { - if address != "" { - if value, exists := profiles.Get(address.String()); exists { - return value.(UserProfile).Country - } - } else if username != "" { - if addr, exists := usernameIndex.Get(username); exists { - if value, exists := profiles.Get(addr.(string)); exists { - return value.(UserProfile).Country - } +// GetProfileByUsername retrieves a profile by username +func GetProfileByUsername(username string) UserProfile { + if addr, exists := usernameIndex.Get(username); exists { + if profile, ok := profiles.Get(addr.(string)); ok { + return profile.(UserProfile) } } - - panic("address or username not found") + panic("username not found") } -// Get city from address or username -func GetCity(address std.Address, username string) string { - if address != "" { - if value, exists := profiles.Get(address.String()); exists { - return value.(UserProfile).City - } - } else if username != "" { - if addr, exists := usernameIndex.Get(username); exists { - if value, exists := profiles.Get(addr.(string)); exists { - return value.(UserProfile).City - } - } +// GetProfileByAddress retrieves a profile by address +func GetProfileByAddress(address std.Address) UserProfile { + if profile, exists := profiles.Get(address.String()); exists { + return profile.(UserProfile) } - - panic("address or username not found") + panic("profile not found") } -// Get modification history specific to a field from address or username -func GetModificationHistory(address std.Address, username, field string) string { - var value interface{} - var exists bool - if address != "" { - value, exists = profiles.Get(address.String()) - } else if username != "" { - if addr, ok := usernameIndex.Get(username); ok { - value, exists = profiles.Get(addr.(string)) +// formatFieldValue formats the value for display +func formatFieldValue(value interface{}) string { + switch v := value.(type) { + case string: + return v + case int: + return ufmt.Sprintf("%d", v) + case float64: + return ufmt.Sprintf("%f", v) + case []interface{}: + var result string + for _, val := range v { + result += formatFieldValue(val) + ", " } + if len(result) > 0 { + return result[:len(result)-2] // Remove trailing comma and space + } + return result + default: + return ufmt.Sprintf("%v", v) } - - if !exists { - panic("address or username not found") - } - - profile, ok := value.(UserProfile) - if !ok || profile.ModificationHistory == nil { - panic("no modification history available") - } - - changes, found := profile.ModificationHistory[field] - if !found { - panic("no modifications recorded for the field") - } - - var b bytes.Buffer - for _, change := range changes { - b.WriteString(ufmt.Sprintf("%s\n", change)) - } - return b.String() } +// Handlers + +// homeHandler lists all profiles func homeHandler(res *mux.ResponseWriter, req *mux.Request) { var b bytes.Buffer b.WriteString("") - res.Write("Username: " + username + " [" + "View Profile]
") - return true + b.WriteString("Username: " + username + " [View Profile]
") + return false }) b.WriteString("") res.Write(b.String()) } +// profileHandler displays a user profile func profileHandler(res *mux.ResponseWriter, req *mux.Request) { username := req.GetVar("username") profile := GetProfileByUsername(username) @@ -374,50 +204,14 @@ func profileHandler(res *mux.ResponseWriter, req *mux.Request) { var b bytes.Buffer b.WriteString("") - // Reteturn home link b.WriteString("[Home]
") b.WriteString("Username: " + profile.Username + "
") b.WriteString("Address: " + profile.Address.String() + "
") - b.WriteString("Avatar URL:
") - b.WriteString("Age: " + profile.Age + "
") - b.WriteString("Gender: " + profile.Gender + "
") - b.WriteString("Country: " + profile.Country + "
") - b.WriteString("City: " + profile.City + "
") - - b.WriteString("" + key + ": " + value.(string) + "
") - return true - }) - - b.WriteString("") - b.WriteString("") - res.Write(b.String()) -} - -func historyHandler(res *mux.ResponseWriter, req *mux.Request) { - username := req.GetVar("username") - profile := GetProfileByUsername(username) - - var b bytes.Buffer - - b.WriteString("") - - b.WriteString("[Home] | [Profile " + username + "]
") - b.WriteString("" + change + "
") - } - } - } else { - b.WriteString("No modifications recorded.
") - } + profile.Fields.Iterate("", "", func(key string, value interface{}) bool { + b.WriteString("" + key + ": " + formatFieldValue(value) + "
") + return false + }) b.WriteString("") res.Write(b.String()) From bec9bcba5bfe1571c7ab16160f0ada0705616b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Fri, 21 Jun 2024 10:43:41 +0200 Subject: [PATCH 19/36] remove no used contextKey --- examples/gno.land/r/demo/profile/profile.gno | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index d93a4453619..ad1430d2e21 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -8,8 +8,6 @@ import ( "std" ) -type contextKey string - type UserProfile struct { Username string Address std.Address From 8a6618824c45835a0a3f9bbfdeb0abff9edeeab0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Fri, 21 Jun 2024 11:00:44 +0200 Subject: [PATCH 20/36] mod --- examples/gno.land/r/demo/profile/gno.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gno.land/r/demo/profile/gno.mod b/examples/gno.land/r/demo/profile/gno.mod index 25c515ccf94..e173fb93ac9 100644 --- a/examples/gno.land/r/demo/profile/gno.mod +++ b/examples/gno.land/r/demo/profile/gno.mod @@ -1,7 +1,7 @@ module gno.land/r/demo/profile require ( - gno.land/p/demo/avl v0.0.0-latest gno.land/p/demo/mux v0.0.0-latest + gno.land/p/demo/avl v0.0.0-latest gno.land/p/demo/ufmt v0.0.0-latest ) From f38eb7f1f792e21a26f4fd0ac044533db34d61a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Mon, 24 Jun 2024 08:22:32 +0200 Subject: [PATCH 21/36] refactor, adding minimal getters and setters --- examples/gno.land/r/demo/profile/profile.gno | 272 +++++++------------ 1 file changed, 95 insertions(+), 177 deletions(-) diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index ad1430d2e21..3ed1fa9cab9 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -6,215 +6,133 @@ import ( "gno.land/p/demo/ufmt" "gno.land/p/demo/mux" "std" + "errors" ) -type UserProfile struct { - Username string - Address std.Address - Fields *avl.Tree -} - -var profiles *avl.Tree // address -> UserProfile -var usernameIndex *avl.Tree // username -> address -var router *mux.Router +var fields = avl.NewTree() +var router = mux.NewRouter() func init() { - profiles = avl.NewTree() - usernameIndex = avl.NewTree() - router = mux.NewRouter() - - router.HandleFunc("", homeHandler) - router.HandleFunc("info/{username}", profileHandler) + //router.HandleFunc("", homeHandler) + //router.HandleFunc("u/{addr}", profileHandler) + //router.HandleFunc("f/{addr}/{field}", fieldHandler) } -// CreateProfile creates a new user profile with a username and address -func CreateProfile(username string) { - caller := std.GetOrigCaller() - - // Check if a profile already exists for this address - if _, exists := profiles.Get(caller.String()); exists { - panic("a profile already exists for this address") - } - - // Check if the username is already taken - if username != "" { - if _, exists := usernameIndex.Get(username); exists { - panic("username is already taken") - } - } - - profile := UserProfile{ - Username: username, - Address: caller, - Fields: avl.NewTree(), - } - - profiles.Set(caller.String(), profile) - usernameIndex.Set(username, caller.String()) - std.Emit("UserProfileCreated", "username", username, "address", caller.String()) +// list of support string fields +var stringFields = map[string]bool{ + "DisplayName": true, + "Homepage": true, + "Bio": true, + "Location": true, + "Avatar": true, + "GravatarEmail": true, } -func UpdateProfile(username string, fields ...interface{}) { - profile := GetProfileByUsername(username) - - // Check for username change - var newUsername string - for i := 0; i < len(fields); i += 2 { - if fields[i] == "Username" { - newUsername = fields[i+1].(string) - break - } - } - - // Update username if it has changed - if newUsername != "" && newUsername != profile.Username { - if _, exists := usernameIndex.Get(newUsername); exists { - panic("username is already taken") - } - usernameIndex.Remove(profile.Username) - profile.Username = newUsername - usernameIndex.Set(newUsername, profile.Address.String()) - std.Emit("UserProfileUpdated", "username", newUsername) - } - - // Update existing fields only - for i := 0; i < len(fields); i += 2 { - key := fields[i].(string) - value := fields[i+1] - if key == "Username" { - continue - } - if _, exists := profile.Fields.Get(key); exists { - profile.Fields.Set(key, value) - std.Emit("UserProfileUpdated", "username", profile.Username, "key", key, "value", ufmt.Sprintf("%v", value)) - } else { - panic(ufmt.Sprintf("field '%s' does not exist in profile", key)) - } - } - - profiles.Set(profile.Address.String(), profile) +// list of support int fields +var intFields = map[int]bool { + "Age": true } -// AddFields adds multiple fields to a UserProfile using key-value pairs -func AddFields(profile UserProfile, fields ...interface{}) UserProfile { - if len(fields)%2 != 0 { - panic("fields must be in key-value pairs") - } +// list of support bool fields +var boolFields = map[string]bool{ + "AvailableForHiring": true, +} - for i := 0; i < len(fields); i += 2 { - key := fields[i].(string) - value := fields[i+1] +// Setters - // Get the current values - var values []interface{} - if existing, exists := profile.Fields.Get(key); exists { - values = existing.([]interface{}) - } +func SetStringField(field, value string) error { + addr := std.PrevRealm().Addr() + if _, ok := stringFields[field]; !ok { + return errors.New("invalid string field") + } + + key := addr.String() + ":" + field + fields.Set(key, value) - // Append the new value - values = append(values, value) - profile.Fields.Set(key, values) - std.Emit("UserProfileUpdated", "username", profile.Username, "key", key, "value", ufmt.Sprintf("%v", value)) - } - profiles.Set(profile.Address.String(), profile) - return profile + return nil } -// RemoveProfile deletes a user profile -func RemoveProfile(username string) { - profile := GetProfileByUsername(username) - profiles.Remove(profile.Address.String()) - usernameIndex.Remove(username) - std.Emit("UserProfileDeleted", "username", username, "address", profile.Address.String()) +func SetIntField(field string, value int) error { + addr := std.PrevRealm().Addr() + + if _, ok := intFields[field]; !ok { + return errors.New("invalid int field") + } + + key := addr.String() + ":" + field + fields.Set(key, value) + + return nil } -// GetField retrieves a field from a UserProfile -func GetField(profile UserProfile, key string) interface{} { - if value, exists := profile.Fields.Get(key); exists { - return value - } - return nil +func SetBoolField(field string, value bool) error { + addr := std.PrevRealm().Addr() + + if _, ok := boolFields[field]; !ok { + return errors.New("invalid bool field") + } + + key := addr.String() + ":" + field + fields.Set(key, value) + + return nil } -// GetProfileByUsername retrieves a profile by username -func GetProfileByUsername(username string) UserProfile { - if addr, exists := usernameIndex.Get(username); exists { - if profile, ok := profiles.Get(addr.(string)); ok { - return profile.(UserProfile) - } - } - panic("username not found") -} +//Getters -// GetProfileByAddress retrieves a profile by address -func GetProfileByAddress(address std.Address) UserProfile { - if profile, exists := profiles.Get(address.String()); exists { - return profile.(UserProfile) +func GetStringField(addr std.Address, field, def string) string { + key := addr.String() + ":" + field + if value, ok := fields.Get(key); ok { + return value.(string) } - panic("profile not found") + + return def } - -// formatFieldValue formats the value for display -func formatFieldValue(value interface{}) string { - switch v := value.(type) { - case string: - return v - case int: - return ufmt.Sprintf("%d", v) - case float64: - return ufmt.Sprintf("%f", v) - case []interface{}: - var result string - for _, val := range v { - result += formatFieldValue(val) + ", " - } - if len(result) > 0 { - return result[:len(result)-2] // Remove trailing comma and space - } - return result - default: - return ufmt.Sprintf("%v", v) +func GetIntField(addr std.Address, field string, def int) int { + key := addr.String() + ":" + field + if value, ok := fields.Get(key); ok { + return value.(int) } + + return def } -// Handlers - -// homeHandler lists all profiles -func homeHandler(res *mux.ResponseWriter, req *mux.Request) { - var b bytes.Buffer - b.WriteString("") - b.WriteString("Username: " + username + " [View Profile]
") - return false - }) - b.WriteString("") - res.Write(b.String()) +func GetBoolField(addr std.Address, field string, def bool) bool { + key := addr.String() + ":" + field + if value, ok := fields.Get(key); ok { + return value.(bool) + } + + return def } -// profileHandler displays a user profile -func profileHandler(res *mux.ResponseWriter, req *mux.Request) { - username := req.GetVar("username") - profile := GetProfileByUsername(username) +// Add getter and setter for bool and int fields - var b bytes.Buffer +// render: home => generate links like this: https://gno.land/r/demo/boards?help&__func=CreateReply&bid=1&threadid=2&postid=2&body.type=textarea +// render: home/addr => display all fields for the address - b.WriteString("") - b.WriteString("[Home]
") - b.WriteString("Address: " + profile.Address.String() + "
") +// later: works with r/users transparently - profile.Fields.Iterate("", "", func(key string, value interface{}) bool { - b.WriteString("" + key + ": " + formatFieldValue(value) + "
") - return false - }) +/* read optim for later +type Profile struct { + displayNamePtr *string + usernamePtr *string +} - b.WriteString("") - res.Write(b.String()) +func (p Profile) DisplayName(def string) string { + if p.displayNamePtr != nil { + return *p.displayNamePtr + } + return def } +*/ + + +//----------------------------- -func Render(path string) string { - return router.Render(path) +/*func AdminAddStringField(field string){ + assertIsDAO() + stringFields[field] = true} } +*/ From 51d5577779972529c685011253385ecc152b3f11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Mon, 24 Jun 2024 17:30:11 +0200 Subject: [PATCH 22/36] whitout test, whitout render refactoring --- examples/gno.land/r/demo/profile/profile.gno | 175 +++++++++++++++---- 1 file changed, 142 insertions(+), 33 deletions(-) diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index 3ed1fa9cab9..657d75d16d9 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -6,16 +6,18 @@ import ( "gno.land/p/demo/ufmt" "gno.land/p/demo/mux" "std" + "strings" "errors" + "strconv" ) var fields = avl.NewTree() var router = mux.NewRouter() func init() { - //router.HandleFunc("", homeHandler) - //router.HandleFunc("u/{addr}", profileHandler) - //router.HandleFunc("f/{addr}/{field}", fieldHandler) + router.HandleFunc("", homeHandler) + router.HandleFunc("u/{addr}", profileHandler) + router.HandleFunc("f/{addr}/{field}", fieldHandler) } // list of support string fields @@ -29,8 +31,8 @@ var stringFields = map[string]bool{ } // list of support int fields -var intFields = map[int]bool { - "Age": true +var intFields = map[string]bool { + "Age": true, } // list of support bool fields @@ -89,50 +91,157 @@ func GetStringField(addr std.Address, field, def string) string { return def } -func GetIntField(addr std.Address, field string, def int) int { +func GetBoolField(addr std.Address, field string, def bool) bool { key := addr.String() + ":" + field if value, ok := fields.Get(key); ok { - return value.(int) + return value.(bool) } - - return def + + return def } -func GetBoolField(addr std.Address, field string, def bool) bool { - key := addr.String() + ":" + field - if value, ok := fields.Get(key); ok { - return value.(bool) - } - +func GetIntField(addr std.Address, field string, def int) int { + key := addr.String() + ":" + field + if value, ok := fields.Get(key); ok { + return value.(int) + } + return def } -// Add getter and setter for bool and int fields +func Render(path string) string { + return router.Render(path) +} + +func homeHandler(res *mux.ResponseWriter, req *mux.Request) { + var b bytes.Buffer + addresses := make(map[string]struct{}) + + b.WriteString("") + b.WriteString("--------------------------
") + + fields.Iterate("", "", func(key string, value interface{}) bool { + parts := strings.SplitN(key, ":", 2) + if len(parts) > 0 { + addresses[parts[0]] = struct{}{} + } + return true + }) + + b.WriteString("Address: %s " + + "[View All Fields] "+ + "[Get String Field] "+ + "[Get Int Field] "+ + "[Get Bool Field]
", + address, address, getStringLink, getIntLink, getBoolLink)) + + b.WriteString("--------------------------
") + } + + b.WriteString("") + res.Write(b.String()) } -func (p Profile) DisplayName(def string) string { - if p.displayNamePtr != nil { - return *p.displayNamePtr +func profileHandler(res *mux.ResponseWriter, req *mux.Request) { + var b bytes.Buffer + addr := req.GetVar("addr") + + b.WriteString("") + b.WriteString(ufmt.Sprintf("%s: %s [Edit]
", field, value, link)) } - return def + + for field := range intFields { + value := GetIntField(address, field, 0) + link := ufmt.Sprintf("/r/demo/profile?help&__func=SetIntField&field=%s", field) + b.WriteString(ufmt.Sprintf("%s: %d [Edit]
", field, value, link)) + } + + for field := range boolFields { + value := GetBoolField(address, field, false) + link := ufmt.Sprintf("/r/demo/profile?help&__func=SetBoolField&field=%s", field) + b.WriteString(ufmt.Sprintf("%s: %t [Edit]
", field, value, link)) + } + + b.WriteString("") + res.Write(b.String()) } -*/ +func fieldHandler(res *mux.ResponseWriter, req *mux.Request) { + var b bytes.Buffer + addr := req.GetVar("addr") + field := req.GetVar("field") + + b.WriteString("") + b.WriteString(ufmt.Sprintf("%s: %s [Edit]
", field, value, editLink)) -/*func AdminAddStringField(field string){ - assertIsDAO() - stringFields[field] = true} + b.WriteString("") + res.Write(b.String()) } -*/ + From 57fd8745fcd8cc49ba49fab08a1dd4295f48d3bc Mon Sep 17 00:00:00 2001 From: kazai--------------------------
") + + fields.Iterate("", "", func(key string, value interface{}) bool { + parts := strings.SplitN(key, ":", 2) + if len(parts) > 0 { + addresses[parts[0]] = struct{}{} + } + return true + }) + + b.WriteString("Address: %s "+ + "[View All Fields] "+ + "[Get String Field] "+ + "[Get Int Field] "+ + "[Get Bool Field]
", + address, ufmt.Sprintf(ViewAllFieldsURL, address), getStringLink, getIntLink, getBoolLink)) + + b.WriteString("--------------------------
") + } + + b.WriteString("") + res.Write(b.String()) +} + +func profileHandler(res *mux.ResponseWriter, req *mux.Request) { + var b bytes.Buffer + addr := req.GetVar("addr") + + b.WriteString("") + b.WriteString(ufmt.Sprintf("%s: %s [Edit]
", field, value, link)) + } + + for field := range intFields { + value := GetIntField(address, field, 0) + link := ufmt.Sprintf(SetIntFieldURL, field) + b.WriteString(ufmt.Sprintf("%s: %d [Edit]
", field, value, link)) + } + + for field := range boolFields { + value := GetBoolField(address, field, false) + link := ufmt.Sprintf(SetBoolFieldURL, field) + b.WriteString(ufmt.Sprintf("%s: %t [Edit]
", field, value, link)) + } + + b.WriteString("") + res.Write(b.String()) +} + +func fieldHandler(res *mux.ResponseWriter, req *mux.Request) { + var b bytes.Buffer + addr := req.GetVar("addr") + field := req.GetVar("field") + + b.WriteString("") + b.WriteString(ufmt.Sprintf("%s: %s [Edit]
", field, value, editLink)) + + b.WriteString("") + res.Write(b.String()) +} + diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index 657d75d16d9..b99e1358016 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -1,14 +1,10 @@ package profile import ( - "bytes" "gno.land/p/demo/avl" - "gno.land/p/demo/ufmt" "gno.land/p/demo/mux" "std" - "strings" "errors" - "strconv" ) var fields = avl.NewTree() @@ -112,136 +108,3 @@ func GetIntField(addr std.Address, field string, def int) int { func Render(path string) string { return router.Render(path) } - -func homeHandler(res *mux.ResponseWriter, req *mux.Request) { - var b bytes.Buffer - addresses := make(map[string]struct{}) - - b.WriteString("") - b.WriteString("--------------------------
") - - fields.Iterate("", "", func(key string, value interface{}) bool { - parts := strings.SplitN(key, ":", 2) - if len(parts) > 0 { - addresses[parts[0]] = struct{}{} - } - return true - }) - - b.WriteString("Address: %s " + - "[View All Fields] "+ - "[Get String Field] "+ - "[Get Int Field] "+ - "[Get Bool Field]
", - address, address, getStringLink, getIntLink, getBoolLink)) - - b.WriteString("--------------------------
") - } - - b.WriteString("") - res.Write(b.String()) -} - -func profileHandler(res *mux.ResponseWriter, req *mux.Request) { - var b bytes.Buffer - addr := req.GetVar("addr") - - b.WriteString("") - b.WriteString(ufmt.Sprintf("%s: %s [Edit]
", field, value, link)) - } - - for field := range intFields { - value := GetIntField(address, field, 0) - link := ufmt.Sprintf("/r/demo/profile?help&__func=SetIntField&field=%s", field) - b.WriteString(ufmt.Sprintf("%s: %d [Edit]
", field, value, link)) - } - - for field := range boolFields { - value := GetBoolField(address, field, false) - link := ufmt.Sprintf("/r/demo/profile?help&__func=SetBoolField&field=%s", field) - b.WriteString(ufmt.Sprintf("%s: %t [Edit]
", field, value, link)) - } - - b.WriteString("") - res.Write(b.String()) -} - -func fieldHandler(res *mux.ResponseWriter, req *mux.Request) { - var b bytes.Buffer - addr := req.GetVar("addr") - field := req.GetVar("field") - - b.WriteString("") - b.WriteString(ufmt.Sprintf("%s: %s [Edit]
", field, value, editLink)) - - b.WriteString("") - res.Write(b.String()) -} - From 5110a6c6f00bba10f4b9259215a21aebb61a968d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Fri, 28 Jun 2024 19:06:22 +0200 Subject: [PATCH 25/36] Update examples/gno.land/r/demo/profile/handlers.gno Co-authored-by: Manfred Touron <94029+moul@users.noreply.github.com> --- examples/gno.land/r/demo/profile/handlers.gno | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gno.land/r/demo/profile/handlers.gno b/examples/gno.land/r/demo/profile/handlers.gno index 8311da53163..ab7d88eee23 100644 --- a/examples/gno.land/r/demo/profile/handlers.gno +++ b/examples/gno.land/r/demo/profile/handlers.gno @@ -29,7 +29,7 @@ func homeHandler(res *mux.ResponseWriter, req *mux.Request) { b.WriteString("[Set %s]
", link, field)) } for field := range intFields { From a857573bad95d55301aa3c38ac486eed404e0ad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Fri, 28 Jun 2024 19:07:48 +0200 Subject: [PATCH 26/36] Update examples/gno.land/r/demo/profile/handlers.gno Co-authored-by: Manfred Touron <94029+moul@users.noreply.github.com> --- examples/gno.land/r/demo/profile/handlers.gno | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gno.land/r/demo/profile/handlers.gno b/examples/gno.land/r/demo/profile/handlers.gno index ab7d88eee23..792001ddc65 100644 --- a/examples/gno.land/r/demo/profile/handlers.gno +++ b/examples/gno.land/r/demo/profile/handlers.gno @@ -102,7 +102,7 @@ func profileHandler(res *mux.ResponseWriter, req *mux.Request) { address := std.Address(addr) for field := range stringFields { - value := GetStringField(address, field, "N/A") + value := GetStringField(address, field, "n/a") link := ufmt.Sprintf(SetStringFieldURL, field) b.WriteString(ufmt.Sprintf("%s: %s [Edit]
", field, value, link)) } From 8f83cfda9079fb29eb840a5c226243ecd2504550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Fri, 28 Jun 2024 19:08:23 +0200 Subject: [PATCH 27/36] Update examples/gno.land/r/demo/profile/profile.gno Co-authored-by: Manfred Touron <94029+moul@users.noreply.github.com> --- examples/gno.land/r/demo/profile/profile.gno | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index b99e1358016..8a614a31222 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -76,7 +76,7 @@ func SetBoolField(field string, value bool) error { return nil } -//Getters +// Getters func GetStringField(addr std.Address, field, def string) string { key := addr.String() + ":" + field From b61da85937568bf5b29fd50f8440d9ad6a303227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Fri, 28 Jun 2024 19:08:37 +0200 Subject: [PATCH 28/36] Update examples/gno.land/r/demo/profile/profile.gno Co-authored-by: Manfred Touron <94029+moul@users.noreply.github.com> --- examples/gno.land/r/demo/profile/profile.gno | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index 8a614a31222..bbf326de98d 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -16,7 +16,7 @@ func init() { router.HandleFunc("f/{addr}/{field}", fieldHandler) } -// list of support string fields +// list of supported string fields var stringFields = map[string]bool{ "DisplayName": true, "Homepage": true, From 214dd6f82176fdedcc898f63c622fa6b554d25e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Fri, 28 Jun 2024 19:09:12 +0200 Subject: [PATCH 29/36] Update examples/gno.land/r/demo/profile/handlers.gno Co-authored-by: Manfred Touron <94029+moul@users.noreply.github.com> --- examples/gno.land/r/demo/profile/handlers.gno | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gno.land/r/demo/profile/handlers.gno b/examples/gno.land/r/demo/profile/handlers.gno index 792001ddc65..39b4b967078 100644 --- a/examples/gno.land/r/demo/profile/handlers.gno +++ b/examples/gno.land/r/demo/profile/handlers.gno @@ -137,7 +137,7 @@ func fieldHandler(res *mux.ResponseWriter, req *mux.Request) { if _, ok := stringFields[field]; ok { value = GetStringField(address, field, "N/A") - editLink = ufmt.Sprintf(SetStringFieldURL+"&addr=%s", field, addr) + editLink = ufmt.Sprintf("%s&addr=%s", SetStringFieldURL, field, addr) } else if _, ok := intFields[field]; ok { value = ufmt.Sprintf("%d", GetIntField(address, field, 0)) editLink = ufmt.Sprintf(SetIntFieldURL+"&addr=%s", field, addr) From 6755ac92c64d1ba544ba57fc71bd4c58a81799bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Sat, 29 Jun 2024 09:00:52 +0200 Subject: [PATCH 30/36] fix: remove Getters call on homeHandler, remove profile display homeHandler and return markdown instead html --- examples/gno.land/r/demo/profile/handlers.gno | 222 +++++++----------- examples/gno.land/r/demo/profile/profile.gno | 81 ++++--- .../gno.land/r/demo/profile/profile_test.gno | 215 +++++++++-------- 3 files changed, 233 insertions(+), 285 deletions(-) diff --git a/examples/gno.land/r/demo/profile/handlers.gno b/examples/gno.land/r/demo/profile/handlers.gno index 39b4b967078..3d51c9b34db 100644 --- a/examples/gno.land/r/demo/profile/handlers.gno +++ b/examples/gno.land/r/demo/profile/handlers.gno @@ -1,154 +1,100 @@ package profile import ( - "bytes" - "gno.land/p/demo/ufmt" - "gno.land/p/demo/mux" - "strings" - "std" + "bytes" + "std" + + "gno.land/p/demo/mux" + "gno.land/p/demo/ufmt" ) const ( - BaseURL = "/r/demo/profile" - SetStringFieldURL = BaseURL + "?help&__func=SetStringField&field=%s" - SetIntFieldURL = BaseURL + "?help&__func=SetIntField&field=%s" - SetBoolFieldURL = BaseURL + "?help&__func=SetBoolField&field=%s" - GetStringFieldURL = BaseURL + "?help&__func=GetStringField&addr=%s" - GetIntFieldURL = BaseURL + "?help&__func=GetIntField&addr=%s" - GetBoolFieldURL = BaseURL + "?help&__func=GetBoolField&addr=%s" - ViewAllFieldsURL = BaseURL + ":u/%s" - ViewFieldURL = BaseURL + ":f/%s/%s" + BaseURL = "/r/demo/profile" + SetStringFieldURL = BaseURL + "?help&__func=SetStringField&field=%s" + SetIntFieldURL = BaseURL + "?help&__func=SetIntField&field=%s" + SetBoolFieldURL = BaseURL + "?help&__func=SetBoolField&field=%s" + ViewAllFieldsURL = BaseURL + ":u/%s" + ViewFieldURL = BaseURL + ":f/%s/%s" + PageSize = 10 // Limit the number of addresses per page ) func homeHandler(res *mux.ResponseWriter, req *mux.Request) { - var b bytes.Buffer - addresses := make(map[string]struct{}) - - b.WriteString("") - b.WriteString("[Set %s]
", link, field)) - } - - for field := range intFields { - link := ufmt.Sprintf(SetIntFieldURL, field) - b.WriteString(ufmt.Sprintf("", link, field)) - } - - for field := range boolFields { - link := ufmt.Sprintf(SetBoolFieldURL, field) - b.WriteString(ufmt.Sprintf("", link, field)) - } - - b.WriteString("--------------------------
") - - fields.Iterate("", "", func(key string, value interface{}) bool { - parts := strings.SplitN(key, ":", 2) - if len(parts) > 0 { - addresses[parts[0]] = struct{}{} - } - return true - }) - - b.WriteString("Address: %s "+ - "[View All Fields] "+ - "[Get String Field] "+ - "[Get Int Field] "+ - "[Get Bool Field]
", - address, ufmt.Sprintf(ViewAllFieldsURL, address), getStringLink, getIntLink, getBoolLink)) - - b.WriteString("--------------------------
") - } - - b.WriteString("") - res.Write(b.String()) + var b bytes.Buffer + + b.WriteString("# Profiles\n") + b.WriteString("## Setters\n") + for field := range stringFields { + link := ufmt.Sprintf(SetStringFieldURL, field) + b.WriteString(ufmt.Sprintf("- [Set %s](%s)\n", field, link)) + } + + for field := range intFields { + link := ufmt.Sprintf(SetIntFieldURL, field) + b.WriteString(ufmt.Sprintf("- [Set %s Field](%s)\n", field, link)) + } + + for field := range boolFields { + link := ufmt.Sprintf(SetBoolFieldURL, field) + b.WriteString(ufmt.Sprintf("- [Set %s Field](%s)\n", field, link)) + } + + b.WriteString("\n---\n\n") + + res.Write(b.String()) } func profileHandler(res *mux.ResponseWriter, req *mux.Request) { - var b bytes.Buffer - addr := req.GetVar("addr") - - b.WriteString("") - b.WriteString(ufmt.Sprintf("%s: %s [Edit]
", field, value, link)) - } - - for field := range intFields { - value := GetIntField(address, field, 0) - link := ufmt.Sprintf(SetIntFieldURL, field) - b.WriteString(ufmt.Sprintf("%s: %d [Edit]
", field, value, link)) - } - - for field := range boolFields { - value := GetBoolField(address, field, false) - link := ufmt.Sprintf(SetBoolFieldURL, field) - b.WriteString(ufmt.Sprintf("%s: %t [Edit]
", field, value, link)) - } - - b.WriteString("") - res.Write(b.String()) + var b bytes.Buffer + addr := req.GetVar("addr") + + b.WriteString(ufmt.Sprintf("# Profile %s\n", addr)) + + address := std.Address(addr) + + for field := range stringFields { + value := GetStringField(address, field, "n/a") + link := ufmt.Sprintf(SetStringFieldURL, field) + b.WriteString(ufmt.Sprintf("- %s: %s [Edit](%s)\n", field, value, link)) + } + + for field := range intFields { + value := GetIntField(address, field, 0) + link := ufmt.Sprintf(SetIntFieldURL, field) + b.WriteString(ufmt.Sprintf("- %s: %d [Edit](%s)\n", field, value, link)) + } + + for field := range boolFields { + value := GetBoolField(address, field, false) + link := ufmt.Sprintf(SetBoolFieldURL, field) + b.WriteString(ufmt.Sprintf("- %s: %t [Edit](%s)\n", field, value, link)) + } + + res.Write(b.String()) } func fieldHandler(res *mux.ResponseWriter, req *mux.Request) { - var b bytes.Buffer - addr := req.GetVar("addr") - field := req.GetVar("field") - - b.WriteString("") - b.WriteString(ufmt.Sprintf("%s: %s [Edit]
", field, value, editLink)) - - b.WriteString("") - res.Write(b.String()) + var b bytes.Buffer + addr := req.GetVar("addr") + field := req.GetVar("field") + + b.WriteString(ufmt.Sprintf("# Field %s for %s\n", field, addr)) + + address := std.Address(addr) + value := "n/a" + var editLink string + + if _, ok := stringFields[field]; ok { + value = GetStringField(address, field, "n/a") + editLink = ufmt.Sprintf("%s&addr=%s", SetStringFieldURL, addr) + } else if _, ok := intFields[field]; ok { + value = ufmt.Sprintf("%d", GetIntField(address, field, 0)) + editLink = ufmt.Sprintf(SetIntFieldURL+"&addr=%s", field, addr) + } else if _, ok := boolFields[field]; ok { + value = ufmt.Sprintf("%t", GetBoolField(address, field, false)) + editLink = ufmt.Sprintf(SetBoolFieldURL+"&addr=%s", field, addr) + } + + b.WriteString(ufmt.Sprintf("- %s: %s [Edit](%s)\n", field, value, editLink)) + + res.Write(b.String()) } - diff --git a/examples/gno.land/r/demo/profile/profile.gno b/examples/gno.land/r/demo/profile/profile.gno index bbf326de98d..d5a64f78a5d 100644 --- a/examples/gno.land/r/demo/profile/profile.gno +++ b/examples/gno.land/r/demo/profile/profile.gno @@ -1,14 +1,17 @@ package profile import ( + "errors" + "std" + "gno.land/p/demo/avl" "gno.land/p/demo/mux" - "std" - "errors" ) -var fields = avl.NewTree() -var router = mux.NewRouter() +var ( + fields = avl.NewTree() + router = mux.NewRouter() +) func init() { router.HandleFunc("", homeHandler) @@ -18,17 +21,17 @@ func init() { // list of supported string fields var stringFields = map[string]bool{ - "DisplayName": true, - "Homepage": true, - "Bio": true, - "Location": true, - "Avatar": true, + "DisplayName": true, + "Homepage": true, + "Bio": true, + "Location": true, + "Avatar": true, "GravatarEmail": true, } // list of support int fields -var intFields = map[string]bool { - "Age": true, +var intFields = map[string]bool{ + "Age": true, } // list of support bool fields @@ -41,39 +44,39 @@ var boolFields = map[string]bool{ func SetStringField(field, value string) error { addr := std.PrevRealm().Addr() if _, ok := stringFields[field]; !ok { - return errors.New("invalid string field") - } - - key := addr.String() + ":" + field + return errors.New("invalid string field") + } + + key := addr.String() + ":" + field fields.Set(key, value) - return nil + return nil } func SetIntField(field string, value int) error { addr := std.PrevRealm().Addr() - - if _, ok := intFields[field]; !ok { - return errors.New("invalid int field") - } - - key := addr.String() + ":" + field + + if _, ok := intFields[field]; !ok { + return errors.New("invalid int field") + } + + key := addr.String() + ":" + field fields.Set(key, value) - - return nil + + return nil } func SetBoolField(field string, value bool) error { addr := std.PrevRealm().Addr() - - if _, ok := boolFields[field]; !ok { - return errors.New("invalid bool field") - } + + if _, ok := boolFields[field]; !ok { + return errors.New("invalid bool field") + } key := addr.String() + ":" + field fields.Set(key, value) - - return nil + + return nil } // Getters @@ -83,28 +86,28 @@ func GetStringField(addr std.Address, field, def string) string { if value, ok := fields.Get(key); ok { return value.(string) } - - return def + + return def } func GetBoolField(addr std.Address, field string, def bool) bool { key := addr.String() + ":" + field if value, ok := fields.Get(key); ok { - return value.(bool) + return value.(bool) } return def } func GetIntField(addr std.Address, field string, def int) int { - key := addr.String() + ":" + field - if value, ok := fields.Get(key); ok { - return value.(int) - } + key := addr.String() + ":" + field + if value, ok := fields.Get(key); ok { + return value.(int) + } - return def + return def } func Render(path string) string { - return router.Render(path) + return router.Render(path) } diff --git a/examples/gno.land/r/demo/profile/profile_test.gno b/examples/gno.land/r/demo/profile/profile_test.gno index 94c73c3198b..aa55db27130 100644 --- a/examples/gno.land/r/demo/profile/profile_test.gno +++ b/examples/gno.land/r/demo/profile/profile_test.gno @@ -1,149 +1,148 @@ package profile import ( - "testing" - "gno.land/p/demo/testutils" - "std" + "std" + "testing" + + "gno.land/p/demo/testutils" ) func TestStringFields(t *testing.T) { - addr := testutils.TestAddress("alice") - std.TestSetRealm(std.NewUserRealm(addr)) - - // Get before setting - name := GetStringField(addr, "DisplayName", "anon") - assertSameString(t, name, "anon") - - // Set - if err := SetStringField("DisplayName", "Alice foo"); err != nil { - t.Errorf("unexpected error: %v", err) - } - if err := SetStringField("Homepage", "https://example.com"); err != nil { - t.Errorf("unexpected error: %v", err) - } - - // Get after setting - name = GetStringField(addr, "DisplayName", "anon") - homepage := GetStringField(addr, "Homepage", "") - bio := GetStringField(addr, "Bio", "42") - - assertSameString(t, name, "Alice foo") - assertSameString(t, homepage, "https://example.com") - assertSameString(t, bio, "42") + addr := testutils.TestAddress("alice") + std.TestSetRealm(std.NewUserRealm(addr)) + + // Get before setting + name := GetStringField(addr, "DisplayName", "anon") + assertSameString(t, name, "anon") + + // Set + if err := SetStringField("DisplayName", "Alice foo"); err != nil { + t.Errorf("unexpected error: %v", err) + } + if err := SetStringField("Homepage", "https://example.com"); err != nil { + t.Errorf("unexpected error: %v", err) + } + + // Get after setting + name = GetStringField(addr, "DisplayName", "anon") + homepage := GetStringField(addr, "Homepage", "") + bio := GetStringField(addr, "Bio", "42") + + assertSameString(t, name, "Alice foo") + assertSameString(t, homepage, "https://example.com") + assertSameString(t, bio, "42") } func TestIntFields(t *testing.T) { - addr := testutils.TestAddress("bob") - std.TestSetRealm(std.NewUserRealm(addr)) + addr := testutils.TestAddress("bob") + std.TestSetRealm(std.NewUserRealm(addr)) - // Get before setting - age := GetIntField(addr, "Age", 25) - assertSameInt(t, age, 25) + // Get before setting + age := GetIntField(addr, "Age", 25) + assertSameInt(t, age, 25) - // Set - if err := SetIntField("Age", 30); err != nil { - t.Errorf("unexpected error: %v", err) - } + // Set + if err := SetIntField("Age", 30); err != nil { + t.Errorf("unexpected error: %v", err) + } - // Get after setting - age = GetIntField(addr, "Age", 25) - assertSameInt(t, age, 30) + // Get after setting + age = GetIntField(addr, "Age", 25) + assertSameInt(t, age, 30) } func TestBoolFields(t *testing.T) { - addr := testutils.TestAddress("charlie") - std.TestSetRealm(std.NewUserRealm(addr)) - - // Get before setting - hiring := GetBoolField(addr, "AvailableForHiring", false) - assertSameBool(t, hiring, false) - - // Set - if err := SetBoolField("AvailableForHiring", true); err != nil { - t.Errorf("unexpected error: %v", err) - } - - // Get after setting - hiring = GetBoolField(addr, "AvailableForHiring", false) - assertSameBool(t, hiring, true) + addr := testutils.TestAddress("charlie") + std.TestSetRealm(std.NewUserRealm(addr)) + + // Get before setting + hiring := GetBoolField(addr, "AvailableForHiring", false) + assertSameBool(t, hiring, false) + + // Set + if err := SetBoolField("AvailableForHiring", true); err != nil { + t.Errorf("unexpected error: %v", err) + } + + // Get after setting + hiring = GetBoolField(addr, "AvailableForHiring", false) + assertSameBool(t, hiring, true) } func TestInvalidStringField(t *testing.T) { - addr := testutils.TestAddress("dave") - std.TestSetRealm(std.NewUserRealm(addr)) + addr := testutils.TestAddress("dave") + std.TestSetRealm(std.NewUserRealm(addr)) - err := SetStringField("InvalidField", "test") - if err == nil { - t.Error("expected error for invalid field, got nil") - } + err := SetStringField("InvalidField", "test") + if err == nil { + t.Error("expected error for invalid field, got nil") + } } func TestInvalidIntField(t *testing.T) { - addr := testutils.TestAddress("eve") - std.TestSetRealm(std.NewUserRealm(addr)) + addr := testutils.TestAddress("eve") + std.TestSetRealm(std.NewUserRealm(addr)) - err := SetIntField("InvalidField", 123) - if err == nil { - t.Error("expected error for invalid field, got nil") - } + err := SetIntField("InvalidField", 123) + if err == nil { + t.Error("expected error for invalid field, got nil") + } } func TestInvalidBoolField(t *testing.T) { - addr := testutils.TestAddress("frank") - std.TestSetRealm(std.NewUserRealm(addr)) + addr := testutils.TestAddress("frank") + std.TestSetRealm(std.NewUserRealm(addr)) - err := SetBoolField("InvalidField", true) - if err == nil { - t.Error("expected error for invalid field, got nil") - } + err := SetBoolField("InvalidField", true) + if err == nil { + t.Error("expected error for invalid field, got nil") + } } func TestMultipleProfiles(t *testing.T) { - addr1 := testutils.TestAddress("user1") - addr2 := testutils.TestAddress("user2") - - // Set profile for addr1 - std.TestSetRealm(std.NewUserRealm(addr1)) - if err := SetStringField("DisplayName", "User One"); err != nil { - t.Errorf("unexpected error: %v", err) - } - - // Set profile for addr2 - std.TestSetRealm(std.NewUserRealm(addr2)) - if err := SetStringField("DisplayName", "User Two"); err != nil { - t.Errorf("unexpected error: %v", err) - } - - // Get profiles - std.TestSetRealm(std.NewUserRealm(addr1)) // Switch back to addr1 - name1 := GetStringField(addr1, "DisplayName", "anon") - std.TestSetRealm(std.NewUserRealm(addr2)) // Switch back to addr2 - name2 := GetStringField(addr2, "DisplayName", "anon") - - assertSameString(t, name1, "User One") - assertSameString(t, name2, "User Two") + addr1 := testutils.TestAddress("user1") + addr2 := testutils.TestAddress("user2") + + // Set profile for addr1 + std.TestSetRealm(std.NewUserRealm(addr1)) + if err := SetStringField("DisplayName", "User One"); err != nil { + t.Errorf("unexpected error: %v", err) + } + + // Set profile for addr2 + std.TestSetRealm(std.NewUserRealm(addr2)) + if err := SetStringField("DisplayName", "User Two"); err != nil { + t.Errorf("unexpected error: %v", err) + } + + // Get profiles + std.TestSetRealm(std.NewUserRealm(addr1)) // Switch back to addr1 + name1 := GetStringField(addr1, "DisplayName", "anon") + std.TestSetRealm(std.NewUserRealm(addr2)) // Switch back to addr2 + name2 := GetStringField(addr2, "DisplayName", "anon") + + assertSameString(t, name1, "User One") + assertSameString(t, name2, "User Two") } - // Assertions helpers func assertSameString(t *testing.T, a, b string) { - t.Helper() - if a != b { - t.Errorf("expected %q, got %q", a, b) - } + t.Helper() + if a != b { + t.Errorf("expected %q, got %q", a, b) + } } func assertSameInt(t *testing.T, a, b int) { - t.Helper() - if a != b { - t.Errorf("expected %d, got %d", a, b) - } + t.Helper() + if a != b { + t.Errorf("expected %d, got %d", a, b) + } } func assertSameBool(t *testing.T, a, b bool) { - t.Helper() - if a != b { - t.Errorf("expected %t, got %t", a, b) - } + t.Helper() + if a != b { + t.Errorf("expected %t, got %t", a, b) + } } - From b30325bfb18768f6c4d258853dc52adae73da97d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Sat, 29 Jun 2024 12:46:21 +0200 Subject: [PATCH 31/36] Update examples/gno.land/r/demo/profile/handlers.gno Co-authored-by: Manfred Touron <94029+moul@users.noreply.github.com> --- examples/gno.land/r/demo/profile/handlers.gno | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gno.land/r/demo/profile/handlers.gno b/examples/gno.land/r/demo/profile/handlers.gno index 3d51c9b34db..65367943e6f 100644 --- a/examples/gno.land/r/demo/profile/handlers.gno +++ b/examples/gno.land/r/demo/profile/handlers.gno @@ -30,7 +30,7 @@ func homeHandler(res *mux.ResponseWriter, req *mux.Request) { for field := range intFields { link := ufmt.Sprintf(SetIntFieldURL, field) - b.WriteString(ufmt.Sprintf("- [Set %s Field](%s)\n", field, link)) + b.WriteString(ufmt.Sprintf("- [Set %s](%s)\n", field, link)) } for field := range boolFields { From 8631c48d69dd58a203cc4e0b8f1d1486416ca8af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Sat, 29 Jun 2024 12:46:41 +0200 Subject: [PATCH 32/36] Update examples/gno.land/r/demo/profile/handlers.gno Co-authored-by: Manfred Touron <94029+moul@users.noreply.github.com> --- examples/gno.land/r/demo/profile/handlers.gno | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/gno.land/r/demo/profile/handlers.gno b/examples/gno.land/r/demo/profile/handlers.gno index 65367943e6f..fb74116eab7 100644 --- a/examples/gno.land/r/demo/profile/handlers.gno +++ b/examples/gno.land/r/demo/profile/handlers.gno @@ -21,7 +21,6 @@ const ( func homeHandler(res *mux.ResponseWriter, req *mux.Request) { var b bytes.Buffer - b.WriteString("# Profiles\n") b.WriteString("## Setters\n") for field := range stringFields { link := ufmt.Sprintf(SetStringFieldURL, field) From f7ff18c523e210d7ebac292bf6b0e3a4ff1d89c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaza=C3=AF?= <149690535+kazai777@users.noreply.github.com> Date: Sat, 29 Jun 2024 12:58:12 +0200 Subject: [PATCH 33/36] refactor: i used constants for they keys --- .../gno.land/r/demo/profile/profile_test.gno | 47 +++++++++++-------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/examples/gno.land/r/demo/profile/profile_test.gno b/examples/gno.land/r/demo/profile/profile_test.gno index aa55db27130..d5cf5ddada4 100644 --- a/examples/gno.land/r/demo/profile/profile_test.gno +++ b/examples/gno.land/r/demo/profile/profile_test.gno @@ -7,26 +7,35 @@ import ( "gno.land/p/demo/testutils" ) +const ( + DisplayName = "DisplayName" + Homepage = "Homepage" + Bio = "Bio" + Age = "Age" + AvailableForHiring = "AvailableForHiring" + InvalidField = "InvalidField" +) + func TestStringFields(t *testing.T) { addr := testutils.TestAddress("alice") std.TestSetRealm(std.NewUserRealm(addr)) // Get before setting - name := GetStringField(addr, "DisplayName", "anon") + name := GetStringField(addr, DisplayName, "anon") assertSameString(t, name, "anon") // Set - if err := SetStringField("DisplayName", "Alice foo"); err != nil { + if err := SetStringField(DisplayName, "Alice foo"); err != nil { t.Errorf("unexpected error: %v", err) } - if err := SetStringField("Homepage", "https://example.com"); err != nil { + if err := SetStringField(Homepage, "https://example.com"); err != nil { t.Errorf("unexpected error: %v", err) } // Get after setting - name = GetStringField(addr, "DisplayName", "anon") - homepage := GetStringField(addr, "Homepage", "") - bio := GetStringField(addr, "Bio", "42") + name = GetStringField(addr, DisplayName, "anon") + homepage := GetStringField(addr, Homepage, "") + bio := GetStringField(addr, Bio, "42") assertSameString(t, name, "Alice foo") assertSameString(t, homepage, "https://example.com") @@ -38,16 +47,16 @@ func TestIntFields(t *testing.T) { std.TestSetRealm(std.NewUserRealm(addr)) // Get before setting - age := GetIntField(addr, "Age", 25) + age := GetIntField(addr, Age, 25) assertSameInt(t, age, 25) // Set - if err := SetIntField("Age", 30); err != nil { + if err := SetIntField(Age, 30); err != nil { t.Errorf("unexpected error: %v", err) } // Get after setting - age = GetIntField(addr, "Age", 25) + age = GetIntField(addr, Age, 25) assertSameInt(t, age, 30) } @@ -56,16 +65,16 @@ func TestBoolFields(t *testing.T) { std.TestSetRealm(std.NewUserRealm(addr)) // Get before setting - hiring := GetBoolField(addr, "AvailableForHiring", false) + hiring := GetBoolField(addr, AvailableForHiring, false) assertSameBool(t, hiring, false) // Set - if err := SetBoolField("AvailableForHiring", true); err != nil { + if err := SetBoolField(AvailableForHiring, true); err != nil { t.Errorf("unexpected error: %v", err) } // Get after setting - hiring = GetBoolField(addr, "AvailableForHiring", false) + hiring = GetBoolField(addr, AvailableForHiring, false) assertSameBool(t, hiring, true) } @@ -73,7 +82,7 @@ func TestInvalidStringField(t *testing.T) { addr := testutils.TestAddress("dave") std.TestSetRealm(std.NewUserRealm(addr)) - err := SetStringField("InvalidField", "test") + err := SetStringField(InvalidField, "test") if err == nil { t.Error("expected error for invalid field, got nil") } @@ -83,7 +92,7 @@ func TestInvalidIntField(t *testing.T) { addr := testutils.TestAddress("eve") std.TestSetRealm(std.NewUserRealm(addr)) - err := SetIntField("InvalidField", 123) + err := SetIntField(InvalidField, 123) if err == nil { t.Error("expected error for invalid field, got nil") } @@ -93,7 +102,7 @@ func TestInvalidBoolField(t *testing.T) { addr := testutils.TestAddress("frank") std.TestSetRealm(std.NewUserRealm(addr)) - err := SetBoolField("InvalidField", true) + err := SetBoolField(InvalidField, true) if err == nil { t.Error("expected error for invalid field, got nil") } @@ -105,21 +114,21 @@ func TestMultipleProfiles(t *testing.T) { // Set profile for addr1 std.TestSetRealm(std.NewUserRealm(addr1)) - if err := SetStringField("DisplayName", "User One"); err != nil { + if err := SetStringField(DisplayName, "User One"); err != nil { t.Errorf("unexpected error: %v", err) } // Set profile for addr2 std.TestSetRealm(std.NewUserRealm(addr2)) - if err := SetStringField("DisplayName", "User Two"); err != nil { + if err := SetStringField(DisplayName, "User Two"); err != nil { t.Errorf("unexpected error: %v", err) } // Get profiles std.TestSetRealm(std.NewUserRealm(addr1)) // Switch back to addr1 - name1 := GetStringField(addr1, "DisplayName", "anon") + name1 := GetStringField(addr1, DisplayName, "anon") std.TestSetRealm(std.NewUserRealm(addr2)) // Switch back to addr2 - name2 := GetStringField(addr2, "DisplayName", "anon") + name2 := GetStringField(addr2, DisplayName, "anon") assertSameString(t, name1, "User One") assertSameString(t, name2, "User Two") From fadbc59ffcdaa3b38bec6606df64f86712b5edca Mon Sep 17 00:00:00 2001 From: Kazai777