- Make app/domains/auth/ and app/core/redis.py mypy-clean under strict. - Add mypy-gate.ini and Makefile mypy-gate target; promote typecheck-gate in CI. - Consolidate domains into app/domains/: bulletin, admin, intelligence, markets. - Extract referral domain incl. DeFi partner DEX ref links; keep Telegram bot wired. - Move app/mcp/ package and app/api/v1/mcp/router into app/domains/mcp/. - Archive dead app/mcp_router.py.
70 lines
1.9 KiB
Python
70 lines
1.9 KiB
Python
"""User storage helpers.
|
|
|
|
Phase 3B of AUDIT-2026-Q3.md.
|
|
|
|
Public API:
|
|
- _get_user, _get_user_by_email, _save_user, _delete_user
|
|
- _is_valid_email
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import re
|
|
from typing import Any, cast
|
|
|
|
from app.core.redis import get_redis
|
|
|
|
|
|
def _get_user(user_id: str) -> dict[str, Any] | None:
|
|
"""Fetch user record by id from Redis hash rmi:users."""
|
|
r = get_redis()
|
|
if not r:
|
|
return None
|
|
raw = r.hget("rmi:users", user_id)
|
|
if not raw:
|
|
return None
|
|
try:
|
|
return cast("dict[str, Any]", json.loads(raw))
|
|
except (json.JSONDecodeError, TypeError):
|
|
return None
|
|
|
|
|
|
def _get_user_by_email(email: str) -> dict[str, Any] | None:
|
|
"""Fetch user record by email via rmi:users:email index -> rmi:users hash."""
|
|
r = get_redis()
|
|
if not r:
|
|
return None
|
|
user_id = r.hget("rmi:users:email", email.lower())
|
|
if not user_id:
|
|
return None
|
|
if isinstance(user_id, bytes):
|
|
user_id = user_id.decode("utf-8")
|
|
return _get_user(user_id)
|
|
|
|
|
|
def _save_user(user: dict[str, Any]) -> None:
|
|
"""Persist user record to Redis hash rmi:users, refresh email index if present."""
|
|
r = get_redis()
|
|
if not r:
|
|
return
|
|
user_id = user["id"]
|
|
r.hset("rmi:users", user_id, json.dumps(user))
|
|
if user.get("email"):
|
|
r.hset("rmi:users:email", user["email"].lower(), user_id)
|
|
|
|
|
|
def _delete_user(user_id: str) -> None:
|
|
"""Remove user record from Redis hash rmi:users and email index."""
|
|
r = get_redis()
|
|
if not r:
|
|
return
|
|
user = _get_user(user_id)
|
|
if user and user.get("email"):
|
|
r.hdel("rmi:users:email", user["email"].lower())
|
|
r.hdel("rmi:users", user_id)
|
|
|
|
|
|
def _is_valid_email(email: str) -> bool:
|
|
"""Basic email validation."""
|
|
pattern = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
|
|
return re.match(pattern, email) is not None
|