@@ -171,4 +171,138 @@ defmodule EpochtalkServer.Models.Post do
171171 from ( p in Post , where: p . id == ^ id )
172172 |> Repo . update_all ( set: [ position: thread_post_count + 1 ] )
173173 end
174+
175+ @ doc """
176+ Paginates `Post` records for a given a `Thread`
177+ """
178+ @ spec page_by_thread_id (
179+ thread_id :: non_neg_integer ,
180+ page :: non_neg_integer | nil ,
181+ opts :: list ( ) | nil
182+ ) :: [ map ( ) ] | [ ]
183+ def page_by_thread_id ( thread_id , page \\ 1 , opts \\ [ ] ) do
184+ per_page = Keyword . get ( opts , :per_page , 25 )
185+ user_id = Keyword . get ( opts , :user_id )
186+ page = if start = Keyword . get ( opts , :start ) , do: ceil ( start / per_page ) , else: page
187+ start = page * per_page - per_page
188+ start = if start < 0 , do: 0 , else: start
189+
190+ inner_query =
191+ Post
192+ |> where ( [ p ] , p . thread_id == ^ thread_id and p . position > ^ start )
193+ |> order_by ( [ p ] , p . position )
194+ |> limit ( ^ per_page )
195+ |> select ( [ p ] , % { id: p . id , position: p . position } )
196+
197+ from ( plist in subquery ( inner_query ) )
198+ |> join (
199+ :left_lateral ,
200+ [ plist ] ,
201+ p1 in fragment (
202+ """
203+ SELECT
204+ p.thread_id, t.board_id, t.slug, b.right_to_left, p.user_id, p.content ->> \' title\' as title,
205+ p.content ->> \' body\' as body, p.metadata, p.deleted, p.locked, p.created_at,
206+ p.updated_at, p.imported_at, CASE WHEN EXISTS (
207+ SELECT rp.id
208+ FROM administration.reports_posts rp
209+ WHERE rp.offender_post_id = p.id AND rp.reporter_user_id = ?
210+ )
211+ THEN \' TRUE\' ::boolean ELSE \' FALSE\' ::boolean END AS reported,
212+ CASE WHEN EXISTS (
213+ SELECT ru.id
214+ FROM administration.reports_users ru
215+ WHERE ru.offender_user_id = p.user_id AND ru.reporter_user_id = ? AND ru.status = \' Pending\'
216+ )
217+ THEN \' TRUE\' ::boolean ELSE \' FALSE\' ::boolean END AS reported_author,
218+ CASE WHEN p.user_id = (
219+ SELECT user_id
220+ FROM posts
221+ WHERE thread_id = t.id ORDER BY created_at limit 1
222+ )
223+ THEN \' TRUE\' ::boolean ELSE \' FALSE\' ::boolean END AS original_poster,
224+ u.username, u.deleted as user_deleted, up.signature, up.post_count, up.avatar,
225+ up.fields->\' name\' as name
226+ FROM posts p
227+ LEFT JOIN users u ON p.user_id = u.id
228+ LEFT JOIN users.profiles up ON u.id = up.user_id
229+ LEFT JOIN threads t ON p.thread_id = t.id
230+ LEFT JOIN boards b ON t.board_id = b.id
231+ WHERE p.id = ?
232+ """ ,
233+ ^ user_id ,
234+ ^ user_id ,
235+ plist . id
236+ ) ,
237+ on: true
238+ )
239+ |> join (
240+ :left_lateral ,
241+ [ plist , p1 ] ,
242+ p2 in fragment (
243+ """
244+ SELECT r.priority, r.highlight_color, r.name as role_name
245+ FROM roles_users ru
246+ LEFT JOIN roles r ON ru.role_id = r.id
247+ WHERE ? = ru.user_id
248+ ORDER BY r.priority limit 1
249+ """ ,
250+ p1 . user_id
251+ ) ,
252+ on: true
253+ )
254+ |> join (
255+ :left_lateral ,
256+ [ ] ,
257+ p3 in fragment ( """
258+ SELECT priority FROM roles WHERE lookup =\' user\'
259+ """ ) ,
260+ on: true
261+ )
262+ |> select ( [ plist , p1 , p2 , p3 ] , % {
263+ id: plist . id ,
264+ position: plist . position ,
265+ thread_id: p1 . thread_id ,
266+ board_id: p1 . board_id ,
267+ slug: p1 . slug ,
268+ user_id: p1 . user_id ,
269+ title: p1 . title ,
270+ body: p1 . body ,
271+ deleted: p1 . deleted ,
272+ locked: p1 . locked ,
273+ right_to_left: p1 . right_to_left ,
274+ metadata: p1 . metadata ,
275+ created_at: p1 . created_at ,
276+ updated_at: p1 . updated_at ,
277+ imported_at: p1 . updated_at ,
278+ username: p1 . username ,
279+ reported: p1 . reported ,
280+ reported_author: p1 . reported_author ,
281+ original_poster: p1 . original_poster ,
282+ user_deleted: p1 . user_deleted ,
283+ signature: p1 . signature ,
284+ avatar: p1 . avatar ,
285+ post_count: p1 . post_count ,
286+ name: p1 . name ,
287+ priority: p2 . priority ,
288+ highlight_color: p2 . highlight_color ,
289+ role_name: p2 . role_name ,
290+ default_priority: p3 . priority
291+ } )
292+ |> order_by ( [ plist ] , plist . position )
293+ |> Repo . all ( )
294+ end
295+
296+ @ doc """
297+ Used to find a specific `Post` by it's `id`
298+ """
299+ @ spec find_by_id ( id :: non_neg_integer ) :: t ( )
300+ def find_by_id ( id ) when is_integer ( id ) do
301+ query =
302+ from p in Post ,
303+ where: p . id == ^ id ,
304+ preload: [ :thread , user: :profile ]
305+
306+ Repo . one ( query )
307+ end
174308end
0 commit comments