import logging import sys from pathlib import Path # Add parent directory to path so we can import 'app' sys.path.insert(0, str(Path(__file__).parent.parent)) from sqlalchemy import text, create_engine from sqlalchemy.orm import Session, configure_mappers from app.db.database import SessionLocal from app.core.settings import DATABASE_URL engine_direct = create_engine(DATABASE_URL, echo=False) SessionLocal.configure(bind=engine_direct) from app.modules.tenant.models.tenant_model import Tenant from app.modules.auth.models.user_model import User from app.modules.auth.models.access_model import Access from app.modules.auth.models.role_model import Role from app.modules.auth.models.role_access_model import RoleAccess from app.modules.documents.models.document_model import Project, ProjectVersion from app.modules.storage.models.storage_model import UserFile, UserStorageUsage from app.modules.drive.models.drive_model import ( DriveFolder, DriveFile, DriveACL, DriveActivity, DriveComment, DriveFileVersion, DriveStar, DriveShare, ) from app.modules.chat.models.chat_model import ChatbotDocument from app.modules.chat.models.chat_session_model import ChatSession from app.modules.chat.models.chat_message_model import ChatMessage from app.modules.chat.models.chat_usage_model import ChatTokenQuota, ChatTokenUsage from app.infrastructure.vector.vector_client import VectorStoreManager from app.modules.notifications.models.notification_model import Notification from app.modules.collab.models.collab_model import CollaborationMessage from app.modules.signing.models.signing_request import SigningRequest from app.modules.configuration.models.system_configuration_model import ( SystemConfiguration, ) configure_mappers() logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) PREDEFINED_ACCESSES = [ # Superadmin ("superadmin.main.view", "Superadmin", "Access to superadmin panel", None), ("superadmin.tenant.read", "Superadmin", "View all tenants", None), ("superadmin.tenant.create", "Superadmin", "Create tenants", None), ("superadmin.tenant.update", "Superadmin", "Update tenants", None), ("superadmin.tenant.delete", "Superadmin", "Delete tenants", None), ("superadmin.user.read", "Superadmin", "View all users", None), ("superadmin.user.create", "Superadmin", "Create users", None), ("superadmin.user.update", "Superadmin", "Update users", None), ("superadmin.user.delete", "Superadmin", "Delete users", None), ("superadmin.role.read", "Superadmin", "View all roles", None), ("superadmin.role.create", "Superadmin", "Create global roles", None), ("superadmin.role.update", "Superadmin", "Update global roles", None), ("superadmin.role.delete", "Superadmin", "Delete global roles", None), ("superadmin.access.read", "Superadmin", "View all accesses", None), ("superadmin.config.read", "Superadmin", "Read system configurations", None), ("superadmin.config.create", "Superadmin", "Create system configurations", None), ("superadmin.config.update", "Superadmin", "Update system configurations", None), ("superadmin.config.delete", "Superadmin", "Delete system configurations", None), # Administration ("admin.user.read", "Administration", "Read users in tenant", None), ("admin.user.create", "Administration", "Create users in tenant", None), ("admin.user.update", "Administration", "Update users in tenant", None), ("admin.user.delete", "Administration", "Delete users from tenant", None), ("admin.user.invite", "Administration", "Invite users", None), ("admin.role.read", "Administration", "Read tenant roles", None), ("admin.role.create", "Administration", "Create tenant roles", None), ("admin.role.update", "Administration", "Update tenant roles", None), ("admin.role.assign", "Administration", "Assign roles to users", None), ("admin.access.read", "Administration", "View tenant accesses", None), ("admin.smtp.read", "Administration", "Read tenant SMTP settings", None), ("admin.smtp.update", "Administration", "Update tenant SMTP settings", None), ("admin.storage.read", "Administration", "Read tenant storage settings", None), ("admin.storage.update", "Administration", "Update tenant storage settings", None), ("admin.org.read", "Administration", "Read organization structure", None), ("admin.org.create", "Administration", "Create organization structure", None), ("admin.org.update", "Administration", "Update organization structure", None), ("admin.org.delete", "Administration", "Delete organization structure", None), ("admin.org.assign", "Administration", "Assign organization roles", None), ("admin.group.read", "Administration", "Read access groups", None), ("admin.group.create", "Administration", "Create access groups", None), ("admin.group.update", "Administration", "Update access groups", None), ("admin.group.delete", "Administration", "Delete access groups", None), # Document Conversion ( "document.conversion.pdf.read", "Document Conversion", "Read PDF conversion resources", "document.conversion", ), ( "document.conversion.pdf.write", "Document Conversion", "Create and run PDF conversions", "document.conversion", ), ( "document.conversion.pdf.to.word", "Document Conversion", "Use PDF to Word conversion", "document.conversion", ), ( "document.conversion.pdf.to.html", "Document Conversion", "Use PDF to HTML conversion", "document.conversion", ), ( "document.conversion.pdf.to.xml", "Document Conversion", "Use PDF to XML conversion", "document.conversion", ), ( "document.conversion.word.to.pdf", "Document Conversion", "Use Word to PDF conversion", "document.conversion", ), ( "document.conversion.image.to.word", "Document Conversion", "Use image to Word conversion", "document.conversion", ), # AI Chatbot ("chatbot", "AI Chatbot", "Full access to AI chatbot module", None), ("chatbot.read", "AI Chatbot", "Read chatbot documents", "chatbot"), ( "chatbot.write", "AI Chatbot", "Upload/manage chatbot documents and chat", "chatbot", ), ("document.extract", "AI Chatbot", "Extract data from documents using AI", "chatbot"), # Document ("document.read", "Documents", "Read documents", None), ("document.edit", "Documents", "Edit documents", None), ("document.comment", "Documents", "Comment on documents", None), ("document.publish", "Documents", "Publish document versions", None), ("document.restore", "Documents", "Restore document versions", None), ("document.presentation.create", "Documents", "Create presentation documents", None), ("document.text.create", "Documents", "Create text documents", None), ("document.word.create", "Documents", "Create word documents", None), ("document.sheet.create", "Documents", "Create spreadsheet documents", None), # Drive Folder ("drive.folder.create", "Drive", "Create folders", None), ("drive.folder.read", "Drive", "Read folders", None), ("drive.folder.update", "Drive", "Update folders", None), ("drive.folder.delete", "Drive", "Delete folders", None), # Drive File ("drive.file.upload", "Drive", "Upload files", None), ("drive.file.download", "Drive", "Download files", None), ("drive.file.delete", "Drive", "Delete files", None), ("drive.file.share", "Drive", "Share files", None), ("drive.file.comment", "Drive", "Comment on files", None), ("drive.file.version.read", "Drive", "View file versions", None), ("drive.file.link.create", "Drive", "Create file links", None), # Signing ("document.sign", "Signing", "Sign documents", None), ("document.sign.request", "Signing", "Request signatures from others", None), ("admin.logs.read", "Administration", "Read tenant activity logs", None), ] def seed_accesses(db: Session) -> int: logger.info("Seeding accesses...") for sql in [ "ALTER TABLE accesses DROP CONSTRAINT IF EXISTS uq_accesses_name", "ALTER TABLE accesses DROP CONSTRAINT IF EXISTS accesses_name_key", "DROP INDEX IF EXISTS accesses_name_key", ]: try: db.execute(text(sql)) except Exception: pass db.commit() created_count = 0 updated_count = 0 seen_names = set() access_by_code = {} for access_code, category, name, parent_code in PREDEFINED_ACCESSES: unique_name = name if unique_name in seen_names: unique_name = f"{category}: {name}" seen_names.add(unique_name) access = db.query(Access).filter(Access.access_code == access_code).first() if access: access.category = category access.name = unique_name updated_count += 1 else: access = Access( access_code=access_code, category=category, name=unique_name, parent_id=None, ) db.add(access) created_count += 1 access_by_code[access_code] = access db.flush() for access_code, _, _, parent_code in PREDEFINED_ACCESSES: access = access_by_code.get(access_code) if not access: continue if parent_code: parent = access_by_code.get(parent_code) access.parent_id = parent.id if parent else None else: access.parent_id = None db.commit() logger.info("Accesses upserted: %s created, %s updated", created_count, updated_count) return created_count + updated_count def seed_roles_with_permissions(db: Session) -> None: logger.info("Creating roles...") superadmin_role = ( db.query(Role).filter(Role.name == "superadmin", Role.tenant_id == None).first() ) if not superadmin_role: superadmin_role = Role(name="superadmin", tenant_id=None) db.add(superadmin_role) db.flush() db.query(RoleAccess).filter(RoleAccess.role_id == superadmin_role.id).delete() db.flush() superadmin_accesses = ( db.query(Access) .filter( Access.access_code.like("superadmin.%") | Access.access_code.like("admin.%") ) .all() ) for access in superadmin_accesses: db.add(RoleAccess(role_id=superadmin_role.id, access_id=access.id)) db.commit() logger.info("Superadmin role synced with %s accesses", len(superadmin_accesses)) def create_and_link_superadmin(db: Session) -> None: logger.info("Setting up superadmin user...") from app.core.security import get_password_hash superadmin_role = ( db.query(Role).filter(Role.name == "superadmin", Role.tenant_id == None).first() ) superadmin = db.query(User).filter(User.email == "admin@maskan.com").first() if not superadmin: superadmin = User( name="System Superadmin", email="admin@maskan.com", tenant_id=None, password_hash=get_password_hash("Admin@123"), role_id=superadmin_role.id if superadmin_role else None, ) db.add(superadmin) db.commit() logger.info("Superadmin user created and linked to role") return if superadmin_role and superadmin.role_id != superadmin_role.id: superadmin.role_id = superadmin_role.id db.commit() logger.info("Existing superadmin user linked to superadmin role") else: logger.info("Superadmin user already exists and is linked correctly") def seed_data(): db = SessionLocal() try: logger.info("=" * 60) logger.info("Starting seed process...") logger.info("=" * 60) seed_accesses(db) seed_roles_with_permissions(db) create_and_link_superadmin(db) logger.info("=" * 60) logger.info("Seeding completed successfully") logger.info("=" * 60) except Exception as e: logger.error("Seeding failed: %s", e) db.rollback() finally: db.close() if __name__ == "__main__": seed_data()