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