sync
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
"use server";
|
||||
|
||||
import { cookies } from "next/headers";
|
||||
import { redirect } from "next/navigation";
|
||||
import { ADMIN_SESSION_COOKIE } from "@/lib/auth/session";
|
||||
import { requireWriteAccess } from "@/lib/auth/require-session";
|
||||
import { applyCoinsDeltaToRcBalance } from "@/lib/coins-rc";
|
||||
import {
|
||||
buildDashboardHref,
|
||||
@@ -25,10 +24,7 @@ function parsePositiveCoins(raw: FormDataEntryValue | null): bigint | null {
|
||||
}
|
||||
|
||||
export async function addSystemSupply(formData: FormData) {
|
||||
const cookieStore = await cookies();
|
||||
if (cookieStore.get(ADMIN_SESSION_COOKIE)?.value !== "1") {
|
||||
redirect("/login");
|
||||
}
|
||||
await requireWriteAccess();
|
||||
|
||||
const tabRaw = String(formData.get("tab") ?? "");
|
||||
const tab: AdminDashboardTab =
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
"use server";
|
||||
|
||||
import { cookies } from "next/headers";
|
||||
import { redirect } from "next/navigation";
|
||||
import { ADMIN_SESSION_COOKIE } from "@/lib/auth/session";
|
||||
import { requireWriteAccess } from "@/lib/auth/require-session";
|
||||
import { parseStoredCoins } from "@/lib/coins-rc";
|
||||
import { createAdminSupabase } from "@/lib/supabase/admin";
|
||||
|
||||
@@ -38,10 +37,7 @@ function normalizeSettingValue(
|
||||
}
|
||||
|
||||
export async function updateSetting(formData: FormData) {
|
||||
const cookieStore = await cookies();
|
||||
if (cookieStore.get(ADMIN_SESSION_COOKIE)?.value !== "1") {
|
||||
redirect("/login");
|
||||
}
|
||||
await requireWriteAccess();
|
||||
|
||||
const key = String(formData.get("key") ?? "").trim();
|
||||
if (!key) {
|
||||
@@ -71,10 +67,7 @@ export async function updateSetting(formData: FormData) {
|
||||
}
|
||||
|
||||
export async function insertSetting(formData: FormData) {
|
||||
const cookieStore = await cookies();
|
||||
if (cookieStore.get(ADMIN_SESSION_COOKIE)?.value !== "1") {
|
||||
redirect("/login");
|
||||
}
|
||||
await requireWriteAccess();
|
||||
|
||||
const key = String(formData.get("newKey") ?? "").trim();
|
||||
const value = normalizeValue(formData.get("newValue"));
|
||||
@@ -102,10 +95,7 @@ export async function insertSetting(formData: FormData) {
|
||||
}
|
||||
|
||||
export async function deleteSetting(formData: FormData) {
|
||||
const cookieStore = await cookies();
|
||||
if (cookieStore.get(ADMIN_SESSION_COOKIE)?.value !== "1") {
|
||||
redirect("/login");
|
||||
}
|
||||
await requireWriteAccess();
|
||||
|
||||
const key = String(formData.get("key") ?? "").trim();
|
||||
if (!key) {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
"use server";
|
||||
|
||||
import { cookies } from "next/headers";
|
||||
import { redirect } from "next/navigation";
|
||||
import { ADMIN_SESSION_COOKIE } from "@/lib/auth/session";
|
||||
import { requireWriteAccess } from "@/lib/auth/require-session";
|
||||
import {
|
||||
buildDashboardHref,
|
||||
type AdminDashboardTab,
|
||||
@@ -19,10 +18,7 @@ function parseScoreField(raw: FormDataEntryValue | null): number | null {
|
||||
}
|
||||
|
||||
export async function updateUserCcRc(formData: FormData) {
|
||||
const cookieStore = await cookies();
|
||||
if (cookieStore.get(ADMIN_SESSION_COOKIE)?.value !== "1") {
|
||||
redirect("/login");
|
||||
}
|
||||
await requireWriteAccess();
|
||||
|
||||
const userId = Number(formData.get("userId"));
|
||||
const tabRaw = String(formData.get("tab") ?? "");
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { getClientIp } from "@/lib/auth/client-ip";
|
||||
import { verifyAdminCredentials } from "@/lib/auth/credentials";
|
||||
import { verifyCredentials } from "@/lib/auth/credentials";
|
||||
import {
|
||||
roleToSessionCookieValue,
|
||||
} from "@/lib/auth/roles";
|
||||
import {
|
||||
checkLoginRateLimit,
|
||||
clearLoginAttempts,
|
||||
@@ -54,7 +57,8 @@ export async function POST(request: Request) {
|
||||
password = String(formData.get("password") ?? "");
|
||||
}
|
||||
|
||||
if (!verifyAdminCredentials(username, password)) {
|
||||
const role = verifyCredentials(username, password);
|
||||
if (!role) {
|
||||
recordFailedLogin(clientIp);
|
||||
if (contentType.includes("application/json")) {
|
||||
return invalidJson();
|
||||
@@ -68,13 +72,13 @@ export async function POST(request: Request) {
|
||||
const res = NextResponse.json({ ok: true });
|
||||
res.cookies.set(
|
||||
ADMIN_SESSION_COOKIE,
|
||||
"1",
|
||||
roleToSessionCookieValue(role),
|
||||
getSessionCookieSetOptions(request),
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
const res = NextResponse.redirect(publicRequestUrl(request, "/"));
|
||||
applySessionCookie(res, request);
|
||||
applySessionCookie(res, request, role);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { cookies } from "next/headers";
|
||||
import { ADMIN_SESSION_COOKIE } from "@/lib/auth/session";
|
||||
import { getSessionRole } from "@/lib/auth/require-session";
|
||||
import {
|
||||
parseMatchIdParam,
|
||||
readMatchLogFile,
|
||||
@@ -9,8 +8,8 @@ export async function GET(
|
||||
_request: Request,
|
||||
context: { params: Promise<{ matchId: string }> },
|
||||
) {
|
||||
const cookieStore = await cookies();
|
||||
if (cookieStore.get(ADMIN_SESSION_COOKIE)?.value !== "1") {
|
||||
const role = await getSessionRole();
|
||||
if (!role) {
|
||||
return Response.json({ error: "Unauthorized" }, { status: 401 });
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { cookies } from "next/headers";
|
||||
import { ADMIN_SESSION_COOKIE } from "@/lib/auth/session";
|
||||
import { getSessionRole } from "@/lib/auth/require-session";
|
||||
import { parseMatchmakerLogParam } from "@/lib/matchmaker-log-source";
|
||||
import { readMatchmakerLogFile } from "@/lib/matchmaker-logs-server";
|
||||
|
||||
const NO_STORE = { "Cache-Control": "no-store, max-age=0" };
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const cookieStore = await cookies();
|
||||
if (cookieStore.get(ADMIN_SESSION_COOKIE)?.value !== "1") {
|
||||
const role = await getSessionRole();
|
||||
if (!role) {
|
||||
return Response.json(
|
||||
{ error: "Unauthorized" },
|
||||
{ status: 401, headers: NO_STORE },
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { Fragment } from "react";
|
||||
import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import { cookies } from "next/headers";
|
||||
import { redirect } from "next/navigation";
|
||||
import { AdminHeader } from "@/components/admin-header";
|
||||
import { ADMIN_SESSION_COOKIE } from "@/lib/auth/session";
|
||||
import { requireSession } from "@/lib/auth/require-session";
|
||||
import {
|
||||
formatRcDecimalFromCoinsBigInt,
|
||||
formatRcLabelFromCoinsBigInt,
|
||||
@@ -58,10 +57,7 @@ export default async function LedgerBookPage({
|
||||
}: {
|
||||
searchParams: Promise<{ from?: string | string[]; to?: string | string[] }>;
|
||||
}) {
|
||||
const cookieStore = await cookies();
|
||||
if (cookieStore.get(ADMIN_SESSION_COOKIE)?.value !== "1") {
|
||||
redirect("/login");
|
||||
}
|
||||
await requireSession();
|
||||
|
||||
const sp = await searchParams;
|
||||
let fromStr = firstSearchParam(sp.from);
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import { cookies } from "next/headers";
|
||||
import { notFound, redirect } from "next/navigation";
|
||||
import { ADMIN_SESSION_COOKIE } from "@/lib/auth/session";
|
||||
import { notFound } from "next/navigation";
|
||||
import { requireSession } from "@/lib/auth/require-session";
|
||||
import { MatchLogColoredBody } from "@/components/match-log-colored-body";
|
||||
import {
|
||||
parseMatchIdParam,
|
||||
@@ -25,10 +24,7 @@ export default async function MatchLogPage({
|
||||
}: {
|
||||
params: Promise<{ matchId: string }>;
|
||||
}) {
|
||||
const cookieStore = await cookies();
|
||||
if (cookieStore.get(ADMIN_SESSION_COOKIE)?.value !== "1") {
|
||||
redirect("/login");
|
||||
}
|
||||
await requireSession();
|
||||
|
||||
const { matchId: raw } = await params;
|
||||
const matchId = parseMatchIdParam(raw);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import type { Metadata } from "next";
|
||||
import { cookies } from "next/headers";
|
||||
import { redirect } from "next/navigation";
|
||||
import { MatchmakerLogTerminal } from "@/components/matchmaker-log-terminal";
|
||||
import { ADMIN_SESSION_COOKIE } from "@/lib/auth/session";
|
||||
import { requireSession } from "@/lib/auth/require-session";
|
||||
import { parseMatchmakerLogParam } from "@/lib/matchmaker-log-source";
|
||||
import { readMatchmakerLogFile } from "@/lib/matchmaker-logs-server";
|
||||
|
||||
@@ -17,10 +15,7 @@ export default async function MatchmakerLogsPage({
|
||||
}: {
|
||||
searchParams: Promise<{ mklog?: string | string[] }>;
|
||||
}) {
|
||||
const cookieStore = await cookies();
|
||||
if (cookieStore.get(ADMIN_SESSION_COOKIE)?.value !== "1") {
|
||||
redirect("/login");
|
||||
}
|
||||
await requireSession();
|
||||
|
||||
const sp = await searchParams;
|
||||
const raw =
|
||||
|
||||
+27
-3
@@ -1,6 +1,8 @@
|
||||
import { AdminDashboard } from "@/components/admin-dashboard";
|
||||
import { AdminHeader } from "@/components/admin-header";
|
||||
import { EditUserCcRcOverlay } from "@/components/edit-user-cc-rc-overlay";
|
||||
import { isReadOnlyRole } from "@/lib/auth/roles";
|
||||
import { requireSession } from "@/lib/auth/require-session";
|
||||
import { loadDashboardStatsBundle } from "@/lib/dashboard-stats";
|
||||
import {
|
||||
normalizeLedgerDateRange,
|
||||
@@ -25,6 +27,10 @@ import {
|
||||
} from "@/lib/match-log-analysis-server";
|
||||
import type { MatchLogAnalysisResult } from "@/lib/match-log-parser";
|
||||
import { emptyMatchLogAnalysisResult } from "@/lib/match-log-parser";
|
||||
import {
|
||||
loadGeolocationAnalytics,
|
||||
type GeolocationAnalyticsResult,
|
||||
} from "@/lib/geolocation-analytics";
|
||||
import {
|
||||
loadPingAnalytics,
|
||||
type PingAnalyticsResult,
|
||||
@@ -78,6 +84,9 @@ export default async function Home({
|
||||
aplayers?: string | string[];
|
||||
}>;
|
||||
}) {
|
||||
const role = await requireSession();
|
||||
const readOnly = isReadOnlyRole(role);
|
||||
|
||||
const sp = await searchParams;
|
||||
const tabParam = firstSearchParam(sp.tab);
|
||||
const tab: AdminDashboardTab =
|
||||
@@ -138,6 +147,11 @@ export default async function Home({
|
||||
byCountries: [],
|
||||
error: null,
|
||||
};
|
||||
let geolocationAnalytics: GeolocationAnalyticsResult = {
|
||||
userAccounts: [],
|
||||
matches: [],
|
||||
error: null,
|
||||
};
|
||||
let statsBundle: Awaited<ReturnType<typeof loadDashboardStatsBundle>> | null =
|
||||
null;
|
||||
|
||||
@@ -272,7 +286,7 @@ export default async function Home({
|
||||
analysisFrom = range.from;
|
||||
analysisTo = range.to;
|
||||
analysisPlayerIds = parseAnalysisPlayerIds(sp.aplayers);
|
||||
const [matchLogResult, pingResult] = await Promise.all([
|
||||
const [matchLogResult, pingResult, geoResult] = await Promise.all([
|
||||
analyzeMatchLogsForMatches(
|
||||
matches,
|
||||
analysisFrom,
|
||||
@@ -280,20 +294,28 @@ export default async function Home({
|
||||
analysisPlayerIds,
|
||||
),
|
||||
loadPingAnalytics(supabase, analysisFrom, analysisTo, analysisPlayerIds),
|
||||
loadGeolocationAnalytics(
|
||||
supabase,
|
||||
users,
|
||||
analysisFrom,
|
||||
analysisTo,
|
||||
analysisPlayerIds,
|
||||
),
|
||||
]);
|
||||
matchAnalysis = matchLogResult;
|
||||
pingAnalytics = pingResult;
|
||||
geolocationAnalytics = geoResult;
|
||||
}
|
||||
}
|
||||
|
||||
let editUser: DbUser | null = null;
|
||||
if (Number.isInteger(editIdNum) && editIdNum >= 1) {
|
||||
if (!readOnly && Number.isInteger(editIdNum) && editIdNum >= 1) {
|
||||
editUser = users.find((u) => Number(u.id) === editIdNum) ?? null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex min-h-full flex-1 flex-col bg-zinc-50 dark:bg-zinc-950">
|
||||
<AdminHeader />
|
||||
<AdminHeader readOnly={readOnly} />
|
||||
{configError ? (
|
||||
<div className="px-6 pt-8">
|
||||
<div
|
||||
@@ -335,6 +357,8 @@ export default async function Home({
|
||||
analysisPlayerIds={analysisPlayerIds}
|
||||
matchAnalysis={matchAnalysis}
|
||||
pingAnalytics={pingAnalytics}
|
||||
geolocationAnalytics={geolocationAnalytics}
|
||||
readOnly={readOnly}
|
||||
/>
|
||||
{editUser ? (
|
||||
<EditUserCcRcOverlay
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import type { Metadata } from "next";
|
||||
import { cookies } from "next/headers";
|
||||
import { redirect } from "next/navigation";
|
||||
import { requireSession } from "@/lib/auth/require-session";
|
||||
import { isReadOnlyRole } from "@/lib/auth/roles";
|
||||
import { AdminHeader } from "@/components/admin-header";
|
||||
import { AdminSettingsEditor } from "@/components/admin-settings-editor";
|
||||
import { ADMIN_SESSION_COOKIE } from "@/lib/auth/session";
|
||||
import { createAdminSupabase } from "@/lib/supabase/admin";
|
||||
import type { DbSetting } from "@/types/database";
|
||||
|
||||
@@ -31,10 +30,8 @@ export default async function SettingsPage({
|
||||
addError?: string | string[];
|
||||
}>;
|
||||
}) {
|
||||
const cookieStore = await cookies();
|
||||
if (cookieStore.get(ADMIN_SESSION_COOKIE)?.value !== "1") {
|
||||
redirect("/login");
|
||||
}
|
||||
const role = await requireSession();
|
||||
const readOnly = isReadOnlyRole(role);
|
||||
|
||||
const sp = await searchParams;
|
||||
const saveError = firstSearchParam(sp.saveError) === "1";
|
||||
@@ -63,7 +60,7 @@ export default async function SettingsPage({
|
||||
|
||||
return (
|
||||
<div className="flex min-h-full flex-1 flex-col bg-zinc-50 dark:bg-zinc-950">
|
||||
<AdminHeader />
|
||||
<AdminHeader readOnly={readOnly} />
|
||||
<main className="flex-1 px-6 py-8">
|
||||
<div className="mx-auto mb-8 max-w-[900px]">
|
||||
<h1 className="text-xl font-semibold tracking-tight text-zinc-900 dark:text-zinc-50">
|
||||
@@ -96,6 +93,7 @@ export default async function SettingsPage({
|
||||
rows={rows}
|
||||
saveError={saveError}
|
||||
addError={addError}
|
||||
readOnly={readOnly}
|
||||
/>
|
||||
)}
|
||||
</main>
|
||||
|
||||
Reference in New Issue
Block a user