hub.gno
5.70 Kb · 201 lines
1// Package hub exposes safe, read-only views over boards2's persistent
2// state. The Get* functions are crossing functions: callers must invoke
3// them with `cross` (e.g. `hub.GetBoard(cross, id)`). The crossing into
4// hub gives each call a live `cur` whose `Previous()` is the caller's
5// realm — that's what boards2's protected entry points use for the
6// namespace check.
7//
8// Note for future maintainers: inside a Get* body, `cur.Previous()` is
9// the *immediate* caller's realm, which may be an intermediary, not
10// necessarily the end user. Do not graft user-identity gating onto
11// these reads.
12package hub
13
14import (
15 "gno.land/p/gnoland/boards"
16
17 boards2 "gno.land/r/gnoland/boards2/v1"
18)
19
20// GetBoard returns a safe board.
21func GetBoard(cur realm, id uint64) (Board, bool) {
22 b, found := getBoard(0, cur, id)
23 if !found {
24 return Board{}, false
25 }
26 return NewSafeBoard(b), true
27}
28
29// GetThread returns a safe board thread.
30func GetThread(cur realm, boardID, threadID uint64) (Thread, bool) {
31 t, found := getThread(0, cur, boardID, threadID)
32 if !found {
33 return Thread{}, false
34 }
35 return NewSafeThread(t), true
36}
37
38// GetComment returns a safe thread comment.
39func GetComment(cur realm, boardID, threadID, commentID uint64) (Comment, bool) {
40 c, found := getComment(0, cur, boardID, threadID, commentID)
41 if !found {
42 return Comment{}, false
43 }
44 return NewSafeComment(c), true
45}
46
47// GetBoards returns a list with all boards.
48// To reverse iterate use a negative count.
49func GetBoards(cur realm, start, count int) []Board {
50 var boards_ []Board
51 boards2.Iterate(cross(cur), start, count, func(b *boards.Board) bool {
52 boards_ = append(boards_, NewSafeBoard(b))
53 return false
54 })
55 return boards_
56}
57
58// GetThreads returns a list with threads of a board.
59// To reverse iterate use a negative count.
60func GetThreads(cur realm, boardID uint64, start, count int) []Thread {
61 b, found := getBoard(0, cur, boardID)
62 if !found {
63 return nil
64 }
65
66 var threads []Thread
67 b.Threads.Iterate(start, count, func(thread *boards.Post) bool {
68 threads = append(threads, NewSafeThread(thread))
69 return false
70 })
71 return threads
72}
73
74// GetMembers returns a list with the members of a board.
75// To reverse iterate use a negative count.
76func GetMembers(cur realm, boardID uint64, start, count int) []boards.User {
77 b, found := getBoard(0, cur, boardID)
78 if !found {
79 return nil
80 }
81
82 var members []boards.User
83 b.Permissions.IterateUsers(start, count, func(u boards.User) bool {
84 members = append(members, u)
85 return false
86 })
87 return members
88}
89
90// GetReposts returns a list with repost of a board thread.
91// To reverse iterate use a negative count.
92func GetReposts(cur realm, boardID, threadID uint64, start, count int) []Thread {
93 t, found := getThread(0, cur, boardID, threadID)
94 if !found {
95 return nil
96 }
97
98 var reposts []Thread
99 t.Reposts.Iterate(start, count, func(rBoardID, rRepostID boards.ID) bool {
100 r, found := getThread(0, cur, uint64(rBoardID), uint64(rRepostID))
101 if found {
102 reposts = append(reposts, NewSafeThread(r))
103 }
104 return false
105 })
106 return reposts
107}
108
109// GetFlag returns a list with thread or comment moderation flags.
110// To reverse iterate use a negative count.
111// Thread flags are returned when `commentID` is zero, or comment flags are returned otherwise.
112func GetFlags(cur realm, boardID, threadID, commentID uint64, start, count int) []boards.Flag {
113 var storage boards.FlagStorage
114 if commentID == 0 {
115 t, found := getThread(0, cur, boardID, threadID)
116 if !found {
117 return nil
118 }
119
120 storage = t.Flags
121 } else {
122 c, found := getComment(0, cur, boardID, threadID, commentID)
123 if !found {
124 return nil
125 }
126
127 storage = c.Flags
128 }
129
130 var flags []boards.Flag
131 storage.Iterate(start, count, func(f boards.Flag) bool {
132 flags = append(flags, f)
133 return false
134 })
135 return flags
136}
137
138// GetComments returns a list with all thread comments and replies.
139// To reverse iterate use a negative count.
140// Top level comments can be filtered by checking `Comment.ParentID`, replies
141// always have a parent comment or reply, while comments have no parent.
142func GetComments(cur realm, boardID, threadID uint64, start, count int) []Comment {
143 t, found := getThread(0, cur, boardID, threadID)
144 if !found {
145 return nil
146 }
147
148 var comments []Comment
149 t.Replies.Iterate(start, count, func(comment *boards.Post) bool {
150 comments = append(comments, NewSafeComment(comment))
151 return false
152 })
153 return comments
154}
155
156// GetReplies returns a list with top level comment replies.
157// To reverse iterate use a negative count.
158func GetReplies(cur realm, boardID, threadID, commentID uint64, start, count int) []Comment {
159 c, found := getComment(0, cur, boardID, threadID, commentID)
160 if !found {
161 return nil
162 }
163
164 var replies []Comment
165 c.Replies.Iterate(start, count, func(comment *boards.Post) bool {
166 replies = append(replies, NewSafeComment(comment))
167 return false
168 })
169 return replies
170}
171
172// getBoard fetches a raw *boards.Board via boards2's protected
173// GetBoard. Non-crossing helper: rlm is hub's own cur, threaded
174// through from the enclosing crossing function.
175func getBoard(_ int, rlm realm, boardID uint64) (*boards.Board, bool) {
176 return boards2.GetBoard(cross(rlm), boards.ID(boardID))
177}
178
179func getThread(_ int, rlm realm, boardID, threadID uint64) (*boards.Post, bool) {
180 b, found := getBoard(0, rlm, boardID)
181 if !found {
182 return nil, false
183 }
184
185 t, found := b.Threads.Get(boards.ID(threadID))
186 if !found {
187 // When thread is not found search it within hidden threads
188 meta := b.Meta.(*boards2.BoardMeta)
189 t, found = meta.HiddenThreads.Get(boards.ID(threadID))
190 }
191 return t, found
192}
193
194func getComment(_ int, rlm realm, boardID, threadID, commentID uint64) (*boards.Post, bool) {
195 t, found := getThread(0, rlm, boardID, threadID)
196 if !found {
197 return nil, false
198 }
199
200 return t.Replies.Get(boards.ID(commentID))
201}