upd
This commit is contained in:
@ -1,12 +1,13 @@
|
|||||||
"""Scheduler for daily birthday notifications."""
|
"""Scheduler for daily birthday notifications."""
|
||||||
import telebot
|
import telebot
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Optional
|
from typing import Optional, Dict, List, Tuple
|
||||||
|
from collections import defaultdict
|
||||||
from apscheduler.schedulers.blocking import BlockingScheduler
|
from apscheduler.schedulers.blocking import BlockingScheduler
|
||||||
from apscheduler.triggers.cron import CronTrigger
|
from apscheduler.triggers.cron import CronTrigger
|
||||||
import pytz
|
import pytz
|
||||||
from database import get_db_session, User, Chat, UserChat
|
from database import get_db_session, User, Chat, UserChat
|
||||||
from messages import format_birthday_greeting
|
from messages import format_birthday_greeting, format_multiple_birthdays_greetings
|
||||||
from config import Config
|
from config import Config
|
||||||
|
|
||||||
|
|
||||||
@ -27,7 +28,10 @@ def send_birthday_notifications(bot: telebot.TeleBot) -> None:
|
|||||||
if not users_with_birthday:
|
if not users_with_birthday:
|
||||||
return
|
return
|
||||||
|
|
||||||
# For each user, send greetings to all their chats
|
# Group users by chat: chat_id -> list of (first_name, theme, user_id)
|
||||||
|
chat_users: Dict[int, List[Tuple[str, str, int]]] = defaultdict(list)
|
||||||
|
|
||||||
|
# For each user, find all their chats
|
||||||
for user in users_with_birthday:
|
for user in users_with_birthday:
|
||||||
# Get all chats where user is a member
|
# Get all chats where user is a member
|
||||||
user_chats = db.query(Chat).join(UserChat).filter(
|
user_chats = db.query(Chat).join(UserChat).filter(
|
||||||
@ -35,14 +39,14 @@ def send_birthday_notifications(bot: telebot.TeleBot) -> None:
|
|||||||
Chat.bot_is_admin == True
|
Chat.bot_is_admin == True
|
||||||
).all()
|
).all()
|
||||||
|
|
||||||
greeting = format_birthday_greeting(user.first_name, user.preference_theme)
|
|
||||||
|
|
||||||
for chat in user_chats:
|
for chat in user_chats:
|
||||||
try:
|
try:
|
||||||
# Check if user is still in chat
|
# Check if user is still in chat
|
||||||
member = bot.get_chat_member(chat.chat_id, user.user_id)
|
member = bot.get_chat_member(chat.chat_id, user.user_id)
|
||||||
if member.status not in ['left', 'kicked']:
|
if member.status not in ['left', 'kicked']:
|
||||||
bot.send_message(chat.chat_id, greeting)
|
chat_users[chat.chat_id].append(
|
||||||
|
(user.first_name, user.preference_theme, user.user_id)
|
||||||
|
)
|
||||||
except telebot.apihelper.ApiTelegramException as e:
|
except telebot.apihelper.ApiTelegramException as e:
|
||||||
# Handle errors: user blocked bot, bot removed from chat, etc.
|
# Handle errors: user blocked bot, bot removed from chat, etc.
|
||||||
if e.error_code == 403:
|
if e.error_code == 403:
|
||||||
@ -57,6 +61,31 @@ def send_birthday_notifications(bot: telebot.TeleBot) -> None:
|
|||||||
except Exception:
|
except Exception:
|
||||||
# Other errors - continue
|
# Other errors - continue
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Send greetings grouped by chat
|
||||||
|
for chat_id, users_data in chat_users.items():
|
||||||
|
try:
|
||||||
|
if len(users_data) == 1:
|
||||||
|
# Single user - use simple format
|
||||||
|
first_name, theme, user_id = users_data[0]
|
||||||
|
greeting = format_birthday_greeting(first_name, theme, user_id)
|
||||||
|
bot.send_message(chat_id, greeting, parse_mode='HTML')
|
||||||
|
else:
|
||||||
|
# Multiple users - use special format
|
||||||
|
greeting = format_multiple_birthdays_greetings(users_data)
|
||||||
|
bot.send_message(chat_id, greeting, parse_mode='HTML')
|
||||||
|
except telebot.apihelper.ApiTelegramException as e:
|
||||||
|
# Handle errors: bot removed from chat, etc.
|
||||||
|
if e.error_code == 403:
|
||||||
|
# Bot was blocked or removed from chat
|
||||||
|
chat = db.query(Chat).filter(Chat.chat_id == chat_id).first()
|
||||||
|
if chat:
|
||||||
|
chat.bot_is_admin = False
|
||||||
|
db.commit()
|
||||||
|
# Silently continue for other errors
|
||||||
|
except Exception:
|
||||||
|
# Other errors - continue
|
||||||
|
pass
|
||||||
finally:
|
finally:
|
||||||
db.close()
|
db.close()
|
||||||
|
|
||||||
|
|||||||
55
messages.py
55
messages.py
@ -38,6 +38,20 @@ def get_theme_emoji(theme: str) -> str:
|
|||||||
"""Get emoji for the given theme."""
|
"""Get emoji for the given theme."""
|
||||||
return THEME_EMOJIS.get(theme, "🎉") # Default emoji
|
return THEME_EMOJIS.get(theme, "🎉") # Default emoji
|
||||||
|
|
||||||
|
# Birthday greeting opening phrases (random variations)
|
||||||
|
BIRTHDAY_GREETINGS = [
|
||||||
|
"С днем рождения",
|
||||||
|
"Поздравляю с днем рождения",
|
||||||
|
"С твоим днем рождения",
|
||||||
|
"Поздравляю тебя с днем рождения",
|
||||||
|
"Поздравляю с днем рождения",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def get_birthday_greeting_opening() -> str:
|
||||||
|
"""Get a random birthday greeting opening phrase."""
|
||||||
|
return random.choice(BIRTHDAY_GREETINGS)
|
||||||
|
|
||||||
# Birthday messages for each theme
|
# Birthday messages for each theme
|
||||||
BIRTHDAY_MESSAGES = {
|
BIRTHDAY_MESSAGES = {
|
||||||
"Автомобили": [
|
"Автомобили": [
|
||||||
@ -132,8 +146,43 @@ def get_birthday_message(theme: str) -> str:
|
|||||||
return random.choice(messages)
|
return random.choice(messages)
|
||||||
|
|
||||||
|
|
||||||
def format_birthday_greeting(first_name: str, theme: str) -> str:
|
def format_birthday_greeting(first_name: str, theme: str, user_id: int) -> str:
|
||||||
"""Format a complete birthday greeting with emoji."""
|
"""Format a complete birthday greeting with emoji and user link."""
|
||||||
emoji = get_theme_emoji(theme)
|
emoji = get_theme_emoji(theme)
|
||||||
|
greeting_opening = get_birthday_greeting_opening()
|
||||||
message = get_birthday_message(theme)
|
message = get_birthday_message(theme)
|
||||||
return f"{emoji} С днем рождения {first_name}, {message}"
|
# Format: party popper + theme emoji + greeting + bold name with link
|
||||||
|
user_link = f"tg://user?id={user_id}"
|
||||||
|
return f"🎉 {greeting_opening}, <a href=\"{user_link}\">{emoji} <b>{first_name}</b></a>, {message}"
|
||||||
|
|
||||||
|
|
||||||
|
def format_multiple_birthdays_greetings(users_data: list[tuple[str, str, int]]) -> str:
|
||||||
|
"""Format greetings for multiple users celebrating birthday today.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
users_data: List of tuples (first_name, theme, user_id)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Formatted message with all greetings
|
||||||
|
"""
|
||||||
|
count = len(users_data)
|
||||||
|
# Determine correct form of "человек"
|
||||||
|
if count == 1:
|
||||||
|
person_word = "человек"
|
||||||
|
elif count in [2, 3, 4]:
|
||||||
|
person_word = "человека"
|
||||||
|
else:
|
||||||
|
person_word = "человек"
|
||||||
|
|
||||||
|
header = f"🎉 Сегодня день рождения отмечают {count} {person_word}:\n\n"
|
||||||
|
|
||||||
|
greetings = []
|
||||||
|
for first_name, theme, user_id in users_data:
|
||||||
|
emoji = get_theme_emoji(theme)
|
||||||
|
greeting_opening = get_birthday_greeting_opening()
|
||||||
|
message = get_birthday_message(theme)
|
||||||
|
user_link = f"tg://user?id={user_id}"
|
||||||
|
greeting = f"<a href=\"{user_link}\">{emoji} <b>{first_name}</b></a> — {greeting_opening.lower()}, {message}"
|
||||||
|
greetings.append(greeting)
|
||||||
|
|
||||||
|
return header + "\n\n".join(greetings)
|
||||||
|
|||||||
Reference in New Issue
Block a user