-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat!: Add support for global configuration
The global configuration is now defined in the yaml format in the frontend. We use the `monaco` editor. This is a breaking change. The following configuration options have to be configured manually after the update: - privacy policy URL - imprint URL - provider - authentication provider (Only the display name in the frontend) - environment (Only the display name in the frontend)
- Loading branch information
1 parent
eb64a9d
commit 2cb2ab5
Showing
32 changed files
with
15,358 additions
and
13,924 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
39 changes: 39 additions & 0 deletions
39
backend/capellacollab/alembic/versions/86ab7d4d1684_add_configuration_table.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
"""Add configuration table | ||
Revision ID: 86ab7d4d1684 | ||
Revises: f55b41e32223 | ||
Create Date: 2023-10-27 14:54:40.452599 | ||
""" | ||
import sqlalchemy as sa | ||
from alembic import op | ||
from sqlalchemy.dialects import postgresql | ||
|
||
# revision identifiers, used by Alembic. | ||
revision = "86ab7d4d1684" | ||
down_revision = "f55b41e32223" | ||
branch_labels = None | ||
depends_on = None | ||
|
||
|
||
def upgrade(): | ||
op.create_table( | ||
"configuration", | ||
sa.Column("id", sa.Integer(), nullable=False), | ||
sa.Column("name", sa.String(), nullable=False), | ||
sa.Column( | ||
"configuration", | ||
postgresql.JSONB(astext_type=sa.Text()), | ||
nullable=False, | ||
), | ||
sa.PrimaryKeyConstraint("id"), | ||
) | ||
op.create_index( | ||
op.f("ix_configuration_id"), "configuration", ["id"], unique=True | ||
) | ||
op.create_index( | ||
op.f("ix_configuration_name"), "configuration", ["name"], unique=True | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
from sqlalchemy import orm | ||
|
||
from . import crud, models | ||
|
||
|
||
def get_config(db: orm.Session, name: str) -> models.ConfigurationBase: | ||
"""Get a configuration by name.""" | ||
configuration = crud.get_configuration_by_name(db, name) | ||
model_type = models.NAME_TO_MODEL_TYPE_MAPPING[name] | ||
if configuration: | ||
return model_type().model_validate(configuration.configuration) | ||
return model_type().model_validate({}) | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
import sqlalchemy as sa | ||
from sqlalchemy import orm | ||
|
||
from . import models | ||
|
||
|
||
def get_configuration_by_name( | ||
db: orm.Session, name: str | ||
) -> None | models.DatabaseConfiguration: | ||
return db.execute( | ||
sa.select(models.DatabaseConfiguration).where( | ||
models.DatabaseConfiguration.name == name | ||
) | ||
).scalar_one_or_none() | ||
|
||
|
||
def get_pydantic_configuration_by_name( | ||
db: orm.Session, pydantic_model: models.ConfigurationBase | ||
): | ||
return pydantic_model.model_validate( | ||
get_configuration_by_name(db, pydantic_model._name) | ||
) | ||
|
||
|
||
def create_configuration( | ||
db: orm.Session, | ||
name: str, | ||
configuration: dict[str, str], | ||
) -> models.DatabaseConfiguration: | ||
db_configuration = models.DatabaseConfiguration( | ||
name=name, configuration=configuration | ||
) | ||
db.add(db_configuration) | ||
db.commit() | ||
return db_configuration | ||
|
||
|
||
def update_configuration( | ||
db: orm.Session, | ||
db_configuration: models.DatabaseConfiguration, | ||
configuration: dict[str, str], | ||
) -> models.DatabaseConfiguration: | ||
db_configuration.configuration = configuration | ||
db.commit() | ||
return db_configuration | ||
|
||
|
||
def delete_configuration( | ||
db: orm.Session, db_configuration: models.DatabaseConfiguration | ||
): | ||
db.delete(db_configuration) | ||
db.commit() | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
import abc | ||
import typing as t | ||
|
||
import pydantic | ||
from sqlalchemy import orm | ||
|
||
from capellacollab.core import database | ||
|
||
|
||
class DatabaseConfiguration(database.Base): | ||
__tablename__ = "configuration" | ||
|
||
id: orm.Mapped[int] = orm.mapped_column( | ||
unique=True, primary_key=True, index=True | ||
) | ||
|
||
name: orm.Mapped[str] = orm.mapped_column(unique=True, index=True) | ||
configuration: orm.Mapped[dict[str, t.Any]] | ||
|
||
|
||
class MetadataConfiguration(pydantic.BaseModel): | ||
model_config = pydantic.ConfigDict(extra="forbid") | ||
|
||
privacy_policy_url: str = pydantic.Field( | ||
default="https://example.com/privacy" | ||
) | ||
imprint_url: str = pydantic.Field(default="https://example.com/imprint") | ||
provider: str = pydantic.Field( | ||
default="Systems Engineering Toolchain team" | ||
) | ||
authentication_provider: str = pydantic.Field( | ||
default="OAuth2", | ||
description="Authentication provides which is displayed in the frontend.", | ||
) | ||
environment: str = pydantic.Field(default="-", description="general") | ||
|
||
|
||
class ConfigurationBase(pydantic.BaseModel, abc.ABC): | ||
""" | ||
All you need to do to add a new configuration is to create a new class | ||
which inherits from this class. | ||
""" | ||
|
||
model_config = pydantic.ConfigDict(extra="forbid") | ||
|
||
_name: t.ClassVar[str] | ||
|
||
|
||
class GlobalConfiguration(ConfigurationBase): | ||
"""Global application configuration.""" | ||
|
||
_name: t.ClassVar[t.Literal["global"]] = "global" | ||
|
||
metadata: MetadataConfiguration = pydantic.Field( | ||
default_factory=MetadataConfiguration | ||
) | ||
|
||
|
||
NAME_TO_MODEL_TYPE_MAPPING: dict[str, t.Type[ConfigurationBase]] = { | ||
model()._name: model for model in ConfigurationBase.__subclasses__() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
# SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
import typing as t | ||
|
||
import fastapi | ||
from sqlalchemy import orm | ||
|
||
from capellacollab.core import database | ||
from capellacollab.core.authentication import injectables as auth_injectables | ||
from capellacollab.users import models as users_models | ||
|
||
from . import core, crud, models | ||
|
||
router = fastapi.APIRouter( | ||
dependencies=[ | ||
fastapi.Depends( | ||
auth_injectables.RoleVerification( | ||
required_role=users_models.Role.ADMIN | ||
) | ||
) | ||
] | ||
) | ||
|
||
schema_router = fastapi.APIRouter(dependencies=[]) | ||
|
||
|
||
def get_endpoints(model_instance: models.ConfigurationBase): | ||
async def get_configuration( | ||
db: orm.Session = fastapi.Depends(database.get_db), | ||
): | ||
return core.get_config(db, model._name) | ||
|
||
async def update_configuration( | ||
body: models.GlobalConfiguration, | ||
db: orm.Session = fastapi.Depends(database.get_db), | ||
): | ||
configuration = crud.get_configuration_by_name(db, model._name) | ||
|
||
if configuration: | ||
return crud.update_configuration( | ||
db, configuration, body.model_dump() | ||
) | ||
return crud.create_configuration( | ||
db, name=model._name, configuration=body.model_dump() | ||
) | ||
|
||
async def get_json_schema(): | ||
return model.model_json_schema() | ||
|
||
return get_configuration, update_configuration, get_json_schema | ||
|
||
|
||
for model in models.ConfigurationBase.__subclasses__(): | ||
model_instance = model() | ||
get_config, update_config, get_schema = get_endpoints(model_instance) | ||
|
||
router.add_api_route( | ||
path=f"/{model_instance._name}", | ||
endpoint=get_config, | ||
methods=["GET"], | ||
response_model=model, | ||
) | ||
|
||
router.add_api_route( | ||
path=f"/{model_instance._name}", | ||
endpoint=update_config, | ||
methods=["PUT"], | ||
response_model=models.ConfigurationBase, | ||
) | ||
|
||
schema_router.add_api_route( | ||
path=f"/{model_instance._name}/schema", | ||
endpoint=get_schema, | ||
methods=["GET"], | ||
response_model=t.Any, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.