feat: DSH编排基建首版(server/tests 88用例/P2插件/8020端口/PORT-NOTE/MOBILE_APP)
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
"""Identity: who am I, and admin-driven member onboarding."""
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ..auth import Ctx, issue_token
|
||||
from ..db import record_audit
|
||||
from ..deps import get_ctx
|
||||
from ..util import USERNAME_RE, now_iso
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
class UserCreate(BaseModel):
|
||||
username: str
|
||||
role: str = "member"
|
||||
|
||||
|
||||
@router.post("/v1/users")
|
||||
def create_user(body: UserCreate, request: Request, ctx: Ctx = Depends(get_ctx)):
|
||||
"""Admin onboards a member directly, bypassing the invite code."""
|
||||
admin = ctx.require_admin(request)
|
||||
if body.role not in ("admin", "member"):
|
||||
raise HTTPException(400, "role must be 'admin' or 'member'")
|
||||
if not USERNAME_RE.match(body.username or ""):
|
||||
raise HTTPException(400, "invalid username")
|
||||
if ctx.conn.execute(
|
||||
"SELECT 1 FROM users WHERE username = %s", (body.username,)
|
||||
).fetchone():
|
||||
raise HTTPException(409, "username already exists")
|
||||
cur = ctx.conn.execute(
|
||||
"INSERT INTO users (username, role, created_at) VALUES (%s, %s, %s) RETURNING id",
|
||||
(body.username, body.role, now_iso()),
|
||||
)
|
||||
user_id = cur.fetchone()["id"]
|
||||
raw = issue_token(ctx.conn, user_id, "initial")
|
||||
record_audit(ctx.conn, admin["id"], "user.create", {"username": body.username, "role": body.role})
|
||||
return {
|
||||
"token": raw,
|
||||
"user": {"id": user_id, "username": body.username, "role": body.role},
|
||||
}
|
||||
|
||||
|
||||
@router.get("/v1/me")
|
||||
def me(request: Request, ctx: Ctx = Depends(get_ctx)):
|
||||
return ctx.require_user(request)
|
||||
Reference in New Issue
Block a user