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