Develop #16
@@ -445,6 +445,45 @@ Base 前缀 `/api/v1/admin`。
|
||||
|
||||
---
|
||||
|
||||
### 6.1 `POST /api/v1/admin/employees`
|
||||
|
||||
创建员工账号。
|
||||
|
||||
- **请求体字段**:
|
||||
|
||||
| 字段 | 类型 | 必填 | 限制 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| `username` | string | 是 | 2~64 字符 | 登录名,workspace 内唯一 |
|
||||
| `display_name` | string | 是 | 1~100 字符 | 显示名称 |
|
||||
| `email` | string | 否 | ≤255 字符 | 邮箱,全局唯一 |
|
||||
| `role_code` | string | 否 | `admin` \| `developer` | 默认 `developer` |
|
||||
| `password` | string | 是 | 8~72 字符 | 登录密码 |
|
||||
|
||||
- **密码说明**:
|
||||
- 密码明文**不会**存入数据库,后端使用 bcrypt 哈希后保存到 `password_hash`。
|
||||
- 请求体中 `password` 必填,长度必须在 8~72 字符之间,否则返回 `422`。
|
||||
- 创建成功后的响应**不**包含 `password` 或 `password_hash`。
|
||||
|
||||
- **响应 201**:
|
||||
```json
|
||||
{
|
||||
"request_id": "...",
|
||||
"data": {
|
||||
"user_id": "...",
|
||||
"username": "...",
|
||||
"display_name": "...",
|
||||
"email": "...",
|
||||
"status": "active",
|
||||
"role_code": "developer",
|
||||
"role_name": "...",
|
||||
"created_at": "..."
|
||||
},
|
||||
"meta": {}
|
||||
}
|
||||
```
|
||||
|
||||
> `PATCH` / `DELETE` 员工接口**不**涉及密码字段,也不返回密码相关信息。
|
||||
|
||||
## 七、Jupyter 路由
|
||||
|
||||
> **本节是 Nginx 行为,不是直接 HTTP 端点**。前端**不要**直接调用。
|
||||
|
||||
@@ -9,6 +9,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from common.db.models import Roles, Users, WorkspaceMembers
|
||||
from common.ids import new_ulid
|
||||
from common.auth.passwords import hash_password
|
||||
from backend.dependencies import (
|
||||
RequestContext,
|
||||
database_session,
|
||||
@@ -26,6 +27,7 @@ class EmployeeCreate(BaseModel):
|
||||
display_name: str = Field(min_length=1, max_length=100)
|
||||
email: str | None = Field(default=None, max_length=255)
|
||||
role_code: Literal["admin", "developer"] = "developer"
|
||||
password: str = Field(min_length=8, max_length=72)
|
||||
|
||||
|
||||
class EmployeeUpdate(BaseModel):
|
||||
@@ -133,7 +135,7 @@ async def create_employee(
|
||||
username=username,
|
||||
display_name=display_name,
|
||||
email=payload.email.strip() if payload.email else None,
|
||||
password_hash="demo-login-disabled",
|
||||
password_hash=hash_password(payload.password),
|
||||
status="active",
|
||||
)
|
||||
session.add(user)
|
||||
|
||||
Reference in New Issue
Block a user