feat(rubgram): change archive strategy to monthly incremental
This commit is contained in:
@@ -43,9 +43,11 @@ import { setFree, setLimit, toggleCheck, toggleLock } from "../api";
|
|||||||
export function SidebarLink({
|
export function SidebarLink({
|
||||||
submission,
|
submission,
|
||||||
className,
|
className,
|
||||||
|
prefetch = true,
|
||||||
}: {
|
}: {
|
||||||
submission: { id: string; name: string; checked: boolean; queue: number };
|
submission: { id: string; name: string; checked: boolean; queue: number };
|
||||||
className?: string;
|
className?: string;
|
||||||
|
prefetch?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const { stop } = useProgress();
|
const { stop } = useProgress();
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
@@ -62,7 +64,7 @@ export function SidebarLink({
|
|||||||
className,
|
className,
|
||||||
id === submission.id && "bg-accent text-accent-foreground",
|
id === submission.id && "bg-accent text-accent-foreground",
|
||||||
)}
|
)}
|
||||||
prefetch
|
prefetch={prefetch}
|
||||||
onClick={(ev) => {
|
onClick={(ev) => {
|
||||||
if ((ev.target as HTMLButtonElement).type === "button") {
|
if ((ev.target as HTMLButtonElement).type === "button") {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
@@ -250,10 +252,17 @@ export function SubmissionList({
|
|||||||
checked: boolean;
|
checked: boolean;
|
||||||
queue: number;
|
queue: number;
|
||||||
paid: boolean;
|
paid: boolean;
|
||||||
|
archived: boolean;
|
||||||
}[];
|
}[];
|
||||||
}) {
|
}) {
|
||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
const [debug] = shared.state("debug");
|
const [debug] = shared.state("debug");
|
||||||
|
const bottomRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Scrolls to the dummy div whenever 'items' changes
|
||||||
|
bottomRef.current?.scrollIntoView({ behavior: "smooth" });
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -272,11 +281,12 @@ export function SubmissionList({
|
|||||||
<SidebarMenuButton
|
<SidebarMenuButton
|
||||||
key={s.id}
|
key={s.id}
|
||||||
asChild
|
asChild
|
||||||
className={cn(debug && !s.paid && "opacity-50")}
|
className={cn(((debug && !s.paid) || s.archived) && "opacity-50")}
|
||||||
>
|
>
|
||||||
<SidebarLink submission={s} />
|
<SidebarLink submission={s} prefetch={!s.archived} />
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
))}
|
))}
|
||||||
|
<div ref={bottomRef} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import { db } from "@/lib/db";
|
|||||||
import { endgameSubmissions } from "@/lib/db/schema";
|
import { endgameSubmissions } from "@/lib/db/schema";
|
||||||
import { getEndgameConfig, random, wipe } from "../api";
|
import { getEndgameConfig, random, wipe } from "../api";
|
||||||
import { LimitManager, SlipButton, SubmissionList, Watcher } from "./client";
|
import { LimitManager, SlipButton, SubmissionList, Watcher } from "./client";
|
||||||
|
import { desc } from "drizzle-orm";
|
||||||
|
|
||||||
export default async function AdminLayout({
|
export default async function AdminLayout({
|
||||||
children,
|
children,
|
||||||
@@ -43,9 +44,10 @@ export default async function AdminLayout({
|
|||||||
checked: endgameSubmissions.checked,
|
checked: endgameSubmissions.checked,
|
||||||
queue: endgameSubmissions.queue,
|
queue: endgameSubmissions.queue,
|
||||||
paid: endgameSubmissions.paid,
|
paid: endgameSubmissions.paid,
|
||||||
|
archived: endgameSubmissions.archived,
|
||||||
})
|
})
|
||||||
.from(endgameSubmissions)
|
.from(endgameSubmissions)
|
||||||
.orderBy(endgameSubmissions.id);
|
.orderBy(desc(endgameSubmissions.archived), endgameSubmissions.id);
|
||||||
const config = await getEndgameConfig();
|
const config = await getEndgameConfig();
|
||||||
return (
|
return (
|
||||||
<SidebarProvider>
|
<SidebarProvider>
|
||||||
|
|||||||
+25
-6
@@ -30,17 +30,31 @@ const {
|
|||||||
BASE_URL,
|
BASE_URL,
|
||||||
} = process.env as Record<string, string>;
|
} = process.env as Record<string, string>;
|
||||||
|
|
||||||
export async function wipe() {
|
export async function archive({ onlyChecked = true, copy = true }) {
|
||||||
if (!(await adminCheck())) throw "Unauthorized";
|
if (!(await adminCheck())) throw "Unauthorized";
|
||||||
await db.transaction(async (tx) => {
|
await db.transaction(async (tx) => {
|
||||||
const deleted = await tx.delete(endgameSubmissions).returning();
|
const deleted = await (copy
|
||||||
await tx.execute(
|
? tx
|
||||||
sql`ALTER SEQUENCE endgame.submissions_queue_seq RESTART WITH 1`,
|
.update(endgameSubmissions)
|
||||||
|
.set({
|
||||||
|
archived: true,
|
||||||
|
})
|
||||||
|
.returning()
|
||||||
|
: tx.delete(endgameSubmissions).returning()
|
||||||
|
).where(
|
||||||
|
and(
|
||||||
|
onlyChecked ? eq(endgameSubmissions.checked, true) : undefined,
|
||||||
|
not(endgameSubmissions.archived),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
const [{ maxRound }] = await db
|
if (!onlyChecked && !copy)
|
||||||
|
await tx.execute(
|
||||||
|
sql`ALTER SEQUENCE endgame.submissions_queue_seq RESTART WITH 1`,
|
||||||
|
);
|
||||||
|
const [{ maxRound }] = await tx
|
||||||
.select({ maxRound: sql<number>`MAX(${endgameArchive.round})` })
|
.select({ maxRound: sql<number>`MAX(${endgameArchive.round})` })
|
||||||
.from(endgameArchive);
|
.from(endgameArchive);
|
||||||
await db.insert(endgameArchive).values(
|
await tx.insert(endgameArchive).values(
|
||||||
deleted
|
deleted
|
||||||
.filter((e) => e.paid)
|
.filter((e) => e.paid)
|
||||||
.map((s) => ({
|
.map((s) => ({
|
||||||
@@ -49,6 +63,11 @@ export async function wipe() {
|
|||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function wipe() {
|
||||||
|
if (!(await adminCheck())) throw "Unauthorized";
|
||||||
|
await archive({ onlyChecked: false });
|
||||||
revalidatePath("/rubgram/admin");
|
revalidatePath("/rubgram/admin");
|
||||||
revalidatePath("/rubgram");
|
revalidatePath("/rubgram");
|
||||||
|
|
||||||
|
|||||||
+25
-3
@@ -1,9 +1,9 @@
|
|||||||
import { env } from "node:process";
|
import { env } from "node:process";
|
||||||
import { redis } from "bun";
|
import { cron, redis } from "bun";
|
||||||
import { formatDistanceToNow } from "date-fns";
|
import { formatDistanceToNow } from "date-fns";
|
||||||
import { and, asc, eq, gt, isNull, lt, not, sql } from "drizzle-orm";
|
import { and, asc, eq, gt, isNull, lt, not, sql } from "drizzle-orm";
|
||||||
import { removeExpiredSubmissions } from "@/app/(ui)/rubgram/api";
|
import { archive, removeExpiredSubmissions } from "@/app/(ui)/rubgram/api";
|
||||||
import { auth } from "@/lib/auth";
|
import { auth, issueInternalToken } from "@/lib/auth";
|
||||||
import { db } from "@/lib/db";
|
import { db } from "@/lib/db";
|
||||||
import {
|
import {
|
||||||
artifactSettings,
|
artifactSettings,
|
||||||
@@ -272,6 +272,28 @@ async function cacheCards() {
|
|||||||
} else schedule(120, cacheCards);
|
} else schedule(120, cacheCards);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cron("0 0 1 * *", async function rubgramArchive() {
|
||||||
|
const { log } = logger("rubgramArchive");
|
||||||
|
log("Started...");
|
||||||
|
await archive({});
|
||||||
|
log("Done");
|
||||||
|
});
|
||||||
|
|
||||||
|
cron("0 0 /14 * *", async function syncAmber() {
|
||||||
|
const { log, error } = logger("syncAmber");
|
||||||
|
log("Syncing...");
|
||||||
|
const token = await issueInternalToken();
|
||||||
|
const res = await fetch(`http://app:3000/api/amber/sync`, {
|
||||||
|
headers: {
|
||||||
|
"X-Internal-Auth": token,
|
||||||
|
},
|
||||||
|
}).catch(() => ({
|
||||||
|
ok: false,
|
||||||
|
}));
|
||||||
|
if (res.ok) log("Success!");
|
||||||
|
else error("Sync failed.");
|
||||||
|
});
|
||||||
|
|
||||||
const redisSubscribers: Record<
|
const redisSubscribers: Record<
|
||||||
string,
|
string,
|
||||||
(payload: { data: unknown; event?: string }) => void
|
(payload: { data: unknown; event?: string }) => void
|
||||||
|
|||||||
@@ -151,6 +151,7 @@ export const endgameSubmissions = endgame.table("submissions", {
|
|||||||
isNotNull(endgameSubmissions.slip),
|
isNotNull(endgameSubmissions.slip),
|
||||||
)!,
|
)!,
|
||||||
),
|
),
|
||||||
|
archived: boolean().notNull().default(false),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const endgameArchive = endgame.table("sarchive", {
|
export const endgameArchive = endgame.table("sarchive", {
|
||||||
|
|||||||
Reference in New Issue
Block a user