diff --git a/app/routers/api.py b/app/routers/api.py index 5ae7184..a411515 100644 --- a/app/routers/api.py +++ b/app/routers/api.py @@ -13,6 +13,7 @@ from app.config import settings from app.db import get_conn from app.routers.board import _issue_column, _map_issue_to_card, STATUS_COLORS, STATUS_LABELS from app.services.gitea_client import gitea +from app.auth.session import SessionManager logger = logging.getLogger(__name__) router = APIRouter(tags=["api"], prefix="/api") @@ -538,6 +539,40 @@ async def delete_checklist(checklist_id: int): return {"status": "ok"} +# ── v1.0.0: User management ── + +@router.get("/users/me") +async def get_my_profile(request: Request): + """Get current user profile.""" + user = SessionManager.decode_session(request.cookies.get("flowdeck_session", "")) + if not user: + return {"login": "guest", "full_name": "Guest", "email": ""} + with get_conn() as conn: + row = conn.execute( + "SELECT * FROM users WHERE login=?", (user.get("login", ""),) + ).fetchone() + if row: + return dict(row) + return {"login": user.get("login", ""), "full_name": "", "email": ""} + + +@router.put("/users/me") +async def update_my_profile(request: Request, full_name: str = Query(default=""), + email: str = Query(default="")): + """Update current user's local profile.""" + user = SessionManager.decode_session(request.cookies.get("flowdeck_session", "")) + if not user: + raise HTTPException(401, "Not authenticated") + login = user.get("login", "") + with get_conn() as conn: + conn.execute( + "UPDATE users SET full_name=?, email=? WHERE login=?", + (full_name, email, login), + ) + conn.commit() + return {"status": "ok"} + + # ── v0.5.0: Card priority & due date ── @router.post("/card/{owner}/{repo}/{issue_id}") diff --git a/app/routers/dashboard.py b/app/routers/dashboard.py index 10f45f5..cb6b296 100644 --- a/app/routers/dashboard.py +++ b/app/routers/dashboard.py @@ -82,6 +82,20 @@ async def view_page_root(request: Request, page_id: int): return template.render(**ctx) +@router.get("/accounts", response_class=HTMLResponse) +async def accounts_page(request: Request): + """Account management panel.""" + from jinja2 import Environment, FileSystemLoader + env = Environment(loader=FileSystemLoader("app/templates")) + sidebar = _sidebar_data(request, []) + user = SessionManager.decode_session(request.cookies.get("flowdeck_session", "")) + with get_conn() as conn: + users = conn.execute("SELECT * FROM users ORDER BY created_at DESC").fetchall() + ctx = {**sidebar, "user": user, "users": [dict(u) for u in users]} + template = env.get_template("accounts.html") + return template.render(**ctx) + + @router.get("/", response_class=HTMLResponse) async def dashboard( request: Request, diff --git a/app/templates/accounts.html b/app/templates/accounts.html new file mode 100644 index 0000000..b76fd1b --- /dev/null +++ b/app/templates/accounts.html @@ -0,0 +1,131 @@ +{% extends "base.html" %} +{% block page_icon %}👤{% endblock %} +{% block page_title %}Accounts{% endblock %} + +{% block content %} +
| User | +Joined | +Role | +|
|---|---|---|---|
|
+
+
+ {{ u.login[0] }}
+ {{ u.login }}
+ |
+ {{ u.email or '—' }} | +{{ u.created_at[:10] if u.created_at else '—' }} | +{% if u.is_admin %}Admin{% else %}Member{% endif %} | +
| No members yet | |||