first commit
This commit is contained in:
1
backend/app/api/admin/__init__.py
Normal file
1
backend/app/api/admin/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""Admin API routers."""
|
||||
BIN
backend/app/api/admin/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
backend/app/api/admin/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
BIN
backend/app/api/admin/__pycache__/experiments.cpython-312.pyc
Normal file
BIN
backend/app/api/admin/__pycache__/experiments.cpython-312.pyc
Normal file
Binary file not shown.
BIN
backend/app/api/admin/__pycache__/goals.cpython-312.pyc
Normal file
BIN
backend/app/api/admin/__pycache__/goals.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
backend/app/api/admin/__pycache__/releases.cpython-312.pyc
Normal file
BIN
backend/app/api/admin/__pycache__/releases.cpython-312.pyc
Normal file
Binary file not shown.
BIN
backend/app/api/admin/__pycache__/router.cpython-312.pyc
Normal file
BIN
backend/app/api/admin/__pycache__/router.cpython-312.pyc
Normal file
Binary file not shown.
BIN
backend/app/api/admin/__pycache__/sdk_configs.cpython-312.pyc
Normal file
BIN
backend/app/api/admin/__pycache__/sdk_configs.cpython-312.pyc
Normal file
Binary file not shown.
BIN
backend/app/api/admin/__pycache__/sites.cpython-312.pyc
Normal file
BIN
backend/app/api/admin/__pycache__/sites.cpython-312.pyc
Normal file
Binary file not shown.
BIN
backend/app/api/admin/__pycache__/variants.cpython-312.pyc
Normal file
BIN
backend/app/api/admin/__pycache__/variants.cpython-312.pyc
Normal file
Binary file not shown.
76
backend/app/api/admin/experiments.py
Normal file
76
backend/app/api/admin/experiments.py
Normal file
@@ -0,0 +1,76 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
|
||||
from app.api.dependencies.auth import get_access_token
|
||||
from app.api.dependencies.permissions import require_permission
|
||||
from app.application.admin.activity import ActivityService
|
||||
from app.application.admin.experiments import ExperimentService
|
||||
from app.schemas.auth import AuthenticatedUser
|
||||
from app.schemas.admin import ActivityLogListResponse, ExperimentCreate, ExperimentListResponse, ExperimentRead, ExperimentUpdate
|
||||
|
||||
router = APIRouter()
|
||||
service = ExperimentService()
|
||||
activity_service = ActivityService()
|
||||
|
||||
|
||||
@router.get("", response_model=ExperimentListResponse)
|
||||
async def list_experiments(
|
||||
access_token: str = Depends(get_access_token),
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_experiments")),
|
||||
) -> ExperimentListResponse:
|
||||
# Admin list should always come from the application/service layer,
|
||||
# not from routes talking to Directus directly.
|
||||
items = await service.list_experiments(access_token=access_token)
|
||||
return ExperimentListResponse(items=items)
|
||||
|
||||
|
||||
@router.get("/{experiment_id}", response_model=ExperimentRead)
|
||||
async def get_experiment(
|
||||
experiment_id: str,
|
||||
access_token: str = Depends(get_access_token),
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_experiments")),
|
||||
) -> ExperimentRead:
|
||||
item = await service.get_experiment(experiment_id, access_token=access_token)
|
||||
if not item:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Experiment '{experiment_id}' not found.",
|
||||
)
|
||||
return item
|
||||
|
||||
|
||||
@router.post("", response_model=ExperimentRead, status_code=status.HTTP_201_CREATED)
|
||||
async def create_experiment(
|
||||
payload: ExperimentCreate,
|
||||
access_token: str = Depends(get_access_token),
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_experiments")),
|
||||
) -> ExperimentRead:
|
||||
return await service.create_experiment(payload, access_token=access_token)
|
||||
|
||||
|
||||
@router.patch("/{experiment_id}", response_model=ExperimentRead)
|
||||
async def update_experiment(
|
||||
experiment_id: str,
|
||||
payload: ExperimentUpdate,
|
||||
access_token: str = Depends(get_access_token),
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_experiments")),
|
||||
) -> ExperimentRead:
|
||||
item = await service.update_experiment(experiment_id, payload, access_token=access_token)
|
||||
if not item:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Experiment '{experiment_id}' not found.",
|
||||
)
|
||||
return item
|
||||
|
||||
|
||||
@router.get("/{experiment_id}/activity", response_model=ActivityLogListResponse)
|
||||
async def list_experiment_activity(
|
||||
experiment_id: str,
|
||||
access_token: str = Depends(get_access_token),
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_experiments")),
|
||||
) -> ActivityLogListResponse:
|
||||
items = await activity_service.list_for_experiment(
|
||||
experiment_id=experiment_id,
|
||||
access_token=access_token,
|
||||
)
|
||||
return ActivityLogListResponse(items=items)
|
||||
35
backend/app/api/admin/goals.py
Normal file
35
backend/app/api/admin/goals.py
Normal file
@@ -0,0 +1,35 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
|
||||
from app.api.dependencies.auth import get_access_token
|
||||
from app.api.dependencies.permissions import require_permission
|
||||
from app.application.admin.goals import GoalService
|
||||
from app.schemas.auth import AuthenticatedUser
|
||||
from app.schemas.admin import GoalListResponse, GoalRead
|
||||
|
||||
router = APIRouter()
|
||||
service = GoalService()
|
||||
|
||||
|
||||
@router.get("", response_model=GoalListResponse)
|
||||
async def list_goals(
|
||||
site_id: str | None = Query(default=None),
|
||||
access_token: str = Depends(get_access_token),
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_goals")),
|
||||
) -> GoalListResponse:
|
||||
items = await service.list_goals(site_id=site_id, access_token=access_token)
|
||||
return GoalListResponse(items=items)
|
||||
|
||||
|
||||
@router.get("/{goal_id}", response_model=GoalRead)
|
||||
async def get_goal(
|
||||
goal_id: str,
|
||||
access_token: str = Depends(get_access_token),
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_goals")),
|
||||
) -> GoalRead:
|
||||
item = await service.get_goal(goal_id, access_token=access_token)
|
||||
if not item:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Goal '{goal_id}' not found.",
|
||||
)
|
||||
return item
|
||||
32
backend/app/api/admin/marketing_cards.py
Normal file
32
backend/app/api/admin/marketing_cards.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
|
||||
from app.api.dependencies.permissions import require_permission
|
||||
from app.application.admin.marketing_cards import MarketingCardService
|
||||
from app.schemas.auth import AuthenticatedUser
|
||||
from app.schemas.marketing_card import MarketingCardListResponse, MarketingCardRead
|
||||
|
||||
router = APIRouter()
|
||||
service = MarketingCardService()
|
||||
|
||||
|
||||
@router.get("", response_model=MarketingCardListResponse)
|
||||
async def list_marketing_cards(
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_experiments")),
|
||||
) -> MarketingCardListResponse:
|
||||
items = await service.list_marketing_cards()
|
||||
return MarketingCardListResponse(items=items)
|
||||
|
||||
|
||||
@router.get("/{card_id}", response_model=MarketingCardRead)
|
||||
async def get_marketing_card(
|
||||
card_id: str,
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_experiments")),
|
||||
) -> MarketingCardRead:
|
||||
item = await service.get_marketing_card(card_id)
|
||||
if not item:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Marketing card '{card_id}' not found.",
|
||||
)
|
||||
return item
|
||||
|
||||
77
backend/app/api/admin/releases.py
Normal file
77
backend/app/api/admin/releases.py
Normal file
@@ -0,0 +1,77 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
|
||||
from app.api.dependencies.auth import get_access_token
|
||||
from app.api.dependencies.permissions import require_permission
|
||||
from app.application.admin.releases import ReleaseService
|
||||
from app.schemas.auth import AuthenticatedUser
|
||||
from app.schemas.admin import BuildReleaseRequest, ReleaseLifecycleResponse, ReleaseListResponse, ReleaseRead
|
||||
|
||||
router = APIRouter()
|
||||
service = ReleaseService()
|
||||
|
||||
|
||||
@router.get("", response_model=ReleaseListResponse)
|
||||
async def list_releases(
|
||||
experiment_id: str | None = Query(default=None),
|
||||
access_token: str = Depends(get_access_token),
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_releases")),
|
||||
) -> ReleaseListResponse:
|
||||
items = await service.list_releases(experiment_id=experiment_id, access_token=access_token)
|
||||
return ReleaseListResponse(items=items)
|
||||
|
||||
|
||||
@router.get("/{release_id}", response_model=ReleaseRead)
|
||||
async def get_release(
|
||||
release_id: str,
|
||||
access_token: str = Depends(get_access_token),
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_releases")),
|
||||
) -> ReleaseRead:
|
||||
item = await service.get_release(release_id, access_token=access_token)
|
||||
if not item:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Release '{release_id}' not found.")
|
||||
return item
|
||||
|
||||
|
||||
@router.post("/build", response_model=ReleaseRead, status_code=status.HTTP_201_CREATED)
|
||||
async def build_release(
|
||||
payload: BuildReleaseRequest,
|
||||
access_token: str = Depends(get_access_token),
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_releases")),
|
||||
) -> ReleaseRead:
|
||||
return await service.build_release(payload, access_token=access_token)
|
||||
|
||||
|
||||
@router.post("/{release_id}/publish", response_model=ReleaseLifecycleResponse)
|
||||
async def publish_release(
|
||||
release_id: str,
|
||||
access_token: str = Depends(get_access_token),
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_releases")),
|
||||
) -> ReleaseLifecycleResponse:
|
||||
item = await service.publish_release(release_id, access_token=access_token)
|
||||
if not item:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Release '{release_id}' not found.")
|
||||
return item
|
||||
|
||||
|
||||
@router.post("/{release_id}/rollback", response_model=ReleaseLifecycleResponse)
|
||||
async def rollback_release(
|
||||
release_id: str,
|
||||
access_token: str = Depends(get_access_token),
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_releases")),
|
||||
) -> ReleaseLifecycleResponse:
|
||||
item = await service.rollback_release(release_id, access_token=access_token)
|
||||
if not item:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Release '{release_id}' not found.")
|
||||
return item
|
||||
|
||||
|
||||
@router.post("/{release_id}/archive", response_model=ReleaseLifecycleResponse)
|
||||
async def archive_release(
|
||||
release_id: str,
|
||||
access_token: str = Depends(get_access_token),
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_releases")),
|
||||
) -> ReleaseLifecycleResponse:
|
||||
item = await service.archive_release(release_id, access_token=access_token)
|
||||
if not item:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Release '{release_id}' not found.")
|
||||
return item
|
||||
18
backend/app/api/admin/router.py
Normal file
18
backend/app/api/admin/router.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
from app.api.admin import (
|
||||
experiments,
|
||||
goals,
|
||||
releases,
|
||||
sdk_configs,
|
||||
sites,
|
||||
variants,
|
||||
)
|
||||
|
||||
router = APIRouter()
|
||||
router.include_router(sites.router, prefix="/sites")
|
||||
router.include_router(experiments.router, prefix="/experiments")
|
||||
router.include_router(variants.router, prefix="/variants")
|
||||
router.include_router(releases.router, prefix="/releases")
|
||||
router.include_router(goals.router, prefix="/goals")
|
||||
router.include_router(sdk_configs.router, prefix="/sdk-configs")
|
||||
34
backend/app/api/admin/sdk_configs.py
Normal file
34
backend/app/api/admin/sdk_configs.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
|
||||
from app.api.dependencies.auth import get_access_token
|
||||
from app.api.dependencies.permissions import require_permission
|
||||
from app.application.admin.sdk_configs import SdkConfigService
|
||||
from app.schemas.auth import AuthenticatedUser
|
||||
from app.schemas.admin import SdkConfigListResponse, SdkConfigRead
|
||||
|
||||
router = APIRouter()
|
||||
service = SdkConfigService()
|
||||
|
||||
|
||||
@router.get("", response_model=SdkConfigListResponse)
|
||||
async def list_sdk_configs(
|
||||
access_token: str = Depends(get_access_token),
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_sdk_configs")),
|
||||
) -> SdkConfigListResponse:
|
||||
items = await service.list_sdk_configs(access_token=access_token)
|
||||
return SdkConfigListResponse(items=items)
|
||||
|
||||
|
||||
@router.get("/{sdk_config_id}", response_model=SdkConfigRead)
|
||||
async def get_sdk_config(
|
||||
sdk_config_id: str,
|
||||
access_token: str = Depends(get_access_token),
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_sdk_configs")),
|
||||
) -> SdkConfigRead:
|
||||
item = await service.get_sdk_config(sdk_config_id, access_token=access_token)
|
||||
if not item:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"SDK config '{sdk_config_id}' not found.",
|
||||
)
|
||||
return item
|
||||
34
backend/app/api/admin/sites.py
Normal file
34
backend/app/api/admin/sites.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
|
||||
from app.api.dependencies.auth import get_access_token
|
||||
from app.api.dependencies.permissions import require_permission
|
||||
from app.application.admin.sites import SiteService
|
||||
from app.schemas.auth import AuthenticatedUser
|
||||
from app.schemas.admin import SiteListResponse, SiteRead
|
||||
|
||||
router = APIRouter()
|
||||
service = SiteService()
|
||||
|
||||
|
||||
@router.get("", response_model=SiteListResponse)
|
||||
async def list_sites(
|
||||
access_token: str = Depends(get_access_token),
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_sites")),
|
||||
) -> SiteListResponse:
|
||||
items = await service.list_sites(access_token=access_token)
|
||||
return SiteListResponse(items=items)
|
||||
|
||||
|
||||
@router.get("/{site_id}", response_model=SiteRead)
|
||||
async def get_site(
|
||||
site_id: str,
|
||||
access_token: str = Depends(get_access_token),
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_sites")),
|
||||
) -> SiteRead:
|
||||
item = await service.get_site(site_id, access_token=access_token)
|
||||
if not item:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Site '{site_id}' not found.",
|
||||
)
|
||||
return item
|
||||
63
backend/app/api/admin/variants.py
Normal file
63
backend/app/api/admin/variants.py
Normal file
@@ -0,0 +1,63 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
|
||||
from app.api.dependencies.auth import get_access_token
|
||||
from app.api.dependencies.permissions import require_permission
|
||||
from app.application.admin.variants import VariantService
|
||||
from app.schemas.auth import AuthenticatedUser
|
||||
from app.schemas.admin import VariantCreate, VariantListResponse, VariantRead, VariantUpdate
|
||||
|
||||
router = APIRouter()
|
||||
service = VariantService()
|
||||
|
||||
|
||||
@router.get("", response_model=VariantListResponse)
|
||||
async def list_variants(
|
||||
experiment_id: str | None = Query(default=None),
|
||||
access_token: str = Depends(get_access_token),
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_variants")),
|
||||
) -> VariantListResponse:
|
||||
items = await service.list_variants(
|
||||
experiment_id=experiment_id,
|
||||
access_token=access_token,
|
||||
)
|
||||
return VariantListResponse(items=items)
|
||||
|
||||
|
||||
@router.get("/{variant_id}", response_model=VariantRead)
|
||||
async def get_variant(
|
||||
variant_id: str,
|
||||
access_token: str = Depends(get_access_token),
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_variants")),
|
||||
) -> VariantRead:
|
||||
item = await service.get_variant(variant_id, access_token=access_token)
|
||||
if not item:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Variant '{variant_id}' not found.",
|
||||
)
|
||||
return item
|
||||
|
||||
|
||||
@router.post("", response_model=VariantRead, status_code=status.HTTP_201_CREATED)
|
||||
async def create_variant(
|
||||
payload: VariantCreate,
|
||||
access_token: str = Depends(get_access_token),
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_variants")),
|
||||
) -> VariantRead:
|
||||
return await service.create_variant(payload, access_token=access_token)
|
||||
|
||||
|
||||
@router.patch("/{variant_id}", response_model=VariantRead)
|
||||
async def update_variant(
|
||||
variant_id: str,
|
||||
payload: VariantUpdate,
|
||||
access_token: str = Depends(get_access_token),
|
||||
_: AuthenticatedUser = Depends(require_permission("can_manage_variants")),
|
||||
) -> VariantRead:
|
||||
item = await service.update_variant(variant_id, payload, access_token=access_token)
|
||||
if not item:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail=f"Variant '{variant_id}' not found.",
|
||||
)
|
||||
return item
|
||||
Reference in New Issue
Block a user