f73e639e4f
- CSV export: all fields properly quoted to prevent column misalignment when values contain commas (e.g. nrTopo with multiple topo numbers) - Layer catalog: 'Numara toate' button fetches feature count per layer via /api/eterra/layers/summary (now supports session auth) - Feature counts displayed as badges on each layer and category total - 'Drumul de azi' section: persists today's layer counts in localStorage grouped by SIRUTA with timestamps
87 lines
2.8 KiB
TypeScript
87 lines
2.8 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import {
|
|
EterraClient,
|
|
type EsriGeometry,
|
|
} from "@/modules/parcel-sync/services/eterra-client";
|
|
import { LAYER_CATALOG } from "@/modules/parcel-sync/services/eterra-layers";
|
|
import { fetchUatGeometry } from "@/modules/parcel-sync/services/uat-geometry";
|
|
import { getSessionCredentials } from "@/modules/parcel-sync/services/session-store";
|
|
|
|
export const runtime = "nodejs";
|
|
export const dynamic = "force-dynamic";
|
|
|
|
type Body = {
|
|
username?: string;
|
|
password?: string;
|
|
siruta?: string | number;
|
|
layerIds?: string[]; // subset — omit to count all
|
|
};
|
|
|
|
/**
|
|
* POST — Count features per layer on the remote eTerra server.
|
|
* Supports session-based auth (falls back to env vars).
|
|
*/
|
|
export async function POST(req: Request) {
|
|
try {
|
|
const body = (await req.json()) as Body;
|
|
const session = getSessionCredentials();
|
|
const username = String(
|
|
body.username || session?.username || process.env.ETERRA_USERNAME || "",
|
|
).trim();
|
|
const password = String(
|
|
body.password || session?.password || process.env.ETERRA_PASSWORD || "",
|
|
).trim();
|
|
const siruta = String(body.siruta ?? "").trim();
|
|
|
|
if (!username || !password)
|
|
return NextResponse.json({ error: "Credențiale lipsă" }, { status: 400 });
|
|
if (!/^\d+$/.test(siruta))
|
|
return NextResponse.json({ error: "SIRUTA invalid" }, { status: 400 });
|
|
|
|
const client = await EterraClient.create(username, password);
|
|
let uatGeometry: EsriGeometry | undefined;
|
|
|
|
// Pre-fetch UAT geometry for spatial layers
|
|
try {
|
|
uatGeometry = await fetchUatGeometry(client, siruta);
|
|
} catch {
|
|
// Some layers don't need it
|
|
}
|
|
|
|
const layers = body.layerIds
|
|
? LAYER_CATALOG.filter((l) => body.layerIds!.includes(l.id))
|
|
: LAYER_CATALOG;
|
|
|
|
const results: Record<string, { count: number; error?: string }> = {};
|
|
|
|
// Count layers in parallel, max 4 concurrent
|
|
const chunks: (typeof layers)[] = [];
|
|
for (let i = 0; i < layers.length; i += 4) {
|
|
chunks.push(layers.slice(i, i + 4));
|
|
}
|
|
|
|
for (const chunk of chunks) {
|
|
const promises = chunk.map(async (layer) => {
|
|
try {
|
|
const count =
|
|
layer.spatialFilter && uatGeometry
|
|
? await client.countLayerByGeometry(layer, uatGeometry)
|
|
: await client.countLayer(layer, siruta);
|
|
results[layer.id] = { count };
|
|
} catch (err) {
|
|
results[layer.id] = {
|
|
count: 0,
|
|
error: err instanceof Error ? err.message : "eroare",
|
|
};
|
|
}
|
|
});
|
|
await Promise.all(promises);
|
|
}
|
|
|
|
return NextResponse.json({ siruta, counts: results });
|
|
} catch (error) {
|
|
const message = error instanceof Error ? error.message : "Eroare server";
|
|
return NextResponse.json({ error: message }, { status: 500 });
|
|
}
|
|
}
|