From b55e295fb9390a2b91ad24918f5e7df8708c1029 Mon Sep 17 00:00:00 2001 From: mous1985 Date: Mon, 23 Dec 2024 18:39:16 +0100 Subject: [PATCH 01/27] first commit --- examples/gno.land/r/mouss/config/config.gno | 46 +++++++++++++++++++ .../gno.land/r/mouss/config/config_test.gno | 1 + examples/gno.land/r/mouss/config/gno.mod | 1 + examples/gno.land/r/mouss/home/home.gno | 0 4 files changed, 48 insertions(+) create mode 100644 examples/gno.land/r/mouss/config/config.gno create mode 100644 examples/gno.land/r/mouss/config/config_test.gno create mode 100644 examples/gno.land/r/mouss/config/gno.mod create mode 100644 examples/gno.land/r/mouss/home/home.gno diff --git a/examples/gno.land/r/mouss/config/config.gno b/examples/gno.land/r/mouss/config/config.gno new file mode 100644 index 00000000000..1f9e323cf3f --- /dev/null +++ b/examples/gno.land/r/mouss/config/config.gno @@ -0,0 +1,46 @@ +package config + +import ( + "errors" + "std" +) + +var ( + main std.Address // mouss's main address + backup std.Address // backup address + + errorInvalidAddr = errors.New("config: invalid address") + errorUnauthorized = errors.New("config: unauthorized") +) + +func init() { + main = "g1hrfvdh7jdvnlxpk2y20tp3scj9jqal3zzu7wjz" +} +func Address() std.Address { + return main +} + +func Backup() std.Address { + return backup +} +func SetBackup(newAddress std.Address) error { + if !newAddress.IsValid() { + return errorInvalidAddr + } + + if err := checkAuthorized(); err != nil { + return err + } + + backup = newAddress + return nil +} + +func checkAuthorized() error { + caller := std.GetOrigCaller() + if caller != main && caller != backup { + return errorUnauthorized + } + + return nil +} diff --git a/examples/gno.land/r/mouss/config/config_test.gno b/examples/gno.land/r/mouss/config/config_test.gno new file mode 100644 index 00000000000..d912156bec0 --- /dev/null +++ b/examples/gno.land/r/mouss/config/config_test.gno @@ -0,0 +1 @@ +package config diff --git a/examples/gno.land/r/mouss/config/gno.mod b/examples/gno.land/r/mouss/config/gno.mod new file mode 100644 index 00000000000..33b71de8f2c --- /dev/null +++ b/examples/gno.land/r/mouss/config/gno.mod @@ -0,0 +1 @@ +module gno.land/r/mouss/config diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno new file mode 100644 index 00000000000..e69de29bb2d From 4cc78200701997d8375d3dac0a34dda149acd1c3 Mon Sep 17 00:00:00 2001 From: mous1985 Date: Tue, 7 Jan 2025 16:57:49 +0100 Subject: [PATCH 02/27] fix: import --- examples/gno.land/r/mouss/aboutme/aboutme.gno | 14 +++++ examples/gno.land/r/mouss/aboutme/gno.mod | 1 + examples/gno.land/r/mouss/config/config.gno | 6 +- examples/gno.land/r/mouss/home/gno.mod | 2 + examples/gno.land/r/mouss/home/home.gno | 56 +++++++++++++++++++ 5 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 examples/gno.land/r/mouss/aboutme/aboutme.gno create mode 100644 examples/gno.land/r/mouss/aboutme/gno.mod create mode 100644 examples/gno.land/r/mouss/home/gno.mod diff --git a/examples/gno.land/r/mouss/aboutme/aboutme.gno b/examples/gno.land/r/mouss/aboutme/aboutme.gno new file mode 100644 index 00000000000..8b79d5df199 --- /dev/null +++ b/examples/gno.land/r/mouss/aboutme/aboutme.gno @@ -0,0 +1,14 @@ +package aboutme + +import ( + "gno.land/p/demo/mux" +) + +var abtMe string + +func init() { + abtMe = "Hi, I'm Mustapha, a contributor to gno.land." +} +func renderAboutMe(res *mux.ResponseWriter, req *mux.Request) { + res.Write(abtMe) +} diff --git a/examples/gno.land/r/mouss/aboutme/gno.mod b/examples/gno.land/r/mouss/aboutme/gno.mod new file mode 100644 index 00000000000..5a668f63f00 --- /dev/null +++ b/examples/gno.land/r/mouss/aboutme/gno.mod @@ -0,0 +1 @@ +module gno.land/r/mouss/aboutme diff --git a/examples/gno.land/r/mouss/config/config.gno b/examples/gno.land/r/mouss/config/config.gno index 1f9e323cf3f..2e11dbf91a8 100644 --- a/examples/gno.land/r/mouss/config/config.gno +++ b/examples/gno.land/r/mouss/config/config.gno @@ -23,8 +23,8 @@ func Address() std.Address { func Backup() std.Address { return backup } -func SetBackup(newAddress std.Address) error { - if !newAddress.IsValid() { +func SetBack(buAddress std.Address) error { + if !buAddress.IsValid() { return errorInvalidAddr } @@ -32,7 +32,7 @@ func SetBackup(newAddress std.Address) error { return err } - backup = newAddress + backup = buAddress return nil } diff --git a/examples/gno.land/r/mouss/home/gno.mod b/examples/gno.land/r/mouss/home/gno.mod new file mode 100644 index 00000000000..3b2e6e0587d --- /dev/null +++ b/examples/gno.land/r/mouss/home/gno.mod @@ -0,0 +1,2 @@ +module gno.land/r/mouss/home + diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno index e69de29bb2d..8d1968bac54 100644 --- a/examples/gno.land/r/mouss/home/home.gno +++ b/examples/gno.land/r/mouss/home/home.gno @@ -0,0 +1,56 @@ +package home + +import ( + "bytes" + + "gno.land/p/demo/mux" +) + +var ( + router = mux.NewRouter() +) + +const ( + RealmURL = "/r/mouss/home" +) + +func init() { + router.HandleFunc("", renderHomepage) + router.HandleFunc("/abtMe", aboutme.renderAboutMe) + +} + +func renderHomepage(res *mux.ResponseWriter, req *mux.Request) { + var b bytes.Buffer + + b.WriteString("[Home]() | [About Me](aboutMe) | [Hackerspace](https://github.com/gnolang/hackerspace/issues/86#issuecomment-2535795751)\n\n") + b.WriteString("--------------------------------\n\n") + b.WriteString("```\n") + for _, line := range gnoArt() { + b.WriteString(line) + b.WriteString("\n") + } + b.WriteString("```\n") + b.WriteString("--------------------------------") + + res.Write(b.String()) +} + +func gnoArt() []string { + return []string{ + " -==++. ", + " *@@@@= @- -@", + " #@@@@@: -==-.-- :-::===: .-++-. @- .===:.- .-.-==- .===:=@", + " #@@@@@@@: -@@%**%@@ #@@#*#@@- *@@**@@* @- +%=::-*@ +@=-:-@* +%=::-*@", + "+@%#**#%@@ %@+ :@@ *@+ #@=+@% %@+ @= :@: -@ +% +%.@: -@", + "-: - *@%:..+@@ *@+ #@=-@@: :@@= @- .@= =@ +@ *%.@= =@", + "--:==+=-:=. =%@%#*@@ *@+ #@+ =%@%%@%= #* %#=.:%*===*@ +% +% -%*===*@", + "-++++=++++. =-:::*@# . . .::. .. :: .:: . . .:: .", + " .-=+++=: .*###%#= ", + " :: ", + } +} + +func Render(path string) string { + return router.Render(path) +} From 51f75c660837b854e2b0598ef5676932507fde66 Mon Sep 17 00:00:00 2001 From: mous1985 Date: Wed, 8 Jan 2025 06:02:41 +0100 Subject: [PATCH 03/27] simple home-page --- examples/gno.land/r/mouss/aboutme/aboutme.gno | 14 ----- examples/gno.land/r/mouss/aboutme/gno.mod | 1 - examples/gno.land/r/mouss/config/config.gno | 8 +-- examples/gno.land/r/mouss/home/gno.mod | 1 - examples/gno.land/r/mouss/home/home.gno | 62 +++++++++++++++++-- 5 files changed, 60 insertions(+), 26 deletions(-) delete mode 100644 examples/gno.land/r/mouss/aboutme/aboutme.gno delete mode 100644 examples/gno.land/r/mouss/aboutme/gno.mod diff --git a/examples/gno.land/r/mouss/aboutme/aboutme.gno b/examples/gno.land/r/mouss/aboutme/aboutme.gno deleted file mode 100644 index 8b79d5df199..00000000000 --- a/examples/gno.land/r/mouss/aboutme/aboutme.gno +++ /dev/null @@ -1,14 +0,0 @@ -package aboutme - -import ( - "gno.land/p/demo/mux" -) - -var abtMe string - -func init() { - abtMe = "Hi, I'm Mustapha, a contributor to gno.land." -} -func renderAboutMe(res *mux.ResponseWriter, req *mux.Request) { - res.Write(abtMe) -} diff --git a/examples/gno.land/r/mouss/aboutme/gno.mod b/examples/gno.land/r/mouss/aboutme/gno.mod deleted file mode 100644 index 5a668f63f00..00000000000 --- a/examples/gno.land/r/mouss/aboutme/gno.mod +++ /dev/null @@ -1 +0,0 @@ -module gno.land/r/mouss/aboutme diff --git a/examples/gno.land/r/mouss/config/config.gno b/examples/gno.land/r/mouss/config/config.gno index 2e11dbf91a8..8a7c6cfa6a2 100644 --- a/examples/gno.land/r/mouss/config/config.gno +++ b/examples/gno.land/r/mouss/config/config.gno @@ -9,8 +9,8 @@ var ( main std.Address // mouss's main address backup std.Address // backup address - errorInvalidAddr = errors.New("config: invalid address") - errorUnauthorized = errors.New("config: unauthorized") + ErrorInvalidAddr = errors.New("config: invalid address") + ErrorUnauthorized = errors.New("config: unauthorized") ) func init() { @@ -25,7 +25,7 @@ func Backup() std.Address { } func SetBack(buAddress std.Address) error { if !buAddress.IsValid() { - return errorInvalidAddr + return ErrorInvalidAddr } if err := checkAuthorized(); err != nil { @@ -39,7 +39,7 @@ func SetBack(buAddress std.Address) error { func checkAuthorized() error { caller := std.GetOrigCaller() if caller != main && caller != backup { - return errorUnauthorized + return ErrorUnauthorized } return nil diff --git a/examples/gno.land/r/mouss/home/gno.mod b/examples/gno.land/r/mouss/home/gno.mod index 3b2e6e0587d..a4ebfa34d16 100644 --- a/examples/gno.land/r/mouss/home/gno.mod +++ b/examples/gno.land/r/mouss/home/gno.mod @@ -1,2 +1 @@ module gno.land/r/mouss/home - diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno index 8d1968bac54..2442eea380e 100644 --- a/examples/gno.land/r/mouss/home/home.gno +++ b/examples/gno.land/r/mouss/home/home.gno @@ -2,36 +2,85 @@ package home import ( "bytes" + "std" "gno.land/p/demo/mux" + "gno.land/p/demo/ufmt" + "gno.land/r/mouss/config" ) var ( + abtMe string + avatar string // profile picture + followers []std.Address + router = mux.NewRouter() ) const ( - RealmURL = "/r/mouss/home" + RealmURL = "/r/mouss/home" + AbtMe = RealmURL + ":abtMe/" + Followers = RealmURL + "$help&func=follow=%s" ) func init() { router.HandleFunc("", renderHomepage) - router.HandleFunc("/abtMe", aboutme.renderAboutMe) + router.HandleFunc("abtMe/", renderAboutMe) + abtMe = "๐Ÿ‘‹ I'm Mustapha, a contributor to gno.land project from France. Iโ€™m passionate about coding, exploring new technologies, and contributing to open-source projects. Besides my tech journey, Iโ€™m also a pizzaiolo ๐Ÿ• who loves cooking and savoring good food." + avatar = "https://github.com/mous1985/assets/blob/master/avatar.png?raw=true" + +} +func Follow(addr std.Address) { + + if !isUser(std.PrevRealm().Addr()) { + panic(config.ErrorUnauthorized) + } + followers = append(followers, addr) } +func isAuthorized(addr std.Address) bool { + return addr == config.Address() || addr == config.Backup() +} +func isUser(addr std.Address) bool { + return !isAuthorized(addr) && !contains(followers, addr) +} +func contains(slice []std.Address, item std.Address) bool { + for _, s := range slice { + if s == item { + return true + } + } + return false +} func renderHomepage(res *mux.ResponseWriter, req *mux.Request) { var b bytes.Buffer - - b.WriteString("[Home]() | [About Me](aboutMe) | [Hackerspace](https://github.com/gnolang/hackerspace/issues/86#issuecomment-2535795751)\n\n") - b.WriteString("--------------------------------\n\n") + link := ufmt.Sprintf(AbtMe) + b.WriteString("[Home]() | " + ufmt.Sprintf("[About Me](%s)", link) + " | [Hackerspace](https://github.com/gnolang/hackerspace/issues/86#issuecomment-2535795751)\n\n") + b.WriteString("------\n\n") b.WriteString("```\n") for _, line := range gnoArt() { b.WriteString(line) b.WriteString("\n") } b.WriteString("```\n") - b.WriteString("--------------------------------") + b.WriteString("------") + + res.Write(b.String()) +} +func renderAboutMe(res *mux.ResponseWriter, req *mux.Request) { + var b bytes.Buffer + b.WriteString("## Aboute Me\n") + b.WriteString("------\n\n") + b.WriteString("![avatar](" + avatar + ")\n\n") + b.WriteString(abtMe + "\n\n") + b.WriteString("------\n\n") + b.WriteString("### Contact\n\n") + b.WriteString("- e-mail:mustapha.benazzouz@outlook.fr\n") + b.WriteString("- github : [@mous1985](https://github.com/mous1985)\n") + b.WriteString("- linkdin : [Mustapha](https://www.linkedin.com/in/mustapha-benazzouz-88646887/)\n") + b.WriteString("------\n\n") + b.WriteString("๐Ÿ‘คfollowers: " + ufmt.Sprintf("%d", len(followers))) res.Write(b.String()) } @@ -49,6 +98,7 @@ func gnoArt() []string { " .-=+++=: .*###%#= ", " :: ", } + } func Render(path string) string { From ac0c168c4eb1b7d1bea977bba1be23068a9cc1af Mon Sep 17 00:00:00 2001 From: mous1985 Date: Wed, 8 Jan 2025 18:54:50 +0100 Subject: [PATCH 04/27] add follower --- examples/gno.land/r/mouss/home/home.gno | 27 ++++++++++++++----------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno index 2442eea380e..b869a6eee6d 100644 --- a/examples/gno.land/r/mouss/home/home.gno +++ b/examples/gno.land/r/mouss/home/home.gno @@ -58,6 +58,8 @@ func renderHomepage(res *mux.ResponseWriter, req *mux.Request) { link := ufmt.Sprintf(AbtMe) b.WriteString("[Home]() | " + ufmt.Sprintf("[About Me](%s)", link) + " | [Hackerspace](https://github.com/gnolang/hackerspace/issues/86#issuecomment-2535795751)\n\n") b.WriteString("------\n\n") + b.WriteString("# Welcome to my Homepage\n\n") + b.WriteString("------\n\n") b.WriteString("```\n") for _, line := range gnoArt() { b.WriteString(line) @@ -70,7 +72,7 @@ func renderHomepage(res *mux.ResponseWriter, req *mux.Request) { } func renderAboutMe(res *mux.ResponseWriter, req *mux.Request) { var b bytes.Buffer - b.WriteString("## Aboute Me\n") + b.WriteString("## About Me\n") b.WriteString("------\n\n") b.WriteString("![avatar](" + avatar + ")\n\n") b.WriteString(abtMe + "\n\n") @@ -78,7 +80,7 @@ func renderAboutMe(res *mux.ResponseWriter, req *mux.Request) { b.WriteString("### Contact\n\n") b.WriteString("- e-mail:mustapha.benazzouz@outlook.fr\n") b.WriteString("- github : [@mous1985](https://github.com/mous1985)\n") - b.WriteString("- linkdin : [Mustapha](https://www.linkedin.com/in/mustapha-benazzouz-88646887/)\n") + b.WriteString("- LinkedIn : [Mustapha](https://www.linkedin.com/in/mustapha-benazzouz-88646887/)\n") b.WriteString("------\n\n") b.WriteString("๐Ÿ‘คfollowers: " + ufmt.Sprintf("%d", len(followers))) @@ -87,16 +89,17 @@ func renderAboutMe(res *mux.ResponseWriter, req *mux.Request) { func gnoArt() []string { return []string{ - " -==++. ", - " *@@@@= @- -@", - " #@@@@@: -==-.-- :-::===: .-++-. @- .===:.- .-.-==- .===:=@", - " #@@@@@@@: -@@%**%@@ #@@#*#@@- *@@**@@* @- +%=::-*@ +@=-:-@* +%=::-*@", - "+@%#**#%@@ %@+ :@@ *@+ #@=+@% %@+ @= :@: -@ +% +%.@: -@", - "-: - *@%:..+@@ *@+ #@=-@@: :@@= @- .@= =@ +@ *%.@= =@", - "--:==+=-:=. =%@%#*@@ *@+ #@+ =%@%%@%= #* %#=.:%*===*@ +% +% -%*===*@", - "-++++=++++. =-:::*@# . . .::. .. :: .:: . . .:: .", - " .-=+++=: .*###%#= ", - " :: ", + + " -==++. ", + " *@@@@= @- -@", + " #@@@@@: -==-.-- :-::===: .-++-. @- .===:.- .-.-==- .===:=@", + " #@@@@@@@: -@@%**%@@ #@@#*#@@- *@@**@@* @- +%=::-*@ +@=-:-@* +%=::-*@", + " +@%#**#%@@ %@+ :@@ *@+ #@=+@% %@+ @= :@: -@ +% +%.@: -@", + " -: - *@%:..+@@ *@+ #@=-@@: :@@= @- .@= =@ +@ *%.@= =@", + " --:==+=-:=. =%@%#*@@ *@+ #@+ =%@%%@%= #* %#=.:%*===*@ +% +% -%*===*@", + " -++++=++++. =-:::*@# . . .::. .. :: .:: . . .:: .", + " .-=+++=: .*###%#= ", + " :: ", } } From 2d47ee097f246e52d76087452cacbd109f79ff62 Mon Sep 17 00:00:00 2001 From: mous1985 Date: Thu, 9 Jan 2025 19:31:42 +0100 Subject: [PATCH 05/27] add recipe to my homepage --- examples/gno.land/r/mouss/home/home.gno | 216 ++++++++++++++++++------ 1 file changed, 162 insertions(+), 54 deletions(-) diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno index b869a6eee6d..199f21fb4bc 100644 --- a/examples/gno.land/r/mouss/home/home.gno +++ b/examples/gno.land/r/mouss/home/home.gno @@ -3,48 +3,129 @@ package home import ( "bytes" "std" + "strconv" + "strings" "gno.land/p/demo/mux" "gno.land/p/demo/ufmt" "gno.land/r/mouss/config" ) -var ( - abtMe string - avatar string // profile picture - followers []std.Address +type Profile struct { + AboutMe string + Avatar string + Email string + Github string + LinkedIn string + Followers []std.Address +} + +type Recipe struct { + Name string + Origin string + Author std.Address + Ingredients string + Instructions string + Tips string +} - router = mux.NewRouter() +var ( + profile = Profile{ + AboutMe: "๐Ÿ‘‹ I'm Mustapha, a contributor to gno.land project from France. " + + "I'm passionate about coding, exploring new technologies, and contributing to open-source projects. " + + "Besides my tech journey, I'm also a pizzaiolo ๐Ÿ• who loves cooking and savoring good food.", + Avatar: "https://github.com/mous1985/assets/blob/master/avatar.png?raw=true", + Email: "mustapha.benazzouz@outlook.fr", + Github: "https://github.com/mous1985", + LinkedIn: "https://www.linkedin.com/in/mustapha-benazzouz-88646887/", + Followers: make([]std.Address, 0), + } + router = mux.NewRouter() + Recipes []*Recipe ) const ( - RealmURL = "/r/mouss/home" - AbtMe = RealmURL + ":abtMe/" - Followers = RealmURL + "$help&func=follow=%s" + RealmURL = "/r/mouss/home" + Rec = RealmURL + ":recipe/%d" + //Followers = RealmURL + "$help&func=follow=%s" ) func init() { router.HandleFunc("", renderHomepage) - router.HandleFunc("abtMe/", renderAboutMe) - abtMe = "๐Ÿ‘‹ I'm Mustapha, a contributor to gno.land project from France. Iโ€™m passionate about coding, exploring new technologies, and contributing to open-source projects. Besides my tech journey, Iโ€™m also a pizzaiolo ๐Ÿ• who loves cooking and savoring good food." - avatar = "https://github.com/mous1985/assets/blob/master/avatar.png?raw=true" + router.HandleFunc("recipe/{id}", renderRecipe) } -func Follow(addr std.Address) { - if !isUser(std.PrevRealm().Addr()) { - panic(config.ErrorUnauthorized) +func AddRecipe(name, origin string, author std.Address, ingredients, instructions string, tips string) string { + if name == "" || len(ingredients) == 0 || len(instructions) == 0 { + panic("Your recipe is incomplet!") + } + recipe := Recipe{ + Name: name, + Origin: origin, + Author: std.PrevRealm().Addr(), + Ingredients: ingredients, + Instructions: instructions, + Tips: tips, } - followers = append(followers, addr) + Recipes = append(Recipes, &recipe) + return "Recipe added successfully!" + +} +// func renderRecipes(res *mux.ResponseWriter, req *mux.Request) { +// var b bytes.Buffer +// writeNavigation(&b) + +// b.WriteString("# Global Recipes Collection\n\n") +// b.WriteString("Share and discover recipes from around the world!\n\n") + +// for _, recipe := range Recipes { +// b.WriteString(ufmt.Sprintf("## %s\n", recipe.Name)) +// b.WriteString(ufmt.Sprintf("Origin: %s\n\n", recipe.Origin)) +// b.WriteString(ufmt.Sprintf("Shared by: %s\n\n", recipe.Author)) + +// b.WriteString("### Ingredients\n") +// for _, ing := range recipe.Ingredients { +// b.WriteString("- " + ing + "\n") +// } +// b.WriteString("\n### Instructions\n") +// for i, inst := range recipe.Instructions { +// b.WriteString(ufmt.Sprintf("%d. %s\n", i+1, inst)) +// } + +// b.WriteString(ufmt.Sprintf("\nCooking Time: %s\n\n", recipe.CookingTime)) +// if recipe.Tips != "" { +// b.WriteString(ufmt.Sprintf("๐Ÿ’ก **Tips**: %s\n\n", recipe.Tips)) +// } +// b.WriteString("------\n\n") +// } + +// res.Write(b.String()) +// } + +func SetProfile(p Profile) { + profile = p } + +func Follow(addr std.Address) error { + if !isUser(std.PrevRealm().Addr()) { + return config.ErrorUnauthorized + } + if contains(profile.Followers, addr) { + return ufmt.Errorf("address %s is already following", addr) + } + profile.Followers = append(profile.Followers, addr) + return nil +} + func isAuthorized(addr std.Address) bool { return addr == config.Address() || addr == config.Backup() } + func isUser(addr std.Address) bool { - return !isAuthorized(addr) && !contains(followers, addr) + return !isAuthorized(addr) && !contains(profile.Followers, addr) } - func contains(slice []std.Address, item std.Address) bool { for _, s := range slice { if s == item { @@ -53,57 +134,84 @@ func contains(slice []std.Address, item std.Address) bool { } return false } -func renderHomepage(res *mux.ResponseWriter, req *mux.Request) { + +func renderRecipe(res *mux.ResponseWriter, req *mux.Request) { + idStr := req.GetVar("id") + id, _ := strconv.Atoi(idStr) + if id >= len(Recipes) { + res.Write("Invalid recipe ID") + return + } + + rec := Recipes[id] var b bytes.Buffer - link := ufmt.Sprintf(AbtMe) - b.WriteString("[Home]() | " + ufmt.Sprintf("[About Me](%s)", link) + " | [Hackerspace](https://github.com/gnolang/hackerspace/issues/86#issuecomment-2535795751)\n\n") - b.WriteString("------\n\n") - b.WriteString("# Welcome to my Homepage\n\n") - b.WriteString("------\n\n") - b.WriteString("```\n") - for _, line := range gnoArt() { - b.WriteString(line) - b.WriteString("\n") + for _, recipe := range Recipes { + + b.WriteString("## " + recipe.Name + "\n") + b.WriteString("**Author:** " + recipe.Author.String() + "\n") + b.WriteString("### Origin: " + recipe.Origin + "\n") + b.WriteString("### Ingredients: " + recipe.Ingredients + "\n") + + b.WriteString("\n### Instructions :" + recipe.Ingredients + "\n") + + if rec.Tips != "" { + b.WriteString(ufmt.Sprintf("๐Ÿ’ก **Tips**: %s\n\n", recipe.Tips)) + } + b.WriteString("------\n\n") } - b.WriteString("```\n") - b.WriteString("------") res.Write(b.String()) } -func renderAboutMe(res *mux.ResponseWriter, req *mux.Request) { + +func writeNavigation(b *bytes.Buffer) { + b.WriteString(strings.Join([]string{ + "[Home]()", + ufmt.Sprintf("[World kitchen](%s)", Rec), + "[Hackerspace](https://github.com/gnolang/hackerspace/issues/86#issuecomment-2535795751)", + }, " | ") + "\n\n------\n\n") +} + +func writeGnoArt(b *bytes.Buffer) { + b.WriteString("```\n") + for _, line := range []string{ + " -==++. ", + " *@@@@= @- -@", + " #@@@@@: -==-.-- :-::===: .-++-. @- .===:.- .-.-==- .===:=@", + " #@@@@@@@: -@@%**%@@ #@@#*#@@- *@@**@@* @- +%=::-*@ +@=-:-@* +%=::-*@", + " +@%#**#%@@ %@+ :@@ *@+ #@=+@% %@+ @= :@: -@ +% +%.@: -@", + " -: - *@%:..+@@ *@+ #@=-@@: :@@= @- .@= =@ +@ *%.@= =@", + " --:==+=-:=. =%@%#*@@ *@+ #@+ =%@%%@%= #* %#=.:%*===*@ +% +% -%*===*@", + " -++++=++++. =-:::*@# . . .::. .. :: .:: . . .:: .", + " .-=+++=: .*###%#= ", + " :: ", + } { + b.WriteString(line + "\n") + } + b.WriteString("```\n------") +} +func renderHomepage(res *mux.ResponseWriter, req *mux.Request) { var b bytes.Buffer - b.WriteString("## About Me\n") + + writeNavigation(&b) + b.WriteString("# Welcome to my Homepage\n\n") b.WriteString("------\n\n") - b.WriteString("![avatar](" + avatar + ")\n\n") - b.WriteString(abtMe + "\n\n") + writeGnoArt(&b) b.WriteString("------\n\n") + b.WriteString("## About Me\n------\n\n") + b.WriteString(ufmt.Sprintf("![avatar](%s)\n\n", profile.Avatar)) + b.WriteString(profile.AboutMe + "\n\n------\n\n") + b.WriteString("### Contact\n\n") - b.WriteString("- e-mail:mustapha.benazzouz@outlook.fr\n") - b.WriteString("- github : [@mous1985](https://github.com/mous1985)\n") - b.WriteString("- LinkedIn : [Mustapha](https://www.linkedin.com/in/mustapha-benazzouz-88646887/)\n") + b.WriteString(ufmt.Sprintf("- Email: %s\n", profile.Email)) + b.WriteString(ufmt.Sprintf("- GitHub: [@mous1985](%s)\n", profile.Github)) + b.WriteString(ufmt.Sprintf("- LinkedIn: [Mustapha](%s)\n", profile.LinkedIn)) + b.WriteString("------\n\n") - b.WriteString("๐Ÿ‘คfollowers: " + ufmt.Sprintf("%d", len(followers))) + b.WriteString(ufmt.Sprintf("๐Ÿ‘ค Followers: %d", len(profile.Followers))) res.Write(b.String()) } -func gnoArt() []string { - return []string{ - - " -==++. ", - " *@@@@= @- -@", - " #@@@@@: -==-.-- :-::===: .-++-. @- .===:.- .-.-==- .===:=@", - " #@@@@@@@: -@@%**%@@ #@@#*#@@- *@@**@@* @- +%=::-*@ +@=-:-@* +%=::-*@", - " +@%#**#%@@ %@+ :@@ *@+ #@=+@% %@+ @= :@: -@ +% +%.@: -@", - " -: - *@%:..+@@ *@+ #@=-@@: :@@= @- .@= =@ +@ *%.@= =@", - " --:==+=-:=. =%@%#*@@ *@+ #@+ =%@%%@%= #* %#=.:%*===*@ +% +% -%*===*@", - " -++++=++++. =-:::*@# . . .::. .. :: .:: . . .:: .", - " .-=+++=: .*###%#= ", - " :: ", - } - -} - func Render(path string) string { return router.Render(path) } From 05d085386a45bb6bde6ed38ad4f06598f5ef4970 Mon Sep 17 00:00:00 2001 From: mous1985 Date: Thu, 9 Jan 2025 20:39:05 +0100 Subject: [PATCH 06/27] refactor v0 of home page --- examples/gno.land/r/mouss/home/home.gno | 180 +++++++++++------------- 1 file changed, 83 insertions(+), 97 deletions(-) diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno index 199f21fb4bc..18f3c206d18 100644 --- a/examples/gno.land/r/mouss/home/home.gno +++ b/examples/gno.land/r/mouss/home/home.gno @@ -3,7 +3,6 @@ package home import ( "bytes" "std" - "strconv" "strings" "gno.land/p/demo/mux" @@ -29,38 +28,44 @@ type Recipe struct { Tips string } +const ( + RealmURL = "/r/mouss/home" + Rec = RealmURL + ":recipe/" +) + var ( profile = Profile{ - AboutMe: "๐Ÿ‘‹ I'm Mustapha, a contributor to gno.land project from France. " + - "I'm passionate about coding, exploring new technologies, and contributing to open-source projects. " + - "Besides my tech journey, I'm also a pizzaiolo ๐Ÿ• who loves cooking and savoring good food.", + AboutMe: "๐Ÿ‘‹ I'm Mustapha, a contributor to gno.land project from France. I'm passionate about coding, exploring new technologies, and contributing to open-source projects. Besides my tech journey, I'm also a pizzaiolo ๐Ÿ• who loves cooking and savoring good food.", Avatar: "https://github.com/mous1985/assets/blob/master/avatar.png?raw=true", Email: "mustapha.benazzouz@outlook.fr", Github: "https://github.com/mous1985", LinkedIn: "https://www.linkedin.com/in/mustapha-benazzouz-88646887/", Followers: make([]std.Address, 0), } - router = mux.NewRouter() - Recipes []*Recipe -) - -const ( - RealmURL = "/r/mouss/home" - Rec = RealmURL + ":recipe/%d" - //Followers = RealmURL + "$help&func=follow=%s" + router = mux.NewRouter() + recipes []*Recipe + margheritaPizza = &Recipe{ + Name: "Authentic Margherita Pizza ๐ŸคŒ", + Origin: "Naples, ๐Ÿ‡ฎ๐Ÿ‡น", + Author: config.Address(), + Ingredients: " \n\n- 1kg 00 flour\n\n- 500ml water\n\n- 3g fresh yeast\n\n- 20g sea salt\n\n- San Marzano tomatoes\n\n- Fresh buffalo mozzarella\n\n- Fresh basil\n\n- Extra virgin olive oil", + Instructions: "\n\n1. Mix flour and water until incorporated\n\n2. Add yeast and salt, knead for 20 minutes\n\n3. Let rise for 2 hours at room temperature\n\n4. Divide into 250g balls\n\n5. Cold ferment for 24-48 hours\n\n6. Shape by hand, being gentle with the dough\n\n7. Top with crushed tomatoes, torn mozzarella, and basil\n\n8. Cook at 450ยฐC for 60-90 seconds", + Tips: "Use a pizza steel or stone preheated for at least 1 hour. The dough should be soft and extensible. For best results, cook in a wood-fired oven.", + } ) func init() { router.HandleFunc("", renderHomepage) - router.HandleFunc("recipe/{id}", renderRecipe) + router.HandleFunc("recipe/", renderRecipes) } -func AddRecipe(name, origin string, author std.Address, ingredients, instructions string, tips string) string { - if name == "" || len(ingredients) == 0 || len(instructions) == 0 { - panic("Your recipe is incomplet!") +func AddRecipe(name, origin, ingredients, instructions, tips string) string { + if err := validateRecipe(name, ingredients, instructions); err != nil { + panic(err.Error()) } - recipe := Recipe{ + + recipe := &Recipe{ Name: name, Origin: origin, Author: std.PrevRealm().Addr(), @@ -68,48 +73,26 @@ func AddRecipe(name, origin string, author std.Address, ingredients, instruction Instructions: instructions, Tips: tips, } - Recipes = append(Recipes, &recipe) + recipes = append(recipes, recipe) return "Recipe added successfully!" - } -// func renderRecipes(res *mux.ResponseWriter, req *mux.Request) { -// var b bytes.Buffer -// writeNavigation(&b) - -// b.WriteString("# Global Recipes Collection\n\n") -// b.WriteString("Share and discover recipes from around the world!\n\n") - -// for _, recipe := range Recipes { -// b.WriteString(ufmt.Sprintf("## %s\n", recipe.Name)) -// b.WriteString(ufmt.Sprintf("Origin: %s\n\n", recipe.Origin)) -// b.WriteString(ufmt.Sprintf("Shared by: %s\n\n", recipe.Author)) - -// b.WriteString("### Ingredients\n") -// for _, ing := range recipe.Ingredients { -// b.WriteString("- " + ing + "\n") -// } -// b.WriteString("\n### Instructions\n") -// for i, inst := range recipe.Instructions { -// b.WriteString(ufmt.Sprintf("%d. %s\n", i+1, inst)) -// } - -// b.WriteString(ufmt.Sprintf("\nCooking Time: %s\n\n", recipe.CookingTime)) -// if recipe.Tips != "" { -// b.WriteString(ufmt.Sprintf("๐Ÿ’ก **Tips**: %s\n\n", recipe.Tips)) -// } -// b.WriteString("------\n\n") -// } - -// res.Write(b.String()) -// } - -func SetProfile(p Profile) { - profile = p +func validateRecipe(name, ingredients, instructions string) error { + if name == "" { + return ufmt.Errorf("recipe name cannot be empty") + } + if len(ingredients) == 0 { + return ufmt.Errorf("ingredients cannot be empty") + } + if len(instructions) == 0 { + return ufmt.Errorf("instructions cannot be empty") + } + return nil } func Follow(addr std.Address) error { - if !isUser(std.PrevRealm().Addr()) { + caller := std.PrevRealm().Addr() + if !isUser(caller) { return config.ErrorUnauthorized } if contains(profile.Followers, addr) { @@ -126,6 +109,7 @@ func isAuthorized(addr std.Address) bool { func isUser(addr std.Address) bool { return !isAuthorized(addr) && !contains(profile.Followers, addr) } + func contains(slice []std.Address, item std.Address) bool { for _, s := range slice { if s == item { @@ -135,42 +119,70 @@ func contains(slice []std.Address, item std.Address) bool { return false } -func renderRecipe(res *mux.ResponseWriter, req *mux.Request) { - idStr := req.GetVar("id") - id, _ := strconv.Atoi(idStr) - if id >= len(Recipes) { - res.Write("Invalid recipe ID") +func renderRecipes(res *mux.ResponseWriter, req *mux.Request) { + var b bytes.Buffer + b.WriteString("## World Kitchen\n\n------\n\n") + writeRecipe(&b, margheritaPizza) + + if len(recipes) == 0 { + b.WriteString("No recipes yet. Be the first to add one!\n") + res.Write(b.String()) return } - rec := Recipes[id] - var b bytes.Buffer - for _, recipe := range Recipes { + for _, recipe := range recipes { + writeRecipe(&b, recipe) + } + res.Write(b.String()) +} - b.WriteString("## " + recipe.Name + "\n") - b.WriteString("**Author:** " + recipe.Author.String() + "\n") - b.WriteString("### Origin: " + recipe.Origin + "\n") - b.WriteString("### Ingredients: " + recipe.Ingredients + "\n") +func writeRecipe(b *bytes.Buffer, recipe *Recipe) { + b.WriteString("## " + recipe.Name + "\n") + b.WriteString("**Author:** " + recipe.Author.String() + "\n\n") + b.WriteString("**Origin:** " + recipe.Origin + "\n\n") + b.WriteString("**Ingredients:** " + recipe.Ingredients + "\n\n") - b.WriteString("\n### Instructions :" + recipe.Ingredients + "\n") + b.WriteString("**Instructions:** " + recipe.Instructions + "\n\n") - if rec.Tips != "" { - b.WriteString(ufmt.Sprintf("๐Ÿ’ก **Tips**: %s\n\n", recipe.Tips)) - } - b.WriteString("------\n\n") + if recipe.Tips != "" { + b.WriteString(ufmt.Sprintf("๐Ÿ’ก **Tips**: %s\n\n", recipe.Tips)) } + b.WriteString("------\n\n") + b.WriteString("------\n\n") +} +func renderHomepage(res *mux.ResponseWriter, req *mux.Request) { + var b bytes.Buffer + writeNavigation(&b) + writeProfile(&b) res.Write(b.String()) } +func writeProfile(b *bytes.Buffer) { + b.WriteString("# Welcome to my Homepage\n\n------\n\n") + writeGnoArt(b) + b.WriteString("------\n\n## About Me\n------\n\n") + b.WriteString(ufmt.Sprintf("![avatar](%s)\n\n", profile.Avatar)) + b.WriteString(profile.AboutMe + "\n\n------\n\n") + b.WriteString("### Contact\n\n") + b.WriteString(ufmt.Sprintf("- Email: %s\n", profile.Email)) + b.WriteString(ufmt.Sprintf("- GitHub: [@mous1985](%s)\n", profile.Github)) + b.WriteString(ufmt.Sprintf("- LinkedIn: [Mustapha](%s)\n", profile.LinkedIn)) + b.WriteString("------\n\n") + b.WriteString(ufmt.Sprintf("๐Ÿ‘ค Followers: %d", len(profile.Followers))) +} + func writeNavigation(b *bytes.Buffer) { b.WriteString(strings.Join([]string{ "[Home]()", - ufmt.Sprintf("[World kitchen](%s)", Rec), + ufmt.Sprintf("[World Kitchen](%s)", Rec), "[Hackerspace](https://github.com/gnolang/hackerspace/issues/86#issuecomment-2535795751)", }, " | ") + "\n\n------\n\n") } +func Render(path string) string { + return router.Render(path) +} func writeGnoArt(b *bytes.Buffer) { b.WriteString("```\n") for _, line := range []string{ @@ -189,29 +201,3 @@ func writeGnoArt(b *bytes.Buffer) { } b.WriteString("```\n------") } -func renderHomepage(res *mux.ResponseWriter, req *mux.Request) { - var b bytes.Buffer - - writeNavigation(&b) - b.WriteString("# Welcome to my Homepage\n\n") - b.WriteString("------\n\n") - writeGnoArt(&b) - b.WriteString("------\n\n") - b.WriteString("## About Me\n------\n\n") - b.WriteString(ufmt.Sprintf("![avatar](%s)\n\n", profile.Avatar)) - b.WriteString(profile.AboutMe + "\n\n------\n\n") - - b.WriteString("### Contact\n\n") - b.WriteString(ufmt.Sprintf("- Email: %s\n", profile.Email)) - b.WriteString(ufmt.Sprintf("- GitHub: [@mous1985](%s)\n", profile.Github)) - b.WriteString(ufmt.Sprintf("- LinkedIn: [Mustapha](%s)\n", profile.LinkedIn)) - - b.WriteString("------\n\n") - b.WriteString(ufmt.Sprintf("๐Ÿ‘ค Followers: %d", len(profile.Followers))) - - res.Write(b.String()) -} - -func Render(path string) string { - return router.Render(path) -} From 918c773928cc57fc4d58ca18a5941987417bf4dc Mon Sep 17 00:00:00 2001 From: mous1985 Date: Fri, 10 Jan 2025 06:31:04 +0100 Subject: [PATCH 07/27] refactor: replace bytes.Buffer with strings.builder --- examples/gno.land/r/mouss/home/home.gno | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno index 18f3c206d18..b85a6481fe8 100644 --- a/examples/gno.land/r/mouss/home/home.gno +++ b/examples/gno.land/r/mouss/home/home.gno @@ -1,7 +1,6 @@ package home import ( - "bytes" "std" "strings" @@ -120,7 +119,7 @@ func contains(slice []std.Address, item std.Address) bool { } func renderRecipes(res *mux.ResponseWriter, req *mux.Request) { - var b bytes.Buffer + var b strings.Builder b.WriteString("## World Kitchen\n\n------\n\n") writeRecipe(&b, margheritaPizza) @@ -136,7 +135,7 @@ func renderRecipes(res *mux.ResponseWriter, req *mux.Request) { res.Write(b.String()) } -func writeRecipe(b *bytes.Buffer, recipe *Recipe) { +func writeRecipe(b *strings.Builder, recipe *Recipe) { b.WriteString("## " + recipe.Name + "\n") b.WriteString("**Author:** " + recipe.Author.String() + "\n\n") b.WriteString("**Origin:** " + recipe.Origin + "\n\n") @@ -152,13 +151,13 @@ func writeRecipe(b *bytes.Buffer, recipe *Recipe) { } func renderHomepage(res *mux.ResponseWriter, req *mux.Request) { - var b bytes.Buffer + var b strings.Builder writeNavigation(&b) writeProfile(&b) res.Write(b.String()) } -func writeProfile(b *bytes.Buffer) { +func writeProfile(b *strings.Builder) { b.WriteString("# Welcome to my Homepage\n\n------\n\n") writeGnoArt(b) b.WriteString("------\n\n## About Me\n------\n\n") @@ -172,7 +171,7 @@ func writeProfile(b *bytes.Buffer) { b.WriteString(ufmt.Sprintf("๐Ÿ‘ค Followers: %d", len(profile.Followers))) } -func writeNavigation(b *bytes.Buffer) { +func writeNavigation(b *strings.Builder) { b.WriteString(strings.Join([]string{ "[Home]()", ufmt.Sprintf("[World Kitchen](%s)", Rec), @@ -183,7 +182,7 @@ func writeNavigation(b *bytes.Buffer) { func Render(path string) string { return router.Render(path) } -func writeGnoArt(b *bytes.Buffer) { +func writeGnoArt(b *strings.Builder) { b.WriteString("```\n") for _, line := range []string{ " -==++. ", From 844a61c05bf9a3fdabc7bbdd607b7756a6fb23df Mon Sep 17 00:00:00 2001 From: mous1985 Date: Fri, 10 Jan 2025 06:44:38 +0100 Subject: [PATCH 08/27] refactor: use p/moul/addrset --- examples/gno.land/r/mouss/home/home.gno | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno index b85a6481fe8..6c945664494 100644 --- a/examples/gno.land/r/mouss/home/home.gno +++ b/examples/gno.land/r/mouss/home/home.gno @@ -6,6 +6,7 @@ import ( "gno.land/p/demo/mux" "gno.land/p/demo/ufmt" + "gno.land/p/moul/addrset" "gno.land/r/mouss/config" ) @@ -15,7 +16,7 @@ type Profile struct { Email string Github string LinkedIn string - Followers []std.Address + Followers addrset.Set } type Recipe struct { @@ -94,21 +95,20 @@ func Follow(addr std.Address) error { if !isUser(caller) { return config.ErrorUnauthorized } - if contains(profile.Followers, addr) { + if profile.Followers.Has(addr) { return ufmt.Errorf("address %s is already following", addr) } - profile.Followers = append(profile.Followers, addr) + profile.Followers.Add(addr) return nil } +func isUser(addr std.Address) bool { + return !isAuthorized(addr) && !profile.Followers.Has(addr) +} func isAuthorized(addr std.Address) bool { return addr == config.Address() || addr == config.Backup() } -func isUser(addr std.Address) bool { - return !isAuthorized(addr) && !contains(profile.Followers, addr) -} - func contains(slice []std.Address, item std.Address) bool { for _, s := range slice { if s == item { @@ -168,7 +168,7 @@ func writeProfile(b *strings.Builder) { b.WriteString(ufmt.Sprintf("- GitHub: [@mous1985](%s)\n", profile.Github)) b.WriteString(ufmt.Sprintf("- LinkedIn: [Mustapha](%s)\n", profile.LinkedIn)) b.WriteString("------\n\n") - b.WriteString(ufmt.Sprintf("๐Ÿ‘ค Followers: %d", len(profile.Followers))) + b.WriteString(ufmt.Sprintf("๐Ÿ‘ค Followers: %d", profile.Followers.Size())) } func writeNavigation(b *strings.Builder) { From b5e2868a1b5e9610273af543c776e83b23986c8f Mon Sep 17 00:00:00 2001 From: mous1985 Date: Fri, 10 Jan 2025 07:37:06 +0100 Subject: [PATCH 09/27] ref: add p/moul/md --- examples/gno.land/r/mouss/home/home.gno | 53 +++++++++++++------------ 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno index 6c945664494..4c917750edf 100644 --- a/examples/gno.land/r/mouss/home/home.gno +++ b/examples/gno.land/r/mouss/home/home.gno @@ -2,11 +2,13 @@ package home import ( "std" + "strconv" "strings" "gno.land/p/demo/mux" "gno.land/p/demo/ufmt" "gno.land/p/moul/addrset" + "gno.land/p/moul/md" "gno.land/r/mouss/config" ) @@ -136,18 +138,17 @@ func renderRecipes(res *mux.ResponseWriter, req *mux.Request) { } func writeRecipe(b *strings.Builder, recipe *Recipe) { - b.WriteString("## " + recipe.Name + "\n") - b.WriteString("**Author:** " + recipe.Author.String() + "\n\n") - b.WriteString("**Origin:** " + recipe.Origin + "\n\n") - b.WriteString("**Ingredients:** " + recipe.Ingredients + "\n\n") - - b.WriteString("**Instructions:** " + recipe.Instructions + "\n\n") + b.WriteString(md.H2(recipe.Name)) + b.WriteString(md.Bold("Author: ") + recipe.Author.String() + "\n\n") + b.WriteString(md.Bold("Origin: ") + recipe.Origin + "\n\n") + b.WriteString(md.Bold("Ingredients:") + "\n" + md.BulletList(strings.Split(recipe.Ingredients, "\n")) + "\n") + b.WriteString(md.Bold("Instructions:") + "\n" + md.OrderedList(strings.Split(recipe.Instructions, "\n")) + "\n") if recipe.Tips != "" { - b.WriteString(ufmt.Sprintf("๐Ÿ’ก **Tips**: %s\n\n", recipe.Tips)) + b.WriteString(md.Italic("๐Ÿ’ก Tips: "+recipe.Tips) + "\n\n") } - b.WriteString("------\n\n") - b.WriteString("------\n\n") + + b.WriteString(md.HorizontalRule() + "\n") } func renderHomepage(res *mux.ResponseWriter, req *mux.Request) { @@ -158,27 +159,27 @@ func renderHomepage(res *mux.ResponseWriter, req *mux.Request) { } func writeProfile(b *strings.Builder) { - b.WriteString("# Welcome to my Homepage\n\n------\n\n") + b.WriteString(md.H1("Welcome to my Homepage") + "\n\n" + md.HorizontalRule() + "\n\n") writeGnoArt(b) - b.WriteString("------\n\n## About Me\n------\n\n") - b.WriteString(ufmt.Sprintf("![avatar](%s)\n\n", profile.Avatar)) - b.WriteString(profile.AboutMe + "\n\n------\n\n") - b.WriteString("### Contact\n\n") - b.WriteString(ufmt.Sprintf("- Email: %s\n", profile.Email)) - b.WriteString(ufmt.Sprintf("- GitHub: [@mous1985](%s)\n", profile.Github)) - b.WriteString(ufmt.Sprintf("- LinkedIn: [Mustapha](%s)\n", profile.LinkedIn)) - b.WriteString("------\n\n") - b.WriteString(ufmt.Sprintf("๐Ÿ‘ค Followers: %d", profile.Followers.Size())) + b.WriteString(md.HorizontalRule() + "\n\n" + md.H2("About Me") + "\n\n") + b.WriteString(md.Image("avatar", profile.Avatar) + "\n\n") + b.WriteString(profile.AboutMe + "\n\n" + md.HorizontalRule() + "\n\n") + b.WriteString(md.H3("Contact") + "\n\n") + b.WriteString(md.BulletList([]string{ + "Email: " + profile.Email, + "GitHub: " + md.Link("@mous1985", profile.Github), + "LinkedIn: " + md.Link("Mustapha", profile.LinkedIn), + })) + b.WriteString("\n\n" + md.Bold("๐Ÿ‘ค Followers: ") + strconv.Itoa(profile.Followers.Size())) } - func writeNavigation(b *strings.Builder) { - b.WriteString(strings.Join([]string{ - "[Home]()", - ufmt.Sprintf("[World Kitchen](%s)", Rec), - "[Hackerspace](https://github.com/gnolang/hackerspace/issues/86#issuecomment-2535795751)", - }, " | ") + "\n\n------\n\n") + navItems := []string{ + md.Link("Home", ""), + md.Link("World Kitchen", Rec), + md.Link("Hackerspace", "https://github.com/gnolang/hackerspace/issues/86#issuecomment-2535795751"), + } + b.WriteString(strings.Join(navItems, " | ") + "\n\n" + md.HorizontalRule() + "\n\n") } - func Render(path string) string { return router.Render(path) } From f64569a28c01f18ae23b7276a985afc3a9b8a99f Mon Sep 17 00:00:00 2001 From: mous1985 Date: Fri, 10 Jan 2025 13:30:54 +0100 Subject: [PATCH 10/27] doc --- examples/gno.land/r/mouss/home/home.gno | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno index 4c917750edf..e677c3318c1 100644 --- a/examples/gno.land/r/mouss/home/home.gno +++ b/examples/gno.land/r/mouss/home/home.gno @@ -12,15 +12,17 @@ import ( "gno.land/r/mouss/config" ) +// Profile represents my personal profile information. type Profile struct { AboutMe string Avatar string Email string Github string LinkedIn string - Followers addrset.Set + Followers addrset.Set // Set of followers addresses. } +// Recipe represents a cooking recipe with its details. type Recipe struct { Name string Origin string @@ -56,12 +58,13 @@ var ( } ) +// init initializes the router with the homepage and recipe routes. func init() { router.HandleFunc("", renderHomepage) router.HandleFunc("recipe/", renderRecipes) - } +// AddRecipe adds a new recipe in recipe page by users func AddRecipe(name, origin, ingredients, instructions, tips string) string { if err := validateRecipe(name, ingredients, instructions); err != nil { panic(err.Error()) @@ -79,6 +82,7 @@ func AddRecipe(name, origin, ingredients, instructions, tips string) string { return "Recipe added successfully!" } +// validateRecipe checks if the provided recipe details are valid. func validateRecipe(name, ingredients, instructions string) error { if name == "" { return ufmt.Errorf("recipe name cannot be empty") @@ -92,6 +96,14 @@ func validateRecipe(name, ingredients, instructions string) error { return nil } +// Follow allows a users to follow my home page. +// It checks if the caller is a valid user and if the address is already being followed. +// If the caller is not authorized, it returns an error. +// If the address is already being followed, it returns an error. +// Otherwise, it adds the address to the list of followers and returns nil. +//TODO:any user can follow and to be followed by any other user +//TODO: add a function to unfollow + func Follow(addr std.Address) error { caller := std.PrevRealm().Addr() if !isUser(caller) { @@ -111,15 +123,6 @@ func isAuthorized(addr std.Address) bool { return addr == config.Address() || addr == config.Backup() } -func contains(slice []std.Address, item std.Address) bool { - for _, s := range slice { - if s == item { - return true - } - } - return false -} - func renderRecipes(res *mux.ResponseWriter, req *mux.Request) { var b strings.Builder b.WriteString("## World Kitchen\n\n------\n\n") From 4959189b32af60bea681f08f5f5ab697bf155c77 Mon Sep 17 00:00:00 2001 From: mous1985 Date: Fri, 10 Jan 2025 19:26:30 +0100 Subject: [PATCH 11/27] ref: func writeRecipe to method (r Recipe)Render func writeProfile to method (p Profile)Render --- examples/gno.land/r/mouss/home/home.gno | 83 ++++++++++++++----------- 1 file changed, 46 insertions(+), 37 deletions(-) diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno index e677c3318c1..5f8fbb8732c 100644 --- a/examples/gno.land/r/mouss/home/home.gno +++ b/examples/gno.land/r/mouss/home/home.gno @@ -7,6 +7,7 @@ import ( "gno.land/p/demo/mux" "gno.land/p/demo/ufmt" + "gno.land/p/moul/addrset" "gno.land/p/moul/md" "gno.land/r/mouss/config" @@ -44,7 +45,7 @@ var ( Email: "mustapha.benazzouz@outlook.fr", Github: "https://github.com/mous1985", LinkedIn: "https://www.linkedin.com/in/mustapha-benazzouz-88646887/", - Followers: make([]std.Address, 0), + Followers: addrset.Set{}, } router = mux.NewRouter() recipes []*Recipe @@ -52,8 +53,8 @@ var ( Name: "Authentic Margherita Pizza ๐ŸคŒ", Origin: "Naples, ๐Ÿ‡ฎ๐Ÿ‡น", Author: config.Address(), - Ingredients: " \n\n- 1kg 00 flour\n\n- 500ml water\n\n- 3g fresh yeast\n\n- 20g sea salt\n\n- San Marzano tomatoes\n\n- Fresh buffalo mozzarella\n\n- Fresh basil\n\n- Extra virgin olive oil", - Instructions: "\n\n1. Mix flour and water until incorporated\n\n2. Add yeast and salt, knead for 20 minutes\n\n3. Let rise for 2 hours at room temperature\n\n4. Divide into 250g balls\n\n5. Cold ferment for 24-48 hours\n\n6. Shape by hand, being gentle with the dough\n\n7. Top with crushed tomatoes, torn mozzarella, and basil\n\n8. Cook at 450ยฐC for 60-90 seconds", + Ingredients: " 1kg 00 flour\n 500ml water\n 3g fresh yeast\n 20g sea salt\n San Marzano tomatoes\n Fresh buffalo mozzarella\n Fresh basil\n Extra virgin olive oil", + Instructions: " Mix flour and water until incorporated\n Add yeast and salt, knead for 20 minutes\n Let rise for 2 hours at room temperature\n Divide into 250g balls\n Cold ferment for 24-48 hours\n Shape by hand, being gentle with the dough\n Top with crushed tomatoes, torn mozzarella, and basil\n Cook at 450ยฐC for 60-90 seconds", Tips: "Use a pizza steel or stone preheated for at least 1 hour. The dough should be soft and extensible. For best results, cook in a wood-fired oven.", } ) @@ -101,8 +102,8 @@ func validateRecipe(name, ingredients, instructions string) error { // If the caller is not authorized, it returns an error. // If the address is already being followed, it returns an error. // Otherwise, it adds the address to the list of followers and returns nil. -//TODO:any user can follow and to be followed by any other user -//TODO: add a function to unfollow +// TODO:any user can follow and to be followed by any other user +// TODO: add a function to unfollow func Follow(addr std.Address) error { caller := std.PrevRealm().Addr() @@ -112,12 +113,12 @@ func Follow(addr std.Address) error { if profile.Followers.Has(addr) { return ufmt.Errorf("address %s is already following", addr) } - profile.Followers.Add(addr) + profile.Followers.Add(addr) //can't add the same address twice return nil } func isUser(addr std.Address) bool { - return !isAuthorized(addr) && !profile.Followers.Has(addr) + return !isAuthorized(addr) } func isAuthorized(addr std.Address) bool { return addr == config.Address() || addr == config.Backup() @@ -126,7 +127,8 @@ func isAuthorized(addr std.Address) bool { func renderRecipes(res *mux.ResponseWriter, req *mux.Request) { var b strings.Builder b.WriteString("## World Kitchen\n\n------\n\n") - writeRecipe(&b, margheritaPizza) + + b.WriteString(margheritaPizza.Render()) if len(recipes) == 0 { b.WriteString("No recipes yet. Be the first to add one!\n") @@ -135,45 +137,52 @@ func renderRecipes(res *mux.ResponseWriter, req *mux.Request) { } for _, recipe := range recipes { - writeRecipe(&b, recipe) + b.WriteString(recipe.Render()) } + res.Write(b.String()) } -func writeRecipe(b *strings.Builder, recipe *Recipe) { - b.WriteString(md.H2(recipe.Name)) - b.WriteString(md.Bold("Author: ") + recipe.Author.String() + "\n\n") - b.WriteString(md.Bold("Origin: ") + recipe.Origin + "\n\n") - b.WriteString(md.Bold("Ingredients:") + "\n" + md.BulletList(strings.Split(recipe.Ingredients, "\n")) + "\n") - b.WriteString(md.Bold("Instructions:") + "\n" + md.OrderedList(strings.Split(recipe.Instructions, "\n")) + "\n") - - if recipe.Tips != "" { - b.WriteString(md.Italic("๐Ÿ’ก Tips: "+recipe.Tips) + "\n\n") +func (r Recipe) Render() string { + var b strings.Builder + b.WriteString(md.H2(r.Name)) + b.WriteString(md.Bold("Author:") + "\n" + r.Author.String() + "\n\n") + b.WriteString(md.Bold("Origin:") + "\n" + r.Origin + "\n\n") + b.WriteString(md.Bold("Ingredients:") + "\n" + md.BulletList(strings.Split(r.Ingredients, "\n")) + "\n\n") + b.WriteString(md.Bold("Instructions:") + "\n" + md.OrderedList(strings.Split(r.Instructions, "\n")) + "\n\n") + + if r.Tips != "" { + b.WriteString(md.Italic("๐Ÿ’ก Tips:"+"\n"+r.Tips) + "\n\n") } b.WriteString(md.HorizontalRule() + "\n") + return b.String() } func renderHomepage(res *mux.ResponseWriter, req *mux.Request) { var b strings.Builder writeNavigation(&b) - writeProfile(&b) + b.WriteString(profile.Render()) res.Write(b.String()) } -func writeProfile(b *strings.Builder) { +func (p Profile) Render() string { + var b strings.Builder + b.WriteString(md.H1("Welcome to my Homepage") + "\n\n" + md.HorizontalRule() + "\n\n") - writeGnoArt(b) + writeGnoArt(&b) b.WriteString(md.HorizontalRule() + "\n\n" + md.H2("About Me") + "\n\n") - b.WriteString(md.Image("avatar", profile.Avatar) + "\n\n") - b.WriteString(profile.AboutMe + "\n\n" + md.HorizontalRule() + "\n\n") + b.WriteString(md.Image("avatar", p.Avatar) + "\n\n") + b.WriteString(p.AboutMe + "\n\n" + md.HorizontalRule() + "\n\n") b.WriteString(md.H3("Contact") + "\n\n") b.WriteString(md.BulletList([]string{ - "Email: " + profile.Email, - "GitHub: " + md.Link("@mous1985", profile.Github), - "LinkedIn: " + md.Link("Mustapha", profile.LinkedIn), + "Email: " + p.Email, + "GitHub: " + md.Link("@mous1985", p.Github), + "LinkedIn: " + md.Link("Mustapha", p.LinkedIn), })) - b.WriteString("\n\n" + md.Bold("๐Ÿ‘ค Followers: ") + strconv.Itoa(profile.Followers.Size())) + b.WriteString("\n\n" + md.Bold("๐Ÿ‘ค Followers: ") + strconv.Itoa(p.Followers.Size())) + + return b.String() } func writeNavigation(b *strings.Builder) { navItems := []string{ @@ -189,16 +198,16 @@ func Render(path string) string { func writeGnoArt(b *strings.Builder) { b.WriteString("```\n") for _, line := range []string{ - " -==++. ", - " *@@@@= @- -@", - " #@@@@@: -==-.-- :-::===: .-++-. @- .===:.- .-.-==- .===:=@", - " #@@@@@@@: -@@%**%@@ #@@#*#@@- *@@**@@* @- +%=::-*@ +@=-:-@* +%=::-*@", - " +@%#**#%@@ %@+ :@@ *@+ #@=+@% %@+ @= :@: -@ +% +%.@: -@", - " -: - *@%:..+@@ *@+ #@=-@@: :@@= @- .@= =@ +@ *%.@= =@", - " --:==+=-:=. =%@%#*@@ *@+ #@+ =%@%%@%= #* %#=.:%*===*@ +% +% -%*===*@", - " -++++=++++. =-:::*@# . . .::. .. :: .:: . . .:: .", - " .-=+++=: .*###%#= ", - " :: ", + " -==++. ", + " *@@@@= @- -@", + " #@@@@@: -==-.-- :-::===: .-++-. @- .===:.- .-.-==- .===:=@", + " #@@@@@@@: -@@%**%@@ #@@#*#@@- *@@**@@* @- +%=::-*@ +@=-:-@* +%=::-*@", + " +@%#**#%@@ %@+ :@@ *@+ #@=+@% %@+ @= :@: -@ +% +%.@: -@", + " -: - *@%:..+@@ *@+ #@=-@@: :@@= @- .@= =@ +@ *%.@= =@", + " --:==+=-:=. =%@%#*@@ *@+ #@+ =%@%%@%= #* %#=.:%*===*@ +% +% -%*===*@", + " -++++=++++. =-:::*@# . . .::. .. :: .:: . . .:: .", + " .-=+++=: .*###%#= ", + " :: ", } { b.WriteString(line + "\n") } From cdbd8de459d1a3f61ffcda61b71e6a61b9eb6330 Mon Sep 17 00:00:00 2001 From: mous1985 Date: Tue, 21 Jan 2025 15:15:33 +0100 Subject: [PATCH 12/27] ref: replace strings.Builder by var out string --- examples/gno.land/r/mouss/home/home.gno | 86 ++++++++++++------------- 1 file changed, 41 insertions(+), 45 deletions(-) diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno index 5f8fbb8732c..db28b21386d 100644 --- a/examples/gno.land/r/mouss/home/home.gno +++ b/examples/gno.land/r/mouss/home/home.gno @@ -36,6 +36,18 @@ type Recipe struct { const ( RealmURL = "/r/mouss/home" Rec = RealmURL + ":recipe/" + gnoArt = ` + -==++. + *@@@@= @- -@ + #@@@@@: -==-.-- :-::===: .-++-. @- .===:.- .-.-==- .===:=@ + #@@@@@@@: -@@%**%@@ #@@#*#@@- *@@**@@* @- +%=::-*@ +@=-:-@* +%=::-*@ + +@%#**#%@@ %@+ :@@ *@+ #@=+@% %@+ @= :@: -@ +% +%.@: -@ + -: - *@%:..+@@ *@+ #@=-@@: :@@= @- .@= =@ +@ *%.@= =@ + --:==+=-:=. =%@%#*@@ *@+ #@+ =%@%%@%= #* %#=.:%*===*@ +% +% -%*===*@ + -++++=++++. =-:::*@# . . .::. .. :: .:: . . .:: . + .-=+++=: .*###%#= + :: +` ) var ( @@ -144,72 +156,56 @@ func renderRecipes(res *mux.ResponseWriter, req *mux.Request) { } func (r Recipe) Render() string { - var b strings.Builder - b.WriteString(md.H2(r.Name)) - b.WriteString(md.Bold("Author:") + "\n" + r.Author.String() + "\n\n") - b.WriteString(md.Bold("Origin:") + "\n" + r.Origin + "\n\n") - b.WriteString(md.Bold("Ingredients:") + "\n" + md.BulletList(strings.Split(r.Ingredients, "\n")) + "\n\n") - b.WriteString(md.Bold("Instructions:") + "\n" + md.OrderedList(strings.Split(r.Instructions, "\n")) + "\n\n") + var out string + out += md.H2(r.Name) + out += md.Bold("Author:") + "\n" + r.Author.String() + "\n\n" + out += md.Bold("Origin:") + "\n" + r.Origin + "\n\n" + out += md.Bold("Ingredients:") + "\n" + md.BulletList(strings.Split(r.Ingredients, "\n")) + "\n\n" + out += md.Bold("Instructions:") + "\n" + md.OrderedList(strings.Split(r.Instructions, "\n")) + "\n\n" if r.Tips != "" { - b.WriteString(md.Italic("๐Ÿ’ก Tips:"+"\n"+r.Tips) + "\n\n") + out += md.Italic("๐Ÿ’ก Tips:"+"\n"+r.Tips) + "\n\n" } - b.WriteString(md.HorizontalRule() + "\n") - return b.String() + out += md.HorizontalRule() + "\n" + return out } func renderHomepage(res *mux.ResponseWriter, req *mux.Request) { - var b strings.Builder - writeNavigation(&b) - b.WriteString(profile.Render()) - res.Write(b.String()) + var out string + writeNavigation(&out) + out += profile.Render() + res.Write(out) } func (p Profile) Render() string { - var b strings.Builder - - b.WriteString(md.H1("Welcome to my Homepage") + "\n\n" + md.HorizontalRule() + "\n\n") - writeGnoArt(&b) - b.WriteString(md.HorizontalRule() + "\n\n" + md.H2("About Me") + "\n\n") - b.WriteString(md.Image("avatar", p.Avatar) + "\n\n") - b.WriteString(p.AboutMe + "\n\n" + md.HorizontalRule() + "\n\n") - b.WriteString(md.H3("Contact") + "\n\n") - b.WriteString(md.BulletList([]string{ + var out string + + out += md.H1("Welcome to my Homepage") + "\n\n" + md.HorizontalRule() + "\n\n" + out += "```\n" + out += gnoArt + out += "```\n------" + out += md.HorizontalRule() + "\n\n" + md.H2("About Me") + "\n\n" + out += md.Image("avatar", p.Avatar) + "\n\n" + out += p.AboutMe + "\n\n" + md.HorizontalRule() + "\n\n" + out += md.H3("Contact") + "\n\n" + out += md.BulletList([]string{ "Email: " + p.Email, "GitHub: " + md.Link("@mous1985", p.Github), "LinkedIn: " + md.Link("Mustapha", p.LinkedIn), - })) - b.WriteString("\n\n" + md.Bold("๐Ÿ‘ค Followers: ") + strconv.Itoa(p.Followers.Size())) + }) + out += "\n\n" + md.Bold("๐Ÿ‘ค Followers: ") + strconv.Itoa(p.Followers.Size()) - return b.String() + return out } -func writeNavigation(b *strings.Builder) { +func writeNavigation(out *string) { navItems := []string{ md.Link("Home", ""), md.Link("World Kitchen", Rec), md.Link("Hackerspace", "https://github.com/gnolang/hackerspace/issues/86#issuecomment-2535795751"), } - b.WriteString(strings.Join(navItems, " | ") + "\n\n" + md.HorizontalRule() + "\n\n") + *out += strings.Join(navItems, " | ") + "\n\n" + md.HorizontalRule() + "\n\n" } func Render(path string) string { return router.Render(path) } -func writeGnoArt(b *strings.Builder) { - b.WriteString("```\n") - for _, line := range []string{ - " -==++. ", - " *@@@@= @- -@", - " #@@@@@: -==-.-- :-::===: .-++-. @- .===:.- .-.-==- .===:=@", - " #@@@@@@@: -@@%**%@@ #@@#*#@@- *@@**@@* @- +%=::-*@ +@=-:-@* +%=::-*@", - " +@%#**#%@@ %@+ :@@ *@+ #@=+@% %@+ @= :@: -@ +% +%.@: -@", - " -: - *@%:..+@@ *@+ #@=-@@: :@@= @- .@= =@ +@ *%.@= =@", - " --:==+=-:=. =%@%#*@@ *@+ #@+ =%@%%@%= #* %#=.:%*===*@ +% +% -%*===*@", - " -++++=++++. =-:::*@# . . .::. .. :: .:: . . .:: .", - " .-=+++=: .*###%#= ", - " :: ", - } { - b.WriteString(line + "\n") - } - b.WriteString("```\n------") -} From 48795c44be9d2a75cacef12bbbfda865e93b39ae Mon Sep 17 00:00:00 2001 From: Mustapha <102119509+mous1985@users.noreply.github.com> Date: Tue, 21 Jan 2025 15:20:12 +0100 Subject: [PATCH 13/27] Update examples/gno.land/r/mouss/config/config.gno Co-authored-by: Leon Hudak <33522493+leohhhn@users.noreply.github.com> --- examples/gno.land/r/mouss/config/config.gno | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/gno.land/r/mouss/config/config.gno b/examples/gno.land/r/mouss/config/config.gno index 8a7c6cfa6a2..3cc78330fa6 100644 --- a/examples/gno.land/r/mouss/config/config.gno +++ b/examples/gno.land/r/mouss/config/config.gno @@ -16,6 +16,7 @@ var ( func init() { main = "g1hrfvdh7jdvnlxpk2y20tp3scj9jqal3zzu7wjz" } + func Address() std.Address { return main } From 91baa9c06709eb28b681f00eea54c3a6d483546c Mon Sep 17 00:00:00 2001 From: mous1985 Date: Tue, 21 Jan 2025 15:30:22 +0100 Subject: [PATCH 14/27] ref : SetBackup(newAddress std.Address) --- examples/gno.land/r/mouss/config/config.gno | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/gno.land/r/mouss/config/config.gno b/examples/gno.land/r/mouss/config/config.gno index 3cc78330fa6..5d2e3d96e0e 100644 --- a/examples/gno.land/r/mouss/config/config.gno +++ b/examples/gno.land/r/mouss/config/config.gno @@ -24,8 +24,8 @@ func Address() std.Address { func Backup() std.Address { return backup } -func SetBack(buAddress std.Address) error { - if !buAddress.IsValid() { +func SetBackup(newAddress std.Address) error { + if !newAddress.IsValid() { return ErrorInvalidAddr } @@ -33,7 +33,7 @@ func SetBack(buAddress std.Address) error { return err } - backup = buAddress + backup = newAddress return nil } From e7f2e73a52e11e9a051dd297f8480c1c5d24db17 Mon Sep 17 00:00:00 2001 From: mous1985 Date: Tue, 21 Jan 2025 15:42:03 +0100 Subject: [PATCH 15/27] test: add config_test.gno --- .../gno.land/r/mouss/config/config_test.gno | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/examples/gno.land/r/mouss/config/config_test.gno b/examples/gno.land/r/mouss/config/config_test.gno index d912156bec0..3219c153906 100644 --- a/examples/gno.land/r/mouss/config/config_test.gno +++ b/examples/gno.land/r/mouss/config/config_test.gno @@ -1 +1,63 @@ package config + +import ( + "std" + "testing" + + "gno.land/p/demo/testutils" + "gno.land/p/demo/uassert" +) + +var ( + mainAddr = Address() + backupAddr = testutils.TestAddress("backup") + unauthorizedAddr = testutils.TestAddress("unauthorized") +) + +func TestAddress(t *testing.T) { + addr := Address() + expected := std.Address("g1hrfvdh7jdvnlxpk2y20tp3scj9jqal3zzu7wjz") + uassert.Equal(t, expected, addr, "Address() should return initialized main address") +} + +func TestSetBackup(t *testing.T) { + // Test setting backup as main address + std.TestSetOrigCaller(mainAddr) + validAddr := testutils.TestAddress("validbackup") + err := SetBackup(validAddr) + uassert.NoError(t, err, "main address should be able to set backup") + + // Test setting invalid address format + err = SetBackup(std.Address("invalid")) + uassert.ErrorIs(t, err, ErrorInvalidAddr, "should reject invalid address format") + + // Test setting empty address + err = SetBackup(std.Address("")) + uassert.ErrorIs(t, err, ErrorInvalidAddr, "should reject empty address") + + // Test unauthorized caller + std.TestSetOrigCaller(unauthorizedAddr) + err = SetBackup(validAddr) + uassert.ErrorIs(t, err, ErrorUnauthorized, "should reject unauthorized caller") +} + +func TestCheckAuthorized(t *testing.T) { + // Test main address authorization + std.TestSetOrigCaller(mainAddr) + err := checkAuthorized() + uassert.NoError(t, err, "main address should be authorized") + + // Test unauthorized address + std.TestSetOrigCaller(unauthorizedAddr) + err = checkAuthorized() + uassert.ErrorIs(t, err, ErrorUnauthorized, "random address should not be authorized") + + // Set and test backup address authorization + std.TestSetOrigCaller(mainAddr) + err = SetBackup(backupAddr) + uassert.NoError(t, err, "setting backup address should succeed") + + std.TestSetOrigCaller(backupAddr) + err = checkAuthorized() + uassert.NoError(t, err, "backup address should be authorized") +} From bb096ac1ac2e9bceac30e3d7d2c461a98acf788c Mon Sep 17 00:00:00 2001 From: Mustapha <102119509+mous1985@users.noreply.github.com> Date: Tue, 21 Jan 2025 15:43:56 +0100 Subject: [PATCH 16/27] Update examples/gno.land/r/mouss/home/home.gno Co-authored-by: Leon Hudak <33522493+leohhhn@users.noreply.github.com> --- examples/gno.land/r/mouss/home/home.gno | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno index db28b21386d..7fd45a9482a 100644 --- a/examples/gno.land/r/mouss/home/home.gno +++ b/examples/gno.land/r/mouss/home/home.gno @@ -51,16 +51,17 @@ const ( ) var ( + router = mux.NewRouter() + recipes []*Recipe + profile = Profile{ - AboutMe: "๐Ÿ‘‹ I'm Mustapha, a contributor to gno.land project from France. I'm passionate about coding, exploring new technologies, and contributing to open-source projects. Besides my tech journey, I'm also a pizzaiolo ๐Ÿ• who loves cooking and savoring good food.", + AboutMe: "๐Ÿ‘‹ I'm Mustapha, a contributor to gno.land project from France. I'm passionate about coding, exploring new technologies, and contributing to open-source projects. Besides my tech journey, I'm also a pizzaiolo ๐Ÿ• who loves cooking and savoring good food.", Avatar: "https://github.com/mous1985/assets/blob/master/avatar.png?raw=true", Email: "mustapha.benazzouz@outlook.fr", Github: "https://github.com/mous1985", LinkedIn: "https://www.linkedin.com/in/mustapha-benazzouz-88646887/", Followers: addrset.Set{}, } - router = mux.NewRouter() - recipes []*Recipe margheritaPizza = &Recipe{ Name: "Authentic Margherita Pizza ๐ŸคŒ", Origin: "Naples, ๐Ÿ‡ฎ๐Ÿ‡น", From b62f3868d23de6284ac122638046f9936d8a1420 Mon Sep 17 00:00:00 2001 From: Mustapha <102119509+mous1985@users.noreply.github.com> Date: Tue, 21 Jan 2025 15:45:14 +0100 Subject: [PATCH 17/27] Update examples/gno.land/r/mouss/home/home.gno Co-authored-by: Leon Hudak <33522493+leohhhn@users.noreply.github.com> --- examples/gno.land/r/mouss/home/home.gno | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno index 7fd45a9482a..ad0893eaa00 100644 --- a/examples/gno.land/r/mouss/home/home.gno +++ b/examples/gno.land/r/mouss/home/home.gno @@ -81,7 +81,7 @@ func init() { // AddRecipe adds a new recipe in recipe page by users func AddRecipe(name, origin, ingredients, instructions, tips string) string { if err := validateRecipe(name, ingredients, instructions); err != nil { - panic(err.Error()) + panic(err) } recipe := &Recipe{ From 933f759fe224ffa596984358585c1a358aeaf3f1 Mon Sep 17 00:00:00 2001 From: Mustapha <102119509+mous1985@users.noreply.github.com> Date: Tue, 21 Jan 2025 15:47:29 +0100 Subject: [PATCH 18/27] Update examples/gno.land/r/mouss/home/home.gno Co-authored-by: Leon Hudak <33522493+leohhhn@users.noreply.github.com> --- examples/gno.land/r/mouss/home/home.gno | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno index ad0893eaa00..9fd879ee74c 100644 --- a/examples/gno.land/r/mouss/home/home.gno +++ b/examples/gno.land/r/mouss/home/home.gno @@ -133,6 +133,7 @@ func Follow(addr std.Address) error { func isUser(addr std.Address) bool { return !isAuthorized(addr) } + func isAuthorized(addr std.Address) bool { return addr == config.Address() || addr == config.Backup() } From 27a0b5d1daddb515317f642aef8a908144cd8035 Mon Sep 17 00:00:00 2001 From: mous1985 Date: Tue, 21 Jan 2025 15:49:37 +0100 Subject: [PATCH 19/27] ref: add new line between func --- examples/gno.land/r/mouss/config/config.gno | 1 + examples/gno.land/r/mouss/home/home.gno | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/examples/gno.land/r/mouss/config/config.gno b/examples/gno.land/r/mouss/config/config.gno index 5d2e3d96e0e..24f23280326 100644 --- a/examples/gno.land/r/mouss/config/config.gno +++ b/examples/gno.land/r/mouss/config/config.gno @@ -24,6 +24,7 @@ func Address() std.Address { func Backup() std.Address { return backup } + func SetBackup(newAddress std.Address) error { if !newAddress.IsValid() { return ErrorInvalidAddr diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno index 9fd879ee74c..292a283e8ab 100644 --- a/examples/gno.land/r/mouss/home/home.gno +++ b/examples/gno.land/r/mouss/home/home.gno @@ -51,11 +51,11 @@ const ( ) var ( - router = mux.NewRouter() - recipes []*Recipe - + router = mux.NewRouter() + recipes []*Recipe + profile = Profile{ - AboutMe: "๐Ÿ‘‹ I'm Mustapha, a contributor to gno.land project from France. I'm passionate about coding, exploring new technologies, and contributing to open-source projects. Besides my tech journey, I'm also a pizzaiolo ๐Ÿ• who loves cooking and savoring good food.", + AboutMe: "๐Ÿ‘‹ I'm Mustapha, a contributor to gno.land project from France. I'm passionate about coding, exploring new technologies, and contributing to open-source projects. Besides my tech journey, I'm also a pizzaiolo ๐Ÿ• who loves cooking and savoring good food.", Avatar: "https://github.com/mous1985/assets/blob/master/avatar.png?raw=true", Email: "mustapha.benazzouz@outlook.fr", Github: "https://github.com/mous1985", @@ -200,6 +200,7 @@ func (p Profile) Render() string { return out } + func writeNavigation(out *string) { navItems := []string{ md.Link("Home", ""), @@ -208,6 +209,7 @@ func writeNavigation(out *string) { } *out += strings.Join(navItems, " | ") + "\n\n" + md.HorizontalRule() + "\n\n" } + func Render(path string) string { return router.Render(path) } From 2caabf7e6374b7efce9f521d9b444af6396a63d8 Mon Sep 17 00:00:00 2001 From: mous1985 Date: Tue, 21 Jan 2025 16:37:41 +0100 Subject: [PATCH 20/27] test: add home_test.gno --- examples/gno.land/r/mouss/home/home.gno | 25 ++++-- examples/gno.land/r/mouss/home/home_test.gno | 89 ++++++++++++++++++++ 2 files changed, 105 insertions(+), 9 deletions(-) create mode 100644 examples/gno.land/r/mouss/home/home_test.gno diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno index 292a283e8ab..e6d4063edba 100644 --- a/examples/gno.land/r/mouss/home/home.gno +++ b/examples/gno.land/r/mouss/home/home.gno @@ -10,6 +10,7 @@ import ( "gno.land/p/moul/addrset" "gno.land/p/moul/md" + "gno.land/r/leon/hof" "gno.land/r/mouss/config" ) @@ -20,7 +21,7 @@ type Profile struct { Email string Github string LinkedIn string - Followers addrset.Set // Set of followers addresses. + Followers *addrset.Set // Set of followers addresses. } // Recipe represents a cooking recipe with its details. @@ -51,8 +52,17 @@ const ( ) var ( - router = mux.NewRouter() - recipes []*Recipe + router = mux.NewRouter() + profile Profile + recipes []*Recipe + margheritaPizza *Recipe +) + +// init initializes the router with the homepage and recipe routes. +func init() { + + router.HandleFunc("", renderHomepage) + router.HandleFunc("recipe/", renderRecipes) profile = Profile{ AboutMe: "๐Ÿ‘‹ I'm Mustapha, a contributor to gno.land project from France. I'm passionate about coding, exploring new technologies, and contributing to open-source projects. Besides my tech journey, I'm also a pizzaiolo ๐Ÿ• who loves cooking and savoring good food.", @@ -60,8 +70,9 @@ var ( Email: "mustapha.benazzouz@outlook.fr", Github: "https://github.com/mous1985", LinkedIn: "https://www.linkedin.com/in/mustapha-benazzouz-88646887/", - Followers: addrset.Set{}, + Followers: &addrset.Set{}, } + margheritaPizza = &Recipe{ Name: "Authentic Margherita Pizza ๐ŸคŒ", Origin: "Naples, ๐Ÿ‡ฎ๐Ÿ‡น", @@ -70,12 +81,8 @@ var ( Instructions: " Mix flour and water until incorporated\n Add yeast and salt, knead for 20 minutes\n Let rise for 2 hours at room temperature\n Divide into 250g balls\n Cold ferment for 24-48 hours\n Shape by hand, being gentle with the dough\n Top with crushed tomatoes, torn mozzarella, and basil\n Cook at 450ยฐC for 60-90 seconds", Tips: "Use a pizza steel or stone preheated for at least 1 hour. The dough should be soft and extensible. For best results, cook in a wood-fired oven.", } -) -// init initializes the router with the homepage and recipe routes. -func init() { - router.HandleFunc("", renderHomepage) - router.HandleFunc("recipe/", renderRecipes) + hof.Register() } // AddRecipe adds a new recipe in recipe page by users diff --git a/examples/gno.land/r/mouss/home/home_test.gno b/examples/gno.land/r/mouss/home/home_test.gno new file mode 100644 index 00000000000..af87b1ece37 --- /dev/null +++ b/examples/gno.land/r/mouss/home/home_test.gno @@ -0,0 +1,89 @@ +package home + +import ( + "std" + "testing" + + "gno.land/p/demo/testutils" + "gno.land/p/demo/uassert" + "gno.land/r/mouss/config" +) + +var ( + user1 = testutils.TestAddress("user1") + user2 = testutils.TestAddress("user2") + mainAddr = config.Address() +) + +func TestProfile(t *testing.T) { + + uassert.NotEmpty(t, profile.AboutMe, "AboutMe should not be empty") + uassert.NotEmpty(t, profile.Avatar, "Avatar should not be empty") + uassert.NotEmpty(t, profile.Email, "Email should not be empty") + uassert.NotEmpty(t, profile.Github, "Github should not be empty") + uassert.NotEmpty(t, profile.LinkedIn, "LinkedIn should not be empty") +} + +func TestAddRecipe(t *testing.T) { + + std.TestSetOrigCaller(user1) + + name := "Test Recipe" + origin := "Test Origin" + ingredients := "Ingredient 1\nIngredient 2" + instructions := "Step 1\nStep 2" + tips := "Test Tips" + + result := AddRecipe(name, origin, ingredients, instructions, tips) + uassert.Equal(t, "Recipe added successfully!", result) + uassert.Equal(t, 1, len(recipes)) + recipe := recipes[0] + uassert.Equal(t, name, recipe.Name) + uassert.Equal(t, origin, recipe.Origin) + uassert.Equal(t, ingredients, recipe.Ingredients) + uassert.Equal(t, instructions, recipe.Instructions) + uassert.Equal(t, tips, recipe.Tips) + uassert.Equal(t, user1, recipe.Author) +} + +func TestFollow(t *testing.T) { + + // Test user following admin's profile + std.TestSetOrigCaller(user1) + err := Follow(user1) + uassert.NoError(t, err, "regular user should be able to follow admin's profile") + + // Test admin trying to follow themselves + std.TestSetOrigCaller(mainAddr) + err = Follow(mainAddr) + uassert.ErrorIs(t, err, config.ErrorUnauthorized, "admin should not be able to follow their own profile") + + // Test following same address twice + std.TestSetOrigCaller(user1) + err = Follow(user1) + uassert.Error(t, err, "should not be able to follow same address twice") + + // Test multiple users following admin + std.TestSetOrigCaller(user2) + err = Follow(user2) + uassert.NoError(t, err, "another user should be able to follow admin's profile") +} + +func TestIsUser(t *testing.T) { + + uassert.True(t, isUser(user1), "should recognize normal user") + + uassert.False(t, isUser(mainAddr), "should not recognize admin as normal user") +} + +func TestIsAuthorized(t *testing.T) { + + uassert.True(t, isAuthorized(mainAddr), "should recognize main address as authorized") + + uassert.False(t, isAuthorized(user1), "should not recognize normal user as authorized") + + std.TestSetOrigCaller(mainAddr) + backupAddr := testutils.TestAddress("backup") + config.SetBackup(backupAddr) + uassert.True(t, isAuthorized(backupAddr), "should recognize backup address as authorized") +} From 68b6a02a8d38b9260d16c14a89c31afa88e4b561 Mon Sep 17 00:00:00 2001 From: mous1985 Date: Wed, 22 Jan 2025 10:15:52 +0100 Subject: [PATCH 21/27] ref: randomnew line in home.gno --- examples/gno.land/r/mouss/home/home.gno | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno index e6d4063edba..0978a841d52 100644 --- a/examples/gno.land/r/mouss/home/home.gno +++ b/examples/gno.land/r/mouss/home/home.gno @@ -58,12 +58,12 @@ var ( margheritaPizza *Recipe ) -// init initializes the router with the homepage and recipe routes. +// init initializes the router with the home page and recipe routes +//sets up my profile information, and my recipe +// and registers the home page in the hall of fame. func init() { - router.HandleFunc("", renderHomepage) router.HandleFunc("recipe/", renderRecipes) - profile = Profile{ AboutMe: "๐Ÿ‘‹ I'm Mustapha, a contributor to gno.land project from France. I'm passionate about coding, exploring new technologies, and contributing to open-source projects. Besides my tech journey, I'm also a pizzaiolo ๐Ÿ• who loves cooking and savoring good food.", Avatar: "https://github.com/mous1985/assets/blob/master/avatar.png?raw=true", @@ -72,7 +72,6 @@ func init() { LinkedIn: "https://www.linkedin.com/in/mustapha-benazzouz-88646887/", Followers: &addrset.Set{}, } - margheritaPizza = &Recipe{ Name: "Authentic Margherita Pizza ๐ŸคŒ", Origin: "Naples, ๐Ÿ‡ฎ๐Ÿ‡น", @@ -81,7 +80,6 @@ func init() { Instructions: " Mix flour and water until incorporated\n Add yeast and salt, knead for 20 minutes\n Let rise for 2 hours at room temperature\n Divide into 250g balls\n Cold ferment for 24-48 hours\n Shape by hand, being gentle with the dough\n Top with crushed tomatoes, torn mozzarella, and basil\n Cook at 450ยฐC for 60-90 seconds", Tips: "Use a pizza steel or stone preheated for at least 1 hour. The dough should be soft and extensible. For best results, cook in a wood-fired oven.", } - hof.Register() } @@ -90,7 +88,6 @@ func AddRecipe(name, origin, ingredients, instructions, tips string) string { if err := validateRecipe(name, ingredients, instructions); err != nil { panic(err) } - recipe := &Recipe{ Name: name, Origin: origin, @@ -148,19 +145,15 @@ func isAuthorized(addr std.Address) bool { func renderRecipes(res *mux.ResponseWriter, req *mux.Request) { var b strings.Builder b.WriteString("## World Kitchen\n\n------\n\n") - b.WriteString(margheritaPizza.Render()) - if len(recipes) == 0 { b.WriteString("No recipes yet. Be the first to add one!\n") res.Write(b.String()) return } - for _, recipe := range recipes { b.WriteString(recipe.Render()) } - res.Write(b.String()) } @@ -171,11 +164,9 @@ func (r Recipe) Render() string { out += md.Bold("Origin:") + "\n" + r.Origin + "\n\n" out += md.Bold("Ingredients:") + "\n" + md.BulletList(strings.Split(r.Ingredients, "\n")) + "\n\n" out += md.Bold("Instructions:") + "\n" + md.OrderedList(strings.Split(r.Instructions, "\n")) + "\n\n" - if r.Tips != "" { out += md.Italic("๐Ÿ’ก Tips:"+"\n"+r.Tips) + "\n\n" } - out += md.HorizontalRule() + "\n" return out } @@ -189,7 +180,6 @@ func renderHomepage(res *mux.ResponseWriter, req *mux.Request) { func (p Profile) Render() string { var out string - out += md.H1("Welcome to my Homepage") + "\n\n" + md.HorizontalRule() + "\n\n" out += "```\n" out += gnoArt @@ -204,7 +194,6 @@ func (p Profile) Render() string { "LinkedIn: " + md.Link("Mustapha", p.LinkedIn), }) out += "\n\n" + md.Bold("๐Ÿ‘ค Followers: ") + strconv.Itoa(p.Followers.Size()) - return out } From e584e45477ec2c24e5ce024378533905a089d995 Mon Sep 17 00:00:00 2001 From: mous1985 Date: Wed, 22 Jan 2025 10:22:20 +0100 Subject: [PATCH 22/27] ref: random new line in home_test.gno --- examples/gno.land/r/mouss/home/home_test.gno | 9 --------- 1 file changed, 9 deletions(-) diff --git a/examples/gno.land/r/mouss/home/home_test.gno b/examples/gno.land/r/mouss/home/home_test.gno index af87b1ece37..1c0924faf1a 100644 --- a/examples/gno.land/r/mouss/home/home_test.gno +++ b/examples/gno.land/r/mouss/home/home_test.gno @@ -16,7 +16,6 @@ var ( ) func TestProfile(t *testing.T) { - uassert.NotEmpty(t, profile.AboutMe, "AboutMe should not be empty") uassert.NotEmpty(t, profile.Avatar, "Avatar should not be empty") uassert.NotEmpty(t, profile.Email, "Email should not be empty") @@ -25,9 +24,7 @@ func TestProfile(t *testing.T) { } func TestAddRecipe(t *testing.T) { - std.TestSetOrigCaller(user1) - name := "Test Recipe" origin := "Test Origin" ingredients := "Ingredient 1\nIngredient 2" @@ -47,7 +44,6 @@ func TestAddRecipe(t *testing.T) { } func TestFollow(t *testing.T) { - // Test user following admin's profile std.TestSetOrigCaller(user1) err := Follow(user1) @@ -70,18 +66,13 @@ func TestFollow(t *testing.T) { } func TestIsUser(t *testing.T) { - uassert.True(t, isUser(user1), "should recognize normal user") - uassert.False(t, isUser(mainAddr), "should not recognize admin as normal user") } func TestIsAuthorized(t *testing.T) { - uassert.True(t, isAuthorized(mainAddr), "should recognize main address as authorized") - uassert.False(t, isAuthorized(user1), "should not recognize normal user as authorized") - std.TestSetOrigCaller(mainAddr) backupAddr := testutils.TestAddress("backup") config.SetBackup(backupAddr) From d9f02e1e05a5bc9f2aa400594175b82bad812fb3 Mon Sep 17 00:00:00 2001 From: mous1985 Date: Wed, 22 Jan 2025 10:56:29 +0100 Subject: [PATCH 23/27] feat: add unfollow function --- examples/gno.land/r/mouss/home/home.gno | 16 +++++++++++++--- examples/gno.land/r/mouss/home/home_test.gno | 17 +++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno index 0978a841d52..dd1a79c124d 100644 --- a/examples/gno.land/r/mouss/home/home.gno +++ b/examples/gno.land/r/mouss/home/home.gno @@ -119,9 +119,6 @@ func validateRecipe(name, ingredients, instructions string) error { // If the caller is not authorized, it returns an error. // If the address is already being followed, it returns an error. // Otherwise, it adds the address to the list of followers and returns nil. -// TODO:any user can follow and to be followed by any other user -// TODO: add a function to unfollow - func Follow(addr std.Address) error { caller := std.PrevRealm().Addr() if !isUser(caller) { @@ -134,6 +131,19 @@ func Follow(addr std.Address) error { return nil } +// Unfollow allows a user to unfollow my home page. +func Unfollow(addr std.Address) error { + caller := std.PrevRealm().Addr() + if !isUser(caller) { + return config.ErrorUnauthorized + } + if !profile.Followers.Has(addr) { + return ufmt.Errorf("address %s is not following", addr) + } + profile.Followers.Remove(addr) + return nil +} + func isUser(addr std.Address) bool { return !isAuthorized(addr) } diff --git a/examples/gno.land/r/mouss/home/home_test.gno b/examples/gno.land/r/mouss/home/home_test.gno index 1c0924faf1a..e9516b839a6 100644 --- a/examples/gno.land/r/mouss/home/home_test.gno +++ b/examples/gno.land/r/mouss/home/home_test.gno @@ -65,6 +65,23 @@ func TestFollow(t *testing.T) { uassert.NoError(t, err, "another user should be able to follow admin's profile") } +func TestUnfollow(t *testing.T) { + // user1 is already follower + //Test successful unfollow + err := Unfollow(user1) + uassert.NoError(t, err) + uassert.False(t, profile.Followers.Has(user1)) + + // Test unfollowing when not following + err = Unfollow(user1) + uassert.Error(t, err) + + // Test unauthorized unfollow + std.TestSetOrigCaller(mainAddr) + err = Unfollow(user1) + uassert.ErrorIs(t, err, config.ErrorUnauthorized) +} + func TestIsUser(t *testing.T) { uassert.True(t, isUser(user1), "should recognize normal user") uassert.False(t, isUser(mainAddr), "should not recognize admin as normal user") From 0586b1b26ce1129b1b1d7a6b16a8a2a06ee3f40d Mon Sep 17 00:00:00 2001 From: mous1985 Date: Wed, 22 Jan 2025 11:22:19 +0100 Subject: [PATCH 24/27] fix: ci --- examples/gno.land/r/mouss/config/config.gno | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/gno.land/r/mouss/config/config.gno b/examples/gno.land/r/mouss/config/config.gno index 24f23280326..8f613c21aaf 100644 --- a/examples/gno.land/r/mouss/config/config.gno +++ b/examples/gno.land/r/mouss/config/config.gno @@ -43,6 +43,5 @@ func checkAuthorized() error { if caller != main && caller != backup { return ErrorUnauthorized } - return nil } From aafaf5ec8bf628551814ec47f554ab9fb92b5977 Mon Sep 17 00:00:00 2001 From: mous1985 Date: Wed, 22 Jan 2025 11:26:57 +0100 Subject: [PATCH 25/27] fix: ci --- examples/gno.land/r/mouss/home/home.gno | 2 +- examples/gno.land/r/mouss/home/home_test.gno | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno index dd1a79c124d..e99e2312deb 100644 --- a/examples/gno.land/r/mouss/home/home.gno +++ b/examples/gno.land/r/mouss/home/home.gno @@ -59,7 +59,7 @@ var ( ) // init initializes the router with the home page and recipe routes -//sets up my profile information, and my recipe +// sets up my profile information, and my recipe // and registers the home page in the hall of fame. func init() { router.HandleFunc("", renderHomepage) diff --git a/examples/gno.land/r/mouss/home/home_test.gno b/examples/gno.land/r/mouss/home/home_test.gno index e9516b839a6..876411138a3 100644 --- a/examples/gno.land/r/mouss/home/home_test.gno +++ b/examples/gno.land/r/mouss/home/home_test.gno @@ -67,7 +67,7 @@ func TestFollow(t *testing.T) { func TestUnfollow(t *testing.T) { // user1 is already follower - //Test successful unfollow + // Test successful unfollow err := Unfollow(user1) uassert.NoError(t, err) uassert.False(t, profile.Followers.Has(user1)) From 7874d678e00ce987573252166cd126e4decd268f Mon Sep 17 00:00:00 2001 From: mous1985 Date: Wed, 22 Jan 2025 11:38:23 +0100 Subject: [PATCH 26/27] fix: ci --- examples/gno.land/r/mouss/home/home.gno | 4 ++-- examples/gno.land/r/mouss/home/home_test.gno | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno index e99e2312deb..e0711b7c286 100644 --- a/examples/gno.land/r/mouss/home/home.gno +++ b/examples/gno.land/r/mouss/home/home.gno @@ -135,10 +135,10 @@ func Follow(addr std.Address) error { func Unfollow(addr std.Address) error { caller := std.PrevRealm().Addr() if !isUser(caller) { - return config.ErrorUnauthorized + return config.ErrorUnauthorized } if !profile.Followers.Has(addr) { - return ufmt.Errorf("address %s is not following", addr) + return ufmt.Errorf("address %s is not following", addr) } profile.Followers.Remove(addr) return nil diff --git a/examples/gno.land/r/mouss/home/home_test.gno b/examples/gno.land/r/mouss/home/home_test.gno index 876411138a3..c36eb9611d3 100644 --- a/examples/gno.land/r/mouss/home/home_test.gno +++ b/examples/gno.land/r/mouss/home/home_test.gno @@ -66,7 +66,7 @@ func TestFollow(t *testing.T) { } func TestUnfollow(t *testing.T) { - // user1 is already follower + // user1 is already follower // Test successful unfollow err := Unfollow(user1) uassert.NoError(t, err) From 7d1e3471523634e7075d7631e8af0fe0948df48a Mon Sep 17 00:00:00 2001 From: mous1985 Date: Wed, 22 Jan 2025 11:42:13 +0100 Subject: [PATCH 27/27] fix: ci --- examples/gno.land/r/mouss/home/home.gno | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/gno.land/r/mouss/home/home.gno b/examples/gno.land/r/mouss/home/home.gno index e0711b7c286..7c289fa2095 100644 --- a/examples/gno.land/r/mouss/home/home.gno +++ b/examples/gno.land/r/mouss/home/home.gno @@ -133,15 +133,15 @@ func Follow(addr std.Address) error { // Unfollow allows a user to unfollow my home page. func Unfollow(addr std.Address) error { - caller := std.PrevRealm().Addr() - if !isUser(caller) { - return config.ErrorUnauthorized - } - if !profile.Followers.Has(addr) { - return ufmt.Errorf("address %s is not following", addr) - } - profile.Followers.Remove(addr) - return nil + caller := std.PrevRealm().Addr() + if !isUser(caller) { + return config.ErrorUnauthorized + } + if !profile.Followers.Has(addr) { + return ufmt.Errorf("address %s is not following", addr) + } + profile.Followers.Remove(addr) + return nil } func isUser(addr std.Address) bool {