From 0291828630ea0fbba937facde41a27c4a1545ce0 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Mon, 9 May 2022 15:32:06 +0000 Subject: [PATCH 1/4] feat: initial r/profile dapp Signed-off-by: Manfred Touron <94029+moul@users.noreply.github.com> --- .../gno.land/r/profile/integration0_test.gno | 13 +++++ examples/gno.land/r/profile/profile.gno | 54 +++++++++++++++++++ examples/gno.land/r/profile/profiles.gno | 53 ++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 examples/gno.land/r/profile/integration0_test.gno create mode 100644 examples/gno.land/r/profile/profile.gno create mode 100644 examples/gno.land/r/profile/profiles.gno diff --git a/examples/gno.land/r/profile/integration0_test.gno b/examples/gno.land/r/profile/integration0_test.gno new file mode 100644 index 00000000000..a42682fb15b --- /dev/null +++ b/examples/gno.land/r/profile/integration0_test.gno @@ -0,0 +1,13 @@ +package main + +import ( + "fmt" + + "gno.land/r/profile" +) + +func main() { + fmt.Println("test") +} + +// Output: diff --git a/examples/gno.land/r/profile/profile.gno b/examples/gno.land/r/profile/profile.gno new file mode 100644 index 00000000000..7702377b487 --- /dev/null +++ b/examples/gno.land/r/profile/profile.gno @@ -0,0 +1,54 @@ +package profile + +import ( + "std" + + "gno.land/r/users" +) + +func newProfile(addr std.Address) *Profile { + now := std.GetTime() + return &Profile{ + address: addr, + created: now, + } +} + +type Profile struct { + dict map[string]interface{} + address std.Address + created uint64 + updated uint64 +} + +func (p *Profile) save() { + now := std.GetTime() + if p.created == 0 { + p.created = now + } + p.updated = now +} + +func (p *Profile) update(dict map[string]interface{}) { + for k, v := range dict { + // TODO: additional checks here + if k == "address" || k == "created" || k == "updated" { + panic("reserved profile key") + } + p.dict[k] = v + } + p.save() +} + +func (p *Profile) Render() string { + output := "" + output += ufmt.Sprintf("* address: %q\n", p.address) + output += ufmt.Sprintf("* created: %v\n", p.created) + if p.updated > 0 { + output += ufmt.Sprintf("* updated: %v\n", p.updated) + } + for k, v := range p.dict { + output += ufmt.Sprintf("* %s: %v\n", k, v) + } + return output +} diff --git a/examples/gno.land/r/profile/profiles.gno b/examples/gno.land/r/profile/profiles.gno new file mode 100644 index 00000000000..89d929f38d9 --- /dev/null +++ b/examples/gno.land/r/profile/profiles.gno @@ -0,0 +1,53 @@ +package profile + +import ( + "std" + + "gno.land/r/users" +) + +// TODO: makes sense to implement an allowance system? + +var profiles *avl.MutTree // std.Address.String() -> *Profile + +func Update(dict map[string]interface{}) { + currentUser := std.GetOrigCaller() + profile := getOrCreateProfileByAddress(currentUser) + profile.update(dict) +} + +func GetByAddressOrName(aon users.AddressOrName) *Profile { + return profiles.Get(aon) +} + +func getOrCreateProfileByAddress(aon users.AddressOrName) *Profile { + // lookup existing profile + profile := profiles.Get(aon) + if profile != nil { + return profile + } + + // create + addr := aon.Resolve() + newProfile := &Profile{address: addr} + profiles.Set(addr, newProfile) + return newProfile +} + +func Render(path string) string { + parts := strings.Split(path, "/") + + switch { + case path == "": + output := ufmt.Sprintf("stats: %d known profiles\n", profiles.Size()) + return output + case len(parts) == 1: + profile := GetByAddressOrName(parts[0]) + if profile != nil { + return profile.Render() + } + return "404: no such profile" + } + + return "404: invalid URL" +} From 42457571cc17ed1431c782d71fd0db71d8836e7d Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Mon, 9 May 2022 15:45:59 +0000 Subject: [PATCH 2/4] chore: fixup Signed-off-by: Manfred Touron <94029+moul@users.noreply.github.com> --- examples/gno.land/r/profile/integration0_test.gno | 3 +++ examples/gno.land/r/profile/profile.gno | 4 ++++ examples/gno.land/r/profile/profiles.gno | 1 + 3 files changed, 8 insertions(+) diff --git a/examples/gno.land/r/profile/integration0_test.gno b/examples/gno.land/r/profile/integration0_test.gno index a42682fb15b..a1af5c47292 100644 --- a/examples/gno.land/r/profile/integration0_test.gno +++ b/examples/gno.land/r/profile/integration0_test.gno @@ -8,6 +8,9 @@ import ( func main() { fmt.Println("test") + // various data types + // avatar + // ip address } // Output: diff --git a/examples/gno.land/r/profile/profile.gno b/examples/gno.land/r/profile/profile.gno index 7702377b487..fc2374fc847 100644 --- a/examples/gno.land/r/profile/profile.gno +++ b/examples/gno.land/r/profile/profile.gno @@ -6,6 +6,8 @@ import ( "gno.land/r/users" ) +// FIXME: manage privacy? + func newProfile(addr std.Address) *Profile { now := std.GetTime() return &Profile{ @@ -32,6 +34,8 @@ func (p *Profile) save() { func (p *Profile) update(dict map[string]interface{}) { for k, v := range dict { // TODO: additional checks here + // TODO: check v.Type() + // TODO: check v.Len() if k == "address" || k == "created" || k == "updated" { panic("reserved profile key") } diff --git a/examples/gno.land/r/profile/profiles.gno b/examples/gno.land/r/profile/profiles.gno index 89d929f38d9..d0a218607c2 100644 --- a/examples/gno.land/r/profile/profiles.gno +++ b/examples/gno.land/r/profile/profiles.gno @@ -11,6 +11,7 @@ import ( var profiles *avl.MutTree // std.Address.String() -> *Profile func Update(dict map[string]interface{}) { + // FIXME: ask a price per stored data length? currentUser := std.GetOrigCaller() profile := getOrCreateProfileByAddress(currentUser) profile.update(dict) From a274f858b9b23330b86908afaaffb7787eed9a4c Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Thu, 12 May 2022 12:15:04 +0000 Subject: [PATCH 3/4] chore: fixup Signed-off-by: Manfred Touron <94029+moul@users.noreply.github.com> --- ...on0_test.gno => integration0_filetest.gno} | 6 ++-- examples/gno.land/r/profile/profile.gno | 11 ++++---- examples/gno.land/r/profile/profiles.gno | 28 +++++++++++++------ 3 files changed, 29 insertions(+), 16 deletions(-) rename examples/gno.land/r/profile/{integration0_test.gno => integration0_filetest.gno} (69%) diff --git a/examples/gno.land/r/profile/integration0_test.gno b/examples/gno.land/r/profile/integration0_filetest.gno similarity index 69% rename from examples/gno.land/r/profile/integration0_test.gno rename to examples/gno.land/r/profile/integration0_filetest.gno index a1af5c47292..0129fb1a7c5 100644 --- a/examples/gno.land/r/profile/integration0_test.gno +++ b/examples/gno.land/r/profile/integration0_filetest.gno @@ -1,16 +1,16 @@ package main import ( - "fmt" - "gno.land/r/profile" ) func main() { - fmt.Println("test") + println(profile.Render("")) + //_ = profile.Render // various data types // avatar // ip address } // Output: +// a diff --git a/examples/gno.land/r/profile/profile.gno b/examples/gno.land/r/profile/profile.gno index fc2374fc847..5080cd72964 100644 --- a/examples/gno.land/r/profile/profile.gno +++ b/examples/gno.land/r/profile/profile.gno @@ -3,13 +3,14 @@ package profile import ( "std" - "gno.land/r/users" + "gno.land/p/ufmt" + // "gno.land/r/users" ) // FIXME: manage privacy? func newProfile(addr std.Address) *Profile { - now := std.GetTime() + now := std.GetTimestamp() return &Profile{ address: addr, created: now, @@ -19,12 +20,12 @@ func newProfile(addr std.Address) *Profile { type Profile struct { dict map[string]interface{} address std.Address - created uint64 - updated uint64 + created std.Time + updated std.Time } func (p *Profile) save() { - now := std.GetTime() + now := std.GetTimestamp() if p.created == 0 { p.created = now } diff --git a/examples/gno.land/r/profile/profiles.gno b/examples/gno.land/r/profile/profiles.gno index d0a218607c2..e1b2a1877a1 100644 --- a/examples/gno.land/r/profile/profiles.gno +++ b/examples/gno.land/r/profile/profiles.gno @@ -2,7 +2,10 @@ package profile import ( "std" + "strings" + "gno.land/p/avl" + "gno.land/p/ufmt" "gno.land/r/users" ) @@ -10,6 +13,10 @@ import ( var profiles *avl.MutTree // std.Address.String() -> *Profile +func init() { + // profiles = avl.NewMutTree() +} + func Update(dict map[string]interface{}) { // FIXME: ask a price per stored data length? currentUser := std.GetOrigCaller() @@ -18,20 +25,24 @@ func Update(dict map[string]interface{}) { } func GetByAddressOrName(aon users.AddressOrName) *Profile { - return profiles.Get(aon) + addr := aon.Resolve() + profile, found := profiles.Get(addr.String()) + if !found { + return nil + } + return profile.(*Profile) } -func getOrCreateProfileByAddress(aon users.AddressOrName) *Profile { +func getOrCreateProfileByAddress(addr std.Address) *Profile { // lookup existing profile - profile := profiles.Get(aon) - if profile != nil { - return profile + profile, found := profiles.Get(addr.String()) + if found { + return profile.(*Profile) } // create - addr := aon.Resolve() newProfile := &Profile{address: addr} - profiles.Set(addr, newProfile) + profiles.Set(addr.String(), newProfile) return newProfile } @@ -43,7 +54,8 @@ func Render(path string) string { output := ufmt.Sprintf("stats: %d known profiles\n", profiles.Size()) return output case len(parts) == 1: - profile := GetByAddressOrName(parts[0]) + aon := users.AddressOrName(parts[0]) + profile := GetByAddressOrName(aon) if profile != nil { return profile.Render() } From 7dd00477eafa5096ffae7b52bd83c1d2db79571c Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Sat, 28 May 2022 22:12:17 +0000 Subject: [PATCH 4/4] chore: switch to unit tests Signed-off-by: Manfred Touron <94029+moul@users.noreply.github.com> --- .../r/profile/integration0_filetest.gno | 16 ---------------- examples/gno.land/r/profile/profiles_test.gno | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 16 deletions(-) delete mode 100644 examples/gno.land/r/profile/integration0_filetest.gno create mode 100644 examples/gno.land/r/profile/profiles_test.gno diff --git a/examples/gno.land/r/profile/integration0_filetest.gno b/examples/gno.land/r/profile/integration0_filetest.gno deleted file mode 100644 index 0129fb1a7c5..00000000000 --- a/examples/gno.land/r/profile/integration0_filetest.gno +++ /dev/null @@ -1,16 +0,0 @@ -package main - -import ( - "gno.land/r/profile" -) - -func main() { - println(profile.Render("")) - //_ = profile.Render - // various data types - // avatar - // ip address -} - -// Output: -// a diff --git a/examples/gno.land/r/profile/profiles_test.gno b/examples/gno.land/r/profile/profiles_test.gno new file mode 100644 index 00000000000..6792a250c75 --- /dev/null +++ b/examples/gno.land/r/profile/profiles_test.gno @@ -0,0 +1,17 @@ +package profile + +import ( + "fmt" + "testing" + + "gno.land/r/profile" +) + +func TestRender(t *testing.T) { + got := profile.Render("") + fmt.Println(got) + //_ = profile.Render + // various data types + // avatar + // ip address +}