infoalloggi-monorepo/apps/infoalloggi/src/server/controllers/annunci.controller.ts

439 lines
10 KiB
TypeScript
Raw Normal View History

2025-08-04 17:45:44 +02:00
import type { Annunci, AnnunciId } from "~/schemas/public/Annunci";
import { TRPCError } from "@trpc/server";
import { createSrcset } from "~/server/services/imageServer";
2025-08-04 17:45:44 +02:00
import { AnnuncioObjectWithImages } from "~/server/services/annunci.service";
import { zAnnuncioId } from "~/server/utils/zod_types";
import { z } from "zod/v4";
2025-08-04 17:45:44 +02:00
import { db } from "~/server/db";
import type { ServizioServizioId } from "~/schemas/public/Servizio";
import { env } from "~/env.mjs";
2025-08-04 17:45:44 +02:00
// const ratelimit = new RateLimiterHandler({
// windowSize: 10,
// maxRequests: 10,
// analytics: true,
// });
export const getAnnunciListHandler = async (): Promise<
Pick<
Annunci,
"id" | "codice" | "titolo_it" | "comune" | "tipo" | "locatore" | "stato"
>[]
> => {
try {
return await db
.selectFrom("annunci")
.select([
"id",
"codice",
"titolo_it",
"comune",
"tipo",
"locatore",
"stato",
])
.execute();
} catch {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Errore query getAllRaw",
});
}
};
export const getCodici_AnnunciHandler = async (): Promise<string[]> => {
try {
const codici = await db
.selectFrom("annunci")
.select("codice")
.where("annunci.web", "=", true)
.where("stato", "!=", "Sospeso")
.execute();
if (!codici) {
return [];
}
return codici.map((c) => c.codice);
} catch {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Errore query getCodici",
});
}
};
export const getAnnunciByCod = async ({
cod,
}: {
cod: string;
}): Promise<Annunci | null> => {
2025-08-04 17:45:44 +02:00
try {
const annuncio = await db
.selectFrom("annunci")
.selectAll()
.where("annunci.web", "=", true)
.where("codice", "=", cod)
.executeTakeFirst();
if (!annuncio) {
console.error("Annuncio non trovato per codice:", cod);
return null;
2025-08-04 17:45:44 +02:00
}
return AnnuncioObjectWithImages<typeof annuncio>(annuncio);
} catch {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Errore query getAnnuncio",
});
}
};
export const getAnnunciMetaByCod = async ({ cod }: { cod: string }) => {
try {
const annuncio = await db
.selectFrom("annunci")
.select(["titolo_it", "desc_it", "og_url"])
.where("annunci.web", "=", true)
.where("codice", "=", cod)
.executeTakeFirst();
if (!annuncio) {
throw new TRPCError({
code: "NOT_FOUND",
message: "Annuncio non trovato",
});
}
return {
ogImage: annuncio.og_url || "",
title: annuncio.titolo_it || "",
description: annuncio.desc_it || "",
ogUrl: env.NEXT_PUBLIC_BASE_URL + "/annuncio/" + cod,
};
2025-08-04 17:45:44 +02:00
} catch {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Errore query getAnnuncio",
});
}
};
export const getAnnunciById = async ({
id,
}: {
id: AnnunciId;
}): Promise<Annunci | null> => {
2025-08-04 17:45:44 +02:00
try {
const annuncio = await db
.selectFrom("annunci")
.selectAll()
.where("id", "=", id)
.executeTakeFirst();
if (!annuncio) {
throw new TRPCError({
code: "NOT_FOUND",
message: "Annuncio non trovato",
});
}
return AnnuncioObjectWithImages<typeof annuncio>(annuncio);
2025-08-04 17:45:44 +02:00
} catch {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Errore query getAnnuncioById",
});
}
};
export type AnnuncioRicercaWPosition = AnnuncioRicerca & {
lat_secondario: string | null;
lon_secondario: string | null;
};
export const get_AnnunciPositionsHandler = async ({
tipologia,
comune,
consegna,
}: {
tipologia?: string;
comune?: string;
consegna?: number;
}): Promise<AnnuncioRicercaWPosition[]> => {
try {
let query = db
.selectFrom("annunci")
.select([
"id",
"codice",
"comune",
"provincia",
"prezzo",
"consegna",
"numero_camere",
"mq",
"tipo",
"titolo_it",
"titolo_en",
"url_immagini",
"modificato_il",
"stato",
"lon_secondario",
"lat_secondario",
])
.where("web", "=", true)
.where("stato", "!=", "Sospeso")
.orderBy("id", "asc");
if (tipologia && tipologia !== "") {
query = query.where("tipo", "=", tipologia);
}
if (comune && comune !== "") {
query = query.where("comune", "like", comune);
}
if (consegna) {
query = query.where("consegna", "=", consegna);
}
const annunci = await query.execute();
if (!annunci) {
return [];
}
for (const annuncio of annunci) {
annuncio.url_immagini = annuncio.url_immagini
? createSrcset(annuncio.url_immagini)
: [];
}
return annunci;
} catch (e) {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Errore query getAnnunciPositions: " + (e as Error).message,
});
}
};
export type AnnuncioRicerca = Pick<
Annunci,
| "id"
| "codice"
| "comune"
| "provincia"
| "prezzo"
| "consegna"
| "numero_camere"
| "mq"
| "tipo"
| "titolo_it"
| "titolo_en"
| "url_immagini"
| "modificato_il"
| "stato"
>;
export const getCursor_AnnunciHandler = async ({
page = 0,
pageSize,
tipologia,
comune,
consegna,
sort,
2025-08-04 17:45:44 +02:00
}: {
page?: number;
pageSize: number;
tipologia?: string;
comune?: string;
consegna?: number;
sort?: "Recenti" | "Prezzo" | "Consegna" | "Mq";
}) => {
2025-08-04 17:45:44 +02:00
try {
let query = db
.selectFrom("annunci")
.select([
"id",
"codice",
"comune",
"provincia",
"prezzo",
"consegna",
"numero_camere",
"mq",
"tipo",
"titolo_it",
"titolo_en",
"url_immagini",
"modificato_il",
"stato",
])
.where("web", "=", true)
.where("stato", "!=", "Sospeso");
if (tipologia && tipologia !== "") {
query = query.where("tipo", "=", tipologia);
2025-08-04 17:45:44 +02:00
}
if (comune && comune !== "") {
query = query.where("comune", "like", comune);
2025-08-04 17:45:44 +02:00
}
if (consegna) {
query = query.where("consegna", "=", consegna);
2025-08-04 17:45:44 +02:00
}
if (sort) {
switch (sort) {
2025-08-04 17:45:44 +02:00
case "Recenti":
query = query.orderBy("modificato_il", "desc");
break;
case "Prezzo":
query = query.orderBy("prezzo", "asc");
break;
case "Consegna":
query = query.orderBy("consegna", "asc");
break;
case "Mq":
query = query.orderBy("mq", "asc");
break;
}
}
query = query.orderBy("id", "asc");
const annunci = await query
.limit(pageSize + 1)
.offset(page * pageSize)
.execute();
const hasMore = annunci.length > pageSize;
if (annunci.length > pageSize) {
annunci.pop(); // Remove the last item if it exceeds the page size
2025-08-04 17:45:44 +02:00
}
for (const annuncio of annunci) {
annuncio.url_immagini = annuncio.url_immagini
? createSrcset(annuncio.url_immagini)
: [];
}
2025-08-04 17:45:44 +02:00
return {
annunci,
hasMore,
2025-08-04 17:45:44 +02:00
};
} catch {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Errore query getWithCursor",
});
}
};
export const getOptions_AnnunciHandler = async () => {
try {
const comuni = await db
.selectFrom("annunci")
.select(["comune", "tipo", "consegna"])
.where("web", "=", true)
.where("stato", "!=", "Sospeso")
.distinct()
.execute();
const results: { comune: string; tipo: string; consegna: number }[] = [];
for (const comune of comuni) {
if (comune.comune && comune.tipo && comune.consegna) {
results.push({
comune: comune.comune,
tipo: comune.tipo,
consegna: comune.consegna,
});
}
}
return results;
} catch {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Errore query getComuni",
});
}
};
export const EdiAnnuncioSchema = z.object({
annuncioId: zAnnuncioId,
titolo_it: z.string().nonempty("Inserisci un titolo valido"),
desc_it: z.string().nonempty("Inserisci una descrizione valida"),
titolo_en: z.string().nonempty("Inserisci un titolo valido"),
desc_en: z.string().nonempty("Inserisci una descrizione valida"),
status: z.string().nonempty("Seleziona uno stato"),
});
type EditAnnuncioFormValues = z.infer<typeof EdiAnnuncioSchema>;
export const editAnnuncioHandler = async ({
annuncioId,
titolo_it,
desc_it,
titolo_en,
desc_en,
status,
}: EditAnnuncioFormValues) => {
try {
await db
.updateTable("annunci")
.set({
titolo_it: titolo_it,
desc_it: desc_it,
titolo_en: titolo_en,
desc_en: desc_en,
stato: status,
})
.where("id", "=", annuncioId)
.execute();
return true;
} catch {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Errore interno",
});
}
};
export const getProprietarioDataHandler = async ({
annuncioId,
servizioId,
}: {
annuncioId: AnnunciId;
servizioId: ServizioServizioId;
}) => {
try {
const opened_at = await db
.selectFrom("servizio_annunci")
.select("open_contatti_at")
.where("servizio_id", "=", servizioId)
.where("annunci_id", "=", annuncioId)
.executeTakeFirst();
if (!opened_at || !opened_at.open_contatti_at) {
return { propData: null, opened_at: null };
}
const propData = await db
.selectFrom("annunci")
.select([
"codice",
"comune",
"indirizzo",
"civico",
"provincia",
"regione",
"cap",
"lat",
"lon",
"numero",
"locatore",
])
.where("id", "=", annuncioId)
.executeTakeFirstOrThrow();
return { propData, opened_at: opened_at.open_contatti_at };
} catch (e) {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Errore recupero dati proprietario: " + (e as Error).message,
});
}
};