#!/usr/bin/env python3 """ Application Startup Script This script initializes the database and creates default data for the dynamic application system. """ import sys import os import logging # Add src directory to path sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from config.database import init_database, get_engine from sqlalchemy.orm import Session from models.application_type import ( ApplicationType, ApplicationField, ApplicationTypeStatus, StatusTransition, FieldType, TransitionTriggerType ) from models.user import User, Role # Configure logging logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) def create_default_application_types(): """Create default QSM and VSM application types if they don't exist""" engine = get_engine() with Session(engine) as session: # Check if types already exist existing_qsm = session.query(ApplicationType).filter_by(type_id="qsm").first() existing_vsm = session.query(ApplicationType).filter_by(type_id="vsm").first() if existing_qsm and existing_vsm: logger.info("Default application types already exist") return # Create QSM type if not exists if not existing_qsm: logger.info("Creating QSM application type...") qsm_type = ApplicationType( type_id="qsm", name="QSM - Qualitätssicherungsmittel", description="Antrag für Qualitätssicherungsmittel zur Verbesserung der Lehre", is_active=True, is_public=True, max_cost_positions=100, max_comparison_offers=100 ) session.add(qsm_type) session.flush() # Create default statuses for QSM create_default_statuses(session, qsm_type) logger.info("QSM application type created successfully") # Create VSM type if not exists if not existing_vsm: logger.info("Creating VSM application type...") vsm_type = ApplicationType( type_id="vsm", name="VSM - Verfasste Studierendenschaft", description="Antrag für Mittel der Verfassten Studierendenschaft", is_active=True, is_public=True, max_cost_positions=100, max_comparison_offers=100 ) session.add(vsm_type) session.flush() # Create default statuses for VSM create_default_statuses(session, vsm_type) logger.info("VSM application type created successfully") session.commit() logger.info("Default application types initialization complete") def create_default_statuses(session, app_type: ApplicationType): """Create default statuses and transitions for an application type""" # Define default statuses statuses = [ { "status_id": "draft", "name": "Entwurf", "is_editable": True, "color": "#6B7280", "is_initial": True, "display_order": 0 }, { "status_id": "submitted", "name": "Eingereicht", "is_editable": False, "color": "#3B82F6", "send_notification": True, "display_order": 10 }, { "status_id": "under_review", "name": "In Prüfung", "is_editable": False, "color": "#8B5CF6", "display_order": 20 }, { "status_id": "approved", "name": "Genehmigt", "is_editable": False, "color": "#10B981", "is_final": True, "send_notification": True, "display_order": 30 }, { "status_id": "rejected", "name": "Abgelehnt", "is_editable": False, "color": "#EF4444", "is_final": True, "send_notification": True, "display_order": 40 } ] status_objects = {} for status_data in statuses: status = ApplicationTypeStatus( application_type_id=app_type.id, **status_data ) session.add(status) session.flush() status_objects[status_data["status_id"]] = status # Create transitions transitions = [ { "from": "draft", "to": "submitted", "name": "Einreichen", "trigger_type": TransitionTriggerType.APPLICANT_ACTION }, { "from": "submitted", "to": "under_review", "name": "Prüfung starten", "trigger_type": TransitionTriggerType.USER_APPROVAL, "config": {"role": "admin"} }, { "from": "under_review", "to": "approved", "name": "Genehmigen", "trigger_type": TransitionTriggerType.USER_APPROVAL, "config": {"role": "admin"} }, { "from": "under_review", "to": "rejected", "name": "Ablehnen", "trigger_type": TransitionTriggerType.USER_APPROVAL, "config": {"role": "admin"} } ] for trans in transitions: transition = StatusTransition( from_status_id=status_objects[trans["from"]].id, to_status_id=status_objects[trans["to"]].id, name=trans["name"], trigger_type=trans["trigger_type"], trigger_config=trans.get("config", {}), is_active=True ) session.add(transition) def create_admin_user(): """Create a default admin user if none exists""" engine = get_engine() with Session(engine) as session: # Check if any admin user exists admin_role = session.query(Role).filter_by(name="admin").first() if not admin_role: logger.warning("Admin role not found, skipping admin user creation") return admin_users = session.query(User).join(User.roles).filter(Role.name == "admin").all() if admin_users: logger.info("Admin user(s) already exist") return logger.info("Creating default admin user...") # Create admin user from services.auth_service import get_password_hash admin = User( email="admin@example.com", given_name="System", family_name="Administrator", display_name="System Admin", auth_provider="local", verification_status="fully_verified", email_verified=True ) # Set password (you should change this!) # For production, this should be set via environment variable default_password = os.getenv("ADMIN_PASSWORD", "changeme123") # Note: You'll need to implement password storage separately # This is just a placeholder session.add(admin) admin.roles.append(admin_role) session.commit() logger.info(f"Default admin user created: admin@example.com") logger.warning(f"IMPORTANT: Change the default admin password immediately!") def main(): """Main startup function""" logger.info("Starting application initialization...") try: # Initialize database schema logger.info("Initializing database schema...") init_database() logger.info("Database schema initialized") # Create default application types create_default_application_types() # Create admin user create_admin_user() logger.info("Application initialization complete!") logger.info("You can now start the application server.") except Exception as e: logger.error(f"Initialization failed: {e}", exc_info=True) sys.exit(1) if __name__ == "__main__": main()