Files
pagodera/app/api/images/route.ts
T
Evandro Fonseca Junior ab37b477df feat: implement market page with QueryProvider and dynamic listings
- wrap root layout with QueryProvider for React Query
- replace market UnderConstruction placeholder with MarketClient and real data fetching
- implement search, pagination, and sort via search params using getActiveListings
- add necessary client components and queries
- update dependencies (e.g., prisma, pkg-types)
2025-11-05 01:58:03 -03:00

129 lines
4.7 KiB
TypeScript

import { NextRequest } from "next/server";
import fs from "node:fs";
import path from "node:path";
import { getItemById } from "@/lib/items-db";
import { getItemByIdUnified } from "@/lib/db/queries/items";
import { buildItemImagePath } from "@/lib/item-images";
export async function GET(req: NextRequest) {
const { searchParams } = new URL(req.url);
const relPath = searchParams.get("path") || "";
const itemId = searchParams.get("item");
const itemName = searchParams.get("name"); // Nome do item para validação (opcional)
let imagePath: string | null = null;
// Se foi fornecido um item ID, buscar o item no banco
if (itemId) {
try {
const itemIdNum = parseInt(itemId, 10);
if (!isNaN(itemIdNum)) {
// Tentar primeiro buscar na tabela unificada PostgreSQL
// Se a tabela não existir, retornará null silenciosamente
let item: any = null;
item = await getItemByIdUnified(itemIdNum);
// Se encontrou na tabela unificada, validar o nome se fornecido
if (item && itemName && item.item_name) {
if (item.item_name.toLowerCase() !== itemName.toLowerCase()) {
// Nome não bate, ignorar este resultado
item = null;
}
}
// Se não encontrou na tabela unificada, tentar SQLite legado
// Passar itemName para buscar por ID E NOME (evita ambiguidade)
if (!item) {
item = getItemById(itemIdNum, itemName || undefined);
}
if (item) {
// PRIORIDADE: 1. image_local_path (local), 2. image_url (externa), 3. image (fallback)
const imageLocalPath = item.image_local_path || "";
const imageUrl = item.image_url || "";
const image = item.image || "";
// Tentar primeiro a imagem local
if (imageLocalPath) {
const normalizedPath = imageLocalPath.replace(/\\/g, "/");
const category = (item.categoria || item.category || "other").toLowerCase();
// Se já for um caminho completo (começa com data/), usar diretamente
if (normalizedPath.startsWith("data/")) {
imagePath = normalizedPath;
} else {
// Construir o caminho usando a função helper
imagePath = buildItemImagePath(category, normalizedPath);
}
// Verificar se o arquivo existe antes de usar
if (imagePath) {
const baseDir = path.join(process.cwd(), "data", "images");
const resolved = path.join(process.cwd(), imagePath);
if (resolved.startsWith(baseDir)) {
try {
await fs.promises.access(resolved);
// Arquivo existe, usar este caminho
} catch {
// Arquivo não existe, tentar fallback externo
imagePath = null;
}
}
}
}
// Se não encontrou imagem local ou não existe, usar URL externa como fallback
if (!imagePath && (imageUrl || image)) {
const externalUrl = imageUrl || image;
if (externalUrl.startsWith("http://") || externalUrl.startsWith("https://")) {
return Response.redirect(externalUrl, 302);
}
}
}
}
} catch (error) {
console.error("[api/images] Erro ao buscar item:", error);
}
} else if (relPath) {
// Se foi fornecido um path, usar diretamente
imagePath = relPath;
}
if (!imagePath) {
// Se não foi possível construir o caminho, retornar 404 ao invés de 400
// para evitar erros visíveis no console do navegador
return new Response("Not Found", { status: 404 });
}
// Permitir apenas caminhos sob data/images para segurança
const baseDir = path.join(process.cwd(), "data", "images");
const resolved = path.join(process.cwd(), imagePath);
if (!resolved.startsWith(baseDir)) {
return new Response("Forbidden", { status: 403 });
}
try {
const file = await fs.promises.readFile(resolved);
const ext = path.extname(resolved).toLowerCase();
const contentType =
ext === ".gif"
? "image/gif"
: ext === ".png"
? "image/png"
: ext === ".webp"
? "image/webp"
: ext === ".jpg" || ext === ".jpeg"
? "image/jpeg"
: "application/octet-stream";
return new Response(file, { status: 200, headers: { "Content-Type": contentType } });
} catch (error) {
console.error("[api/images] Erro ao ler arquivo:", error);
// Retornar 404 silenciosamente para não gerar erros no console
return new Response("Not Found", { status: 404 });
}
}