chore(api): add explicit type casting for request payloads
This commit is contained in:
@@ -16,8 +16,15 @@ export async function GET() {
|
|||||||
const games = await prisma.game.findMany({
|
const games = await prisma.game.findMany({
|
||||||
where: { userId: session.user.id },
|
where: { userId: session.user.id },
|
||||||
select: {
|
select: {
|
||||||
id: true, mode: true, startArticle: true, targetArticle: true,
|
id: true,
|
||||||
path: true, clicks: true, timeSeconds: true, won: true, playedAt: true,
|
mode: true,
|
||||||
|
startArticle: true,
|
||||||
|
targetArticle: true,
|
||||||
|
path: true,
|
||||||
|
clicks: true,
|
||||||
|
timeSeconds: true,
|
||||||
|
won: true,
|
||||||
|
playedAt: true,
|
||||||
},
|
},
|
||||||
orderBy: { playedAt: "desc" },
|
orderBy: { playedAt: "desc" },
|
||||||
});
|
});
|
||||||
@@ -25,8 +32,13 @@ export async function GET() {
|
|||||||
const dailyResults = await prisma.dailyResult.findMany({
|
const dailyResults = await prisma.dailyResult.findMany({
|
||||||
where: { userId: session.user.id },
|
where: { userId: session.user.id },
|
||||||
select: {
|
select: {
|
||||||
id: true, puzzleId: true, path: true, clicks: true,
|
id: true,
|
||||||
timeSeconds: true, won: true, playedAt: true,
|
puzzleId: true,
|
||||||
|
path: true,
|
||||||
|
clicks: true,
|
||||||
|
timeSeconds: true,
|
||||||
|
won: true,
|
||||||
|
playedAt: true,
|
||||||
},
|
},
|
||||||
orderBy: { playedAt: "desc" },
|
orderBy: { playedAt: "desc" },
|
||||||
});
|
});
|
||||||
@@ -34,7 +46,10 @@ export async function GET() {
|
|||||||
const data = {
|
const data = {
|
||||||
profile: user,
|
profile: user,
|
||||||
games: games.map((g) => ({ ...g, path: JSON.parse(g.path) as string[] })),
|
games: games.map((g) => ({ ...g, path: JSON.parse(g.path) as string[] })),
|
||||||
dailyResults: dailyResults.map((d) => ({ ...d, path: JSON.parse(d.path) as string[] })),
|
dailyResults: dailyResults.map((d) => ({
|
||||||
|
...d,
|
||||||
|
path: JSON.parse(d.path) as string[],
|
||||||
|
})),
|
||||||
exportedAt: new Date().toISOString(),
|
exportedAt: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ import { prisma } from "../../../../../lib/prisma";
|
|||||||
|
|
||||||
type Params = { params: Promise<{ id: string }> };
|
type Params = { params: Promise<{ id: string }> };
|
||||||
|
|
||||||
// PATCH /api/admin/daily/[id] — modifier un puzzle
|
// PATCH /api/admin/daily/[id] - modifier un puzzle
|
||||||
export async function PATCH(req: Request, { params }: Params) {
|
export async function PATCH(req: Request, { params }: Params) {
|
||||||
const { id } = await params;
|
const { id } = await params;
|
||||||
const { startArticle, targetArticle } = await req.json() as {
|
const { startArticle, targetArticle } = (await req.json()) as {
|
||||||
startArticle: string;
|
startArticle: string;
|
||||||
targetArticle: string;
|
targetArticle: string;
|
||||||
};
|
};
|
||||||
@@ -17,7 +17,7 @@ export async function PATCH(req: Request, { params }: Params) {
|
|||||||
return NextResponse.json(puzzle);
|
return NextResponse.json(puzzle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// DELETE /api/admin/daily/[id] — supprimer un puzzle
|
// DELETE /api/admin/daily/[id] - supprimer un puzzle
|
||||||
export async function DELETE(_req: Request, { params }: Params) {
|
export async function DELETE(_req: Request, { params }: Params) {
|
||||||
const { id } = await params;
|
const { id } = await params;
|
||||||
await prisma.dailyPuzzle.delete({ where: { id } });
|
await prisma.dailyPuzzle.delete({ where: { id } });
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { prisma } from "../../../../lib/prisma";
|
import { prisma } from "../../../../lib/prisma";
|
||||||
|
|
||||||
// GET /api/admin/daily — liste tous les puzzles
|
// GET /api/admin/daily - liste tous les puzzles
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
const puzzles = await prisma.dailyPuzzle.findMany({
|
const puzzles = await prisma.dailyPuzzle.findMany({
|
||||||
orderBy: { date: "desc" },
|
orderBy: { date: "desc" },
|
||||||
@@ -11,9 +11,9 @@ export async function GET() {
|
|||||||
return NextResponse.json(puzzles);
|
return NextResponse.json(puzzles);
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST /api/admin/daily — créer un puzzle pour une date
|
// POST /api/admin/daily - créer un puzzle pour une date
|
||||||
export async function POST(req: Request) {
|
export async function POST(req: Request) {
|
||||||
const { date, startArticle, targetArticle } = await req.json() as {
|
const { date, startArticle, targetArticle } = (await req.json()) as {
|
||||||
date: string;
|
date: string;
|
||||||
startArticle: string;
|
startArticle: string;
|
||||||
targetArticle: string;
|
targetArticle: string;
|
||||||
|
|||||||
@@ -10,48 +10,55 @@ export async function GET() {
|
|||||||
const since14 = new Date(todayStart);
|
const since14 = new Date(todayStart);
|
||||||
since14.setDate(since14.getDate() - 13);
|
since14.setDate(since14.getDate() - 13);
|
||||||
|
|
||||||
const [totalUsers, totalGames, todayGames, recentUsers, recentGames, modeStats, activityRaw] =
|
const [
|
||||||
await Promise.all([
|
totalUsers,
|
||||||
prisma.user.count(),
|
totalGames,
|
||||||
prisma.game.count(),
|
todayGames,
|
||||||
prisma.game.count({ where: { playedAt: { gte: todayStart } } }),
|
recentUsers,
|
||||||
prisma.user.findMany({
|
recentGames,
|
||||||
orderBy: { createdAt: "desc" },
|
modeStats,
|
||||||
take: 50,
|
activityRaw,
|
||||||
select: {
|
] = await Promise.all([
|
||||||
id: true,
|
prisma.user.count(),
|
||||||
name: true,
|
prisma.game.count(),
|
||||||
email: true,
|
prisma.game.count({ where: { playedAt: { gte: todayStart } } }),
|
||||||
banned: true,
|
prisma.user.findMany({
|
||||||
createdAt: true,
|
orderBy: { createdAt: "desc" },
|
||||||
_count: { select: { games: true } },
|
take: 50,
|
||||||
},
|
select: {
|
||||||
}),
|
id: true,
|
||||||
prisma.game.findMany({
|
name: true,
|
||||||
orderBy: { playedAt: "desc" },
|
email: true,
|
||||||
take: 50,
|
banned: true,
|
||||||
select: {
|
createdAt: true,
|
||||||
id: true,
|
_count: { select: { games: true } },
|
||||||
mode: true,
|
},
|
||||||
startArticle: true,
|
}),
|
||||||
targetArticle: true,
|
prisma.game.findMany({
|
||||||
clicks: true,
|
orderBy: { playedAt: "desc" },
|
||||||
timeSeconds: true,
|
take: 50,
|
||||||
won: true,
|
select: {
|
||||||
playedAt: true,
|
id: true,
|
||||||
user: { select: { name: true } },
|
mode: true,
|
||||||
},
|
startArticle: true,
|
||||||
}),
|
targetArticle: true,
|
||||||
prisma.game.groupBy({
|
clicks: true,
|
||||||
by: ["mode"],
|
timeSeconds: true,
|
||||||
_count: { id: true },
|
won: true,
|
||||||
_avg: { clicks: true, timeSeconds: true },
|
playedAt: true,
|
||||||
}),
|
user: { select: { name: true } },
|
||||||
prisma.game.findMany({
|
},
|
||||||
where: { playedAt: { gte: since14 } },
|
}),
|
||||||
select: { playedAt: 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
|
// Agréger l'activité par jour
|
||||||
const activityMap = new Map<string, number>();
|
const activityMap = new Map<string, number>();
|
||||||
|
|||||||
@@ -3,17 +3,17 @@ import { prisma } from "../../../../../lib/prisma";
|
|||||||
|
|
||||||
type Params = { params: Promise<{ id: string }> };
|
type Params = { params: Promise<{ id: string }> };
|
||||||
|
|
||||||
// DELETE /api/admin/users/[id] — supprimer un utilisateur
|
// DELETE /api/admin/users/[id] - supprimer un utilisateur
|
||||||
export async function DELETE(_req: Request, { params }: Params) {
|
export async function DELETE(_req: Request, { params }: Params) {
|
||||||
const { id } = await params;
|
const { id } = await params;
|
||||||
await prisma.user.delete({ where: { id } });
|
await prisma.user.delete({ where: { id } });
|
||||||
return NextResponse.json({ ok: true });
|
return NextResponse.json({ ok: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
// PATCH /api/admin/users/[id] — ban/unban
|
// PATCH /api/admin/users/[id] - ban/unban
|
||||||
export async function PATCH(req: Request, { params }: Params) {
|
export async function PATCH(req: Request, { params }: Params) {
|
||||||
const { id } = await params;
|
const { id } = await params;
|
||||||
const { banned } = await req.json() as { banned: boolean };
|
const { banned } = (await req.json()) as { banned: boolean };
|
||||||
const user = await prisma.user.update({ where: { id }, data: { banned } });
|
const user = await prisma.user.update({ where: { id }, data: { banned } });
|
||||||
return NextResponse.json({ id: user.id, banned: user.banned });
|
return NextResponse.json({ id: user.id, banned: user.banned });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,11 +13,13 @@ export async function GET() {
|
|||||||
take: 20,
|
take: 20,
|
||||||
});
|
});
|
||||||
|
|
||||||
return NextResponse.json(results.map((r, i) => ({
|
return NextResponse.json(
|
||||||
rank: i + 1,
|
results.map((r, i) => ({
|
||||||
name: r.user.name,
|
rank: i + 1,
|
||||||
clicks: r.clicks,
|
name: r.user.name,
|
||||||
timeSeconds: r.timeSeconds,
|
clicks: r.clicks,
|
||||||
userId: r.userId,
|
timeSeconds: r.timeSeconds,
|
||||||
})));
|
userId: r.userId,
|
||||||
|
})),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+39
-9
@@ -13,7 +13,9 @@ async function getOrCreatePuzzle() {
|
|||||||
if (existing) return existing;
|
if (existing) return existing;
|
||||||
|
|
||||||
const { start, target } = await pickTwoArticles();
|
const { start, target } = await pickTwoArticles();
|
||||||
return prisma.dailyPuzzle.create({ data: { date, startArticle: start, targetArticle: target } });
|
return prisma.dailyPuzzle.create({
|
||||||
|
data: { date, startArticle: start, targetArticle: target },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET - retourne le puzzle du jour + si l'utilisateur a déjà joué
|
// GET - retourne le puzzle du jour + si l'utilisateur a déjà joué
|
||||||
@@ -24,28 +26,49 @@ export async function GET() {
|
|||||||
let myResult = null;
|
let myResult = null;
|
||||||
if (session?.user?.id) {
|
if (session?.user?.id) {
|
||||||
myResult = await prisma.dailyResult.findUnique({
|
myResult = await prisma.dailyResult.findUnique({
|
||||||
where: { puzzleId_userId: { puzzleId: puzzle.id, userId: session.user.id } },
|
where: {
|
||||||
|
puzzleId_userId: { puzzleId: puzzle.id, userId: session.user.id },
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
puzzle: { id: puzzle.id, date: puzzle.date, startArticle: puzzle.startArticle, targetArticle: puzzle.targetArticle },
|
puzzle: {
|
||||||
|
id: puzzle.id,
|
||||||
|
date: puzzle.date,
|
||||||
|
startArticle: puzzle.startArticle,
|
||||||
|
targetArticle: puzzle.targetArticle,
|
||||||
|
},
|
||||||
alreadyPlayed: !!myResult,
|
alreadyPlayed: !!myResult,
|
||||||
myResult: myResult ? { clicks: myResult.clicks, timeSeconds: myResult.timeSeconds, won: myResult.won, path: JSON.parse(myResult.path) } : null,
|
myResult: myResult
|
||||||
|
? {
|
||||||
|
clicks: myResult.clicks,
|
||||||
|
timeSeconds: myResult.timeSeconds,
|
||||||
|
won: myResult.won,
|
||||||
|
path: JSON.parse(myResult.path),
|
||||||
|
}
|
||||||
|
: null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST - soumettre un résultat
|
// POST - soumettre un résultat
|
||||||
export async function POST(req: Request) {
|
export async function POST(req: Request) {
|
||||||
const session = await auth();
|
const session = await auth();
|
||||||
if (!session?.user?.id) return NextResponse.json({ error: "Non connecté" }, { status: 401 });
|
if (!session?.user?.id)
|
||||||
|
return NextResponse.json({ error: "Non connecté" }, { status: 401 });
|
||||||
|
|
||||||
const { puzzleId, path, clicks, timeSeconds, won } = await req.json() as {
|
const { puzzleId, path, clicks, timeSeconds, won } = (await req.json()) as {
|
||||||
puzzleId: string; path: string[]; clicks: number; timeSeconds: number; won: boolean;
|
puzzleId: string;
|
||||||
|
path: string[];
|
||||||
|
clicks: number;
|
||||||
|
timeSeconds: number;
|
||||||
|
won: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Vérifier que le puzzle est bien celui du jour
|
// Vérifier que le puzzle est bien celui du jour
|
||||||
const puzzle = await prisma.dailyPuzzle.findUnique({ where: { id: puzzleId } });
|
const puzzle = await prisma.dailyPuzzle.findUnique({
|
||||||
|
where: { id: puzzleId },
|
||||||
|
});
|
||||||
if (!puzzle || puzzle.date !== todayKey()) {
|
if (!puzzle || puzzle.date !== todayKey()) {
|
||||||
return NextResponse.json({ error: "Puzzle invalide" }, { status: 400 });
|
return NextResponse.json({ error: "Puzzle invalide" }, { status: 400 });
|
||||||
}
|
}
|
||||||
@@ -53,7 +76,14 @@ export async function POST(req: Request) {
|
|||||||
// Upsert - on n'enregistre qu'une fois
|
// Upsert - on n'enregistre qu'une fois
|
||||||
const result = await prisma.dailyResult.upsert({
|
const result = await prisma.dailyResult.upsert({
|
||||||
where: { puzzleId_userId: { puzzleId, userId: session.user.id } },
|
where: { puzzleId_userId: { puzzleId, userId: session.user.id } },
|
||||||
create: { puzzleId, userId: session.user.id, path: JSON.stringify(path), clicks, timeSeconds, won },
|
create: {
|
||||||
|
puzzleId,
|
||||||
|
userId: session.user.id,
|
||||||
|
path: JSON.stringify(path),
|
||||||
|
clicks,
|
||||||
|
timeSeconds,
|
||||||
|
won,
|
||||||
|
},
|
||||||
update: {},
|
update: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export async function POST(req: NextRequest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { mode, startArticle, targetArticle, path, clicks, timeSeconds, won } =
|
const { mode, startArticle, targetArticle, path, clicks, timeSeconds, won } =
|
||||||
await req.json() as {
|
(await req.json()) as {
|
||||||
mode: string;
|
mode: string;
|
||||||
startArticle: string;
|
startArticle: string;
|
||||||
targetArticle: string;
|
targetArticle: string;
|
||||||
@@ -53,6 +53,6 @@ export async function GET() {
|
|||||||
games.map((g) => ({
|
games.map((g) => ({
|
||||||
...g,
|
...g,
|
||||||
path: JSON.parse(g.path) as string[],
|
path: JSON.parse(g.path) as string[],
|
||||||
}))
|
})),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ export async function GET() {
|
|||||||
const wins = all.filter((g) => g.won);
|
const wins = all.filter((g) => g.won);
|
||||||
const wonGames = wins.filter((g) => g.clicks > 0);
|
const wonGames = wins.filter((g) => g.clicks > 0);
|
||||||
const avgClicks = wonGames.length
|
const avgClicks = wonGames.length
|
||||||
? Math.round(wonGames.reduce((s, g) => s + g.clicks, 0) / wonGames.length)
|
? Math.round(
|
||||||
|
wonGames.reduce((s, g) => s + g.clicks, 0) / wonGames.length,
|
||||||
|
)
|
||||||
: null;
|
: null;
|
||||||
const bestTime = wins.length
|
const bestTime = wins.length
|
||||||
? Math.min(...wins.map((g) => g.timeSeconds))
|
? Math.min(...wins.map((g) => g.timeSeconds))
|
||||||
|
|||||||
@@ -3,15 +3,27 @@ import bcrypt from "bcryptjs";
|
|||||||
import { prisma } from "../../../lib/prisma";
|
import { prisma } from "../../../lib/prisma";
|
||||||
|
|
||||||
export async function POST(req: NextRequest) {
|
export async function POST(req: NextRequest) {
|
||||||
const { name, email, password } = await req.json() as { name?: string; email?: string; password?: string };
|
const { name, email, password } = (await req.json()) as {
|
||||||
|
name?: string;
|
||||||
|
email?: string;
|
||||||
|
password?: string;
|
||||||
|
};
|
||||||
|
|
||||||
if (!name?.trim() || !email?.trim() || !password || password.length < 6) {
|
if (!name?.trim() || !email?.trim() || !password || password.length < 6) {
|
||||||
return NextResponse.json({ error: "Champs invalides (mot de passe min. 6 caractères)" }, { status: 400 });
|
return NextResponse.json(
|
||||||
|
{ error: "Champs invalides (mot de passe min. 6 caractères)" },
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const existing = await prisma.user.findUnique({ where: { email: email.toLowerCase() } });
|
const existing = await prisma.user.findUnique({
|
||||||
|
where: { email: email.toLowerCase() },
|
||||||
|
});
|
||||||
if (existing) {
|
if (existing) {
|
||||||
return NextResponse.json({ error: "Cet email est déjà utilisé" }, { status: 409 });
|
return NextResponse.json(
|
||||||
|
{ error: "Cet email est déjà utilisé" },
|
||||||
|
{ status: 409 },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const hashed = await bcrypt.hash(password, 10);
|
const hashed = await bcrypt.hash(password, 10);
|
||||||
@@ -19,5 +31,8 @@ export async function POST(req: NextRequest) {
|
|||||||
data: { name: name.trim(), email: email.toLowerCase(), password: hashed },
|
data: { name: name.trim(), email: email.toLowerCase(), password: hashed },
|
||||||
});
|
});
|
||||||
|
|
||||||
return NextResponse.json({ id: user.id, name: user.name, email: user.email }, { status: 201 });
|
return NextResponse.json(
|
||||||
|
{ id: user.id, name: user.name, email: user.email },
|
||||||
|
{ status: 201 },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,14 +28,14 @@ const PLAYER_TIMEOUT_MS = 15_000;
|
|||||||
function prunePlayers(room: Room) {
|
function prunePlayers(room: Room) {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
room.players = room.players.filter(
|
room.players = room.players.filter(
|
||||||
(p) => now - p.lastSeen < PLAYER_TIMEOUT_MS
|
(p) => now - p.lastSeen < PLAYER_TIMEOUT_MS,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// PATCH /api/rooms/[code]
|
// PATCH /api/rooms/[code]
|
||||||
export async function PATCH(
|
export async function PATCH(
|
||||||
request: NextRequest,
|
request: NextRequest,
|
||||||
{ params }: { params: Promise<{ code: string }> }
|
{ params }: { params: Promise<{ code: string }> },
|
||||||
) {
|
) {
|
||||||
const { code } = await params;
|
const { code } = await params;
|
||||||
const rooms = getRooms();
|
const rooms = getRooms();
|
||||||
@@ -62,14 +62,24 @@ export async function PATCH(
|
|||||||
switch (action) {
|
switch (action) {
|
||||||
// Rejoindre
|
// Rejoindre
|
||||||
case "join": {
|
case "join": {
|
||||||
if (!playerName || typeof playerName !== "string" || playerName.trim() === "") {
|
if (
|
||||||
|
!playerName ||
|
||||||
|
typeof playerName !== "string" ||
|
||||||
|
playerName.trim() === ""
|
||||||
|
) {
|
||||||
return Response.json({ error: "Pseudo invalide" }, { status: 400 });
|
return Response.json({ error: "Pseudo invalide" }, { status: 400 });
|
||||||
}
|
}
|
||||||
if (room.players.length >= room.maxPlayers) {
|
if (room.players.length >= room.maxPlayers) {
|
||||||
return Response.json({ error: `Salle pleine (${room.maxPlayers} joueurs max)` }, { status: 409 });
|
return Response.json(
|
||||||
|
{ error: `Salle pleine (${room.maxPlayers} joueurs max)` },
|
||||||
|
{ status: 409 },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (room.phase !== "waiting" && room.phase !== "results") {
|
if (room.phase !== "waiting" && room.phase !== "results") {
|
||||||
return Response.json({ error: "Partie en cours, attends la prochaine manche" }, { status: 409 });
|
return Response.json(
|
||||||
|
{ error: "Partie en cours, attends la prochaine manche" },
|
||||||
|
{ status: 409 },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newId = generatePlayerId();
|
const newId = generatePlayerId();
|
||||||
@@ -99,10 +109,16 @@ export async function PATCH(
|
|||||||
case "start": {
|
case "start": {
|
||||||
const host = room.players.find((p) => p.id === playerId);
|
const host = room.players.find((p) => p.id === playerId);
|
||||||
if (!host?.isHost) {
|
if (!host?.isHost) {
|
||||||
return Response.json({ error: "Seul l'hote peut demarrer" }, { status: 403 });
|
return Response.json(
|
||||||
|
{ error: "Seul l'hote peut demarrer" },
|
||||||
|
{ status: 403 },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (room.players.length < 1) {
|
if (room.players.length < 1) {
|
||||||
return Response.json({ error: "Pas assez de joueurs" }, { status: 400 });
|
return Response.json(
|
||||||
|
{ error: "Pas assez de joueurs" },
|
||||||
|
{ status: 400 },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!startArticle || !targetArticle) {
|
if (!startArticle || !targetArticle) {
|
||||||
return Response.json({ error: "Articles manquants" }, { status: 400 });
|
return Response.json({ error: "Articles manquants" }, { status: 400 });
|
||||||
@@ -174,7 +190,7 @@ export async function PATCH(
|
|||||||
|
|
||||||
// 1er joueur a gagner = +10 points
|
// 1er joueur a gagner = +10 points
|
||||||
const alreadyWon = room.players.some(
|
const alreadyWon = room.players.some(
|
||||||
(p) => p.hasWon && p.id !== player.id
|
(p) => p.hasWon && p.id !== player.id,
|
||||||
);
|
);
|
||||||
if (!alreadyWon) {
|
if (!alreadyWon) {
|
||||||
player.score += 10;
|
player.score += 10;
|
||||||
@@ -190,7 +206,10 @@ export async function PATCH(
|
|||||||
case "nextRound": {
|
case "nextRound": {
|
||||||
const host = room.players.find((p) => p.id === playerId);
|
const host = room.players.find((p) => p.id === playerId);
|
||||||
if (!host?.isHost) {
|
if (!host?.isHost) {
|
||||||
return Response.json({ error: "Seul l'hote peut continuer" }, { status: 403 });
|
return Response.json(
|
||||||
|
{ error: "Seul l'hote peut continuer" },
|
||||||
|
{ status: 403 },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
room.phase = "waiting";
|
room.phase = "waiting";
|
||||||
room.roundWinner = null;
|
room.roundWinner = null;
|
||||||
@@ -207,7 +226,10 @@ export async function PATCH(
|
|||||||
case "resetGame": {
|
case "resetGame": {
|
||||||
const host = room.players.find((p) => p.id === playerId);
|
const host = room.players.find((p) => p.id === playerId);
|
||||||
if (!host?.isHost) {
|
if (!host?.isHost) {
|
||||||
return Response.json({ error: "Seul l'hote peut reinitialiser" }, { status: 403 });
|
return Response.json(
|
||||||
|
{ error: "Seul l'hote peut reinitialiser" },
|
||||||
|
{ status: 403 },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
room.phase = "waiting";
|
room.phase = "waiting";
|
||||||
room.round = 0;
|
room.round = 0;
|
||||||
@@ -226,4 +248,3 @@ export async function PATCH(
|
|||||||
return Response.json({ error: "Action inconnue" }, { status: 400 });
|
return Response.json({ error: "Action inconnue" }, { status: 400 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+18
-4
@@ -76,14 +76,28 @@ function pruneOldRooms(rooms: Map<string, Room>) {
|
|||||||
// Response: { room: Room, playerId: string }
|
// Response: { room: Room, playerId: string }
|
||||||
export async function POST(request: NextRequest) {
|
export async function POST(request: NextRequest) {
|
||||||
const body = await request.json();
|
const body = await request.json();
|
||||||
const { playerName, maxPlayers, totalRounds } = body as { playerName: string; maxPlayers?: number; totalRounds?: number };
|
const { playerName, maxPlayers, totalRounds } = body as {
|
||||||
|
playerName: string;
|
||||||
|
maxPlayers?: number;
|
||||||
|
totalRounds?: number;
|
||||||
|
};
|
||||||
|
|
||||||
if (!playerName || typeof playerName !== "string" || playerName.trim() === "") {
|
if (
|
||||||
|
!playerName ||
|
||||||
|
typeof playerName !== "string" ||
|
||||||
|
playerName.trim() === ""
|
||||||
|
) {
|
||||||
return Response.json({ error: "Pseudo invalide" }, { status: 400 });
|
return Response.json({ error: "Pseudo invalide" }, { status: 400 });
|
||||||
}
|
}
|
||||||
|
|
||||||
const clampedMax = Math.min(Math.max(typeof maxPlayers === "number" ? Math.floor(maxPlayers) : 16, 2), 16);
|
const clampedMax = Math.min(
|
||||||
const clampedRounds = Math.min(Math.max(typeof totalRounds === "number" ? Math.floor(totalRounds) : 3, 1), 10);
|
Math.max(typeof maxPlayers === "number" ? Math.floor(maxPlayers) : 16, 2),
|
||||||
|
16,
|
||||||
|
);
|
||||||
|
const clampedRounds = Math.min(
|
||||||
|
Math.max(typeof totalRounds === "number" ? Math.floor(totalRounds) : 3, 1),
|
||||||
|
10,
|
||||||
|
);
|
||||||
|
|
||||||
const rooms = getRooms();
|
const rooms = getRooms();
|
||||||
pruneOldRooms(rooms);
|
pruneOldRooms(rooms);
|
||||||
|
|||||||
@@ -33,7 +33,9 @@ export async function GET(_req: Request, { params }: Params) {
|
|||||||
? Math.round(won.reduce((s, g) => s + g.clicks, 0) / won.length)
|
? Math.round(won.reduce((s, g) => s + g.clicks, 0) / won.length)
|
||||||
: null;
|
: null;
|
||||||
const bestClicks = won.length ? Math.min(...won.map((g) => g.clicks)) : null;
|
const bestClicks = won.length ? Math.min(...won.map((g) => g.clicks)) : null;
|
||||||
const bestTime = won.length ? Math.min(...won.map((g) => g.timeSeconds)) : null;
|
const bestTime = won.length
|
||||||
|
? Math.min(...won.map((g) => g.timeSeconds))
|
||||||
|
: null;
|
||||||
const avgTime = won.length
|
const avgTime = won.length
|
||||||
? won.reduce((s, g) => s + g.timeSeconds, 0) / won.length
|
? won.reduce((s, g) => s + g.timeSeconds, 0) / won.length
|
||||||
: null;
|
: null;
|
||||||
|
|||||||
Reference in New Issue
Block a user