boards.gno
4.44 Kb · 152 lines
1package boards2
2
3import (
4 "gno.land/p/gnoland/boards/exts/permissions/v0"
5 "gno.land/p/gnoland/boards/v0"
6 "gno.land/p/moul/realmpath/v0"
7 "gno.land/p/moul/txlink/v0"
8 "gno.land/p/nt/bptree/v0"
9)
10
11const (
12 realmPkgPath = "gno.land/r/gnoland/boards2/v0"
13 gRealmPath = "/r/gnoland/boards2/v0"
14)
15
16var (
17 // RealmLink contains Boards2 realm link.
18 // It can be used to generate board TX links from other realms.
19 RealmLink = txlink.Realm(realmPkgPath)
20
21 // RequiredAccountAmount contains the required account amount for open board interactions.
22 // The amount requirement is not applied to members that were invited to an open board.
23 // Amount is defined as ugnot.
24 RequiredAccountAmount = int64(3_000_000_000)
25
26 // Notice contains an optional message that is displayed globally within the realm.
27 Notice string
28
29 // Help contains optional Markdown with Boards2 realm help.
30 Help string
31)
32
33// TODO: Refactor globals in favor of a cleaner pattern
34var (
35 gListedBoardsByID bptree.BPTree // string(id) -> *boards.Board
36 gInviteRequests bptree.BPTree // string(board id) -> *bptree.BPTree(address -> time.Time)
37 gBannedUsers bptree.BPTree // string(board id) -> *bptree.BPTree(address -> time.Time)
38 gLocked struct {
39 realm bool
40 realmMembers bool
41 }
42)
43
44var (
45 gBoards = boards.NewStorage()
46 gBoardsSequence = boards.NewIdentifierGenerator()
47 gPerms = initRealmPermissions("g1skl80cuz8zq3lul9pgz5pc35l2pfzgxgfpsqkx", // GovDAO T1 multisig
48 "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") // test1
49)
50
51// initRealmPermissions returns the default realm permissions.
52func initRealmPermissions(owners ...address) boards.Permissions {
53 perms := permissions.New(
54 permissions.UseSingleUserRole(),
55 permissions.WithSuperRole(RoleOwner),
56 )
57 perms.AddRole(RoleAdmin, PermissionBoardCreate)
58 for _, owner := range owners {
59 perms.SetUserRoles(owner, RoleOwner)
60 }
61
62 perms.ValidateFunc(PermissionBoardCreate, validateBasicBoardCreate)
63 perms.ValidateFunc(PermissionMemberInvite, validateBasicMemberInvite)
64 perms.ValidateFunc(PermissionRoleChange, validateBasicRoleChange)
65 return perms
66}
67
68// getInviteRequests returns invite requests for a board.
69func getInviteRequests(boardID boards.ID) (_ *bptree.BPTree, found bool) {
70 v := gInviteRequests.Get(boardID.Key())
71 if v == nil {
72 return nil, false
73 }
74 return v.(*bptree.BPTree), true
75}
76
77// getBannedUsers returns banned users within a board.
78func getBannedUsers(boardID boards.ID) (_ *bptree.BPTree, found bool) {
79 v := gBannedUsers.Get(boardID.Key())
80 if v == nil {
81 return nil, false
82 }
83 return v.(*bptree.BPTree), true
84}
85
86// mustGetBoardByName returns a board or panics when it's not found.
87func mustGetBoardByName(name string) *boards.Board {
88 board, found := gBoards.GetByName(name)
89 if !found {
90 panic("board does not exist with name: " + name)
91 }
92 return board
93}
94
95// mustGetBoard returns a board or panics when it's not found.
96func mustGetBoard(id boards.ID) *boards.Board {
97 board, found := gBoards.Get(id)
98 if !found {
99 panic("board does not exist with ID: " + id.String())
100 }
101 return board
102}
103
104// getThread returns a board thread.
105func getThread(board *boards.Board, threadID boards.ID) (*boards.Post, bool) {
106 thread, found := board.Threads.Get(threadID)
107 if !found {
108 // When thread is not found search it within hidden threads
109 meta := board.Meta.(*BoardMeta)
110 thread, found = meta.HiddenThreads.Get(threadID)
111 }
112 return thread, found
113}
114
115// getReply returns a thread comment or reply.
116func getReply(thread *boards.Post, replyID boards.ID) (*boards.Post, bool) {
117 meta := thread.Meta.(*ThreadMeta)
118 return meta.AllReplies.Get(replyID)
119}
120
121// mustGetThread returns a thread or panics when it's not found.
122func mustGetThread(board *boards.Board, threadID boards.ID) *boards.Post {
123 thread, found := getThread(board, threadID)
124 if !found {
125 panic("thread does not exist with ID: " + threadID.String())
126 }
127 return thread
128}
129
130// mustGetReply returns a reply or panics when it's not found.
131func mustGetReply(thread *boards.Post, replyID boards.ID) *boards.Post {
132 reply, found := getReply(thread, replyID)
133 if !found {
134 panic("reply does not exist with ID: " + replyID.String())
135 }
136 return reply
137}
138
139func mustGetPermissions(bid boards.ID) boards.Permissions {
140 if bid != 0 {
141 board := mustGetBoard(bid)
142 return board.Permissions
143 }
144 return gPerms
145}
146
147func parseRealmPath(path string) *realmpath.Request {
148 // Make sure request is using current realm path so paths can be parsed during Render
149 r := realmpath.Parse(path)
150 r.Realm = string(RealmLink)
151 return r
152}