~ knotless Search/
↑↓ move↵ open⇧↵ all results

grain.social/grain

photography-focused photo sharing platform

grain.social
1 collaborator
0
2
46 lines · 1.8 KB Raw History
import { defineQuery, views } from "$hatk";
import type { Gallery } from "$hatk";
import { hydrateGalleries } from "../hydrate/galleries.ts";

/**
 * The review queue: submissions the group has neither accepted nor declined.
 *
 * Anyone's, not only members': who is a member is not a public fact grain can
 * check. Whoever acts as the group decides; declining a stranger is one click.
 */
export default defineQuery("social.grain.unspecced.getGroupSubmissions", async (ctx) => {
  const { params, ok, db } = ctx;
  const limit = params.limit ?? 30;
  const rows = (await db.query(
    `SELECT s.uri, s.cid, s.gallery, s.created_at FROM "social.grain.group.submission" s
     LEFT JOIN _repos r ON r.did = s.did
     WHERE s."group" = $1
       AND (r.status IS NULL OR r.status NOT IN ('takendown', 'deactivated', 'deleted'))
       AND NOT EXISTS (SELECT 1 FROM "social.grain.group.item" i WHERE i.did = s."group" AND i.gallery = s.gallery)
       AND NOT EXISTS (SELECT 1 FROM "social.grain.group.decline" d WHERE d.did = s."group" AND d.submission = s.uri)
     ORDER BY s.created_at DESC
     LIMIT $2`,
    [params.group, limit],
  )) as { uri: string; cid: string; gallery: string; created_at: string }[];

  const galleries = await ctx.getRecords<Gallery>("social.grain.gallery", [
    ...new Set(rows.map((r) => r.gallery)),
  ]);
  const galleryViews = await hydrateGalleries(ctx, [...galleries.values()]);
  const viewByUri = new Map(galleryViews.map((g) => [g.uri, g]));

  const submissions = rows.flatMap((r) => {
    const gallery = viewByUri.get(r.gallery);
    if (!gallery) return []; // the gallery was deleted; nothing to review
    return [
      views.submissionView({
        uri: r.uri,
        cid: r.cid,
        group: params.group,
        gallery,
        createdAt: r.created_at,
      }),
    ];
  });
  return ok({ submissions });
});