boards.gno
4.39 Kb · 151 lines
1package boards2
2
3import (
4 "gno.land/p/gnoland/boards"
5 "gno.land/p/gnoland/boards/exts/permissions"
6 "gno.land/p/moul/realmpath"
7 "gno.land/p/moul/txlink"
8 "gno.land/p/nt/bptree/v0"
9)
10
11const (
12 realmPkgPath = "gno.land/r/gnoland/boards2/v1"
13 gRealmPath = "/r/gnoland/boards2/v1"
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("g1rp7cmetn27eqlpjpc4vuusf8kaj746tysc0qgh") // GovDAO T1 multisig
48)
49
50// initRealmPermissions returns the default realm permissions.
51func initRealmPermissions(owners ...address) boards.Permissions {
52 perms := permissions.New(
53 permissions.UseSingleUserRole(),
54 permissions.WithSuperRole(RoleOwner),
55 )
56 perms.AddRole(RoleAdmin, PermissionBoardCreate)
57 for _, owner := range owners {
58 perms.SetUserRoles(owner, RoleOwner)
59 }
60
61 perms.ValidateFunc(PermissionBoardCreate, validateBasicBoardCreate)
62 perms.ValidateFunc(PermissionMemberInvite, validateBasicMemberInvite)
63 perms.ValidateFunc(PermissionRoleChange, validateBasicRoleChange)
64 return perms
65}
66
67// getInviteRequests returns invite requests for a board.
68func getInviteRequests(boardID boards.ID) (_ *bptree.BPTree, found bool) {
69 v, exists := gInviteRequests.Get(boardID.Key())
70 if !exists {
71 return nil, false
72 }
73 return v.(*bptree.BPTree), true
74}
75
76// getBannedUsers returns banned users within a board.
77func getBannedUsers(boardID boards.ID) (_ *bptree.BPTree, found bool) {
78 v, exists := gBannedUsers.Get(boardID.Key())
79 if !exists {
80 return nil, false
81 }
82 return v.(*bptree.BPTree), true
83}
84
85// mustGetBoardByName returns a board or panics when it's not found.
86func mustGetBoardByName(name string) *boards.Board {
87 board, found := gBoards.GetByName(name)
88 if !found {
89 panic("board does not exist with name: " + name)
90 }
91 return board
92}
93
94// mustGetBoard returns a board or panics when it's not found.
95func mustGetBoard(id boards.ID) *boards.Board {
96 board, found := gBoards.Get(id)
97 if !found {
98 panic("board does not exist with ID: " + id.String())
99 }
100 return board
101}
102
103// getThread returns a board thread.
104func getThread(board *boards.Board, threadID boards.ID) (*boards.Post, bool) {
105 thread, found := board.Threads.Get(threadID)
106 if !found {
107 // When thread is not found search it within hidden threads
108 meta := board.Meta.(*BoardMeta)
109 thread, found = meta.HiddenThreads.Get(threadID)
110 }
111 return thread, found
112}
113
114// getReply returns a thread comment or reply.
115func getReply(thread *boards.Post, replyID boards.ID) (*boards.Post, bool) {
116 meta := thread.Meta.(*ThreadMeta)
117 return meta.AllReplies.Get(replyID)
118}
119
120// mustGetThread returns a thread or panics when it's not found.
121func mustGetThread(board *boards.Board, threadID boards.ID) *boards.Post {
122 thread, found := getThread(board, threadID)
123 if !found {
124 panic("thread does not exist with ID: " + threadID.String())
125 }
126 return thread
127}
128
129// mustGetReply returns a reply or panics when it's not found.
130func mustGetReply(thread *boards.Post, replyID boards.ID) *boards.Post {
131 reply, found := getReply(thread, replyID)
132 if !found {
133 panic("reply does not exist with ID: " + replyID.String())
134 }
135 return reply
136}
137
138func mustGetPermissions(bid boards.ID) boards.Permissions {
139 if bid != 0 {
140 board := mustGetBoard(bid)
141 return board.Permissions
142 }
143 return gPerms
144}
145
146func parseRealmPath(path string) *realmpath.Request {
147 // Make sure request is using current realm path so paths can be parsed during Render
148 r := realmpath.Parse(path)
149 r.Realm = string(RealmLink)
150 return r
151}