Fixes
This commit is contained in:
@@ -354,7 +354,8 @@ async def create_dispute(
|
||||
db,
|
||||
user_id=assignment.participant.user_id,
|
||||
marathon_title=marathon.title,
|
||||
challenge_title=assignment.challenge.title
|
||||
challenge_title=assignment.challenge.title,
|
||||
assignment_id=assignment_id
|
||||
)
|
||||
|
||||
# Load relationships for response
|
||||
|
||||
@@ -23,6 +23,9 @@ class Settings(BaseSettings):
|
||||
TELEGRAM_BOT_USERNAME: str = ""
|
||||
TELEGRAM_LINK_TOKEN_EXPIRE_MINUTES: int = 10
|
||||
|
||||
# Frontend
|
||||
FRONTEND_URL: str = "http://localhost:3000"
|
||||
|
||||
# Uploads
|
||||
UPLOAD_DIR: str = "uploads"
|
||||
MAX_IMAGE_SIZE: int = 15 * 1024 * 1024 # 15 MB
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import logging
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||
)
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from pathlib import Path
|
||||
|
||||
@@ -22,7 +22,8 @@ class TelegramNotifier:
|
||||
self,
|
||||
chat_id: int,
|
||||
text: str,
|
||||
parse_mode: str = "HTML"
|
||||
parse_mode: str = "HTML",
|
||||
reply_markup: dict | None = None
|
||||
) -> bool:
|
||||
"""Send a message to a Telegram chat."""
|
||||
if not self.bot_token:
|
||||
@@ -31,13 +32,17 @@ class TelegramNotifier:
|
||||
|
||||
try:
|
||||
async with httpx.AsyncClient() as client:
|
||||
payload = {
|
||||
"chat_id": chat_id,
|
||||
"text": text,
|
||||
"parse_mode": parse_mode
|
||||
}
|
||||
if reply_markup:
|
||||
payload["reply_markup"] = reply_markup
|
||||
|
||||
response = await client.post(
|
||||
f"{self.api_url}/sendMessage",
|
||||
json={
|
||||
"chat_id": chat_id,
|
||||
"text": text,
|
||||
"parse_mode": parse_mode
|
||||
},
|
||||
json=payload,
|
||||
timeout=10.0
|
||||
)
|
||||
if response.status_code == 200:
|
||||
@@ -53,7 +58,8 @@ class TelegramNotifier:
|
||||
self,
|
||||
db: AsyncSession,
|
||||
user_id: int,
|
||||
message: str
|
||||
message: str,
|
||||
reply_markup: dict | None = None
|
||||
) -> bool:
|
||||
"""Send notification to a user by user_id."""
|
||||
result = await db.execute(
|
||||
@@ -61,10 +67,16 @@ class TelegramNotifier:
|
||||
)
|
||||
user = result.scalar_one_or_none()
|
||||
|
||||
if not user or not user.telegram_id:
|
||||
if not user:
|
||||
logger.warning(f"[Notify] User {user_id} not found")
|
||||
return False
|
||||
|
||||
return await self.send_message(user.telegram_id, message)
|
||||
if not user.telegram_id:
|
||||
logger.warning(f"[Notify] User {user_id} ({user.nickname}) has no telegram_id")
|
||||
return False
|
||||
|
||||
logger.info(f"[Notify] Sending to user {user.nickname} (telegram_id={user.telegram_id})")
|
||||
return await self.send_message(user.telegram_id, message, reply_markup=reply_markup)
|
||||
|
||||
async def notify_marathon_participants(
|
||||
self,
|
||||
@@ -171,16 +183,41 @@ class TelegramNotifier:
|
||||
db: AsyncSession,
|
||||
user_id: int,
|
||||
marathon_title: str,
|
||||
challenge_title: str
|
||||
challenge_title: str,
|
||||
assignment_id: int
|
||||
) -> bool:
|
||||
"""Notify user about dispute raised on their assignment."""
|
||||
message = (
|
||||
f"⚠️ <b>На твоё задание подан спор</b>\n\n"
|
||||
f"Марафон: {marathon_title}\n"
|
||||
f"Задание: {challenge_title}\n\n"
|
||||
f"Зайди на сайт, чтобы ответить на спор."
|
||||
)
|
||||
return await self.notify_user(db, user_id, message)
|
||||
logger.info(f"[Dispute] Sending notification to user_id={user_id} for assignment_id={assignment_id}")
|
||||
|
||||
dispute_url = f"{settings.FRONTEND_URL}/assignments/{assignment_id}"
|
||||
logger.info(f"[Dispute] URL: {dispute_url}")
|
||||
|
||||
# Telegram requires HTTPS for inline keyboard URLs
|
||||
use_inline_button = dispute_url.startswith("https://")
|
||||
|
||||
if use_inline_button:
|
||||
message = (
|
||||
f"⚠️ <b>На твоё задание подан спор</b>\n\n"
|
||||
f"Марафон: {marathon_title}\n"
|
||||
f"Задание: {challenge_title}"
|
||||
)
|
||||
reply_markup = {
|
||||
"inline_keyboard": [[
|
||||
{"text": "Открыть спор", "url": dispute_url}
|
||||
]]
|
||||
}
|
||||
else:
|
||||
message = (
|
||||
f"⚠️ <b>На твоё задание подан спор</b>\n\n"
|
||||
f"Марафон: {marathon_title}\n"
|
||||
f"Задание: {challenge_title}\n\n"
|
||||
f"🔗 {dispute_url}"
|
||||
)
|
||||
reply_markup = None
|
||||
|
||||
result = await self.notify_user(db, user_id, message, reply_markup=reply_markup)
|
||||
logger.info(f"[Dispute] Notification result: {result}")
|
||||
return result
|
||||
|
||||
async def notify_dispute_resolved(
|
||||
self,
|
||||
|
||||
Reference in New Issue
Block a user