-
Notifications
You must be signed in to change notification settings - Fork 399
/
Copy pathboard.gno
139 lines (122 loc) · 3.28 KB
/
board.gno
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package boards
import (
"std"
"strconv"
"time"
"gno.land/p/demo/avl"
"gno.land/p/moul/txlink"
)
//----------------------------------------
// Board
type BoardID uint64
func (bid BoardID) String() string {
return strconv.Itoa(int(bid))
}
type Board struct {
id BoardID // only set for public boards.
url string
name string
creator std.Address
threads avl.Tree // Post.id -> *Post
postsCtr uint64 // increments Post.id
createdAt time.Time
deleted avl.Tree // TODO reserved for fast-delete.
}
func newBoard(id BoardID, url string, name string, creator std.Address) *Board {
if !reName.MatchString(name) {
panic("invalid name: " + name)
}
exists := gBoardsByName.Has(name)
if exists {
panic("board already exists")
}
return &Board{
id: id,
url: url,
name: name,
creator: creator,
threads: avl.Tree{},
createdAt: time.Now(),
deleted: avl.Tree{},
}
}
/* TODO support this once we figure out how to ensure URL correctness.
// A private board is not tracked by gBoards*,
// but must be persisted by the caller's realm.
// Private boards have 0 id and does not ping
// back the remote board on reposts.
func NewPrivateBoard(url string, name string, creator std.Address) *Board {
return newBoard(0, url, name, creator)
}
*/
func (board *Board) IsPrivate() bool {
return board.id == 0
}
func (board *Board) GetThread(pid PostID) *Post {
pidkey := postIDKey(pid)
postI, exists := board.threads.Get(pidkey)
if !exists {
return nil
}
return postI.(*Post)
}
func (board *Board) AddThread(creator std.Address, title string, body string) *Post {
pid := board.incGetPostID()
pidkey := postIDKey(pid)
thread := newPost(board, pid, creator, title, body, pid, 0, 0)
board.threads.Set(pidkey, thread)
return thread
}
// NOTE: this can be potentially very expensive for threads with many replies.
// TODO: implement optional fast-delete where thread is simply moved.
func (board *Board) DeleteThread(pid PostID) {
pidkey := postIDKey(pid)
_, removed := board.threads.Remove(pidkey)
if !removed {
panic("thread does not exist with id " + pid.String())
}
}
func (board *Board) HasPermission(addr std.Address, perm Permission) bool {
if board.creator == addr {
switch perm {
case EditPermission:
return true
case DeletePermission:
return true
default:
return false
}
}
return false
}
// Renders the board for display suitable as plaintext in
// console. This is suitable for demonstration or tests,
// but not for prod.
func (board *Board) RenderBoard() string {
str := ""
str += "\\[[post](" + board.GetPostFormURL() + ")]\n\n"
if board.threads.Size() > 0 {
board.threads.Iterate("", "", func(key string, value interface{}) bool {
if str != "" {
str += "----------------------------------------\n"
}
str += value.(*Post).RenderSummary() + "\n"
return false
})
}
return str
}
func (board *Board) incGetPostID() PostID {
board.postsCtr++
return PostID(board.postsCtr)
}
func (board *Board) GetURLFromThreadAndReplyID(threadID, replyID PostID) string {
if replyID == 0 {
return board.url + "/" + threadID.String()
} else {
return board.url + "/" + threadID.String() + "/" + replyID.String()
}
}
func (board *Board) GetPostFormURL() string {
return txlink.Call("CreateThread", "bid", board.id.String())
}