This commit is contained in:
Marcelo Dares
2026-04-29 01:15:50 +02:00
parent 65aaf9275e
commit ea23136288
172 changed files with 30358 additions and 353 deletions

View File

@@ -0,0 +1,81 @@
import { NextResponse } from "next/server";
import { requireAdminApiUser } from "@/lib/auth/admin";
import {
listOfficialNormativeSources,
listOfficialNormativeSuggestions,
suggestOfficialNormativeSource,
} from "@/lib/compliance/regulations";
import type { OfficialNormativeSourceView, OfficialNormativeSuggestionInput } from "@/lib/compliance/types";
function isValidSourceType(value: unknown): value is OfficialNormativeSourceView["sourceType"] {
return value === "ley" || value === "reglamento" || value === "lineamiento" || value === "portal";
}
function parseSuggestion(body: Record<string, unknown>): OfficialNormativeSuggestionInput | null {
const stateCode = typeof body.stateCode === "string" ? body.stateCode.trim().toUpperCase() : "";
const municipalityCode = typeof body.municipalityCode === "string" ? body.municipalityCode.trim().toUpperCase() : null;
const authorityName = typeof body.authorityName === "string" ? body.authorityName.trim() : "";
const title = typeof body.title === "string" ? body.title.trim() : "";
const officialUrl = typeof body.officialUrl === "string" ? body.officialUrl.trim() : "";
const sourceType = body.sourceType;
const notes = typeof body.notes === "string" ? body.notes.trim() : undefined;
if (!stateCode || !authorityName || !title || !officialUrl || !isValidSourceType(sourceType)) {
return null;
}
return {
stateCode,
municipalityCode,
authorityName,
title,
officialUrl,
sourceType,
notes,
};
}
export async function GET(request: Request) {
const user = await requireAdminApiUser();
if (!user) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const url = new URL(request.url);
const includeSuggestions = url.searchParams.get("includeSuggestions") === "1";
const stateCode = url.searchParams.get("stateCode")?.trim() || null;
const municipalityCode = url.searchParams.get("municipalityCode")?.trim() || null;
const pilotOnly = url.searchParams.get("pilotOnly") !== "0";
const sources = await listOfficialNormativeSources({
stateCode,
municipalityCode,
pilotOnly,
});
const suggestions = includeSuggestions ? await listOfficialNormativeSuggestions() : undefined;
return NextResponse.json({
ok: true,
sources,
suggestions,
});
}
export async function POST(request: Request) {
const user = await requireAdminApiUser();
if (!user) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const body = (await request.json().catch(() => ({}))) as Record<string, unknown>;
const suggestion = parseSuggestion(body);
if (!suggestion) {
return NextResponse.json({ error: "Datos invalidos para sugerencia normativa." }, { status: 400 });
}
const created = await suggestOfficialNormativeSource(suggestion);
return NextResponse.json({ ok: true, suggestion: created }, { status: 201 });
}