feat: add revalidation functionality and integrate it into various components and API routes
This commit is contained in:
parent
bc1f114837
commit
727f1e760c
10 changed files with 331 additions and 106 deletions
1
apps/infoalloggi/.github/workflows/ci.yml
vendored
1
apps/infoalloggi/.github/workflows/ci.yml
vendored
|
|
@ -28,6 +28,7 @@ env:
|
||||||
SKIP_REDIS: "false"
|
SKIP_REDIS: "false"
|
||||||
SKEBBY_USER: "test"
|
SKEBBY_USER: "test"
|
||||||
SKEBBY_PASS : "test"
|
SKEBBY_PASS : "test"
|
||||||
|
REVALIDATION_SECRET: "test"
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ ENV KEYDB_URL="localhost:6380"
|
||||||
ENV TILES_URL="localhost:6379"
|
ENV TILES_URL="localhost:6379"
|
||||||
ENV SKEBBY_USER="mock"
|
ENV SKEBBY_USER="mock"
|
||||||
ENV SKEBBY_PASS="mock"
|
ENV SKEBBY_PASS="mock"
|
||||||
|
ENV REVALIDATION_SECRET="mock"
|
||||||
|
|
||||||
|
|
||||||
RUN SKIP_ENV_VALIDATION=1 npm run build
|
RUN SKIP_ENV_VALIDATION=1 npm run build
|
||||||
|
|
@ -128,6 +129,8 @@ ARG SKEBBY_USER
|
||||||
ENV SKEBBY_USER=$SKEBBY_USER
|
ENV SKEBBY_USER=$SKEBBY_USER
|
||||||
ARG SKEBBY_PASS
|
ARG SKEBBY_PASS
|
||||||
ENV SKEBBY_PASS=$SKEBBY_PASS
|
ENV SKEBBY_PASS=$SKEBBY_PASS
|
||||||
|
ENV REVALIDATION_SECRET="SWKpgaaLfsyeqV1eOT0WG7TUFBewir8kJXure3O37ki8Lt4Z4IiEgBW4zPHDdM5c"
|
||||||
|
|
||||||
|
|
||||||
RUN addgroup -g 1001 -S nodejs
|
RUN addgroup -g 1001 -S nodejs
|
||||||
RUN adduser -S nextjs -u 1001
|
RUN adduser -S nextjs -u 1001
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ const server = z.object({
|
||||||
TILES_URL: z.string(),
|
TILES_URL: z.string(),
|
||||||
SKEBBY_USER: z.string(),
|
SKEBBY_USER: z.string(),
|
||||||
SKEBBY_PASS: z.string(),
|
SKEBBY_PASS: z.string(),
|
||||||
|
REVALIDATION_SECRET: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -73,6 +74,7 @@ const processEnv = {
|
||||||
TILES_URL: process.env.TILES_URL,
|
TILES_URL: process.env.TILES_URL,
|
||||||
SKEBBY_USER: process.env.SKEBBY_USER,
|
SKEBBY_USER: process.env.SKEBBY_USER,
|
||||||
SKEBBY_PASS: process.env.SKEBBY_PASS,
|
SKEBBY_PASS: process.env.SKEBBY_PASS,
|
||||||
|
REVALIDATION_SECRET: process.env.REVALIDATION_SECRET,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Don't touch the part below
|
// Don't touch the part below
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,10 @@ import { format } from "date-fns";
|
||||||
import { it } from "date-fns/locale";
|
import { it } from "date-fns/locale";
|
||||||
import {
|
import {
|
||||||
CalendarIcon,
|
CalendarIcon,
|
||||||
|
CodeSquare,
|
||||||
Eye,
|
Eye,
|
||||||
Printer,
|
Printer,
|
||||||
|
RefreshCcw,
|
||||||
RotateCw,
|
RotateCw,
|
||||||
TriangleAlert,
|
TriangleAlert,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
|
@ -132,9 +134,15 @@ export const AnnuncioEditForm = ({ data }: { data: Annunci }) => {
|
||||||
|
|
||||||
const { mutateAsync: revalidate } =
|
const { mutateAsync: revalidate } =
|
||||||
api.settings.revalidateAnnuncio.useMutation({
|
api.settings.revalidateAnnuncio.useMutation({
|
||||||
|
onSettled: async () => {
|
||||||
|
toast.success("Revalidazione completata");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { mutateAsync: update } = api.settings.updateAnnuncio.useMutation({
|
||||||
onSettled: async () => {
|
onSettled: async () => {
|
||||||
toast.success(
|
toast.success(
|
||||||
"La revalidazione dell'annuncio è stata richiesta con successo,\n potrebbero volerci alcuni minuti prima che le modifiche siano visibili.",
|
"L'aggiornamento dell'annuncio è stata richiesta con successo,\n potrebbero volerci alcuni minuti prima che le modifiche siano visibili.",
|
||||||
{
|
{
|
||||||
duration: 5000,
|
duration: 5000,
|
||||||
},
|
},
|
||||||
|
|
@ -214,11 +222,20 @@ export const AnnuncioEditForm = ({ data }: { data: Annunci }) => {
|
||||||
onSubmit={form.handleSubmit(onSubmit)}
|
onSubmit={form.handleSubmit(onSubmit)}
|
||||||
>
|
>
|
||||||
<div className="mx-auto grid w-full max-w-7xl flex-1 auto-rows-max gap-4">
|
<div className="mx-auto grid w-full max-w-7xl flex-1 auto-rows-max gap-4">
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
<h1 className="whitespace-nowrap font-semibold text-2xl tracking-tight">
|
<h1 className="whitespace-nowrap font-semibold text-2xl tracking-tight">
|
||||||
Annuncio {data.codice}
|
Annuncio {data.codice}
|
||||||
</h1>
|
</h1>
|
||||||
<StatusBadge status={data.stato} />
|
<StatusBadge status={data.stato} />
|
||||||
|
<div className="ml-auto flex items-center gap-2">
|
||||||
|
<Button className="bg-green-500" size="sm" type="submit">
|
||||||
|
Salva
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
<Link href={`/annuncio/${data.codice}`} target="_blank">
|
<Link href={`/annuncio/${data.codice}`} target="_blank">
|
||||||
<Button
|
<Button
|
||||||
className="flex items-center gap-2"
|
className="flex items-center gap-2"
|
||||||
|
|
@ -242,12 +259,35 @@ export const AnnuncioEditForm = ({ data }: { data: Annunci }) => {
|
||||||
<Printer /> Scheda
|
<Printer /> Scheda
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
<Confirm
|
<Popover>
|
||||||
description="Sei sicuro di voler richiedere la revalidazione dell'annuncio? Questa operazione potrebbe richiedere alcuni minuti prima che le modifiche siano visibili e resetterà eventuali modifiche effettuate dopo la sincronizzazione giornaliera."
|
<PopoverTrigger asChild>
|
||||||
onConfirm={async () => {
|
<Button
|
||||||
await revalidate({ cod: data.codice });
|
className="flex items-center gap-2"
|
||||||
|
size="sm"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<CodeSquare /> Strumenti
|
||||||
|
</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="flex w-fit items-center gap-2">
|
||||||
|
<Button
|
||||||
|
className="flex items-center gap-2 bg-purple-500"
|
||||||
|
onClick={async () => {
|
||||||
|
await revalidate({
|
||||||
|
cod: data.codice,
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
title="Revalidazione Annuncio"
|
size="sm"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<RefreshCcw /> Rigenera pagina
|
||||||
|
</Button>
|
||||||
|
<Confirm
|
||||||
|
description="Sei sicuro di voler richiedere l'aggiornamento dell'annuncio? Questa operazione potrebbe richiedere alcuni minuti prima che le modifiche siano visibili e resetterà eventuali modifiche effettuate dopo la sincronizzazione giornaliera."
|
||||||
|
onConfirm={async () => {
|
||||||
|
await update({ cod: data.codice });
|
||||||
|
}}
|
||||||
|
title="Aggiornamento Annuncio"
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
className="flex items-center gap-2"
|
className="flex items-center gap-2"
|
||||||
|
|
@ -255,16 +295,11 @@ export const AnnuncioEditForm = ({ data }: { data: Annunci }) => {
|
||||||
type="button"
|
type="button"
|
||||||
variant="warning"
|
variant="warning"
|
||||||
>
|
>
|
||||||
<TriangleAlert /> Rivalida
|
<TriangleAlert /> Aggiorna
|
||||||
</Button>
|
</Button>
|
||||||
</Confirm>
|
</Confirm>
|
||||||
<div className="flex items-center gap-2 md:ml-auto">
|
</PopoverContent>
|
||||||
<Button size="sm" type="button" variant="outline">
|
</Popover>
|
||||||
Annulla
|
|
||||||
</Button>
|
|
||||||
<Button className="bg-green-500" size="sm" type="submit">
|
|
||||||
Salva
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid h-max gap-3 md:grid-cols-[1fr_250px] lg:grid-cols-3">
|
<div className="grid h-max gap-3 md:grid-cols-[1fr_250px] lg:grid-cols-3">
|
||||||
|
|
|
||||||
|
|
@ -236,7 +236,7 @@ export async function getStaticProps(
|
||||||
meta,
|
meta,
|
||||||
trpcState: ssg.dehydrate(),
|
trpcState: ssg.dehydrate(),
|
||||||
},
|
},
|
||||||
revalidate: 1,
|
revalidate: 21600, // 6 hours - ensures fresh data 4x per day
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
31
apps/infoalloggi/src/pages/api/revalidation.ts
Normal file
31
apps/infoalloggi/src/pages/api/revalidation.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
import { env } from "~/env.mjs";
|
||||||
|
|
||||||
|
export default async function handler(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse,
|
||||||
|
) {
|
||||||
|
if (req.query.secret !== env.REVALIDATION_SECRET) {
|
||||||
|
return res.status(401).json({ message: "Invalid token" });
|
||||||
|
}
|
||||||
|
const path = req.query.path as string;
|
||||||
|
|
||||||
|
if (!path) {
|
||||||
|
return res.status(400).json({ message: "Missing path parameter" });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await res.revalidate(`${path}`);
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
success: true,
|
||||||
|
message: `Page ${path} revalidated successfully`,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error revalidating:", err);
|
||||||
|
return res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: err instanceof Error ? err.message : "Unknown error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { RefreshCcw, TriangleAlert } from "lucide-react";
|
import { CodeSquare, RefreshCcw, TriangleAlert } from "lucide-react";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import { Confirm } from "~/components/confirm";
|
import { Confirm } from "~/components/confirm";
|
||||||
import { AreaRiservataLayout } from "~/components/Layout";
|
import { AreaRiservataLayout } from "~/components/Layout";
|
||||||
|
|
@ -6,6 +6,11 @@ import { LoadingPage } from "~/components/loading";
|
||||||
import { Status500 } from "~/components/status-page";
|
import { Status500 } from "~/components/status-page";
|
||||||
import { AnnunciTable } from "~/components/tables/annunci-tables";
|
import { AnnunciTable } from "~/components/tables/annunci-tables";
|
||||||
import { Button } from "~/components/ui/button";
|
import { Button } from "~/components/ui/button";
|
||||||
|
import {
|
||||||
|
Popover,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
} from "~/components/ui/popover";
|
||||||
import type { NextPageWithLayout } from "~/pages/_app";
|
import type { NextPageWithLayout } from "~/pages/_app";
|
||||||
import { generateSSGHelper } from "~/server/utils/ssgHelper";
|
import { generateSSGHelper } from "~/server/utils/ssgHelper";
|
||||||
import { api } from "~/utils/api";
|
import { api } from "~/utils/api";
|
||||||
|
|
@ -13,8 +18,7 @@ import { api } from "~/utils/api";
|
||||||
const Admin_Annunci: NextPageWithLayout = () => {
|
const Admin_Annunci: NextPageWithLayout = () => {
|
||||||
const { data, isLoading, refetch } = api.annunci.getAnnunciList.useQuery();
|
const { data, isLoading, refetch } = api.annunci.getAnnunciList.useQuery();
|
||||||
|
|
||||||
const { mutateAsync: revalidate } =
|
const { mutateAsync: update } = api.settings.updateAllAnnunci.useMutation({
|
||||||
api.settings.revalidateAllAnnunci.useMutation({
|
|
||||||
onSettled: async () => {
|
onSettled: async () => {
|
||||||
toast.success(
|
toast.success(
|
||||||
"La revalidazione dell'annuncio è stata richiesta con successo,\n potrebbero volerci alcuni minuti prima che le modifiche siano visibili.",
|
"La revalidazione dell'annuncio è stata richiesta con successo,\n potrebbero volerci alcuni minuti prima che le modifiche siano visibili.",
|
||||||
|
|
@ -24,6 +28,12 @@ const Admin_Annunci: NextPageWithLayout = () => {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const { mutateAsync: revalidate } =
|
||||||
|
api.settings.revalidateAllAnnunci.useMutation({
|
||||||
|
onSettled: async () => {
|
||||||
|
toast.success("Revalidazione completata");
|
||||||
|
},
|
||||||
|
});
|
||||||
if (isLoading) return <LoadingPage />;
|
if (isLoading) return <LoadingPage />;
|
||||||
if (!data) return <Status500 />;
|
if (!data) return <Status500 />;
|
||||||
return (
|
return (
|
||||||
|
|
@ -39,12 +49,33 @@ const Admin_Annunci: NextPageWithLayout = () => {
|
||||||
>
|
>
|
||||||
<RefreshCcw className="size-6" />
|
<RefreshCcw className="size-6" />
|
||||||
</button>
|
</button>
|
||||||
<Confirm
|
<Popover>
|
||||||
description="Sei sicuro di voler richiedere la revalidazione gli annunci? Questa operazione potrebbe richiedere alcuni minuti prima che le modifiche siano visibili e resetterà eventuali modifiche effettuate dopo la sincronizzazione giornaliera."
|
<PopoverTrigger asChild>
|
||||||
onConfirm={async () => {
|
<Button
|
||||||
|
className="flex items-center gap-2"
|
||||||
|
size="sm"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<CodeSquare /> Strumenti avanzati
|
||||||
|
</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="flex flex-col items-center gap-2">
|
||||||
|
<Button
|
||||||
|
className="flex items-center gap-2 bg-purple-500"
|
||||||
|
onClick={async () => {
|
||||||
await revalidate();
|
await revalidate();
|
||||||
}}
|
}}
|
||||||
title="Rivalida tutti gli annunci"
|
size="sm"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<RefreshCcw /> Rigenera pagine annnunci
|
||||||
|
</Button>
|
||||||
|
<Confirm
|
||||||
|
description="Sei sicuro di voler richiedere l'aggiornamento degli annunci? Questa operazione potrebbe richiedere alcuni minuti prima che le modifiche siano visibili e resetterà eventuali modifiche effettuate dopo la sincronizzazione giornaliera."
|
||||||
|
onConfirm={async () => {
|
||||||
|
await update();
|
||||||
|
}}
|
||||||
|
title="Aggiornamento Annunci"
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
className="flex items-center gap-2"
|
className="flex items-center gap-2"
|
||||||
|
|
@ -52,9 +83,11 @@ const Admin_Annunci: NextPageWithLayout = () => {
|
||||||
type="button"
|
type="button"
|
||||||
variant="warning"
|
variant="warning"
|
||||||
>
|
>
|
||||||
<TriangleAlert /> Rivalida tutti gli annunci
|
<TriangleAlert /> Aggiorna tutti gli annunci
|
||||||
</Button>
|
</Button>
|
||||||
</Confirm>
|
</Confirm>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<AnnunciTable data={data} />
|
<AnnunciTable data={data} />
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import {
|
||||||
createTRPCRouter,
|
createTRPCRouter,
|
||||||
publicProcedure,
|
publicProcedure,
|
||||||
} from "~/server/api/trpc";
|
} from "~/server/api/trpc";
|
||||||
|
import { getCodici_AnnunciHandler } from "~/server/controllers/annunci.controller";
|
||||||
import {
|
import {
|
||||||
addEtichetta,
|
addEtichetta,
|
||||||
getAllEtichette,
|
getAllEtichette,
|
||||||
|
|
@ -36,6 +37,10 @@ import {
|
||||||
newStringa,
|
newStringa,
|
||||||
updateStringhe,
|
updateStringhe,
|
||||||
} from "~/server/services/testi_stringhe.service";
|
} from "~/server/services/testi_stringhe.service";
|
||||||
|
import {
|
||||||
|
revalidate,
|
||||||
|
revalidateMultiple,
|
||||||
|
} from "~/server/utils/revalidationHelper";
|
||||||
import {
|
import {
|
||||||
zEtichettaId,
|
zEtichettaId,
|
||||||
zFlagsId,
|
zFlagsId,
|
||||||
|
|
@ -250,22 +255,20 @@ export const settingsRouter = createTRPCRouter({
|
||||||
stringaValue: input.stringaValue,
|
stringaValue: input.stringaValue,
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|
||||||
revalidateAllAnnunci: adminProcedure.mutation(async () => {
|
revalidateAllAnnunci: adminProcedure.mutation(async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${env.BACKENDSERVER_URL}/update`);
|
const annunciOnline = await getCodici_AnnunciHandler();
|
||||||
|
const { success, failed } = await revalidateMultiple(
|
||||||
if (!response.ok) {
|
annunciOnline.map((cod) => `/annuncio/${cod}`),
|
||||||
const errorData = await response.text().catch(() => "Unknown error");
|
|
||||||
throw new Error(
|
|
||||||
`Revalidation failed with status ${response.status}: ${errorData}`,
|
|
||||||
);
|
);
|
||||||
|
console.log(`Successfully revalidated pages: ${success.join(", ")}`);
|
||||||
|
if (failed.length > 0) {
|
||||||
|
failed.forEach(({ path, error }) => {
|
||||||
|
console.error(`Failed to revalidate ${path}: ${error}`);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json().catch(() => ({}));
|
|
||||||
return {
|
return {
|
||||||
status: "success",
|
status: "success",
|
||||||
details: data,
|
|
||||||
};
|
};
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Revalidation error:", err);
|
console.error("Revalidation error:", err);
|
||||||
|
|
@ -284,21 +287,9 @@ export const settingsRouter = createTRPCRouter({
|
||||||
)
|
)
|
||||||
.mutation(async ({ input }) => {
|
.mutation(async ({ input }) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
await revalidate(`/annuncio/${input.cod}`);
|
||||||
`${env.BACKENDSERVER_URL}/update-cod/${input.cod}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const errorData = await response.text().catch(() => "Unknown error");
|
|
||||||
throw new Error(
|
|
||||||
`Revalidation failed with status ${response.status}: ${errorData}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await response.json().catch(() => ({}));
|
|
||||||
return {
|
return {
|
||||||
status: "success",
|
status: "success",
|
||||||
details: data,
|
|
||||||
};
|
};
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Revalidation error:", err);
|
console.error("Revalidation error:", err);
|
||||||
|
|
@ -309,4 +300,74 @@ export const settingsRouter = createTRPCRouter({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
updateAllAnnunci: adminProcedure.mutation(async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${env.BACKENDSERVER_URL}/update`);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorData = await response.text().catch(() => "Unknown error");
|
||||||
|
throw new Error(
|
||||||
|
`Update failed with status ${response.status}: ${errorData}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json().catch(() => ({}));
|
||||||
|
const annunciOnline = await getCodici_AnnunciHandler();
|
||||||
|
const { success, failed } = await revalidateMultiple(
|
||||||
|
annunciOnline.map((cod) => `/annuncio/${cod}`),
|
||||||
|
);
|
||||||
|
console.log(`Successfully revalidated pages: ${success.join(", ")}`);
|
||||||
|
if (failed.length > 0) {
|
||||||
|
failed.forEach(({ path, error }) => {
|
||||||
|
console.error(`Failed to revalidate ${path}: ${error}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
status: "success",
|
||||||
|
details: data,
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Update error:", err);
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "INTERNAL_SERVER_ERROR",
|
||||||
|
message: err instanceof Error ? err.message : "Update failed",
|
||||||
|
cause: err,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
updateAnnuncio: adminProcedure
|
||||||
|
.input(
|
||||||
|
z.object({
|
||||||
|
cod: z.string(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.mutation(async ({ input }) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`${env.BACKENDSERVER_URL}/update-cod/${input.cod}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorData = await response.text().catch(() => "Unknown error");
|
||||||
|
throw new Error(
|
||||||
|
`Update failed with status ${response.status}: ${errorData}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json().catch(() => ({}));
|
||||||
|
await revalidate(`/annuncio/${input.cod}`);
|
||||||
|
return {
|
||||||
|
status: "success",
|
||||||
|
details: data,
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Update error:", err);
|
||||||
|
throw new TRPCError({
|
||||||
|
code: "INTERNAL_SERVER_ERROR",
|
||||||
|
message: err instanceof Error ? err.message : "Update failed",
|
||||||
|
cause: err,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import type { ServizioServizioId } from "~/schemas/public/Servizio";
|
||||||
import { db } from "~/server/db";
|
import { db } from "~/server/db";
|
||||||
import { AnnuncioObjectWithImages } from "~/server/services/annunci.service";
|
import { AnnuncioObjectWithImages } from "~/server/services/annunci.service";
|
||||||
import { createSrcset } from "~/server/services/imageServer";
|
import { createSrcset } from "~/server/services/imageServer";
|
||||||
|
import { revalidate } from "../utils/revalidationHelper";
|
||||||
|
|
||||||
// const ratelimit = new RateLimiterHandler({
|
// const ratelimit = new RateLimiterHandler({
|
||||||
// windowSize: 10,
|
// windowSize: 10,
|
||||||
|
|
@ -371,13 +372,15 @@ export const editAnnuncioHandler = async ({
|
||||||
data: AnnunciUpdate;
|
data: AnnunciUpdate;
|
||||||
}) => {
|
}) => {
|
||||||
try {
|
try {
|
||||||
await db
|
const annuncio = await db
|
||||||
.updateTable("annunci")
|
.updateTable("annunci")
|
||||||
.set({
|
.set({
|
||||||
...data,
|
...data,
|
||||||
})
|
})
|
||||||
.where("id", "=", annuncioId)
|
.where("id", "=", annuncioId)
|
||||||
.execute();
|
.returning("codice")
|
||||||
|
.executeTakeFirstOrThrow();
|
||||||
|
await revalidate(`/annuncio/${annuncio.codice}`);
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
|
|
|
||||||
56
apps/infoalloggi/src/server/utils/revalidationHelper.ts
Normal file
56
apps/infoalloggi/src/server/utils/revalidationHelper.ts
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
export const revalidate = async (path: string) => {
|
||||||
|
try {
|
||||||
|
const res = await fetch(
|
||||||
|
`${process.env.NEXT_PUBLIC_BASE_URL}/api/revalidation?secret=${process.env.REVALIDATION_SECRET}&path=${encodeURIComponent(path)}`,
|
||||||
|
{
|
||||||
|
method: "GET",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (!res.ok) {
|
||||||
|
const errorData = (await res.json()) as {
|
||||||
|
message: string;
|
||||||
|
success: boolean;
|
||||||
|
};
|
||||||
|
throw new Error(
|
||||||
|
`Failed to revalidate path ${path}: ${errorData.message}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error revalidating path ${path}:`, error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const revalidateMultiple = async (
|
||||||
|
paths: string[],
|
||||||
|
): Promise<{
|
||||||
|
success: string[];
|
||||||
|
failed: Array<{ path: string; error: string }>;
|
||||||
|
}> => {
|
||||||
|
const results = await Promise.allSettled(
|
||||||
|
paths.map((path) => revalidate(path)),
|
||||||
|
);
|
||||||
|
|
||||||
|
const success: string[] = [];
|
||||||
|
const failed: Array<{ path: string; error: string }> = [];
|
||||||
|
|
||||||
|
results.forEach((result, index) => {
|
||||||
|
const path = paths[index];
|
||||||
|
if (!path) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result.status === "fulfilled") {
|
||||||
|
success.push(path);
|
||||||
|
} else {
|
||||||
|
failed.push({
|
||||||
|
path,
|
||||||
|
error:
|
||||||
|
result.reason instanceof Error
|
||||||
|
? result.reason.message
|
||||||
|
: "Unknown error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { success, failed };
|
||||||
|
};
|
||||||
Loading…
Add table
Reference in a new issue