Enforce admin CSRF, harden catalog translate, use CMS hotel name for PayPal.
Local Build and Deploy / deploy (push) Successful in 1m38s
Local Build and Deploy / deploy (push) Successful in 1m38s
Mutating withAdmin routes now require a double-submit CSRF token; translate is capped at 500 items with audit logging; PayPal descriptions prefer siteSettings hotel_name. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
6b884ad25a
commit
2de3696993
18 files changed
+218
-62
No files matched your search
@@ -19,6 +19,7 @@ import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { adminFetch } from "@/lib/admin-fetch";
|
||||
|
||||
// ── Types ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -62,7 +63,7 @@ async function runSseImport(
|
||||
onDone: (classname: string) => void,
|
||||
onComplete: (succeeded: number, failed: number) => void,
|
||||
): Promise<void> {
|
||||
const res = await fetch(url, {
|
||||
const res = await adminFetch(url, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
@@ -202,7 +203,7 @@ function SourcesManager({
|
||||
async function handleSave(src: Partial<CloneSource>) {
|
||||
setSaving(true);
|
||||
try {
|
||||
const res = await fetch("/api/admin/import/clone", {
|
||||
const res = await adminFetch("/api/admin/import/clone", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(src),
|
||||
@@ -224,7 +225,7 @@ function SourcesManager({
|
||||
async function handleDelete(src: CloneSource) {
|
||||
setDeletingId(src.id);
|
||||
try {
|
||||
const res = await fetch(
|
||||
const res = await adminFetch(
|
||||
`/api/admin/import/clone?id=${encodeURIComponent(src.id)}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
@@ -417,7 +418,7 @@ function FurniGrid({ source }: FurniGridProps) {
|
||||
});
|
||||
if (search) params.set("search", search);
|
||||
if (filterVal !== "all") params.set("filter", filterVal);
|
||||
const res = await fetch(`/api/admin/import/clone?${params}`);
|
||||
const res = await adminFetch(`/api/admin/import/clone?${params}`);
|
||||
const data = await res.json();
|
||||
if (!res.ok) {
|
||||
setError(data.error || "Failed to load");
|
||||
@@ -535,7 +536,7 @@ function FurniGrid({ source }: FurniGridProps) {
|
||||
async function cloneAll() {
|
||||
let names: string[] = [];
|
||||
try {
|
||||
const res = await fetch(
|
||||
const res = await adminFetch(
|
||||
`/api/admin/import/clone?source=${encodeURIComponent(source.id)}&action=clonable`,
|
||||
);
|
||||
const data = await res.json();
|
||||
@@ -913,7 +914,7 @@ export function ImportCloneClient() {
|
||||
|
||||
const fetchSources = useCallback(async () => {
|
||||
try {
|
||||
const res = await fetch("/api/admin/import/clone?action=sources");
|
||||
const res = await adminFetch("/api/admin/import/clone?action=sources");
|
||||
const data = await res.json();
|
||||
if (res.ok) {
|
||||
setSources(data.sources || []);
|
||||
|
||||
Reference in new issue
Block a user