Skip to content

Commit

Permalink
feat: Unify various API endpoints related to config
Browse files Browse the repository at this point in the history
More details in the linked issue.

Closes #1960
  • Loading branch information
zusorio committed Dec 6, 2024
1 parent 0b5d8c2 commit 4b70bc8
Show file tree
Hide file tree
Showing 27 changed files with 274 additions and 668 deletions.
18 changes: 1 addition & 17 deletions backend/capellacollab/feedback/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,9 @@
import fastapi
from sqlalchemy import orm

from capellacollab.config import config
from capellacollab.core import database
from capellacollab.core import logging as log
from capellacollab.core.authentication import injectables as auth_injectables
from capellacollab.settings.configuration import core as config_core
from capellacollab.settings.configuration import models as config_models
from capellacollab.users import injectables as user_injectables
from capellacollab.users import models as users_models

Expand All @@ -23,21 +20,8 @@
router = fastapi.APIRouter()


@router.get(
"/configurations/feedback",
response_model=config_models.FeedbackConfiguration,
)
def get_feedback_configuration(
db: orm.Session = fastapi.Depends(database.get_db),
):
feedback = config_core.get_global_configuration(db).feedback
if not (config.smtp and config.smtp.enabled):
util.disable_feedback(feedback)
return feedback


@router.post(
"/feedback",
"",
status_code=204,
dependencies=[
fastapi.Depends(
Expand Down
45 changes: 0 additions & 45 deletions backend/capellacollab/metadata/routes.py

This file was deleted.

23 changes: 0 additions & 23 deletions backend/capellacollab/navbar/routes.py

This file was deleted.

8 changes: 3 additions & 5 deletions backend/capellacollab/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
from capellacollab.events import routes as events_router
from capellacollab.feedback import routes as feedback_routes
from capellacollab.health import routes as health_routes
from capellacollab.metadata import routes as core_metadata
from capellacollab.navbar import routes as navbar_routes
from capellacollab.notices import routes as notices_routes
from capellacollab.projects import routes as projects_routes
from capellacollab.sessions import routes as sessions_routes
Expand All @@ -30,9 +28,9 @@
responses=auth_responses.api_exceptions(include_authentication=True),
tags=["Health"],
)
router.include_router(core_metadata.router, tags=["Metadata"])
router.include_router(navbar_routes.router, tags=["Navbar"])
router.include_router(feedback_routes.router, tags=["Feedback"])
router.include_router(
feedback_routes.router, prefix="/feedback", tags=["Feedback"]
)
router.include_router(
sessions_routes.router,
prefix="/sessions",
Expand Down
20 changes: 20 additions & 0 deletions backend/capellacollab/settings/configuration/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,3 +244,23 @@ class GlobalConfiguration(ConfigurationBase):
NAME_TO_MODEL_TYPE_MAPPING: dict[str, t.Type[ConfigurationBase]] = {
model()._name: model for model in ConfigurationBase.__subclasses__()
}


class Metadata(core_pydantic.BaseModel):
version: str
privacy_policy_url: str | None
imprint_url: str | None
provider: str | None
authentication_provider: str | None
environment: str | None

host: str | None
port: str | None
protocol: str | None


class UnifiedConfig(core_pydantic.BaseModel):
metadata: Metadata
feedback: FeedbackConfiguration
navbar: NavbarConfiguration
beta: BetaConfiguration
39 changes: 31 additions & 8 deletions backend/capellacollab/settings/configuration/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,41 @@
from capellacollab.users import crud as users_crud
from capellacollab.users import models as users_models

from . import core, crud, models
from . import core, crud, models, util

router = fastapi.APIRouter(
dependencies=[
fastapi.Depends(
auth_injectables.RoleVerification(
required_role=users_models.Role.ADMIN
)
)
],
tags=["Configuration"],
)

schema_router = fastapi.APIRouter(dependencies=[], tags=["Configuration"])


@router.get(
"/unified",
)
def get_unified_config(
db: orm.Session = fastapi.Depends(database.get_db),
) -> models.UnifiedConfig:
cfg = core.get_global_configuration(db)

return models.UnifiedConfig(
metadata=util.get_metadata(cfg),
feedback=util.get_feedback(cfg),
beta=cfg.beta,
navbar=cfg.navbar,
)


@router.get(
f"/{models.GlobalConfiguration._name}",
response_model=models.GlobalConfiguration,
dependencies=[
fastapi.Depends(
auth_injectables.RoleVerification(
required_role=users_models.Role.ADMIN
)
)
],
)
async def get_configuration(
db: orm.Session = fastapi.Depends(database.get_db),
Expand All @@ -41,6 +57,13 @@ async def get_configuration(
@router.put(
f"/{models.GlobalConfiguration._name}",
response_model=models.GlobalConfiguration,
dependencies=[
fastapi.Depends(
auth_injectables.RoleVerification(
required_role=users_models.Role.ADMIN
)
)
],
)
async def update_configuration(
body: models.GlobalConfiguration,
Expand Down
34 changes: 34 additions & 0 deletions backend/capellacollab/settings/configuration/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# SPDX-FileCopyrightText: Copyright DB InfraGO AG and contributors
# SPDX-License-Identifier: Apache-2.0

import capellacollab
from capellacollab.config import config
from capellacollab.settings.configuration import models


def get_metadata(
global_config: models.GlobalConfiguration,
) -> models.Metadata:
return models.Metadata.model_validate(
global_config.metadata.model_dump()
| {
"version": capellacollab.__version__,
"host": config.general.host,
"port": str(config.general.port),
"protocol": config.general.scheme,
}
)


def get_feedback(
global_config: models.GlobalConfiguration,
) -> models.FeedbackConfiguration:
feedback = global_config.feedback
if not (config.smtp and config.smtp.enabled):
feedback.enabled = False
feedback.after_session = False
feedback.on_footer = False
feedback.on_session_card = False
feedback.interval.enabled = False

return feedback
13 changes: 0 additions & 13 deletions backend/capellacollab/users/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from capellacollab.projects.users import crud as projects_users_crud
from capellacollab.sessions import routes as session_routes
from capellacollab.settings.configuration import core as config_core
from capellacollab.settings.configuration import models as config_models
from capellacollab.users import injectables as users_injectables
from capellacollab.users import models as users_models
from capellacollab.users.tokens import routes as tokens_routes
Expand All @@ -41,18 +40,6 @@ def get_current_user(
return user


@router.get(
"/beta",
response_model=config_models.BetaConfiguration,
)
def get_beta_config(db: orm.Session = fastapi.Depends(database.get_db)):
cfg = config_core.get_global_configuration(db)

return config_models.BetaConfiguration.model_validate(
cfg.beta.model_dump()
)


@router.get(
"/{user_id}",
response_model=models.User,
Expand Down
8 changes: 4 additions & 4 deletions backend/tests/settings/test_global_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,9 @@ def test_metadata_is_updated(

assert response.status_code == 200

response = client.get("/api/v1/metadata")
response = client.get("/api/v1/settings/configurations/unified")
assert response.status_code == 200
assert response.json()["environment"] == "test"
assert response.json()["metadata"]["environment"] == "test"


@pytest.mark.usefixtures("admin")
Expand All @@ -154,9 +154,9 @@ def test_navbar_is_updated(

assert response.status_code == 200

response = client.get("/api/v1/navbar")
response = client.get("/api/v1/settings/configurations/unified")
assert response.status_code == 200
assert response.json()["external_links"][0] == {
assert response.json()["navbar"]["external_links"][0] == {
"name": "Example",
"href": "https://example.com",
"role": "user",
Expand Down
8 changes: 4 additions & 4 deletions backend/tests/test_feedback.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,9 @@ def test_feedback_is_updated(

assert response.status_code == 200

response = client.get("/api/v1/configurations/feedback")
response = client.get("/api/v1/settings/configurations/unified")
assert response.status_code == 200
assert response.json() == {
assert response.json()["feedback"] == {
"enabled": True,
"after_session": True,
"on_footer": True,
Expand Down Expand Up @@ -262,9 +262,9 @@ def test_activate_feedback_without_recipients(

@pytest.mark.usefixtures("user", "smtp_config_not_set", "feedback_enabled")
def test_feedback_is_disabled_without_smtp(client: testclient.TestClient):
response = client.get("/api/v1/configurations/feedback")
response = client.get("/api/v1/settings/configurations/unified")
assert response.status_code == 200
assert response.json()["enabled"] is False
assert response.json()["feedback"]["enabled"] is False


def test_feedback_metric(db: orm.Session):
Expand Down
24 changes: 7 additions & 17 deletions frontend/src/app/general/metadata/metadata.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,8 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { BehaviorSubject, Observable, tap } from 'rxjs';
import {
Metadata,
MetadataService as OpenAPIMetadataService,
} from 'src/app/openapi';
import { map } from 'rxjs';
import { UnifiedConfigWrapperService } from '../../services/unified-config-wrapper/unified-config-wrapper.service';

@Injectable({
providedIn: 'root',
Expand All @@ -18,19 +15,18 @@ export class MetadataService {
constructor(
private httpClient: HttpClient,
public dialog: MatDialog,
private metadataService: OpenAPIMetadataService,
private unifiedConfigWrapperService: UnifiedConfigWrapperService,
) {
this.loadVersion();
this.loadBackendMetadata().subscribe();
}

public version: Version | undefined;
public oldVersion: string | undefined;

private _backendMetadata = new BehaviorSubject<Metadata | undefined>(
undefined,
);
readonly backendMetadata = this._backendMetadata.asObservable();
readonly backendMetadata =
this.unifiedConfigWrapperService.unifiedConfig$.pipe(
map((unifiedConfig) => unifiedConfig?.metadata),
);

loadVersion(): void {
if (!this.version) {
Expand All @@ -42,12 +38,6 @@ export class MetadataService {
}
}

loadBackendMetadata(): Observable<Metadata> {
return this.metadataService
.getMetadata()
.pipe(tap((metadata: Metadata) => this._backendMetadata.next(metadata)));
}

get changedVersion(): boolean {
const currentVersion = localStorage.getItem('version');

Expand Down
Loading

0 comments on commit 4b70bc8

Please sign in to comment.