215 lines
9.6 KiB
Python
215 lines
9.6 KiB
Python
import click
|
|
from flask import Flask
|
|
from flask.cli import with_appcontext
|
|
from flask_migrate import Migrate
|
|
from datetime import datetime
|
|
import os
|
|
from flask_cors import CORS
|
|
# Importamos la base de datos y los modelos del S.I.P
|
|
from app.database import db
|
|
from app.models import Role, User
|
|
from app.models.biometria import (
|
|
Persona, OrigenHuella, TiposF, Subclasificacion,
|
|
Huella, PuntoCaracteristico, HuellaPuntoCaracteristico, FichaClasificacion
|
|
)
|
|
|
|
# =========================================================
|
|
# 1. COMANDO CLI DE CLICK (Configurado Correctamente)
|
|
# =========================================================
|
|
@click.command(name="seed")
|
|
@with_appcontext
|
|
def seed_db_command():
|
|
"""Siembra de roles, usuarios administrativos y datos iniciales del S.I.P"""
|
|
click.echo("Iniciando el sembrado de datos en PostgreSQL...")
|
|
|
|
# --- [ROLES Y USUARIOS] ---
|
|
admin_role = Role.query.filter_by(name='admin').first()
|
|
if not admin_role:
|
|
admin_role = Role(name='admin', permissions=['read:users', 'write:users', 'manage:biometria'])
|
|
db.session.add(admin_role)
|
|
db.session.commit()
|
|
|
|
investigador_role = Role.query.filter_by(name='investigador').first()
|
|
if not investigador_role:
|
|
investigador_role = Role(name='investigador', permissions=['manage:biometria'])
|
|
db.session.add(investigador_role)
|
|
db.session.commit()
|
|
|
|
admin_user = User.query.filter_by(username='admin_root').first()
|
|
if not admin_user:
|
|
admin_user = User(username='admin_root', email='admin@uader.edu.ar', role_id=admin_role.id)
|
|
admin_user.set_password('admin1234')
|
|
db.session.add(admin_user)
|
|
db.session.commit()
|
|
|
|
investigador_user = User.query.filter_by(username='investigador_demo').first()
|
|
if not investigador_user:
|
|
investigador_user = User(username='investigador_demo', email='investigador@uader.edu.ar', role_id=investigador_role.id)
|
|
investigador_user.set_password('investigador1234')
|
|
db.session.add(investigador_user)
|
|
db.session.commit()
|
|
|
|
# --- [1. PERSONAS] ---
|
|
if Persona.query.count() == 0:
|
|
personas_data = [
|
|
Persona(cod_id=1, cod_nombre='Juan Pérez', fecha_nacimiento=datetime.strptime('1990-05-20', '%Y-%m-%d').date(), sexo='M'),
|
|
Persona(cod_id=2, cod_nombre='Ana Gómez', fecha_nacimiento=datetime.strptime('1985-12-01', '%Y-%m-%d').date(), sexo='F'),
|
|
Persona(cod_id=3, cod_nombre='Carlos López', fecha_nacimiento=datetime.strptime('2000-07-15', '%Y-%m-%d').date(), sexo='M')
|
|
]
|
|
db.session.bulk_save_objects(personas_data)
|
|
|
|
# --- [2. ORIGEN DE HUELLAS] ---
|
|
if OrigenHuella.query.count() == 0:
|
|
origenes_data = [
|
|
OrigenHuella(id=1, descripcion='Índice derecho', lado='derecho'),
|
|
OrigenHuella(id=2, descripcion='Índice izquierdo', lado='izquierdo'),
|
|
OrigenHuella(id=3, descripcion='Pulgar derecho', lado='derecho')
|
|
]
|
|
db.session.bulk_save_objects(origenes_data)
|
|
|
|
# --- [3. TIPOS FUNDAMENTALES] ---
|
|
if TiposF.query.count() == 0:
|
|
tipos_data = [
|
|
TiposF(id=1, nombre='Arco', descripcion='Huella en forma de arco', foto=None),
|
|
TiposF(id=2, nombre='Presilla', descripcion='Huella en forma de presilla', foto=None),
|
|
TiposF(id=3, nombre='Verticilo', descripcion='Huella en forma de espiral', foto=None)
|
|
]
|
|
db.session.bulk_save_objects(tipos_data)
|
|
db.session.commit()
|
|
|
|
# --- [4. SUBCLASIFICACIONES] ---
|
|
if Subclasificacion.query.count() == 0:
|
|
sub_data = [
|
|
Subclasificacion(id=1, nombre='Arco simple', tipo_f_id=1),
|
|
Subclasificacion(id=2, nombre='Presilla derecha', tipo_f_id=2),
|
|
Subclasificacion(id=3, nombre='Verticilo central', tipo_f_id=3)
|
|
]
|
|
db.session.bulk_save_objects(sub_data)
|
|
|
|
# --- [5. PUNTOS CARACTERÍSTICOS] ---
|
|
if PuntoCaracteristico.query.count() == 0:
|
|
puntos_data = [
|
|
PuntoCaracteristico(id=1, nombre='Bifurcación', foto=None),
|
|
PuntoCaracteristico(id=2, nombre='Final de cresta', foto=None),
|
|
PuntoCaracteristico(id=3, nombre='Punto de isla', foto=None)
|
|
]
|
|
db.session.bulk_save_objects(puntos_data)
|
|
|
|
db.session.commit()
|
|
|
|
# --- [6. HUELLAS] ---
|
|
if Huella.query.count() == 0:
|
|
huellas_data = [
|
|
Huella(id=1, descripcion='Huella digital clara', origen_hd='Escáner', foto=None, persona_cod_id=1, origen_huella_id=1),
|
|
Huella(id=2, descripcion='Huella con ligera distorsión', origen_hd='Tinta', foto=None, persona_cod_id=2, origen_huella_id=2),
|
|
Huella(id=3, descripcion='Huella poco definida', origen_hd='Escáner', foto=None, persona_cod_id=3, origen_huella_id=3)
|
|
]
|
|
db.session.bulk_save_objects(huellas_data)
|
|
db.session.commit()
|
|
|
|
# --- [7. COORDENADAS PIVOTE] ---
|
|
if HuellaPuntoCaracteristico.query.count() == 0:
|
|
coordenadas_data = [
|
|
HuellaPuntoCaracteristico(huella_id=1, punto_id=1, x=12.345678, y=45.678912, angulo=30.00),
|
|
HuellaPuntoCaracteristico(huella_id=1, punto_id=2, x=15.111111, y=50.222222, angulo=45.00),
|
|
HuellaPuntoCaracteristico(huella_id=2, punto_id=3, x=20.333333, y=60.444444, angulo=60.00)
|
|
]
|
|
db.session.bulk_save_objects(coordenadas_data)
|
|
|
|
# --- [8. FICHAS DE CLASIFICACIÓN] ---
|
|
if FichaClasificacion.query.count() == 0:
|
|
fichas_data = [
|
|
FichaClasificacion(id=1, huella_id=1, subclasificacion_id=1, tipos_f_id=1, fecha=datetime.strptime('2025-09-30', '%Y-%m-%d').date()),
|
|
FichaClasificacion(id=2, huella_id=2, subclasificacion_id=2, tipos_f_id=2, fecha=datetime.strptime('2025-09-30', '%Y-%m-%d').date()),
|
|
FichaClasificacion(id=3, huella_id=3, subclasificacion_id=3, tipos_f_id=3, fecha=datetime.strptime('2025-09-30', '%Y-%m-%d').date())
|
|
]
|
|
db.session.bulk_save_objects(fichas_data)
|
|
|
|
db.session.commit()
|
|
click.echo("¡Base de datos del S.I.P sembrada e integrada al 100%!")
|
|
|
|
|
|
# =========================================================
|
|
# 2. FABRICA DE LA APLICACIÓN (Application Factory)
|
|
# =========================================================
|
|
|
|
|
|
def create_app():
|
|
app = Flask(__name__)
|
|
|
|
# 3. Inicialización de Flask-CORS agresiva a nivel de aplicación interna
|
|
CORS(app, resources={r"/*": {"origins": "*"}}, supports_credentials=True)
|
|
|
|
# 4. CAPA DE CONTROL ADICIONAL: Interceptor nativo de Preflight Checks
|
|
@app.after_request
|
|
def add_cors_headers(response):
|
|
# Permitimos cualquier origen de desarrollo (como tu puerto 8080)
|
|
response.headers["Access-Control-Allow-Origin"] = "*"
|
|
response.headers["Access-Control-Allow-Headers"] = "Content-Type,Authorization"
|
|
response.headers["Access-Control-Allow-Methods"] = "GET,POST,PUT,DELETE,OPTIONS"
|
|
return response
|
|
|
|
@app.before_request
|
|
def handle_options_directly():
|
|
from flask import make_response, request
|
|
# Si el navegador pregunta mediante OPTIONS, respondemos de inmediato con 200 OK
|
|
# saltándonos cualquier validación posterior de rutas o Blueprints
|
|
if request.method.upper() == "OPTIONS":
|
|
response = make_response()
|
|
response.headers["Access-Control-Allow-Origin"] = "*"
|
|
response.headers["Access-Control-Allow-Headers"] = "Content-Type,Authorization"
|
|
response.headers["Access-Control-Allow-Methods"] = "GET,POST,PUT,DELETE,OPTIONS"
|
|
return response, 200
|
|
|
|
# Mapeo exacto de tu archivo .env de la raíz
|
|
POSTGRES_USER = os.getenv('POSTGRES_USER', 'admin')
|
|
POSTGRES_PASSWORD = os.getenv('POSTGRES_PASSWORD', 'secretpassword_2026_x8')
|
|
POSTGRES_DB = os.getenv('POSTGRES_DB', 'huellas_investigacion')
|
|
POSTGRES_HOST = os.getenv('POSTGRES_HOST', 'db') # Cambiado a 'db' según tu .env
|
|
POSTGRES_PORT = os.getenv('POSTGRES_PORT', '5432')
|
|
|
|
# Reconstruimos la URI de forma segura en Python para evitar fallos de interpolación string
|
|
app.config['SQLALCHEMY_DATABASE_URI'] = f'postgresql://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_HOST}:{POSTGRES_PORT}/{POSTGRES_DB}'
|
|
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
|
|
|
# Secreto para los Tokens JWT de tu módulo auth
|
|
app.config['JWT_SECRET_KEY'] = os.getenv('JWT_SECRET_KEY', 'laravel_style_jwt_secret_token_scientific_2026')
|
|
|
|
# Inicializar base de datos y migraciones
|
|
db.init_app(app)
|
|
Migrate(app, db)
|
|
|
|
# =========================================================
|
|
# REGISTRO DE BLUEPRINTS (Normalización de Prefijos REST)
|
|
# =========================================================
|
|
try:
|
|
# 1. Rutas de Autenticación
|
|
from app.routes.auth import auth_bp
|
|
# Mapea directamente: POST /api/auth/login y GET /api/auth/me
|
|
app.register_blueprint(auth_bp, url_prefix='/api/auth')
|
|
print("-> Blueprint 'auth' registrado en /api/auth")
|
|
|
|
# 2. Rutas de Usuarios
|
|
from app.routes.users import users_bp
|
|
# Al poner el prefijo '/api' a secas, mapea exacto: GET /api/users
|
|
app.register_blueprint(users_bp, url_prefix='/api')
|
|
print("-> Blueprint 'users' registrado en /api")
|
|
|
|
# 3. Rutas de Roles
|
|
from app.routes.roles import roles_bp
|
|
# Al poner el prefijo '/api' a secas, mapea exacto: GET /api/roles y POST /api/roles
|
|
app.register_blueprint(roles_bp, url_prefix='/api')
|
|
print("-> Blueprint 'roles' registrado en /api")
|
|
|
|
except ImportError as e:
|
|
print(f"⚠️ Error al importar los módulos de rutas: {e}")
|
|
|
|
# Registrar comando seed
|
|
app.cli.add_command(seed_db_command)
|
|
|
|
return app
|
|
|
|
app = create_app()
|
|
|
|
if __name__ == '__main__':
|
|
app.run(host='0.0.0.0', port=5000) |