This commit is contained in:
@@ -1,27 +1,70 @@
|
||||
from datetime import UTC, datetime, timedelta
|
||||
|
||||
import httpx
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.config import settings
|
||||
from app.models.car import ServiceNotification
|
||||
from app.models.user import User
|
||||
|
||||
MODERATOR_ROLES = {"admin", "verifier", "moderator"}
|
||||
|
||||
|
||||
async def notify_user(user: User, text: str) -> None:
|
||||
async def notify_user(user: User, text: str) -> bool:
|
||||
if not settings.bot_token or settings.app_env == "test":
|
||||
return
|
||||
return False
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=5) as client:
|
||||
await client.post(
|
||||
response = await client.post(
|
||||
f"https://api.telegram.org/bot{settings.bot_token}/sendMessage",
|
||||
data={"chat_id": str(user.telegram_id), "text": text},
|
||||
)
|
||||
return response.status_code < 400
|
||||
except Exception:
|
||||
return
|
||||
return False
|
||||
|
||||
|
||||
async def notify_platform_moderators(session: AsyncSession, text: str) -> None:
|
||||
result = await session.execute(select(User).where(User.platform_role.in_(MODERATOR_ROLES)))
|
||||
for user in result.scalars():
|
||||
await notify_user(user, text)
|
||||
|
||||
|
||||
async def retry_failed_notifications(session: AsyncSession, *, limit: int = 50) -> int:
|
||||
return await process_notification_queue(session, limit=limit)
|
||||
|
||||
|
||||
async def process_notification_queue(session: AsyncSession, *, limit: int = 50) -> int:
|
||||
now = datetime.now(UTC)
|
||||
result = await session.execute(
|
||||
select(ServiceNotification)
|
||||
.where(
|
||||
ServiceNotification.status.in_(["pending", "failed", "retrying"]),
|
||||
ServiceNotification.retry_count < 5,
|
||||
)
|
||||
.order_by(ServiceNotification.created_at.asc())
|
||||
.limit(limit)
|
||||
)
|
||||
delivered = 0
|
||||
for notification in result.scalars():
|
||||
if notification.status == "retrying" and notification.created_at > now - timedelta(seconds=30):
|
||||
continue
|
||||
notification.status = "processing"
|
||||
user = await session.get(User, notification.recipient_user_id)
|
||||
if user is None:
|
||||
notification.status = "abandoned"
|
||||
notification.last_error = "recipient_not_found"
|
||||
continue
|
||||
ok = await notify_user(user, f"{notification.title}\n{notification.body}" if notification.body else notification.title)
|
||||
notification.retry_count += 1
|
||||
if ok:
|
||||
notification.status = "sent"
|
||||
notification.sent_at = datetime.now(UTC)
|
||||
notification.last_error = None
|
||||
delivered += 1
|
||||
else:
|
||||
notification.status = "abandoned" if notification.retry_count >= 5 else "retrying"
|
||||
notification.last_error = "telegram_delivery_failed"
|
||||
await session.commit()
|
||||
return delivered
|
||||
|
||||
Reference in New Issue
Block a user