158 lines · 6.1 KB
import { all, first } from "./db";
import { allSites } from "./sites/store";
import { siteDirectoryReady, siteDirectoryStats, type SiteStats } from "./sites/directory";

const DAY_MS = 24 * 60 * 60 * 1000;

type Count = { count: number };

async function count(sql: string, ...params: (string | number)[]): Promise<number> {
  return (await first<Count>(sql, ...params))?.count ?? 0;
}

export type AdminOrgRow = { id: string; name: string; members: number; repos: number; sites: number; reports: number };
export type AdminUserRow = {
  id: string;
  name: string;
  email: string;
  verified: boolean;
  isAdmin: boolean;
  repos: number;
  reports: number;
  createdAt: number;
};

/** Until the directory is backfilled: every site row, read from its scope. */
async function scannedSiteStats(now: number, week: number): Promise<SiteStats> {
  const allSiteRows = await allSites();
  const siteCount = (keep: (site: (typeof allSiteRows)[number]) => boolean) => allSiteRows.filter(keep).length;
  const siteOwner = new Map(allSiteRows.map((site) => [site.id, site.owner_id]));
  const sitesByOwner = new Map<string, number>();
  for (const site of allSiteRows) {
    if (site.owner_id) sitesByOwner.set(site.owner_id, (sitesByOwner.get(site.owner_id) ?? 0) + 1);
  }
  const openSiteReports = await all<{ site_id: string }>(
    "SELECT site_id FROM abuse_reports WHERE status = 'open' AND site_id IS NOT NULL",
  );
  const reportsByOwner = new Map<string, number>();
  for (const report of openSiteReports) {
    const owner = siteOwner.get(report.site_id);
    if (owner) reportsByOwner.set(owner, (reportsByOwner.get(owner) ?? 0) + 1);