import { Hono } from 'hono' import { jwt } from 'hono/jwt' import { db, trx } from '../services/db.service.js' import { actions } from '../actions/db.actions.js' import sharp from 'sharp' import path from 'path' import mime from 'mime-types' const api = new Hono() const JWT_SECRET = process.env.JWT_SECRET || 'tu_clave_secreta' // --- MIDDLEWARE AUTH CON BYPASS --- // api.use('/*', async (c, next) => { // if (process.env.DISABLE_AUTH === 'true') { // c.set('jwtPayload', { username: 'TEST_USER', role: 'admin' }) // return await next() // } // const jwtMiddleware = jwt({ secret: JWT_SECRET, alg: 'HS256' }) // return jwtMiddleware(c, next) // }) // --- RUTA PARA TRANSACCIONES (TRX) --- api.on(['GET', 'POST'], '/', async (c) => { const body = c.req.method === 'POST' ? await c.req.json().catch(() => ({})) : {} const query = c.req.query() const postData = { ...query, ...body } if (Object.keys(postData).length === 0) { return c.json({ success: false, error: 'No data provided' }, 400) } try { const data = await trx(postData, actions) // Manejo de BigInt para evitar errores en JSON.stringify const cleanData = JSON.parse(JSON.stringify(data, (_, v) => typeof v === 'bigint' ? v.toString() : v)) return c.json({ success: true, data: cleanData }) } catch (error) { return c.json({ success: false, error: error.message }, 500) } }) // --- RUTA FICHAR --- api.on(['GET', 'POST'], '/fichar/:query', async (c) => { const payload = c.get('jwtPayload') const user = payload?.username || 'ANONYMOUS' const queryType = c.req.param('query') try { const ret = queryType === 'nuevo' ? await db.raw('CALL RegistrarFichaje(:user)', { user }) : await db.raw('SELECT Fecha, Tipo, Duracion FROM UsuariosFichajes WHERE Usuario = :user ORDER BY id DESC LIMIT 1', { user }) return c.json({ success: true, data: ret }) } catch (error) { return c.json({ success: false, error: error.message }, 500) } }) // --- RUTA DE SUBIDA (UPLOAD) --- api.post('/upload', async (c) => { try { const body = await c.req.parseBody() const file = body.file if (!file) throw new Error('No se ha enviado ningún archivo') const arrayBuffer = await file.arrayBuffer() let finalBuffer = Buffer.from(arrayBuffer) const isImg = file.type.startsWith('image/') if (isImg) { finalBuffer = await sharp(finalBuffer) .resize(1024, null, { withoutEnlargement: true }) .jpeg({ quality: 75 }) .toBuffer() } const res = await db.insert('Documentos', { CodigoPoliza: body.CodigoPoliza || null, CodigoRecibo: body.CodigoRecibo ? BigInt(body.CodigoRecibo) : null, CodigoSiniestro: body.CodigoSiniestro ? BigInt(body.CodigoSiniestro) : null, NIF: body.NIF || null, Nombre: file.name, Extension: isImg ? '.jpg' : path.extname(file.name).toLowerCase(), Archivo: finalBuffer }) const insertId = Array.isArray(res) ? res[0].insertId : res?.insertId return c.json({ success: true, id: insertId?.toString() }) } catch (err) { return c.json({ success: false, error: err.message }, 500) } }) // --- RUTA DE DESCARGA --- api.get('/download', async (c) => { try { const { id, CodigoPoliza, CodigoRecibo, CodigoSiniestro, NIF, download } = c.req.query() const filtros = Object.fromEntries( Object.entries({ id, CodigoPoliza, CodigoRecibo, CodigoSiniestro, NIF }) .filter(([_, v]) => v) ) if (Object.keys(filtros).length === 0) return c.json({ success: false, error: 'Faltan parámetros' }, 400) const docs = await db.select('Documentos', filtros) if (!docs.length) return c.json({ success: false, error: 'Sin resultados' }, 404) if (id) { const doc = docs[0] const contentType = mime.lookup(doc.Extension) || 'application/octet-stream' c.header('Content-Type', contentType) c.header('Content-Disposition', `${download === 'true' ? 'attachment' : 'inline'}; filename="${doc.Nombre}"`) return c.body(doc.Archivo) } return c.json(docs.map((doc) => { const { Archivo, ...info } = doc return { ...info, id: info.id.toString(), url: `/api/db/download?id=${info.id}`, urlDownload: `/api/db/download?id=${info.id}&download=true` } })) } catch (err) { return c.json({ success: false, error: err.message }, 500) } }) export default api