espace-paie-odentas/app/api/documents/route.ts

156 lines
No EOL
5.5 KiB
TypeScript

// app/api/documents/route.ts
export const dynamic = "force-dynamic";
import { NextResponse } from "next/server";
import { cookies } from "next/headers";
import { createRouteHandlerClient } from "@supabase/auth-helpers-nextjs";
import { getS3SignedUrl } from "@/lib/aws-s3";
function json(status: number, body: any) {
return NextResponse.json(body, { status });
}
export async function GET(req: Request) {
try {
const c = cookies();
const sb = createRouteHandlerClient({ cookies });
// 1) Récupérer la catégorie depuis les query params
const { searchParams } = new URL(req.url);
const category = searchParams.get("category");
const metadataOnly = searchParams.get("metadata_only") === "true";
const period = searchParams.get("period");
if (!category) {
return json(400, { error: "missing_category_parameter" });
}
console.log('📄 Documents API - Category:', category, 'Metadata only:', metadataOnly, 'Period:', period);
// 2) Déterminer l'organisation active
let orgId = c.get("active_org_id")?.value || "";
console.log('📄 Documents API - Org ID from cookie:', orgId);
console.log('📄 Documents API - All cookies:', {
active_org_id: c.get("active_org_id")?.value,
active_org_name: c.get("active_org_name")?.value,
active_org_key: c.get("active_org_key")?.value,
});
// 3) Si pas d'orgId dans les cookies, vérifier si c'est un client authentifié
if (!orgId) {
const { data: { user }, error: userError } = await sb.auth.getUser();
console.log('📄 Documents API - User:', user?.id, 'Error:', userError);
if (!user) {
return json(401, { error: "unauthorized", details: "No user found" });
}
// Vérifier si c'est un staff
const { data: staffUser } = await sb
.from("staff_users")
.select("is_staff")
.eq("user_id", user.id)
.maybeSingle();
console.log('📄 Documents API - Is staff?', staffUser?.is_staff);
// Si c'est un staff sans org sélectionnée, retourner une erreur explicite
if (staffUser?.is_staff) {
return json(400, {
error: "no_organization_selected",
details: "Staff user must select an organization first"
});
}
// Récupérer l'organisation du client via organization_members
const { data: member, error: memberError } = await sb
.from("organization_members")
.select("org_id")
.eq("user_id", user.id)
.eq("revoked", false)
.maybeSingle();
console.log('📄 Documents API - Member:', member, 'Error:', memberError);
if (member?.org_id) {
orgId = member.org_id;
console.log('📄 Documents API - Org ID from member:', orgId);
}
}
if (!orgId) {
return json(400, { error: "no_organization_found" });
}
// 4) Récupérer les documents depuis Supabase avec RLS
console.log('📄 Documents API - Fetching from Supabase with org_id:', orgId, 'category:', category);
let query = sb
.from("documents")
.select("*")
.eq("org_id", orgId)
.eq("category", category);
// Filtrer par période si spécifié
if (period) {
query = query.eq("period_label", period);
}
const { data: documents, error } = await query.order("date_added", { ascending: false });
if (error) {
console.error('📄 Documents API - Supabase Error:', error);
return json(500, { error: "supabase_error", details: error.message });
}
console.log('📄 Documents API - Found documents:', documents?.length || 0);
// 5) Transformer les documents au format attendé par le frontend
// Si metadata_only=true, ne pas générer les URLs pré-signées S3
// Exclure les fichiers .DS_Store et autres fichiers système
const formattedDocuments = await Promise.all(
(documents || [])
.filter(doc => {
// Exclure les fichiers .DS_Store et autres fichiers système
const filename = doc.filename || '';
return !filename.startsWith('.') && filename !== '.DS_Store';
})
.map(async (doc) => {
let presignedUrl: string | null = null;
// Générer l'URL S3 présignée seulement si demandé (pas en mode metadata_only)
if (!metadataOnly && doc.storage_path) {
try {
presignedUrl = await getS3SignedUrl(doc.storage_path, 3600); // Expire dans 1 heure
console.log('✅ Generated presigned URL for:', doc.filename);
} catch (error) {
console.error('❌ Error generating presigned URL for:', doc.filename, error);
}
}
return {
id: doc.id,
title: doc.filename || doc.type_label || 'Document',
url: presignedUrl, // null si metadata_only=true
updatedAt: doc.date_added,
sizeBytes: doc.size_bytes || 0,
period_label: doc.period_label,
meta: {
category: doc.category,
type_label: doc.type_label,
storage_path: doc.storage_path, // Garder le path original pour référence
}
};
})
);
console.log('📄 Documents API - Returning formatted documents:', formattedDocuments.length);
return json(200, formattedDocuments);
} catch (err: any) {
console.error('📄 Documents API - Unexpected error:', err);
return json(500, { error: "server_error", message: err.message });
}
}