Files
dtic-DIIAA/tools/adn/db/exporters/md_exporter.rb
T

131 lines
4.4 KiB
Ruby

# frozen_string_literal: true
require 'date'
module BitacorasDB
module Exporters
class MDExporter
def initialize(db, logger = nil)
@db = db
@logger = logger || default_logger
end
def exportar_bitacora(fecha, ruta_destino)
@logger.info("Exportando bitácora #{fecha} a #{ruta_destino}...")
bitacora = @db.find_bitacora_by_fecha(fecha)
unless bitacora
@logger.error("No se encontró la bitácora para la fecha: #{fecha}")
return false
end
bitacora_id = bitacora['id']
# Obtener datos estructurados (incluyendo lo nuevo)
entradas = @db.execute("
SELECT e.*, n.nombre as nodo_nombre
FROM bitacoras.entradas e
LEFT JOIN bitacoras.nodos n ON e.nodo_id = n.id
WHERE e.bitacora_id = $1
ORDER BY n.nombre, e.inicio ASC
", [bitacora_id])
gestion = @db.execute("
SELECT g.*, n.nombre as nodo_nombre
FROM bitacoras.gestion g
LEFT JOIN bitacoras.nodos n ON g.nodo_id = n.id
WHERE g.bitacora_id = $1 OR g.activo = true
ORDER BY g.tipo, g.orden
", [bitacora_id]) rescue [] # Por si la tabla no existe aún en otros entornos
resumenes = @db.execute("
SELECT r.*, n.nombre as nodo_nombre
FROM bitacoras.resumen_nodos r
JOIN bitacoras.nodos n ON r.nodo_id = n.id
WHERE r.bitacora_id = $1
", [bitacora_id]) rescue []
# Generar contenido Markdown
contenido = generar_markdown(fecha, bitacora['resumen'], gestion, resumenes, entradas)
File.write(ruta_destino, contenido)
@logger.info("✅ Exportación completada con éxito.")
true
rescue => e
@logger.error("Error exportando bitácora: #{e.message}")
false
end
private
def generar_markdown(fecha, resumen_gen, gestion, resumenes, entradas)
y, m, d = fecha.to_s.split('-')
md = String.new("<!-- GENERADO AUTOMÁTICAMENTE por adn db exportar:md — No editar manualmente -->\n")
md << "# Bitácora de Operaciones - #{d}/#{m}/#{y}\n\n"
if gestion && gestion.ntuples > 0
md << "## 📋 Control de Gestión\n\n"
pendientes = gestion.select { |g| g['tipo'] == 'pendiente' }
if pendientes.any?
md << "### 📝 Resumen de Actividades\n" # Formato ADN
md << "| NODO | PENDIENTES |\n| :--- | :--- |\n"
pendientes.each do |p|
md << "| #{p['nodo_nombre'] || '—'} | #{p['detalle']} |\n"
end
md << "\n"
end
en_proceso = gestion.select { |g| g['tipo'] == 'proceso' }
if en_proceso.any?
md << "### ⏳ En Proceso\n"
md << "| NODO | ACTIVIDAD |\n| :--- | :--- |\n"
en_proceso.each do |p|
md << "| #{p['nodo_nombre'] || '—'} | #{p['detalle']} |\n"
end
md << "\n"
end
end
if resumenes && resumenes.ntuples > 0
md << "### 📝 Resumen Integral\n"
md << "| NODO | RESUMEN INTEGRAL |\n| :--- | :--- |\n"
resumenes.each do |r|
md << "| #{r['nodo_nombre']} | #{r['resumen']} |\n"
end
md << "\n"
end
md << "## 📂 Actividades Detalladas\n\n"
por_nodo = entradas.group_by { |e| e['nodo_nombre'] || 'sin-nodo' }
por_nodo.each do |nodo, entries|
md << "### #{nodo}\n\n"
md << "| I | F | Descripción | E |\n"
md << "| :--- | :--- | :--- | :--- |\n"
entries.each do |e|
inicio = e['inicio'] ? e['inicio'][0..4] : '-'
fin = e['fin'] ? e['fin'][0..4] : '-'
ia = e['es_ia'] == 't' ? '(IA) ' : ''
estado = "[#{e['modo']}] #{e['estado']}"
md << "| #{inicio} | #{fin} | #{ia}#{e['descripcion']} | #{estado} |\n"
end
md << "\n"
end
md << "---\n"
md << "<!-- GENERADO AUTOMÁTICAMENTE desde PostgreSQL el #{Time.now.strftime('%Y-%m-%d %H:%M')} -->\n"
md << "<!-- Fuente de verdad: DB. Regenerar con: adn db exportar:md #{fecha} -->\n"
md
end
def default_logger
Class.new do
def info(msg); puts "[INFO] #{msg}"; end
def error(msg); puts "[ERROR] #{msg}"; end
end.new
end
end
end
end