users migrace má nové sloupce gitea_user_id, gitea_sync_status, gitea_sync_error, gitea_synced_at.
Přidal jsem gitea_provisioning.py, který přes Gitea API vytváří, aktivuje, deaktivuje a synchronizuje účty.
Role viewer Gitea účet nemá; developer a admin účet mají.
Změny role a enable/disable v administraci spouští sync do Gitea.
Admin UI v routes/users.py zobrazuje stav Gitea synchronizace a má ruční Sync Gitea.
Google login po přihlášení dorovnává Gitea stav podle portálového uživatele.
Gitea OAuth login je v portálu vypnutý; endpointy zůstaly, ale vrací hlášku, že se má použít Google.
Lokální login se zobrazuje/povolí jen při explicitním AUTH_MODE=local.
Gitea API token se čte z GITEA_ADMIN_TOKEN, případně fallback GITEA_API_TOKEN nebo GITEA_TOKEN. Podřízené Gitea username je deterministicky portal-{user_id}, portálová tabulka zůstává zdroj pravdy.
Ověření: python -m py_compile prošel pro všechny upravené Python soubory.
This commit is contained in:
JiriUhlir
2026-06-10 09:34:56 +02:00
parent 38edf07ff3
commit b1263edac6
7 changed files with 334 additions and 24 deletions
+10 -14
View File
@@ -9,7 +9,7 @@ from urllib.request import urlopen
from fastapi import APIRouter, Form, Request
from fastapi.responses import HTMLResponse, RedirectResponse
from app.auth import authenticate_user, current_user, find_or_create_google_user, find_or_create_oauth_user, mark_last_login
from app.auth import authenticate_user, current_user, find_or_create_google_user, mark_last_login
from app.config import (
get_auth_mode,
get_gitea_public_url,
@@ -21,6 +21,7 @@ from app.config import (
read_env_value,
)
from app.db.audit import log_audit_event
from app.gitea_provisioning import sync_gitea_user
from app.templates.layout import page
router = APIRouter()
@@ -39,7 +40,7 @@ def login_form(request: Request):
@router.post("/login", response_class=HTMLResponse)
def login(request: Request, username: str = Form(...), password: str = Form(...)):
if get_auth_mode() == "google":
if get_auth_mode() != "local":
return _render_login("Local login is disabled. Use Google sign in.")
user = authenticate_user(username, password)
@@ -64,8 +65,7 @@ def login(request: Request, username: str = Form(...), password: str = Form(...)
def gitea_login(request: Request):
if current_user(request):
return RedirectResponse(url="/portal/operations", status_code=303)
if get_auth_mode() != "mixed":
return _render_login("Gitea login is not enabled in this auth mode.")
return _render_login("Gitea login is disabled. Use Google sign in.")
gitea_url = get_gitea_public_url()
client_id = read_env_value("GITEA_OAUTH_CLIENT_ID", "")
@@ -98,8 +98,7 @@ def gitea_login(request: Request):
@router.get("/auth/gitea/callback", response_class=HTMLResponse)
def gitea_callback(request: Request, code: str = "", state: str = "", error: str = ""):
if get_auth_mode() != "mixed":
return _render_login("Gitea login is not enabled in this auth mode.")
return _render_login("Gitea login is disabled. Use Google sign in.")
expected_state = request.session.pop("gitea_oauth_state", None)
if error:
@@ -228,6 +227,8 @@ def google_callback(request: Request, code: str = "", state: str = "", error: st
_log_google_failure("disabled_user", username=username)
return _render_login("Uživatel je v portálu vypnutý.")
sync_result = sync_gitea_user(user)
request.session.clear()
request.session["user_id"] = user["id"]
mark_last_login(int(user["id"]))
@@ -242,6 +243,7 @@ def google_callback(request: Request, code: str = "", state: str = "", error: st
"email": user.get("email"),
"role": user.get("role"),
"provider": "google",
"gitea_sync_status": sync_result.get("status"),
},
)
log_audit_event(
@@ -249,7 +251,7 @@ def google_callback(request: Request, code: str = "", state: str = "", error: st
action="auth.google.login.success",
target_type="user",
target_id=user.get("id"),
metadata={"username": user.get("username"), "provider": "google"},
metadata={"username": user.get("username"), "provider": "google", "gitea_sync_status": sync_result.get("status")},
)
return RedirectResponse(url="/portal", status_code=303)
except Exception:
@@ -397,12 +399,6 @@ def _render_login(error: str | None = None) -> str:
error_html = f'<p class="alert alert-danger">{html.escape(error)}</p>'
auth_mode = get_auth_mode()
gitea_login_html = ""
if auth_mode == "mixed" and is_gitea_oauth_button_enabled():
gitea_login_html = """
<p>
<a class="btn btn-secondary" href="/portal/auth/gitea/login">Sign in with Gitea</a>
</p>
"""
google_login_html = ""
if auth_mode in {"google", "mixed"} and is_google_oauth_button_enabled():
google_login_html = """
@@ -414,7 +410,7 @@ def _render_login(error: str | None = None) -> str:
google_login_html = '<p class="alert alert-danger">Google login is not fully configured.</p>'
local_login_html = ""
if auth_mode in {"mixed", "local"}:
if auth_mode == "local":
local_login_html = """
<form method="post" action="/portal/login">
<h3>Local login</h3>