gitea user and pswd, some pages removed, logs
This commit is contained in:
+96
-3
@@ -1,4 +1,5 @@
|
||||
import html
|
||||
import re
|
||||
from urllib.parse import quote
|
||||
|
||||
from fastapi import APIRouter, Depends, Form, HTTPException, Request
|
||||
@@ -6,12 +7,25 @@ from fastapi.responses import HTMLResponse, RedirectResponse
|
||||
|
||||
from app.auth import require_user
|
||||
from app.db.audit import log_audit_event
|
||||
from app.db.users import ROLES, count_enabled_admins, delete_user, get_user, list_users, set_user_enabled, update_user_role
|
||||
from app.gitea_provisioning import sync_gitea_user
|
||||
from app.db.users import (
|
||||
ROLES,
|
||||
count_enabled_admins,
|
||||
delete_user,
|
||||
get_user,
|
||||
list_users,
|
||||
set_gitea_username,
|
||||
set_user_enabled,
|
||||
update_user_role,
|
||||
)
|
||||
from app.gitea_provisioning import apply_gitea_credentials, sync_gitea_user
|
||||
from app.templates.layout import page
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
# Gitea handle: začíná alfanumerickým znakem, dál povolen . _ -; max 40 znaků.
|
||||
GITEA_USERNAME_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]{0,39}$")
|
||||
MIN_GITEA_PASSWORD_LEN = 8
|
||||
|
||||
|
||||
def require_admin(user: dict) -> None:
|
||||
if (user.get("role") or "").lower() != "admin":
|
||||
@@ -100,11 +114,30 @@ def users_page(request: Request, message: str = "", error: str = "", user=Depend
|
||||
gitea_sync_status = managed_user.get("gitea_sync_status", "not_required") or "not_required"
|
||||
gitea_sync_error = html.escape(managed_user.get("gitea_sync_error", "") or "")
|
||||
gitea_synced_at = html.escape(managed_user.get("gitea_synced_at", "") or "")
|
||||
gitea_username_value = (managed_user.get("gitea_username") or "").strip()
|
||||
current_gitea_username = gitea_username_value or (f"portal-{user_id}" if gitea_user_id else "")
|
||||
gitea_details = f"ID {html.escape(str(gitea_user_id))}" if gitea_user_id else "No account"
|
||||
if current_gitea_username:
|
||||
gitea_details += f"<br><small>@{html.escape(current_gitea_username)}</small>"
|
||||
if gitea_synced_at:
|
||||
gitea_details += f"<br><small>{gitea_synced_at}</small>"
|
||||
if gitea_sync_error:
|
||||
gitea_details += f'<br><small class="text-danger">{gitea_sync_error}</small>'
|
||||
gitea_cred_form = f"""
|
||||
<details class="gitea-cred">
|
||||
<summary>Změnit jméno/heslo</summary>
|
||||
<form method="post" action="/portal/admin/users/{user_id_html}/gitea-credentials" class="metadata-form"
|
||||
onsubmit="return confirm('Změnit Gitea přihlašovací údaje uživatele {username}?');">
|
||||
<label>Gitea jméno</label>
|
||||
<input name="gitea_username" value="{html.escape(current_gitea_username, quote=True)}" placeholder="portal-{user_id_html}" autocomplete="off">
|
||||
<label>Nové heslo</label>
|
||||
<input type="password" name="gitea_password" placeholder="prázdné = beze změny" autocomplete="new-password">
|
||||
<div class="form-actions">
|
||||
<button type="submit"><i class="fa-solid fa-key" aria-hidden="true"></i> Uložit</button>
|
||||
</div>
|
||||
</form>
|
||||
</details>
|
||||
"""
|
||||
toggle_label = "Disable" if enabled else "Enable"
|
||||
toggle_action = "disable" if enabled else "enable"
|
||||
|
||||
@@ -123,7 +156,7 @@ def users_page(request: Request, message: str = "", error: str = "", user=Depend
|
||||
</form>
|
||||
</td>
|
||||
<td>{render_enabled_pill(enabled)}</td>
|
||||
<td>{render_sync_pill(gitea_sync_status)}<br><small>{gitea_details}</small></td>
|
||||
<td>{render_sync_pill(gitea_sync_status)}<br><small>{gitea_details}</small>{gitea_cred_form}</td>
|
||||
<td>{created_at}</td>
|
||||
<td>{last_login_at}</td>
|
||||
<td class="actions-cell service-actions">
|
||||
@@ -297,6 +330,66 @@ def sync_gitea_user_action(user_id: int, user=Depends(require_user)):
|
||||
return RedirectResponse(url="/portal/admin/users?message=" + quote("Gitea synchronized."), status_code=303)
|
||||
|
||||
|
||||
@router.post("/admin/users/{user_id}/gitea-credentials")
|
||||
def update_gitea_credentials_action(
|
||||
user_id: int,
|
||||
gitea_username: str = Form(""),
|
||||
gitea_password: str = Form(""),
|
||||
user=Depends(require_user),
|
||||
):
|
||||
require_admin(user)
|
||||
target = get_user(user_id)
|
||||
if not target:
|
||||
raise HTTPException(status_code=404, detail="User not found")
|
||||
|
||||
new_username = (gitea_username or "").strip()
|
||||
new_password = gitea_password or ""
|
||||
|
||||
if not new_username and not new_password:
|
||||
return RedirectResponse(
|
||||
url="/portal/admin/users?error=" + quote("Zadejte Gitea jméno nebo nové heslo."),
|
||||
status_code=303,
|
||||
)
|
||||
if new_username and not GITEA_USERNAME_RE.match(new_username):
|
||||
return RedirectResponse(
|
||||
url="/portal/admin/users?error=" + quote("Neplatné Gitea jméno (povoleno A-Z, 0-9, . _ -, max 40 znaků)."),
|
||||
status_code=303,
|
||||
)
|
||||
if new_password and len(new_password) < MIN_GITEA_PASSWORD_LEN:
|
||||
return RedirectResponse(
|
||||
url="/portal/admin/users?error=" + quote(f"Heslo musí mít alespoň {MIN_GITEA_PASSWORD_LEN} znaků."),
|
||||
status_code=303,
|
||||
)
|
||||
|
||||
result = apply_gitea_credentials(target, new_username, new_password)
|
||||
if result.get("status") == "error":
|
||||
return RedirectResponse(
|
||||
url="/portal/admin/users?error=" + quote(f"Gitea: {result.get('error')}"),
|
||||
status_code=303,
|
||||
)
|
||||
|
||||
applied = result.get("applied") or []
|
||||
if "username" in applied:
|
||||
set_gitea_username(user_id, result.get("gitea_username") or new_username)
|
||||
|
||||
log_audit_event(
|
||||
user,
|
||||
action="user.gitea.credentials_updated",
|
||||
target_type="user",
|
||||
target_id=user_id,
|
||||
metadata={
|
||||
"username": target.get("username"),
|
||||
"gitea_username": result.get("gitea_username"),
|
||||
"applied": applied, # heslo se nikdy nezaznamenává
|
||||
},
|
||||
)
|
||||
changed = ", ".join(applied) if applied else "beze změny"
|
||||
return RedirectResponse(
|
||||
url="/portal/admin/users?message=" + quote(f"Gitea přihlašovací údaje aktualizovány ({changed})."),
|
||||
status_code=303,
|
||||
)
|
||||
|
||||
|
||||
@router.post("/admin/users/{user_id}/delete")
|
||||
def delete_user_action(user_id: int, user=Depends(require_user)):
|
||||
require_admin(user)
|
||||
|
||||
Reference in New Issue
Block a user