feat(install): agregar opcion --empty-academic en install.sh e init_db.py para inicializar base de datos sin datos demo

This commit is contained in:
2026-09-23 20:44:08 -03:00
parent ddd1714eb2
commit 95d2aac323
5 changed files with 196 additions and 102 deletions
+141 -90
View File
@@ -8,6 +8,7 @@ if hasattr(sys.stderr, 'reconfigure'):
sys.stderr.reconfigure(encoding='utf-8')
from app import create_app, db
from app import models
from app.models.user import User
from app.models.role import Role, Permission, SYSTEM_MODULES
from sqlalchemy import text
@@ -313,6 +314,49 @@ def init_database():
# 4. Verificar o crear usuarios institucionales de cada rol
keep_users = ('--keep-users' in sys.argv) or (os.environ.get('KEEP_USERS', '').lower() in ['1', 'true', 'yes'])
empty_academic = any(arg in sys.argv for arg in ['--empty-academic', '--no-demo', '--clean-db', '--without-demo-data', '--skip-demo']) or \
(os.environ.get('EMPTY_ACADEMIC', '').lower() in ['1', 'true', 'yes'])
if empty_academic:
print("[*] Opción --empty-academic activa: Se configurará la base de datos limpia SIN carreras, materias, ciclos lectivos, aulas, edificios ni reservas por defecto.")
try:
from app.models.reservation import Reservation
from app.models.grade import MilestoneGrade
from app.models.milestone import AcademicMilestone
from app.models.subject import CommissionTeacher, Commission, Subject
from app.models.enrollment import StudentEnrollment
from app.models.career import Career
from app.models.classroom import ClassroomResource, Classroom
from app.models.building import Building
from app.models.academic_term import AcademicTerm
Reservation.query.delete()
try:
MilestoneGrade.query.delete()
AcademicMilestone.query.delete()
except Exception:
pass
try:
CommissionTeacher.query.delete()
except Exception:
pass
StudentEnrollment.query.delete()
Commission.query.delete()
Subject.query.delete()
Career.query.delete()
try:
ClassroomResource.query.delete()
except Exception:
pass
Classroom.query.delete()
Building.query.delete()
AcademicTerm.query.delete()
db.session.commit()
print(" [OK] Tablas de carreras, materias, comisiones, aulas, edificios y reservas aseguradas vacías.")
except Exception as pe:
db.session.rollback()
print(f" [!] Nota durante verificación de tablas académicas vacías: {pe}")
if keep_users:
print("[*] Opción --keep-users activa: Preservando usuarios, roles y contraseñas existentes intactos (no se modifican ni pisan).")
else:
@@ -380,33 +424,36 @@ def init_database():
print(f" [OK] Usuario {u_info['email']} validado (Rol: {u_info['role_name']}).")
# 5. Inicializar edificios institucionales oficiales
print("[*] Verificando edificios institucionales...")
from app.models.building import Building
b_central = Building.query.filter_by(name='Edificio Central').first()
if not b_central:
b_central = Building(
name='Edificio Central',
code='CENTRAL',
address='Tte. Gral. Juan Domingo Peron 802, CABA',
floors=4,
description='Sede central institucional de UniCABA. Aulas de grado, auditorio y laboratorios.'
)
db.session.add(b_central)
else:
b_central.address = 'Tte. Gral. Juan Domingo Peron 802, CABA'
if not empty_academic:
print("[*] Verificando edificios institucionales...")
from app.models.building import Building
b_central = Building.query.filter_by(name='Edificio Central').first()
if not b_central:
b_central = Building(
name='Edificio Central',
code='CENTRAL',
address='Tte. Gral. Juan Domingo Peron 802, CABA',
floors=4,
description='Sede central institucional de UniCABA. Aulas de grado, auditorio y laboratorios.'
)
db.session.add(b_central)
else:
b_central.address = 'Tte. Gral. Juan Domingo Peron 802, CABA'
b_virtual = Building.query.filter_by(name='Campus Virtual').first()
if not b_virtual:
b_virtual = Building(
name='Campus Virtual',
code='VIRTUAL',
address='Entorno Digital / Microsoft Teams - Moodle',
floors=0,
description='Entorno de aulas virtuales y clases a distancia'
)
db.session.add(b_virtual)
db.session.commit()
print("[OK] Edificios institucionales configurados con dirección oficial.")
b_virtual = Building.query.filter_by(name='Campus Virtual').first()
if not b_virtual:
b_virtual = Building(
name='Campus Virtual',
code='VIRTUAL',
address='Entorno Digital / Microsoft Teams - Moodle',
floors=0,
description='Entorno de aulas virtuales y clases a distancia'
)
db.session.add(b_virtual)
db.session.commit()
print("[OK] Edificios institucionales configurados con dirección oficial.")
else:
print("[*] Modo --empty-academic: Omitiendo creación de edificios institucionales por defecto.")
# 6. Inicializar catalogo dinamico de tipificaciones de hitos academicos
print("[*] Verificando catalogo de tipificaciones de hitos academicos...")
@@ -432,76 +479,80 @@ def init_database():
print(f"[OK] Catalogo de tipificaciones inicializado ({MilestoneType.query.count()} tipos disponibles).")
# 7. Inicializar aulas, materias, comisiones y reservas de muestra
from app.models.classroom import Classroom
from app.models.subject import Subject, Commission
from app.models.reservation import Reservation, ReservationStatus
from datetime import datetime, timedelta, date
if not empty_academic:
from app.models.classroom import Classroom
from app.models.subject import Subject, Commission
from app.models.reservation import Reservation, ReservationStatus
from datetime import datetime, timedelta, date
if Classroom.query.count() == 0:
print("[*] Generando catalogo de aulas...")
for floor in ['PB', '1', '2', '3']:
for num in range(1, 8):
code = f'{floor}0{num}' if floor != 'PB' else f'PB-0{num}'
c = Classroom(
code=code,
building=b_central.name,
building_id=b_central.id,
floor=floor,
capacity=30 + (num * 5),
description=f'Aula física estándar {code} en {b_central.name}',
if Classroom.query.count() == 0 and 'b_central' in locals() and b_central and 'b_virtual' in locals() and b_virtual:
print("[*] Generando catalogo de aulas...")
for floor in ['PB', '1', '2', '3']:
for num in range(1, 8):
code = f'{floor}0{num}' if floor != 'PB' else f'PB-0{num}'
c = Classroom(
code=code,
building=b_central.name,
building_id=b_central.id,
floor=floor,
capacity=30 + (num * 5),
description=f'Aula física estándar {code} en {b_central.name}',
is_active=True
)
db.session.add(c)
for v in range(1, 4):
vc = Classroom(
code=f'VIRTUAL-0{v}',
building=b_virtual.name,
building_id=b_virtual.id,
floor='0',
capacity=100,
description=f'Sala virtual Microsoft Teams {v}',
is_active=True
)
db.session.add(c)
db.session.add(vc)
db.session.commit()
print(f"[OK] {Classroom.query.count()} aulas creadas.")
for v in range(1, 4):
vc = Classroom(
code=f'VIRTUAL-0{v}',
building=b_virtual.name,
building_id=b_virtual.id,
floor='0',
capacity=100,
description=f'Sala virtual Microsoft Teams {v}',
is_active=True
)
db.session.add(vc)
db.session.commit()
print(f"[OK] {Classroom.query.count()} aulas creadas.")
# Materia y Comisión
s = Subject.query.filter_by(code='ARQ-101').first()
if not s:
s = Subject(name='Arquitectura de Software', code='ARQ-101', is_active=True)
db.session.add(s)
db.session.commit()
# Materia y Comisión
s = Subject.query.filter_by(code='ARQ-101').first()
if not s:
s = Subject(name='Arquitectura de Software', code='ARQ-101', is_active=True)
db.session.add(s)
db.session.commit()
comm = Commission.query.filter_by(code='COM-A').first()
if not comm:
comm = Commission(code='COM-A', subject_id=s.id, shift='Noche', semester=2, year=2026, max_students=40, is_active=True)
db.session.add(comm)
db.session.commit()
comm = Commission.query.filter_by(code='COM-A').first()
if not comm:
comm = Commission(code='COM-A', subject_id=s.id, shift='Noche', semester=2, year=2026, max_students=40, is_active=True)
db.session.add(comm)
db.session.commit()
# Reservas de Hoy
if Reservation.query.count() == 0:
print("[*] Generando reservas de muestra...")
today = date.today()
classrooms = Classroom.query.all()
docente = User.query.filter_by(email='docente@edu-space.com').first()
for idx, cl in enumerate(classrooms[:19]):
start_hour = 8 + (idx % 6) * 2
r = Reservation(
classroom_id=cl.id,
commission_id=comm.id,
user_id=docente.id if docente else 1,
start_time=datetime.combine(today, datetime.min.time()) + timedelta(hours=start_hour),
end_time=datetime.combine(today, datetime.min.time()) + timedelta(hours=start_hour + 2),
purpose='Clase Regular',
status=ReservationStatus.CONFIRMED.value,
shift='Noche' if start_hour >= 18 else 'Tarde' if start_hour >= 13 else 'Mañana',
expected_attendees=cl.capacity - 5
)
db.session.add(r)
db.session.commit()
print(f"[OK] {Reservation.query.count()} reservas creadas.")
# Reservas de Hoy
if Reservation.query.count() == 0:
print("[*] Generando reservas de muestra...")
today = date.today()
classrooms = Classroom.query.all()
docente = User.query.filter_by(email='docente@edu-space.com').first()
for idx, cl in enumerate(classrooms[:19]):
start_hour = 8 + (idx % 6) * 2
r = Reservation(
classroom_id=cl.id,
commission_id=comm.id,
user_id=docente.id if docente else 1,
start_time=datetime.combine(today, datetime.min.time()) + timedelta(hours=start_hour),
end_time=datetime.combine(today, datetime.min.time()) + timedelta(hours=start_hour + 2),
purpose='Clase Regular',
status=ReservationStatus.CONFIRMED.value,
shift='Noche' if start_hour >= 18 else 'Tarde' if start_hour >= 13 else 'Mañana',
expected_attendees=cl.capacity - 5
)
db.session.add(r)
db.session.commit()
print(f"[OK] {Reservation.query.count()} reservas creadas.")
else:
print("[*] Modo --empty-academic: Omitiendo creación de aulas, materias, comisiones y reservas de muestra.")
print("[OK] Base de datos creada con tablas vacías para gestión académica y de espacios desde cero.")
print("\n[LISTO] Base de datos inicializada y lista para usar.")