refactor(lib): organize modules by feature

This commit is contained in:
2026-08-02 16:56:55 +07:00 Unverified
parent 6c3b1cab83
commit d513b47d09
58 changed files with 85 additions and 85 deletions
+2 -2
View File
@@ -1,7 +1,7 @@
"use server"; "use server";
import { requireAdmin } from "@/lib/auth"; import { requireAdmin } from "@/lib/auth/auth";
import { getGuildRolesInternal, type DiscordRole } from "@/lib/discord"; import { getGuildRolesInternal, type DiscordRole } from "@/lib/discord/discord";
export async function getGuildRoles(): Promise<DiscordRole[]> { export async function getGuildRoles(): Promise<DiscordRole[]> {
await requireAdmin(); await requireAdmin();
+2 -2
View File
@@ -7,9 +7,9 @@ import { cdn, questions } from "@/db/schema";
import type { ImageAnswerMode, QuestionType } from "@/db/schema"; import type { ImageAnswerMode, QuestionType } from "@/db/schema";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { revalidatePath } from "next/cache"; import { revalidatePath } from "next/cache";
import { requireAdmin } from "@/lib/auth"; import { requireAdmin } from "@/lib/auth/auth";
import { sanitizeHtml } from "@/lib/sanitize-html"; import { sanitizeHtml } from "@/lib/sanitize-html";
import { sse } from "@/lib/sse"; import { sse } from "@/lib/realtime/sse";
export async function createQuestion( export async function createQuestion(
formId: string, formId: string,
+7 -7
View File
@@ -5,16 +5,16 @@ import { submissions, answers } from "@/db/schema";
import { and, count, eq, lt, lte, or } from "drizzle-orm"; import { and, count, eq, lt, lte, or } from "drizzle-orm";
import { revalidatePath } from "next/cache"; import { revalidatePath } from "next/cache";
import { getServerSession } from "next-auth"; import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth-options"; import { authOptions } from "@/lib/auth/auth-options";
import { requireAdmin, requireDiscordId, requireFormAccess } from "@/lib/auth"; import { requireAdmin, requireDiscordId, requireFormAccess } from "@/lib/auth/auth";
import { sse } from "@/lib/sse"; import { sse } from "@/lib/realtime/sse";
import type { FormAnswerPayload } from "@/lib/form-answer-values"; import type { FormAnswerPayload } from "@/lib/form/form-answer-values";
import { import {
normalizeSubmissionAnswers, normalizeSubmissionAnswers,
type StoredAnswerSnapshot, type StoredAnswerSnapshot,
} from "@/lib/submission-intake"; } from "@/lib/form/submission-intake";
import { submissionWebhookMessage } from "@/lib/submission-webhook"; import { submissionWebhookMessage } from "@/lib/form/submission-webhook";
import { isFormAcceptingSubmissions } from "@/lib/form-availability"; import { isFormAcceptingSubmissions } from "@/lib/form/form-availability";
function getSubmissionResultLink(formId: string, submissionId: string) { function getSubmissionResultLink(formId: string, submissionId: string) {
const baseUrl = process.env.BASE_URL || process.env.NEXTAUTH_URL; const baseUrl = process.env.BASE_URL || process.env.NEXTAUTH_URL;
+1 -1
View File
@@ -72,7 +72,7 @@ import {
getQuestionResponseSettings, getQuestionResponseSettings,
getQuestionResponseType, getQuestionResponseType,
type QuestionResponseType, type QuestionResponseType,
} from "@/lib/question-response-type"; } from "@/lib/form/question-response-type";
import { import {
SaveStatusIndicator, SaveStatusIndicator,
SortableQuestion, SortableQuestion,
+2 -2
View File
@@ -11,7 +11,7 @@ import { toast } from "sonner";
import { testDiscordWebhook, updateForm } from "@/app/admin/form/actions"; import { testDiscordWebhook, updateForm } from "@/app/admin/form/actions";
import { Loader2, ChevronDown, Check, AlertCircle, Send } from "lucide-react"; import { Loader2, ChevronDown, Check, AlertCircle, Send } from "lucide-react";
import { getGuildRoles } from "@/app/actions/discord"; import { getGuildRoles } from "@/app/actions/discord";
import type { DiscordRole } from "@/lib/discord"; import type { DiscordRole } from "@/lib/discord/discord";
import { import {
DropdownMenu, DropdownMenu,
DropdownMenuCheckboxItem, DropdownMenuCheckboxItem,
@@ -23,7 +23,7 @@ import { getErrorMessage } from "@/lib/utils";
import { import {
isValidDiscordWebhookUrl, isValidDiscordWebhookUrl,
previewWebhookTemplate, previewWebhookTemplate,
} from "@/lib/discord-webhook-settings"; } from "@/lib/discord/discord-webhook-settings";
import { import {
useDebouncedAutoSave, useDebouncedAutoSave,
type AutoSaveStatus, type AutoSaveStatus,
+4 -4
View File
@@ -2,14 +2,14 @@ import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar";
import { FormAdminSidebar } from "@/components/form-admin-sidebar"; import { FormAdminSidebar } from "@/components/form-admin-sidebar";
import { Metadata } from "next"; import { Metadata } from "next";
import { getServerSession } from "next-auth"; import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth-options"; import { authOptions } from "@/lib/auth/auth-options";
import { getSessionDiscordId } from "@/lib/auth"; import { getSessionDiscordId } from "@/lib/auth/auth";
import { getDiscordMemberProfile } from "@/lib/discord"; import { getDiscordMemberProfile } from "@/lib/discord/discord";
import { db } from "@/db"; import { db } from "@/db";
import { submissions } from "@/db/schema"; import { submissions } from "@/db/schema";
import { asc, eq } from "drizzle-orm"; import { asc, eq } from "drizzle-orm";
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
import { isFormAcceptingSubmissions } from "@/lib/form-availability"; import { isFormAcceptingSubmissions } from "@/lib/form/form-availability";
export const metadata: Metadata = { export const metadata: Metadata = {
title: { title: {
@@ -42,8 +42,8 @@ import {
import Image from 'next/image'; import Image from 'next/image';
import { stripHtml } from "@/lib/utils"; import { stripHtml } from "@/lib/utils";
import { HtmlDisplay } from "@/components/html-display"; import { HtmlDisplay } from "@/components/html-display";
import { formatStoredAnswer } from "@/lib/form-answer-values"; import { formatStoredAnswer } from "@/lib/form/form-answer-values";
import { normalizeStoredAnswerSnapshot } from "@/lib/submission-intake"; import { normalizeStoredAnswerSnapshot } from "@/lib/form/submission-intake";
import { updateSubmissionAdminNote } from "@/app/admin/form/actions"; import { updateSubmissionAdminNote } from "@/app/admin/form/actions";
import { import {
useDebouncedAutoSave, useDebouncedAutoSave,
@@ -6,7 +6,7 @@ import { ArrowLeft, ArrowRight } from "lucide-react";
import SubmissionDetailClient from "./client"; import SubmissionDetailClient from "./client";
import { DeleteSubmissionButton } from "@/components/delete-buttons"; import { DeleteSubmissionButton } from "@/components/delete-buttons";
import { RealtimeRefresh } from "@/components/realtime-refresh"; import { RealtimeRefresh } from "@/components/realtime-refresh";
import { getDiscordMemberProfile } from "@/lib/discord"; import { getDiscordMemberProfile } from "@/lib/discord/discord";
interface SubmissionDetailPageProps { interface SubmissionDetailPageProps {
params: Promise<{ params: Promise<{
+1 -1
View File
@@ -8,7 +8,7 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@
import { Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious } from "@/components/ui/pagination"; import { Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious } from "@/components/ui/pagination";
import { DeleteAllSubmissionsButton, DeleteSubmissionButton } from "@/components/delete-buttons"; import { DeleteAllSubmissionsButton, DeleteSubmissionButton } from "@/components/delete-buttons";
import { ResultsFilters } from "@/components/results-filters"; import { ResultsFilters } from "@/components/results-filters";
import type { DiscordMemberProfile } from "@/lib/discord"; import type { DiscordMemberProfile } from "@/lib/discord/discord";
const RESULTS_PAGE_SIZE = 25; const RESULTS_PAGE_SIZE = 25;
type ResultFilters = { type ResultFilters = {
+3 -3
View File
@@ -2,12 +2,12 @@ import { NextResponse } from "next/server";
import { db } from "@/db"; import { db } from "@/db";
import { answers } from "@/db/schema"; import { answers } from "@/db/schema";
import { inArray } from "drizzle-orm"; import { inArray } from "drizzle-orm";
import { requireAdmin } from "@/lib/auth"; import { requireAdmin } from "@/lib/auth/auth";
import { import {
getFilteredSubmissions, getFilteredSubmissions,
parseResultFilters, parseResultFilters,
} from "@/lib/admin-form-results"; } from "@/lib/form/admin-form-results";
import { answerCellValue } from "@/lib/form-answer-values"; import { answerCellValue } from "@/lib/form/form-answer-values";
import { stripHtml } from "@/lib/utils"; import { stripHtml } from "@/lib/utils";
function csvCell(value: unknown) { function csvCell(value: unknown) {
+2 -2
View File
@@ -1,5 +1,5 @@
import { parseResultFilters, getFilteredSubmissions } from "@/lib/admin-form-results"; import { parseResultFilters, getFilteredSubmissions } from "@/lib/form/admin-form-results";
import { getDiscordMemberProfile } from "@/lib/discord"; import { getDiscordMemberProfile } from "@/lib/discord/discord";
import { RealtimeRefresh } from "@/components/realtime-refresh"; import { RealtimeRefresh } from "@/components/realtime-refresh";
import ResultsClient from "./client"; import ResultsClient from "./client";
+3 -3
View File
@@ -5,10 +5,10 @@ import { forms, submissions } from "@/db/schema";
import { and, eq } from "drizzle-orm"; import { and, eq } from "drizzle-orm";
import { revalidatePath } from "next/cache"; import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
import { requireAdmin } from "@/lib/auth"; import { requireAdmin } from "@/lib/auth/auth";
import { sanitizeHtml } from "@/lib/sanitize-html"; import { sanitizeHtml } from "@/lib/sanitize-html";
import { sse } from "@/lib/sse"; import { sse } from "@/lib/realtime/sse";
import { isValidDiscordWebhookUrl } from "@/lib/discord-webhook-settings"; import { isValidDiscordWebhookUrl } from "@/lib/discord/discord-webhook-settings";
export async function createForm(formData: FormData) { export async function createForm(formData: FormData) {
await requireAdmin(); await requireAdmin();
+2 -2
View File
@@ -15,9 +15,9 @@ import { DeleteFormButton } from "@/components/delete-buttons";
import { AdminShellServer } from "@/components/admin-shell-server"; import { AdminShellServer } from "@/components/admin-shell-server";
import { createDefaultForm } from "./actions"; import { createDefaultForm } from "./actions";
import { RealtimeRefresh } from "@/components/realtime-refresh"; import { RealtimeRefresh } from "@/components/realtime-refresh";
import { getFormSubmissionStats } from "@/lib/form-submission-stats"; import { getFormSubmissionStats } from "@/lib/form/form-submission-stats";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { isFormAcceptingSubmissions } from "@/lib/form-availability"; import { isFormAcceptingSubmissions } from "@/lib/form/form-availability";
export const dynamic = "force-dynamic"; export const dynamic = "force-dynamic";
+2 -2
View File
@@ -1,7 +1,7 @@
import { getServerSession } from "next-auth"; import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth-options"; import { authOptions } from "@/lib/auth/auth-options";
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
import { getAdminDiscordIds, getSessionDiscordId } from "@/lib/auth"; import { getAdminDiscordIds, getSessionDiscordId } from "@/lib/auth/auth";
export default async function AdminLayout({ export default async function AdminLayout({
children, children,
+1 -1
View File
@@ -18,7 +18,7 @@ import {
TableHeader, TableHeader,
TableRow, TableRow,
} from "@/components/ui/table"; } from "@/components/ui/table";
import { getAdminDashboardData } from "@/lib/admin-dashboard"; import { getAdminDashboardData } from "@/lib/admin/admin-dashboard";
import { import {
ClipboardList, ClipboardList,
FilePlus2, FilePlus2,
+1 -1
View File
@@ -4,7 +4,7 @@ import { Readable } from "node:stream";
import { pipeline } from "node:stream/promises"; import { pipeline } from "node:stream/promises";
import { randomUUID } from "node:crypto"; import { randomUUID } from "node:crypto";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { requireAdmin } from "@/lib/auth"; import { requireAdmin } from "@/lib/auth/auth";
export const dynamic = "force-dynamic"; export const dynamic = "force-dynamic";
+2 -2
View File
@@ -1,6 +1,6 @@
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { requireAdmin } from "@/lib/auth"; import { requireAdmin } from "@/lib/auth/auth";
import { saveVideoUpload } from "@/lib/video-upload-storage"; import { saveVideoUpload } from "@/lib/video/video-upload-storage";
export const dynamic = "force-dynamic"; export const dynamic = "force-dynamic";
+1 -1
View File
@@ -1,5 +1,5 @@
import NextAuth from "next-auth"; import NextAuth from "next-auth";
import { authOptions } from "@/lib/auth-options"; import { authOptions } from "@/lib/auth/auth-options";
const handler = NextAuth(authOptions); const handler = NextAuth(authOptions);
export { handler as GET, handler as POST }; export { handler as GET, handler as POST };
+1 -1
View File
@@ -1,6 +1,6 @@
import { NextRequest, NextResponse } from "next/server"; import { NextRequest, NextResponse } from "next/server";
import { cookies } from "next/headers"; import { cookies } from "next/headers";
import { requireAdmin } from "@/lib/auth"; import { requireAdmin } from "@/lib/auth/auth";
const TIKTOK_OAUTH_STATE_COOKIE = "tiktok-oauth-state"; const TIKTOK_OAUTH_STATE_COOKIE = "tiktok-oauth-state";
+1 -1
View File
@@ -1,7 +1,7 @@
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { randomBytes } from "node:crypto"; import { randomBytes } from "node:crypto";
import { cookies } from "next/headers"; import { cookies } from "next/headers";
import { requireAdmin } from "@/lib/auth"; import { requireAdmin } from "@/lib/auth/auth";
const TIKTOK_OAUTH_STATE_COOKIE = "tiktok-oauth-state"; const TIKTOK_OAUTH_STATE_COOKIE = "tiktok-oauth-state";
+1 -1
View File
@@ -1,6 +1,6 @@
import { cookies } from "next/headers"; import { cookies } from "next/headers";
import { NextRequest, NextResponse } from "next/server"; import { NextRequest, NextResponse } from "next/server";
import { requireAdmin } from "@/lib/auth"; import { requireAdmin } from "@/lib/auth/auth";
function escapeHtml(value: unknown) { function escapeHtml(value: unknown) {
return String(value ?? "") return String(value ?? "")
+1 -1
View File
@@ -1,7 +1,7 @@
import { randomBytes } from "node:crypto"; import { randomBytes } from "node:crypto";
import { cookies } from "next/headers"; import { cookies } from "next/headers";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { requireAdmin } from "@/lib/auth"; import { requireAdmin } from "@/lib/auth/auth";
const COOKIE = "youtube-oauth-state"; const COOKIE = "youtube-oauth-state";
+1 -1
View File
@@ -1,5 +1,5 @@
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { processDueVideoUploads } from "@/lib/video-platforms"; import { processDueVideoUploads } from "@/lib/video/video-platforms";
export const dynamic = "force-dynamic"; export const dynamic = "force-dynamic";
+2 -2
View File
@@ -1,8 +1,8 @@
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { db } from "@/db"; import { db } from "@/db";
import { cdn } from "@/db/schema"; import { cdn } from "@/db/schema";
import { requireDiscordId } from "@/lib/auth"; import { requireDiscordId } from "@/lib/auth/auth";
import { validateImageUploadFile, cdnUrl } from "@/lib/cdn-images"; import { validateImageUploadFile, cdnUrl } from "@/lib/cdn/cdn-images";
export async function POST(req: Request) { export async function POST(req: Request) {
let discordId: string; let discordId: string;
+1 -1
View File
@@ -1,5 +1,5 @@
import { db } from "@/db"; import { db } from "@/db";
import { cdnImageResponse } from "@/lib/cdn-images"; import { cdnImageResponse } from "@/lib/cdn/cdn-images";
export async function GET( export async function GET(
_request: Request, _request: Request,
+5 -5
View File
@@ -1,17 +1,17 @@
import { db } from "@/db"; import { db } from "@/db";
import { FormFillerClient } from "../client"; import { FormFillerClient } from "../client";
import { getServerSession } from "next-auth"; import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth-options"; import { authOptions } from "@/lib/auth/auth-options";
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
import LoginDialog from "@/components/login-dialog"; import LoginDialog from "@/components/login-dialog";
import { canAccessForm, getSessionDiscordId } from "@/lib/auth"; import { canAccessForm, getSessionDiscordId } from "@/lib/auth/auth";
import { RealtimeRefresh } from "@/components/realtime-refresh"; import { RealtimeRefresh } from "@/components/realtime-refresh";
import { import {
decodeCheckboxAnswer, decodeCheckboxAnswer,
type FormAnswerValue, type FormAnswerValue,
} from "@/lib/form-answer-values"; } from "@/lib/form/form-answer-values";
import { getFormSubmissionStats } from "@/lib/form-submission-stats"; import { getFormSubmissionStats } from "@/lib/form/form-submission-stats";
import { isFormAcceptingSubmissions } from "@/lib/form-availability"; import { isFormAcceptingSubmissions } from "@/lib/form/form-availability";
export const dynamic = "force-dynamic"; export const dynamic = "force-dynamic";
+3 -3
View File
@@ -55,8 +55,8 @@ import {
import { Spinner } from "@/components/ui/spinner"; import { Spinner } from "@/components/ui/spinner";
import { import {
type FormAnswerValue, type FormAnswerValue,
} from "@/lib/form-answer-values"; } from "@/lib/form/form-answer-values";
import { isImageOnlyResponse } from "@/lib/question-response-type"; import { isImageOnlyResponse } from "@/lib/form/question-response-type";
import { import {
buildFormSchema, buildFormSchema,
parseStoredDraft, parseStoredDraft,
@@ -64,7 +64,7 @@ import {
type FormFillerClientProps, type FormFillerClientProps,
type FormValues, type FormValues,
type StoredDraft, type StoredDraft,
} from "@/lib/form-client"; } from "@/lib/form/form-client";
export function FormLayoutClient({ export function FormLayoutClient({
userName, userName,
+4 -4
View File
@@ -1,12 +1,12 @@
import { getServerSession } from "next-auth"; import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth-options"; import { authOptions } from "@/lib/auth/auth-options";
import { FormLayoutClient, LoginButton } from "./client"; import { FormLayoutClient, LoginButton } from "./client";
import { Metadata } from "next"; import { Metadata } from "next";
import { ThemeToggle } from "@/components/theme-toggle"; import { ThemeToggle } from "@/components/theme-toggle";
import { getSessionDiscordId } from "@/lib/auth"; import { getSessionDiscordId } from "@/lib/auth/auth";
import { getDiscordMemberProfile } from "@/lib/discord"; import { getDiscordMemberProfile } from "@/lib/discord/discord";
import Link from 'next/link'; import Link from 'next/link';
import { getAdminDiscordIds } from "@/lib/auth"; import { getAdminDiscordIds } from "@/lib/auth/auth";
const siteUrl = process.env.BASE_URL; const siteUrl = process.env.BASE_URL;
+3 -3
View File
@@ -7,11 +7,11 @@ import {
} from "@/components/ui/card"; } from "@/components/ui/card";
import { HtmlDisplay } from "@/components/html-display"; import { HtmlDisplay } from "@/components/html-display";
import { getServerSession } from "next-auth"; import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth-options"; import { authOptions } from "@/lib/auth/auth-options";
import { canAccessForm, getSessionDiscordId } from "@/lib/auth"; import { canAccessForm, getSessionDiscordId } from "@/lib/auth/auth";
import { RealtimeRefresh } from "@/components/realtime-refresh"; import { RealtimeRefresh } from "@/components/realtime-refresh";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { getFormSubmissionStats } from "@/lib/form-submission-stats"; import { getFormSubmissionStats } from "@/lib/form/form-submission-stats";
export const dynamic = "force-dynamic"; export const dynamic = "force-dynamic";
+3 -3
View File
@@ -1,10 +1,10 @@
import { getServerSession } from "next-auth"; import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth-options"; import { authOptions } from "@/lib/auth/auth-options";
import { import {
getAdminDiscordIds, getAdminDiscordIds,
getSessionDiscordId, getSessionDiscordId,
} from "@/lib/auth"; } from "@/lib/auth/auth";
import { isSseTopic, sse } from "@/lib/sse"; import { isSseTopic, sse } from "@/lib/realtime/sse";
export async function GET( export async function GET(
request: Request, request: Request,
+3 -3
View File
@@ -1,7 +1,7 @@
import { getServerSession } from "next-auth"; import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth-options"; import { authOptions } from "@/lib/auth/auth-options";
import { getSessionDiscordId } from "@/lib/auth"; import { getSessionDiscordId } from "@/lib/auth/auth";
import { getDiscordMemberProfile } from "@/lib/discord"; import { getDiscordMemberProfile } from "@/lib/discord/discord";
import { AdminShell } from "@/components/admin-shell"; import { AdminShell } from "@/components/admin-shell";
export async function AdminShellServer({ children }: { children: React.ReactNode }) { export async function AdminShellServer({ children }: { children: React.ReactNode }) {
+1 -1
View File
@@ -12,7 +12,7 @@ import {
DropdownMenuTrigger, DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"; } from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import type { DiscordRole } from "@/lib/discord"; import type { DiscordRole } from "@/lib/discord/discord";
export interface DiscordMemberProfile { export interface DiscordMemberProfile {
id: string; id: string;
+2 -2
View File
@@ -2,11 +2,11 @@
import { useEffect } from "react"; import { useEffect } from "react";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { sse } from "@/lib/sse"; import { sse } from "@/lib/realtime/sse";
import { import {
startRealtimeRefresh, startRealtimeRefresh,
type RealtimeRefreshHandlers, type RealtimeRefreshHandlers,
} from "@/lib/realtime-refresh"; } from "@/lib/realtime/realtime-refresh";
type FormRealtimeRefreshProps = { type FormRealtimeRefreshProps = {
topic: "forms" | "submissions"; topic: "forms" | "submissions";
+1 -1
View File
@@ -18,7 +18,7 @@ import {
PopoverContent, PopoverContent,
PopoverTrigger, PopoverTrigger,
} from "@/components/ui/popover"; } from "@/components/ui/popover";
import type { ResultFilters } from "@/lib/admin-form-results"; import type { ResultFilters } from "@/lib/form/admin-form-results";
import { Download, X, CalendarDays } from "lucide-react"; import { Download, X, CalendarDays } from "lucide-react";
import { format, parseISO } from "date-fns"; import { format, parseISO } from "date-fns";
@@ -4,8 +4,8 @@ import DiscordProvider from "next-auth/providers/discord";
import { DrizzleAdapter } from "@auth/drizzle-adapter"; import { DrizzleAdapter } from "@auth/drizzle-adapter";
import { db } from "@/db"; import { db } from "@/db";
import { accounts, sessions, users, verificationTokens } from "@/db/schema"; import { accounts, sessions, users, verificationTokens } from "@/db/schema";
import type { SessionWithDiscord } from "@/lib/auth"; import type { SessionWithDiscord } from "@/lib/auth/auth";
import { addDiscordGuildMember } from "@/lib/discord"; import { addDiscordGuildMember } from "@/lib/discord/discord";
const discordIdCache = new Map<string, string>(); const discordIdCache = new Map<string, string>();
+2 -2
View File
@@ -2,8 +2,8 @@ import "server-only";
import { getServerSession } from "next-auth"; import { getServerSession } from "next-auth";
import type { Session } from "next-auth"; import type { Session } from "next-auth";
import { db } from "@/db"; import { db } from "@/db";
import { authOptions } from "@/lib/auth-options"; import { authOptions } from "@/lib/auth/auth-options";
import { getGuildMemberRoles } from "@/lib/discord"; import { getGuildMemberRoles } from "@/lib/discord/discord";
export type SessionWithDiscord = Session & { export type SessionWithDiscord = Session & {
user?: Session["user"] & { user?: Session["user"] & {
@@ -1,5 +1,5 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { isFormAcceptingSubmissions } from "@/lib/form-availability"; import { isFormAcceptingSubmissions } from "@/lib/form/form-availability";
const now = new Date("2026-07-30T12:00:00.000Z"); const now = new Date("2026-07-30T12:00:00.000Z");
@@ -1,6 +1,6 @@
import { z } from "zod"; import { z } from "zod";
import type { FormAnswerValue } from "@/lib/form-answer-values"; import type { FormAnswerValue } from "@/lib/form/form-answer-values";
import { decodeCheckboxAnswer } from "@/lib/form-answer-values"; import { decodeCheckboxAnswer } from "@/lib/form/form-answer-values";
export type Question = { export type Question = {
id: string; id: string;
@@ -3,7 +3,7 @@ import {
getQuestionResponseSettings, getQuestionResponseSettings,
getQuestionResponseType, getQuestionResponseType,
isImageOnlyResponse, isImageOnlyResponse,
} from "@/lib/question-response-type"; } from "@/lib/form/question-response-type";
describe("question response types", () => { describe("question response types", () => {
test("maps stored question settings to the four editor choices", () => { test("maps stored question settings to the four editor choices", () => {
@@ -1,5 +1,5 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { normalizeSubmissionAnswers } from "@/lib/submission-intake"; import { normalizeSubmissionAnswers } from "@/lib/form/submission-intake";
const question = { const question = {
id: "question-1", id: "question-1",
@@ -4,7 +4,7 @@ import {
encodeAnswerValue, encodeAnswerValue,
formatStoredAnswer, formatStoredAnswer,
type FormAnswerValue, type FormAnswerValue,
} from "@/lib/form-answer-values"; } from "@/lib/form/form-answer-values";
import { stripHtml } from "@/lib/utils"; import { stripHtml } from "@/lib/utils";
export type SubmissionQuestion = { export type SubmissionQuestion = {
@@ -4,7 +4,7 @@ import {
type NormalizedSubmissionAnswer, type NormalizedSubmissionAnswer,
type OldAnswersByQuestionId, type OldAnswersByQuestionId,
type SubmissionQuestion, type SubmissionQuestion,
} from "@/lib/submission-intake"; } from "@/lib/form/submission-intake";
const NEW_SUBMISSION_TEMPLATE = "New submission from {username} ({id})."; const NEW_SUBMISSION_TEMPLATE = "New submission from {username} ({id}).";
const UPDATED_SUBMISSION_TEMPLATE = "Submission updated by {username} ({id}).\n{update}"; const UPDATED_SUBMISSION_TEMPLATE = "Submission updated by {username} ({id}).\n{update}";
+1 -1
View File
@@ -1,5 +1,5 @@
import { describe, expect, test } from "bun:test"; import { describe, expect, test } from "bun:test";
import { isSseTopic, sse } from "@/lib/sse"; import { isSseTopic, sse } from "@/lib/realtime/sse";
describe("leaderboard SSE contract", () => { describe("leaderboard SSE contract", () => {
test("registers the public leaderboards topic", () => { test("registers the public leaderboards topic", () => {
View File
@@ -13,7 +13,7 @@ import {
validateThumbnailFile, validateThumbnailFile,
validateVideoFile, validateVideoFile,
publishVideoJob, publishVideoJob,
} from "@/lib/video-platforms"; } from "@/lib/video/video-platforms";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
const VIDEO_DIR = process.env.VIDEO_UPLOAD_DIR || "/nfs/erika"; const VIDEO_DIR = process.env.VIDEO_UPLOAD_DIR || "/nfs/erika";