bifroest/app/data_sources/routes.py
2026-10-27 08:34:17 +01:00

109 lines
6.6 KiB
Python

"""Datenquellen verbinden und testen."""
from typing import Annotated
from fastapi import APIRouter, Form, Request
from fastapi.concurrency import run_in_threadpool
from fastapi.responses import HTMLResponse, Response
from app import web
from app.core.errors import Invalid
from app.data_sources import service as sources
from app.data_sources.connectors.pull_requests import PROVIDERS
from app.workspaces import service as workspaces
def router() -> APIRouter:
r = APIRouter()
@r.get("/workspaces/{workspace_id}/sources/new")
def new(request: Request, principal: web.User, workspace_id: int) -> HTMLResponse:
with web.db(request).session() as session:
workspace = workspaces.require_admin(session, principal, workspace_id).workspace
return web.render(request, "source_new.html", {"workspace": workspace, "current_workspace": workspace,
"form": {}, "allow_local": web.settings(request).git_allow_local,
"providers": PROVIDERS})
@r.post("/workspaces/{workspace_id}/sources")
def create(request: Request, principal: web.Checked, workspace_id: int, name: Annotated[str, Form()],
url: Annotated[str, Form()], branch: Annotated[str, Form()] = "main",
token: Annotated[str, Form()] = "", exposure_confirmed: Annotated[bool, Form()] = False,
pr_provider: Annotated[str, Form()] = "none",
delete_branches: Annotated[str, Form()] = "1", username: Annotated[str, Form()] = "") -> Response:
settings = web.settings(request)
try:
with web.db(request).session() as session:
source = sources.create_git(session, principal, settings, web.vault(request), workspace_id,
name=name, url=url, branch=branch, token=token,
exposure_confirmed=exposure_confirmed, pr_provider=pr_provider,
delete_branches=delete_branches == "1", username=username)
except Invalid as e:
with web.db(request).session() as session:
workspace = workspaces.require_admin(session, principal, workspace_id).workspace
# Das Token wird nicht zurück ins Formular geschrieben
form = {"name": name, "url": url, "branch": branch, "exposure_confirmed": exposure_confirmed,
"pr_provider": pr_provider, "delete_branches": delete_branches == "1", "username": username}
return web.render(request, "source_new.html", {"workspace": workspace, "current_workspace": workspace,
"form": form, "error": str(e),
"allow_local": settings.git_allow_local,
"providers": PROVIDERS}, 400)
# Gleich testen, damit der Chat ohne zusätzlichen Klick verfügbar wird
test(request, principal, source.id)
return web.redirect(f"/workspaces/{workspace_id}/data")
@r.post("/sources/{source_id}/test")
async def test_route(request: Request, principal: web.Checked, source_id: int) -> HTMLResponse:
source, membership = await run_in_threadpool(test, request, principal, source_id)
return web.render(request, "_source_row.html", {"s": source, "membership": membership})
@r.get("/sources/{source_id}/edit")
def edit(request: Request, principal: web.User, source_id: int, error: str = "",
status: int = 200) -> HTMLResponse:
with web.db(request).session() as session:
source = sources.require_testable(session, principal, source_id)
workspace = workspaces.get(session, principal, source.workspace_id).workspace
return web.render(request, "source_edit.html", {"source": source, "workspace": workspace, "error": error,
"current_workspace": workspace, "providers": PROVIDERS},
status)
@r.post("/sources/{source_id}")
def update(request: Request, principal: web.Checked, source_id: int, name: Annotated[str, Form()],
branch: Annotated[str, Form()] = "main", token: Annotated[str, Form()] = "",
remove_token: Annotated[bool, Form()] = False, pr_provider: Annotated[str, Form()] = "none",
delete_branches: Annotated[str, Form()] = "1", username: Annotated[str, Form()] = "") -> Response:
try:
with web.db(request).session() as session:
source = sources.update_git(session, principal, web.settings(request), web.vault(request),
source_id, name=name, branch=branch, token=token,
remove_token=remove_token, pr_provider=pr_provider,
delete_branches=delete_branches == "1", username=username)
except Invalid as e:
with web.db(request).session() as session:
source = sources.require_testable(session, principal, source_id)
workspace = workspaces.get(session, principal, source.workspace_id).workspace
return web.render(request, "source_edit.html", {"source": source, "workspace": workspace,
"current_workspace": workspace, "error": str(e),
"providers": PROVIDERS}, 400)
test(request, principal, source.id)
return web.redirect(f"/workspaces/{source.workspace_id}/data")
@r.post("/sources/{source_id}/delete")
def delete(request: Request, principal: web.Checked, source_id: int) -> Response:
with web.db(request).session() as session:
workspace_id = sources.delete(session, principal, source_id)
return web.redirect(f"/workspaces/{workspace_id}/data")
return r
def test(request: Request, principal, source_id: int):
"""Test außerhalb einer Transaktion ausführen, Ergebnis danach speichern."""
db, settings = web.db(request), web.settings(request)
with db.session() as session:
source = sources.require_testable(session, principal, source_id)
result = sources.run_test(source, settings, web.vault(request))
with db.session() as session:
sources.save_test(session, principal, source_id, result)
source = sources.get(session, principal, source_id)
membership = workspaces.get(session, principal, source.workspace_id)
return source, membership