diff --git a/app/admin/page.tsx b/app/admin/page.tsx new file mode 100644 index 0000000..175c793 --- /dev/null +++ b/app/admin/page.tsx @@ -0,0 +1,419 @@ +"use client"; + +import { useEffect, useState } from "react"; +import Link from "next/link"; + +type User = { + id: string; + name: string; + email: string; + banned: boolean; + createdAt: string; + _count: { games: number }; +}; + +type Game = { + id: string; + mode: string; + startArticle: string; + targetArticle: string; + clicks: number; + timeSeconds: number; + won: boolean; + playedAt: string; + user: { name: string }; +}; + +type ModeStat = { + mode: string; + _count: { id: number }; + _avg: { clicks: number | null; timeSeconds: number | null }; +}; + +type ActivityDay = { date: string; count: number }; + +type AdminStats = { + totalUsers: number; + totalGames: number; + todayGames: number; + recentUsers: User[]; + recentGames: Game[]; + modeStats: ModeStat[]; + activity: ActivityDay[]; +}; + +type DailyPuzzle = { + id: string; + date: string; + startArticle: string; + targetArticle: string; + _count: { results: number }; +}; + +function fmt(s: number) { + const m = Math.floor(s / 60); + const sec = Math.round(s % 60); + return m > 0 ? `${m}m${sec.toString().padStart(2, "0")}s` : `${sec}s`; +} + +function MiniBarChart({ data }: { data: ActivityDay[] }) { + const max = Math.max(...data.map((d) => d.count), 1); + return ( +
+ {data.map((d) => { + const pct = (d.count / max) * 100; + const day = new Date(d.date + "T12:00:00").toLocaleDateString("fr-FR", { day: "numeric", month: "short" }); + return ( +
+
+
+ {day} — {d.count} +
+
+ ); + })} +
+ ); +} + +export default function AdminPage() { + const [data, setData] = useState(null); + const [dailyPuzzles, setDailyPuzzles] = useState(null); + const [loading, setLoading] = useState(true); + const [tab, setTab] = useState<"overview" | "users" | "games" | "daily">("overview"); + + // Daily puzzle form + const [puzzleForm, setPuzzleForm] = useState({ date: "", startArticle: "", targetArticle: "" }); + const [editingPuzzle, setEditingPuzzle] = useState(null); + const [puzzleSaving, setPuzzleSaving] = useState(false); + + // Confirm delete + const [confirmDelete, setConfirmDelete] = useState<{ type: "user" | "puzzle"; id: string; label: string } | null>(null); + + function refreshStats() { + return fetch("/api/admin/stats") + .then((r) => { if (!r.ok) throw new Error(); return r.json(); }) + .then(setData); + } + + function refreshDaily() { + return fetch("/api/admin/daily") + .then((r) => r.json()) + .then(setDailyPuzzles); + } + + useEffect(() => { + Promise.all([refreshStats(), refreshDaily()]) + .catch(() => setData(null)) + .finally(() => setLoading(false)); + }, []); + + async function handleBan(user: User) { + const res = await fetch(`/api/admin/users/${user.id}`, { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ banned: !user.banned }), + }); + if (res.ok) await refreshStats(); + } + + async function handleDeleteUser(id: string) { + await fetch(`/api/admin/users/${id}`, { method: "DELETE" }); + await refreshStats(); + setConfirmDelete(null); + } + + async function handleDeletePuzzle(id: string) { + await fetch(`/api/admin/daily/${id}`, { method: "DELETE" }); + await refreshDaily(); + setConfirmDelete(null); + } + + async function handleSavePuzzle() { + setPuzzleSaving(true); + try { + if (editingPuzzle) { + await fetch(`/api/admin/daily/${editingPuzzle.id}`, { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ startArticle: puzzleForm.startArticle, targetArticle: puzzleForm.targetArticle }), + }); + } else { + await fetch("/api/admin/daily", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(puzzleForm), + }); + } + await refreshDaily(); + setPuzzleForm({ date: "", startArticle: "", targetArticle: "" }); + setEditingPuzzle(null); + } finally { + setPuzzleSaving(false); + } + } + + function startEditPuzzle(p: DailyPuzzle) { + setEditingPuzzle(p); + setPuzzleForm({ date: p.date, startArticle: p.startArticle, targetArticle: p.targetArticle }); + } + + const card = "bg-[#1a1a1a] border border-[#2e2e2e] rounded-xl p-4"; + const tabBtn = (active: boolean) => + `px-3 py-2 rounded-lg text-xs sm:text-sm font-semibold transition-colors cursor-pointer ${ + active ? "bg-[#7c3aed] text-white" : "bg-[#1a1a1a] border border-[#2e2e2e] text-[#888] hover:text-[#f0f0f0]" + }`; + const inputCls = "w-full min-h-10 px-3 bg-[#0f0f0f] border border-[#2e2e2e] rounded-xl text-sm text-[#f0f0f0] outline-none focus:border-[#7c3aed] transition-colors"; + + return ( +
+ {/* Header */} +
+
+

Admin

+

WikiRush — panneau d'administration

+
+ + ← Accueil + +
+ + {loading &&
Chargement...
} + {!loading && !data &&
Accès refusé ou erreur serveur.
} + + {/* Confirm dialog */} + {confirmDelete && ( +
+
+

Confirmer la suppression

+

Supprimer {confirmDelete.label} ? Cette action est irréversible.

+
+ + +
+
+
+ )} + + {data && ( + <> + {/* Tabs */} +
+ + + + +
+ + {/* Overview */} + {tab === "overview" && ( +
+
+ {[ + { label: "Utilisateurs", value: data.totalUsers.toLocaleString("fr-FR") }, + { label: "Parties totales", value: data.totalGames.toLocaleString("fr-FR") }, + { label: "Parties aujourd'hui", value: data.todayGames.toLocaleString("fr-FR") }, + ].map(({ label, value }) => ( +
+

{label}

+

{value}

+
+ ))} +
+ + {/* Graphique activité */} +
+

Activité — 14 derniers jours

+ +
+ {new Date(data.activity[0]?.date + "T12:00:00").toLocaleDateString("fr-FR", { day: "numeric", month: "short" })} + aujourd'hui +
+
+ + {/* Modes */} +
+

Parties par mode

+
+ {data.modeStats.sort((a, b) => b._count.id - a._count.id).map((m) => ( +
+ {m.mode} +
+ {m._count.id.toLocaleString("fr-FR")} parties + {m._avg.clicks !== null && ~{Math.round(m._avg.clicks)} clics} + {m._avg.timeSeconds !== null && ~{fmt(m._avg.timeSeconds)}} +
+
+ ))} +
+
+
+ )} + + {/* Users */} + {tab === "users" && ( +
+

Utilisateurs

+
+ {data.recentUsers.map((u) => ( +
+
+

+ {u.name} + {u.banned && Banni} +

+

{u.email}

+
+
+

{u._count.games} parties

+

{new Date(u.createdAt).toLocaleDateString("fr-FR")}

+
+
+ + +
+
+ ))} +
+
+ )} + + {/* Games */} + {tab === "games" && ( +
+

50 dernières parties

+
+ {data.recentGames.map((g) => ( +
+
+

+ {g.user.name} + + {g.startArticle} → {g.targetArticle} +

+

{new Date(g.playedAt).toLocaleString("fr-FR")}

+
+
+ + {g.won ? "Gagné" : "Perdu"} + + {g.mode} + {g.clicks} clics + {fmt(g.timeSeconds)} +
+
+ ))} +
+
+ )} + + {/* Daily puzzles */} + {tab === "daily" && ( +
+ {/* Formulaire */} +
+

+ {editingPuzzle ? `Modifier le puzzle du ${editingPuzzle.date}` : "Nouveau puzzle"} +

+
+ {!editingPuzzle && ( + setPuzzleForm((f) => ({ ...f, date: e.target.value }))} + placeholder="Date (YYYY-MM-DD)" + /> + )} + setPuzzleForm((f) => ({ ...f, startArticle: e.target.value }))} + placeholder="Article de départ (ex: Tour Eiffel)" + /> + setPuzzleForm((f) => ({ ...f, targetArticle: e.target.value }))} + placeholder="Article cible (ex: Napoléon Bonaparte)" + /> +
+ + {editingPuzzle && ( + + )} +
+
+
+ + {/* Liste */} + {dailyPuzzles && ( +
+

Puzzles existants

+
+ {dailyPuzzles.map((p) => ( +
+
+

{p.date}

+

{p.startArticle} → {p.targetArticle}

+

{p._count.results} résultat{p._count.results > 1 ? "s" : ""}

+
+
+ + +
+
+ ))} +
+
+ )} +
+ )} + + )} +
+ ); +} diff --git a/app/api/admin/daily/[id]/route.ts b/app/api/admin/daily/[id]/route.ts new file mode 100644 index 0000000..79ba26c --- /dev/null +++ b/app/api/admin/daily/[id]/route.ts @@ -0,0 +1,25 @@ +import { NextResponse } from "next/server"; +import { prisma } from "../../../../../lib/prisma"; + +type Params = { params: Promise<{ id: string }> }; + +// PATCH /api/admin/daily/[id] — modifier un puzzle +export async function PATCH(req: Request, { params }: Params) { + const { id } = await params; + const { startArticle, targetArticle } = await req.json() as { + startArticle: string; + targetArticle: string; + }; + const puzzle = await prisma.dailyPuzzle.update({ + where: { id }, + data: { startArticle, targetArticle }, + }); + return NextResponse.json(puzzle); +} + +// DELETE /api/admin/daily/[id] — supprimer un puzzle +export async function DELETE(_req: Request, { params }: Params) { + const { id } = await params; + await prisma.dailyPuzzle.delete({ where: { id } }); + return NextResponse.json({ ok: true }); +} diff --git a/app/api/admin/daily/route.ts b/app/api/admin/daily/route.ts new file mode 100644 index 0000000..f8c4077 --- /dev/null +++ b/app/api/admin/daily/route.ts @@ -0,0 +1,28 @@ +import { NextResponse } from "next/server"; +import { prisma } from "../../../../lib/prisma"; + +// GET /api/admin/daily — liste tous les puzzles +export async function GET() { + const puzzles = await prisma.dailyPuzzle.findMany({ + orderBy: { date: "desc" }, + take: 30, + include: { _count: { select: { results: true } } }, + }); + return NextResponse.json(puzzles); +} + +// POST /api/admin/daily — créer un puzzle pour une date +export async function POST(req: Request) { + const { date, startArticle, targetArticle } = await req.json() as { + date: string; + startArticle: string; + targetArticle: string; + }; + + const puzzle = await prisma.dailyPuzzle.upsert({ + where: { date }, + create: { date, startArticle, targetArticle }, + update: { startArticle, targetArticle }, + }); + return NextResponse.json(puzzle); +} diff --git a/app/api/admin/stats/route.ts b/app/api/admin/stats/route.ts new file mode 100644 index 0000000..8df3777 --- /dev/null +++ b/app/api/admin/stats/route.ts @@ -0,0 +1,80 @@ +import { NextResponse } from "next/server"; +import { prisma } from "../../../../lib/prisma"; + +export async function GET() { + const now = new Date(); + const todayStart = new Date(now); + todayStart.setHours(0, 0, 0, 0); + + // Activité sur les 14 derniers jours + const since14 = new Date(todayStart); + since14.setDate(since14.getDate() - 13); + + const [totalUsers, totalGames, todayGames, recentUsers, recentGames, modeStats, activityRaw] = + await Promise.all([ + prisma.user.count(), + prisma.game.count(), + prisma.game.count({ where: { playedAt: { gte: todayStart } } }), + prisma.user.findMany({ + orderBy: { createdAt: "desc" }, + take: 50, + select: { + id: true, + name: true, + email: true, + banned: true, + createdAt: true, + _count: { select: { games: true } }, + }, + }), + prisma.game.findMany({ + orderBy: { playedAt: "desc" }, + take: 50, + select: { + id: true, + mode: true, + startArticle: true, + targetArticle: true, + clicks: true, + timeSeconds: true, + won: true, + playedAt: true, + user: { select: { name: true } }, + }, + }), + prisma.game.groupBy({ + by: ["mode"], + _count: { id: true }, + _avg: { clicks: true, timeSeconds: true }, + }), + prisma.game.findMany({ + where: { playedAt: { gte: since14 } }, + select: { playedAt: true }, + }), + ]); + + // Agréger l'activité par jour + const activityMap = new Map(); + for (let i = 0; i < 14; i++) { + const d = new Date(since14); + d.setDate(d.getDate() + i); + activityMap.set(d.toISOString().slice(0, 10), 0); + } + for (const g of activityRaw) { + const key = g.playedAt.toISOString().slice(0, 10); + activityMap.set(key, (activityMap.get(key) ?? 0) + 1); + } + const activity = Array.from(activityMap.entries()) + .sort(([a], [b]) => a.localeCompare(b)) + .map(([date, count]) => ({ date, count })); + + return NextResponse.json({ + totalUsers, + totalGames, + todayGames, + recentUsers, + recentGames, + modeStats, + activity, + }); +} diff --git a/app/api/admin/users/[id]/route.ts b/app/api/admin/users/[id]/route.ts new file mode 100644 index 0000000..a65856e --- /dev/null +++ b/app/api/admin/users/[id]/route.ts @@ -0,0 +1,19 @@ +import { NextResponse } from "next/server"; +import { prisma } from "../../../../../lib/prisma"; + +type Params = { params: Promise<{ id: string }> }; + +// DELETE /api/admin/users/[id] — supprimer un utilisateur +export async function DELETE(_req: Request, { params }: Params) { + const { id } = await params; + await prisma.user.delete({ where: { id } }); + return NextResponse.json({ ok: true }); +} + +// PATCH /api/admin/users/[id] — ban/unban +export async function PATCH(req: Request, { params }: Params) { + const { id } = await params; + const { banned } = await req.json() as { banned: boolean }; + const user = await prisma.user.update({ where: { id }, data: { banned } }); + return NextResponse.json({ id: user.id, banned: user.banned }); +} diff --git a/app/components/HomeScreen.tsx b/app/components/HomeScreen.tsx index 6e3f630..f29bab4 100644 --- a/app/components/HomeScreen.tsx +++ b/app/components/HomeScreen.tsx @@ -30,10 +30,6 @@ type HomeScreenProps = { setPlayerName: (v: string) => void; joinCode: string; setJoinCode: (v: string) => void; - maxPlayers: number; - setMaxPlayers: (v: number) => void; - totalRounds: number; - setTotalRounds: (v: number) => void; error: string | null; setError: (v: string | null) => void; loading: boolean; @@ -53,10 +49,6 @@ export function HomeScreen({ setPlayerName, joinCode, setJoinCode, - maxPlayers, - setMaxPlayers, - totalRounds, - setTotalRounds, error, setError, loading, @@ -155,47 +147,13 @@ export function HomeScreen({

Multijoueur

-
- -
- - Max - - -
-
- - Manches - - -
-
+ {/* Join row - colonne sur mobile, ligne sur sm+ */}
void; onStart: () => void; onReset: () => void; + maxPlayers: number; + setMaxPlayers: (v: number) => void; + totalRounds: number; + setTotalRounds: (v: number) => void; }; export function LobbyScreen({ - room, playerId, error, setError, loading, onLeave, onStart, onReset, + room, + playerId, + error, + setError, + loading, + onLeave, + onStart, + onReset, + maxPlayers, + setMaxPlayers, + totalRounds, + setTotalRounds, }: LobbyScreenProps) { const isHost = room.players.find((p) => p.id === playerId)?.isHost ?? false; const [copied, setCopied] = useState(false); + const [blurred, setBlurred] = useState(true); const { allowed: searchAllowed, toggle: toggleSearch } = useSearchAllowed(); function copyCode() { @@ -29,33 +45,62 @@ export function LobbyScreen({ }); } - const btnGhost = "w-full min-h-11 px-5 rounded-xl text-sm font-semibold bg-[#242424] border border-[#2e2e2e] text-[#f0f0f0] hover:bg-[#1a1a1a] cursor-pointer transition-colors"; - const btnPrimary = "w-full min-h-11 px-5 rounded-xl text-sm font-semibold bg-[#7c3aed] text-white hover:bg-[#6d28d9] disabled:opacity-50 cursor-pointer transition-colors"; + const btnGhost = + "w-full min-h-11 px-5 rounded-xl text-sm font-semibold bg-[#242424] border border-[#2e2e2e] text-[#f0f0f0] hover:bg-[#1a1a1a] cursor-pointer transition-colors"; + const btnPrimary = + "w-full min-h-11 px-5 rounded-xl text-sm font-semibold bg-[#7c3aed] text-white hover:bg-[#6d28d9] disabled:opacity-50 cursor-pointer transition-colors"; return (
- {/* Code */}
- Code de la salle - +
+ - {copied ? "Copié !" : "Clique pour copier"} + + {copied ? "Copié !" : "Clique pour copier"} +
{error && (
{error} - +
)} @@ -66,39 +111,106 @@ export function LobbyScreen({
    {room.players.map((p) => ( -
  • - {p.name} - {p.isHost && Hôte} - {p.id === playerId && Toi} - {p.score} pts +
  • + + {p.name} + + {p.isHost && ( + + Hôte + + )} + {p.id === playerId && ( + + Toi + + )} + + {p.score} pts +
  • ))}
+ {isHost && ( +
+

+ Paramètres +

+
+
+ Joueurs max + +
+
+ Manches + +
+
+
+ )} + - {room.round > 0 &&

Manche {room.round} terminée

} + {room.round > 0 && ( +

+ Manche {room.round} terminée +

+ )} {isHost ? (
{room.round > 0 && ( - + )}
) : ( -

En attente que l'hôte démarre...

+

+ En attente que l'hôte démarre... +

)}
); diff --git a/app/components/ScreenRouter.tsx b/app/components/ScreenRouter.tsx index 8a3b976..1858ef6 100644 --- a/app/components/ScreenRouter.tsx +++ b/app/components/ScreenRouter.tsx @@ -67,8 +67,6 @@ export function ScreenRouter({ ); diff --git a/app/mentions-legales/page.tsx b/app/mentions-legales/page.tsx index 503b40a..b419a73 100644 --- a/app/mentions-legales/page.tsx +++ b/app/mentions-legales/page.tsx @@ -60,25 +60,35 @@ export default function MentionsLegalesPage() {

- Raison sociale :{" "} - QuantumCraft Studios + Raison sociale : SAS + SAPINET

- SIRET : 932 107 758 00017 + SIREN : 899 483 457 (RCS + de Nanterre)

- Adresse : 58 Rue de - Monceau, 75008 Paris, France + Adresse : 65 rue de la + Croix, 92000 Nanterre +

+

+ Contact :{" "} + + contact@sapi.net +

Site web :{" "} - quantumcraft-studios.com + sapi.net

diff --git a/auth.ts b/auth.ts index 7cb17fe..ba7e20f 100644 --- a/auth.ts +++ b/auth.ts @@ -21,6 +21,7 @@ export const { handlers, auth, signIn, signOut } = NextAuth({ user.password, ); if (!valid) return null; + if (user.banned) return null; return { id: user.id, name: user.name, email: user.email }; }, }), @@ -31,11 +32,17 @@ export const { handlers, auth, signIn, signOut } = NextAuth({ }, callbacks: { jwt({ token, user }) { - if (user) token.id = user.id; + if (user) { + token.id = user.id; + token.email = user.email; + } return token; }, session({ session, token }) { - if (session.user) session.user.id = token.id as string; + if (session.user) { + session.user.id = token.id as string; + session.user.email = token.email as string; + } return session; }, }, diff --git a/lib/generated/prisma/commonInputTypes.ts b/lib/generated/prisma/commonInputTypes.ts index 913d599..8c92ab6 100644 --- a/lib/generated/prisma/commonInputTypes.ts +++ b/lib/generated/prisma/commonInputTypes.ts @@ -28,6 +28,11 @@ export type StringFilter<$PrismaModel = never> = { not?: Prisma.NestedStringFilter<$PrismaModel> | string } +export type BoolFilter<$PrismaModel = never> = { + equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel> + not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean +} + export type DateTimeFilter<$PrismaModel = never> = { equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> in?: Date[] | string[] @@ -56,6 +61,14 @@ export type StringWithAggregatesFilter<$PrismaModel = never> = { _max?: Prisma.NestedStringFilter<$PrismaModel> } +export type BoolWithAggregatesFilter<$PrismaModel = never> = { + equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel> + not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedBoolFilter<$PrismaModel> + _max?: Prisma.NestedBoolFilter<$PrismaModel> +} + export type DateTimeWithAggregatesFilter<$PrismaModel = never> = { equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> in?: Date[] | string[] @@ -92,11 +105,6 @@ export type FloatFilter<$PrismaModel = never> = { not?: Prisma.NestedFloatFilter<$PrismaModel> | number } -export type BoolFilter<$PrismaModel = never> = { - equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel> - not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean -} - export type IntWithAggregatesFilter<$PrismaModel = never> = { equals?: number | Prisma.IntFieldRefInput<$PrismaModel> in?: number[] @@ -129,14 +137,6 @@ export type FloatWithAggregatesFilter<$PrismaModel = never> = { _max?: Prisma.NestedFloatFilter<$PrismaModel> } -export type BoolWithAggregatesFilter<$PrismaModel = never> = { - equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel> - not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedBoolFilter<$PrismaModel> - _max?: Prisma.NestedBoolFilter<$PrismaModel> -} - export type NestedStringFilter<$PrismaModel = never> = { equals?: string | Prisma.StringFieldRefInput<$PrismaModel> in?: string[] @@ -151,6 +151,11 @@ export type NestedStringFilter<$PrismaModel = never> = { not?: Prisma.NestedStringFilter<$PrismaModel> | string } +export type NestedBoolFilter<$PrismaModel = never> = { + equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel> + not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean +} + export type NestedDateTimeFilter<$PrismaModel = never> = { equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> in?: Date[] | string[] @@ -190,6 +195,14 @@ export type NestedIntFilter<$PrismaModel = never> = { not?: Prisma.NestedIntFilter<$PrismaModel> | number } +export type NestedBoolWithAggregatesFilter<$PrismaModel = never> = { + equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel> + not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedBoolFilter<$PrismaModel> + _max?: Prisma.NestedBoolFilter<$PrismaModel> +} + export type NestedDateTimeWithAggregatesFilter<$PrismaModel = never> = { equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> in?: Date[] | string[] @@ -215,11 +228,6 @@ export type NestedFloatFilter<$PrismaModel = never> = { not?: Prisma.NestedFloatFilter<$PrismaModel> | number } -export type NestedBoolFilter<$PrismaModel = never> = { - equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel> - not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean -} - export type NestedIntWithAggregatesFilter<$PrismaModel = never> = { equals?: number | Prisma.IntFieldRefInput<$PrismaModel> in?: number[] @@ -252,12 +260,4 @@ export type NestedFloatWithAggregatesFilter<$PrismaModel = never> = { _max?: Prisma.NestedFloatFilter<$PrismaModel> } -export type NestedBoolWithAggregatesFilter<$PrismaModel = never> = { - equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel> - not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean - _count?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedBoolFilter<$PrismaModel> - _max?: Prisma.NestedBoolFilter<$PrismaModel> -} - diff --git a/lib/generated/prisma/internal/class.ts b/lib/generated/prisma/internal/class.ts index 6b3d3cc..82d9951 100644 --- a/lib/generated/prisma/internal/class.ts +++ b/lib/generated/prisma/internal/class.ts @@ -20,7 +20,7 @@ const config: runtime.GetPrismaClientConfig = { "clientVersion": "7.7.0", "engineVersion": "75cbdc1eb7150937890ad5465d861175c6624711", "activeProvider": "sqlite", - "inlineSchema": "generator client {\n provider = \"prisma-client\"\n output = \"../lib/generated/prisma\"\n}\n\ndatasource db {\n provider = \"sqlite\"\n}\n\nmodel User {\n id String @id @default(uuid(7))\n name String\n email String @unique\n password String\n createdAt DateTime @default(now())\n games Game[]\n dailyResults DailyResult[]\n}\n\nmodel Game {\n id String @id @default(uuid(7))\n userId String\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n mode String // \"solo\" | \"multi\" | \"daily\" | \"blitz\"\n startArticle String\n targetArticle String\n path String // JSON array de titres\n clicks Int\n timeSeconds Float\n won Boolean @default(true)\n playedAt DateTime @default(now())\n\n @@index([userId])\n}\n\nmodel DailyPuzzle {\n id String @id @default(uuid(7))\n date String @unique // \"YYYY-MM-DD\"\n startArticle String\n targetArticle String\n results DailyResult[]\n}\n\nmodel DailyResult {\n id String @id @default(uuid(7))\n puzzleId String\n puzzle DailyPuzzle @relation(fields: [puzzleId], references: [id], onDelete: Cascade)\n userId String\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n path String // JSON\n clicks Int\n timeSeconds Float\n won Boolean\n playedAt DateTime @default(now())\n\n @@unique([puzzleId, userId])\n @@index([puzzleId])\n}\n", + "inlineSchema": "generator client {\n provider = \"prisma-client\"\n output = \"../lib/generated/prisma\"\n}\n\ndatasource db {\n provider = \"sqlite\"\n}\n\nmodel User {\n id String @id @default(uuid(7))\n name String\n email String @unique\n password String\n banned Boolean @default(false)\n createdAt DateTime @default(now())\n games Game[]\n dailyResults DailyResult[]\n}\n\nmodel Game {\n id String @id @default(uuid(7))\n userId String\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n mode String // \"solo\" | \"multi\" | \"daily\" | \"blitz\"\n startArticle String\n targetArticle String\n path String // JSON array de titres\n clicks Int\n timeSeconds Float\n won Boolean @default(true)\n playedAt DateTime @default(now())\n\n @@index([userId])\n}\n\nmodel DailyPuzzle {\n id String @id @default(uuid(7))\n date String @unique // \"YYYY-MM-DD\"\n startArticle String\n targetArticle String\n results DailyResult[]\n}\n\nmodel DailyResult {\n id String @id @default(uuid(7))\n puzzleId String\n puzzle DailyPuzzle @relation(fields: [puzzleId], references: [id], onDelete: Cascade)\n userId String\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n path String // JSON\n clicks Int\n timeSeconds Float\n won Boolean\n playedAt DateTime @default(now())\n\n @@unique([puzzleId, userId])\n @@index([puzzleId])\n}\n", "runtimeDataModel": { "models": {}, "enums": {}, @@ -32,10 +32,10 @@ const config: runtime.GetPrismaClientConfig = { } } -config.runtimeDataModel = JSON.parse("{\"models\":{\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"password\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"games\",\"kind\":\"object\",\"type\":\"Game\",\"relationName\":\"GameToUser\"},{\"name\":\"dailyResults\",\"kind\":\"object\",\"type\":\"DailyResult\",\"relationName\":\"DailyResultToUser\"}],\"dbName\":null},\"Game\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"GameToUser\"},{\"name\":\"mode\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"startArticle\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"targetArticle\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"path\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"clicks\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"timeSeconds\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"won\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"playedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"DailyPuzzle\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"date\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"startArticle\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"targetArticle\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"results\",\"kind\":\"object\",\"type\":\"DailyResult\",\"relationName\":\"DailyPuzzleToDailyResult\"}],\"dbName\":null},\"DailyResult\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"puzzleId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"puzzle\",\"kind\":\"object\",\"type\":\"DailyPuzzle\",\"relationName\":\"DailyPuzzleToDailyResult\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"DailyResultToUser\"},{\"name\":\"path\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"clicks\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"timeSeconds\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"won\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"playedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}") +config.runtimeDataModel = JSON.parse("{\"models\":{\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"password\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"banned\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"games\",\"kind\":\"object\",\"type\":\"Game\",\"relationName\":\"GameToUser\"},{\"name\":\"dailyResults\",\"kind\":\"object\",\"type\":\"DailyResult\",\"relationName\":\"DailyResultToUser\"}],\"dbName\":null},\"Game\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"GameToUser\"},{\"name\":\"mode\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"startArticle\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"targetArticle\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"path\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"clicks\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"timeSeconds\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"won\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"playedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"DailyPuzzle\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"date\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"startArticle\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"targetArticle\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"results\",\"kind\":\"object\",\"type\":\"DailyResult\",\"relationName\":\"DailyPuzzleToDailyResult\"}],\"dbName\":null},\"DailyResult\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"puzzleId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"puzzle\",\"kind\":\"object\",\"type\":\"DailyPuzzle\",\"relationName\":\"DailyPuzzleToDailyResult\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"DailyResultToUser\"},{\"name\":\"path\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"clicks\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"timeSeconds\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"won\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"playedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}") config.parameterizationSchema = { - strings: JSON.parse("[\"where\",\"orderBy\",\"cursor\",\"user\",\"games\",\"results\",\"_count\",\"puzzle\",\"dailyResults\",\"User.findUnique\",\"User.findUniqueOrThrow\",\"User.findFirst\",\"User.findFirstOrThrow\",\"User.findMany\",\"data\",\"User.createOne\",\"User.createMany\",\"User.createManyAndReturn\",\"User.updateOne\",\"User.updateMany\",\"User.updateManyAndReturn\",\"create\",\"update\",\"User.upsertOne\",\"User.deleteOne\",\"User.deleteMany\",\"having\",\"_min\",\"_max\",\"User.groupBy\",\"User.aggregate\",\"Game.findUnique\",\"Game.findUniqueOrThrow\",\"Game.findFirst\",\"Game.findFirstOrThrow\",\"Game.findMany\",\"Game.createOne\",\"Game.createMany\",\"Game.createManyAndReturn\",\"Game.updateOne\",\"Game.updateMany\",\"Game.updateManyAndReturn\",\"Game.upsertOne\",\"Game.deleteOne\",\"Game.deleteMany\",\"_avg\",\"_sum\",\"Game.groupBy\",\"Game.aggregate\",\"DailyPuzzle.findUnique\",\"DailyPuzzle.findUniqueOrThrow\",\"DailyPuzzle.findFirst\",\"DailyPuzzle.findFirstOrThrow\",\"DailyPuzzle.findMany\",\"DailyPuzzle.createOne\",\"DailyPuzzle.createMany\",\"DailyPuzzle.createManyAndReturn\",\"DailyPuzzle.updateOne\",\"DailyPuzzle.updateMany\",\"DailyPuzzle.updateManyAndReturn\",\"DailyPuzzle.upsertOne\",\"DailyPuzzle.deleteOne\",\"DailyPuzzle.deleteMany\",\"DailyPuzzle.groupBy\",\"DailyPuzzle.aggregate\",\"DailyResult.findUnique\",\"DailyResult.findUniqueOrThrow\",\"DailyResult.findFirst\",\"DailyResult.findFirstOrThrow\",\"DailyResult.findMany\",\"DailyResult.createOne\",\"DailyResult.createMany\",\"DailyResult.createManyAndReturn\",\"DailyResult.updateOne\",\"DailyResult.updateMany\",\"DailyResult.updateManyAndReturn\",\"DailyResult.upsertOne\",\"DailyResult.deleteOne\",\"DailyResult.deleteMany\",\"DailyResult.groupBy\",\"DailyResult.aggregate\",\"AND\",\"OR\",\"NOT\",\"id\",\"puzzleId\",\"userId\",\"path\",\"clicks\",\"timeSeconds\",\"won\",\"playedAt\",\"equals\",\"in\",\"notIn\",\"lt\",\"lte\",\"gt\",\"gte\",\"not\",\"contains\",\"startsWith\",\"endsWith\",\"date\",\"startArticle\",\"targetArticle\",\"every\",\"some\",\"none\",\"mode\",\"name\",\"email\",\"password\",\"createdAt\",\"puzzleId_userId\",\"is\",\"isNot\",\"connectOrCreate\",\"upsert\",\"createMany\",\"set\",\"disconnect\",\"delete\",\"connect\",\"updateMany\",\"deleteMany\",\"increment\",\"decrement\",\"multiply\",\"divide\"]"), - graph: "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_ACABAABAADACAAA8ACADAAAAPwAgAQAAQAAwAgAAPAAgBQUAAKoBACBUAQAAAAFnAQAAAAFoAQAAAAFpAQAAAAEBDgAARAAgBFQBAAAAAWcBAAAAAWgBAAAAAWkBAAAAAQEOAABGADABDgAARgAwBQUAAJ0BACBUAQCRAQAhZwEAkQEAIWgBAJEBACFpAQCRAQAhAgAAADwAIA4AAEkAIARUAQCRAQAhZwEAkQEAIWgBAJEBACFpAQCRAQAhAgAAAD8AIA4AAEsAIAIAAAA_ACAOAABLACADAAAAPAAgFQAARAAgFgAASQAgAQAAADwAIAEAAAA_ACADBgAAmgEAIBsAAJwBACAcAACbAQAgB1EAAHsAMFIAAFIAEFMAAHsAMFQBAGwAIWcBAGwAIWgBAGwAIWkBAGwAIQMAAAA_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-ACBRAAB8ADBSAAA_ABBTAAB8ADBUAQB9ACFnAQB9ACFoAQB9ACFpAQB9ACELXAEAAAABXQEAAAAEXgEAAAAEXwEAAAABYAEAAAABYQEAAAABYgEAAAABYwEAegAhZAEAAAABZQEAAAABZgEAAAABA2oAAAcAIGsAAAcAIGwAAAcAIA1RAAB_ADBSAAA5ABBTAAB_ADBUAQBsACFWAQBsACFXAQBsACFYAgBtACFZCABuACFaIABvACFbQABwACFoAQBsACFpAQBsACFtAQBsACEIUQAAgAEAMFIAACMAEFMAAIABADBUAQBsACFuAQBsACFvAQBsACFwAQBsACFxQABwACEKBAAAgwEAIAgAAH4AIFEAAIEBADBSAAAQABBTAACBAQAwVAEAfQAhbgEAfQAhbwEAfQAhcAEAfQAhcUAAggEAIQhcQAAAAAFdQAAAAAReQAAAAARfQAAAAAFgQAAAAAFhQAAAAAFiQAAAAAFjQABzACEDagAAAwAgawAAAwAgbAAAAwAgAlUBAAAAAVYBAAAAAQ0DAACKAQAgBwAAiQEAIFEAAIUBADBSAAAHABBTAACFAQAwVAEAfQAhVQEAfQAhVgEAfQAhVwEAfQAhWAIAhgEAIVkIAIcBACFaIACIAQAhW0AAggEAIQhcAgAAAAFdAgAAAAReAgAAAARfAgAAAAFgAgAAAAFhAgAAAAFiAgAAAAFjAgByACEIXAgAAAABXQgAAAAEXggAAAAEXwgAAAABYAgAAAABYQgAAAABYggAAAABYwgAdwAhAlwgAAAAAWMgAHUAIQoFAAB-ACBRAAB8ADBSAAA_ABBTAAB8ADBUAQB9ACFnAQB9ACFoAQB9ACFpAQB9ACFzAAA_ACB0AAA_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_ACAVAADcAQAgFgAA4wEAIAYAAAA_ACAOAADjAQAgVAEAkQEAIWcBAJEBACFoAQCRAQAhaQEAkQEAIQRUAQCRAQAhZwEAkQEAIWgBAJEBACFpAQCRAQAhAwQGAgYABggKAwEDAAECAwABBwAEAgULAwYABQEFDAACBA0ACA4AAAAAAwYACxsADBwADQAAAAMGAAsbAAwcAA0BAwABAQMAAQUGABIbABUcABYtABMuABQAAAAAAAUGABIbABUcABYtABMuABQAAAMGABsbABwcAB0AAAADBgAbGwAcHAAdAgMAAQcABAIDAAEHAAQFBgAiGwAlHAAmLQAjLgAkAAAAAAAFBgAiGwAlHAAmLQAjLgAkCQIBCg8BCxIBDBMBDRQBDxYBEBgHERkIEhsBEx0HFB4JFx8BGCABGSEHHSQKHiUOHyYCICcCISgCIikCIyoCJCwCJS4HJi8PJzECKDMHKTQQKjUCKzYCLDcHLzoRMDsXMT0EMj4EM0EENEIENUMENkUEN0cHOEgYOUoEOkwHO00ZPE4EPU8EPlAHP1MaQFQeQVUDQlYDQ1cDRFgDRVkDRlsDR10HSF4fSWADSmIHS2MgTGQDTWUDTmYHT2khUGon" + strings: JSON.parse("[\"where\",\"orderBy\",\"cursor\",\"user\",\"games\",\"results\",\"_count\",\"puzzle\",\"dailyResults\",\"User.findUnique\",\"User.findUniqueOrThrow\",\"User.findFirst\",\"User.findFirstOrThrow\",\"User.findMany\",\"data\",\"User.createOne\",\"User.createMany\",\"User.createManyAndReturn\",\"User.updateOne\",\"User.updateMany\",\"User.updateManyAndReturn\",\"create\",\"update\",\"User.upsertOne\",\"User.deleteOne\",\"User.deleteMany\",\"having\",\"_min\",\"_max\",\"User.groupBy\",\"User.aggregate\",\"Game.findUnique\",\"Game.findUniqueOrThrow\",\"Game.findFirst\",\"Game.findFirstOrThrow\",\"Game.findMany\",\"Game.createOne\",\"Game.createMany\",\"Game.createManyAndReturn\",\"Game.updateOne\",\"Game.updateMany\",\"Game.updateManyAndReturn\",\"Game.upsertOne\",\"Game.deleteOne\",\"Game.deleteMany\",\"_avg\",\"_sum\",\"Game.groupBy\",\"Game.aggregate\",\"DailyPuzzle.findUnique\",\"DailyPuzzle.findUniqueOrThrow\",\"DailyPuzzle.findFirst\",\"DailyPuzzle.findFirstOrThrow\",\"DailyPuzzle.findMany\",\"DailyPuzzle.createOne\",\"DailyPuzzle.createMany\",\"DailyPuzzle.createManyAndReturn\",\"DailyPuzzle.updateOne\",\"DailyPuzzle.updateMany\",\"DailyPuzzle.updateManyAndReturn\",\"DailyPuzzle.upsertOne\",\"DailyPuzzle.deleteOne\",\"DailyPuzzle.deleteMany\",\"DailyPuzzle.groupBy\",\"DailyPuzzle.aggregate\",\"DailyResult.findUnique\",\"DailyResult.findUniqueOrThrow\",\"DailyResult.findFirst\",\"DailyResult.findFirstOrThrow\",\"DailyResult.findMany\",\"DailyResult.createOne\",\"DailyResult.createMany\",\"DailyResult.createManyAndReturn\",\"DailyResult.updateOne\",\"DailyResult.updateMany\",\"DailyResult.updateManyAndReturn\",\"DailyResult.upsertOne\",\"DailyResult.deleteOne\",\"DailyResult.deleteMany\",\"DailyResult.groupBy\",\"DailyResult.aggregate\",\"AND\",\"OR\",\"NOT\",\"id\",\"puzzleId\",\"userId\",\"path\",\"clicks\",\"timeSeconds\",\"won\",\"playedAt\",\"equals\",\"in\",\"notIn\",\"lt\",\"lte\",\"gt\",\"gte\",\"not\",\"contains\",\"startsWith\",\"endsWith\",\"date\",\"startArticle\",\"targetArticle\",\"every\",\"some\",\"none\",\"mode\",\"name\",\"email\",\"password\",\"banned\",\"createdAt\",\"puzzleId_userId\",\"is\",\"isNot\",\"connectOrCreate\",\"upsert\",\"createMany\",\"set\",\"disconnect\",\"delete\",\"connect\",\"updateMany\",\"deleteMany\",\"increment\",\"decrement\",\"multiply\",\"divide\"]"), + graph: "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_ADBSAAA5ABBTAAB_ADBUAQBsACFWAQBsACFXAQBsACFYAgBtACFZCABuACFaIABvACFbQABwACFoAQBsACFpAQBsACFtAQBsACEDAAAAAwAgAQAAOAAwGgAAOQAgAwAAAAMAIAEAAAQAMAIAAAUAIAgFAAB-ACBRAAB8ADBSAAA_ABBTAAB8ADBUAQAAAAFnAQAAAAFoAQB9ACFpAQB9ACEBAAAAPAAgAQAAADwAIAgFAAB-ACBRAAB8ADBSAAA_ABBTAAB8ADBUAQB9ACFnAQB9ACFoAQB9ACFpAQB9ACEBBQAAqwEAIAMAAAA_ACABAABAADACAAA8ACADAAAAPwAgAQAAQAAwAgAAPAAgAwAAAD8AIAEAAEAAMAIAADwAIAUFAACqAQAgVAEAAAABZwEAAAABaAEAAAABaQEAAAABAQ4AAEQAIARUAQAAAAFnAQAAAAFoAQAAAAFpAQAAAAEBDgAARgAwAQ4AAEYAMAUFAACdAQAgVAEAkQEAIWcBAJEBACFoAQCRAQAhaQEAkQEAIQIAAAA8ACAOAABJACAEVAEAkQEAIWcBAJEBACFoAQCRAQAhaQEAkQEAIQIAAAA_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_CAAAAAGAAQgAAAABgQEIAAAAAYIBCAAAAAEBeSAAAAABAXlAAAAAAQUVAADcAQAgFgAA4gEAIHYAAN0BACB3AADhAQAgfAAAPAAgBRUAANoBACAWAADfAQAgdgAA2wEAIHcAAN4BACB8AAABACADFQAA3AEAIHYAAN0BACB8AAA8ACADFQAA2gEAIHYAANsBACB8AAABACAAAAALFQAAngEAMBYAAKMBADB2AACfAQAwdwAAoAEAMHgAAKEBACB5AACiAQAwegAAogEAMHsAAKIBADB8AACiAQAwfQAApAEAMH4AAKUBADAIAwAAmQEAIFQBAAAAAVYBAAAAAVcBAAAAAVgCAAAAAVkIAAAAAVogAAAAAVtAAAAAAQIAAAAJACAVAACpAQAgAwAAAAkAIBUAAKkBACAWAACoAQAgAQ4AANkBADAOAwAAigEAIAcAAIkBACBRAACGAQAwUgAABwAQUwAAhgEAMFQBAAAAAVUBAH0AIVYBAH0AIVcBAH0AIVgCAIcBACFZCACIAQAhWiAAggEAIVtAAIMBACFzAACFAQAgAgAAAAkAIA4AAKgBACACAAAApgEAIA4AAKcBACALUQAApQEAMFIAAKYBABBTAAClAQAwVAEAfQAhVQEAfQAhVgEAfQAhVwEAfQAhWAIAhwEAIVkIAIgBACFaIACCAQAhW0AAgwEAIQtRAAClAQAwUgAApgEAEFMAAKUBADBUAQB9ACFVAQB9ACFWAQB9ACFXAQB9ACFYAgCHAQAhWQgAiAEAIVogAIIBACFbQACDAQAhB1QBAJEBACFWAQCRAQAhVwEAkQEAIVgCAJIBACFZCACTAQAhWiAAlAEAIVtAAJUBACEIAwAAlwEAIFQBAJEBACFWAQCRAQAhVwEAkQEAIVgCAJIBACFZCACTAQAhWiAAlAEAIVtAAJUBACEIAwAAmQEAIFQBAAAAAVYBAAAAAVcBAAAAAVgCAAAAAVkIAAAAAVogAAAAAVtAAAAAAQQVAACeAQAwdgAAnwEAMHgAAKEBACB8AACiAQAwAAAAAAAABRUAANQBACAWAADXAQAgdgAA1QEAIHcAANYBACB8AAABACADFQAA1AEAIHYAANUBACB8AAABACAAAAALFQAAwQEAMBYAAMYBADB2AADCAQAwdwAAwwEAMHgAAMQBACB5AADFAQAwegAAxQEAMHsAAMUBADB8AADFAQAwfQAAxwEAMH4AAMgBADALFQAAuAEAMBYAALwBADB2AAC5AQAwdwAAugEAMHgAALsBACB5AACiAQAwegAAogEAMHsAAKIBADB8AACiAQAwfQAAvQEAMH4AAKUBADAIBwAAmAEAIFQBAAAAAVUBAAAAAVcBAAAAAVgCAAAAAVkIAAAAAVogAAAAAVtAAAAAAQIAAAAJACAVAADAAQAgAwAAAAkAIBUAAMABACAWAAC_AQAgAQ4AANMBADACAAAACQAgDgAAvwEAIAIAAACmAQAgDgAAvgEAIAdUAQCRAQAhVQEAkQEAIVcBAJEBACFYAgCSAQAhWQgAkwEAIVogAJQBACFbQACVAQAhCAcAAJYBACBUAQCRAQAhVQEAkQEAIVcBAJEBACFYAgCSAQAhWQgAkwEAIVogAJQBACFbQACVAQAhCAcAAJgBACBUAQAAAAFVAQAAAAFXAQAAAAFYAgAAAAFZCAAAAAFaIAAAAAFbQAAAAAEJVAEAAAABVwEAAAABWAIAAAABWQgAAAABWiAAAAABW0AAAAABaAEAAAABaQEAAAABbQEAAAABAgAAAAUAIBUAAMwBACADAAAABQAgFQAAzAEAIBYAAMsBACABDgAA0gEAMA4DAACKAQAgUQAAiwEAMFIAAAMAEFMAAIsBADBUAQAAAAFWAQB9ACFXAQB9ACFYAgCHAQAhWQgAiAEAIVogAIIBACFbQACDAQAhaAEAfQAhaQEAfQAhbQEAfQAhAgAAAAUAIA4AAMsBACACAAAAyQEAIA4AAMoBACANUQAAyAEAMFIAAMkBABBTAADIAQAwVAEAfQAhVgEAfQAhVwEAfQAhWAIAhwEAIVkIAIgBACFaIACCAQAhW0AAgwEAIWgBAH0AIWkBAH0AIW0BAH0AIQ1RAADIAQAwUgAAyQEAEFMAAMgBADBUAQB9ACFWAQB9ACFXAQB9ACFYAgCHAQAhWQgAiAEAIVogAIIBACFbQACDAQAhaAEAfQAhaQEAfQAhbQEAfQAhCVQBAJEBACFXAQCRAQAhWAIAkgEAIVkIAJMBACFaIACUAQAhW0AAlQEAIWgBAJEBACFpAQCRAQAhbQEAkQEAIQlUAQCRAQAhVwEAkQEAIVgCAJIBACFZCACTAQAhWiAAlAEAIVtAAJUBACFoAQCRAQAhaQEAkQEAIW0BAJEBACEJVAEAAAABVwEAAAABWAIAAAABWQgAAAABWiAAAAABW0AAAAABaAEAAAABaQEAAAABbQEAAAABBBUAAMEBADB2AADCAQAweAAAxAEAIHwAAMUBADAEFQAAuAEAMHYAALkBADB4AAC7AQAgfAAAogEAMAABBQAAqwEAIAIEAADPAQAgCAAAqwEAIAlUAQAAAAFXAQAAAAFYAgAAAAFZCAAAAAFaIAAAAAFbQAAAAAFoAQAAAAFpAQAAAAFtAQAAAAEHVAEAAAABVQEAAAABVwEAAAABWAIAAAABWQgAAAABWiAAAAABW0AAAAABBwgAAM4BACBUAQAAAAFuAQAAAAFvAQAAAAFwAQAAAAFxIAAAAAFyQAAAAAECAAAAAQAgFQAA1AEAIAMAAAAQACAVAADUAQAgFgAA2AEAIAkAAAAQACAIAAC3AQAgDgAA2AEAIFQBAJEBACFuAQCRAQAhbwEAkQEAIXABAJEBACFxIACUAQAhckAAlQEAIQcIAAC3AQAgVAEAkQEAIW4BAJEBACFvAQCRAQAhcAEAkQEAIXEgAJQBACFyQACVAQAhB1QBAAAAAVYBAAAAAVcBAAAAAVgCAAAAAVkIAAAAAVogAAAAAVtAAAAAAQcEAADNAQAgVAEAAAABbgEAAAABbwEAAAABcAEAAAABcSAAAAABckAAAAABAgAAAAEAIBUAANoBACAEVAEAAAABZwEAAAABaAEAAAABaQEAAAABAgAAADwAIBUAANwBACADAAAAEAAgFQAA2gEAIBYAAOABACAJAAAAEAAgBAAAtgEAIA4AAOABACBUAQCRAQAhbgEAkQEAIW8BAJEBACFwAQCRAQAhcSAAlAEAIXJAAJUBACEHBAAAtgEAIFQBAJEBACFuAQCRAQAhbwEAkQEAIXABAJEBACFxIACUAQAhckAAlQEAIQMAAAA_ACAVAADcAQAgFgAA4wEAIAYAAAA_ACAOAADjAQAgVAEAkQEAIWcBAJEBACFoAQCRAQAhaQEAkQEAIQRUAQCRAQAhZwEAkQEAIWgBAJEBACFpAQCRAQAhAwQGAgYABggKAwEDAAECAwABBwAEAgULAwYABQEFDAACBA0ACA4AAAAAAwYACxsADBwADQAAAAMGAAsbAAwcAA0BAwABAQMAAQUGABIbABUcABYtABMuABQAAAAAAAUGABIbABUcABYtABMuABQAAAMGABsbABwcAB0AAAADBgAbGwAcHAAdAgMAAQcABAIDAAEHAAQFBgAiGwAlHAAmLQAjLgAkAAAAAAAFBgAiGwAlHAAmLQAjLgAkCQIBCg8BCxIBDBMBDRQBDxYBEBgHERkIEhsBEx0HFB4JFx8BGCABGSEHHSQKHiUOHyYCICcCISgCIikCIyoCJCwCJS4HJi8PJzECKDMHKTQQKjUCKzYCLDcHLzoRMDsXMT0EMj4EM0EENEIENUMENkUEN0cHOEgYOUoEOkwHO00ZPE4EPU8EPlAHP1MaQFQeQVUDQlYDQ1cDRFgDRVkDRlsDR10HSF4fSWADSmIHS2MgTGQDTWUDTmYHT2khUGon" } async function decodeBase64AsWasm(wasmBase64: string): Promise { diff --git a/lib/generated/prisma/internal/prismaNamespace.ts b/lib/generated/prisma/internal/prismaNamespace.ts index 001e6ac..9f282c7 100644 --- a/lib/generated/prisma/internal/prismaNamespace.ts +++ b/lib/generated/prisma/internal/prismaNamespace.ts @@ -744,6 +744,7 @@ export const UserScalarFieldEnum = { name: 'name', email: 'email', password: 'password', + banned: 'banned', createdAt: 'createdAt' } as const @@ -811,6 +812,13 @@ export type StringFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, +/** + * Reference to a field of type 'Boolean' + */ +export type BooleanFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Boolean'> + + + /** * Reference to a field of type 'DateTime' */ @@ -831,13 +839,6 @@ export type IntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'In export type FloatFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Float'> - -/** - * Reference to a field of type 'Boolean' - */ -export type BooleanFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Boolean'> - - /** * Batch Payload for updateMany & deleteMany & createMany */ diff --git a/lib/generated/prisma/internal/prismaNamespaceBrowser.ts b/lib/generated/prisma/internal/prismaNamespaceBrowser.ts index 19949e3..31b8e0b 100644 --- a/lib/generated/prisma/internal/prismaNamespaceBrowser.ts +++ b/lib/generated/prisma/internal/prismaNamespaceBrowser.ts @@ -75,6 +75,7 @@ export const UserScalarFieldEnum = { name: 'name', email: 'email', password: 'password', + banned: 'banned', createdAt: 'createdAt' } as const diff --git a/lib/generated/prisma/models/Game.ts b/lib/generated/prisma/models/Game.ts index cdcf29a..cacc63b 100644 --- a/lib/generated/prisma/models/Game.ts +++ b/lib/generated/prisma/models/Game.ts @@ -535,10 +535,6 @@ export type FloatFieldUpdateOperationsInput = { divide?: number } -export type BoolFieldUpdateOperationsInput = { - set?: boolean -} - export type GameCreateWithoutUserInput = { id?: string mode: string diff --git a/lib/generated/prisma/models/User.ts b/lib/generated/prisma/models/User.ts index 452066e..f565a3c 100644 --- a/lib/generated/prisma/models/User.ts +++ b/lib/generated/prisma/models/User.ts @@ -29,6 +29,7 @@ export type UserMinAggregateOutputType = { name: string | null email: string | null password: string | null + banned: boolean | null createdAt: Date | null } @@ -37,6 +38,7 @@ export type UserMaxAggregateOutputType = { name: string | null email: string | null password: string | null + banned: boolean | null createdAt: Date | null } @@ -45,6 +47,7 @@ export type UserCountAggregateOutputType = { name: number email: number password: number + banned: number createdAt: number _all: number } @@ -55,6 +58,7 @@ export type UserMinAggregateInputType = { name?: true email?: true password?: true + banned?: true createdAt?: true } @@ -63,6 +67,7 @@ export type UserMaxAggregateInputType = { name?: true email?: true password?: true + banned?: true createdAt?: true } @@ -71,6 +76,7 @@ export type UserCountAggregateInputType = { name?: true email?: true password?: true + banned?: true createdAt?: true _all?: true } @@ -152,6 +158,7 @@ export type UserGroupByOutputType = { name: string email: string password: string + banned: boolean createdAt: Date _count: UserCountAggregateOutputType | null _min: UserMinAggregateOutputType | null @@ -181,6 +188,7 @@ export type UserWhereInput = { name?: Prisma.StringFilter<"User"> | string email?: Prisma.StringFilter<"User"> | string password?: Prisma.StringFilter<"User"> | string + banned?: Prisma.BoolFilter<"User"> | boolean createdAt?: Prisma.DateTimeFilter<"User"> | Date | string games?: Prisma.GameListRelationFilter dailyResults?: Prisma.DailyResultListRelationFilter @@ -191,6 +199,7 @@ export type UserOrderByWithRelationInput = { name?: Prisma.SortOrder email?: Prisma.SortOrder password?: Prisma.SortOrder + banned?: Prisma.SortOrder createdAt?: Prisma.SortOrder games?: Prisma.GameOrderByRelationAggregateInput dailyResults?: Prisma.DailyResultOrderByRelationAggregateInput @@ -204,6 +213,7 @@ export type UserWhereUniqueInput = Prisma.AtLeast<{ NOT?: Prisma.UserWhereInput | Prisma.UserWhereInput[] name?: Prisma.StringFilter<"User"> | string password?: Prisma.StringFilter<"User"> | string + banned?: Prisma.BoolFilter<"User"> | boolean createdAt?: Prisma.DateTimeFilter<"User"> | Date | string games?: Prisma.GameListRelationFilter dailyResults?: Prisma.DailyResultListRelationFilter @@ -214,6 +224,7 @@ export type UserOrderByWithAggregationInput = { name?: Prisma.SortOrder email?: Prisma.SortOrder password?: Prisma.SortOrder + banned?: Prisma.SortOrder createdAt?: Prisma.SortOrder _count?: Prisma.UserCountOrderByAggregateInput _max?: Prisma.UserMaxOrderByAggregateInput @@ -228,6 +239,7 @@ export type UserScalarWhereWithAggregatesInput = { name?: Prisma.StringWithAggregatesFilter<"User"> | string email?: Prisma.StringWithAggregatesFilter<"User"> | string password?: Prisma.StringWithAggregatesFilter<"User"> | string + banned?: Prisma.BoolWithAggregatesFilter<"User"> | boolean createdAt?: Prisma.DateTimeWithAggregatesFilter<"User"> | Date | string } @@ -236,6 +248,7 @@ export type UserCreateInput = { name: string email: string password: string + banned?: boolean createdAt?: Date | string games?: Prisma.GameCreateNestedManyWithoutUserInput dailyResults?: Prisma.DailyResultCreateNestedManyWithoutUserInput @@ -246,6 +259,7 @@ export type UserUncheckedCreateInput = { name: string email: string password: string + banned?: boolean createdAt?: Date | string games?: Prisma.GameUncheckedCreateNestedManyWithoutUserInput dailyResults?: Prisma.DailyResultUncheckedCreateNestedManyWithoutUserInput @@ -256,6 +270,7 @@ export type UserUpdateInput = { name?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.StringFieldUpdateOperationsInput | string + banned?: Prisma.BoolFieldUpdateOperationsInput | boolean createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string games?: Prisma.GameUpdateManyWithoutUserNestedInput dailyResults?: Prisma.DailyResultUpdateManyWithoutUserNestedInput @@ -266,6 +281,7 @@ export type UserUncheckedUpdateInput = { name?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.StringFieldUpdateOperationsInput | string + banned?: Prisma.BoolFieldUpdateOperationsInput | boolean createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string games?: Prisma.GameUncheckedUpdateManyWithoutUserNestedInput dailyResults?: Prisma.DailyResultUncheckedUpdateManyWithoutUserNestedInput @@ -276,6 +292,7 @@ export type UserCreateManyInput = { name: string email: string password: string + banned?: boolean createdAt?: Date | string } @@ -284,6 +301,7 @@ export type UserUpdateManyMutationInput = { name?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.StringFieldUpdateOperationsInput | string + banned?: Prisma.BoolFieldUpdateOperationsInput | boolean createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string } @@ -292,6 +310,7 @@ export type UserUncheckedUpdateManyInput = { name?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.StringFieldUpdateOperationsInput | string + banned?: Prisma.BoolFieldUpdateOperationsInput | boolean createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string } @@ -300,6 +319,7 @@ export type UserCountOrderByAggregateInput = { name?: Prisma.SortOrder email?: Prisma.SortOrder password?: Prisma.SortOrder + banned?: Prisma.SortOrder createdAt?: Prisma.SortOrder } @@ -308,6 +328,7 @@ export type UserMaxOrderByAggregateInput = { name?: Prisma.SortOrder email?: Prisma.SortOrder password?: Prisma.SortOrder + banned?: Prisma.SortOrder createdAt?: Prisma.SortOrder } @@ -316,6 +337,7 @@ export type UserMinOrderByAggregateInput = { name?: Prisma.SortOrder email?: Prisma.SortOrder password?: Prisma.SortOrder + banned?: Prisma.SortOrder createdAt?: Prisma.SortOrder } @@ -328,6 +350,10 @@ export type StringFieldUpdateOperationsInput = { set?: string } +export type BoolFieldUpdateOperationsInput = { + set?: boolean +} + export type DateTimeFieldUpdateOperationsInput = { set?: Date | string } @@ -365,6 +391,7 @@ export type UserCreateWithoutGamesInput = { name: string email: string password: string + banned?: boolean createdAt?: Date | string dailyResults?: Prisma.DailyResultCreateNestedManyWithoutUserInput } @@ -374,6 +401,7 @@ export type UserUncheckedCreateWithoutGamesInput = { name: string email: string password: string + banned?: boolean createdAt?: Date | string dailyResults?: Prisma.DailyResultUncheckedCreateNestedManyWithoutUserInput } @@ -399,6 +427,7 @@ export type UserUpdateWithoutGamesInput = { name?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.StringFieldUpdateOperationsInput | string + banned?: Prisma.BoolFieldUpdateOperationsInput | boolean createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string dailyResults?: Prisma.DailyResultUpdateManyWithoutUserNestedInput } @@ -408,6 +437,7 @@ export type UserUncheckedUpdateWithoutGamesInput = { name?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.StringFieldUpdateOperationsInput | string + banned?: Prisma.BoolFieldUpdateOperationsInput | boolean createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string dailyResults?: Prisma.DailyResultUncheckedUpdateManyWithoutUserNestedInput } @@ -417,6 +447,7 @@ export type UserCreateWithoutDailyResultsInput = { name: string email: string password: string + banned?: boolean createdAt?: Date | string games?: Prisma.GameCreateNestedManyWithoutUserInput } @@ -426,6 +457,7 @@ export type UserUncheckedCreateWithoutDailyResultsInput = { name: string email: string password: string + banned?: boolean createdAt?: Date | string games?: Prisma.GameUncheckedCreateNestedManyWithoutUserInput } @@ -451,6 +483,7 @@ export type UserUpdateWithoutDailyResultsInput = { name?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.StringFieldUpdateOperationsInput | string + banned?: Prisma.BoolFieldUpdateOperationsInput | boolean createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string games?: Prisma.GameUpdateManyWithoutUserNestedInput } @@ -460,6 +493,7 @@ export type UserUncheckedUpdateWithoutDailyResultsInput = { name?: Prisma.StringFieldUpdateOperationsInput | string email?: Prisma.StringFieldUpdateOperationsInput | string password?: Prisma.StringFieldUpdateOperationsInput | string + banned?: Prisma.BoolFieldUpdateOperationsInput | boolean createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string games?: Prisma.GameUncheckedUpdateManyWithoutUserNestedInput } @@ -509,6 +543,7 @@ export type UserSelect dailyResults?: boolean | Prisma.User$dailyResultsArgs @@ -520,6 +555,7 @@ export type UserSelectCreateManyAndReturn @@ -528,6 +564,7 @@ export type UserSelectUpdateManyAndReturn @@ -536,10 +573,11 @@ export type UserSelectScalar = { name?: boolean email?: boolean password?: boolean + banned?: boolean createdAt?: boolean } -export type UserOmit = runtime.Types.Extensions.GetOmit<"id" | "name" | "email" | "password" | "createdAt", ExtArgs["result"]["user"]> +export type UserOmit = runtime.Types.Extensions.GetOmit<"id" | "name" | "email" | "password" | "banned" | "createdAt", ExtArgs["result"]["user"]> export type UserInclude = { games?: boolean | Prisma.User$gamesArgs dailyResults?: boolean | Prisma.User$dailyResultsArgs @@ -559,6 +597,7 @@ export type $UserPayload composites: {} @@ -989,6 +1028,7 @@ export interface UserFieldRefs { readonly name: Prisma.FieldRef<"User", 'String'> readonly email: Prisma.FieldRef<"User", 'String'> readonly password: Prisma.FieldRef<"User", 'String'> + readonly banned: Prisma.FieldRef<"User", 'Boolean'> readonly createdAt: Prisma.FieldRef<"User", 'DateTime'> } diff --git a/package.json b/package.json index 421d915..b40032c 100644 --- a/package.json +++ b/package.json @@ -12,8 +12,10 @@ "postinstall": "npx node-gyp rebuild --directory node_modules/.pnpm/better-sqlite3@12.8.0/node_modules/better-sqlite3 2>/dev/null || true" }, "dependencies": { + "@panva/hkdf": "^1.2.1", "@prisma/client": "^7.7.0", "bcryptjs": "^3.0.3", + "jose": "^6.2.2", "next": "16.2.3", "next-auth": "5.0.0-beta.30", "react": "19.2.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f8eda6e..0d1cfb8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,12 +8,18 @@ importers: .: dependencies: + '@panva/hkdf': + specifier: ^1.2.1 + version: 1.2.1 '@prisma/client': specifier: ^7.7.0 version: 7.7.0(prisma@7.7.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(better-sqlite3@12.8.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3) bcryptjs: specifier: ^3.0.3 version: 3.0.3 + jose: + specifier: ^6.2.2 + version: 6.2.2 next: specifier: 16.2.3 version: 16.2.3(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) diff --git a/prisma/migrations/20260411125349_add_banned_to_user/migration.sql b/prisma/migrations/20260411125349_add_banned_to_user/migration.sql new file mode 100644 index 0000000..e2c48b5 --- /dev/null +++ b/prisma/migrations/20260411125349_add_banned_to_user/migration.sql @@ -0,0 +1,17 @@ +-- RedefineTables +PRAGMA defer_foreign_keys=ON; +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_User" ( + "id" TEXT NOT NULL PRIMARY KEY, + "name" TEXT NOT NULL, + "email" TEXT NOT NULL, + "password" TEXT NOT NULL, + "banned" BOOLEAN NOT NULL DEFAULT false, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP +); +INSERT INTO "new_User" ("createdAt", "email", "id", "name", "password") SELECT "createdAt", "email", "id", "name", "password" FROM "User"; +DROP TABLE "User"; +ALTER TABLE "new_User" RENAME TO "User"; +CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); +PRAGMA foreign_keys=ON; +PRAGMA defer_foreign_keys=OFF; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index bc5b462..8a50d74 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -12,6 +12,7 @@ model User { name String email String @unique password String + banned Boolean @default(false) createdAt DateTime @default(now()) games Game[] dailyResults DailyResult[] diff --git a/proxy.ts b/proxy.ts new file mode 100644 index 0000000..2214f3d --- /dev/null +++ b/proxy.ts @@ -0,0 +1,55 @@ +import { NextRequest, NextResponse } from "next/server"; +import { jwtDecrypt } from "jose"; +import { hkdf } from "@panva/hkdf"; + +const ADMIN_EMAIL = process.env.ADMIN_EMAIL; + +async function getDerivedEncryptionKey(secret: string, salt: string) { + return hkdf( + "sha256", + secret, + salt, + `Auth.js Generated Encryption Key (${salt})`, + 64, + ); +} + +async function getEmailFromRequest(req: NextRequest): Promise { + const secret = process.env.AUTH_SECRET; + if (!secret) return null; + + const cookieName = + process.env.NODE_ENV === "production" + ? "__Secure-authjs.session-token" + : "authjs.session-token"; + + const token = req.cookies.get(cookieName)?.value; + if (!token) return null; + + try { + const encryptionKey = await getDerivedEncryptionKey(secret, cookieName); + const { payload } = await jwtDecrypt(token, encryptionKey, { + clockTolerance: 15, + keyManagementAlgorithms: ["dir"], + contentEncryptionAlgorithms: ["A256CBC-HS512", "A256GCM"], + }); + return (payload.email as string) ?? null; + } catch { + return null; + } +} + +export async function proxy(req: NextRequest) { + const email = await getEmailFromRequest(req); + if (!ADMIN_EMAIL || email !== ADMIN_EMAIL) { + if (req.nextUrl.pathname.startsWith("/api/")) { + return NextResponse.json({ error: "Accès refusé" }, { status: 403 }); + } + return NextResponse.redirect(new URL("/", req.url)); + } + return NextResponse.next(); +} + +export const config = { + matcher: ["/admin/:path*", "/api/admin/:path*"], +}; diff --git a/wikirush.db b/wikirush.db new file mode 100644 index 0000000..6ce84d4 Binary files /dev/null and b/wikirush.db differ