Version 1.2.2. Added usage overview. Shows token used and cost in $.
This commit is contained in:
@@ -1,5 +1,21 @@
|
||||
"""
|
||||
users.py — User CRUD operations (async, PostgreSQL).
|
||||
|
||||
Design decisions:
|
||||
- User IDs are TEXT (UUID stored as string), NOT the PostgreSQL UUID type.
|
||||
Reason: PostgreSQL UUID type causes FK mismatch errors with asyncpg when columns
|
||||
in other tables store user_id as TEXT. Keeping everything TEXT avoids implicit
|
||||
type casting and makes joins reliable.
|
||||
|
||||
- New users get personality files seeded from the global SOUL.md / USER.md.
|
||||
Admins get the real USER.md verbatim. Non-admins get a blank template so they
|
||||
can fill in their own context without seeing the admin's personal info.
|
||||
|
||||
- User email addresses are automatically added to email_whitelist so the agent
|
||||
can reply to the user without manual whitelist configuration.
|
||||
|
||||
- User folders (provisioned in {users_base_folder}/{username}/) allow non-admin
|
||||
users to have a private filesystem space without configuring the global whitelist.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -137,6 +153,12 @@ async def _sync_email_whitelist(pool, old_email: str | None, new_email: str | No
|
||||
|
||||
|
||||
async def create_user(username: str, password: str, role: str = "user", email: str = "") -> dict:
|
||||
"""
|
||||
Create a new user. Automatically:
|
||||
- Seeds per-user personality from global SOUL.md / USER.md
|
||||
- Adds user's email to email_whitelist (so the agent can reply)
|
||||
- Provisions a user folder if system:users_base_folder is configured
|
||||
"""
|
||||
user_id = str(uuid.uuid4())
|
||||
now = _now()
|
||||
pw_hash = hash_password(password)
|
||||
@@ -222,6 +244,11 @@ async def update_user(user_id: str, **fields) -> bool:
|
||||
|
||||
|
||||
async def delete_user(user_id: str) -> bool:
|
||||
"""
|
||||
Delete a user. Nullifies FK references first to avoid constraint violations.
|
||||
Agents, conversations, and audit entries are preserved (owner set to NULL)
|
||||
rather than cascade-deleted — important for audit trail integrity.
|
||||
"""
|
||||
pool = await get_pool()
|
||||
# Fetch email before delete for whitelist cleanup
|
||||
old_row = await pool.fetchrow("SELECT email FROM users WHERE id = $1", user_id)
|
||||
|
||||
Reference in New Issue
Block a user