From a2953e97c44c03d3587e0e53f83e87ba59543aad Mon Sep 17 00:00:00 2001
From: lekss361
Date: Sat, 23 May 2026 12:06:37 +0000
Subject: [PATCH] =?UTF-8?q?refactor(security):=20=D1=83=D0=B1=D1=80=D0=B0?=
=?UTF-8?q?=D1=82=D1=8C=20UI=20=D0=B2=D0=B2=D0=BE=D0=B4=D0=B0=20admin=20to?=
=?UTF-8?q?ken=20(backend=20=D0=BD=D0=B5=20=D1=82=D1=80=D0=B5=D0=B1=D1=83?=
=?UTF-8?q?=D0=B5=D1=82=20=D1=81=20PR=20#437)=20(#442)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
frontend/src/app/admin/leads/page.tsx | 51 +---
frontend/src/app/admin/scrape/all/page.tsx | 40 +--
.../src/app/admin/scrape/cadastre/page.tsx | 80 ++----
frontend/src/app/admin/scrape/geo/page.tsx | 41 +---
.../src/app/admin/scrape/objective/page.tsx | 63 +----
frontend/src/app/admin/scrape/page.tsx | 232 ++----------------
.../src/components/admin/BulkGeoPanel.tsx | 13 +-
.../src/components/admin/JobSettingsPanel.tsx | 19 +-
.../src/components/admin/ScrapeLogsPanel.tsx | 13 +-
9 files changed, 69 insertions(+), 483 deletions(-)
diff --git a/frontend/src/app/admin/leads/page.tsx b/frontend/src/app/admin/leads/page.tsx
index cbdbef25..7c7e96c6 100644
--- a/frontend/src/app/admin/leads/page.tsx
+++ b/frontend/src/app/admin/leads/page.tsx
@@ -68,11 +68,6 @@ interface LeadsStats {
}
export default function AdminLeadsPage() {
- const [token] = useState(() =>
- typeof window === "undefined"
- ? ""
- : (localStorage.getItem("admin_token") ?? ""),
- );
const [statusFilter, setStatusFilter] = useState("");
const [sourceFilter, setSourceFilter] = useState("");
const [convertedFilter, setConvertedFilter] = useState("");
@@ -81,36 +76,24 @@ export default function AdminLeadsPage() {
const limit = 50;
const stats = useQuery({
- queryKey: ["admin-leads-stats", token],
- queryFn: () =>
- apiFetch("/api/v1/admin/leads/stats?months=12", {
- headers: { "X-Admin-Token": token },
- }),
- enabled: !!token,
+ queryKey: ["admin-leads-stats"],
+ queryFn: () => apiFetch("/api/v1/admin/leads/stats?months=12"),
});
const funnelBySource = useQuery({
- queryKey: ["admin-leads-funnel-source", token],
+ queryKey: ["admin-leads-funnel-source"],
queryFn: () =>
apiFetch(
"/api/v1/admin/leads/funnel/by-source?months=12",
- {
- headers: { "X-Admin-Token": token },
- },
),
- enabled: !!token,
});
const funnelMonthly = useQuery({
- queryKey: ["admin-leads-funnel-monthly", token],
+ queryKey: ["admin-leads-funnel-monthly"],
queryFn: () =>
apiFetch(
"/api/v1/admin/leads/funnel/monthly?months=24",
- {
- headers: { "X-Admin-Token": token },
- },
),
- enabled: !!token,
});
const sankeyOption = useMemo(() => {
@@ -239,18 +222,13 @@ export default function AdminLeadsPage() {
}, [funnelMonthly.data]);
const sources = useQuery({
- queryKey: ["admin-leads-sources", token],
- queryFn: () =>
- apiFetch("/api/v1/admin/leads/sources", {
- headers: { "X-Admin-Token": token },
- }),
- enabled: !!token,
+ queryKey: ["admin-leads-sources"],
+ queryFn: () => apiFetch("/api/v1/admin/leads/sources"),
});
const leads = useQuery({
queryKey: [
"admin-leads",
- token,
statusFilter,
sourceFilter,
convertedFilter,
@@ -265,11 +243,8 @@ export default function AdminLeadsPage() {
if (sourceFilter) qs.set("source", sourceFilter);
if (convertedFilter !== "") qs.set("converted", convertedFilter);
if (search) qs.set("search", search);
- return apiFetch(`/api/v1/admin/leads/?${qs.toString()}`, {
- headers: { "X-Admin-Token": token },
- });
+ return apiFetch(`/api/v1/admin/leads/?${qs.toString()}`);
},
- enabled: !!token,
});
const fmtMoney = (v: number | null) =>
@@ -279,18 +254,6 @@ export default function AdminLeadsPage() {
? `${(v / 1e6).toFixed(2)} М ₽`
: v.toLocaleString("ru");
- if (!token) {
- return (
-
- Введите Admin Token на странице{" "}
-
- Скрапер
- {" "}
- — он сохранится для всех админ-страниц.
-
- );
- }
-
if (stats.isError || leads.isError) {
const err = String(stats.error ?? leads.error ?? "");
return (
diff --git a/frontend/src/app/admin/scrape/all/page.tsx b/frontend/src/app/admin/scrape/all/page.tsx
index b4feb6ff..d3635112 100644
--- a/frontend/src/app/admin/scrape/all/page.tsx
+++ b/frontend/src/app/admin/scrape/all/page.tsx
@@ -4,7 +4,7 @@ import { useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { apiFetch } from "@/lib/api";
-import { cardStyle, inputStyle, labelStyle, td, th } from "@/lib/adminStyles";
+import { cardStyle, labelStyle, td, th } from "@/lib/adminStyles";
import { BulkGeoPanel } from "@/components/admin/BulkGeoPanel";
import { JobSettingsPanel } from "@/components/admin/JobSettingsPanel";
@@ -67,46 +67,31 @@ function diffSecs(a: string | null, b: string | null): string {
}
export default function ScrapeAllAdminPage() {
- const [token, setToken] = useState(() =>
- typeof window === "undefined"
- ? ""
- : (localStorage.getItem("admin_token") ?? ""),
- );
const [filter, setFilter] = useState<
"all" | "kn" | "nspd" | "objective" | "nspd_geo"
>("all");
const [logsRunId, setLogsRunId] = useState("");
- const saveToken = (v: string) => {
- setToken(v);
- localStorage.setItem("admin_token", v);
- };
-
const runs = useQuery({
- queryKey: ["unified-runs", token, filter],
+ queryKey: ["unified-runs", filter],
queryFn: () => {
const q =
filter !== "all" ? `?scraper_type=${filter}&limit=30` : "?limit=30";
- return apiFetch(`/api/v1/admin/scrape/all/runs${q}`, {
- headers: { "X-Admin-Token": token },
- });
+ return apiFetch(`/api/v1/admin/scrape/all/runs${q}`);
},
- enabled: !!token,
refetchInterval: 5000,
});
const logs = useQuery({
- queryKey: ["unified-logs", token, filter, logsRunId],
+ queryKey: ["unified-logs", filter, logsRunId],
queryFn: () => {
const params = new URLSearchParams({ limit: "100" });
if (filter !== "all") params.set("scraper_type", filter);
if (logsRunId !== "") params.set("run_id", String(logsRunId));
return apiFetch(
`/api/v1/admin/scrape/all/logs?${params}`,
- { headers: { "X-Admin-Token": token } },
);
},
- enabled: !!token,
refetchInterval: 8000,
});
@@ -146,19 +131,6 @@ export default function ScrapeAllAdminPage() {
аудита.
-
-
{/* Сводка-плитки */}
-
+
{/* Bulk geo backfill */}
-
+
{/* Logs */}
diff --git a/frontend/src/app/admin/scrape/cadastre/page.tsx b/frontend/src/app/admin/scrape/cadastre/page.tsx
index 95958980..0ca8c312 100644
--- a/frontend/src/app/admin/scrape/cadastre/page.tsx
+++ b/frontend/src/app/admin/scrape/cadastre/page.tsx
@@ -122,25 +122,14 @@ function reqPerSec(job: CadastreJob): string {
// Query keys
// ---------------------------------------------------------------------------
-const jobsKey = (token: string) => ["admin", "cadastre", "jobs", token];
-const jobKey = (token: string, id: number) => [
- "admin",
- "cadastre",
- "job",
- id,
- token,
-];
+const jobsKey = () => ["admin", "cadastre", "jobs"];
+const jobKey = (id: number) => ["admin", "cadastre", "job", id];
// ---------------------------------------------------------------------------
// Component
// ---------------------------------------------------------------------------
export default function CadastreScrapeAdminPage() {
- const [token, setToken] = useState(() =>
- typeof window === "undefined"
- ? ""
- : (localStorage.getItem("admin_token") ?? ""),
- );
const [scope, setScope] = useState("pilot");
const [name, setName] = useState("");
const [quartersText, setQuartersText] = useState("");
@@ -152,35 +141,23 @@ export default function CadastreScrapeAdminPage() {
const queryClient = useQueryClient();
- const saveToken = (v: string) => {
- setToken(v);
- if (typeof window !== "undefined") {
- localStorage.setItem("admin_token", v);
- }
- };
-
// -------------------------------------------------------------------------
// Queries
// -------------------------------------------------------------------------
const jobs = useQuery({
- queryKey: jobsKey(token),
+ queryKey: jobsKey(),
queryFn: () =>
- apiFetch("/api/v1/admin/cadastre/jobs?limit=30", {
- headers: { "X-Admin-Token": token },
- }),
- enabled: !!token,
+ apiFetch("/api/v1/admin/cadastre/jobs?limit=30"),
refetchInterval: 5000,
});
// Per-job detail (only fetched when row is expanded)
const expandedJob = useQuery({
- queryKey: jobKey(token, expandedId ?? 0),
+ queryKey: jobKey(expandedId ?? 0),
queryFn: () =>
- apiFetch(`/api/v1/admin/cadastre/jobs/${expandedId}`, {
- headers: { "X-Admin-Token": token },
- }),
- enabled: !!token && expandedId !== null,
+ apiFetch(`/api/v1/admin/cadastre/jobs/${expandedId}`),
+ enabled: expandedId !== null,
refetchInterval: expandedId !== null ? 5000 : false,
});
@@ -204,17 +181,13 @@ export default function CadastreScrapeAdminPage() {
"/api/v1/admin/cadastre/jobs",
{
method: "POST",
- headers: {
- "X-Admin-Token": token,
- "Content-Type": "application/json",
- },
body: JSON.stringify(body),
},
);
},
onSuccess: (data) => {
setLastResp(data);
- void queryClient.invalidateQueries({ queryKey: jobsKey(token) });
+ void queryClient.invalidateQueries({ queryKey: jobsKey() });
},
});
@@ -222,11 +195,11 @@ export default function CadastreScrapeAdminPage() {
mutationFn: (id: number) =>
apiFetch<{ cancelled: boolean }>(
`/api/v1/admin/cadastre/jobs/${id}/cancel`,
- { method: "POST", headers: { "X-Admin-Token": token } },
+ { method: "POST" },
),
onSuccess: (_data, id) => {
- void queryClient.invalidateQueries({ queryKey: jobKey(token, id) });
- void queryClient.invalidateQueries({ queryKey: jobsKey(token) });
+ void queryClient.invalidateQueries({ queryKey: jobKey(id) });
+ void queryClient.invalidateQueries({ queryKey: jobsKey() });
},
});
@@ -234,11 +207,11 @@ export default function CadastreScrapeAdminPage() {
mutationFn: (id: number) =>
apiFetch<{ resumed: boolean }>(
`/api/v1/admin/cadastre/jobs/${id}/resume`,
- { method: "POST", headers: { "X-Admin-Token": token } },
+ { method: "POST" },
),
onSuccess: (_data, id) => {
- void queryClient.invalidateQueries({ queryKey: jobKey(token, id) });
- void queryClient.invalidateQueries({ queryKey: jobsKey(token) });
+ void queryClient.invalidateQueries({ queryKey: jobKey(id) });
+ void queryClient.invalidateQueries({ queryKey: jobsKey() });
},
});
@@ -248,7 +221,6 @@ export default function CadastreScrapeAdminPage() {
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
- if (!token) return;
if (scope === "manual_list" && !quartersText.trim()) {
alert("Для Manual list укажите хотя бы один квартал");
return;
@@ -662,22 +634,8 @@ export default function CadastreScrapeAdminPage() {
незавершённых targets.
- {/* Admin Token */}
-
-
{/* Create job form */}
-