Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: r/profile dapp #1983

Merged
merged 46 commits into from
Jul 14, 2024
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
e73da9b
profile realm
kazai777 Apr 25, 2024
f98cafa
panic message start with lowercase letter
kazai777 May 8, 2024
9c6b768
add mapping comment
kazai777 May 9, 2024
5f29419
modify comparison
kazai777 May 9, 2024
bf3b0dd
replace return and bool by panic
kazai777 May 9, 2024
3796c3c
modify name of function and replace return by panic
kazai777 May 9, 2024
4770d4b
replace return by panic
kazai777 May 9, 2024
f13d0d6
add emit
kazai777 May 12, 2024
a0b7975
Merge branch 'gnolang:master' into addprofile
kazai777 May 13, 2024
38b5439
remove unnecessary condition
kazai777 May 13, 2024
d1c108c
displaymodificationhistory simplified
kazai777 May 14, 2024
69173f8
Merge branch 'master' into addprofile
kazai777 May 14, 2024
a0a1027
add mux for routing
kazai777 May 14, 2024
21f6ccb
remove old username in avl tree after update username
kazai777 May 14, 2024
e78e0bc
make tidy
kazai777 May 14, 2024
9b87d58
add link in profile page and hisotry page
kazai777 May 14, 2024
3db2185
Merge branch 'master' into addprofile
kazai777 May 15, 2024
208b913
Merge branch 'master' into addprofile
kazai777 Jun 3, 2024
61bdfc2
add an avl.tree to add multiple websites
kazai777 Jun 18, 2024
8793a51
add std.Emit with the changes made in UpdateProfile
kazai777 Jun 18, 2024
6fac788
renaming getter functions with the Get prefix
kazai777 Jun 18, 2024
19d5b23
Refactoring v0.1
kazai777 Jun 21, 2024
bec9bcb
remove no used contextKey
kazai777 Jun 21, 2024
8a66188
mod
kazai777 Jun 21, 2024
f38eb7f
refactor, adding minimal getters and setters
kazai777 Jun 24, 2024
51d5577
whitout test, whitout render refactoring
kazai777 Jun 24, 2024
57fd874
add unit test
Jun 25, 2024
2c962ca
clean code and refactoring handlers
kazai777 Jun 25, 2024
7101443
Merge branch 'master' into addprofile
kazai777 Jun 25, 2024
5110a6c
Update examples/gno.land/r/demo/profile/handlers.gno
kazai777 Jun 28, 2024
a857573
Update examples/gno.land/r/demo/profile/handlers.gno
kazai777 Jun 28, 2024
8f83cfd
Update examples/gno.land/r/demo/profile/profile.gno
kazai777 Jun 28, 2024
b61da85
Update examples/gno.land/r/demo/profile/profile.gno
kazai777 Jun 28, 2024
214dd6f
Update examples/gno.land/r/demo/profile/handlers.gno
kazai777 Jun 28, 2024
6755ac9
fix: remove Getters call on homeHandler, remove profile display homeH…
kazai777 Jun 29, 2024
52a0e4b
Merge branch 'master' into addprofile
kazai777 Jun 29, 2024
b30325b
Update examples/gno.land/r/demo/profile/handlers.gno
kazai777 Jun 29, 2024
8631c48
Update examples/gno.land/r/demo/profile/handlers.gno
kazai777 Jun 29, 2024
f7ff18c
refactor: i used constants for they keys
kazai777 Jun 29, 2024
a3795fb
Merge branch 'master' into addprofile
moul Jul 4, 2024
fadbc59
fix: move constant on the profile file, rename file handlers by rende…
kazai777 Jul 8, 2024
5789de8
refactor: testfile with new uassert function, global declaration for …
kazai777 Jul 8, 2024
cea8dee
make tidy
kazai777 Jul 8, 2024
0869813
Merge branch 'master' into addprofile
kazai777 Jul 8, 2024
f51af5f
Merge branch 'master' into addprofile
leohhhn Jul 13, 2024
2c27587
Merge branch 'master' into addprofile
moul Jul 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions examples/gno.land/r/demo/profile/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
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/testutils v0.0.0-latest
gno.land/p/demo/ufmt v0.0.0-latest
)
99 changes: 99 additions & 0 deletions examples/gno.land/r/demo/profile/handlers.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package profile
kazai777 marked this conversation as resolved.
Show resolved Hide resolved

import (
"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"
ViewAllFieldsURL = BaseURL + ":u/%s"
ViewFieldURL = BaseURL + ":f/%s/%s"
PageSize = 10 // Limit the number of addresses per page
kazai777 marked this conversation as resolved.
Show resolved Hide resolved
)

func homeHandler(res *mux.ResponseWriter, req *mux.Request) {
var b bytes.Buffer

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](%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(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(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)
kazai777 marked this conversation as resolved.
Show resolved Hide resolved
} 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())
}
113 changes: 113 additions & 0 deletions examples/gno.land/r/demo/profile/profile.gno
kazai777 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package profile

import (
"errors"
"std"

"gno.land/p/demo/avl"
"gno.land/p/demo/mux"
)

var (
fields = avl.NewTree()
router = mux.NewRouter()
)

func init() {
router.HandleFunc("", homeHandler)
router.HandleFunc("u/{addr}", profileHandler)
router.HandleFunc("f/{addr}/{field}", fieldHandler)
}

// list of supported string fields
var stringFields = map[string]bool{
"DisplayName": true,
kazai777 marked this conversation as resolved.
Show resolved Hide resolved
"Homepage": true,
"Bio": true,
"Location": true,
"Avatar": true,
"GravatarEmail": true,
}

// list of support int fields
var intFields = map[string]bool{
"Age": true,
}

// list of support bool fields
var boolFields = map[string]bool{
"AvailableForHiring": true,
}

// Setters

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)

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
fields.Set(key, 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
}

// Getters

func GetStringField(addr std.Address, field, def string) string {
key := addr.String() + ":" + field
if value, ok := fields.Get(key); ok {
return value.(string)
}

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 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)
}

return def
}

func Render(path string) string {
return router.Render(path)
}
157 changes: 157 additions & 0 deletions examples/gno.land/r/demo/profile/profile_test.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package profile

import (
"std"
"testing"

"gno.land/p/demo/testutils"
)

const (
DisplayName = "DisplayName"
Homepage = "Homepage"
Bio = "Bio"
Age = "Age"
AvailableForHiring = "AvailableForHiring"
InvalidField = "InvalidField"
)
kazai777 marked this conversation as resolved.
Show resolved Hide resolved

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")
}

func TestIntFields(t *testing.T) {
addr := testutils.TestAddress("bob")
std.TestSetRealm(std.NewUserRealm(addr))

// 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)
kazai777 marked this conversation as resolved.
Show resolved Hide resolved
}

// Get after setting
age = GetIntField(addr, Age, 25)
assertSameInt(t, age, 30)
kazai777 marked this conversation as resolved.
Show resolved Hide resolved
}

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)
}

func TestInvalidStringField(t *testing.T) {
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")
}
}

func TestInvalidIntField(t *testing.T) {
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")
}
}

func TestInvalidBoolField(t *testing.T) {
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")
}
}

func TestMultipleProfiles(t *testing.T) {
addr1 := testutils.TestAddress("user1")
addr2 := testutils.TestAddress("user2")
kazai777 marked this conversation as resolved.
Show resolved Hide resolved

// 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)
}
}

func assertSameInt(t *testing.T, a, b int) {
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)
}
}
Loading