Skip to content

Commit 0f48ffb

Browse files
committed
wip: improvements
These changes were done before the change of direction for the boards implementation. Commiting them to avoid loosing the ideas and improvements present here.
1 parent cecf7a8 commit 0f48ffb

File tree

10 files changed

+252
-52
lines changed

10 files changed

+252
-52
lines changed

examples/gno.land/p/demo/boardsv2/draft3/app.gno

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package boards
33
import (
44
"gno.land/p/demo/boards/post"
55
"gno.land/p/demo/boards/post/plugin"
6+
pluginfork "gno.land/p/demo/boards/post/plugin/fork"
7+
pluginpoll "gno.land/p/demo/boards/post/plugin/poll"
68
pluginreputation "gno.land/p/demo/boards/post/plugin/reputation"
79
plugintitle "gno.land/p/demo/boards/post/plugin/title"
810
)
@@ -38,14 +40,13 @@ func New(st post.Store, options ...Option) App {
3840
pluginreputation.UsePolicy(app.reputationPolicy),
3941
pluginreputation.AllowedPostLevels(post.LevelPost, post.LevelComment),
4042
),
43+
pluginfork.New(
44+
pluginfork.AllowedPostLevels(post.LevelPost),
45+
),
4146
)
4247
return app
4348
}
4449

45-
func (a App) GetPost(path string) (_ *post.Post, found bool) {
46-
return a.post.Get(path) // NOTE: Allowing this enables us to have generic functions like Lock
47-
}
48-
4950
func (a App) GetBoard(path string) (_ Board, found bool) {
5051
p, found := a.posts.Get(path)
5152
if !found || p.Level != LevelBoard {
@@ -73,7 +74,16 @@ func (a App) GetComment(path string) (_ Comment, found bool) {
7374
func (a App) CreateBoard(slug, title, description string, tags []string) (Board, error) {}
7475

7576
// Fork forks either a board or a thread by their path.
76-
func (a App) Fork(path, newPath string) error {}
77+
func (a App) ForkBoard(b Board, newPath string) error {
78+
// NOTE: Instead of `app.ForkBoard()` we could use `b.Fork(newPath)` instead but that requires Board to have plugin access
79+
// NOTE: This case gets the plugin from the plugin list to fork
80+
p, _ := a.plugins.Get(pluginfork.Name)
81+
return p.Fork(b.Post, newPath)
82+
}
83+
84+
func (a App) ForkThread(t Thread, newPath string) error {
85+
// TODO: Implement thread fork app support
86+
}
7787

7888
// Lock locks either a board or a thread by their path.
7989
// Once a board is locked new threads to the board and comments to the existing

examples/gno.land/p/demo/boardsv2/draft3/board.gno

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,31 @@
11
package boards
22

33
import (
4+
"gno.land/p/demo/boards/post"
5+
pluginfork "gno.land/p/demo/boards/post/plugin/fork"
46
pluginreputation "gno.land/p/demo/boards/post/plugin/reputation"
57
plugintitle "gno.land/p/demo/boards/post/plugin/title"
68
)
79

8-
type Board struct {
9-
*post.Post
10-
}
10+
type (
11+
BoardContent plugintitle.Content
12+
13+
Board struct {
14+
*post.Post
15+
}
16+
)
1117

12-
func (b Board) Title() string {
13-
return b.getContent().Title
18+
func NewBoard(pst *post.Post) Board {
19+
// TODO: Local plugins must be initialized here (same for other plugins)
20+
return Board{pst}
1421
}
1522

16-
func (b Board) Description() string {
17-
return b.getContent().Description
23+
func (b Board) Info() BoardContent {
24+
return BoardContent(b.getContent())
1825
}
1926

20-
func (b Board) Tags() string {
21-
return b.getContent().Tags
27+
func (b Board) Update(c BoardContent) {
28+
b.PluginStore[plugintitle.Name] = plugintitle.Content(c)
2229
}
2330

2431
func (b Board) Upvote() error {
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package pluginfork
2+
3+
import (
4+
"gno.land/p/demo/boards/post"
5+
)
6+
7+
const Name = "fork"
8+
9+
// TODO: Implement fork plugin to support thread forking
10+
type Plugin struct {
11+
AllowedPostLevels []int
12+
}
13+
14+
func New(o ...Option) Plugin {
15+
var p Plugin
16+
for _, apply := range o {
17+
apply(&p)
18+
}
19+
return p
20+
}
21+
22+
func (p Plugin) Name() string {
23+
return Name
24+
}
25+
26+
func (p Plugin) Render() string {
27+
// TODO: Implement render support for text
28+
return ""
29+
}
30+
31+
func (p Plugin) HasForkSupport(pst *post.Post) bool {
32+
if len(p.AllowedPostLevels) == 0 {
33+
return true
34+
}
35+
36+
for _, lvl := range p.AllowedPostLevels {
37+
if pst.Level == lvl {
38+
return true
39+
}
40+
}
41+
return false
42+
}
43+
44+
func (p Plugin) Fork(pst *post.Post, newPath string) error {
45+
// TODO: Implement fork support
46+
return nil
47+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package pluginfork
2+
3+
type Option func(*Plugin)
4+
5+
func AllowedPostLevels(levels []int) Option {
6+
return func(p *Plugin) {
7+
p.AllowedPostLevels = levels
8+
}
9+
}

examples/gno.land/p/demo/boardsv2/draft3/post/plugin/reputation/reputation.gno

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package pluginreputation
22

3-
import "errors"
3+
import (
4+
"errors"
5+
"std"
6+
)
47

8+
// NOTE: Think about implementing a reputation based policy
59
const (
610
PolicyLinear Policy = iota
711
PolicyTokenBased
@@ -14,15 +18,15 @@ var ErrNotSupported = errors.New("reputation not supported")
1418
type (
1519
Policy int
1620

17-
// TODO: Implement reputation plugin
1821
Plugin struct {
22+
Store Store
1923
Policy Policy
2024
AllowedPostLevels []int
2125
}
2226

2327
Reputation struct {
2428
Upvotes uint
25-
Downbotes uint
29+
Downvotes uint
2630
}
2731
)
2832

@@ -55,28 +59,41 @@ func (p Plugin) HasReputationSupport(pst *post.Post) bool {
5559
return false
5660
}
5761

58-
func (p *Plugin) Votes(pst *post.Post) uint32 {
62+
func (p Plugin) Votes(pst *post.Post) (upvotes uint64, downvotes uint64) {
5963
if !p.HasReputationSupport(pst) {
6064
return ErrNotSupported
6165
}
6266

63-
// TODO: Implement
67+
r := pst.PluginStore[Name].(*Reputation)
68+
return r.Upvotes, r.Downvotes
69+
}
70+
71+
func (p Plugin) Voters(pst *post.Post) []std.Address {
72+
if !p.HasReputationSupport(pst) {
73+
return ErrNotSupported
74+
}
75+
76+
// TODO: Implement support for tracking voters
6477
}
6578

6679
func (p *Plugin) Upvote(pst *post.Post) error {
6780
if !p.HasReputationSupport(pst) {
6881
return ErrNotSupported
6982
}
7083

71-
// TODO: Modify global state
72-
// TODO: Modify local state
84+
// TODO: Handle accounts and change downvotes for existing accounts that downvoted
7385
r := pst.PluginStore[Name].(*Reputation)
86+
r.Upvotes++
87+
p.store.inc(pst.ID)
7488
}
7589

7690
func (p *Plugin) Downvote(pst *post.Post) error {
7791
if !p.HasReputationSupport(pst) {
7892
return ErrNotSupported
7993
}
8094

81-
// TODO: Implement
95+
// TODO: Handle accounts and change upvotes for existing accounts that upvoted
96+
r := pst.PluginStore[Name].(*Reputation)
97+
r.Downvotes++
98+
p.store.dec(pst.ID)
8299
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package pluginreputation
2+
3+
import (
4+
"gno.land/p/demo/seqid"
5+
)
6+
7+
type (
8+
VotesIterFn = func(votes uint64, path string) bool
9+
10+
Store struct {
11+
votes avl.Tree // string(count) -> string(path)
12+
}
13+
)
14+
15+
func (s Store) Iterate(fn VotesIterFn) bool {
16+
// TODO: Support pagination of votes?
17+
return s.votes.Iterate("", "", func(key string, v interface{}) bool {
18+
count, _ := seqid.FromBinary(key)
19+
return fn(uint64(count), v.(string))
20+
})
21+
}
22+
23+
func (s *Store) inc(path string) uint64 {
24+
var (
25+
current seqid.ID
26+
v, found = s.votes.Get(path)
27+
)
28+
if found {
29+
current = v.(seqid.ID)
30+
// TODO: Implement the right solution because this is not right, just showcase
31+
s.votes.Remove(current.Binary())
32+
}
33+
34+
current.Next()
35+
s.votes.Set(current.Binary(), path)
36+
return uint64(current)
37+
}
38+
39+
func (s *Store) dec(path string) uint64 {
40+
var (
41+
current seqid.ID
42+
v, found = s.votes.Get(path)
43+
)
44+
if found {
45+
current = v.(seqid.ID)
46+
}
47+
48+
if current == 0 {
49+
return current
50+
}
51+
52+
s.votes.Remove(current.Binary())
53+
current--
54+
if current != 0 {
55+
s.votes.Set(current.Binary(), current)
56+
}
57+
return uint64(current)
58+
}

examples/gno.land/p/demo/boardsv2/draft3/post/plugin/text/text.gno

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
// plugintext is a content type for representing a tweet, blog post or a thread like Reddit.
22
package plugintext
33

4+
import (
5+
"gno.land/p/demo/boards/post" // NOTE: Plugins should be at the same level of post package
6+
)
7+
48
const Name = "post-text"
59

610
type (
7-
Plugin struct{}
8-
Text struct {
11+
Plugin struct{}
12+
Content struct {
913
Title string
1014
Body string
1115
Tags []string
@@ -26,9 +30,9 @@ func (p Plugin) Render() string {
2630
}
2731

2832
func (p Plugin) Content(pst *post.Post) Content {
29-
return pst.Body[Name].(*Text)
33+
return pst.Body[Name].(*Content)
3034
}
3135

32-
func (p Plugin) SetContent(pst *post.Post, t Text) {
36+
func (p Plugin) SetContent(pst *post.Post, c Content) {
3337
pst.Body[Name] = c
3438
}

examples/gno.land/p/demo/boardsv2/draft3/post/post.gno

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,18 @@ import (
77
"gno.land/p/demo/boards/post/plugin"
88
)
99

10-
type (
11-
Post struct {
12-
ID string
13-
PluginStore plugin.Plugin
14-
Parent *Post
15-
Level int
16-
Base *Post
17-
Children []*Post
18-
Forks []*Post
19-
UpdatedAt time.Time
20-
CreatedAt time.Time
21-
Creator std.Address
22-
}
23-
)
10+
type Post struct {
11+
ID string
12+
PluginStore plugin.Plugin
13+
Parent *Post
14+
Level int
15+
Base *Post
16+
Children []*Post
17+
Forks []*Post
18+
UpdatedAt time.Time
19+
CreatedAt time.Time
20+
Creator std.Address
21+
}
2422

2523
func (p Post) NextIncrementalKey(baseKey string) string {
2624
return baseKey + "/" + strconv.Itoa(len(p.Children))

0 commit comments

Comments
 (0)