hub.gno
6.02 Kb · 213 lines
1// The `hub.gno` file exposes safe, read-only views over the realm's
2// persistent state.
3//
4// Note for future maintainers: these reads perform no caller
5// authorization, so do not graft user-identity gating onto them.
6
7package boards2
8
9import (
10 "gno.land/p/gnoland/boards"
11 hubexts "gno.land/p/gnoland/boards/exts/hub"
12)
13
14// Safe view types are defined in the hub extensions package and
15// re-exported here so callers can keep using them via this realm.
16type (
17 Board = hubexts.Board
18 Comment = hubexts.Comment
19 Flag = hubexts.Flag
20 Member = hubexts.Member
21 Thread = hubexts.Thread
22)
23
24// GetBoard returns a safe board.
25func GetBoard(id uint64) (Board, bool) {
26 b, found := gBoards.Get(boards.ID(id))
27 if !found {
28 return Board{}, false
29 }
30 return hubexts.NewSafeBoard(b), true
31}
32
33// GetThread returns a safe board thread.
34func GetThread(boardID, threadID uint64) (Thread, bool) {
35 t, found := getBoardThread(boardID, threadID)
36 if !found {
37 return Thread{}, false
38 }
39 return hubexts.NewSafeThread(t), true
40}
41
42// GetComment returns a safe thread comment or reply.
43// `commentID` can be the ID of a top level comment or of a nested reply.
44func GetComment(boardID, threadID, commentID uint64) (Comment, bool) {
45 c, found := getComment(boardID, threadID, commentID)
46 if !found {
47 return Comment{}, false
48 }
49 return hubexts.NewSafeComment(c), true
50}
51
52// GetBoards returns a list with all boards.
53// To reverse iterate use a negative count.
54func GetBoards(start, count int) []Board {
55 var boards_ []Board
56 gBoards.Iterate(start, count, func(b *boards.Board) bool {
57 boards_ = append(boards_, hubexts.NewSafeBoard(b))
58 return false
59 })
60 return boards_
61}
62
63// GetThreads returns a list with threads of a board.
64// To reverse iterate use a negative count.
65// A board without thread storage has no threads, so nil is returned.
66func GetThreads(boardID uint64, start, count int) []Thread {
67 b, found := gBoards.Get(boards.ID(boardID))
68 if !found || b.Threads == nil {
69 return nil
70 }
71
72 var threads []Thread
73 b.Threads.Iterate(start, count, func(thread *boards.Post) bool {
74 threads = append(threads, hubexts.NewSafeThread(thread))
75 return false
76 })
77 return threads
78}
79
80// GetMembers returns a list with the members of a board.
81// A zero `boardID` refers to the realm, so the realm admin users are returned.
82// A non permissioned board has no members, so nil is returned.
83func GetMembers(boardID uint64, start, count int) []Member {
84 perms := gPerms
85 if boardID != 0 {
86 b, found := gBoards.Get(boards.ID(boardID))
87 if !found {
88 return nil
89 }
90 perms = b.Permissions
91 }
92
93 if perms == nil {
94 return nil
95 }
96
97 var members []Member
98 perms.IterateUsers(start, count, func(u boards.User) bool {
99 members = append(members, hubexts.NewSafeMember(u))
100 return false
101 })
102 return members
103}
104
105// GetReposts returns a list with repost of a board thread.
106// To reverse iterate use a negative count.
107// A repost is not included when its destination thread has been deleted,
108// so the total accessible results can be shorter than the thread's RepostCount(),
109// and a single call can return fewer than count results.
110// (The reason for the discrepancy is that the start index can be large,
111// and this function cannot scan all reposts up to the start index to
112// resolve the discrepancy.)
113func GetReposts(boardID, threadID uint64, start, count int) []Thread {
114 t, found := getBoardThread(boardID, threadID)
115 if !found {
116 return nil
117 }
118
119 var reposts []Thread
120 t.Reposts.Iterate(start, count, func(rBoardID, rRepostID boards.ID) bool {
121 r, found := getBoardThread(uint64(rBoardID), uint64(rRepostID))
122 if found {
123 reposts = append(reposts, hubexts.NewSafeThread(r))
124 }
125 return false
126 })
127 return reposts
128}
129
130// GetFlags returns a list with thread or comment moderation flags.
131// To reverse iterate use a negative count.
132// Thread flags are returned when `commentID` is zero, or the flags of the
133// comment or reply with that ID are returned otherwise.
134func GetFlags(boardID, threadID, commentID uint64, start, count int) []Flag {
135 var storage boards.FlagStorage
136 if commentID == 0 {
137 t, found := getBoardThread(boardID, threadID)
138 if !found {
139 return nil
140 }
141
142 storage = t.Flags
143 } else {
144 c, found := getComment(boardID, threadID, commentID)
145 if !found {
146 return nil
147 }
148
149 storage = c.Flags
150 }
151
152 var flags []Flag
153 storage.Iterate(start, count, func(f boards.Flag) bool {
154 flags = append(flags, hubexts.NewSafeFlag(f))
155 return false
156 })
157 return flags
158}
159
160// GetComments returns a list with top-level comments of a thread.
161// To reverse iterate use a negative count.
162func GetComments(boardID, threadID uint64, start, count int) []Comment {
163 t, found := getBoardThread(boardID, threadID)
164 if !found {
165 return nil
166 }
167
168 var comments []Comment
169 // Replies only has direct replies.
170 t.Replies.Iterate(start, count, func(comment *boards.Post) bool {
171 comments = append(comments, hubexts.NewSafeComment(comment))
172 return false
173 })
174 return comments
175}
176
177// GetReplies returns a list with the direct replies of a comment or reply.
178// To reverse iterate use a negative count.
179// `commentID` can be the ID of a top level comment or of a nested reply.
180func GetReplies(boardID, threadID, commentID uint64, start, count int) []Comment {
181 c, found := getComment(boardID, threadID, commentID)
182 if !found {
183 return nil
184 }
185
186 var replies []Comment
187 c.Replies.Iterate(start, count, func(comment *boards.Post) bool {
188 replies = append(replies, hubexts.NewSafeComment(comment))
189 return false
190 })
191 return replies
192}
193
194// getBoardThread returns a board thread from their IDs.
195func getBoardThread(boardID, threadID uint64) (*boards.Post, bool) {
196 b, found := gBoards.Get(boards.ID(boardID))
197 if !found {
198 return nil, false
199 }
200 return getThread(b, boards.ID(threadID))
201}
202
203// getComment returns a thread comment or reply from their IDs.
204// It searches the thread's flat index of all comments and replies, so
205// nested replies are addressable by ID and not only top level comments.
206func getComment(boardID, threadID, commentID uint64) (*boards.Post, bool) {
207 t, found := getBoardThread(boardID, threadID)
208 if !found {
209 return nil, false
210 }
211
212 return getReply(t, boards.ID(commentID))
213}