Add scouthub-attivit-be
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import { Request, Response, NextFunction, Router } from 'express';
|
||||
import { HttpError } from '../../errors';
|
||||
import { attivitaSaveSchema } from '../../types/validation';
|
||||
import * as attivitaService from './attivita.service';
|
||||
|
||||
function asyncHandler(
|
||||
handler: (req: Request, res: Response, next: NextFunction) => Promise<void>,
|
||||
) {
|
||||
return (req: Request, res: Response, next: NextFunction): void => {
|
||||
handler(req, res, next).catch(next);
|
||||
};
|
||||
}
|
||||
|
||||
export const attivitaPrivateRouter = Router();
|
||||
|
||||
attivitaPrivateRouter.get(
|
||||
'/get/lista/my',
|
||||
asyncHandler(async (req, res) => {
|
||||
const lista = await attivitaService.getListMy(req.auth!.userId);
|
||||
res.status(200).json(lista);
|
||||
}),
|
||||
);
|
||||
|
||||
attivitaPrivateRouter.get(
|
||||
'/change/stato/:idAttivita/:idStato',
|
||||
asyncHandler(async (req, res, next) => {
|
||||
const idAttivita = Number(req.params.idAttivita);
|
||||
if (!Number.isInteger(idAttivita)) {
|
||||
next(new HttpError(400, "l'idAttivita deve essere un numero intero"));
|
||||
return;
|
||||
}
|
||||
|
||||
const idStato = req.params.idStato;
|
||||
const stato = await attivitaService.changeStato(idAttivita, idStato, req.auth!);
|
||||
res.status(200).json(stato);
|
||||
}),
|
||||
);
|
||||
|
||||
attivitaPrivateRouter.post(
|
||||
'/save',
|
||||
asyncHandler(async (req, res, next) => {
|
||||
const parsed = attivitaSaveSchema.safeParse(req.body);
|
||||
if (!parsed.success) {
|
||||
next(new HttpError(400, JSON.stringify(parsed.error.flatten())));
|
||||
return;
|
||||
}
|
||||
|
||||
await attivitaService.save(parsed.data, req.auth!);
|
||||
res.status(200).end();
|
||||
}),
|
||||
);
|
||||
@@ -0,0 +1,63 @@
|
||||
import { Request, Response, NextFunction, Router } from 'express';
|
||||
import { z } from 'zod';
|
||||
import { HttpError } from '../../errors';
|
||||
import * as attivitaService from './attivita.service';
|
||||
|
||||
const searchObjectSchema = z.array(
|
||||
z.object({
|
||||
id: z.number().nullable(),
|
||||
nome: z.string().nullable(),
|
||||
gruppo: z.string(),
|
||||
}),
|
||||
);
|
||||
|
||||
function asyncHandler(
|
||||
handler: (req: Request, res: Response, next: NextFunction) => Promise<void>,
|
||||
) {
|
||||
return (req: Request, res: Response, next: NextFunction): void => {
|
||||
handler(req, res, next).catch(next);
|
||||
};
|
||||
}
|
||||
|
||||
export const attivitaPublicRouter = Router();
|
||||
|
||||
attivitaPublicRouter.get(
|
||||
'/get/lista/home',
|
||||
asyncHandler(async (req, res) => {
|
||||
const lista = await attivitaService.getListaHome();
|
||||
res.status(200).json(lista);
|
||||
}),
|
||||
);
|
||||
|
||||
attivitaPublicRouter.post(
|
||||
'/get/lista/search',
|
||||
asyncHandler(async (req, res, next) => {
|
||||
const parsed = searchObjectSchema.safeParse(req.body);
|
||||
if (!parsed.success) {
|
||||
next(new HttpError(400, 'body non valido: atteso un array di SearchObjectDto'));
|
||||
return;
|
||||
}
|
||||
|
||||
const lista = await attivitaService.getListaSearch(parsed.data);
|
||||
res.status(200).json(lista);
|
||||
}),
|
||||
);
|
||||
|
||||
attivitaPublicRouter.get(
|
||||
'/get/one/:id',
|
||||
asyncHandler(async (req, res, next) => {
|
||||
const id = Number(req.params.id);
|
||||
if (!Number.isInteger(id)) {
|
||||
next(new HttpError(400, "l'id deve essere un numero intero"));
|
||||
return;
|
||||
}
|
||||
|
||||
const attivita = await attivitaService.getOne(id);
|
||||
if (!attivita) {
|
||||
next(new HttpError(404, 'attività non trovata'));
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(200).json(attivita);
|
||||
}),
|
||||
);
|
||||
@@ -0,0 +1,560 @@
|
||||
import { Prisma, PrismaClient } from '@prisma/client';
|
||||
import { prisma } from '../../db/prisma';
|
||||
import { HttpError } from '../../errors';
|
||||
import { AuthContext } from '../../middlewares/auth.types';
|
||||
import {
|
||||
AttivitaDto,
|
||||
BrancaDto,
|
||||
CategoriaDto,
|
||||
MaterialeDto,
|
||||
ParagrafoDto,
|
||||
PeriodoAnnoDto,
|
||||
SearchObjectDto,
|
||||
TipologicaDto,
|
||||
} from '../../types/dto';
|
||||
import { AttivitaSaveInput } from '../../types/validation';
|
||||
|
||||
const attivitaInclude = {
|
||||
stato: true,
|
||||
brancaLinks: { include: { branca: true } },
|
||||
categoriaLinks: { include: { categoria: { include: { tipo: true } } } },
|
||||
materialeLinks: { include: { materiale: true } },
|
||||
periodoAnnoLinks: { include: { periodoAnno: true } },
|
||||
paragrafi: { include: { tipo: true } },
|
||||
} satisfies Prisma.AttivitaInclude;
|
||||
|
||||
type AttivitaWithRelations = Prisma.AttivitaGetPayload<{ include: typeof attivitaInclude }>;
|
||||
|
||||
function toTipologicaDto(entity: { id: string; nome: string }): TipologicaDto {
|
||||
return { id: entity.id, nome: entity.nome };
|
||||
}
|
||||
|
||||
function toAttivitaDto(entity: AttivitaWithRelations): AttivitaDto {
|
||||
const brancaList: BrancaDto[] = entity.brancaLinks
|
||||
.filter((link) => !link.cancellato)
|
||||
.map((link) => ({
|
||||
id: link.branca.id,
|
||||
nome: link.branca.nome,
|
||||
inizioEta: link.branca.inizioEta,
|
||||
fineEta: link.branca.fineEta,
|
||||
colore: link.branca.colore,
|
||||
cancellato: false,
|
||||
dataCreazione: link.branca.dataCreazione,
|
||||
dataModifica: link.branca.dataModifica,
|
||||
utenteModifica: link.branca.utenteModifica,
|
||||
}));
|
||||
|
||||
const categoriaList: CategoriaDto[] = entity.categoriaLinks
|
||||
.filter((link) => !link.cancellato)
|
||||
.map((link) => ({
|
||||
id: link.categoria.id,
|
||||
nome: link.categoria.nome,
|
||||
padre: link.categoria.padreId,
|
||||
tipo: toTipologicaDto(link.categoria.tipo),
|
||||
cancellato: false,
|
||||
dataCreazione: link.categoria.dataCreazione,
|
||||
dataModifica: link.categoria.dataModifica,
|
||||
utenteModifica: link.categoria.utenteModifica,
|
||||
}));
|
||||
|
||||
const materialeList: MaterialeDto[] = entity.materialeLinks
|
||||
.filter((link) => !link.cancellato)
|
||||
.map((link) => ({
|
||||
id: link.materiale.id,
|
||||
nome: link.materiale.nome,
|
||||
proprieta: link.proprieta,
|
||||
cancellato: false,
|
||||
dataCreazione: link.materiale.dataCreazione,
|
||||
dataModifica: link.materiale.dataModifica,
|
||||
utenteModifica: link.materiale.utenteModifica,
|
||||
}));
|
||||
|
||||
const periodoAnnoList: PeriodoAnnoDto[] = entity.periodoAnnoLinks
|
||||
.filter((link) => !link.cancellato)
|
||||
.map((link) => ({
|
||||
id: link.periodoAnno.id,
|
||||
nome: link.periodoAnno.nome,
|
||||
inizioMese: link.periodoAnno.inizioMese,
|
||||
fineMese: link.periodoAnno.fineMese,
|
||||
cancellato: false,
|
||||
dataCreazione: link.periodoAnno.dataCreazione,
|
||||
dataModifica: link.periodoAnno.dataModifica,
|
||||
utenteModifica: link.periodoAnno.utenteModifica,
|
||||
}));
|
||||
|
||||
const paragrafoList: ParagrafoDto[] = [...entity.paragrafi]
|
||||
.sort((a, b) => a.ordine - b.ordine)
|
||||
.map((paragrafo) => ({
|
||||
id: paragrafo.id,
|
||||
attivitaId: paragrafo.attivitaId,
|
||||
corpo: paragrafo.corpo,
|
||||
autore: paragrafo.autore,
|
||||
tipo: toTipologicaDto(paragrafo.tipo),
|
||||
ordine: paragrafo.ordine,
|
||||
dataCreazione: paragrafo.dataCreazione,
|
||||
dataModifica: paragrafo.dataModifica,
|
||||
utenteModifica: paragrafo.utenteModifica,
|
||||
}));
|
||||
|
||||
return {
|
||||
id: entity.id,
|
||||
nome: entity.nome,
|
||||
autore: entity.autore,
|
||||
padre: entity.padreId,
|
||||
stato: toTipologicaDto(entity.stato),
|
||||
brancaList,
|
||||
categoriaList,
|
||||
materialeList,
|
||||
paragrafoList,
|
||||
periodoAnnoList,
|
||||
dataCreazione: entity.dataCreazione,
|
||||
dataModifica: entity.dataModifica,
|
||||
utenteModifica: entity.utenteModifica,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getListaHome(): Promise<AttivitaDto[]> {
|
||||
const entities = await prisma.attivita.findMany({
|
||||
where: { statoId: 'PU' },
|
||||
include: attivitaInclude,
|
||||
orderBy: { dataModifica: 'desc' },
|
||||
});
|
||||
|
||||
return entities.map(toAttivitaDto);
|
||||
}
|
||||
|
||||
export async function getOne(id: number): Promise<AttivitaDto | null> {
|
||||
const entity = await prisma.attivita.findUnique({
|
||||
where: { id },
|
||||
include: attivitaInclude,
|
||||
});
|
||||
|
||||
return entity ? toAttivitaDto(entity) : null;
|
||||
}
|
||||
|
||||
export async function getListMy(autoreId: string): Promise<AttivitaDto[]> {
|
||||
const entities = await prisma.attivita.findMany({
|
||||
where: { autoreId },
|
||||
include: attivitaInclude,
|
||||
orderBy: { dataModifica: 'desc' },
|
||||
});
|
||||
|
||||
return entities.map(toAttivitaDto);
|
||||
}
|
||||
|
||||
export async function getListaSearch(dtoList: SearchObjectDto[]): Promise<AttivitaDto[]> {
|
||||
const brancaIds = dtoList.filter((d) => d.gruppo === 'branca').map((d) => d.id as number);
|
||||
const categoriaIds = dtoList.filter((d) => d.gruppo === 'categoria').map((d) => d.id as number);
|
||||
const materialeIds = dtoList.filter((d) => d.gruppo === 'materiale').map((d) => d.id as number);
|
||||
const periodoAnnoIds = dtoList
|
||||
.filter((d) => d.gruppo === 'periodoAnno')
|
||||
.map((d) => d.id as number);
|
||||
const testoList = dtoList
|
||||
.filter((d) => d.gruppo === 'testo')
|
||||
.map((d) => d.nome)
|
||||
.filter((nome): nome is string => !!nome);
|
||||
|
||||
const and: Prisma.AttivitaWhereInput[] = [];
|
||||
|
||||
if (brancaIds.length > 0) {
|
||||
and.push({
|
||||
brancaLinks: { some: { brancaId: { in: brancaIds }, cancellato: false } },
|
||||
});
|
||||
}
|
||||
|
||||
if (categoriaIds.length > 0) {
|
||||
and.push({
|
||||
categoriaLinks: { some: { categoriaId: { in: categoriaIds }, cancellato: false } },
|
||||
});
|
||||
}
|
||||
|
||||
if (materialeIds.length > 0) {
|
||||
and.push({
|
||||
materialeLinks: { some: { materialeId: { in: materialeIds }, cancellato: false } },
|
||||
});
|
||||
}
|
||||
|
||||
if (periodoAnnoIds.length > 0) {
|
||||
and.push({
|
||||
periodoAnnoLinks: { some: { periodoAnnoId: { in: periodoAnnoIds }, cancellato: false } },
|
||||
});
|
||||
}
|
||||
|
||||
if (testoList.length > 0) {
|
||||
and.push({
|
||||
OR: testoList.flatMap((testo) => [
|
||||
{ nome: { contains: testo, mode: 'insensitive' } },
|
||||
{ paragrafi: { some: { corpo: { contains: testo, mode: 'insensitive' } } } },
|
||||
]),
|
||||
});
|
||||
}
|
||||
|
||||
const entities = await prisma.attivita.findMany({
|
||||
where: and.length > 0 ? { AND: and } : {},
|
||||
include: attivitaInclude,
|
||||
orderBy: { dataModifica: 'desc' },
|
||||
});
|
||||
|
||||
return entities.map(toAttivitaDto);
|
||||
}
|
||||
|
||||
export async function changeStato(
|
||||
idAttivita: number,
|
||||
idStato: string,
|
||||
auth: AuthContext,
|
||||
): Promise<TipologicaDto> {
|
||||
const existing = await prisma.attivita.findUnique({ where: { id: idAttivita } });
|
||||
if (!existing) {
|
||||
throw new HttpError(404, 'attività non trovata');
|
||||
}
|
||||
if (existing.autoreId !== auth.userId) {
|
||||
throw new HttpError(403, 'non sei autore di questa attività');
|
||||
}
|
||||
|
||||
const updated = await prisma.attivita.update({
|
||||
where: { id: idAttivita },
|
||||
data: {
|
||||
statoId: idStato,
|
||||
utenteModifica: auth.name,
|
||||
},
|
||||
include: { stato: true },
|
||||
});
|
||||
|
||||
return toTipologicaDto(updated.stato);
|
||||
}
|
||||
|
||||
type Tx = Omit<PrismaClient, '$connect' | '$disconnect' | '$on' | '$transaction' | '$use' | '$extends'>;
|
||||
|
||||
async function upsertBranca(
|
||||
tx: Tx,
|
||||
attivitaId: number,
|
||||
input: AttivitaSaveInput['brancaList'][number],
|
||||
auth: AuthContext,
|
||||
): Promise<number> {
|
||||
let brancaId = input.id;
|
||||
|
||||
if (!brancaId) {
|
||||
const found = await tx.branca.findFirst({
|
||||
where: { nome: { equals: input.nome, mode: 'insensitive' } },
|
||||
});
|
||||
|
||||
if (found) {
|
||||
brancaId = found.id;
|
||||
} else {
|
||||
const created = await tx.branca.create({
|
||||
data: {
|
||||
nome: input.nome,
|
||||
utenteModifica: auth.name,
|
||||
},
|
||||
});
|
||||
brancaId = created.id;
|
||||
}
|
||||
}
|
||||
|
||||
const existingLink = await tx.brancaAttivita.findUnique({
|
||||
where: { attivitaId_brancaId: { attivitaId, brancaId } },
|
||||
});
|
||||
|
||||
if (existingLink) {
|
||||
await tx.brancaAttivita.update({
|
||||
where: { attivitaId_brancaId: { attivitaId, brancaId } },
|
||||
data: {
|
||||
cancellato: false,
|
||||
utenteModifica: auth.name,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await tx.brancaAttivita.create({
|
||||
data: {
|
||||
attivitaId,
|
||||
brancaId,
|
||||
cancellato: false,
|
||||
utenteModifica: auth.name,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return brancaId;
|
||||
}
|
||||
|
||||
async function upsertCategoria(
|
||||
tx: Tx,
|
||||
attivitaId: number,
|
||||
input: AttivitaSaveInput['categoriaList'][number],
|
||||
auth: AuthContext,
|
||||
): Promise<number> {
|
||||
let categoriaId = input.id;
|
||||
|
||||
if (!categoriaId) {
|
||||
const found = await tx.categoria.findFirst({
|
||||
where: { nome: { equals: input.nome, mode: 'insensitive' } },
|
||||
});
|
||||
|
||||
if (found) {
|
||||
categoriaId = found.id;
|
||||
} else {
|
||||
const created = await tx.categoria.create({
|
||||
data: {
|
||||
nome: input.nome,
|
||||
tipoId: 'A',
|
||||
utenteModifica: auth.name,
|
||||
},
|
||||
});
|
||||
categoriaId = created.id;
|
||||
}
|
||||
}
|
||||
|
||||
const existingLink = await tx.categoriaAttivita.findUnique({
|
||||
where: { attivitaId_categoriaId: { attivitaId, categoriaId } },
|
||||
});
|
||||
|
||||
if (existingLink) {
|
||||
await tx.categoriaAttivita.update({
|
||||
where: { attivitaId_categoriaId: { attivitaId, categoriaId } },
|
||||
data: {
|
||||
cancellato: false,
|
||||
utenteModifica: auth.name,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await tx.categoriaAttivita.create({
|
||||
data: {
|
||||
attivitaId,
|
||||
categoriaId,
|
||||
cancellato: false,
|
||||
utenteModifica: auth.name,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return categoriaId;
|
||||
}
|
||||
|
||||
async function upsertMateriale(
|
||||
tx: Tx,
|
||||
attivitaId: number,
|
||||
input: AttivitaSaveInput['materialeList'][number],
|
||||
auth: AuthContext,
|
||||
): Promise<number> {
|
||||
let materialeId = input.id;
|
||||
|
||||
if (!materialeId) {
|
||||
const found = await tx.materiale.findFirst({
|
||||
where: { nome: { equals: input.nome, mode: 'insensitive' } },
|
||||
});
|
||||
|
||||
if (found) {
|
||||
materialeId = found.id;
|
||||
} else {
|
||||
const created = await tx.materiale.create({
|
||||
data: {
|
||||
nome: input.nome,
|
||||
utenteModifica: auth.name,
|
||||
},
|
||||
});
|
||||
materialeId = created.id;
|
||||
}
|
||||
}
|
||||
|
||||
const proprieta = (input.proprieta ?? Prisma.JsonNull) as Prisma.InputJsonValue;
|
||||
|
||||
const existingLink = await tx.materialeAttivita.findUnique({
|
||||
where: { attivitaId_materialeId: { attivitaId, materialeId } },
|
||||
});
|
||||
|
||||
if (existingLink) {
|
||||
await tx.materialeAttivita.update({
|
||||
where: { attivitaId_materialeId: { attivitaId, materialeId } },
|
||||
data: {
|
||||
cancellato: false,
|
||||
proprieta,
|
||||
utenteModifica: auth.name,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await tx.materialeAttivita.create({
|
||||
data: {
|
||||
attivitaId,
|
||||
materialeId,
|
||||
cancellato: false,
|
||||
proprieta,
|
||||
utenteModifica: auth.name,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return materialeId;
|
||||
}
|
||||
|
||||
async function upsertPeriodoAnno(
|
||||
tx: Tx,
|
||||
attivitaId: number,
|
||||
input: AttivitaSaveInput['periodoAnnoList'][number],
|
||||
auth: AuthContext,
|
||||
): Promise<number> {
|
||||
let periodoAnnoId = input.id;
|
||||
|
||||
if (!periodoAnnoId) {
|
||||
const found = await tx.periodoAnno.findFirst({
|
||||
where: { nome: { equals: input.nome, mode: 'insensitive' } },
|
||||
});
|
||||
|
||||
if (found) {
|
||||
periodoAnnoId = found.id;
|
||||
} else {
|
||||
const created = await tx.periodoAnno.create({
|
||||
data: {
|
||||
nome: input.nome,
|
||||
utenteModifica: auth.name,
|
||||
},
|
||||
});
|
||||
periodoAnnoId = created.id;
|
||||
}
|
||||
}
|
||||
|
||||
const existingLink = await tx.periodoAnnoAttivita.findUnique({
|
||||
where: { attivitaId_periodoAnnoId: { attivitaId, periodoAnnoId } },
|
||||
});
|
||||
|
||||
if (existingLink) {
|
||||
await tx.periodoAnnoAttivita.update({
|
||||
where: { attivitaId_periodoAnnoId: { attivitaId, periodoAnnoId } },
|
||||
data: {
|
||||
cancellato: false,
|
||||
utenteModifica: auth.name,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await tx.periodoAnnoAttivita.create({
|
||||
data: {
|
||||
attivitaId,
|
||||
periodoAnnoId,
|
||||
cancellato: false,
|
||||
utenteModifica: auth.name,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return periodoAnnoId;
|
||||
}
|
||||
|
||||
export async function save(dto: AttivitaSaveInput, auth: AuthContext): Promise<void> {
|
||||
await prisma.$transaction(async (tx) => {
|
||||
let attivitaId: number;
|
||||
|
||||
if (dto.id) {
|
||||
const existing = await tx.attivita.findUnique({ where: { id: dto.id } });
|
||||
if (!existing) {
|
||||
throw new HttpError(404, 'attività non trovata');
|
||||
}
|
||||
if (existing.autoreId !== auth.userId) {
|
||||
throw new HttpError(403, 'non sei autore di questa attività');
|
||||
}
|
||||
|
||||
await tx.attivita.update({
|
||||
where: { id: dto.id },
|
||||
data: {
|
||||
nome: dto.nome,
|
||||
statoId: dto.stato.id,
|
||||
utenteModifica: auth.name,
|
||||
},
|
||||
});
|
||||
attivitaId = dto.id;
|
||||
} else {
|
||||
const created = await tx.attivita.create({
|
||||
data: {
|
||||
nome: dto.nome,
|
||||
autore: auth.name,
|
||||
autoreId: auth.userId,
|
||||
statoId: dto.stato.id,
|
||||
utenteModifica: auth.name,
|
||||
},
|
||||
});
|
||||
attivitaId = created.id;
|
||||
}
|
||||
|
||||
const brancaIds = new Set<number>();
|
||||
for (const branca of dto.brancaList) {
|
||||
brancaIds.add(await upsertBranca(tx, attivitaId, branca, auth));
|
||||
}
|
||||
await tx.brancaAttivita.updateMany({
|
||||
where: { attivitaId, brancaId: { notIn: [...brancaIds] }, cancellato: false },
|
||||
data: {
|
||||
cancellato: true,
|
||||
utenteModifica: auth.name,
|
||||
},
|
||||
});
|
||||
|
||||
const categoriaIds = new Set<number>();
|
||||
for (const categoria of dto.categoriaList) {
|
||||
categoriaIds.add(await upsertCategoria(tx, attivitaId, categoria, auth));
|
||||
}
|
||||
await tx.categoriaAttivita.updateMany({
|
||||
where: { attivitaId, categoriaId: { notIn: [...categoriaIds] }, cancellato: false },
|
||||
data: {
|
||||
cancellato: true,
|
||||
utenteModifica: auth.name,
|
||||
},
|
||||
});
|
||||
|
||||
const materialeIds = new Set<number>();
|
||||
for (const materiale of dto.materialeList) {
|
||||
materialeIds.add(await upsertMateriale(tx, attivitaId, materiale, auth));
|
||||
}
|
||||
await tx.materialeAttivita.updateMany({
|
||||
where: { attivitaId, materialeId: { notIn: [...materialeIds] }, cancellato: false },
|
||||
data: {
|
||||
cancellato: true,
|
||||
utenteModifica: auth.name,
|
||||
},
|
||||
});
|
||||
|
||||
const periodoAnnoIds = new Set<number>();
|
||||
for (const periodoAnno of dto.periodoAnnoList) {
|
||||
periodoAnnoIds.add(await upsertPeriodoAnno(tx, attivitaId, periodoAnno, auth));
|
||||
}
|
||||
await tx.periodoAnnoAttivita.updateMany({
|
||||
where: { attivitaId, periodoAnnoId: { notIn: [...periodoAnnoIds] }, cancellato: false },
|
||||
data: {
|
||||
cancellato: true,
|
||||
utenteModifica: auth.name,
|
||||
},
|
||||
});
|
||||
|
||||
const paragrafoIds = new Set<number>();
|
||||
for (const paragrafo of dto.paragrafoList) {
|
||||
// Il paragrafo non ha un autore proprio nell'API: eredita quello dell'attivita'
|
||||
// se non esplicitamente indicato nel payload.
|
||||
const paragrafoAutore = paragrafo.autore ?? auth.name;
|
||||
|
||||
if (paragrafo.id) {
|
||||
await tx.paragrafo.update({
|
||||
where: { id: paragrafo.id },
|
||||
data: {
|
||||
corpo: paragrafo.corpo,
|
||||
autore: paragrafoAutore,
|
||||
tipoId: paragrafo.tipo.id,
|
||||
ordine: paragrafo.ordine,
|
||||
utenteModifica: auth.name,
|
||||
},
|
||||
});
|
||||
paragrafoIds.add(paragrafo.id);
|
||||
} else {
|
||||
const created = await tx.paragrafo.create({
|
||||
data: {
|
||||
attivitaId,
|
||||
corpo: paragrafo.corpo,
|
||||
autore: paragrafoAutore,
|
||||
tipoId: paragrafo.tipo.id,
|
||||
ordine: paragrafo.ordine,
|
||||
utenteModifica: auth.name,
|
||||
},
|
||||
});
|
||||
paragrafoIds.add(created.id);
|
||||
}
|
||||
}
|
||||
await tx.paragrafo.deleteMany({
|
||||
where: { attivitaId, id: { notIn: [...paragrafoIds] } },
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import { Request, Response, NextFunction, Router } from 'express';
|
||||
import * as autocompleteService from './autocomplete.service';
|
||||
|
||||
function asyncHandler(
|
||||
handler: (req: Request, res: Response, next: NextFunction) => Promise<void>,
|
||||
) {
|
||||
return (req: Request, res: Response, next: NextFunction): void => {
|
||||
handler(req, res, next).catch(next);
|
||||
};
|
||||
}
|
||||
|
||||
function extractKeyword(body: unknown): string | undefined {
|
||||
return typeof body === 'string' ? body : undefined;
|
||||
}
|
||||
|
||||
export const autocompleteRouter = Router();
|
||||
|
||||
autocompleteRouter.post(
|
||||
'/get/search',
|
||||
asyncHandler(async (req, res) => {
|
||||
const groups = await autocompleteService.getSearch(extractKeyword(req.body));
|
||||
res.status(200).json(groups);
|
||||
}),
|
||||
);
|
||||
|
||||
autocompleteRouter.post(
|
||||
'/get/branca',
|
||||
asyncHandler(async (req, res) => {
|
||||
const lista = await autocompleteService.getBranca(extractKeyword(req.body));
|
||||
res.status(200).json(lista);
|
||||
}),
|
||||
);
|
||||
|
||||
autocompleteRouter.post(
|
||||
'/get/categoria',
|
||||
asyncHandler(async (req, res) => {
|
||||
const lista = await autocompleteService.getCategoria(extractKeyword(req.body));
|
||||
res.status(200).json(lista);
|
||||
}),
|
||||
);
|
||||
|
||||
autocompleteRouter.post(
|
||||
'/get/materiale',
|
||||
asyncHandler(async (req, res) => {
|
||||
const lista = await autocompleteService.getMateriale(extractKeyword(req.body));
|
||||
res.status(200).json(lista);
|
||||
}),
|
||||
);
|
||||
|
||||
autocompleteRouter.post(
|
||||
'/get/periodoAnno',
|
||||
asyncHandler(async (req, res) => {
|
||||
const lista = await autocompleteService.getPeriodoAnno(extractKeyword(req.body));
|
||||
res.status(200).json(lista);
|
||||
}),
|
||||
);
|
||||
@@ -0,0 +1,62 @@
|
||||
import { prisma } from '../../db/prisma';
|
||||
import { SearchGroupDto, SearchObjectDto } from '../../types/dto';
|
||||
|
||||
export async function getBranca(keyword?: string | null): Promise<SearchObjectDto[]> {
|
||||
const entities = await prisma.branca.findMany({
|
||||
where: { nome: { contains: keyword ?? '', mode: 'insensitive' } },
|
||||
});
|
||||
|
||||
return entities.map((entity) => ({ id: entity.id, nome: entity.nome, gruppo: 'branca' }));
|
||||
}
|
||||
|
||||
export async function getCategoria(keyword?: string | null): Promise<SearchObjectDto[]> {
|
||||
const entities = await prisma.categoria.findMany({
|
||||
where: { nome: { contains: keyword ?? '', mode: 'insensitive' } },
|
||||
});
|
||||
|
||||
return entities.map((entity) => ({ id: entity.id, nome: entity.nome, gruppo: 'categoria' }));
|
||||
}
|
||||
|
||||
export async function getMateriale(keyword?: string | null): Promise<SearchObjectDto[]> {
|
||||
const entities = await prisma.materiale.findMany({
|
||||
where: { nome: { contains: keyword ?? '', mode: 'insensitive' } },
|
||||
});
|
||||
|
||||
return entities.map((entity) => ({ id: entity.id, nome: entity.nome, gruppo: 'materiale' }));
|
||||
}
|
||||
|
||||
export async function getPeriodoAnno(keyword?: string | null): Promise<SearchObjectDto[]> {
|
||||
const entities = await prisma.periodoAnno.findMany({
|
||||
where: { nome: { contains: keyword ?? '', mode: 'insensitive' } },
|
||||
});
|
||||
|
||||
return entities.map((entity) => ({ id: entity.id, nome: entity.nome, gruppo: 'periodoAnno' }));
|
||||
}
|
||||
|
||||
export async function getSearch(keyword?: string | null): Promise<SearchGroupDto[]> {
|
||||
const groups: SearchGroupDto[] = [
|
||||
{ label: 'Testo', objectsList: [{ id: null, nome: keyword ?? null, gruppo: 'testo' }] },
|
||||
];
|
||||
|
||||
const brancaList = await getBranca(keyword);
|
||||
if (brancaList.length > 0) {
|
||||
groups.push({ label: 'Branca', objectsList: brancaList });
|
||||
}
|
||||
|
||||
const categoriaList = await getCategoria(keyword);
|
||||
if (categoriaList.length > 0) {
|
||||
groups.push({ label: 'Categoria', objectsList: categoriaList });
|
||||
}
|
||||
|
||||
const materialeList = await getMateriale(keyword);
|
||||
if (materialeList.length > 0) {
|
||||
groups.push({ label: 'Materiale', objectsList: materialeList });
|
||||
}
|
||||
|
||||
const periodoAnnoList = await getPeriodoAnno(keyword);
|
||||
if (periodoAnnoList.length > 0) {
|
||||
groups.push({ label: 'Periodo anno', objectsList: periodoAnnoList });
|
||||
}
|
||||
|
||||
return groups;
|
||||
}
|
||||
Reference in New Issue
Block a user