diff --git a/backend/capellacollab/core/database/__init__.py b/backend/capellacollab/core/database/__init__.py index 12fdc4be6d..581e427b21 100644 --- a/backend/capellacollab/core/database/__init__.py +++ b/backend/capellacollab/core/database/__init__.py @@ -17,7 +17,7 @@ SessionLocal = orm.sessionmaker(autocommit=False, autoflush=False, bind=engine) -class Base(orm.DeclarativeBase): +class Base(orm.MappedAsDataclass, orm.DeclarativeBase): type_annotation_map = { dict[str, str]: postgresql.JSONB, dict[str, t.Any]: postgresql.JSONB, diff --git a/backend/capellacollab/core/database/migration.py b/backend/capellacollab/core/database/migration.py index 66ddbc1491..cf78b3f745 100644 --- a/backend/capellacollab/core/database/migration.py +++ b/backend/capellacollab/core/database/migration.py @@ -84,7 +84,7 @@ def migrate_db(engine, database_url: str): create_coffee_machine_model(session) -def initialize_admin_user(db): +def initialize_admin_user(db: orm.Session): LOGGER.info("Initialized adminuser %s", config["initial"]["admin"]) admin_user = users_crud.create_user( db=db, @@ -94,7 +94,7 @@ def initialize_admin_user(db): events_crud.create_user_creation_event(db, admin_user) -def initialize_default_project(db): +def initialize_default_project(db: orm.Session): LOGGER.info("Initialized project 'default'") projects_crud.create_project( db=db, @@ -104,7 +104,7 @@ def initialize_default_project(db): ) -def initialize_coffee_machine_project(db): +def initialize_coffee_machine_project(db: orm.Session): LOGGER.info("Initialize project 'Coffee Machine'") projects_crud.create_project( db=db, @@ -114,7 +114,7 @@ def initialize_coffee_machine_project(db): ) -def create_tools(db): +def create_tools(db: orm.Session): LOGGER.info("Initialized tools") registry = config["docker"]["registry"] if os.getenv("DEVELOPMENT_MODE", "").lower() in ("1", "true", "t"): @@ -131,12 +131,12 @@ def create_tools(db): ) tools_crud.create_tool(db, papyrus) - tools_crud.create_version(db, papyrus.id, "6.1") - tools_crud.create_version(db, papyrus.id, "6.0") + tools_crud.create_version(db, papyrus, "6.1") + tools_crud.create_version(db, papyrus, "6.0") - tools_crud.create_nature(db, papyrus.id, "UML 2.5") - tools_crud.create_nature(db, papyrus.id, "SysML 1.4") - tools_crud.create_nature(db, papyrus.id, "SysML 1.1") + tools_crud.create_nature(db, papyrus, "UML 2.5") + tools_crud.create_nature(db, papyrus, "SysML 1.4") + tools_crud.create_nature(db, papyrus, "SysML 1.1") else: # Use public Github images per default @@ -154,21 +154,22 @@ def create_tools(db): docker_image_template=f"{registry}/jupyter-notebook:$version", ) tools_crud.create_tool(db, jupyter) + assert jupyter.integrations integrations_crud.update_integrations( db, jupyter.integrations, integrations_models.PatchToolIntegrations(jupyter=True), ) - default_version = tools_crud.create_version(db, capella.id, "6.0.0", True) - tools_crud.create_version(db, capella.id, "5.2.0") - tools_crud.create_version(db, capella.id, "5.0.0") + default_version = tools_crud.create_version(db, capella, "6.0.0", True) + tools_crud.create_version(db, capella, "5.2.0") + tools_crud.create_version(db, capella, "5.0.0") - tools_crud.create_version(db, jupyter.id, "python-3.11") - tools_crud.create_nature(db, jupyter.id, "notebooks") + tools_crud.create_version(db, jupyter, "python-3.11") + tools_crud.create_nature(db, jupyter, "notebooks") - default_nature = tools_crud.create_nature(db, capella.id, "model") - tools_crud.create_nature(db, capella.id, "library") + default_nature = tools_crud.create_nature(db, capella, "model") + tools_crud.create_nature(db, capella, "library") for model in toolmodels_crud.get_models(db): toolmodels_crud.set_tool_for_model(db, model, capella) @@ -184,6 +185,7 @@ def create_t4c_instance_and_repositories(db): version = tools_crud.get_version_by_tool_id_version_name( db, tool.id, "5.2.0" ) + assert version default_instance = settings_t4c_models.DatabaseT4CInstance( name="default", license="placeholder", diff --git a/backend/capellacollab/events/crud.py b/backend/capellacollab/events/crud.py index b63df31c21..12954b949f 100644 --- a/backend/capellacollab/events/crud.py +++ b/backend/capellacollab/events/crud.py @@ -26,14 +26,16 @@ def create_event( raise ValueError( f"Event type must of one of the following: {allowed_types}" ) + event = models.DatabaseUserHistoryEvent( - user_id=user.id, + user=user, event_type=event_type, execution_time=datetime.datetime.now(datetime.UTC), - executor_id=executor.id if executor else None, - project_id=project.id if project else None, + executor=executor, + project=project, reason=reason, ) + db.add(event) db.commit() diff --git a/backend/capellacollab/events/models.py b/backend/capellacollab/events/models.py index b74186bfe9..23b91da1a6 100644 --- a/backend/capellacollab/events/models.py +++ b/backend/capellacollab/events/models.py @@ -3,7 +3,6 @@ import datetime import enum -import typing as t import pydantic import sqlalchemy as sa @@ -14,10 +13,6 @@ from capellacollab.projects import models as projects_models from capellacollab.users import models as users_models -if t.TYPE_CHECKING: - from capellacollab.projects.models import DatabaseProject - from capellacollab.users.models import DatabaseUser - class EventType(enum.Enum): CREATED_USER = "CreatedUser" @@ -55,27 +50,37 @@ class HistoryEvent(BaseHistoryEvent): class DatabaseUserHistoryEvent(database.Base): __tablename__ = "user_history_events" - id: orm.Mapped[int] = orm.mapped_column(primary_key=True, index=True) + id: orm.Mapped[int] = orm.mapped_column( + init=False, primary_key=True, index=True + ) - user_id: orm.Mapped[int] = orm.mapped_column(sa.ForeignKey("users.id")) - user: orm.Mapped["DatabaseUser"] = orm.relationship( + user_id: orm.Mapped[int] = orm.mapped_column( + sa.ForeignKey("users.id"), + init=False, + ) + user: orm.Mapped[users_models.DatabaseUser] = orm.relationship( back_populates="events", foreign_keys=[user_id] ) + event_type: orm.Mapped[EventType] + reason: orm.Mapped[str | None] = orm.mapped_column(default=None) + executor_id: orm.Mapped[int | None] = orm.mapped_column( - sa.ForeignKey("users.id") + sa.ForeignKey("users.id"), + init=False, ) - executor: orm.Mapped["DatabaseUser"] = orm.relationship( - foreign_keys=[executor_id] + executor: orm.Mapped[users_models.DatabaseUser | None] = orm.relationship( + default=None, foreign_keys=[executor_id] ) project_id: orm.Mapped[int | None] = orm.mapped_column( - sa.ForeignKey("projects.id") - ) - project: orm.Mapped["DatabaseProject"] = orm.relationship( - foreign_keys=[project_id] + sa.ForeignKey("projects.id"), + init=False, ) + project: orm.Mapped[ + projects_models.DatabaseProject | None + ] = orm.relationship(default=None, foreign_keys=[project_id]) - execution_time: orm.Mapped[datetime.datetime] - event_type: orm.Mapped[EventType] - reason: orm.Mapped[str | None] + execution_time: orm.Mapped[datetime.datetime] = orm.mapped_column( + default=datetime.datetime.now(datetime.UTC) + ) diff --git a/backend/capellacollab/health/routes.py b/backend/capellacollab/health/routes.py index 84bbc1c1da..0708522540 100644 --- a/backend/capellacollab/health/routes.py +++ b/backend/capellacollab/health/routes.py @@ -107,7 +107,7 @@ def project_status(db: orm.Session = fastapi.Depends(database.get_db)): def _create_tool_model_status_tasks( db: orm.Session, logger: logging.LoggerAdapter, - model: toolmodels_models.DatabaseCapellaModel, + model: toolmodels_models.DatabaseToolModel, ) -> models.ToolModelStatusTasks: return models.ToolModelStatusTasks( primary_git_repository_status=asyncio.create_task( diff --git a/backend/capellacollab/notices/models.py b/backend/capellacollab/notices/models.py index ef38002985..e454a21f6a 100644 --- a/backend/capellacollab/notices/models.py +++ b/backend/capellacollab/notices/models.py @@ -34,7 +34,9 @@ class NoticeResponse(CreateNoticeRequest): class DatabaseNotice(database.Base): __tablename__ = "notices" - id: orm.Mapped[int] = orm.mapped_column(primary_key=True, index=True) + id: orm.Mapped[int] = orm.mapped_column( + init=False, primary_key=True, index=True + ) title: orm.Mapped[str] message: orm.Mapped[str] level: orm.Mapped[NoticeLevel] diff --git a/backend/capellacollab/projects/models.py b/backend/capellacollab/projects/models.py index be808655c6..26ab9825e0 100644 --- a/backend/capellacollab/projects/models.py +++ b/backend/capellacollab/projects/models.py @@ -14,7 +14,7 @@ from capellacollab.projects.users import models as project_users_models if t.TYPE_CHECKING: - from capellacollab.projects.toolmodels.models import DatabaseCapellaModel + from capellacollab.projects.toolmodels.models import DatabaseToolModel from capellacollab.projects.users.models import ProjectUserAssociation @@ -105,20 +105,25 @@ class DatabaseProject(database.Base): __tablename__ = "projects" id: orm.Mapped[int] = orm.mapped_column( - unique=True, primary_key=True, index=True + init=False, unique=True, primary_key=True, index=True ) name: orm.Mapped[str] = orm.mapped_column(unique=True, index=True) slug: orm.Mapped[str] = orm.mapped_column(unique=True, index=True) - description: orm.Mapped[str | None] - visibility: orm.Mapped[Visibility] - type: orm.Mapped[ProjectType] + + description: orm.Mapped[str | None] = orm.mapped_column(default=None) + visibility: orm.Mapped[Visibility] = orm.mapped_column( + default=Visibility.PRIVATE + ) + type: orm.Mapped[ProjectType] = orm.mapped_column( + default=ProjectType.GENERAL + ) users: orm.Mapped[list[ProjectUserAssociation]] = orm.relationship( - back_populates="project" + default_factory=list, back_populates="project" ) - models: orm.Mapped[list[DatabaseCapellaModel]] = orm.relationship( - back_populates="project" + models: orm.Mapped[list[DatabaseToolModel]] = orm.relationship( + default_factory=list, back_populates="project" ) is_archived: orm.Mapped[bool] = orm.mapped_column(default=False) diff --git a/backend/capellacollab/projects/toolmodels/backups/crud.py b/backend/capellacollab/projects/toolmodels/backups/crud.py index df5673a24a..ff08ce3d2c 100644 --- a/backend/capellacollab/projects/toolmodels/backups/crud.py +++ b/backend/capellacollab/projects/toolmodels/backups/crud.py @@ -28,7 +28,7 @@ def get_pipeline_by_id( def get_pipelines_for_tool_model( - db: orm.Session, model: toolmodels_models.DatabaseCapellaModel + db: orm.Session, model: toolmodels_models.DatabaseToolModel ) -> abc.Sequence[models.DatabaseBackup]: return ( db.execute( @@ -42,7 +42,7 @@ def get_pipelines_for_tool_model( def get_first_pipeline_for_tool_model( - db: orm.Session, model: toolmodels_models.DatabaseCapellaModel + db: orm.Session, model: toolmodels_models.DatabaseToolModel ) -> models.DatabaseBackup | None: return ( db.execute( diff --git a/backend/capellacollab/projects/toolmodels/backups/injectables.py b/backend/capellacollab/projects/toolmodels/backups/injectables.py index bd0511d980..6fc9a60987 100644 --- a/backend/capellacollab/projects/toolmodels/backups/injectables.py +++ b/backend/capellacollab/projects/toolmodels/backups/injectables.py @@ -16,7 +16,7 @@ def get_existing_pipeline( pipeline_id: int, - model: toolmodels_models.DatabaseCapellaModel = fastapi.Depends( + model: toolmodels_models.DatabaseToolModel = fastapi.Depends( toolmodels_injectables.get_existing_capella_model ), db: orm.Session = fastapi.Depends(database.get_db), diff --git a/backend/capellacollab/projects/toolmodels/backups/models.py b/backend/capellacollab/projects/toolmodels/backups/models.py index 356010a270..4de74fbadb 100644 --- a/backend/capellacollab/projects/toolmodels/backups/models.py +++ b/backend/capellacollab/projects/toolmodels/backups/models.py @@ -16,7 +16,7 @@ ) if t.TYPE_CHECKING: - from capellacollab.projects.toolmodels.models import DatabaseCapellaModel + from capellacollab.projects.toolmodels.models import DatabaseToolModel from capellacollab.projects.toolmodels.modelsources.git.models import ( DatabaseGitModel, ) @@ -51,7 +51,7 @@ class Backup(pydantic.BaseModel): class DatabaseBackup(database.Base): __tablename__ = "backups" id: orm.Mapped[int] = orm.mapped_column( - primary_key=True, index=True, autoincrement=True + init=False, primary_key=True, index=True, autoincrement=True ) created_by: orm.Mapped[str] @@ -64,17 +64,19 @@ class DatabaseBackup(database.Base): run_nightly: orm.Mapped[bool] git_model_id: orm.Mapped[int] = orm.mapped_column( - sa.ForeignKey("git_models.id") + sa.ForeignKey("git_models.id"), init=False ) git_model: orm.Mapped["DatabaseGitModel"] = orm.relationship() t4c_model_id: orm.Mapped[int] = orm.mapped_column( - sa.ForeignKey("t4c_models.id") + sa.ForeignKey("t4c_models.id"), init=False ) t4c_model: orm.Mapped["DatabaseT4CModel"] = orm.relationship() - model_id: orm.Mapped[int] = orm.mapped_column(sa.ForeignKey("models.id")) - model: orm.Mapped["DatabaseCapellaModel"] = orm.relationship() + model_id: orm.Mapped[int] = orm.mapped_column( + sa.ForeignKey("models.id"), init=False + ) + model: orm.Mapped["DatabaseToolModel"] = orm.relationship() runs: orm.Mapped[ list["runs_models.DatabasePipelineRun"] @@ -82,4 +84,5 @@ class DatabaseBackup(database.Base): "DatabasePipelineRun", back_populates="pipeline", cascade="all, delete-orphan", + default_factory=list, ) diff --git a/backend/capellacollab/projects/toolmodels/backups/routes.py b/backend/capellacollab/projects/toolmodels/backups/routes.py index 5a2e2daf33..08aff2218e 100644 --- a/backend/capellacollab/projects/toolmodels/backups/routes.py +++ b/backend/capellacollab/projects/toolmodels/backups/routes.py @@ -44,7 +44,7 @@ @router.get("", response_model=list[models.Backup]) def get_pipelines( - model: toolmodels_models.DatabaseCapellaModel = fastapi.Depends( + model: toolmodels_models.DatabaseToolModel = fastapi.Depends( toolmodels_injectables.get_existing_capella_model ), db: orm.Session = fastapi.Depends(database.get_db), @@ -67,7 +67,7 @@ def get_pipeline( @router.post("", response_model=models.Backup) def create_backup( body: models.CreateBackup, - capella_model: toolmodels_models.DatabaseCapellaModel = fastapi.Depends( + capella_model: toolmodels_models.DatabaseToolModel = fastapi.Depends( toolmodels_injectables.get_existing_capella_model ), db: orm.Session = fastapi.Depends(database.get_db), diff --git a/backend/capellacollab/projects/toolmodels/backups/runs/models.py b/backend/capellacollab/projects/toolmodels/backups/runs/models.py index 21204aa43e..0c9aad0916 100644 --- a/backend/capellacollab/projects/toolmodels/backups/runs/models.py +++ b/backend/capellacollab/projects/toolmodels/backups/runs/models.py @@ -28,32 +28,37 @@ class PipelineRunStatus(enum.Enum): class DatabasePipelineRun(Base): __tablename__ = "pipeline_run" id: orm.Mapped[int] = orm.mapped_column( - primary_key=True, index=True, autoincrement=True + init=False, primary_key=True, index=True, autoincrement=True ) - reference_id: orm.Mapped[str | None] status: orm.Mapped[PipelineRunStatus] pipeline_id: orm.Mapped[int] = orm.mapped_column( - sa.ForeignKey("backups.id") + sa.ForeignKey("backups.id"), init=False ) pipeline: orm.Mapped[pipeline_models.DatabaseBackup] = orm.relationship( pipeline_models.DatabaseBackup ) triggerer_id: orm.Mapped[str] = orm.mapped_column( - sa.ForeignKey("users.id") + sa.ForeignKey("users.id"), init=False ) triggerer: orm.Mapped[users_models.DatabaseUser] = orm.relationship( users_models.DatabaseUser ) trigger_time: orm.Mapped[datetime.datetime] - end_time: orm.Mapped[datetime.datetime | None] - logs_last_fetched_timestamp: orm.Mapped[datetime.datetime | None] environment: orm.Mapped[dict[str, str]] + reference_id: orm.Mapped[str | None] = orm.mapped_column(default=None) + end_time: orm.Mapped[datetime.datetime | None] = orm.mapped_column( + default=None + ) + logs_last_fetched_timestamp: orm.Mapped[ + datetime.datetime | None + ] = orm.mapped_column(default=None) + class PipelineRun(pydantic.BaseModel): model_config = pydantic.ConfigDict(from_attributes=True) diff --git a/backend/capellacollab/projects/toolmodels/backups/validation.py b/backend/capellacollab/projects/toolmodels/backups/validation.py index 63838302e6..d537feabd0 100644 --- a/backend/capellacollab/projects/toolmodels/backups/validation.py +++ b/backend/capellacollab/projects/toolmodels/backups/validation.py @@ -10,7 +10,7 @@ def check_last_pipeline_run_status( - db: orm.Session, model: toolmodel_models.DatabaseCapellaModel + db: orm.Session, model: toolmodel_models.DatabaseToolModel ) -> runs_models.PipelineRunStatus | None: if pipeline := crud.get_first_pipeline_for_tool_model(db, model): # Only consider first pipeline for monitoring, usually there is only one pipeline. diff --git a/backend/capellacollab/projects/toolmodels/crud.py b/backend/capellacollab/projects/toolmodels/crud.py index 4c64e84896..8128b645bb 100644 --- a/backend/capellacollab/projects/toolmodels/crud.py +++ b/backend/capellacollab/projects/toolmodels/crud.py @@ -14,17 +14,17 @@ from .restrictions import models as restrictions_models -def get_models(db: orm.Session) -> abc.Sequence[models.DatabaseCapellaModel]: - return db.execute(sa.select(models.DatabaseCapellaModel)).scalars().all() +def get_models(db: orm.Session) -> abc.Sequence[models.DatabaseToolModel]: + return db.execute(sa.select(models.DatabaseToolModel)).scalars().all() def get_models_by_version( db: orm.Session, version_id: int -) -> abc.Sequence[models.DatabaseCapellaModel]: +) -> abc.Sequence[models.DatabaseToolModel]: return ( db.execute( - sa.select(models.DatabaseCapellaModel).where( - models.DatabaseCapellaModel.version_id == version_id + sa.select(models.DatabaseToolModel).where( + models.DatabaseToolModel.version_id == version_id ) ) .scalars() @@ -34,11 +34,11 @@ def get_models_by_version( def get_models_by_nature( db: orm.Session, nature_id: int -) -> abc.Sequence[models.DatabaseCapellaModel]: +) -> abc.Sequence[models.DatabaseToolModel]: return ( db.execute( - sa.select(models.DatabaseCapellaModel).where( - models.DatabaseCapellaModel.nature_id == nature_id + sa.select(models.DatabaseToolModel).where( + models.DatabaseToolModel.nature_id == nature_id ) ) .scalars() @@ -48,11 +48,11 @@ def get_models_by_nature( def get_models_by_tool( db: orm.Session, tool_id: int -) -> abc.Sequence[models.DatabaseCapellaModel]: +) -> abc.Sequence[models.DatabaseToolModel]: return ( db.execute( - sa.select(models.DatabaseCapellaModel).where( - models.DatabaseCapellaModel.tool_id == tool_id + sa.select(models.DatabaseToolModel).where( + models.DatabaseToolModel.tool_id == tool_id ) ) .scalars() @@ -62,16 +62,16 @@ def get_models_by_tool( def get_model_by_slugs( db: orm.Session, project_slug: str, model_slug: str -) -> models.DatabaseCapellaModel | None: +) -> models.DatabaseToolModel | None: return db.execute( - sa.select(models.DatabaseCapellaModel) - .options(orm.joinedload(models.DatabaseCapellaModel.project)) + sa.select(models.DatabaseToolModel) + .options(orm.joinedload(models.DatabaseToolModel.project)) .where( - models.DatabaseCapellaModel.project.has( + models.DatabaseToolModel.project.has( projects_model.DatabaseProject.slug == project_slug ) ) - .where(models.DatabaseCapellaModel.slug == model_slug) + .where(models.DatabaseToolModel.slug == model_slug) ).scalar_one_or_none() @@ -84,10 +84,8 @@ def create_model( nature: tools_models.DatabaseNature | None = None, configuration: dict[str, str] | None = None, display_order: int | None = None, -) -> models.DatabaseCapellaModel: - restrictions = restrictions_models.DatabaseToolModelRestrictions() - - model = models.DatabaseCapellaModel( +) -> models.DatabaseToolModel: + model = models.DatabaseToolModel( name=post_model.name, slug=slugify.slugify(post_model.name), description=post_model.description if post_model.description else "", @@ -95,10 +93,13 @@ def create_model( tool=tool, version=version, nature=nature, - restrictions=restrictions, configuration=configuration, display_order=display_order, ) + + restrictions = restrictions_models.DatabaseToolModelRestrictions( + model=model + ) db.add(restrictions) db.add(model) db.commit() @@ -107,9 +108,9 @@ def create_model( def set_tool_for_model( db: orm.Session, - model: models.DatabaseCapellaModel, + model: models.DatabaseToolModel, tool: tools_models.DatabaseTool, -) -> models.DatabaseCapellaModel: +) -> models.DatabaseToolModel: model.tool = tool db.commit() return model @@ -117,10 +118,10 @@ def set_tool_for_model( def set_tool_details_for_model( db: orm.Session, - model: models.DatabaseCapellaModel, + model: models.DatabaseToolModel, version: tools_models.DatabaseVersion, nature: tools_models.DatabaseNature, -) -> models.DatabaseCapellaModel: +) -> models.DatabaseToolModel: model.version = version model.nature = nature db.commit() @@ -129,14 +130,14 @@ def set_tool_details_for_model( def update_model( db: orm.Session, - model: models.DatabaseCapellaModel, + model: models.DatabaseToolModel, description: str | None, name: str | None, - version: tools_models.DatabaseVersion, - nature: tools_models.DatabaseNature, + version: tools_models.DatabaseVersion | None, + nature: tools_models.DatabaseNature | None, project: projects_model.DatabaseProject, display_order: int | None, -) -> models.DatabaseCapellaModel: +) -> models.DatabaseToolModel: model.version = version model.nature = nature model.project = project @@ -151,6 +152,6 @@ def update_model( return model -def delete_model(db: orm.Session, model: models.DatabaseCapellaModel): +def delete_model(db: orm.Session, model: models.DatabaseToolModel): db.delete(model) db.commit() diff --git a/backend/capellacollab/projects/toolmodels/diagrams/validation.py b/backend/capellacollab/projects/toolmodels/diagrams/validation.py index 576fe75d57..e3bb6ca5a4 100644 --- a/backend/capellacollab/projects/toolmodels/diagrams/validation.py +++ b/backend/capellacollab/projects/toolmodels/diagrams/validation.py @@ -12,7 +12,7 @@ async def check_diagram_cache_health( db: orm.Session, - model: toolmodels_models.DatabaseCapellaModel, + model: toolmodels_models.DatabaseToolModel, logger: logging.LoggerAdapter, ) -> git_models.ModelArtifactStatus: return await git_validation.check_pipeline_health( diff --git a/backend/capellacollab/projects/toolmodels/injectables.py b/backend/capellacollab/projects/toolmodels/injectables.py index bcfb49481c..2ea3b1db2c 100644 --- a/backend/capellacollab/projects/toolmodels/injectables.py +++ b/backend/capellacollab/projects/toolmodels/injectables.py @@ -18,7 +18,7 @@ def get_existing_capella_model( projects_injectables.get_existing_project ), db: orm.Session = fastapi.Depends(database.get_db), -) -> models.DatabaseCapellaModel: +) -> models.DatabaseToolModel: model = crud.get_model_by_slugs(db, project.slug, model_slug) if not model: raise fastapi.HTTPException( diff --git a/backend/capellacollab/projects/toolmodels/modelbadge/validation.py b/backend/capellacollab/projects/toolmodels/modelbadge/validation.py index 776a2bdc8d..1ab4693666 100644 --- a/backend/capellacollab/projects/toolmodels/modelbadge/validation.py +++ b/backend/capellacollab/projects/toolmodels/modelbadge/validation.py @@ -12,7 +12,7 @@ async def check_model_badge_health( db: orm.Session, - model: toolmodels_models.DatabaseCapellaModel, + model: toolmodels_models.DatabaseToolModel, logger: logging.LoggerAdapter, ) -> git_models.ModelArtifactStatus: return await git_validation.check_pipeline_health( diff --git a/backend/capellacollab/projects/toolmodels/models.py b/backend/capellacollab/projects/toolmodels/models.py index 0ab55fd171..247734839a 100644 --- a/backend/capellacollab/projects/toolmodels/models.py +++ b/backend/capellacollab/projects/toolmodels/models.py @@ -62,12 +62,12 @@ class ToolDetails(pydantic.BaseModel): nature_id: int -class DatabaseCapellaModel(database.Base): +class DatabaseToolModel(database.Base): __tablename__ = "models" __table_args__ = (sa.UniqueConstraint("project_id", "slug"),) id: orm.Mapped[int] = orm.mapped_column( - primary_key=True, index=True, unique=True + init=False, primary_key=True, index=True, unique=True ) name: orm.Mapped[str] = orm.mapped_column(index=True) @@ -78,36 +78,47 @@ class DatabaseCapellaModel(database.Base): configuration: orm.Mapped[dict[str, str] | None] project_id: orm.Mapped[int] = orm.mapped_column( - sa.ForeignKey("projects.id") + sa.ForeignKey("projects.id"), init=False ) project: orm.Mapped[DatabaseProject] = orm.relationship( back_populates="models" ) - tool_id: orm.Mapped[int] = orm.mapped_column(sa.ForeignKey("tools.id")) + tool_id: orm.Mapped[int] = orm.mapped_column( + sa.ForeignKey("tools.id"), init=False + ) tool: orm.Mapped[DatabaseTool] = orm.relationship() version_id: orm.Mapped[int | None] = orm.mapped_column( - sa.ForeignKey("versions.id") + sa.ForeignKey("versions.id"), init=False + ) + version: orm.Mapped[DatabaseVersion | None] = orm.relationship( + default=None ) - version: orm.Mapped[DatabaseVersion] = orm.relationship() nature_id: orm.Mapped[int | None] = orm.mapped_column( - sa.ForeignKey("types.id") + sa.ForeignKey("types.id"), init=False ) - nature: orm.Mapped[DatabaseNature] = orm.relationship() + nature: orm.Mapped[DatabaseNature | None] = orm.relationship(default=None) - editing_mode: orm.Mapped[EditingMode | None] + editing_mode: orm.Mapped[EditingMode | None] = orm.mapped_column( + default=None + ) t4c_models: orm.Mapped[list[DatabaseT4CModel]] = orm.relationship( - back_populates="model" + default_factory=list, back_populates="model" ) git_models: orm.Mapped[list[DatabaseGitModel]] = orm.relationship( - back_populates="model" + default_factory=list, back_populates="model" ) - restrictions: orm.Mapped[DatabaseToolModelRestrictions] = orm.relationship( - back_populates="model", uselist=False, cascade="delete" + restrictions: orm.Mapped[ + DatabaseToolModelRestrictions | None + ] = orm.relationship( + back_populates="model", + uselist=False, + cascade="delete", + default=None, ) diff --git a/backend/capellacollab/projects/toolmodels/modelsources/git/crud.py b/backend/capellacollab/projects/toolmodels/modelsources/git/crud.py index ca5bae0da5..3696413876 100644 --- a/backend/capellacollab/projects/toolmodels/modelsources/git/crud.py +++ b/backend/capellacollab/projects/toolmodels/modelsources/git/crud.py @@ -30,13 +30,13 @@ def get_primary_git_model_of_capellamodel( def add_git_model_to_capellamodel( db: orm.Session, - capella_model: toolsmodels_models.DatabaseCapellaModel, + capella_model: toolsmodels_models.DatabaseToolModel, post_git_model: models.PostGitModel, ) -> models.DatabaseGitModel: primary = not get_primary_git_model_of_capellamodel(db, capella_model.id) git_model = models.DatabaseGitModel.from_post_git_model( - capella_model.id, primary, post_git_model + capella_model, primary, post_git_model ) db.add(git_model) diff --git a/backend/capellacollab/projects/toolmodels/modelsources/git/injectables.py b/backend/capellacollab/projects/toolmodels/modelsources/git/injectables.py index cda2be3d7f..aa2608be8d 100644 --- a/backend/capellacollab/projects/toolmodels/modelsources/git/injectables.py +++ b/backend/capellacollab/projects/toolmodels/modelsources/git/injectables.py @@ -20,7 +20,7 @@ def get_existing_git_model( git_model_id: int, - capella_model: toolmodels_models.DatabaseCapellaModel = fastapi.Depends( + capella_model: toolmodels_models.DatabaseToolModel = fastapi.Depends( toolmodels_injectables.get_existing_capella_model ), db: orm.Session = fastapi.Depends(database.get_db), @@ -39,7 +39,7 @@ def get_existing_git_model( def get_existing_primary_git_model( - capella_model: toolmodels_models.DatabaseCapellaModel = fastapi.Depends( + capella_model: toolmodels_models.DatabaseToolModel = fastapi.Depends( toolmodels_injectables.get_existing_capella_model ), db: orm.Session = fastapi.Depends(database.get_db), diff --git a/backend/capellacollab/projects/toolmodels/modelsources/git/models.py b/backend/capellacollab/projects/toolmodels/modelsources/git/models.py index c8bc69488c..f72eb71656 100644 --- a/backend/capellacollab/projects/toolmodels/modelsources/git/models.py +++ b/backend/capellacollab/projects/toolmodels/modelsources/git/models.py @@ -12,7 +12,7 @@ from capellacollab.core import database if t.TYPE_CHECKING: - from capellacollab.projects.toolmodels.models import DatabaseCapellaModel + from capellacollab.projects.toolmodels.models import DatabaseToolModel class PostGitModel(pydantic.BaseModel): @@ -43,7 +43,7 @@ class DatabaseGitModel(database.Base): __tablename__ = "git_models" id: orm.Mapped[int] = orm.mapped_column( - primary_key=True, index=True, autoincrement=True + init=False, primary_key=True, index=True, autoincrement=True ) name: orm.Mapped[str] path: orm.Mapped[str] @@ -51,8 +51,10 @@ class DatabaseGitModel(database.Base): revision: orm.Mapped[str] primary: orm.Mapped[bool] - model_id: orm.Mapped[int] = orm.mapped_column(sa.ForeignKey("models.id")) - model: orm.Mapped["DatabaseCapellaModel"] = orm.relationship( + model_id: orm.Mapped[int] = orm.mapped_column( + sa.ForeignKey("models.id"), init=False + ) + model: orm.Mapped["DatabaseToolModel"] = orm.relationship( back_populates="git_models" ) @@ -61,12 +63,12 @@ class DatabaseGitModel(database.Base): @classmethod def from_post_git_model( - cls, model_id: int, primary: bool, new_model: PostGitModel + cls, model: "DatabaseToolModel", primary: bool, new_model: PostGitModel ): return cls( name="", primary=primary, - model_id=model_id, + model=model, **new_model.model_dump(), ) diff --git a/backend/capellacollab/projects/toolmodels/modelsources/git/routes.py b/backend/capellacollab/projects/toolmodels/modelsources/git/routes.py index c0f2965c6a..987ff17df0 100644 --- a/backend/capellacollab/projects/toolmodels/modelsources/git/routes.py +++ b/backend/capellacollab/projects/toolmodels/modelsources/git/routes.py @@ -66,7 +66,7 @@ def validate_path( @router.get("", response_model=list[models.GitModel]) def get_git_models( - capella_model: toolmodels_models.DatabaseCapellaModel = fastapi.Depends( + capella_model: toolmodels_models.DatabaseToolModel = fastapi.Depends( toolmodels_injectables.get_existing_capella_model ), ) -> list[models.DatabaseGitModel]: @@ -151,7 +151,7 @@ async def get_revisions_with_model_credentials( ) def create_git_model( post_git_model: models.PostGitModel, - capella_model: toolmodels_models.DatabaseCapellaModel = fastapi.Depends( + capella_model: toolmodels_models.DatabaseToolModel = fastapi.Depends( toolmodels_injectables.get_existing_capella_model ), db: orm.Session = fastapi.Depends(database.get_db), diff --git a/backend/capellacollab/projects/toolmodels/modelsources/git/validation.py b/backend/capellacollab/projects/toolmodels/modelsources/git/validation.py index fe98bd767c..8ce2b57bde 100644 --- a/backend/capellacollab/projects/toolmodels/modelsources/git/validation.py +++ b/backend/capellacollab/projects/toolmodels/modelsources/git/validation.py @@ -15,7 +15,7 @@ async def check_primary_git_repository( db: orm.Session, - model: toolmodels_models.DatabaseCapellaModel, + model: toolmodels_models.DatabaseToolModel, log: logging.LoggerAdapter, ) -> models.GitModelStatus: primary_repo = crud.get_primary_git_model_of_capellamodel(db, model.id) @@ -43,7 +43,7 @@ async def check_primary_git_repository( async def check_pipeline_health( db: orm.Session, - model: toolmodels_models.DatabaseCapellaModel, + model: toolmodels_models.DatabaseToolModel, job_name: str, logger: logging.LoggerAdapter, ) -> models.ModelArtifactStatus: diff --git a/backend/capellacollab/projects/toolmodels/modelsources/t4c/crud.py b/backend/capellacollab/projects/toolmodels/modelsources/t4c/crud.py index ee48d9b41c..56a3107715 100644 --- a/backend/capellacollab/projects/toolmodels/modelsources/t4c/crud.py +++ b/backend/capellacollab/projects/toolmodels/modelsources/t4c/crud.py @@ -29,7 +29,7 @@ def get_t4c_models(db: orm.Session) -> abc.Sequence[models.DatabaseT4CModel]: def get_t4c_models_for_tool_model( - db: orm.Session, model: toolmodels_models.DatabaseCapellaModel + db: orm.Session, model: toolmodels_models.DatabaseToolModel ) -> abc.Sequence[models.DatabaseT4CModel]: return ( db.execute( @@ -44,7 +44,7 @@ def get_t4c_models_for_tool_model( def create_t4c_model( db: orm.Session, - model: toolmodels_models.DatabaseCapellaModel, + model: toolmodels_models.DatabaseToolModel, repository: repositories_models.DatabaseT4CRepository, name: str, ) -> models.DatabaseT4CModel: diff --git a/backend/capellacollab/projects/toolmodels/modelsources/t4c/injectables.py b/backend/capellacollab/projects/toolmodels/modelsources/t4c/injectables.py index 81ff0fe389..3f9946657f 100644 --- a/backend/capellacollab/projects/toolmodels/modelsources/t4c/injectables.py +++ b/backend/capellacollab/projects/toolmodels/modelsources/t4c/injectables.py @@ -16,7 +16,7 @@ def get_existing_t4c_model( t4c_model_id: int, - capella_model: toolmodels_models.DatabaseCapellaModel = fastapi.Depends( + capella_model: toolmodels_models.DatabaseToolModel = fastapi.Depends( toolmodels_injectables.get_existing_capella_model ), db: orm.Session = fastapi.Depends(database.get_db), diff --git a/backend/capellacollab/projects/toolmodels/modelsources/t4c/models.py b/backend/capellacollab/projects/toolmodels/modelsources/t4c/models.py index 7fc1f740ae..9796609f01 100644 --- a/backend/capellacollab/projects/toolmodels/modelsources/t4c/models.py +++ b/backend/capellacollab/projects/toolmodels/modelsources/t4c/models.py @@ -15,7 +15,7 @@ ) if t.TYPE_CHECKING: - from capellacollab.projects.toolmodels.models import DatabaseCapellaModel + from capellacollab.projects.toolmodels.models import DatabaseToolModel from capellacollab.settings.modelsources.t4c.repositories.models import ( DatabaseT4CRepository, ) @@ -28,19 +28,21 @@ class DatabaseT4CModel(database.Base): ) id: orm.Mapped[int] = orm.mapped_column( - unique=True, primary_key=True, index=True + init=False, unique=True, primary_key=True, index=True ) name: orm.Mapped[str] = orm.mapped_column(index=True) repository_id: orm.Mapped[int] = orm.mapped_column( - sa.ForeignKey("t4c_repositories.id") + sa.ForeignKey("t4c_repositories.id"), init=False ) repository: orm.Mapped[DatabaseT4CRepository] = orm.relationship( back_populates="models" ) - model_id: orm.Mapped[int] = orm.mapped_column(sa.ForeignKey("models.id")) - model: orm.Mapped[DatabaseCapellaModel] = orm.relationship( + model_id: orm.Mapped[int] = orm.mapped_column( + sa.ForeignKey("models.id"), init=False + ) + model: orm.Mapped[DatabaseToolModel] = orm.relationship( back_populates="t4c_models" ) diff --git a/backend/capellacollab/projects/toolmodels/modelsources/t4c/routes.py b/backend/capellacollab/projects/toolmodels/modelsources/t4c/routes.py index dd22a81cc9..739ea75d4e 100644 --- a/backend/capellacollab/projects/toolmodels/modelsources/t4c/routes.py +++ b/backend/capellacollab/projects/toolmodels/modelsources/t4c/routes.py @@ -41,7 +41,7 @@ response_model=list[models.T4CModel], ) def list_t4c_models( - model: toolmodels_models.DatabaseCapellaModel = fastapi.Depends( + model: toolmodels_models.DatabaseToolModel = fastapi.Depends( toolmodels_injectables.get_existing_capella_model ), db: orm.Session = fastapi.Depends(database.get_db), @@ -74,7 +74,7 @@ def get_t4c_model( ) def create_t4c_model( body: models.SubmitT4CModel, - model: toolmodels_models.DatabaseCapellaModel = fastapi.Depends( + model: toolmodels_models.DatabaseToolModel = fastapi.Depends( toolmodels_injectables.get_existing_capella_model ), db: orm.Session = fastapi.Depends(database.get_db), diff --git a/backend/capellacollab/projects/toolmodels/restrictions/injectables.py b/backend/capellacollab/projects/toolmodels/restrictions/injectables.py index 4df8d1e2c3..742a339caf 100644 --- a/backend/capellacollab/projects/toolmodels/restrictions/injectables.py +++ b/backend/capellacollab/projects/toolmodels/restrictions/injectables.py @@ -10,8 +10,10 @@ def get_model_restrictions( - model: toolmodels_models.DatabaseCapellaModel = fastapi.Depends( + model: toolmodels_models.DatabaseToolModel = fastapi.Depends( toolmodels_injectables.get_existing_capella_model ), -) -> models.DatabaseToolModelRestrictions: - return model.restrictions +) -> models.DatabaseToolModelRestrictions | None: + restrictions = model.restrictions + assert restrictions # restrictions are only None for a short time during creation + return restrictions diff --git a/backend/capellacollab/projects/toolmodels/restrictions/models.py b/backend/capellacollab/projects/toolmodels/restrictions/models.py index e2d93d2a07..ee646f58b6 100644 --- a/backend/capellacollab/projects/toolmodels/restrictions/models.py +++ b/backend/capellacollab/projects/toolmodels/restrictions/models.py @@ -12,7 +12,7 @@ from capellacollab.core import database if t.TYPE_CHECKING: - from capellacollab.projects.toolmodels.models import DatabaseCapellaModel + from capellacollab.projects.toolmodels.models import DatabaseToolModel class ToolModelRestrictions(pydantic.BaseModel): @@ -28,11 +28,13 @@ class DatabaseToolModelRestrictions(database.Base): __tablename__ = "model_restrictions" id: orm.Mapped[int] = orm.mapped_column( - primary_key=True, index=True, unique=True + init=False, primary_key=True, index=True, unique=True ) - model_id: orm.Mapped[int] = orm.mapped_column(sa.ForeignKey("models.id")) - model: orm.Mapped[DatabaseCapellaModel] = orm.relationship( + model_id: orm.Mapped[int] = orm.mapped_column( + sa.ForeignKey("models.id"), init=False + ) + model: orm.Mapped[DatabaseToolModel] = orm.relationship( back_populates="restrictions" ) diff --git a/backend/capellacollab/projects/toolmodels/restrictions/routes.py b/backend/capellacollab/projects/toolmodels/restrictions/routes.py index 9819b93274..4114d84550 100644 --- a/backend/capellacollab/projects/toolmodels/restrictions/routes.py +++ b/backend/capellacollab/projects/toolmodels/restrictions/routes.py @@ -41,12 +41,16 @@ def update_restrictions( restrictions: models.DatabaseToolModelRestrictions = fastapi.Depends( injectables.get_model_restrictions ), - model: toolmodels_models.DatabaseCapellaModel = fastapi.Depends( + model: toolmodels_models.DatabaseToolModel = fastapi.Depends( toolmodels_injectables.get_existing_capella_model ), db: orm.Session = fastapi.Depends(database.get_db), ) -> models.DatabaseToolModelRestrictions: - if body.allow_pure_variants and not model.tool.integrations.pure_variants: + if ( + body.allow_pure_variants + and model.tool.integrations + and not model.tool.integrations.pure_variants + ): raise fastapi.HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail={ diff --git a/backend/capellacollab/projects/toolmodels/routes.py b/backend/capellacollab/projects/toolmodels/routes.py index 32befc9ff4..63f4ce900f 100644 --- a/backend/capellacollab/projects/toolmodels/routes.py +++ b/backend/capellacollab/projects/toolmodels/routes.py @@ -45,7 +45,7 @@ def get_models( project: projects_models.DatabaseProject = fastapi.Depends( projects_injectables.get_existing_project ), -) -> list[models.DatabaseCapellaModel]: +) -> list[models.DatabaseToolModel]: return project.models @@ -55,10 +55,10 @@ def get_models( tags=["Projects - Models"], ) def get_model_by_slug( - model: models.DatabaseCapellaModel = fastapi.Depends( + model: models.DatabaseToolModel = fastapi.Depends( injectables.get_existing_capella_model ), -) -> models.DatabaseCapellaModel: +) -> models.DatabaseToolModel: return model @@ -80,13 +80,13 @@ def create_new_tool_model( projects_injectables.get_existing_project ), db: orm.Session = fastapi.Depends(database.get_db), -) -> models.DatabaseCapellaModel: +) -> models.DatabaseToolModel: tool = tools_injectables.get_existing_tool( tool_id=new_model.tool_id, db=db ) configuration = {} - if tool.integrations.jupyter: + if tool.integrations and tool.integrations.jupyter: configuration["workspace"] = str(uuid.uuid4()) try: @@ -102,7 +102,7 @@ def create_new_tool_model( }, ) - if tool.integrations.jupyter: + if tool.integrations and tool.integrations.jupyter: workspace.create_shared_workspace( configuration["workspace"], project, model, "2Gi" ) @@ -127,14 +127,14 @@ def patch_tool_model( project: projects_models.DatabaseProject = fastapi.Depends( projects_injectables.get_existing_project ), - model: models.DatabaseCapellaModel = fastapi.Depends( + model: models.DatabaseToolModel = fastapi.Depends( injectables.get_existing_capella_model ), db: orm.Session = fastapi.Depends(database.get_db), user: users_models.DatabaseUser = fastapi.Depends( users_injectables.get_own_user ), -) -> models.DatabaseCapellaModel: +) -> models.DatabaseToolModel: if body.name: new_slug = slugify.slugify(body.name) @@ -154,7 +154,7 @@ def patch_tool_model( if body.version_id else model.version ) - if body.version_id and version.tool != model.tool: + if version and body.version_id and version.tool != model.tool: raise fastapi.HTTPException( status_code=status.HTTP_409_CONFLICT, detail={ @@ -167,7 +167,7 @@ def patch_tool_model( if body.nature_id else model.nature ) - if body.nature_id is not None and nature.tool != model.tool: + if nature and body.nature_id and nature.tool != model.tool: raise fastapi.HTTPException( status_code=status.HTTP_409_CONFLICT, detail={ @@ -208,7 +208,7 @@ def patch_tool_model( tags=["Projects - Models"], ) def delete_tool_model( - model: models.DatabaseCapellaModel = fastapi.Depends( + model: models.DatabaseToolModel = fastapi.Depends( injectables.get_existing_capella_model ), db: orm.Session = fastapi.Depends(database.get_db), @@ -231,7 +231,8 @@ def delete_tool_model( ) if ( - model.tool.integrations.jupyter + model.tool.integrations + and model.tool.integrations.jupyter and model.configuration and "workspace" in model.configuration ): @@ -290,7 +291,7 @@ def determine_new_project_to_move_model( def raise_if_model_exists_in_project( - model: models.DatabaseCapellaModel, + model: models.DatabaseToolModel, project: projects_models.DatabaseProject, ): if model.slug in [model.slug for model in project.models]: diff --git a/backend/capellacollab/projects/toolmodels/validation.py b/backend/capellacollab/projects/toolmodels/validation.py index c7c8453f8a..72650d9e38 100644 --- a/backend/capellacollab/projects/toolmodels/validation.py +++ b/backend/capellacollab/projects/toolmodels/validation.py @@ -5,7 +5,7 @@ def calculate_model_warnings( - model: models.DatabaseCapellaModel, + model: models.DatabaseToolModel, ) -> list[str]: warnings = [] if not model.nature: diff --git a/backend/capellacollab/projects/toolmodels/workspace.py b/backend/capellacollab/projects/toolmodels/workspace.py index 8cda5908f0..2d1c0f3c20 100644 --- a/backend/capellacollab/projects/toolmodels/workspace.py +++ b/backend/capellacollab/projects/toolmodels/workspace.py @@ -10,7 +10,7 @@ def create_shared_workspace( name: str, project: projects_models.DatabaseProject, - model: models.DatabaseCapellaModel, + model: models.DatabaseToolModel, size: str, ): operators.get_operator().create_persistent_volume( diff --git a/backend/capellacollab/projects/users/models.py b/backend/capellacollab/projects/users/models.py index 86c5cafa5b..4ed1fa2725 100644 --- a/backend/capellacollab/projects/users/models.py +++ b/backend/capellacollab/projects/users/models.py @@ -53,14 +53,14 @@ class ProjectUserAssociation(database.Base): __tablename__ = "project_user_association" user_id: orm.Mapped[int] = orm.mapped_column( - sa.ForeignKey("users.id"), primary_key=True + sa.ForeignKey("users.id"), primary_key=True, init=False ) user: orm.Mapped["DatabaseUser"] = orm.relationship( back_populates="projects" ) project_id: orm.Mapped[int] = orm.mapped_column( - sa.ForeignKey("projects.id"), primary_key=True + sa.ForeignKey("projects.id"), primary_key=True, init=False ) project: orm.Mapped["DatabaseProject"] = orm.relationship( back_populates="users" diff --git a/backend/capellacollab/sessions/hooks/jupyter.py b/backend/capellacollab/sessions/hooks/jupyter.py index 1d941c0094..e74ffd3649 100644 --- a/backend/capellacollab/sessions/hooks/jupyter.py +++ b/backend/capellacollab/sessions/hooks/jupyter.py @@ -136,7 +136,7 @@ def _get_project_share_volume_mounts( def _is_project_member( self, - model: toolmodels_models.DatabaseCapellaModel, + model: toolmodels_models.DatabaseToolModel, username: str, db: orm.Session, ) -> bool: @@ -147,7 +147,7 @@ def _is_project_member( def _has_project_write_access( self, - model: toolmodels_models.DatabaseCapellaModel, + model: toolmodels_models.DatabaseToolModel, username: str, db: orm.Session, ) -> bool: diff --git a/backend/capellacollab/sessions/hooks/pure_variants.py b/backend/capellacollab/sessions/hooks/pure_variants.py index 642a793c56..cabd59299d 100644 --- a/backend/capellacollab/sessions/hooks/pure_variants.py +++ b/backend/capellacollab/sessions/hooks/pure_variants.py @@ -82,7 +82,7 @@ def configuration_hook( # type: ignore def _model_allows_pure_variants( self, - model: toolmodels_models.DatabaseCapellaModel, + model: toolmodels_models.DatabaseToolModel, ): return model.restrictions and model.restrictions.allow_pure_variants diff --git a/backend/capellacollab/sessions/models.py b/backend/capellacollab/sessions/models.py index b489d3a161..5e69b83626 100644 --- a/backend/capellacollab/sessions/models.py +++ b/backend/capellacollab/sessions/models.py @@ -112,17 +112,21 @@ class DatabaseSession(database.Base): ) owner: orm.Mapped[DatabaseUser] = orm.relationship() - tool_id: orm.Mapped[int] = orm.mapped_column(sa.ForeignKey("tools.id")) + tool_id: orm.Mapped[int] = orm.mapped_column( + sa.ForeignKey("tools.id"), init=False + ) tool: orm.Mapped[DatabaseTool] = orm.relationship() version_id: orm.Mapped[int] = orm.mapped_column( - sa.ForeignKey("versions.id") + sa.ForeignKey("versions.id"), init=False ) version: orm.Mapped[DatabaseVersion] = orm.relationship() project_id: orm.Mapped[str | None] = orm.mapped_column( - sa.ForeignKey("projects.id") + sa.ForeignKey("projects.id"), init=False ) - project: orm.Mapped[projects_models.DatabaseProject] = orm.relationship() + project: orm.Mapped[ + projects_models.DatabaseProject | None + ] = orm.relationship() environment: orm.Mapped[dict[str, str] | None] diff --git a/backend/capellacollab/sessions/routes.py b/backend/capellacollab/sessions/routes.py index 68863b2973..cff83ca50f 100644 --- a/backend/capellacollab/sessions/routes.py +++ b/backend/capellacollab/sessions/routes.py @@ -244,7 +244,7 @@ def models_as_json( session_model_list: list[ tuple[ models.PostReadonlySessionEntry, - toolmodels_models.DatabaseCapellaModel, + toolmodels_models.DatabaseToolModel, ] ] ): @@ -267,7 +267,9 @@ def git_model_as_json( "revision": revision, "depth": 0 if deep_clone else 1, "entrypoint": git_model.entrypoint, - "nature": git_model.model.nature.name, + "nature": ( + git_model.model.nature.name if git_model.model.nature else "" + ), } if git_model.username: d["username"] = git_model.username @@ -357,11 +359,12 @@ def raise_if_conflicting_persistent_sessions( # Currently, all tools share one workspace. Eclipse based tools lock the workspace. # We can only run one Eclipse-based tool at a time. # Status tracked in https://github.com/DSD-DBS/capella-collab-manager/issues/847 - if tool.integrations.jupyter: + if tool.integrations and tool.integrations.jupyter: # Check if there is already an Jupyter session running. if True in [ session.tool.integrations.jupyter for session in existing_user_sessions + if session.tool.integrations ]: raise fastapi.HTTPException( status_code=status.HTTP_409_CONFLICT, diff --git a/backend/capellacollab/settings/configuration/models.py b/backend/capellacollab/settings/configuration/models.py index 829395a052..ea554bfcf1 100644 --- a/backend/capellacollab/settings/configuration/models.py +++ b/backend/capellacollab/settings/configuration/models.py @@ -14,7 +14,7 @@ class DatabaseConfiguration(database.Base): __tablename__ = "configuration" id: orm.Mapped[int] = orm.mapped_column( - unique=True, primary_key=True, index=True + init=False, unique=True, primary_key=True, index=True ) name: orm.Mapped[str] = orm.mapped_column(unique=True, index=True) diff --git a/backend/capellacollab/settings/integrations/purevariants/models.py b/backend/capellacollab/settings/integrations/purevariants/models.py index bae5c84238..da77d1ad2b 100644 --- a/backend/capellacollab/settings/integrations/purevariants/models.py +++ b/backend/capellacollab/settings/integrations/purevariants/models.py @@ -28,7 +28,9 @@ def validate_license_url(value: str | None): class DatabasePureVariantsLicenses(database.Base): __tablename__ = "pure_variants" - id: orm.Mapped[int] = orm.mapped_column(primary_key=True, index=True) + id: orm.Mapped[int] = orm.mapped_column( + init=False, primary_key=True, index=True + ) license_server_url: orm.Mapped[str | None] license_key_filename: orm.Mapped[str | None] diff --git a/backend/capellacollab/settings/modelsources/git/models.py b/backend/capellacollab/settings/modelsources/git/models.py index fa47081460..f408c60673 100644 --- a/backend/capellacollab/settings/modelsources/git/models.py +++ b/backend/capellacollab/settings/modelsources/git/models.py @@ -34,7 +34,7 @@ class DatabaseGitInstance(database.Base): __tablename__ = "git_instances" id: orm.Mapped[int] = orm.mapped_column( - primary_key=True, index=True, autoincrement=True + init=False, primary_key=True, index=True, autoincrement=True ) name: orm.Mapped[str] diff --git a/backend/capellacollab/settings/modelsources/t4c/models.py b/backend/capellacollab/settings/modelsources/t4c/models.py index 91ad5d6586..065a28716b 100644 --- a/backend/capellacollab/settings/modelsources/t4c/models.py +++ b/backend/capellacollab/settings/modelsources/t4c/models.py @@ -46,39 +46,42 @@ class DatabaseT4CInstance(database.Base): __tablename__ = "t4c_instances" id: orm.Mapped[int] = orm.mapped_column( - primary_key=True, index=True, autoincrement=True + init=False, primary_key=True, index=True, autoincrement=True ) name: orm.Mapped[str] = orm.mapped_column(unique=True) license: orm.Mapped[str] host: orm.Mapped[str] - port: orm.Mapped[int] = orm.mapped_column( - sa.CheckConstraint("port >= 0 AND port <= 65535"), default=2036 - ) - cdo_port: orm.Mapped[int] = orm.mapped_column( - sa.CheckConstraint("cdo_port >= 0 AND cdo_port <= 65535"), - default=12036, - ) - http_port: orm.Mapped[int | None] = orm.mapped_column( - sa.CheckConstraint("http_port >= 0 AND http_port <= 65535"), - ) + usage_api: orm.Mapped[str] rest_api: orm.Mapped[str] username: orm.Mapped[str] password: orm.Mapped[str] - protocol: orm.Mapped[Protocol] = orm.mapped_column(default=Protocol.tcp) - version_id: orm.Mapped[int] = orm.mapped_column( - sa.ForeignKey("versions.id") + sa.ForeignKey("versions.id"), init=False ) version: orm.Mapped[DatabaseVersion] = orm.relationship() repositories: orm.Mapped[list[DatabaseT4CRepository]] = orm.relationship( - back_populates="instance", cascade="all, delete" + default_factory=list, back_populates="instance", cascade="all, delete" ) + port: orm.Mapped[int] = orm.mapped_column( + sa.CheckConstraint("port >= 0 AND port <= 65535"), default=2036 + ) + + http_port: orm.Mapped[int | None] = orm.mapped_column( + sa.CheckConstraint("http_port >= 0 AND http_port <= 65535"), + default=None, + ) + cdo_port: orm.Mapped[int] = orm.mapped_column( + sa.CheckConstraint("cdo_port >= 0 AND cdo_port <= 65535"), + default=12036, + ) + protocol: orm.Mapped[Protocol] = orm.mapped_column(default=Protocol.tcp) + is_archived: orm.Mapped[bool] = orm.mapped_column(default=False) diff --git a/backend/capellacollab/settings/modelsources/t4c/repositories/crud.py b/backend/capellacollab/settings/modelsources/t4c/repositories/crud.py index 885b1397b6..f3654666fc 100644 --- a/backend/capellacollab/settings/modelsources/t4c/repositories/crud.py +++ b/backend/capellacollab/settings/modelsources/t4c/repositories/crud.py @@ -82,9 +82,9 @@ def _get_user_write_t4c_repositories( sa.select(models.DatabaseT4CRepository) .join(models.DatabaseT4CRepository.models) .join(t4c_models.DatabaseT4CModel.model) - .join(toolmodels_models.DatabaseCapellaModel.version) + .join(toolmodels_models.DatabaseToolModel.version) .where(tools_models.DatabaseVersion.name == version_name) - .join(toolmodels_models.DatabaseCapellaModel.project) + .join(toolmodels_models.DatabaseToolModel.project) .where(projects_models.DatabaseProject.is_archived.is_(False)) .join(projects_models.DatabaseProject.users) .where( @@ -104,9 +104,9 @@ def _get_admin_t4c_repositories( sa.select(models.DatabaseT4CRepository) .join(models.DatabaseT4CRepository.models) .join(t4c_models.DatabaseT4CModel.model) - .join(toolmodels_models.DatabaseCapellaModel.version) + .join(toolmodels_models.DatabaseToolModel.version) .where(tools_models.DatabaseVersion.name == version_name) - .join(toolmodels_models.DatabaseCapellaModel.project) + .join(toolmodels_models.DatabaseToolModel.project) .where(projects_models.DatabaseProject.is_archived.is_(False)) ) diff --git a/backend/capellacollab/settings/modelsources/t4c/repositories/models.py b/backend/capellacollab/settings/modelsources/t4c/repositories/models.py index 2786d71f15..d661486ab8 100644 --- a/backend/capellacollab/settings/modelsources/t4c/repositories/models.py +++ b/backend/capellacollab/settings/modelsources/t4c/repositories/models.py @@ -27,19 +27,25 @@ class DatabaseT4CRepository(database.Base): __table_args__ = (sa.UniqueConstraint("instance_id", "name"),) id: orm.Mapped[int] = orm.mapped_column( - primary_key=True, index=True, autoincrement=True, unique=True + init=False, + primary_key=True, + index=True, + autoincrement=True, + unique=True, ) name: orm.Mapped[str] instance_id: orm.Mapped[int] = orm.mapped_column( - sa.ForeignKey("t4c_instances.id") + sa.ForeignKey("t4c_instances.id"), init=False ) instance: orm.Mapped[DatabaseT4CInstance] = orm.relationship( back_populates="repositories" ) models: orm.Mapped[list[DatabaseT4CModel]] = orm.relationship( - back_populates="repository", cascade="all, delete" + back_populates="repository", + cascade="all, delete", + default_factory=list, ) diff --git a/backend/capellacollab/tools/crud.py b/backend/capellacollab/tools/crud.py index 9692e9b8ec..044820ead9 100644 --- a/backend/capellacollab/tools/crud.py +++ b/backend/capellacollab/tools/crud.py @@ -38,7 +38,7 @@ def create_tool( db: orm.Session, tool: models.DatabaseTool ) -> models.DatabaseTool: tool.integrations = integrations_models.DatabaseToolIntegrations( - pure_variants=False, t4c=False, jupyter=False + tool=tool, pure_variants=False, t4c=False, jupyter=False ) db.add(tool) db.commit() @@ -151,7 +151,7 @@ def update_version( def create_version( db: orm.Session, - tool_id: int, + tool: models.DatabaseTool, name: str, is_recommended: bool = False, is_deprecated: bool = False, @@ -160,7 +160,7 @@ def create_version( name=name, is_recommended=is_recommended, is_deprecated=is_deprecated, - tool_id=tool_id, + tool=tool, ) db.add(version) db.commit() @@ -223,9 +223,9 @@ def get_natures_by_tool_id( def create_nature( - db: orm.Session, tool_id: int, name: str + db: orm.Session, tool: models.DatabaseTool, name: str ) -> models.DatabaseNature: - nature = models.DatabaseNature(name=name, tool_id=tool_id) + nature = models.DatabaseNature(name=name, tool=tool) db.add(nature) db.commit() return nature diff --git a/backend/capellacollab/tools/integrations/models.py b/backend/capellacollab/tools/integrations/models.py index 9615d5663b..937885194e 100644 --- a/backend/capellacollab/tools/integrations/models.py +++ b/backend/capellacollab/tools/integrations/models.py @@ -32,9 +32,11 @@ class PatchToolIntegrations(pydantic.BaseModel): class DatabaseToolIntegrations(database.Base): __tablename__ = "tool_integrations" - id: orm.Mapped[int] = orm.mapped_column(primary_key=True) + id: orm.Mapped[int] = orm.mapped_column(init=False, primary_key=True) - tool_id: orm.Mapped[int] = orm.mapped_column(sa.ForeignKey("tools.id")) + tool_id: orm.Mapped[int] = orm.mapped_column( + sa.ForeignKey("tools.id"), init=False + ) tool: orm.Mapped[DatabaseTool] = orm.relationship( back_populates="integrations" ) diff --git a/backend/capellacollab/tools/integrations/routes.py b/backend/capellacollab/tools/integrations/routes.py index a5953e333e..349144d196 100644 --- a/backend/capellacollab/tools/integrations/routes.py +++ b/backend/capellacollab/tools/integrations/routes.py @@ -31,4 +31,5 @@ def update_integrations( ), db: orm.Session = fastapi.Depends(database.get_db), ) -> models.DatabaseToolIntegrations: + assert tool.integrations return crud.update_integrations(db, tool.integrations, body) diff --git a/backend/capellacollab/tools/models.py b/backend/capellacollab/tools/models.py index ec682ad095..65e436211b 100644 --- a/backend/capellacollab/tools/models.py +++ b/backend/capellacollab/tools/models.py @@ -20,22 +20,30 @@ class DatabaseTool(database.Base): __tablename__ = "tools" - id: orm.Mapped[int] = orm.mapped_column(primary_key=True) + id: orm.Mapped[int] = orm.mapped_column(init=False, primary_key=True) name: orm.Mapped[str] docker_image_template: orm.Mapped[str] - docker_image_backup_template: orm.Mapped[str | None] - readonly_docker_image_template: orm.Mapped[str | None] + docker_image_backup_template: orm.Mapped[str | None] = orm.mapped_column( + default=None + ) + readonly_docker_image_template: orm.Mapped[str | None] = orm.mapped_column( + default=None + ) + + integrations: orm.Mapped[ + DatabaseToolIntegrations | None + ] = orm.relationship( + default=None, + back_populates="tool", + uselist=False, + ) versions: orm.Mapped[list[DatabaseVersion]] = orm.relationship( - back_populates="tool" + default_factory=list, back_populates="tool" ) natures: orm.Mapped[list[DatabaseNature]] = orm.relationship( - back_populates="tool" - ) - - integrations: orm.Mapped[DatabaseToolIntegrations] = orm.relationship( - back_populates="tool", uselist=False + default_factory=list, back_populates="tool" ) @@ -43,14 +51,15 @@ class DatabaseVersion(database.Base): __tablename__ = "versions" __table_args__ = (sa.UniqueConstraint("tool_id", "name"),) - id: orm.Mapped[int] = orm.mapped_column(primary_key=True) + id: orm.Mapped[int] = orm.mapped_column(init=False, primary_key=True) name: orm.Mapped[str] is_recommended: orm.Mapped[bool] is_deprecated: orm.Mapped[bool] tool_id: orm.Mapped[int | None] = orm.mapped_column( - sa.ForeignKey("tools.id") + sa.ForeignKey("tools.id"), + init=False, ) tool: orm.Mapped[DatabaseTool] = orm.relationship( back_populates="versions" @@ -61,11 +70,11 @@ class DatabaseNature(database.Base): __tablename__ = "types" __table_args__ = (sa.UniqueConstraint("tool_id", "name"),) - id: orm.Mapped[int] = orm.mapped_column(primary_key=True) + id: orm.Mapped[int] = orm.mapped_column(init=False, primary_key=True) name: orm.Mapped[str] tool_id: orm.Mapped[int | None] = orm.mapped_column( - sa.ForeignKey("tools.id") + sa.ForeignKey("tools.id"), init=False ) tool: orm.Mapped[DatabaseTool] = orm.relationship(back_populates="natures") diff --git a/backend/capellacollab/tools/routes.py b/backend/capellacollab/tools/routes.py index 0b89b32072..668310a58a 100644 --- a/backend/capellacollab/tools/routes.py +++ b/backend/capellacollab/tools/routes.py @@ -130,7 +130,7 @@ def create_tool_version( tool: models.DatabaseTool = fastapi.Depends(injectables.get_existing_tool), db: orm.Session = fastapi.Depends(database.get_db), ) -> models.DatabaseVersion: - return crud.create_version(db, tool.id, body.name) + return crud.create_version(db, tool, body.name) @router.patch( @@ -194,11 +194,11 @@ def get_tool_natures( ], ) def create_tool_nature( - tool_id: int, body: models.CreateToolNature, + tool: models.DatabaseTool = fastapi.Depends(injectables.get_existing_tool), db: orm.Session = fastapi.Depends(database.get_db), ) -> models.DatabaseNature: - return crud.create_nature(db, tool_id, body.name) + return crud.create_nature(db, tool, body.name) @router.delete( diff --git a/backend/capellacollab/users/models.py b/backend/capellacollab/users/models.py index d1ffef652e..2abcb1c663 100644 --- a/backend/capellacollab/users/models.py +++ b/backend/capellacollab/users/models.py @@ -59,23 +59,34 @@ class PostUser(pydantic.BaseModel): class DatabaseUser(database.Base): __tablename__ = "users" - id: orm.Mapped[int] = orm.mapped_column(primary_key=True, index=True) + id: orm.Mapped[int] = orm.mapped_column( + init=False, primary_key=True, index=True + ) name: orm.Mapped[str] = orm.mapped_column(unique=True, index=True) role: orm.Mapped[Role] - created: orm.Mapped[datetime.datetime | None] - last_login: orm.Mapped[datetime.datetime | None] + created: orm.Mapped[datetime.datetime | None] = orm.mapped_column( + default=datetime.datetime.now(datetime.UTC) + ) projects: orm.Mapped[list[ProjectUserAssociation]] = orm.relationship( - back_populates="user" + default_factory=list, back_populates="user" ) sessions: orm.Mapped[list[DatabaseSession]] = orm.relationship( - back_populates="owner" + default_factory=list, back_populates="owner" ) events: orm.Mapped[list[DatabaseUserHistoryEvent]] = orm.relationship( - back_populates="user", foreign_keys="DatabaseUserHistoryEvent.user_id" + default_factory=list, + back_populates="user", + foreign_keys="DatabaseUserHistoryEvent.user_id", ) tokens: orm.Mapped[list[DatabaseUserToken]] = orm.relationship( - back_populates="user", cascade="all, delete-orphan" + default_factory=list, + back_populates="user", + cascade="all, delete-orphan", + ) + + last_login: orm.Mapped[datetime.datetime | None] = orm.mapped_column( + default=None ) diff --git a/backend/capellacollab/users/tokens/crud.py b/backend/capellacollab/users/tokens/crud.py index cadf80e540..233c2e7d4e 100644 --- a/backend/capellacollab/users/tokens/crud.py +++ b/backend/capellacollab/users/tokens/crud.py @@ -9,23 +9,24 @@ from sqlalchemy import orm from capellacollab.core import credentials +from capellacollab.users import models as users_models from . import models def create_token( db: orm.Session, - user_id: int, + user: users_models.DatabaseUser, description: str, expiration_date: datetime.date | None, - source: str | None, + source: str, ) -> tuple[models.DatabaseUserToken, str]: password = "collabmanager_" + credentials.generate_password(32) ph = argon2.PasswordHasher() if not expiration_date: expiration_date = datetime.date.today() + datetime.timedelta(days=30) db_token = models.DatabaseUserToken( - user_id=user_id, + user=user, hash=ph.hash(password), expiration_date=expiration_date, description=description, diff --git a/backend/capellacollab/users/tokens/models.py b/backend/capellacollab/users/tokens/models.py index 38345a8403..23acc32beb 100644 --- a/backend/capellacollab/users/tokens/models.py +++ b/backend/capellacollab/users/tokens/models.py @@ -38,9 +38,11 @@ class DatabaseUserToken(database.Base): __tablename__ = "basic_auth_token" id: orm.Mapped[int] = orm.mapped_column( - primary_key=True, index=True, autoincrement=True + init=False, primary_key=True, index=True, autoincrement=True + ) + user_id: orm.Mapped[int] = orm.mapped_column( + sa.ForeignKey("users.id"), init=False ) - user_id: orm.Mapped[int] = orm.mapped_column(sa.ForeignKey("users.id")) user: orm.Mapped["DatabaseUser"] = orm.relationship( back_populates="tokens", foreign_keys=[user_id] ) diff --git a/backend/capellacollab/users/tokens/routes.py b/backend/capellacollab/users/tokens/routes.py index 33ee0b844b..fe08816e91 100644 --- a/backend/capellacollab/users/tokens/routes.py +++ b/backend/capellacollab/users/tokens/routes.py @@ -34,7 +34,7 @@ def create_token_for_user( ) -> models.UserTokenWithPassword: token, password = crud.create_token( db, - user.id, + user, post_token.description, post_token.expiration_date, post_token.source, diff --git a/backend/tests/projects/toolmodels/conftest.py b/backend/tests/projects/toolmodels/conftest.py index 401d9ca218..a34ef4545a 100644 --- a/backend/tests/projects/toolmodels/conftest.py +++ b/backend/tests/projects/toolmodels/conftest.py @@ -45,7 +45,7 @@ def fixture_capella_model( db: orm.Session, project: project_models.DatabaseProject, capella_tool_version: tools_models.DatabaseVersion, -) -> toolmodels_models.DatabaseCapellaModel: +) -> toolmodels_models.DatabaseToolModel: model = toolmodels_models.PostCapellaModel( name="test", description="test", tool_id=capella_tool_version.tool.id ) @@ -91,7 +91,7 @@ def fixture_git_instance( @pytest.fixture(name="git_model") def fixture_git_models( - db: orm.Session, capella_model: toolmodels_models.DatabaseCapellaModel + db: orm.Session, capella_model: toolmodels_models.DatabaseToolModel ) -> project_git_models.DatabaseGitModel: git_model = project_git_models.PostGitModel( path="https://example.com/test/project", @@ -277,7 +277,7 @@ def fixture_t4c_repository( @pytest.fixture(name="t4c_model") def fixture_t4c_model( db: orm.Session, - capella_model: toolmodels_models.DatabaseCapellaModel, + capella_model: toolmodels_models.DatabaseToolModel, t4c_repository: settings_t4c_repositories_models.DatabaseT4CRepository, ) -> models_t4c_models.DatabaseT4CModel: return models_t4c_crud.create_t4c_model( diff --git a/backend/tests/projects/toolmodels/test_toolmodel_routes.py b/backend/tests/projects/toolmodels/test_toolmodel_routes.py index 2b84e72edd..56fc196f06 100644 --- a/backend/tests/projects/toolmodels/test_toolmodel_routes.py +++ b/backend/tests/projects/toolmodels/test_toolmodel_routes.py @@ -43,7 +43,7 @@ def fixture_override_dependency(): def test_rename_toolmodel_successful( - capella_model: toolmodels_models.DatabaseCapellaModel, + capella_model: toolmodels_models.DatabaseToolModel, project: projects_models.DatabaseProject, client: testclient.TestClient, executor_name: str, @@ -89,7 +89,7 @@ def test_rename_toolmodel_where_name_already_exists( def test_update_toolmodel_order_successful( - capella_model: toolmodels_models.DatabaseCapellaModel, + capella_model: toolmodels_models.DatabaseToolModel, project: projects_models.DatabaseProject, client: testclient.TestClient, executor_name: str, diff --git a/backend/tests/sessions/test_sessions_routes.py b/backend/tests/sessions/test_sessions_routes.py index 695c6b906d..cfdec31752 100644 --- a/backend/tests/sessions/test_sessions_routes.py +++ b/backend/tests/sessions/test_sessions_routes.py @@ -34,14 +34,8 @@ ) from capellacollab.sessions.operators import get_operator from capellacollab.sessions.operators import models as operators_models +from capellacollab.tools import crud as tools_crud from capellacollab.tools import models as tools_models -from capellacollab.tools.crud import ( - create_tool, - create_tool_with_name, - create_version, - get_natures, - get_versions, -) from capellacollab.tools.integrations.crud import update_integrations from capellacollab.tools.integrations.models import PatchToolIntegrations from capellacollab.users.crud import create_user @@ -179,7 +173,7 @@ def test_create_readonly_session_as_user( ): _, version = next( (v.tool, v) - for v in get_versions(db) + for v in tools_crud.get_versions(db) if v.tool.name == "Capella" and v.name == "5.0.0" ) @@ -217,8 +211,8 @@ def test_create_readonly_session_as_user( def test_no_readonly_session_as_user(client, db, user, kubernetes): - tool = create_tool_with_name(db, "Test") - version = create_version(db, tool.id, "test") + tool = tools_crud.create_tool_with_name(db, "Test") + version = tools_crud.create_version(db, tool, "test") model, git_model = setup_git_model_for_user(db, user, version) @@ -249,7 +243,7 @@ def test_one_readonly_sessions_as_user_per_tool_version( ): version = next( v - for v in get_versions(db) + for v in tools_crud.get_versions(db) if v.tool.name == "Capella" and v.name == "5.0.0" ) @@ -276,7 +270,7 @@ def test_one_readonly_sessions_as_user_per_tool_version( def setup_git_model_for_user(db, user, version): project = create_project(db, name=str(uuid1())) - nature = get_natures(db)[0] + nature = tools_crud.get_natures(db)[0] add_user_to_project( db, project, @@ -357,7 +351,7 @@ def test_create_read_only_session_as_user( ): version = next( v - for v in get_versions(db) + for v in tools_crud.get_versions(db) if v.tool.name == "Capella" and v.name == "6.0.0" ) @@ -377,7 +371,6 @@ def test_create_read_only_session_as_user( }, ) out = response.json() - print(out) session = get_session_by_id(db, out["id"]) assert response.status_code == 200 @@ -393,7 +386,7 @@ def test_create_read_only_session_as_user( def test_create_persistent_jupyter_session(client, db, user, kubernetes): - jupyter = create_tool( + jupyter = tools_crud.create_tool( db, tools_models.DatabaseTool( name="jupyter", @@ -404,8 +397,8 @@ def test_create_persistent_jupyter_session(client, db, user, kubernetes): db, jupyter.integrations, PatchToolIntegrations(jupyter=True) ) - jupyter_version = create_version( - db, name="python-3.10.8", tool_id=jupyter.id + jupyter_version = tools_crud.create_version( + db, name="python-3.10.8", tool=jupyter ) response = client.post( diff --git a/backend/tests/settings/conftest.py b/backend/tests/settings/conftest.py index d0aa936b11..e27b2bd9ae 100644 --- a/backend/tests/settings/conftest.py +++ b/backend/tests/settings/conftest.py @@ -15,7 +15,7 @@ @pytest.fixture(name="test_tool_version") def fixture_test_tool_version(db: orm.Session) -> tools_models.DatabaseVersion: tool = tools_crud.create_tool_with_name(db, "Test") - return tools_crud.create_version(db, tool.id, "test") + return tools_crud.create_version(db, tool, "test") @pytest.fixture(name="admin_user")