Merge branch 'BATON-008-backend_dev'
This commit is contained in:
commit
42f4251184
11 changed files with 651 additions and 4 deletions
|
|
@ -15,12 +15,14 @@ from fastapi.middleware.cors import CORSMiddleware
|
|||
from fastapi.responses import JSONResponse
|
||||
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
||||
|
||||
from backend import config, db, telegram
|
||||
from backend.middleware import rate_limit_register, rate_limit_signal, verify_admin_token, verify_webhook_secret
|
||||
from backend import config, db, push, telegram
|
||||
from backend.middleware import rate_limit_auth_register, rate_limit_register, rate_limit_signal, verify_admin_token, verify_webhook_secret
|
||||
from backend.models import (
|
||||
AdminBlockRequest,
|
||||
AdminCreateUserRequest,
|
||||
AdminSetPasswordRequest,
|
||||
AuthRegisterRequest,
|
||||
AuthRegisterResponse,
|
||||
RegisterRequest,
|
||||
RegisterResponse,
|
||||
SignalRequest,
|
||||
|
|
@ -183,6 +185,84 @@ async def signal(
|
|||
return SignalResponse(status="ok", signal_id=signal_id)
|
||||
|
||||
|
||||
@app.post("/api/auth/register", response_model=AuthRegisterResponse, status_code=201)
|
||||
async def auth_register(
|
||||
body: AuthRegisterRequest,
|
||||
_: None = Depends(rate_limit_auth_register),
|
||||
) -> AuthRegisterResponse:
|
||||
password_hash = _hash_password(body.password)
|
||||
push_sub_json = (
|
||||
body.push_subscription.model_dump_json() if body.push_subscription else None
|
||||
)
|
||||
try:
|
||||
reg_id = await db.create_registration(
|
||||
email=str(body.email),
|
||||
login=body.login,
|
||||
password_hash=password_hash,
|
||||
push_subscription=push_sub_json,
|
||||
)
|
||||
except Exception as exc:
|
||||
# aiosqlite.IntegrityError on email/login UNIQUE conflict
|
||||
if "UNIQUE" in str(exc) or "unique" in str(exc).lower():
|
||||
raise HTTPException(status_code=409, detail="Email или логин уже существует")
|
||||
raise
|
||||
reg = await db.get_registration(reg_id)
|
||||
asyncio.create_task(
|
||||
telegram.send_registration_notification(
|
||||
reg_id=reg_id,
|
||||
login=body.login,
|
||||
email=str(body.email),
|
||||
created_at=reg["created_at"] if reg else "",
|
||||
)
|
||||
)
|
||||
return AuthRegisterResponse(status="pending", message="Заявка отправлена на рассмотрение")
|
||||
|
||||
|
||||
async def _handle_callback_query(cb: dict) -> None:
|
||||
"""Process approve/reject callback from admin Telegram inline buttons."""
|
||||
data = cb.get("data", "")
|
||||
callback_query_id = cb.get("id", "")
|
||||
message = cb.get("message", {})
|
||||
chat_id = message.get("chat", {}).get("id")
|
||||
message_id = message.get("message_id")
|
||||
|
||||
if ":" not in data:
|
||||
return
|
||||
action, reg_id_str = data.split(":", 1)
|
||||
try:
|
||||
reg_id = int(reg_id_str)
|
||||
except ValueError:
|
||||
return
|
||||
|
||||
reg = await db.get_registration(reg_id)
|
||||
if reg is None:
|
||||
await telegram.answer_callback_query(callback_query_id)
|
||||
return
|
||||
|
||||
if action == "approve":
|
||||
await db.update_registration_status(reg_id, "approved")
|
||||
if chat_id and message_id:
|
||||
await telegram.edit_message_text(
|
||||
chat_id, message_id, f"✅ Пользователь {reg['login']} одобрен"
|
||||
)
|
||||
if reg["push_subscription"]:
|
||||
asyncio.create_task(
|
||||
push.send_push(
|
||||
reg["push_subscription"],
|
||||
"Baton",
|
||||
"Ваша регистрация одобрена!",
|
||||
)
|
||||
)
|
||||
elif action == "reject":
|
||||
await db.update_registration_status(reg_id, "rejected")
|
||||
if chat_id and message_id:
|
||||
await telegram.edit_message_text(
|
||||
chat_id, message_id, f"❌ Пользователь {reg['login']} отклонён"
|
||||
)
|
||||
|
||||
await telegram.answer_callback_query(callback_query_id)
|
||||
|
||||
|
||||
@app.get("/admin/users", dependencies=[Depends(verify_admin_token)])
|
||||
async def admin_list_users() -> list[dict]:
|
||||
return await db.admin_list_users()
|
||||
|
|
@ -227,6 +307,13 @@ async def webhook_telegram(
|
|||
_: None = Depends(verify_webhook_secret),
|
||||
) -> dict[str, Any]:
|
||||
update = await request.json()
|
||||
|
||||
# Handle inline button callback queries (approve/reject registration)
|
||||
callback_query = update.get("callback_query")
|
||||
if callback_query:
|
||||
await _handle_callback_query(callback_query)
|
||||
return {"ok": True}
|
||||
|
||||
message = update.get("message", {})
|
||||
text = message.get("text", "")
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue