feat: voting averages

This commit is contained in:
TrèsAbhi committed 2024-09-01 15:46:39 -05:00
1 parent c3c16bf607
commit 2d2d31adf7
24 files changed
+643 -254

No files matched your search

@@ -0,0 +1,81 @@
import { NextRequest, NextResponse } from 'next/server';
import { isValidBlitzId } from '../../../../../core/blitz/isValidBlitzId';
import { tankDefinitions } from '../../../../../core/blitzkit/tankDefinitions';
import { usersDatabase } from '../../../../../databases/users';
import { BlitzkitResponse } from '../../../../../hooks/useTankVotes';
import { TankVoteCategory } from '../cast/route';
export interface TankVotes {
categories: Record<TankVoteCategory, number | null>;
votes: number;
last_updated?: number;
}
export async function GET(
request: NextRequest,
{ params }: { params: { id: string } },
) {
const id = Number(params.id);
const awaitedTankDefinitions = await tankDefinitions;
if (isNaN(id) || !awaitedTankDefinitions[id]) {
return NextResponse.json({
status: 'error',
error: 'INVALID_TANK_ID',
} satisfies BlitzkitResponse<TankVotes>);
}
const blitzIdString = request.nextUrl.searchParams.get('player');
const blitzId = Number(blitzIdString);
const blitzToken = request.nextUrl.searchParams.get('token');
if ((blitzIdString === null) !== (blitzToken === null)) {
return NextResponse.json({
status: 'error',
error: 'UNDEFINED_TOKEN_OR_PLAYER_ID',
} satisfies BlitzkitResponse<TankVotes>);
}
if (
blitzIdString !== null &&
(!(await isValidBlitzId(blitzId, blitzToken ?? undefined)) ||
isNaN(blitzId))
) {
return NextResponse.json({
status: 'error',
error: 'INVALID_TOKEN_OR_PLAYER_ID',
} satisfies BlitzkitResponse);
}
try {
const aggregation = await usersDatabase.tankVote.aggregate({
where: { id },
_count: { id: true },
_avg: {
easiness: true,
firepower: true,
maneuverability: true,
survivability: true,
},
});
const userVote = await usersDatabase.tankVote.findUnique({
where: { id, user_blitz_id: blitzId },
select: { last_updated: true },
});
return NextResponse.json({
status: 'ok',
data: {
categories: aggregation._avg,
votes: aggregation._count.id,
last_updated: userVote?.last_updated.getTime(),
},
} satisfies BlitzkitResponse<TankVotes>);
} catch (message) {
return NextResponse.json({
status: 'error',
error: 'DATABASE_ERROR',
message,
} satisfies BlitzkitResponse<TankVotes>);
}
}
+101
View File
@@ -0,0 +1,101 @@
import { NextRequest, NextResponse } from 'next/server';
import { isValidBlitzId } from '../../../../../core/blitz/isValidBlitzId';
import { tankDefinitions } from '../../../../../core/blitzkit/tankDefinitions';
import { usersDatabase } from '../../../../../databases/users';
import { BlitzkitResponse } from '../../../../../hooks/useTankVotes';
import { StarsInt } from '../../../../tools/tankopedia/[id]/components/Model/MetaSection/components/Stars';
export const TANK_VOTE_CATEGORIES = [
'easiness',
'firepower',
'maneuverability',
'survivability',
];
export type TankVoteCategory = (typeof TANK_VOTE_CATEGORIES)[number];
export async function GET(
request: NextRequest,
{ params }: { params: { id: string } },
) {
const tankId = Number(params.id);
const awaitedTankDefinitions = await tankDefinitions;
if (isNaN(tankId) || !awaitedTankDefinitions[tankId]) {
return NextResponse.json({
status: 'error',
error: 'INVALID_TANK_ID',
} satisfies BlitzkitResponse);
}
const blitzId = Number(request.nextUrl.searchParams.get('player'));
if (isNaN(blitzId) || !(await isValidBlitzId(blitzId))) {
return NextResponse.json({
status: 'error',
error: 'INVALID_PLAYER_ID',
} satisfies BlitzkitResponse);
}
const votes: Partial<Record<TankVoteCategory, StarsInt>> = {};
let recognizedVoteCategories = 0;
for (const category of TANK_VOTE_CATEGORIES) {
const voteRaw = request.nextUrl.searchParams.get(category);
if (voteRaw === null) continue;
const vote = Number(voteRaw);
if (isNaN(vote) || !Number.isInteger(vote) || vote < 1 || vote > 5) {
return NextResponse.json({
status: 'error',
error: 'INVALID_VOTE',
} satisfies BlitzkitResponse);
}
votes[category] = vote as StarsInt;
recognizedVoteCategories++;
}
if (recognizedVoteCategories === 0) {
return NextResponse.json({
status: 'error',
error: 'NO_VOTES',
} satisfies BlitzkitResponse);
}
try {
await usersDatabase.user.upsert({
where: { blitz_id: blitzId },
update: {
last_used: new Date(),
tank_votes: {
upsert: {
where: { id: tankId },
update: { ...votes, last_updated: new Date() },
create: { ...votes, id: tankId, last_updated: new Date() },
},
},
},
create: {
blitz_id: blitzId,
last_used: new Date(),
tank_votes: {
create: { ...votes, id: tankId, last_updated: new Date() },
},
},
});
return NextResponse.json({
status: 'ok',
data: undefined,
} satisfies BlitzkitResponse<undefined>);
} catch (message) {
return NextResponse.json({
status: 'error',
error: 'DATABASE_ERROR',
message,
} satisfies BlitzkitResponse);
}
}