First upload
This commit is contained in:
74
server/api/auth.js
Normal file
74
server/api/auth.js
Normal file
@@ -0,0 +1,74 @@
|
||||
import { Hono } from 'hono'
|
||||
import { sign } from 'hono/jwt'
|
||||
import { pool } from '../services/db.service.js'
|
||||
|
||||
const auth = new Hono()
|
||||
|
||||
// Configuración externa
|
||||
const SYNO_BASE = 'http://192.168.1.100:5000/webapi/auth.cgi'
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'cambia_esto_en_el_env'
|
||||
|
||||
auth.post('/login', async (c) => {
|
||||
const { username, password } = await c.req.json().catch(() => ({}))
|
||||
|
||||
if (!username || !password) {
|
||||
return c.json({ success: false, message: 'Faltan credenciales' }, 400)
|
||||
}
|
||||
|
||||
try {
|
||||
// 1. Preparar parámetros para el NAS Synology
|
||||
const params = new URLSearchParams({
|
||||
api: 'SYNO.API.Auth',
|
||||
version: '6',
|
||||
method: 'login',
|
||||
account: username,
|
||||
passwd: password,
|
||||
format: 'sid'
|
||||
})
|
||||
|
||||
// 2. Petición al NAS usando el fetch nativo
|
||||
const response = await fetch(`${SYNO_BASE}?${params.toString()}`)
|
||||
const data = await response.json()
|
||||
|
||||
if (data.success && data.data) {
|
||||
// 3. Generar JWT (expiración en 8 horas)
|
||||
const payload = {
|
||||
username,
|
||||
sid: data.data.sid,
|
||||
exp: Math.floor(Date.now() / 1000) + (60 * 60 * 8)
|
||||
}
|
||||
|
||||
const token = await sign(payload, JWT_SECRET)
|
||||
|
||||
// 4. Asegurar el usuario en la base de datos (MariaDB)
|
||||
try {
|
||||
await pool.query('INSERT IGNORE INTO Usuarios (Usuario) VALUES (?)', [username])
|
||||
} catch (dbError) {
|
||||
console.error('Error al registrar usuario en DB:', dbError)
|
||||
}
|
||||
|
||||
return c.json({
|
||||
success: true,
|
||||
token,
|
||||
data: {
|
||||
user: { username }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Error de autenticación del NAS
|
||||
return c.json({
|
||||
success: false,
|
||||
message: `Error de autenticación (Código: ${data.error?.code || 'unknown'})`
|
||||
}, 401)
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error crítico en Auth:', error)
|
||||
return c.json({
|
||||
success: false,
|
||||
message: 'NAS Unreachable / Internal Error'
|
||||
}, 500)
|
||||
}
|
||||
})
|
||||
|
||||
export default auth
|
||||
132
server/api/db.js
Normal file
132
server/api/db.js
Normal file
@@ -0,0 +1,132 @@
|
||||
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
|
||||
33
server/api/mail.js
Normal file
33
server/api/mail.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Hono } from 'hono'
|
||||
import { send } from '../services/mail.service.js'
|
||||
|
||||
const mail = new Hono()
|
||||
|
||||
/**
|
||||
* Endpoint para envío de correo
|
||||
* Soporta GET (para pruebas rápidas) y POST (para producción)
|
||||
*/
|
||||
mail.on(['GET', 'POST'], '/', async (c) => {
|
||||
try {
|
||||
// Llamamos al servicio de correo
|
||||
// Nota: Aquí podrías extraer to, subject y html de c.req.json() o c.req.query()
|
||||
await send(
|
||||
'natxocc@natxocc.com',
|
||||
'Prueba desde Hono',
|
||||
'<h1>Este es un correo de prueba</h1>'
|
||||
)
|
||||
|
||||
return c.json({
|
||||
success: true,
|
||||
message: 'Email enviado correctamente'
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error en ruta mail:', error)
|
||||
return c.json({
|
||||
success: false,
|
||||
error: error.message
|
||||
}, 500)
|
||||
}
|
||||
})
|
||||
|
||||
export default mail
|
||||
61
server/api/soap.js
Normal file
61
server/api/soap.js
Normal file
@@ -0,0 +1,61 @@
|
||||
import { Hono } from 'hono'
|
||||
import { soapCall } from '../services/soap2.service.js'
|
||||
|
||||
const api = new Hono()
|
||||
|
||||
/**
|
||||
* Endpoint simplificado: /api/soap/12345/Polizas
|
||||
* El servicio soapCall se encarga de traducir "Polizas" a "DescargaPolizas"
|
||||
*/
|
||||
api.get('/:CodigoMediador/:alias', async (c) => {
|
||||
const params = c.req.param() // Contiene CodigoMediador y alias
|
||||
const query = c.req.query()
|
||||
|
||||
try {
|
||||
// Pasamos params directamente porque soapCall ya sabe buscar el 'alias'
|
||||
const result = await soapCall(params, query)
|
||||
|
||||
return c.json({
|
||||
success: true,
|
||||
data: result
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(`[Router Error] ${params.alias}:`, error.message)
|
||||
return c.json({
|
||||
success: false,
|
||||
message: error.message || 'Error en el servicio externo SOAP'
|
||||
}, 500)
|
||||
}
|
||||
})
|
||||
|
||||
export default api
|
||||
/*
|
||||
import { Hono } from 'hono'
|
||||
import { soapCall } from '../services/soap2.service.js'
|
||||
|
||||
const api = new Hono()
|
||||
|
||||
api.get('/:CodigoMediador/:service/:method', async (c) => {
|
||||
const params = c.req.param()
|
||||
const query = c.req.query()
|
||||
|
||||
try {
|
||||
const result = await soapCall(params, query)
|
||||
|
||||
return c.json({
|
||||
success: true,
|
||||
message: false,
|
||||
data: result
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(`Error en llamada SOAP ${params.service}/${params.method}:`, error)
|
||||
|
||||
return c.json({
|
||||
success: false,
|
||||
message: error.message || 'Error en el servicio externo SOAP'
|
||||
}, 500)
|
||||
}
|
||||
})
|
||||
|
||||
export default api
|
||||
*/
|
||||
Reference in New Issue
Block a user