Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

boards.gno

4.54 Kb · 156 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	initialOwner address = "g1skl80cuz8zq3lul9pgz5pc35l2pfzgxgfpsqkx" // GovDAO T1 multisig
 15)
 16
 17var (
 18	// RealmLink contains Boards2 realm link.
 19	// It can be used to generate board TX links from other realms.
 20	RealmLink = txlink.Realm(realmPkgPath)
 21
 22	// RequiredAccountAmount contains the required account amount for open board interactions.
 23	// The amount requirement is not applied to members that were invited to an open board.
 24	// Amount is defined as ugnot.
 25	RequiredAccountAmount = int64(3_000_000_000)
 26
 27	// Notice contains an optional message that is displayed globally within the realm.
 28	Notice string
 29
 30	// Help contains optional Markdown with Boards2 realm help.
 31	Help string
 32)
 33
 34// TODO: Refactor globals in favor of a cleaner pattern
 35var (
 36	gListedBoardsByID bptree.BPTree // string(id) -> *boards.Board
 37	gInviteRequests   bptree.BPTree // string(board id) -> *bptree.BPTree(address -> time.Time)
 38	gBannedUsers      bptree.BPTree // string(board id) -> *bptree.BPTree(address -> time.Time)
 39	gLocked           struct {
 40		realm        bool
 41		realmMembers bool
 42	}
 43)
 44
 45var (
 46	gBoards         = boards.NewStorage()
 47	gBoardsSequence = boards.NewIdentifierGenerator()
 48	gPerms          = initRealmPermissions(initialOwner)
 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
 68func init() {
 69	addBoard(gBoardsSequence.Next(), initialOwner, "OpenDiscussions", true, true)
 70}
 71
 72// getInviteRequests returns invite requests for a board.
 73func getInviteRequests(boardID boards.ID) (_ *bptree.BPTree, found bool) {
 74	v := gInviteRequests.Get(boardID.Key())
 75	if v == nil {
 76		return nil, false
 77	}
 78	return v.(*bptree.BPTree), true
 79}
 80
 81// getBannedUsers returns banned users within a board.
 82func getBannedUsers(boardID boards.ID) (_ *bptree.BPTree, found bool) {
 83	v := gBannedUsers.Get(boardID.Key())
 84	if v == nil {
 85		return nil, false
 86	}
 87	return v.(*bptree.BPTree), true
 88}
 89
 90// mustGetBoardByName returns a board or panics when it's not found.
 91func mustGetBoardByName(name string) *boards.Board {
 92	board, found := gBoards.GetByName(name)
 93	if !found {
 94		panic("board does not exist with name: " + name)
 95	}
 96	return board
 97}
 98
 99// mustGetBoard returns a board or panics when it's not found.
100func mustGetBoard(id boards.ID) *boards.Board {
101	board, found := gBoards.Get(id)
102	if !found {
103		panic("board does not exist with ID: " + id.String())
104	}
105	return board
106}
107
108// getThread returns a board thread.
109func getThread(board *boards.Board, threadID boards.ID) (*boards.Post, bool) {
110	thread, found := board.Threads.Get(threadID)
111	if !found {
112		// When thread is not found search it within hidden threads
113		meta := board.Meta.(*BoardMeta)
114		thread, found = meta.HiddenThreads.Get(threadID)
115	}
116	return thread, found
117}
118
119// getReply returns a thread comment or reply.
120func getReply(thread *boards.Post, replyID boards.ID) (*boards.Post, bool) {
121	meta := thread.Meta.(*ThreadMeta)
122	return meta.AllReplies.Get(replyID)
123}
124
125// mustGetThread returns a thread or panics when it's not found.
126func mustGetThread(board *boards.Board, threadID boards.ID) *boards.Post {
127	thread, found := getThread(board, threadID)
128	if !found {
129		panic("thread does not exist with ID: " + threadID.String())
130	}
131	return thread
132}
133
134// mustGetReply returns a reply or panics when it's not found.
135func mustGetReply(thread *boards.Post, replyID boards.ID) *boards.Post {
136	reply, found := getReply(thread, replyID)
137	if !found {
138		panic("reply does not exist with ID: " + replyID.String())
139	}
140	return reply
141}
142
143func mustGetPermissions(bid boards.ID) boards.Permissions {
144	if bid != 0 {
145		board := mustGetBoard(bid)
146		return board.Permissions
147	}
148	return gPerms
149}
150
151func parseRealmPath(path string) *realmpath.Request {
152	// Make sure request is using current realm path so paths can be parsed during Render
153	r := realmpath.Parse(path)
154	r.Realm = string(RealmLink)
155	return r
156}