From 51a7593a2a890405863e5f3456a670644fb1c947 Mon Sep 17 00:00:00 2001 From: leohhhn Date: Tue, 16 Jan 2024 19:52:54 +0100 Subject: [PATCH 01/27] add sorting by title & pub date --- examples/gno.land/p/demo/blog/blog.gno | 31 +++++++++++++++++--------- examples/gno.land/p/demo/blog/gno.mod | 1 + examples/gno.land/p/demo/blog/util.gno | 14 +++++++++++- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/examples/gno.land/p/demo/blog/blog.gno b/examples/gno.land/p/demo/blog/blog.gno index 1cf37b7ad3a..bbca5fa9534 100644 --- a/examples/gno.land/p/demo/blog/blog.gno +++ b/examples/gno.land/p/demo/blog/blog.gno @@ -2,21 +2,25 @@ package blog import ( "errors" + "gno.land/p/demo/avl" + "gno.land/p/demo/mux" + "gno.land/p/demo/seqid" + "gno.land/p/demo/ufmt" + "std" "strconv" "strings" "time" - - "gno.land/p/demo/avl" - "gno.land/p/demo/mux" - "gno.land/p/demo/ufmt" ) type Blog struct { - Title string - Prefix string // i.e. r/gnoland/blog: - Posts avl.Tree // slug -> Post - NoBreadcrumb bool + Title string + Prefix string // i.e. r/gnoland/blog: + Posts avl.Tree // slug -> *Post + PostsPublished avl.Tree // published-date -> *Post + PostsAlphabetical avl.Tree // title -> *Post + NoBreadcrumb bool + PostIndex seqid.ID } func (b Blog) RenderLastPostsWidget(limit int) string { @@ -42,7 +46,7 @@ func (b Blog) RenderHome(res *mux.ResponseWriter, req *mux.Request) { } res.Write("
") - b.Posts.Iterate("", "", func(key string, value interface{}) bool { + b.PostsPublished.Iterate("", "", func(key string, value interface{}) bool { post := value.(*Post) res.Write(post.RenderListItem()) return false @@ -157,9 +161,15 @@ func (b *Blog) prepareAndSetPost(post *Post) error { // more input sanitization? post.Blog = b - post.UpdatedAt = time.Now() + post.UpdatedAt = post.CreatedAt + + trimmedTitleKey := strings.Replace(post.Title, " ", "", -1) + pubDateKey := makePubDate(post.CreatedAt, int64(b.PostIndex.Next())) + b.PostsAlphabetical.Set(trimmedTitleKey, post) + b.PostsPublished.Set(pubDateKey, post) b.Posts.Set(post.Slug, post) + return nil } @@ -236,6 +246,7 @@ func (p *Post) RenderListItem() string { output := "
\n\n" output += ufmt.Sprintf("## [%s](%s)\n", p.Title, p.URL()) output += ufmt.Sprintf("**[Learn More](%s)**\n", p.URL()) + // output += p.Summary() + "\n\n" // output += p.RenderTagList() + "\n\n" // output += formatAuthorAndDate(p.Author, p.CreatedAt) + "\n" diff --git a/examples/gno.land/p/demo/blog/gno.mod b/examples/gno.land/p/demo/blog/gno.mod index 65f58e7a0f6..bbea91ea08f 100644 --- a/examples/gno.land/p/demo/blog/gno.mod +++ b/examples/gno.land/p/demo/blog/gno.mod @@ -3,5 +3,6 @@ module gno.land/p/demo/blog require ( gno.land/p/demo/avl v0.0.0-latest gno.land/p/demo/mux v0.0.0-latest + gno.land/p/demo/seqid v0.0.0-latest gno.land/p/demo/ufmt v0.0.0-latest ) diff --git a/examples/gno.land/p/demo/blog/util.gno b/examples/gno.land/p/demo/blog/util.gno index b4a8652af72..8bc3b329177 100644 --- a/examples/gno.land/p/demo/blog/util.gno +++ b/examples/gno.land/p/demo/blog/util.gno @@ -1,7 +1,19 @@ package blog -import "strings" +import ( + "strconv" + "strings" + "time" +) func breadcrumb(parts []string) string { return "# " + strings.Join(parts, " / ") + "\n\n" } + +func makePubDate(t time.Time, id int64) string { + // We use the timestamp to sort by publish order. + // In case of multiple msgs to publish in the same transaction + // there will be a timestamp conflict (time.Now() is per transaction, not per msg). + // This functions assures that timestamp IDs are unique in this case. + return strconv.Itoa(int(t.Unix())) + "-" + strconv.Itoa(int(id)) +} From 57fe1881eb91e4770c45179b7fd43f38dccb5368 Mon Sep 17 00:00:00 2001 From: leohhhn Date: Sat, 20 Jan 2024 17:38:32 +0100 Subject: [PATCH 02/27] add publisher, authors, modify publish date. add nicer rendering --- examples/gno.land/p/demo/blog/blog.gno | 85 ++++++++++++------- examples/gno.land/p/demo/blog/util.gno | 10 --- examples/gno.land/r/gnoland/blog/admin.gno | 10 ++- examples/gno.land/r/gnoland/pages/admin.gno | 6 +- .../gno.land/r/gnoland/pages/page_about.gno | 2 +- .../r/gnoland/pages/page_ecosystem.gno | 2 +- .../gno.land/r/gnoland/pages/page_events.gno | 2 +- .../gno.land/r/gnoland/pages/page_gnolang.gno | 2 +- .../gno.land/r/gnoland/pages/page_gor.gno | 2 +- .../r/gnoland/pages/page_partners.gno | 2 +- .../gno.land/r/gnoland/pages/page_start.gno | 2 +- .../r/gnoland/pages/page_testnets.gno | 2 +- .../r/gnoland/pages/page_tokenomics.gno | 2 +- examples/gno.land/r/manfred/present/admin.gno | 6 +- .../r/manfred/present/present_miami23.gno | 2 +- gno.land/genesis/genesis_balances.txt | 1 + gno.land/genesis/genesis_txs.txt | 4 +- 17 files changed, 81 insertions(+), 61 deletions(-) diff --git a/examples/gno.land/p/demo/blog/blog.gno b/examples/gno.land/p/demo/blog/blog.gno index bbca5fa9534..8a9b5832dfe 100644 --- a/examples/gno.land/p/demo/blog/blog.gno +++ b/examples/gno.land/p/demo/blog/blog.gno @@ -66,19 +66,12 @@ func (b Blog) RenderPost(res *mux.ResponseWriter, req *mux.Request) { } p := post.(*Post) - if !b.NoBreadcrumb { - breadStr := breadcrumb([]string{ - ufmt.Sprintf("[%s](%s)", b.Title, b.Prefix), - "p", - p.Title, - }) - res.Write(breadStr) - } - - // output += ufmt.Sprintf("## [%s](%s)\n", p.Title, p.URL()) res.Write(p.Body + "\n\n") + res.Write("---\n\n") + res.Write(p.RenderTagList() + "\n\n") - res.Write(formatAuthorAndDate(p.Author, p.CreatedAt) + "\n\n") + res.Write(p.RenderAuthorList() + "\n\n") + res.Write(p.RenderPublishData() + "\n\n") // comments p.Comments.ReverseIterate("", "", func(key string, value interface{}) bool { @@ -128,19 +121,32 @@ func (b Blog) Render(path string) string { return router.Render(path) } -func (b *Blog) NewPost(author std.Address, slug, title, body string, tags []string) error { +func (b *Blog) NewPost(publisher std.Address, slug, title, body, pubDate string, authors, tags []string) error { _, found := b.Posts.Get(slug) if found { - return errors.New("slug already exists.") + return errors.New("slug already exists") + } + + var parsedTime time.Time + var err error + if pubDate != "" { + parsedTime, err = time.Parse(time.RFC3339, pubDate) + if err != nil { + return err + } + } else { + // If no publication date was passed in by caller, take current block time + parsedTime = time.Now() } post := Post{ - Author: author, + Publisher: publisher, + Authors: authors, Slug: slug, Title: title, Body: body, Tags: tags, - CreatedAt: time.Now(), + CreatedAt: parsedTime, } return b.prepareAndSetPost(&post) } @@ -150,24 +156,23 @@ func (b *Blog) prepareAndSetPost(post *Post) error { post.Body = strings.TrimSpace(post.Body) if post.Title == "" { - return errors.New("title is missing.") + return errors.New("title is missing") } if post.Body == "" { - return errors.New("body is missing.") + return errors.New("body is missing") } if post.Slug == "" { - return errors.New("slug is missing.") + return errors.New("slug is missing") } - // more input sanitization? post.Blog = b post.UpdatedAt = post.CreatedAt trimmedTitleKey := strings.Replace(post.Title, " ", "", -1) - pubDateKey := makePubDate(post.CreatedAt, int64(b.PostIndex.Next())) + pubDateKey := post.CreatedAt.Format(time.RFC3339) + b.PostsAlphabetical.Set(trimmedTitleKey, post) b.PostsPublished.Set(pubDateKey, post) - b.Posts.Set(post.Slug, post) return nil @@ -189,7 +194,8 @@ type Post struct { CreatedAt time.Time UpdatedAt time.Time Comments avl.Tree - Author std.Address + Authors []string + Publisher std.Address Tags []string CommentIndex int } @@ -259,7 +265,7 @@ func (p *Post) RenderTagList() string { if p == nil { return "error: no such post\n" } - output := "" + output := "Tags: " for idx, tag := range p.Tags { if idx > 0 { output += " " @@ -270,6 +276,29 @@ func (p *Post) RenderTagList() string { return output } +func (p *Post) RenderAuthorList() string { + out := "Written by: " + if p.Authors != nil { + for idx, author := range p.Authors { + out += author + if idx < len(p.Authors)-1 { + out += ", " + } + } + } + + return out +} + +func (p *Post) RenderPublishData() string { + out := "Published on " + out += p.CreatedAt.Format("02 Jan 2006") + " " + out += "by " + p.Publisher.String() + " " + out += "to " + p.Blog.Title + + return out +} + func (p *Post) URL() string { if p == nil { return p.Blog.Prefix + "404" @@ -298,15 +327,9 @@ type Comment struct { } func (c Comment) RenderListItem() string { - output := "" - output += ufmt.Sprintf("#### %s\n", formatAuthorAndDate(c.Author, c.CreatedAt)) + output := "" // todo see where it is used + //output += ufmt.Sprintf("#### %s\n", formatAuthorAndDate(c.Author, c.CreatedAt)) output += c.Comment + "\n" output += "\n" return output } - -func formatAuthorAndDate(author std.Address, createdAt time.Time) string { - authorString := author.String() // FIXME: username. - createdAtString := createdAt.Format("2006-01-02 3:04pm MST") - return ufmt.Sprintf("by %s on %s", authorString, createdAtString) -} diff --git a/examples/gno.land/p/demo/blog/util.gno b/examples/gno.land/p/demo/blog/util.gno index 8bc3b329177..22bc11bed07 100644 --- a/examples/gno.land/p/demo/blog/util.gno +++ b/examples/gno.land/p/demo/blog/util.gno @@ -1,19 +1,9 @@ package blog import ( - "strconv" "strings" - "time" ) func breadcrumb(parts []string) string { return "# " + strings.Join(parts, " / ") + "\n\n" } - -func makePubDate(t time.Time, id int64) string { - // We use the timestamp to sort by publish order. - // In case of multiple msgs to publish in the same transaction - // there will be a timestamp conflict (time.Now() is per transaction, not per msg). - // This functions assures that timestamp IDs are unique in this case. - return strconv.Itoa(int(t.Unix())) + "-" + strconv.Itoa(int(id)) -} diff --git a/examples/gno.land/r/gnoland/blog/admin.gno b/examples/gno.land/r/gnoland/blog/admin.gno index 646fe5f155e..d3d343a9e07 100644 --- a/examples/gno.land/r/gnoland/blog/admin.gno +++ b/examples/gno.land/r/gnoland/blog/admin.gno @@ -16,7 +16,9 @@ var ( func init() { // adminAddr = std.GetOrigCaller() // FIXME: find a way to use this from the main's genesis. - adminAddr = "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq" + //adminAddr = "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq" // mafnred + //adminAddr = "g1l9aypkr8xfvs82zeux486ddzec88ty69lue9de" // dev + adminAddr = "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5" // test1 } func AdminSetAdminAddr(addr std.Address) { @@ -39,12 +41,14 @@ func AdminRemoveModerator(addr std.Address) { moderatorList.Set(addr.String(), false) // FIXME: delete instead? } -func ModAddPost(slug, title, body, tags string) { +func ModAddPost(slug, title, body, publicationDate, authors, tags string) { assertIsModerator() caller := std.GetOrigCaller() tagList := strings.Split(tags, ",") - err := b.NewPost(caller, slug, title, body, tagList) + authorList := strings.Split(authors, ",") + + err := b.NewPost(caller, slug, title, body, publicationDate, authorList, tagList) checkErr(err) } diff --git a/examples/gno.land/r/gnoland/pages/admin.gno b/examples/gno.land/r/gnoland/pages/admin.gno index 39fba6d3274..ffebb991f7e 100644 --- a/examples/gno.land/r/gnoland/pages/admin.gno +++ b/examples/gno.land/r/gnoland/pages/admin.gno @@ -38,12 +38,14 @@ func AdminRemoveModerator(addr std.Address) { moderatorList.Set(addr.String(), false) // XXX: delete instead? } -func ModAddPost(slug, title, body, tags string) { +func ModAddPost(slug, title, body, publicationDate, authors, tags string) { assertIsModerator() caller := std.GetOrigCaller() tagList := strings.Split(tags, ",") - err := b.NewPost(caller, slug, title, body, tagList) + authorList := strings.Split(authors, ",") + + err := b.NewPost(caller, slug, title, body, publicationDate, authorList, tagList) checkErr(err) } diff --git a/examples/gno.land/r/gnoland/pages/page_about.gno b/examples/gno.land/r/gnoland/pages/page_about.gno index 9aba4e39f76..283401e59f4 100644 --- a/examples/gno.land/r/gnoland/pages/page_about.gno +++ b/examples/gno.land/r/gnoland/pages/page_about.gno @@ -16,5 +16,5 @@ This consensus mechanism also achieves higher security with fewer validators, op Any blockchain using Gnolang achieves succinctness, composability, expressivity, and completeness not found in any other smart contract platform. By observing a minimal structure, the design can endure over time and challenge the regime of information censorship we’re living in today.` - _ = b.NewPost("", path, title, body, nil) + _ = b.NewPost("", path, title, body, "", nil, nil) } diff --git a/examples/gno.land/r/gnoland/pages/page_ecosystem.gno b/examples/gno.land/r/gnoland/pages/page_ecosystem.gno index 68969c44529..53af37a75d5 100644 --- a/examples/gno.land/r/gnoland/pages/page_ecosystem.gno +++ b/examples/gno.land/r/gnoland/pages/page_ecosystem.gno @@ -31,5 +31,5 @@ Gnoswap is currently under development and led by the Onbloc team. Gnoswap will Through the Gno.land Developer Portal, new developers can explore the exciting world of Gnolang (Gno), a novel programming language that powers the Gno.land blockchain. If you want to interact with Gno.land, start writing a realm, build a dApp, or even port a Solidity contract to a Gnolang realm, you’ll find the resources to [get started here](https://docs.onbloc.xyz/).` ) - _ = b.NewPost("", path, title, body, nil) + _ = b.NewPost("", path, title, body, "", nil, nil) } diff --git a/examples/gno.land/r/gnoland/pages/page_events.gno b/examples/gno.land/r/gnoland/pages/page_events.gno index 18e7faeb3d3..ced3b6b7771 100644 --- a/examples/gno.land/r/gnoland/pages/page_events.gno +++ b/examples/gno.land/r/gnoland/pages/page_events.gno @@ -147,5 +147,5 @@ If you’re interested in building web3 with us, catch up with Gno.land in perso
` ) - _ = b.NewPost("", path, title, body, nil) + _ = b.NewPost("", path, title, body, "", nil, nil) } diff --git a/examples/gno.land/r/gnoland/pages/page_gnolang.gno b/examples/gno.land/r/gnoland/pages/page_gnolang.gno index f0c2bfe276d..5f6f4ece8a3 100644 --- a/examples/gno.land/r/gnoland/pages/page_gnolang.gno +++ b/examples/gno.land/r/gnoland/pages/page_gnolang.gno @@ -39,5 +39,5 @@ Using Gno, developers can rapidly accelerate application development and adopt a The Go language is so well designed that the Gno smart contract system will become the new gold standard for smart contract development and other blockchain applications. As a programming language that is universally adopted, secure, composable, and complete, Gno is essential for the broader adoption of web3 and its sustainable growth.` ) - _ = b.NewPost("", path, title, body, nil) + _ = b.NewPost("", path, title, body, "", nil, nil) } diff --git a/examples/gno.land/r/gnoland/pages/page_gor.gno b/examples/gno.land/r/gnoland/pages/page_gor.gno index 3a6bb022e09..2774157b8b1 100644 --- a/examples/gno.land/r/gnoland/pages/page_gor.gno +++ b/examples/gno.land/r/gnoland/pages/page_gor.gno @@ -217,5 +217,5 @@ Game of Realms participants and core contributors have made significant progress ` - _ = b.NewPost("", path, title, body, nil) + _ = b.NewPost("", path, title, body, "", nil, nil) } diff --git a/examples/gno.land/r/gnoland/pages/page_partners.gno b/examples/gno.land/r/gnoland/pages/page_partners.gno index 440302437fa..a68ff98a05c 100644 --- a/examples/gno.land/r/gnoland/pages/page_partners.gno +++ b/examples/gno.land/r/gnoland/pages/page_partners.gno @@ -17,5 +17,5 @@ Are you a builder, tinkerer, or researcher? If you’re looking to create awesom ` - _ = b.NewPost("", path, title, body, nil) + _ = b.NewPost("", path, title, body, "", nil, nil) } diff --git a/examples/gno.land/r/gnoland/pages/page_start.gno b/examples/gno.land/r/gnoland/pages/page_start.gno index a36ec6e52b1..1e1e27ca655 100644 --- a/examples/gno.land/r/gnoland/pages/page_start.gno +++ b/examples/gno.land/r/gnoland/pages/page_start.gno @@ -17,5 +17,5 @@ func init() { - [Install Gno Key](/r/demo/boards:testboard/5) - TODO: add more links ` - _ = b.NewPost("", path, title, body, nil) + _ = b.NewPost("", path, title, body, "", nil, nil) } diff --git a/examples/gno.land/r/gnoland/pages/page_testnets.gno b/examples/gno.land/r/gnoland/pages/page_testnets.gno index b6c09ab71ee..1158c4cfbbc 100644 --- a/examples/gno.land/r/gnoland/pages/page_testnets.gno +++ b/examples/gno.land/r/gnoland/pages/page_testnets.gno @@ -15,5 +15,5 @@ func init() { See CONTRIBUTING.md on GitHub. ` - _ = b.NewPost("", path, title, body, nil) + _ = b.NewPost("", path, title, body, "", nil, nil) } diff --git a/examples/gno.land/r/gnoland/pages/page_tokenomics.gno b/examples/gno.land/r/gnoland/pages/page_tokenomics.gno index de899ae0a70..b2e6100bae8 100644 --- a/examples/gno.land/r/gnoland/pages/page_tokenomics.gno +++ b/examples/gno.land/r/gnoland/pages/page_tokenomics.gno @@ -7,5 +7,5 @@ func init() { // XXX: description = """ body = `Lorem Ipsum` ) - _ = b.NewPost("", path, title, body, nil) + _ = b.NewPost("", path, title, body, "", nil, nil) } diff --git a/examples/gno.land/r/manfred/present/admin.gno b/examples/gno.land/r/manfred/present/admin.gno index ff0cb075656..8157a11bfd3 100644 --- a/examples/gno.land/r/manfred/present/admin.gno +++ b/examples/gno.land/r/manfred/present/admin.gno @@ -38,12 +38,14 @@ func AdminRemoveModerator(addr std.Address) { moderatorList.Set(addr.String(), false) // XXX: delete instead? } -func ModAddPost(slug, title, body, tags string) { +func ModAddPost(slug, title, body, publicationDate, authors, tags string) { assertIsModerator() caller := std.GetOrigCaller() tagList := strings.Split(tags, ",") - err := b.NewPost(caller, slug, title, body, tagList) + authorList := strings.Split(authors, ",") + + err := b.NewPost(caller, slug, title, body, publicationDate, authorList, tagList) checkErr(err) } diff --git a/examples/gno.land/r/manfred/present/present_miami23.gno b/examples/gno.land/r/manfred/present/present_miami23.gno index 36b1980bb0b..cff2240945e 100644 --- a/examples/gno.land/r/manfred/present/present_miami23.gno +++ b/examples/gno.land/r/manfred/present/present_miami23.gno @@ -40,5 +40,5 @@ Rendered by Gno. - Engage in workshops. - Connect and have fun with colleagues. ` - _ = b.NewPost(adminAddr, path, title, body, []string{"demo", "portal-loop", "miami"}) + _ = b.NewPost(adminAddr, path, title, body, "", nil, []string{"demo", "portal-loop", "miami"}) } diff --git a/gno.land/genesis/genesis_balances.txt b/gno.land/genesis/genesis_balances.txt index 87c5389efe6..7e21042e954 100644 --- a/gno.land/genesis/genesis_balances.txt +++ b/gno.land/genesis/genesis_balances.txt @@ -7,6 +7,7 @@ # Test accounts. g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5=10000000000000ugnot # test1 g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj=10000000000000ugnot # test2 +g1l9aypkr8xfvs82zeux486ddzec88ty69lue9de=10000000000000ugnot # dev # Faucet accounts. g1f4v282mwyhu29afke4vq5r2xzcm6z3ftnugcnv=1000000000000ugnot # faucet0 (jae) diff --git a/gno.land/genesis/genesis_txs.txt b/gno.land/genesis/genesis_txs.txt index 33257380260..32876c86d82 100644 --- a/gno.land/genesis/genesis_txs.txt +++ b/gno.land/genesis/genesis_txs.txt @@ -12,6 +12,4 @@ {"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateThread","args":["1","NFT example","NFT's are all the rage these days, for various reasons.\n\nI read over EIP-721 which appears to be the de-facto NFT standard on Ethereum. Then, made a sample implementation of EIP-721 (let's here called GRC-721). The implementation isn't complete, but it demonstrates the main functionality.\n\n - [EIP-721](https://eips.ethereum.org/EIPS/eip-721)\n - [gno.land/r/demo/nft/nft.gno](https://gno.land/r/demo/nft/nft.gno)\n - [zrealm_nft3.gno test](https://github.com/gnolang/gno/blob/master/examples/gno.land/r/demo/nft/z_3_filetest.gno)\n\nIn short, this demonstrates how to implement Ethereum contract interfaces in Gno.land; by using only standard Go language features.\n\nPlease leave a comment ([guide](https://gno.land/r/demo/boards:testboard/1)).\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"A+FhNtsXHjLfSJk1lB8FbiL4mGPjc50Kt81J7EKDnJ2y"},"signature":"ZXfrTiHxPFQL8uSm+Tv7WXIHPMca9okhm94RAlC6YgNbB1VHQYYpoP4w+cnL3YskVzGrOZxensXa9CAZ+cNNeg=="}],"memo":""} {"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateThread","args":["1","Simple echo example with coins","This is a simple test realm contract that demonstrates how to use the banker.\n\nSee [gno.land/r/demo/banktest/banktest.gno](/r/banktest/banktest.gno) to see the original contract code.\n\nThis article will go through each line to explain how it works.\n\n```go\npackage banktest\n```\n\nThis package is locally named \"banktest\" (could be anything).\n\n```go\nimport (\n\t\"std\"\n)\n```\n\nThe \"std\" package is defined by the gno code in stdlibs/std/. \u003c/br\u003e\nSelf explanatory; and you'll see more usage from std later.\n\n```go\ntype activity struct {\n\tcaller std.Address\n\tsent std.Coins\n\treturned std.Coins\n\ttime std.Time\n}\n\nfunc (act *activity) String() string {\n\treturn act.caller.String() + \" \" +\n\t\tact.sent.String() + \" sent, \" +\n\t\tact.returned.String() + \" returned, at \" +\n\t\tstd.FormatTimestamp(act.time, \"2006-01-02 3:04pm MST\")\n}\n\nvar latest [10]*activity\n```\n\nThis is just maintaining a list of recent activity to this contract.\nNotice that the \"latest\" variable is defined \"globally\" within\nthe context of the realm with path \"gno.land/r/demo/banktest\".\n\nThis means that calls to functions defined within this package\nare encapsulated within this \"data realm\", where the data is \nmutated based on transactions that can potentially cross many\nrealm and non-realm packge boundaries (in the call stack).\n\n```go\n// Deposit will take the coins (to the realm's pkgaddr) or return them to user.\nfunc Deposit(returnDenom string, returnAmount int64) string {\n\tstd.AssertOriginCall()\n\tcaller := std.GetOrigCaller()\n\tsend := std.Coins{{returnDenom, returnAmount}}\n```\n\nThis is the beginning of the definition of the contract function named\n\"Deposit\". `std.AssertOriginCall() asserts that this function was called by a\ngno transactional Message. The caller is the user who signed off on this\ntransactional message. Send is the amount of deposit sent along with this\nmessage.\n\n```go\n\t// record activity\n\tact := \u0026activity{\n\t\tcaller: caller,\n\t\tsent: std.GetOrigSend(),\n\t\treturned: send,\n\t\ttime: std.GetTimestamp(),\n\t}\n\tfor i := len(latest) - 2; i \u003e= 0; i-- {\n\t\tlatest[i+1] = latest[i] // shift by +1.\n\t}\n\tlatest[0] = act\n```\n\nUpdating the \"latest\" array for viewing at gno.land/r/demo/banktest: (w/ trailing colon).\n\n```go\n\t// return if any.\n\tif returnAmount \u003e 0 {\n```\n\nIf the user requested the return of coins...\n\n```go\n\t\tbanker := std.GetBanker(std.BankerTypeOrigSend)\n```\n\nuse a std.Banker instance to return any deposited coins to the original sender.\n\n```go\n\t\tpkgaddr := std.GetOrigPkgAddr()\n\t\t// TODO: use std.Coins constructors, this isn't generally safe.\n\t\tbanker.SendCoins(pkgaddr, caller, send)\n\t\treturn \"returned!\"\n```\n\nNotice that each realm package has an associated Cosmos address.\n\n\nFinally, the results are rendered via an ABCI query call when you visit [/r/banktest:](/r/banktest:).\n\n```go\nfunc Render(path string) string {\n\t// get realm coins.\n\tbanker := std.GetBanker(std.BankerTypeReadonly)\n\tcoins := banker.GetCoins(std.GetOrigPkgAddr())\n\n\t// render\n\tres := \"\"\n\tres += \"## recent activity\\n\"\n\tres += \"\\n\"\n\tfor _, act := range latest {\n\t\tif act == nil {\n\t\t\tbreak\n\t\t}\n\t\tres += \" * \" + act.String() + \"\\n\"\n\t}\n\tres += \"\\n\"\n\tres += \"## total deposits\\n\"\n\tres += coins.String()\n\treturn res\n}\n```\n\nYou can call this contract yourself, by vistiing [/r/banktest](/r/banktest) and the [quickstart guide](/r/boards:testboard/4).\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"A+FhNtsXHjLfSJk1lB8FbiL4mGPjc50Kt81J7EKDnJ2y"},"signature":"iZX/llZlNTdZMLv1goCTgK2bWqzT8enlTq56wMTCpVxJGA0BTvuEM5Nnt9vrnlG6Taqj2GuTrmEnJBkDFTmt9g=="}],"memo":""} {"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateThread","args":["1","TASK: Describe in your words","Describe in an essay (250+ words), on your favorite medium, why you are interested in gno.land and gnolang.\n\nReply here with a URL link to your written piece as a comment, for rewards.\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AmG6kzznyo1uNqWPAYU6wDpsmzQKDaEOrVRaZ08vOyX0"},"signature":"4HBNtrta8HdeHj4JTN56PBTRK8GOe31NMRRXDiyYtjozuyRdWfOGEsGjGgHWcoBUJq6DepBgD4FetdqfhZ6TNQ=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateThread","args":["1","Getting Started","This is a demo of Gno smart contract programming. This document was\nconstructed by Gno onto a smart contract hosted on the data Realm\nname [\"gno.land/r/demo/boards\"](https://gno.land/r/demo/boards/)\n([github](https://github.com/gnolang/gno/tree/master/examples/gno.land/r/demo/boards)).\n\n\n\n## Build `gnokey`, create your account, and interact with Gno.\n\nNOTE: Where you see `--remote %%REMOTE%%` here, that flag can be replaced\nwith `--remote localhost:26657` for local testnets.\n\n### Build `gnokey`.\n\n```bash\ngit clone git@github.com:gnolang/gno.git\ncd ./gno\nmake\n```\n\n### Generate a seed/mnemonic code.\n\n```bash\n./build/gnokey generate\n```\n\nNOTE: You can generate 24 words with any good bip39 generator.\n\n### Create a new account using your mnemonic.\n\n```bash\n./build/gnokey add KEYNAME --recover\n```\n\nNOTE: `KEYNAME` is your key identifier, and should be changed.\n\n### Verify that you can see your account locally.\n\n```bash\n./build/gnokey list\n```\n\n## Interact with the blockchain:\n\n### Get your current balance, account number, and sequence number.\n\n```bash\n./build/gnokey query auth/accounts/ACCOUNT_ADDR --remote %%REMOTE%%\n```\n\nNOTE: you can retrieve your `ACCOUNT_ADDR` with `./build/gnokey list`.\n\n### Acquire testnet tokens using the official faucet.\n\nGo to https://gno.land/faucet\n\n### Create a board with a smart contract call.\n\nNOTE: `BOARDNAME` will be the slug of the board, and should be changed.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateBoard\" --args \"BOARDNAME\" --gas-fee \"1000000ugnot\" --gas-wanted \"2000000\" --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateBoard\n\nNext, query for the permanent board ID by querying (you need this to create a new post):\n\n```bash\n./build/gnokey query \"vm/qeval\" --data \"gno.land/r/demo/boards\nGetBoardIDFromName(\\\"BOARDNAME\\\")\" --remote %%REMOTE%%\n```\n\n### Create a post of a board with a smart contract call.\n\nNOTE: If a board was created successfully, your SEQUENCE_NUMBER would have increased.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateThread\" --args BOARD_ID --args \"Hello gno.land\" --args\\#file \"./examples/gno.land/r/demo/boards/example_post.md\" --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateThread\n\n### Create a comment to a post.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateReply\" --args \"BOARD_ID\" --args \"1\" --args \"1\" --args \"Nice to meet you too.\" --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateReply\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards\nBOARDNAME/1\" --remote %%REMOTE%%\n```\n\n### Render page with optional path expression.\n\nThe contents of `https://gno.land/r/demo/boards:` and `https://gno.land/r/demo/boards:gnolang` are rendered by calling\nthe `Render(path string)` function like so:\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards\ngnolang\"\n```\n\n## Starting a local `gnoland` node:\n\n### Add test account.\n\n```bash\n./build/gnokey add test1 --recover\n```\n\nUse this mneonic:\n\u003e source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast\n\n### Start `gnoland` node.\n\n```bash\n./build/gnoland\n```\n\nNOTE: This can be reset with `make reset`\n\n### Publish the \"gno.land/p/demo/avl\" package.\n\n```bash\n./build/gnokey maketx addpkg test1 --pkgpath \"gno.land/p/demo/avl\" --pkgdir \"examples/gno.land/p/demo/avl\" --deposit 100000000ugnot --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote localhost:26657\n```\n\n### Publish the \"gno.land/r/demo/boards\" realm package.\n\n```bash\n./build/gnokey maketx addpkg test1 --pkgpath \"gno.land/r/demo/boards\" --pkgdir \"examples/gno.land/r/demo/boards\" --deposit 100000000ugnot --gas-fee 1000000ugnot --gas-wanted 300000000 --broadcast true --chainid %%CHAINID%% --remote localhost:26657\n```\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/gnoland/blog","func":"ModAddPost","args":["post1","First post","Lorem Ipsum", "tag1,tag2"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/gnoland/blog","func":"ModAddPost","args":["post2","Second post","Lorem Ipsum", "tag1,tag3"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateThread","args":["1","Getting Started","This is a demo of Gno smart contract programming. This document was\nconstructed by Gno onto a smart contract hosted on the data Realm\nname [\"gno.land/r/demo/boards\"](https://gno.land/r/demo/boards/)\n([github](https://github.com/gnolang/gno/tree/master/examples/gno.land/r/demo/boards)).\n\n\n\n## Build `gnokey`, create your account, and interact with Gno.\n\nNOTE: Where you see `--remote %%REMOTE%%` here, that flag can be replaced\nwith `--remote localhost:26657` for local testnets.\n\n### Build `gnokey`.\n\n```bash\ngit clone git@github.com:gnolang/gno.git\ncd ./gno\nmake\n```\n\n### Generate a seed/mnemonic code.\n\n```bash\n./build/gnokey generate\n```\n\nNOTE: You can generate 24 words with any good bip39 generator.\n\n### Create a new account using your mnemonic.\n\n```bash\n./build/gnokey add KEYNAME --recover\n```\n\nNOTE: `KEYNAME` is your key identifier, and should be changed.\n\n### Verify that you can see your account locally.\n\n```bash\n./build/gnokey list\n```\n\n## Interact with the blockchain:\n\n### Get your current balance, account number, and sequence number.\n\n```bash\n./build/gnokey query auth/accounts/ACCOUNT_ADDR --remote %%REMOTE%%\n```\n\nNOTE: you can retrieve your `ACCOUNT_ADDR` with `./build/gnokey list`.\n\n### Acquire testnet tokens using the official faucet.\n\nGo to https://gno.land/faucet\n\n### Create a board with a smart contract call.\n\nNOTE: `BOARDNAME` will be the slug of the board, and should be changed.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateBoard\" --args \"BOARDNAME\" --gas-fee \"1000000ugnot\" --gas-wanted \"2000000\" --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateBoard\n\nNext, query for the permanent board ID by querying (you need this to create a new post):\n\n```bash\n./build/gnokey query \"vm/qeval\" --data \"gno.land/r/demo/boards\nGetBoardIDFromName(\\\"BOARDNAME\\\")\" --remote %%REMOTE%%\n```\n\n### Create a post of a board with a smart contract call.\n\nNOTE: If a board was created successfully, your SEQUENCE_NUMBER would have increased.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateThread\" --args BOARD_ID --args \"Hello gno.land\" --args\\#file \"./examples/gno.land/r/demo/boards/example_post.md\" --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateThread\n\n### Create a comment to a post.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateReply\" --args \"BOARD_ID\" --args \"1\" --args \"1\" --args \"Nice to meet you too.\" --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateReply\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards\nBOARDNAME/1\" --remote %%REMOTE%%\n```\n\n### Render page with optional path expression.\n\nThe contents of `https://gno.land/r/demo/boards:` and `https://gno.land/r/demo/boards:gnolang` are rendered by calling\nthe `Render(path string)` function like so:\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards\ngnolang\"\n```\n\n## Starting a local `gnoland` node:\n\n### Add test account.\n\n```bash\n./build/gnokey add test1 --recover\n```\n\nUse this mneonic:\n\u003e source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast\n\n### Start `gnoland` node.\n\n```bash\n./build/gnoland\n```\n\nNOTE: This can be reset with `make reset`\n\n### Publish the \"gno.land/p/demo/avl\" package.\n\n```bash\n./build/gnokey maketx addpkg test1 --pkgpath \"gno.land/p/demo/avl\" --pkgdir \"examples/gno.land/p/demo/avl\" --deposit 100000000ugnot --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote localhost:26657\n```\n\n### Publish the \"gno.land/r/demo/boards\" realm package.\n\n```bash\n./build/gnokey maketx addpkg test1 --pkgpath \"gno.land/r/demo/boards\" --pkgdir \"examples/gno.land/r/demo/boards\" --deposit 100000000ugnot --gas-fee 1000000ugnot --gas-wanted 300000000 --broadcast true --chainid %%CHAINID%% --remote localhost:26657\n```\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} \ No newline at end of file From 013a6a29516fcc2052380ce3437d8c00c729029b Mon Sep 17 00:00:00 2001 From: leohhhn Date: Sat, 20 Jan 2024 17:50:11 +0100 Subject: [PATCH 03/27] remove usage of seqid --- examples/gno.land/p/demo/blog/blog.gno | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/gno.land/p/demo/blog/blog.gno b/examples/gno.land/p/demo/blog/blog.gno index 8a9b5832dfe..06b3426db23 100644 --- a/examples/gno.land/p/demo/blog/blog.gno +++ b/examples/gno.land/p/demo/blog/blog.gno @@ -4,7 +4,6 @@ import ( "errors" "gno.land/p/demo/avl" "gno.land/p/demo/mux" - "gno.land/p/demo/seqid" "gno.land/p/demo/ufmt" "std" @@ -20,7 +19,6 @@ type Blog struct { PostsPublished avl.Tree // published-date -> *Post PostsAlphabetical avl.Tree // title -> *Post NoBreadcrumb bool - PostIndex seqid.ID } func (b Blog) RenderLastPostsWidget(limit int) string { @@ -261,6 +259,7 @@ func (p *Post) RenderListItem() string { return output } +// Render post tags func (p *Post) RenderTagList() string { if p == nil { return "error: no such post\n" @@ -276,9 +275,11 @@ func (p *Post) RenderTagList() string { return output } +// Render authors if there are any func (p *Post) RenderAuthorList() string { - out := "Written by: " + out := "" if p.Authors != nil { + out = "Written by: " for idx, author := range p.Authors { out += author if idx < len(p.Authors)-1 { From 2fcd656b1550560e8a018b50a312e4d6979b33c0 Mon Sep 17 00:00:00 2001 From: leohhhn Date: Sat, 20 Jan 2024 18:35:06 +0100 Subject: [PATCH 04/27] reverse sort order --- examples/gno.land/p/demo/blog/blog.gno | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gno.land/p/demo/blog/blog.gno b/examples/gno.land/p/demo/blog/blog.gno index 06b3426db23..1fa067a94df 100644 --- a/examples/gno.land/p/demo/blog/blog.gno +++ b/examples/gno.land/p/demo/blog/blog.gno @@ -44,7 +44,7 @@ func (b Blog) RenderHome(res *mux.ResponseWriter, req *mux.Request) { } res.Write("
") - b.PostsPublished.Iterate("", "", func(key string, value interface{}) bool { + b.PostsPublished.ReverseIterate("", "", func(key string, value interface{}) bool { post := value.(*Post) res.Write(post.RenderListItem()) return false From 4fa2e983e75bda61a905207619bae3b1e6e66093 Mon Sep 17 00:00:00 2001 From: leohhhn Date: Mon, 22 Jan 2024 14:53:14 +0100 Subject: [PATCH 05/27] update ModEditPost --- examples/gno.land/p/demo/blog/blog.gno | 12 ++++++++++-- examples/gno.land/r/gnoland/blog/admin.gno | 10 ++++++---- examples/gno.land/r/gnoland/blog/gnoblog.gno | 7 +++++++ examples/gno.land/r/gnoland/blog/gnoblog_test.gno | 4 ++-- examples/gno.land/r/gnoland/pages/admin.gno | 6 ++++-- examples/gno.land/r/manfred/present/admin.gno | 6 ++++-- 6 files changed, 33 insertions(+), 12 deletions(-) diff --git a/examples/gno.land/p/demo/blog/blog.gno b/examples/gno.land/p/demo/blog/blog.gno index 1fa067a94df..e58fd21e44e 100644 --- a/examples/gno.land/p/demo/blog/blog.gno +++ b/examples/gno.land/p/demo/blog/blog.gno @@ -164,7 +164,7 @@ func (b *Blog) prepareAndSetPost(post *Post) error { } post.Blog = b - post.UpdatedAt = post.CreatedAt + post.UpdatedAt = time.Now() trimmedTitleKey := strings.Replace(post.Title, " ", "", -1) pubDateKey := post.CreatedAt.Format(time.RFC3339) @@ -198,10 +198,18 @@ type Post struct { CommentIndex int } -func (p *Post) Update(title, body string, tags []string) error { +func (p *Post) Update(title, body, publicationDate string, authors, tags []string) error { p.Title = title p.Body = body p.Tags = tags + p.Authors = authors + + parsedTime, err := time.Parse(time.RFC3339, publicationDate) + if err != nil { + return err + } + + p.CreatedAt = parsedTime return p.Blog.prepareAndSetPost(p) } diff --git a/examples/gno.land/r/gnoland/blog/admin.gno b/examples/gno.land/r/gnoland/blog/admin.gno index d3d343a9e07..dc386c3c622 100644 --- a/examples/gno.land/r/gnoland/blog/admin.gno +++ b/examples/gno.land/r/gnoland/blog/admin.gno @@ -17,8 +17,8 @@ var ( func init() { // adminAddr = std.GetOrigCaller() // FIXME: find a way to use this from the main's genesis. //adminAddr = "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq" // mafnred - //adminAddr = "g1l9aypkr8xfvs82zeux486ddzec88ty69lue9de" // dev - adminAddr = "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5" // test1 + adminAddr = "g1l9aypkr8xfvs82zeux486ddzec88ty69lue9de" // dev + //adminAddr = "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5" // test1 } func AdminSetAdminAddr(addr std.Address) { @@ -52,11 +52,13 @@ func ModAddPost(slug, title, body, publicationDate, authors, tags string) { checkErr(err) } -func ModEditPost(slug, title, body, tags string) { +func ModEditPost(slug, title, body, publicationDate, authors, tags string) { assertIsModerator() tagList := strings.Split(tags, ",") - err := b.GetPost(slug).Update(title, body, tagList) + authorList := strings.Split(authors, ",") + + err := b.GetPost(slug).Update(title, body, publicationDate, authorList, tagList) checkErr(err) } diff --git a/examples/gno.land/r/gnoland/blog/gnoblog.gno b/examples/gno.land/r/gnoland/blog/gnoblog.gno index cad84507614..15cb04c1c46 100644 --- a/examples/gno.land/r/gnoland/blog/gnoblog.gno +++ b/examples/gno.land/r/gnoland/blog/gnoblog.gno @@ -20,6 +20,13 @@ func AddComment(postSlug, comment string) { checkErr(err) } +func PostExists(slug string) bool { + if b.GetPost(slug) == nil { + return false + } + return true +} + func Render(path string) string { return b.Render(path) } diff --git a/examples/gno.land/r/gnoland/blog/gnoblog_test.gno b/examples/gno.land/r/gnoland/blog/gnoblog_test.gno index e98b34fdc2b..411bb40caa7 100644 --- a/examples/gno.land/r/gnoland/blog/gnoblog_test.gno +++ b/examples/gno.land/r/gnoland/blog/gnoblog_test.gno @@ -108,14 +108,14 @@ comment2 // edit post. { - ModEditPost("slug2", "title2++", "body2++", "tag1,tag4") + ModEditPost("slug2", "title2++", "body2++", "2009-11-10T23:00:00Z", "manfred ", "tag1,tag4") got := Render("p/slug2") expected := ` # [Gnoland's Blog](/r/gnoland/blog:) / p / title2++ body2++ -[#tag1](/r/gnoland/blog:t/tag1) [#tag4](/r/gnoland/blog:t/tag4) +[#tag1](/r/gnoland/blog:t/tag1) [#tag4](/r/gnoland/blog:t/tag4) by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq on 2009-02-13 11:31pm UTC diff --git a/examples/gno.land/r/gnoland/pages/admin.gno b/examples/gno.land/r/gnoland/pages/admin.gno index ffebb991f7e..ab447e8f604 100644 --- a/examples/gno.land/r/gnoland/pages/admin.gno +++ b/examples/gno.land/r/gnoland/pages/admin.gno @@ -49,11 +49,13 @@ func ModAddPost(slug, title, body, publicationDate, authors, tags string) { checkErr(err) } -func ModEditPost(slug, title, body, tags string) { +func ModEditPost(slug, title, body, publicationDate, authors, tags string) { assertIsModerator() tagList := strings.Split(tags, ",") - err := b.GetPost(slug).Update(title, body, tagList) + authorList := strings.Split(authors, ",") + + err := b.GetPost(slug).Update(title, body, publicationDate, authorList, tagList) checkErr(err) } diff --git a/examples/gno.land/r/manfred/present/admin.gno b/examples/gno.land/r/manfred/present/admin.gno index 8157a11bfd3..60af578b54f 100644 --- a/examples/gno.land/r/manfred/present/admin.gno +++ b/examples/gno.land/r/manfred/present/admin.gno @@ -49,11 +49,13 @@ func ModAddPost(slug, title, body, publicationDate, authors, tags string) { checkErr(err) } -func ModEditPost(slug, title, body, tags string) { +func ModEditPost(slug, title, body, publicationDate, authors, tags string) { assertIsModerator() tagList := strings.Split(tags, ",") - err := b.GetPost(slug).Update(title, body, tagList) + authorList := strings.Split(authors, ",") + + err := b.GetPost(slug).Update(title, body, publicationDate, authorList, tagList) checkErr(err) } From 524df94968d1e9f7a1cb07baf62389d84f2d8a3e Mon Sep 17 00:00:00 2001 From: leohhhn Date: Tue, 23 Jan 2024 11:25:46 +0100 Subject: [PATCH 06/27] modify post footer, post list item --- examples/gno.land/r/gnoland/blog/admin.gno | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/gno.land/r/gnoland/blog/admin.gno b/examples/gno.land/r/gnoland/blog/admin.gno index dc386c3c622..55c4413f259 100644 --- a/examples/gno.land/r/gnoland/blog/admin.gno +++ b/examples/gno.land/r/gnoland/blog/admin.gno @@ -17,8 +17,8 @@ var ( func init() { // adminAddr = std.GetOrigCaller() // FIXME: find a way to use this from the main's genesis. //adminAddr = "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq" // mafnred - adminAddr = "g1l9aypkr8xfvs82zeux486ddzec88ty69lue9de" // dev - //adminAddr = "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5" // test1 + //adminAddr = "g1l9aypkr8xfvs82zeux486ddzec88ty69lue9de" // dev + adminAddr = "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5" // test1 } func AdminSetAdminAddr(addr std.Address) { From 1f6afa0cbf1dfb3082a3b5471b4d97e587c59dca Mon Sep 17 00:00:00 2001 From: leohhhn Date: Tue, 23 Jan 2024 16:42:18 +0100 Subject: [PATCH 07/27] wip fixing bugs --- examples/gno.land/p/demo/blog/blog.gno | 33 ++++++++++++---------- examples/gno.land/r/gnoland/blog/admin.gno | 11 ++++++-- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/examples/gno.land/p/demo/blog/blog.gno b/examples/gno.land/p/demo/blog/blog.gno index e58fd21e44e..bd90e59a63c 100644 --- a/examples/gno.land/p/demo/blog/blog.gno +++ b/examples/gno.land/p/demo/blog/blog.gno @@ -256,12 +256,12 @@ func (p *Post) RenderListItem() string { return "error: no such post\n" } output := "
\n\n" - output += ufmt.Sprintf("## [%s](%s)\n", p.Title, p.URL()) - output += ufmt.Sprintf("**[Learn More](%s)**\n", p.URL()) + output += ufmt.Sprintf("### [%s](%s)\n", p.Title, p.URL()) + //output += ufmt.Sprintf("**[Learn More](%s)**\n\n", p.URL()) + output += " " + p.CreatedAt.String() + " " // output += p.Summary() + "\n\n" // output += p.RenderTagList() + "\n\n" - // output += formatAuthorAndDate(p.Author, p.CreatedAt) + "\n" output += "\n" output += "
" return output @@ -279,29 +279,32 @@ func (p *Post) RenderTagList() string { } tagURL := p.Blog.Prefix + "t/" + tag output += ufmt.Sprintf("[#%s](%s)", tag, tagURL) + } return output } // Render authors if there are any func (p *Post) RenderAuthorList() string { - out := "" - if p.Authors != nil { - out = "Written by: " - for idx, author := range p.Authors { - out += author - if idx < len(p.Authors)-1 { - out += ", " - } - } + out := "Written " + if len(p.Authors) != 0 { + out += "by " + p.Authors[0] + + //for idx, author := range p.Authors { + // out += author + // if idx < len(p.Authors)-1 { + // out += ", " + // } + //} } - + //str := p.CreatedAt.String() + //out += " on " + str + " " + //_ = str return out } func (p *Post) RenderPublishData() string { - out := "Published on " - out += p.CreatedAt.Format("02 Jan 2006") + " " + out := "Published " out += "by " + p.Publisher.String() + " " out += "to " + p.Blog.Title diff --git a/examples/gno.land/r/gnoland/blog/admin.gno b/examples/gno.land/r/gnoland/blog/admin.gno index 55c4413f259..2c17b9a5913 100644 --- a/examples/gno.land/r/gnoland/blog/admin.gno +++ b/examples/gno.land/r/gnoland/blog/admin.gno @@ -45,8 +45,15 @@ func ModAddPost(slug, title, body, publicationDate, authors, tags string) { assertIsModerator() caller := std.GetOrigCaller() - tagList := strings.Split(tags, ",") - authorList := strings.Split(authors, ",") + + var tagList []string + if tags != "" { + tagList = strings.Split(tags, ",") + } + var authorList []string + if authors != "" { + authorList = strings.Split(authors, ",") + } err := b.NewPost(caller, slug, title, body, publicationDate, authorList, tagList) checkErr(err) From a52b6e20084a6d2899b28298a9796ab475eada93 Mon Sep 17 00:00:00 2001 From: leohhhn Date: Fri, 26 Jan 2024 11:33:02 +0100 Subject: [PATCH 08/27] add rendering back --- examples/gno.land/p/demo/blog/blog.gno | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/examples/gno.land/p/demo/blog/blog.gno b/examples/gno.land/p/demo/blog/blog.gno index bd90e59a63c..3fb9ed7a8da 100644 --- a/examples/gno.land/p/demo/blog/blog.gno +++ b/examples/gno.land/p/demo/blog/blog.gno @@ -259,7 +259,7 @@ func (p *Post) RenderListItem() string { output += ufmt.Sprintf("### [%s](%s)\n", p.Title, p.URL()) //output += ufmt.Sprintf("**[Learn More](%s)**\n\n", p.URL()) - output += " " + p.CreatedAt.String() + " " + output += " " + p.CreatedAt.Format("02 Jan 2006") // output += p.Summary() + "\n\n" // output += p.RenderTagList() + "\n\n" output += "\n" @@ -288,18 +288,17 @@ func (p *Post) RenderTagList() string { func (p *Post) RenderAuthorList() string { out := "Written " if len(p.Authors) != 0 { - out += "by " + p.Authors[0] - - //for idx, author := range p.Authors { - // out += author - // if idx < len(p.Authors)-1 { - // out += ", " - // } - //} + out += "by " + + for idx, author := range p.Authors { + out += author + if idx < len(p.Authors)-1 { + out += ", " + } + } } - //str := p.CreatedAt.String() - //out += " on " + str + " " - //_ = str + out += " on " + p.CreatedAt.Format("02 Jan 2006") + return out } From dd3874252fc6e29c056655d6bd85c99431c6629a Mon Sep 17 00:00:00 2001 From: leohhhn Date: Fri, 26 Jan 2024 11:36:32 +0100 Subject: [PATCH 09/27] remove leftovers --- examples/gno.land/r/gnoland/blog/admin.gno | 4 +--- gno.land/genesis/genesis_balances.txt | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/gno.land/r/gnoland/blog/admin.gno b/examples/gno.land/r/gnoland/blog/admin.gno index 2c17b9a5913..d21e794f081 100644 --- a/examples/gno.land/r/gnoland/blog/admin.gno +++ b/examples/gno.land/r/gnoland/blog/admin.gno @@ -16,9 +16,7 @@ var ( func init() { // adminAddr = std.GetOrigCaller() // FIXME: find a way to use this from the main's genesis. - //adminAddr = "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq" // mafnred - //adminAddr = "g1l9aypkr8xfvs82zeux486ddzec88ty69lue9de" // dev - adminAddr = "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5" // test1 + adminAddr = "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq" } func AdminSetAdminAddr(addr std.Address) { diff --git a/gno.land/genesis/genesis_balances.txt b/gno.land/genesis/genesis_balances.txt index 7e21042e954..87c5389efe6 100644 --- a/gno.land/genesis/genesis_balances.txt +++ b/gno.land/genesis/genesis_balances.txt @@ -7,7 +7,6 @@ # Test accounts. g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5=10000000000000ugnot # test1 g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj=10000000000000ugnot # test2 -g1l9aypkr8xfvs82zeux486ddzec88ty69lue9de=10000000000000ugnot # dev # Faucet accounts. g1f4v282mwyhu29afke4vq5r2xzcm6z3ftnugcnv=1000000000000ugnot # faucet0 (jae) From 713f307fa07424bf3b07503204b6321d27e6c0a6 Mon Sep 17 00:00:00 2001 From: leohhhn Date: Fri, 26 Jan 2024 11:39:31 +0100 Subject: [PATCH 10/27] update gnomod --- examples/gno.land/p/demo/blog/blog.gno | 8 ++++---- examples/gno.land/p/demo/blog/gno.mod | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/examples/gno.land/p/demo/blog/blog.gno b/examples/gno.land/p/demo/blog/blog.gno index 3fb9ed7a8da..4c70d7787ee 100644 --- a/examples/gno.land/p/demo/blog/blog.gno +++ b/examples/gno.land/p/demo/blog/blog.gno @@ -2,14 +2,14 @@ package blog import ( "errors" - "gno.land/p/demo/avl" - "gno.land/p/demo/mux" - "gno.land/p/demo/ufmt" - "std" "strconv" "strings" "time" + + "gno.land/p/demo/avl" + "gno.land/p/demo/mux" + "gno.land/p/demo/ufmt" ) type Blog struct { diff --git a/examples/gno.land/p/demo/blog/gno.mod b/examples/gno.land/p/demo/blog/gno.mod index bbea91ea08f..65f58e7a0f6 100644 --- a/examples/gno.land/p/demo/blog/gno.mod +++ b/examples/gno.land/p/demo/blog/gno.mod @@ -3,6 +3,5 @@ module gno.land/p/demo/blog require ( gno.land/p/demo/avl v0.0.0-latest gno.land/p/demo/mux v0.0.0-latest - gno.land/p/demo/seqid v0.0.0-latest gno.land/p/demo/ufmt v0.0.0-latest ) From f1ef78f0a8cd8bb36002b6f46e0c40685a6f99b1 Mon Sep 17 00:00:00 2001 From: leohhhn Date: Fri, 26 Jan 2024 14:15:18 +0100 Subject: [PATCH 11/27] update tests --- examples/gno.land/p/demo/blog/blog.gno | 4 ++-- examples/gno.land/r/gnoland/blog/admin.gno | 1 + examples/gno.land/r/gnoland/blog/gnoblog.gno | 14 +++++++------- examples/gno.land/r/gnoland/blog/gnoblog_test.gno | 7 +++---- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/examples/gno.land/p/demo/blog/blog.gno b/examples/gno.land/p/demo/blog/blog.gno index 4c70d7787ee..53097849ff5 100644 --- a/examples/gno.land/p/demo/blog/blog.gno +++ b/examples/gno.land/p/demo/blog/blog.gno @@ -257,7 +257,7 @@ func (p *Post) RenderListItem() string { } output := "
\n\n" output += ufmt.Sprintf("### [%s](%s)\n", p.Title, p.URL()) - //output += ufmt.Sprintf("**[Learn More](%s)**\n\n", p.URL()) + // output += ufmt.Sprintf("**[Learn More](%s)**\n\n", p.URL()) output += " " + p.CreatedAt.Format("02 Jan 2006") // output += p.Summary() + "\n\n" @@ -339,7 +339,7 @@ type Comment struct { func (c Comment) RenderListItem() string { output := "" // todo see where it is used - //output += ufmt.Sprintf("#### %s\n", formatAuthorAndDate(c.Author, c.CreatedAt)) + // output += ufmt.Sprintf("#### %s\n", formatAuthorAndDate(c.Author, c.CreatedAt)) output += c.Comment + "\n" output += "\n" return output diff --git a/examples/gno.land/r/gnoland/blog/admin.gno b/examples/gno.land/r/gnoland/blog/admin.gno index d21e794f081..f615e26e491 100644 --- a/examples/gno.land/r/gnoland/blog/admin.gno +++ b/examples/gno.land/r/gnoland/blog/admin.gno @@ -54,6 +54,7 @@ func ModAddPost(slug, title, body, publicationDate, authors, tags string) { } err := b.NewPost(caller, slug, title, body, publicationDate, authorList, tagList) + checkErr(err) } diff --git a/examples/gno.land/r/gnoland/blog/gnoblog.gno b/examples/gno.land/r/gnoland/blog/gnoblog.gno index 15cb04c1c46..1cdc95fe9a8 100644 --- a/examples/gno.land/r/gnoland/blog/gnoblog.gno +++ b/examples/gno.land/r/gnoland/blog/gnoblog.gno @@ -20,13 +20,6 @@ func AddComment(postSlug, comment string) { checkErr(err) } -func PostExists(slug string) bool { - if b.GetPost(slug) == nil { - return false - } - return true -} - func Render(path string) string { return b.Render(path) } @@ -34,3 +27,10 @@ func Render(path string) string { func RenderLastPostsWidget(limit int) string { return b.RenderLastPostsWidget(limit) } + +func PostExists(slug string) bool { + if b.GetPost(slug) == nil { + return false + } + return true +} diff --git a/examples/gno.land/r/gnoland/blog/gnoblog_test.gno b/examples/gno.land/r/gnoland/blog/gnoblog_test.gno index 411bb40caa7..16d9b59ffa1 100644 --- a/examples/gno.land/r/gnoland/blog/gnoblog_test.gno +++ b/examples/gno.land/r/gnoland/blog/gnoblog_test.gno @@ -21,11 +21,10 @@ No posts. ` assertMDEquals(t, got, expected) } - // create two posts, list post. { - ModAddPost("slug1", "title1", "body1", "tag1,tag2") - ModAddPost("slug2", "title2", "body2", "tag1,tag3") + ModAddPost("slug1", "title1", "body1", "2022-05-02T13:17:22Z", "moul", "tag1,tag2") + ModAddPost("slug2", "title2", "body2", "2022-05-02T13:17:22Z", "moul", "tag1,tag3") got := Render("") expected := ` # Gnoland's Blog @@ -108,7 +107,7 @@ comment2 // edit post. { - ModEditPost("slug2", "title2++", "body2++", "2009-11-10T23:00:00Z", "manfred ", "tag1,tag4") + ModEditPost("slug2", "title2++", "body2++", "2009-11-10T23:00:00Z", "manfred", "tag1,tag4") got := Render("p/slug2") expected := ` # [Gnoland's Blog](/r/gnoland/blog:) / p / title2++ From 84b9a53157c2d959674caa1fd2d9357a2c313ba2 Mon Sep 17 00:00:00 2001 From: leohhhn Date: Mon, 5 Feb 2024 17:44:31 +0100 Subject: [PATCH 12/27] render tags better --- examples/gno.land/p/demo/blog/blog.gno | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/gno.land/p/demo/blog/blog.gno b/examples/gno.land/p/demo/blog/blog.gno index 53097849ff5..e02b192fabb 100644 --- a/examples/gno.land/p/demo/blog/blog.gno +++ b/examples/gno.land/p/demo/blog/blog.gno @@ -272,6 +272,10 @@ func (p *Post) RenderTagList() string { if p == nil { return "error: no such post\n" } + if len(p.Tags) == 0 { + return "" + } + output := "Tags: " for idx, tag := range p.Tags { if idx > 0 { From 7ed1b5df154b7c57852834e6495e37a7994a974a Mon Sep 17 00:00:00 2001 From: leohhhn Date: Mon, 5 Feb 2024 17:51:48 +0100 Subject: [PATCH 13/27] return gen txs --- gno.land/genesis/genesis_txs.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gno.land/genesis/genesis_txs.txt b/gno.land/genesis/genesis_txs.txt index 32876c86d82..db376e21e89 100644 --- a/gno.land/genesis/genesis_txs.txt +++ b/gno.land/genesis/genesis_txs.txt @@ -12,4 +12,6 @@ {"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateThread","args":["1","NFT example","NFT's are all the rage these days, for various reasons.\n\nI read over EIP-721 which appears to be the de-facto NFT standard on Ethereum. Then, made a sample implementation of EIP-721 (let's here called GRC-721). The implementation isn't complete, but it demonstrates the main functionality.\n\n - [EIP-721](https://eips.ethereum.org/EIPS/eip-721)\n - [gno.land/r/demo/nft/nft.gno](https://gno.land/r/demo/nft/nft.gno)\n - [zrealm_nft3.gno test](https://github.com/gnolang/gno/blob/master/examples/gno.land/r/demo/nft/z_3_filetest.gno)\n\nIn short, this demonstrates how to implement Ethereum contract interfaces in Gno.land; by using only standard Go language features.\n\nPlease leave a comment ([guide](https://gno.land/r/demo/boards:testboard/1)).\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"A+FhNtsXHjLfSJk1lB8FbiL4mGPjc50Kt81J7EKDnJ2y"},"signature":"ZXfrTiHxPFQL8uSm+Tv7WXIHPMca9okhm94RAlC6YgNbB1VHQYYpoP4w+cnL3YskVzGrOZxensXa9CAZ+cNNeg=="}],"memo":""} {"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateThread","args":["1","Simple echo example with coins","This is a simple test realm contract that demonstrates how to use the banker.\n\nSee [gno.land/r/demo/banktest/banktest.gno](/r/banktest/banktest.gno) to see the original contract code.\n\nThis article will go through each line to explain how it works.\n\n```go\npackage banktest\n```\n\nThis package is locally named \"banktest\" (could be anything).\n\n```go\nimport (\n\t\"std\"\n)\n```\n\nThe \"std\" package is defined by the gno code in stdlibs/std/. \u003c/br\u003e\nSelf explanatory; and you'll see more usage from std later.\n\n```go\ntype activity struct {\n\tcaller std.Address\n\tsent std.Coins\n\treturned std.Coins\n\ttime std.Time\n}\n\nfunc (act *activity) String() string {\n\treturn act.caller.String() + \" \" +\n\t\tact.sent.String() + \" sent, \" +\n\t\tact.returned.String() + \" returned, at \" +\n\t\tstd.FormatTimestamp(act.time, \"2006-01-02 3:04pm MST\")\n}\n\nvar latest [10]*activity\n```\n\nThis is just maintaining a list of recent activity to this contract.\nNotice that the \"latest\" variable is defined \"globally\" within\nthe context of the realm with path \"gno.land/r/demo/banktest\".\n\nThis means that calls to functions defined within this package\nare encapsulated within this \"data realm\", where the data is \nmutated based on transactions that can potentially cross many\nrealm and non-realm packge boundaries (in the call stack).\n\n```go\n// Deposit will take the coins (to the realm's pkgaddr) or return them to user.\nfunc Deposit(returnDenom string, returnAmount int64) string {\n\tstd.AssertOriginCall()\n\tcaller := std.GetOrigCaller()\n\tsend := std.Coins{{returnDenom, returnAmount}}\n```\n\nThis is the beginning of the definition of the contract function named\n\"Deposit\". `std.AssertOriginCall() asserts that this function was called by a\ngno transactional Message. The caller is the user who signed off on this\ntransactional message. Send is the amount of deposit sent along with this\nmessage.\n\n```go\n\t// record activity\n\tact := \u0026activity{\n\t\tcaller: caller,\n\t\tsent: std.GetOrigSend(),\n\t\treturned: send,\n\t\ttime: std.GetTimestamp(),\n\t}\n\tfor i := len(latest) - 2; i \u003e= 0; i-- {\n\t\tlatest[i+1] = latest[i] // shift by +1.\n\t}\n\tlatest[0] = act\n```\n\nUpdating the \"latest\" array for viewing at gno.land/r/demo/banktest: (w/ trailing colon).\n\n```go\n\t// return if any.\n\tif returnAmount \u003e 0 {\n```\n\nIf the user requested the return of coins...\n\n```go\n\t\tbanker := std.GetBanker(std.BankerTypeOrigSend)\n```\n\nuse a std.Banker instance to return any deposited coins to the original sender.\n\n```go\n\t\tpkgaddr := std.GetOrigPkgAddr()\n\t\t// TODO: use std.Coins constructors, this isn't generally safe.\n\t\tbanker.SendCoins(pkgaddr, caller, send)\n\t\treturn \"returned!\"\n```\n\nNotice that each realm package has an associated Cosmos address.\n\n\nFinally, the results are rendered via an ABCI query call when you visit [/r/banktest:](/r/banktest:).\n\n```go\nfunc Render(path string) string {\n\t// get realm coins.\n\tbanker := std.GetBanker(std.BankerTypeReadonly)\n\tcoins := banker.GetCoins(std.GetOrigPkgAddr())\n\n\t// render\n\tres := \"\"\n\tres += \"## recent activity\\n\"\n\tres += \"\\n\"\n\tfor _, act := range latest {\n\t\tif act == nil {\n\t\t\tbreak\n\t\t}\n\t\tres += \" * \" + act.String() + \"\\n\"\n\t}\n\tres += \"\\n\"\n\tres += \"## total deposits\\n\"\n\tres += coins.String()\n\treturn res\n}\n```\n\nYou can call this contract yourself, by vistiing [/r/banktest](/r/banktest) and the [quickstart guide](/r/boards:testboard/4).\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"A+FhNtsXHjLfSJk1lB8FbiL4mGPjc50Kt81J7EKDnJ2y"},"signature":"iZX/llZlNTdZMLv1goCTgK2bWqzT8enlTq56wMTCpVxJGA0BTvuEM5Nnt9vrnlG6Taqj2GuTrmEnJBkDFTmt9g=="}],"memo":""} {"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateThread","args":["1","TASK: Describe in your words","Describe in an essay (250+ words), on your favorite medium, why you are interested in gno.land and gnolang.\n\nReply here with a URL link to your written piece as a comment, for rewards.\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AmG6kzznyo1uNqWPAYU6wDpsmzQKDaEOrVRaZ08vOyX0"},"signature":"4HBNtrta8HdeHj4JTN56PBTRK8GOe31NMRRXDiyYtjozuyRdWfOGEsGjGgHWcoBUJq6DepBgD4FetdqfhZ6TNQ=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateThread","args":["1","Getting Started","This is a demo of Gno smart contract programming. This document was\nconstructed by Gno onto a smart contract hosted on the data Realm\nname [\"gno.land/r/demo/boards\"](https://gno.land/r/demo/boards/)\n([github](https://github.com/gnolang/gno/tree/master/examples/gno.land/r/demo/boards)).\n\n\n\n## Build `gnokey`, create your account, and interact with Gno.\n\nNOTE: Where you see `--remote %%REMOTE%%` here, that flag can be replaced\nwith `--remote localhost:26657` for local testnets.\n\n### Build `gnokey`.\n\n```bash\ngit clone git@github.com:gnolang/gno.git\ncd ./gno\nmake\n```\n\n### Generate a seed/mnemonic code.\n\n```bash\n./build/gnokey generate\n```\n\nNOTE: You can generate 24 words with any good bip39 generator.\n\n### Create a new account using your mnemonic.\n\n```bash\n./build/gnokey add KEYNAME --recover\n```\n\nNOTE: `KEYNAME` is your key identifier, and should be changed.\n\n### Verify that you can see your account locally.\n\n```bash\n./build/gnokey list\n```\n\n## Interact with the blockchain:\n\n### Get your current balance, account number, and sequence number.\n\n```bash\n./build/gnokey query auth/accounts/ACCOUNT_ADDR --remote %%REMOTE%%\n```\n\nNOTE: you can retrieve your `ACCOUNT_ADDR` with `./build/gnokey list`.\n\n### Acquire testnet tokens using the official faucet.\n\nGo to https://gno.land/faucet\n\n### Create a board with a smart contract call.\n\nNOTE: `BOARDNAME` will be the slug of the board, and should be changed.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateBoard\" --args \"BOARDNAME\" --gas-fee \"1000000ugnot\" --gas-wanted \"2000000\" --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateBoard\n\nNext, query for the permanent board ID by querying (you need this to create a new post):\n\n```bash\n./build/gnokey query \"vm/qeval\" --data \"gno.land/r/demo/boards\nGetBoardIDFromName(\\\"BOARDNAME\\\")\" --remote %%REMOTE%%\n```\n\n### Create a post of a board with a smart contract call.\n\nNOTE: If a board was created successfully, your SEQUENCE_NUMBER would have increased.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateThread\" --args BOARD_ID --args \"Hello gno.land\" --args\\#file \"./examples/gno.land/r/demo/boards/example_post.md\" --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateThread\n\n### Create a comment to a post.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateReply\" --args \"BOARD_ID\" --args \"1\" --args \"1\" --args \"Nice to meet you too.\" --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateReply\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards\nBOARDNAME/1\" --remote %%REMOTE%%\n```\n\n### Render page with optional path expression.\n\nThe contents of `https://gno.land/r/demo/boards:` and `https://gno.land/r/demo/boards:gnolang` are rendered by calling\nthe `Render(path string)` function like so:\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards\ngnolang\"\n```\n\n## Starting a local `gnoland` node:\n\n### Add test account.\n\n```bash\n./build/gnokey add test1 --recover\n```\n\nUse this mneonic:\n\u003e source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast\n\n### Start `gnoland` node.\n\n```bash\n./build/gnoland\n```\n\nNOTE: This can be reset with `make reset`\n\n### Publish the \"gno.land/p/demo/avl\" package.\n\n```bash\n./build/gnokey maketx addpkg test1 --pkgpath \"gno.land/p/demo/avl\" --pkgdir \"examples/gno.land/p/demo/avl\" --deposit 100000000ugnot --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote localhost:26657\n```\n\n### Publish the \"gno.land/r/demo/boards\" realm package.\n\n```bash\n./build/gnokey maketx addpkg test1 --pkgpath \"gno.land/r/demo/boards\" --pkgdir \"examples/gno.land/r/demo/boards\" --deposit 100000000ugnot --gas-fee 1000000ugnot --gas-wanted 300000000 --broadcast true --chainid %%CHAINID%% --remote localhost:26657\n```\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} \ No newline at end of file +{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateThread","args":["1","Getting Started","This is a demo of Gno smart contract programming. This document was\nconstructed by Gno onto a smart contract hosted on the data Realm\nname [\"gno.land/r/demo/boards\"](https://gno.land/r/demo/boards/)\n([github](https://github.com/gnolang/gno/tree/master/examples/gno.land/r/demo/boards)).\n\n\n\n## Build `gnokey`, create your account, and interact with Gno.\n\nNOTE: Where you see `--remote %%REMOTE%%` here, that flag can be replaced\nwith `--remote localhost:26657` for local testnets.\n\n### Build `gnokey`.\n\n```bash\ngit clone git@github.com:gnolang/gno.git\ncd ./gno\nmake\n```\n\n### Generate a seed/mnemonic code.\n\n```bash\n./build/gnokey generate\n```\n\nNOTE: You can generate 24 words with any good bip39 generator.\n\n### Create a new account using your mnemonic.\n\n```bash\n./build/gnokey add KEYNAME --recover\n```\n\nNOTE: `KEYNAME` is your key identifier, and should be changed.\n\n### Verify that you can see your account locally.\n\n```bash\n./build/gnokey list\n```\n\n## Interact with the blockchain:\n\n### Get your current balance, account number, and sequence number.\n\n```bash\n./build/gnokey query auth/accounts/ACCOUNT_ADDR --remote %%REMOTE%%\n```\n\nNOTE: you can retrieve your `ACCOUNT_ADDR` with `./build/gnokey list`.\n\n### Acquire testnet tokens using the official faucet.\n\nGo to https://gno.land/faucet\n\n### Create a board with a smart contract call.\n\nNOTE: `BOARDNAME` will be the slug of the board, and should be changed.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateBoard\" --args \"BOARDNAME\" --gas-fee \"1000000ugnot\" --gas-wanted \"2000000\" --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateBoard\n\nNext, query for the permanent board ID by querying (you need this to create a new post):\n\n```bash\n./build/gnokey query \"vm/qeval\" --data \"gno.land/r/demo/boards\nGetBoardIDFromName(\\\"BOARDNAME\\\")\" --remote %%REMOTE%%\n```\n\n### Create a post of a board with a smart contract call.\n\nNOTE: If a board was created successfully, your SEQUENCE_NUMBER would have increased.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateThread\" --args BOARD_ID --args \"Hello gno.land\" --args\\#file \"./examples/gno.land/r/demo/boards/example_post.md\" --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateThread\n\n### Create a comment to a post.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateReply\" --args \"BOARD_ID\" --args \"1\" --args \"1\" --args \"Nice to meet you too.\" --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateReply\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards\nBOARDNAME/1\" --remote %%REMOTE%%\n```\n\n### Render page with optional path expression.\n\nThe contents of `https://gno.land/r/demo/boards:` and `https://gno.land/r/demo/boards:gnolang` are rendered by calling\nthe `Render(path string)` function like so:\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards\ngnolang\"\n```\n\n## Starting a local `gnoland` node:\n\n### Add test account.\n\n```bash\n./build/gnokey add test1 --recover\n```\n\nUse this mneonic:\n\u003e source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast\n\n### Start `gnoland` node.\n\n```bash\n./build/gnoland\n```\n\nNOTE: This can be reset with `make reset`\n\n### Publish the \"gno.land/p/demo/avl\" package.\n\n```bash\n./build/gnokey maketx addpkg test1 --pkgpath \"gno.land/p/demo/avl\" --pkgdir \"examples/gno.land/p/demo/avl\" --deposit 100000000ugnot --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote localhost:26657\n```\n\n### Publish the \"gno.land/r/demo/boards\" realm package.\n\n```bash\n./build/gnokey maketx addpkg test1 --pkgpath \"gno.land/r/demo/boards\" --pkgdir \"examples/gno.land/r/demo/boards\" --deposit 100000000ugnot --gas-fee 1000000ugnot --gas-wanted 300000000 --broadcast true --chainid %%CHAINID%% --remote localhost:26657\n```\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/gnoland/blog","func":"ModAddPost","args":["post1","First post","Lorem Ipsum", "tag1,tag2"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/gnoland/blog","func":"ModAddPost","args":["post2","Second post","Lorem Ipsum", "tag1,tag3"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} \ No newline at end of file From 6b272f8092c7300d0ef3ac3efb6fa856fc457184 Mon Sep 17 00:00:00 2001 From: leohhhn Date: Tue, 6 Feb 2024 13:41:11 +0100 Subject: [PATCH 14/27] remove newlines --- examples/gno.land/p/demo/blog/util.gno | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/gno.land/p/demo/blog/util.gno b/examples/gno.land/p/demo/blog/util.gno index 22bc11bed07..b4a8652af72 100644 --- a/examples/gno.land/p/demo/blog/util.gno +++ b/examples/gno.land/p/demo/blog/util.gno @@ -1,8 +1,6 @@ package blog -import ( - "strings" -) +import "strings" func breadcrumb(parts []string) string { return "# " + strings.Join(parts, " / ") + "\n\n" From a8694e785e7b519651915e247cc0a4711852acf2 Mon Sep 17 00:00:00 2001 From: leohhhn Date: Thu, 8 Feb 2024 23:11:34 +0100 Subject: [PATCH 15/27] fixup genesis blog tx, start reworking tests --- examples/gno.land/r/gnoland/blog/gnoblog_test.gno | 12 +++++------- gno.land/genesis/genesis_txs.txt | 4 ++-- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/examples/gno.land/r/gnoland/blog/gnoblog_test.gno b/examples/gno.land/r/gnoland/blog/gnoblog_test.gno index 16d9b59ffa1..6131da78e94 100644 --- a/examples/gno.land/r/gnoland/blog/gnoblog_test.gno +++ b/examples/gno.land/r/gnoland/blog/gnoblog_test.gno @@ -24,21 +24,19 @@ No posts. // create two posts, list post. { ModAddPost("slug1", "title1", "body1", "2022-05-02T13:17:22Z", "moul", "tag1,tag2") - ModAddPost("slug2", "title2", "body2", "2022-05-02T13:17:22Z", "moul", "tag1,tag3") + ModAddPost("slug2", "title2", "body2", "2022-05-02T13:17:23Z", "moul", "tag1,tag3") got := Render("") expected := ` # Gnoland's Blog
-## [title1](/r/gnoland/blog:p/slug1) -**[Learn More](/r/gnoland/blog:p/slug1)** - +### [title2](/r/gnoland/blog:p/slug2) + 02 May 2022
-## [title2](/r/gnoland/blog:p/slug2) -**[Learn More](/r/gnoland/blog:p/slug2)** - +### [title1](/r/gnoland/blog:p/slug1) + 02 May 2022
` assertMDEquals(t, got, expected) diff --git a/gno.land/genesis/genesis_txs.txt b/gno.land/genesis/genesis_txs.txt index db376e21e89..b320aa72ebe 100644 --- a/gno.land/genesis/genesis_txs.txt +++ b/gno.land/genesis/genesis_txs.txt @@ -13,5 +13,5 @@ {"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateThread","args":["1","Simple echo example with coins","This is a simple test realm contract that demonstrates how to use the banker.\n\nSee [gno.land/r/demo/banktest/banktest.gno](/r/banktest/banktest.gno) to see the original contract code.\n\nThis article will go through each line to explain how it works.\n\n```go\npackage banktest\n```\n\nThis package is locally named \"banktest\" (could be anything).\n\n```go\nimport (\n\t\"std\"\n)\n```\n\nThe \"std\" package is defined by the gno code in stdlibs/std/. \u003c/br\u003e\nSelf explanatory; and you'll see more usage from std later.\n\n```go\ntype activity struct {\n\tcaller std.Address\n\tsent std.Coins\n\treturned std.Coins\n\ttime std.Time\n}\n\nfunc (act *activity) String() string {\n\treturn act.caller.String() + \" \" +\n\t\tact.sent.String() + \" sent, \" +\n\t\tact.returned.String() + \" returned, at \" +\n\t\tstd.FormatTimestamp(act.time, \"2006-01-02 3:04pm MST\")\n}\n\nvar latest [10]*activity\n```\n\nThis is just maintaining a list of recent activity to this contract.\nNotice that the \"latest\" variable is defined \"globally\" within\nthe context of the realm with path \"gno.land/r/demo/banktest\".\n\nThis means that calls to functions defined within this package\nare encapsulated within this \"data realm\", where the data is \nmutated based on transactions that can potentially cross many\nrealm and non-realm packge boundaries (in the call stack).\n\n```go\n// Deposit will take the coins (to the realm's pkgaddr) or return them to user.\nfunc Deposit(returnDenom string, returnAmount int64) string {\n\tstd.AssertOriginCall()\n\tcaller := std.GetOrigCaller()\n\tsend := std.Coins{{returnDenom, returnAmount}}\n```\n\nThis is the beginning of the definition of the contract function named\n\"Deposit\". `std.AssertOriginCall() asserts that this function was called by a\ngno transactional Message. The caller is the user who signed off on this\ntransactional message. Send is the amount of deposit sent along with this\nmessage.\n\n```go\n\t// record activity\n\tact := \u0026activity{\n\t\tcaller: caller,\n\t\tsent: std.GetOrigSend(),\n\t\treturned: send,\n\t\ttime: std.GetTimestamp(),\n\t}\n\tfor i := len(latest) - 2; i \u003e= 0; i-- {\n\t\tlatest[i+1] = latest[i] // shift by +1.\n\t}\n\tlatest[0] = act\n```\n\nUpdating the \"latest\" array for viewing at gno.land/r/demo/banktest: (w/ trailing colon).\n\n```go\n\t// return if any.\n\tif returnAmount \u003e 0 {\n```\n\nIf the user requested the return of coins...\n\n```go\n\t\tbanker := std.GetBanker(std.BankerTypeOrigSend)\n```\n\nuse a std.Banker instance to return any deposited coins to the original sender.\n\n```go\n\t\tpkgaddr := std.GetOrigPkgAddr()\n\t\t// TODO: use std.Coins constructors, this isn't generally safe.\n\t\tbanker.SendCoins(pkgaddr, caller, send)\n\t\treturn \"returned!\"\n```\n\nNotice that each realm package has an associated Cosmos address.\n\n\nFinally, the results are rendered via an ABCI query call when you visit [/r/banktest:](/r/banktest:).\n\n```go\nfunc Render(path string) string {\n\t// get realm coins.\n\tbanker := std.GetBanker(std.BankerTypeReadonly)\n\tcoins := banker.GetCoins(std.GetOrigPkgAddr())\n\n\t// render\n\tres := \"\"\n\tres += \"## recent activity\\n\"\n\tres += \"\\n\"\n\tfor _, act := range latest {\n\t\tif act == nil {\n\t\t\tbreak\n\t\t}\n\t\tres += \" * \" + act.String() + \"\\n\"\n\t}\n\tres += \"\\n\"\n\tres += \"## total deposits\\n\"\n\tres += coins.String()\n\treturn res\n}\n```\n\nYou can call this contract yourself, by vistiing [/r/banktest](/r/banktest) and the [quickstart guide](/r/boards:testboard/4).\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"A+FhNtsXHjLfSJk1lB8FbiL4mGPjc50Kt81J7EKDnJ2y"},"signature":"iZX/llZlNTdZMLv1goCTgK2bWqzT8enlTq56wMTCpVxJGA0BTvuEM5Nnt9vrnlG6Taqj2GuTrmEnJBkDFTmt9g=="}],"memo":""} {"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateThread","args":["1","TASK: Describe in your words","Describe in an essay (250+ words), on your favorite medium, why you are interested in gno.land and gnolang.\n\nReply here with a URL link to your written piece as a comment, for rewards.\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AmG6kzznyo1uNqWPAYU6wDpsmzQKDaEOrVRaZ08vOyX0"},"signature":"4HBNtrta8HdeHj4JTN56PBTRK8GOe31NMRRXDiyYtjozuyRdWfOGEsGjGgHWcoBUJq6DepBgD4FetdqfhZ6TNQ=="}],"memo":""} {"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateThread","args":["1","Getting Started","This is a demo of Gno smart contract programming. This document was\nconstructed by Gno onto a smart contract hosted on the data Realm\nname [\"gno.land/r/demo/boards\"](https://gno.land/r/demo/boards/)\n([github](https://github.com/gnolang/gno/tree/master/examples/gno.land/r/demo/boards)).\n\n\n\n## Build `gnokey`, create your account, and interact with Gno.\n\nNOTE: Where you see `--remote %%REMOTE%%` here, that flag can be replaced\nwith `--remote localhost:26657` for local testnets.\n\n### Build `gnokey`.\n\n```bash\ngit clone git@github.com:gnolang/gno.git\ncd ./gno\nmake\n```\n\n### Generate a seed/mnemonic code.\n\n```bash\n./build/gnokey generate\n```\n\nNOTE: You can generate 24 words with any good bip39 generator.\n\n### Create a new account using your mnemonic.\n\n```bash\n./build/gnokey add KEYNAME --recover\n```\n\nNOTE: `KEYNAME` is your key identifier, and should be changed.\n\n### Verify that you can see your account locally.\n\n```bash\n./build/gnokey list\n```\n\n## Interact with the blockchain:\n\n### Get your current balance, account number, and sequence number.\n\n```bash\n./build/gnokey query auth/accounts/ACCOUNT_ADDR --remote %%REMOTE%%\n```\n\nNOTE: you can retrieve your `ACCOUNT_ADDR` with `./build/gnokey list`.\n\n### Acquire testnet tokens using the official faucet.\n\nGo to https://gno.land/faucet\n\n### Create a board with a smart contract call.\n\nNOTE: `BOARDNAME` will be the slug of the board, and should be changed.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateBoard\" --args \"BOARDNAME\" --gas-fee \"1000000ugnot\" --gas-wanted \"2000000\" --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateBoard\n\nNext, query for the permanent board ID by querying (you need this to create a new post):\n\n```bash\n./build/gnokey query \"vm/qeval\" --data \"gno.land/r/demo/boards\nGetBoardIDFromName(\\\"BOARDNAME\\\")\" --remote %%REMOTE%%\n```\n\n### Create a post of a board with a smart contract call.\n\nNOTE: If a board was created successfully, your SEQUENCE_NUMBER would have increased.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateThread\" --args BOARD_ID --args \"Hello gno.land\" --args\\#file \"./examples/gno.land/r/demo/boards/example_post.md\" --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateThread\n\n### Create a comment to a post.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateReply\" --args \"BOARD_ID\" --args \"1\" --args \"1\" --args \"Nice to meet you too.\" --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateReply\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards\nBOARDNAME/1\" --remote %%REMOTE%%\n```\n\n### Render page with optional path expression.\n\nThe contents of `https://gno.land/r/demo/boards:` and `https://gno.land/r/demo/boards:gnolang` are rendered by calling\nthe `Render(path string)` function like so:\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards\ngnolang\"\n```\n\n## Starting a local `gnoland` node:\n\n### Add test account.\n\n```bash\n./build/gnokey add test1 --recover\n```\n\nUse this mneonic:\n\u003e source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast\n\n### Start `gnoland` node.\n\n```bash\n./build/gnoland\n```\n\nNOTE: This can be reset with `make reset`\n\n### Publish the \"gno.land/p/demo/avl\" package.\n\n```bash\n./build/gnokey maketx addpkg test1 --pkgpath \"gno.land/p/demo/avl\" --pkgdir \"examples/gno.land/p/demo/avl\" --deposit 100000000ugnot --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote localhost:26657\n```\n\n### Publish the \"gno.land/r/demo/boards\" realm package.\n\n```bash\n./build/gnokey maketx addpkg test1 --pkgpath \"gno.land/r/demo/boards\" --pkgdir \"examples/gno.land/r/demo/boards\" --deposit 100000000ugnot --gas-fee 1000000ugnot --gas-wanted 300000000 --broadcast true --chainid %%CHAINID%% --remote localhost:26657\n```\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/gnoland/blog","func":"ModAddPost","args":["post1","First post","Lorem Ipsum", "tag1,tag2"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/gnoland/blog","func":"ModAddPost","args":["post2","Second post","Lorem Ipsum", "tag1,tag3"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} \ No newline at end of file +{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/gnoland/blog","func":"ModAddPost","args":["post1","First post","Lorem Ipsum", "2022-05-02T13:17:22Z" , "genesis", "tag1,tag2"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/gnoland/blog","func":"ModAddPost","args":["post2","Second post","Lorem Ipsum", "2022-05-02T13:17:23Z", "genesis", "tag1,tag3"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} \ No newline at end of file From 132d2ef17b9874e742d2951493184ec8687dd473 Mon Sep 17 00:00:00 2001 From: leohhhn Date: Fri, 9 Feb 2024 13:13:58 +0100 Subject: [PATCH 16/27] wip --- examples/gno.land/p/demo/blog/blog.gno | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/examples/gno.land/p/demo/blog/blog.gno b/examples/gno.land/p/demo/blog/blog.gno index e02b192fabb..8f3f1e370f0 100644 --- a/examples/gno.land/p/demo/blog/blog.gno +++ b/examples/gno.land/p/demo/blog/blog.gno @@ -120,8 +120,7 @@ func (b Blog) Render(path string) string { } func (b *Blog) NewPost(publisher std.Address, slug, title, body, pubDate string, authors, tags []string) error { - _, found := b.Posts.Get(slug) - if found { + if _, found := b.Posts.Get(slug); found { return errors.New("slug already exists") } @@ -169,6 +168,18 @@ func (b *Blog) prepareAndSetPost(post *Post) error { trimmedTitleKey := strings.Replace(post.Title, " ", "", -1) pubDateKey := post.CreatedAt.Format(time.RFC3339) + // Prevent accidental overwrite + // Cannot have two posts with same title key + if _, found := b.PostsAlphabetical.Get(trimmedTitleKey); found { + return errors.New("post with that title already exists") + } + // If two posts have the same timestamp, increment one by one second, so they differ + _, found := b.PostsPublished.Get(pubDateKey) + if found { + pubDateKey = post.CreatedAt.Add(time.Second * 1).Format(time.RFC3339) + } + + // Store post under keys b.PostsAlphabetical.Set(trimmedTitleKey, post) b.PostsPublished.Set(pubDateKey, post) b.Posts.Set(post.Slug, post) From 4f916c8e074514465842a428b3367c1c03a0d037 Mon Sep 17 00:00:00 2001 From: leohhhn Date: Fri, 9 Feb 2024 19:04:59 +0100 Subject: [PATCH 17/27] extract post errors --- examples/gno.land/p/demo/blog/blog.gno | 18 ++++++++---------- examples/gno.land/p/demo/blog/errors.gno | 9 ++++++++- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/examples/gno.land/p/demo/blog/blog.gno b/examples/gno.land/p/demo/blog/blog.gno index 8f3f1e370f0..8b56eefe46d 100644 --- a/examples/gno.land/p/demo/blog/blog.gno +++ b/examples/gno.land/p/demo/blog/blog.gno @@ -1,7 +1,6 @@ package blog import ( - "errors" "std" "strconv" "strings" @@ -121,7 +120,7 @@ func (b Blog) Render(path string) string { func (b *Blog) NewPost(publisher std.Address, slug, title, body, pubDate string, authors, tags []string) error { if _, found := b.Posts.Get(slug); found { - return errors.New("slug already exists") + return ErrPostSlugExists } var parsedTime time.Time @@ -145,6 +144,7 @@ func (b *Blog) NewPost(publisher std.Address, slug, title, body, pubDate string, Tags: tags, CreatedAt: parsedTime, } + return b.prepareAndSetPost(&post) } @@ -153,13 +153,13 @@ func (b *Blog) prepareAndSetPost(post *Post) error { post.Body = strings.TrimSpace(post.Body) if post.Title == "" { - return errors.New("title is missing") + return ErrPostTitleMissing } if post.Body == "" { - return errors.New("body is missing") + return ErrPostBodyMissing } if post.Slug == "" { - return errors.New("slug is missing") + return ErrPostSlugMissing } post.Blog = b @@ -168,15 +168,13 @@ func (b *Blog) prepareAndSetPost(post *Post) error { trimmedTitleKey := strings.Replace(post.Title, " ", "", -1) pubDateKey := post.CreatedAt.Format(time.RFC3339) - // Prevent accidental overwrite // Cannot have two posts with same title key if _, found := b.PostsAlphabetical.Get(trimmedTitleKey); found { - return errors.New("post with that title already exists") + return ErrPostTitleExists } // If two posts have the same timestamp, increment one by one second, so they differ - _, found := b.PostsPublished.Get(pubDateKey) - if found { - pubDateKey = post.CreatedAt.Add(time.Second * 1).Format(time.RFC3339) + if _, found := b.PostsPublished.Get(pubDateKey); found { + return ErrPostPubDateExists } // Store post under keys diff --git a/examples/gno.land/p/demo/blog/errors.gno b/examples/gno.land/p/demo/blog/errors.gno index db9f8f39fa1..7611f61dece 100644 --- a/examples/gno.land/p/demo/blog/errors.gno +++ b/examples/gno.land/p/demo/blog/errors.gno @@ -2,4 +2,11 @@ package blog import "errors" -var ErrNoSuchPost = errors.New("no such post") +var ( + ErrPostTitleMissing = errors.New("post title is missing") + ErrPostSlugMissing = errors.New("post slug is missing") + ErrPostBodyMissing = errors.New("post body is missing") + ErrPostSlugExists = errors.New("post with specified slug already exists") + ErrPostPubDateExists = errors.New("post with specified publication date exists") + ErrPostTitleExists = errors.New("post with specified title already exists") +) From e158248c52f01b14bfcefb83991d632334b818b6 Mon Sep 17 00:00:00 2001 From: leohhhn Date: Fri, 9 Feb 2024 20:31:54 +0100 Subject: [PATCH 18/27] update dates on pages --- gno.land/genesis/genesis_txs.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gno.land/genesis/genesis_txs.txt b/gno.land/genesis/genesis_txs.txt index b320aa72ebe..3baf9d3231b 100644 --- a/gno.land/genesis/genesis_txs.txt +++ b/gno.land/genesis/genesis_txs.txt @@ -13,5 +13,5 @@ {"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateThread","args":["1","Simple echo example with coins","This is a simple test realm contract that demonstrates how to use the banker.\n\nSee [gno.land/r/demo/banktest/banktest.gno](/r/banktest/banktest.gno) to see the original contract code.\n\nThis article will go through each line to explain how it works.\n\n```go\npackage banktest\n```\n\nThis package is locally named \"banktest\" (could be anything).\n\n```go\nimport (\n\t\"std\"\n)\n```\n\nThe \"std\" package is defined by the gno code in stdlibs/std/. \u003c/br\u003e\nSelf explanatory; and you'll see more usage from std later.\n\n```go\ntype activity struct {\n\tcaller std.Address\n\tsent std.Coins\n\treturned std.Coins\n\ttime std.Time\n}\n\nfunc (act *activity) String() string {\n\treturn act.caller.String() + \" \" +\n\t\tact.sent.String() + \" sent, \" +\n\t\tact.returned.String() + \" returned, at \" +\n\t\tstd.FormatTimestamp(act.time, \"2006-01-02 3:04pm MST\")\n}\n\nvar latest [10]*activity\n```\n\nThis is just maintaining a list of recent activity to this contract.\nNotice that the \"latest\" variable is defined \"globally\" within\nthe context of the realm with path \"gno.land/r/demo/banktest\".\n\nThis means that calls to functions defined within this package\nare encapsulated within this \"data realm\", where the data is \nmutated based on transactions that can potentially cross many\nrealm and non-realm packge boundaries (in the call stack).\n\n```go\n// Deposit will take the coins (to the realm's pkgaddr) or return them to user.\nfunc Deposit(returnDenom string, returnAmount int64) string {\n\tstd.AssertOriginCall()\n\tcaller := std.GetOrigCaller()\n\tsend := std.Coins{{returnDenom, returnAmount}}\n```\n\nThis is the beginning of the definition of the contract function named\n\"Deposit\". `std.AssertOriginCall() asserts that this function was called by a\ngno transactional Message. The caller is the user who signed off on this\ntransactional message. Send is the amount of deposit sent along with this\nmessage.\n\n```go\n\t// record activity\n\tact := \u0026activity{\n\t\tcaller: caller,\n\t\tsent: std.GetOrigSend(),\n\t\treturned: send,\n\t\ttime: std.GetTimestamp(),\n\t}\n\tfor i := len(latest) - 2; i \u003e= 0; i-- {\n\t\tlatest[i+1] = latest[i] // shift by +1.\n\t}\n\tlatest[0] = act\n```\n\nUpdating the \"latest\" array for viewing at gno.land/r/demo/banktest: (w/ trailing colon).\n\n```go\n\t// return if any.\n\tif returnAmount \u003e 0 {\n```\n\nIf the user requested the return of coins...\n\n```go\n\t\tbanker := std.GetBanker(std.BankerTypeOrigSend)\n```\n\nuse a std.Banker instance to return any deposited coins to the original sender.\n\n```go\n\t\tpkgaddr := std.GetOrigPkgAddr()\n\t\t// TODO: use std.Coins constructors, this isn't generally safe.\n\t\tbanker.SendCoins(pkgaddr, caller, send)\n\t\treturn \"returned!\"\n```\n\nNotice that each realm package has an associated Cosmos address.\n\n\nFinally, the results are rendered via an ABCI query call when you visit [/r/banktest:](/r/banktest:).\n\n```go\nfunc Render(path string) string {\n\t// get realm coins.\n\tbanker := std.GetBanker(std.BankerTypeReadonly)\n\tcoins := banker.GetCoins(std.GetOrigPkgAddr())\n\n\t// render\n\tres := \"\"\n\tres += \"## recent activity\\n\"\n\tres += \"\\n\"\n\tfor _, act := range latest {\n\t\tif act == nil {\n\t\t\tbreak\n\t\t}\n\t\tres += \" * \" + act.String() + \"\\n\"\n\t}\n\tres += \"\\n\"\n\tres += \"## total deposits\\n\"\n\tres += coins.String()\n\treturn res\n}\n```\n\nYou can call this contract yourself, by vistiing [/r/banktest](/r/banktest) and the [quickstart guide](/r/boards:testboard/4).\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"A+FhNtsXHjLfSJk1lB8FbiL4mGPjc50Kt81J7EKDnJ2y"},"signature":"iZX/llZlNTdZMLv1goCTgK2bWqzT8enlTq56wMTCpVxJGA0BTvuEM5Nnt9vrnlG6Taqj2GuTrmEnJBkDFTmt9g=="}],"memo":""} {"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateThread","args":["1","TASK: Describe in your words","Describe in an essay (250+ words), on your favorite medium, why you are interested in gno.land and gnolang.\n\nReply here with a URL link to your written piece as a comment, for rewards.\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AmG6kzznyo1uNqWPAYU6wDpsmzQKDaEOrVRaZ08vOyX0"},"signature":"4HBNtrta8HdeHj4JTN56PBTRK8GOe31NMRRXDiyYtjozuyRdWfOGEsGjGgHWcoBUJq6DepBgD4FetdqfhZ6TNQ=="}],"memo":""} {"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/demo/boards","func":"CreateThread","args":["1","Getting Started","This is a demo of Gno smart contract programming. This document was\nconstructed by Gno onto a smart contract hosted on the data Realm\nname [\"gno.land/r/demo/boards\"](https://gno.land/r/demo/boards/)\n([github](https://github.com/gnolang/gno/tree/master/examples/gno.land/r/demo/boards)).\n\n\n\n## Build `gnokey`, create your account, and interact with Gno.\n\nNOTE: Where you see `--remote %%REMOTE%%` here, that flag can be replaced\nwith `--remote localhost:26657` for local testnets.\n\n### Build `gnokey`.\n\n```bash\ngit clone git@github.com:gnolang/gno.git\ncd ./gno\nmake\n```\n\n### Generate a seed/mnemonic code.\n\n```bash\n./build/gnokey generate\n```\n\nNOTE: You can generate 24 words with any good bip39 generator.\n\n### Create a new account using your mnemonic.\n\n```bash\n./build/gnokey add KEYNAME --recover\n```\n\nNOTE: `KEYNAME` is your key identifier, and should be changed.\n\n### Verify that you can see your account locally.\n\n```bash\n./build/gnokey list\n```\n\n## Interact with the blockchain:\n\n### Get your current balance, account number, and sequence number.\n\n```bash\n./build/gnokey query auth/accounts/ACCOUNT_ADDR --remote %%REMOTE%%\n```\n\nNOTE: you can retrieve your `ACCOUNT_ADDR` with `./build/gnokey list`.\n\n### Acquire testnet tokens using the official faucet.\n\nGo to https://gno.land/faucet\n\n### Create a board with a smart contract call.\n\nNOTE: `BOARDNAME` will be the slug of the board, and should be changed.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateBoard\" --args \"BOARDNAME\" --gas-fee \"1000000ugnot\" --gas-wanted \"2000000\" --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateBoard\n\nNext, query for the permanent board ID by querying (you need this to create a new post):\n\n```bash\n./build/gnokey query \"vm/qeval\" --data \"gno.land/r/demo/boards\nGetBoardIDFromName(\\\"BOARDNAME\\\")\" --remote %%REMOTE%%\n```\n\n### Create a post of a board with a smart contract call.\n\nNOTE: If a board was created successfully, your SEQUENCE_NUMBER would have increased.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateThread\" --args BOARD_ID --args \"Hello gno.land\" --args\\#file \"./examples/gno.land/r/demo/boards/example_post.md\" --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateThread\n\n### Create a comment to a post.\n\n```bash\n./build/gnokey maketx call KEYNAME --pkgpath \"gno.land/r/demo/boards\" --func \"CreateReply\" --args \"BOARD_ID\" --args \"1\" --args \"1\" --args \"Nice to meet you too.\" --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote %%REMOTE%%\n```\n\nInteractive documentation: https://gno.land/r/demo/boards?help\u0026__func=CreateReply\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards\nBOARDNAME/1\" --remote %%REMOTE%%\n```\n\n### Render page with optional path expression.\n\nThe contents of `https://gno.land/r/demo/boards:` and `https://gno.land/r/demo/boards:gnolang` are rendered by calling\nthe `Render(path string)` function like so:\n\n```bash\n./build/gnokey query \"vm/qrender\" --data \"gno.land/r/demo/boards\ngnolang\"\n```\n\n## Starting a local `gnoland` node:\n\n### Add test account.\n\n```bash\n./build/gnokey add test1 --recover\n```\n\nUse this mneonic:\n\u003e source bonus chronic canvas draft south burst lottery vacant surface solve popular case indicate oppose farm nothing bullet exhibit title speed wink action roast\n\n### Start `gnoland` node.\n\n```bash\n./build/gnoland\n```\n\nNOTE: This can be reset with `make reset`\n\n### Publish the \"gno.land/p/demo/avl\" package.\n\n```bash\n./build/gnokey maketx addpkg test1 --pkgpath \"gno.land/p/demo/avl\" --pkgdir \"examples/gno.land/p/demo/avl\" --deposit 100000000ugnot --gas-fee 1000000ugnot --gas-wanted 2000000 --broadcast true --chainid %%CHAINID%% --remote localhost:26657\n```\n\n### Publish the \"gno.land/r/demo/boards\" realm package.\n\n```bash\n./build/gnokey maketx addpkg test1 --pkgpath \"gno.land/r/demo/boards\" --pkgdir \"examples/gno.land/r/demo/boards\" --deposit 100000000ugnot --gas-fee 1000000ugnot --gas-wanted 300000000 --broadcast true --chainid %%CHAINID%% --remote localhost:26657\n```\n"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/gnoland/blog","func":"ModAddPost","args":["post1","First post","Lorem Ipsum", "2022-05-02T13:17:22Z" , "genesis", "tag1,tag2"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} -{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/gnoland/blog","func":"ModAddPost","args":["post2","Second post","Lorem Ipsum", "2022-05-02T13:17:23Z", "genesis", "tag1,tag3"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} \ No newline at end of file +{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/gnoland/blog","func":"ModAddPost","args":["post1","First post","Lorem Ipsum","2022-05-20T13:17:22Z","","tag1,tag2"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} +{"msg":[{"@type":"/vm.m_call","caller":"g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq","send":"","pkg_path":"gno.land/r/gnoland/blog","func":"ModAddPost","args":["post2","Second post","Lorem Ipsum","2022-05-20T13:17:23Z","","tag1,tag3"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":"sHjOGXZEi9wt2FSXFHmkDDoVQyepvFHKRDDU0zgedHYnCYPx5/YndyihsDD5Y2Z7/RgNYBh4JlJwDMGFNStzBQ=="}],"memo":""} \ No newline at end of file From d06608bea67068335c9e467ca72350746abfd597 Mon Sep 17 00:00:00 2001 From: leohhhn Date: Mon, 12 Feb 2024 10:44:09 +0100 Subject: [PATCH 19/27] update dates on pages v2 --- examples/gno.land/p/demo/blog/blog.gno | 7 +++++-- examples/gno.land/p/demo/blog/errors.gno | 1 + examples/gno.land/r/gnoland/blog/gnoblog_test.gno | 5 +++-- examples/gno.land/r/gnoland/pages/page_about.gno | 2 +- examples/gno.land/r/gnoland/pages/page_ecosystem.gno | 2 +- examples/gno.land/r/gnoland/pages/page_events.gno | 2 +- examples/gno.land/r/gnoland/pages/page_gnolang.gno | 2 +- examples/gno.land/r/gnoland/pages/page_gor.gno | 2 +- examples/gno.land/r/gnoland/pages/page_partners.gno | 2 +- examples/gno.land/r/gnoland/pages/page_start.gno | 2 +- examples/gno.land/r/gnoland/pages/page_testnets.gno | 2 +- examples/gno.land/r/gnoland/pages/page_tokenomics.gno | 2 +- 12 files changed, 18 insertions(+), 13 deletions(-) diff --git a/examples/gno.land/p/demo/blog/blog.gno b/examples/gno.land/p/demo/blog/blog.gno index 8b56eefe46d..23ae6fb5927 100644 --- a/examples/gno.land/p/demo/blog/blog.gno +++ b/examples/gno.land/p/demo/blog/blog.gno @@ -63,6 +63,7 @@ func (b Blog) RenderPost(res *mux.ResponseWriter, req *mux.Request) { } p := post.(*Post) + res.Write("# " + p.Title + "\n\n") res.Write(p.Body + "\n\n") res.Write("---\n\n") @@ -172,7 +173,7 @@ func (b *Blog) prepareAndSetPost(post *Post) error { if _, found := b.PostsAlphabetical.Get(trimmedTitleKey); found { return ErrPostTitleExists } - // If two posts have the same timestamp, increment one by one second, so they differ + // Cannot have two posts with *exact* same timestamp if _, found := b.PostsPublished.Get(pubDateKey); found { return ErrPostPubDateExists } @@ -317,7 +318,9 @@ func (p *Post) RenderAuthorList() string { func (p *Post) RenderPublishData() string { out := "Published " - out += "by " + p.Publisher.String() + " " + if p.Publisher != "" { + out += "by " + p.Publisher.String() + " " + } out += "to " + p.Blog.Title return out diff --git a/examples/gno.land/p/demo/blog/errors.gno b/examples/gno.land/p/demo/blog/errors.gno index 7611f61dece..9d885d7222f 100644 --- a/examples/gno.land/p/demo/blog/errors.gno +++ b/examples/gno.land/p/demo/blog/errors.gno @@ -9,4 +9,5 @@ var ( ErrPostSlugExists = errors.New("post with specified slug already exists") ErrPostPubDateExists = errors.New("post with specified publication date exists") ErrPostTitleExists = errors.New("post with specified title already exists") + ErrNoSuchPost = errors.New("no such post") ) diff --git a/examples/gno.land/r/gnoland/blog/gnoblog_test.gno b/examples/gno.land/r/gnoland/blog/gnoblog_test.gno index 6131da78e94..1725a2413bd 100644 --- a/examples/gno.land/r/gnoland/blog/gnoblog_test.gno +++ b/examples/gno.land/r/gnoland/blog/gnoblog_test.gno @@ -23,8 +23,8 @@ No posts. } // create two posts, list post. { - ModAddPost("slug1", "title1", "body1", "2022-05-02T13:17:22Z", "moul", "tag1,tag2") - ModAddPost("slug2", "title2", "body2", "2022-05-02T13:17:23Z", "moul", "tag1,tag3") + ModAddPost("slug1", "title1", "body1", "2022-05-20T13:17:22Z", "moul", "tag1,tag2") + ModAddPost("slug2", "title2", "body2", "2022-05-20T13:17:23Z", "moul", "tag1,tag3") got := Render("") expected := ` # Gnoland's Blog @@ -45,6 +45,7 @@ No posts. // view post. { got := Render("p/slug2") + expected := ` # [Gnoland's Blog](/r/gnoland/blog:) / p / title2 diff --git a/examples/gno.land/r/gnoland/pages/page_about.gno b/examples/gno.land/r/gnoland/pages/page_about.gno index 283401e59f4..ad94c7174dc 100644 --- a/examples/gno.land/r/gnoland/pages/page_about.gno +++ b/examples/gno.land/r/gnoland/pages/page_about.gno @@ -16,5 +16,5 @@ This consensus mechanism also achieves higher security with fewer validators, op Any blockchain using Gnolang achieves succinctness, composability, expressivity, and completeness not found in any other smart contract platform. By observing a minimal structure, the design can endure over time and challenge the regime of information censorship we’re living in today.` - _ = b.NewPost("", path, title, body, "", nil, nil) + _ = b.NewPost("", path, title, body, "2022-05-20T13:17:22Z", nil, nil) } diff --git a/examples/gno.land/r/gnoland/pages/page_ecosystem.gno b/examples/gno.land/r/gnoland/pages/page_ecosystem.gno index 53af37a75d5..c5e0134565f 100644 --- a/examples/gno.land/r/gnoland/pages/page_ecosystem.gno +++ b/examples/gno.land/r/gnoland/pages/page_ecosystem.gno @@ -31,5 +31,5 @@ Gnoswap is currently under development and led by the Onbloc team. Gnoswap will Through the Gno.land Developer Portal, new developers can explore the exciting world of Gnolang (Gno), a novel programming language that powers the Gno.land blockchain. If you want to interact with Gno.land, start writing a realm, build a dApp, or even port a Solidity contract to a Gnolang realm, you’ll find the resources to [get started here](https://docs.onbloc.xyz/).` ) - _ = b.NewPost("", path, title, body, "", nil, nil) + _ = b.NewPost("", path, title, body, "2022-05-20T13:17:23Z", nil, nil) } diff --git a/examples/gno.land/r/gnoland/pages/page_events.gno b/examples/gno.land/r/gnoland/pages/page_events.gno index ced3b6b7771..eca3cda88ca 100644 --- a/examples/gno.land/r/gnoland/pages/page_events.gno +++ b/examples/gno.land/r/gnoland/pages/page_events.gno @@ -147,5 +147,5 @@ If you’re interested in building web3 with us, catch up with Gno.land in perso
` ) - _ = b.NewPost("", path, title, body, "", nil, nil) + _ = b.NewPost("", path, title, body, "2022-05-20T13:17:24Z", nil, nil) } diff --git a/examples/gno.land/r/gnoland/pages/page_gnolang.gno b/examples/gno.land/r/gnoland/pages/page_gnolang.gno index 5f6f4ece8a3..da01650ecd4 100644 --- a/examples/gno.land/r/gnoland/pages/page_gnolang.gno +++ b/examples/gno.land/r/gnoland/pages/page_gnolang.gno @@ -39,5 +39,5 @@ Using Gno, developers can rapidly accelerate application development and adopt a The Go language is so well designed that the Gno smart contract system will become the new gold standard for smart contract development and other blockchain applications. As a programming language that is universally adopted, secure, composable, and complete, Gno is essential for the broader adoption of web3 and its sustainable growth.` ) - _ = b.NewPost("", path, title, body, "", nil, nil) + _ = b.NewPost("", path, title, body, "2022-05-20T13:17:25Z", nil, nil) } diff --git a/examples/gno.land/r/gnoland/pages/page_gor.gno b/examples/gno.land/r/gnoland/pages/page_gor.gno index 2774157b8b1..98047b34848 100644 --- a/examples/gno.land/r/gnoland/pages/page_gor.gno +++ b/examples/gno.land/r/gnoland/pages/page_gor.gno @@ -217,5 +217,5 @@ Game of Realms participants and core contributors have made significant progress ` - _ = b.NewPost("", path, title, body, "", nil, nil) + _ = b.NewPost("", path, title, body, "2022-05-20T13:17:26Z", nil, nil) } diff --git a/examples/gno.land/r/gnoland/pages/page_partners.gno b/examples/gno.land/r/gnoland/pages/page_partners.gno index a68ff98a05c..36674d84a78 100644 --- a/examples/gno.land/r/gnoland/pages/page_partners.gno +++ b/examples/gno.land/r/gnoland/pages/page_partners.gno @@ -17,5 +17,5 @@ Are you a builder, tinkerer, or researcher? If you’re looking to create awesom ` - _ = b.NewPost("", path, title, body, "", nil, nil) + _ = b.NewPost("", path, title, body, "2022-05-20T13:17:27Z", nil, nil) } diff --git a/examples/gno.land/r/gnoland/pages/page_start.gno b/examples/gno.land/r/gnoland/pages/page_start.gno index 1e1e27ca655..e08244ae57b 100644 --- a/examples/gno.land/r/gnoland/pages/page_start.gno +++ b/examples/gno.land/r/gnoland/pages/page_start.gno @@ -17,5 +17,5 @@ func init() { - [Install Gno Key](/r/demo/boards:testboard/5) - TODO: add more links ` - _ = b.NewPost("", path, title, body, "", nil, nil) + _ = b.NewPost("", path, title, body, "2022-05-20T13:17:28Z", nil, nil) } diff --git a/examples/gno.land/r/gnoland/pages/page_testnets.gno b/examples/gno.land/r/gnoland/pages/page_testnets.gno index 1158c4cfbbc..031afa4b044 100644 --- a/examples/gno.land/r/gnoland/pages/page_testnets.gno +++ b/examples/gno.land/r/gnoland/pages/page_testnets.gno @@ -15,5 +15,5 @@ func init() { See CONTRIBUTING.md on GitHub. ` - _ = b.NewPost("", path, title, body, "", nil, nil) + _ = b.NewPost("", path, title, body, "2022-05-20T13:17:29Z", nil, nil) } diff --git a/examples/gno.land/r/gnoland/pages/page_tokenomics.gno b/examples/gno.land/r/gnoland/pages/page_tokenomics.gno index b2e6100bae8..f51364c36e6 100644 --- a/examples/gno.land/r/gnoland/pages/page_tokenomics.gno +++ b/examples/gno.land/r/gnoland/pages/page_tokenomics.gno @@ -7,5 +7,5 @@ func init() { // XXX: description = """ body = `Lorem Ipsum` ) - _ = b.NewPost("", path, title, body, "", nil, nil) + _ = b.NewPost("", path, title, body, "2022-05-20T13:17:30Z", nil, nil) } From a15bd8bed3475d8d145b16453c09db1f59faafd3 Mon Sep 17 00:00:00 2001 From: leohhhn Date: Tue, 13 Feb 2024 14:46:48 +0100 Subject: [PATCH 20/27] temp add test1 as admin to blog realm --- examples/gno.land/r/gnoland/blog/admin.gno | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/gno.land/r/gnoland/blog/admin.gno b/examples/gno.land/r/gnoland/blog/admin.gno index f615e26e491..1264c8440e9 100644 --- a/examples/gno.land/r/gnoland/blog/admin.gno +++ b/examples/gno.land/r/gnoland/blog/admin.gno @@ -16,7 +16,8 @@ var ( func init() { // adminAddr = std.GetOrigCaller() // FIXME: find a way to use this from the main's genesis. - adminAddr = "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq" + //adminAddr = "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq" + adminAddr = "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5" } func AdminSetAdminAddr(addr std.Address) { From 28a49d0ac76f0d07f00c8daf3d8096fbf13ce487 Mon Sep 17 00:00:00 2001 From: leohhhn Date: Tue, 13 Feb 2024 19:56:29 +0100 Subject: [PATCH 21/27] fix tests --- examples/gno.land/r/gnoland/blog/admin.gno | 4 +- .../gno.land/r/gnoland/blog/gnoblog_test.gno | 57 +++++++++++-------- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/examples/gno.land/r/gnoland/blog/admin.gno b/examples/gno.land/r/gnoland/blog/admin.gno index 1264c8440e9..05ebea4f211 100644 --- a/examples/gno.land/r/gnoland/blog/admin.gno +++ b/examples/gno.land/r/gnoland/blog/admin.gno @@ -16,8 +16,8 @@ var ( func init() { // adminAddr = std.GetOrigCaller() // FIXME: find a way to use this from the main's genesis. - //adminAddr = "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq" - adminAddr = "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5" + adminAddr = "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq" + //adminAddr = "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5" } func AdminSetAdminAddr(addr std.Address) { diff --git a/examples/gno.land/r/gnoland/blog/gnoblog_test.gno b/examples/gno.land/r/gnoland/blog/gnoblog_test.gno index 1725a2413bd..d534eb7c2ad 100644 --- a/examples/gno.land/r/gnoland/blog/gnoblog_test.gno +++ b/examples/gno.land/r/gnoland/blog/gnoblog_test.gno @@ -21,40 +21,44 @@ No posts. ` assertMDEquals(t, got, expected) } + // create two posts, list post. { ModAddPost("slug1", "title1", "body1", "2022-05-20T13:17:22Z", "moul", "tag1,tag2") ModAddPost("slug2", "title2", "body2", "2022-05-20T13:17:23Z", "moul", "tag1,tag3") got := Render("") expected := ` -# Gnoland's Blog + # Gnoland's Blog
### [title2](/r/gnoland/blog:p/slug2) - 02 May 2022 + 20 May 2022
### [title1](/r/gnoland/blog:p/slug1) - 02 May 2022 + 20 May 2022
-` + ` assertMDEquals(t, got, expected) } // view post. { got := Render("p/slug2") - expected := ` -# [Gnoland's Blog](/r/gnoland/blog:) / p / title2 +# title2 body2 -[#tag1](/r/gnoland/blog:t/tag1) [#tag3](/r/gnoland/blog:t/tag3) +--- -by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq on 2009-02-13 11:31pm UTC -` +Tags: [#tag1](/r/gnoland/blog:t/tag1) [#tag3](/r/gnoland/blog:t/tag3) + +Written by moul on 20 May 2022 + +Published by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq to Gnoland's Blog + ` assertMDEquals(t, got, expected) } @@ -70,11 +74,10 @@ by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq on 2009-02-13 11:31pm UTC
-## [title1](/r/gnoland/blog:p/slug1) -**[Learn More](/r/gnoland/blog:p/slug1)** - +### [title1](/r/gnoland/blog:p/slug1) + 20 May 2022
-` + ` assertMDEquals(t, got, expected) } @@ -87,20 +90,22 @@ by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq on 2009-02-13 11:31pm UTC AddComment("slug1", "comment5") got := Render("p/slug2") expected := ` -# [Gnoland's Blog](/r/gnoland/blog:) / p / title2 +# title2 body2 -[#tag1](/r/gnoland/blog:t/tag1) [#tag3](/r/gnoland/blog:t/tag3) +--- + +Tags: [#tag1](/r/gnoland/blog:t/tag1) [#tag3](/r/gnoland/blog:t/tag3) + +Written by moul on 20 May 2022 -by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq on 2009-02-13 11:31pm UTC +Published by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq to Gnoland's Blog -#### by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq on 2009-02-13 11:31pm UTC comment4 -#### by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq on 2009-02-13 11:31pm UTC comment2 -` + ` assertMDEquals(t, got, expected) } @@ -109,20 +114,22 @@ comment2 ModEditPost("slug2", "title2++", "body2++", "2009-11-10T23:00:00Z", "manfred", "tag1,tag4") got := Render("p/slug2") expected := ` -# [Gnoland's Blog](/r/gnoland/blog:) / p / title2++ +# title2++ body2++ -[#tag1](/r/gnoland/blog:t/tag1) [#tag4](/r/gnoland/blog:t/tag4) +--- + +Tags: [#tag1](/r/gnoland/blog:t/tag1) [#tag4](/r/gnoland/blog:t/tag4) -by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq on 2009-02-13 11:31pm UTC +Written by manfred on 10 Nov 2009 + +Published by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq to Gnoland's Blog -#### by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq on 2009-02-13 11:31pm UTC comment4 -#### by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq on 2009-02-13 11:31pm UTC comment2 -` + ` assertMDEquals(t, got, expected) } From 7aeaa66cad7a2c7259dfea3d9668ac60846c5462 Mon Sep 17 00:00:00 2001 From: leohhhn Date: Tue, 13 Feb 2024 19:57:45 +0100 Subject: [PATCH 22/27] fix lint --- examples/gno.land/r/gnoland/blog/admin.gno | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gno.land/r/gnoland/blog/admin.gno b/examples/gno.land/r/gnoland/blog/admin.gno index 05ebea4f211..0528b55970e 100644 --- a/examples/gno.land/r/gnoland/blog/admin.gno +++ b/examples/gno.land/r/gnoland/blog/admin.gno @@ -17,7 +17,7 @@ var ( func init() { // adminAddr = std.GetOrigCaller() // FIXME: find a way to use this from the main's genesis. adminAddr = "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq" - //adminAddr = "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5" + // adminAddr = "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5" } func AdminSetAdminAddr(addr std.Address) { From 4283930e528efb855d07baab166e5f405122d319 Mon Sep 17 00:00:00 2001 From: leohhhn Date: Wed, 14 Feb 2024 05:41:05 +0100 Subject: [PATCH 23/27] fixup CI --- examples/gno.land/p/demo/blog/blog.gno | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/gno.land/p/demo/blog/blog.gno b/examples/gno.land/p/demo/blog/blog.gno index 23ae6fb5927..9e47da61f18 100644 --- a/examples/gno.land/p/demo/blog/blog.gno +++ b/examples/gno.land/p/demo/blog/blog.gno @@ -136,7 +136,7 @@ func (b *Blog) NewPost(publisher std.Address, slug, title, body, pubDate string, parsedTime = time.Now() } - post := Post{ + post := &Post{ Publisher: publisher, Authors: authors, Slug: slug, @@ -146,7 +146,7 @@ func (b *Blog) NewPost(publisher std.Address, slug, title, body, pubDate string, CreatedAt: parsedTime, } - return b.prepareAndSetPost(&post) + return b.prepareAndSetPost(post) } func (b *Blog) prepareAndSetPost(post *Post) error { From b1582a0b601810b658d53b5007b3120d201acd50 Mon Sep 17 00:00:00 2001 From: leohhhn Date: Thu, 22 Feb 2024 10:52:13 +0100 Subject: [PATCH 24/27] update rendering, fix tests --- examples/gno.land/p/demo/blog/blog.gno | 4 +- examples/gno.land/r/gnoland/blog/admin.gno | 1 - .../r/manfred/present/present_miami23.gno | 4 +- .../present/present_miami23_filetest.gno | 52 ++----------------- 4 files changed, 6 insertions(+), 55 deletions(-) diff --git a/examples/gno.land/p/demo/blog/blog.gno b/examples/gno.land/p/demo/blog/blog.gno index 9e47da61f18..ecfd827088d 100644 --- a/examples/gno.land/p/demo/blog/blog.gno +++ b/examples/gno.land/p/demo/blog/blog.gno @@ -300,9 +300,9 @@ func (p *Post) RenderTagList() string { // Render authors if there are any func (p *Post) RenderAuthorList() string { - out := "Written " + out := "Written" if len(p.Authors) != 0 { - out += "by " + out += " by " for idx, author := range p.Authors { out += author diff --git a/examples/gno.land/r/gnoland/blog/admin.gno b/examples/gno.land/r/gnoland/blog/admin.gno index 0528b55970e..f615e26e491 100644 --- a/examples/gno.land/r/gnoland/blog/admin.gno +++ b/examples/gno.land/r/gnoland/blog/admin.gno @@ -17,7 +17,6 @@ var ( func init() { // adminAddr = std.GetOrigCaller() // FIXME: find a way to use this from the main's genesis. adminAddr = "g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq" - // adminAddr = "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5" } func AdminSetAdminAddr(addr std.Address) { diff --git a/examples/gno.land/r/manfred/present/present_miami23.gno b/examples/gno.land/r/manfred/present/present_miami23.gno index cff2240945e..ca2160de3a9 100644 --- a/examples/gno.land/r/manfred/present/present_miami23.gno +++ b/examples/gno.land/r/manfred/present/present_miami23.gno @@ -4,8 +4,6 @@ func init() { path := "miami23" title := "Portal Loop Demo (Miami 2023)" body := ` -# Portal Loop Demo (Miami 2023) - Rendered by Gno. [Source (WIP)](https://github.com/gnolang/gno/pull/1176) @@ -40,5 +38,5 @@ Rendered by Gno. - Engage in workshops. - Connect and have fun with colleagues. ` - _ = b.NewPost(adminAddr, path, title, body, "", nil, []string{"demo", "portal-loop", "miami"}) + _ = b.NewPost(adminAddr, path, title, body, "2023-10-15T13:17:24Z", []string{"moul"}, []string{"demo", "portal-loop", "miami"}) } diff --git a/examples/gno.land/r/manfred/present/present_miami23_filetest.gno b/examples/gno.land/r/manfred/present/present_miami23_filetest.gno index 05c41905060..ac19d83ade4 100644 --- a/examples/gno.land/r/manfred/present/present_miami23_filetest.gno +++ b/examples/gno.land/r/manfred/present/present_miami23_filetest.gno @@ -1,57 +1,11 @@ package main -import "gno.land/r/manfred/present" +import ( + "gno.land/r/manfred/present" +) func main() { println(present.Render("")) println("------------------------------------") println(present.Render("p/miami23")) } - -// Output: -//
-// -// ## [Portal Loop Demo (Miami 2023)](/r/manfred/present:p/miami23) -// **[Learn More](/r/manfred/present:p/miami23)** -// -//
-// ------------------------------------ -// # Portal Loop Demo (Miami 2023) -// -// Rendered by Gno. -// -// [Source (WIP)](https://github.com/gnolang/gno/pull/1176) -// -// ## Portal Loop -// -// - DONE: Dynamic homepage, key pages, aliases, and redirects. -// - TODO: Deploy with history, complete worxdao v0. -// - Will replace the static gno.land site. -// - Enhances local development. -// -// [GitHub Issue](https://github.com/gnolang/gno/issues/1108) -// -// ## Roadmap -// -// - Crafting the roadmap this week, open to collaboration. -// - Combining onchain (portal loop) and offchain (GitHub). -// - Next week: Unveiling the official v0 roadmap. -// -// ## Teams, DAOs, Projects -// -// - Developing worxDAO contracts for directories of projects and teams. -// - GitHub teams and projects align with this structure. -// - CODEOWNER file updates coming. -// - Initial teams announced next week. -// -// ## Tech Team Retreat Plan -// -// - Continue Portal Loop. -// - Consider dApp development. -// - Explore new topics [here](https://github.com/orgs/gnolang/projects/15/). -// - Engage in workshops. -// - Connect and have fun with colleagues. -// -// [#demo](/r/manfred/present:t/demo) [#portal-loop](/r/manfred/present:t/portal-loop) [#miami](/r/manfred/present:t/miami) -// -// by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq on 1970-01-01 12:00am UTC From 6c32b094273e4941fe26ba6369995a7d333bbce9 Mon Sep 17 00:00:00 2001 From: leohhhn Date: Sat, 24 Feb 2024 17:33:07 +0100 Subject: [PATCH 25/27] update comments rendering --- examples/gno.land/p/demo/blog/blog.gno | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/examples/gno.land/p/demo/blog/blog.gno b/examples/gno.land/p/demo/blog/blog.gno index ecfd827088d..43565d20706 100644 --- a/examples/gno.land/p/demo/blog/blog.gno +++ b/examples/gno.land/p/demo/blog/blog.gno @@ -71,12 +71,17 @@ func (b Blog) RenderPost(res *mux.ResponseWriter, req *mux.Request) { res.Write(p.RenderAuthorList() + "\n\n") res.Write(p.RenderPublishData() + "\n\n") + res.Write("---\n") + res.Write("
Comment section\n\n") + // comments p.Comments.ReverseIterate("", "", func(key string, value interface{}) bool { comment := value.(*Comment) res.Write(comment.RenderListItem()) return false }) + + res.Write("
\n") } func (b Blog) RenderTag(res *mux.ResponseWriter, req *mux.Request) { @@ -354,9 +359,15 @@ type Comment struct { } func (c Comment) RenderListItem() string { - output := "" // todo see where it is used - // output += ufmt.Sprintf("#### %s\n", formatAuthorAndDate(c.Author, c.CreatedAt)) - output += c.Comment + "\n" - output += "\n" + output := "
" + output += c.Comment + "\n\n" + output += "
" + + output += "
" + output += ufmt.Sprintf("by %s on %s", c.Author, c.CreatedAt.Format(time.RFC822)) + output += "
\n\n\n" + + output += "---\n\n" + return output } From d3bc3640279b4f5e4b2c79bbfadb6ac34e5833b4 Mon Sep 17 00:00:00 2001 From: leohhhn Date: Sat, 24 Feb 2024 17:49:56 +0100 Subject: [PATCH 26/27] fix tests --- examples/gno.land/p/demo/blog/blog.gno | 2 +- .../gno.land/r/gnoland/blog/gnoblog_test.gno | 48 +++++++++++++++---- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/examples/gno.land/p/demo/blog/blog.gno b/examples/gno.land/p/demo/blog/blog.gno index 43565d20706..6be11336b0c 100644 --- a/examples/gno.land/p/demo/blog/blog.gno +++ b/examples/gno.land/p/demo/blog/blog.gno @@ -365,7 +365,7 @@ func (c Comment) RenderListItem() string { output += "
" output += ufmt.Sprintf("by %s on %s", c.Author, c.CreatedAt.Format(time.RFC822)) - output += "
\n\n\n" + output += "\n\n" output += "---\n\n" diff --git a/examples/gno.land/r/gnoland/blog/gnoblog_test.gno b/examples/gno.land/r/gnoland/blog/gnoblog_test.gno index d534eb7c2ad..d8e66b1203a 100644 --- a/examples/gno.land/r/gnoland/blog/gnoblog_test.gno +++ b/examples/gno.land/r/gnoland/blog/gnoblog_test.gno @@ -7,7 +7,7 @@ import ( ) func TestPackage(t *testing.T) { - std.TestSetOrigCaller(std.Address("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq")) + std.TestSetOrigCaller(std.Address("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5")) author := std.GetOrigCaller() @@ -57,7 +57,13 @@ Tags: [#tag1](/r/gnoland/blog:t/tag1) [#tag3](/r/gnoland/blog:t/tag3) Written by moul on 20 May 2022 -Published by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq to Gnoland's Blog +Published by g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 to Gnoland's Blog + +--- +
Comment section + +
+ ` assertMDEquals(t, got, expected) } @@ -100,11 +106,24 @@ Tags: [#tag1](/r/gnoland/blog:t/tag1) [#tag3](/r/gnoland/blog:t/tag3) Written by moul on 20 May 2022 -Published by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq to Gnoland's Blog +Published by g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 to Gnoland's Blog + +--- +
Comment section + +
comment4 + +
by g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 on 13 Feb 09 23:31 UTC
+ +--- + +
comment2 -comment4 +
by g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 on 13 Feb 09 23:31 UTC
-comment2 +--- + +
` assertMDEquals(t, got, expected) } @@ -124,11 +143,24 @@ Tags: [#tag1](/r/gnoland/blog:t/tag1) [#tag4](/r/gnoland/blog:t/tag4) Written by manfred on 10 Nov 2009 -Published by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq to Gnoland's Blog +Published by g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 to Gnoland's Blog + +--- +
Comment section + +
comment4 + +
by g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 on 13 Feb 09 23:31 UTC
-comment4 +--- + +
comment2 + +
by g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 on 13 Feb 09 23:31 UTC
+ +--- -comment2 +
` assertMDEquals(t, got, expected) } From 60a5d61933b2e26fd1111df341ffc0c6ee01fbed Mon Sep 17 00:00:00 2001 From: leohhhn Date: Sat, 24 Feb 2024 18:01:23 +0100 Subject: [PATCH 27/27] fix tests 2 --- .../gno.land/r/gnoland/blog/gnoblog_test.gno | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/gno.land/r/gnoland/blog/gnoblog_test.gno b/examples/gno.land/r/gnoland/blog/gnoblog_test.gno index d8e66b1203a..1be61138b39 100644 --- a/examples/gno.land/r/gnoland/blog/gnoblog_test.gno +++ b/examples/gno.land/r/gnoland/blog/gnoblog_test.gno @@ -7,7 +7,7 @@ import ( ) func TestPackage(t *testing.T) { - std.TestSetOrigCaller(std.Address("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5")) + std.TestSetOrigCaller(std.Address("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq")) author := std.GetOrigCaller() @@ -57,7 +57,7 @@ Tags: [#tag1](/r/gnoland/blog:t/tag1) [#tag3](/r/gnoland/blog:t/tag3) Written by moul on 20 May 2022 -Published by g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 to Gnoland's Blog +Published by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq to Gnoland's Blog ---
Comment section @@ -106,20 +106,20 @@ Tags: [#tag1](/r/gnoland/blog:t/tag1) [#tag3](/r/gnoland/blog:t/tag3) Written by moul on 20 May 2022 -Published by g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 to Gnoland's Blog +Published by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq to Gnoland's Blog ---
Comment section
comment4 -
by g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 on 13 Feb 09 23:31 UTC
+
by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq on 13 Feb 09 23:31 UTC
---
comment2 -
by g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 on 13 Feb 09 23:31 UTC
+
by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq on 13 Feb 09 23:31 UTC
--- @@ -143,20 +143,20 @@ Tags: [#tag1](/r/gnoland/blog:t/tag1) [#tag4](/r/gnoland/blog:t/tag4) Written by manfred on 10 Nov 2009 -Published by g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 to Gnoland's Blog +Published by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq to Gnoland's Blog ---
Comment section
comment4 -
by g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 on 13 Feb 09 23:31 UTC
+
by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq on 13 Feb 09 23:31 UTC
---
comment2 -
by g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 on 13 Feb 09 23:31 UTC
+
by g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq on 13 Feb 09 23:31 UTC
---