from __future__ import annotations import logging from collections.abc import Callable import discord import config import sheets from member_sync import announce_birthday, is_birthday_today, sync_member async def run_birthday_daily( bot: discord.Client, log: logging.Logger, has_announced_today: Callable[[int], bool], mark_announced_today: Callable[[int], None], ) -> None: """Announce birthdays in the configured guild for users whose birthday is today.""" guild = bot.get_guild(config.GUILD_ID) if guild is None: log.warning("Birthday task: guild %s not found", config.GUILD_ID) return try: data = sheets.refresh() except Exception as e: log.error("Birthday task: sheet refresh failed: %s", e) data = sheets.get_cache() announced = 0 for row in data: bday_str = str(row.get("Sünnipäev", "")).strip() if not is_birthday_today(bday_str): continue member = None raw_id = str(row.get("User ID", "")).strip() if raw_id: try: member = guild.get_member(int(raw_id)) except ValueError: pass if member is None: discord_name = str(row.get("Discord", "")).strip() if discord_name: member = discord.utils.find( lambda m, n=discord_name: m.name.lower() == n.lower(), guild.members, ) if member and not has_announced_today(member.id): await announce_birthday(member, bot) mark_announced_today(member.id) announced += 1 log.info("Sünnipäeva ülesanne: teavitati %d liiget", announced) async def handle_member_join( member: discord.Member, bot: discord.Client, log: logging.Logger, has_announced_today: Callable[[int], bool], mark_announced_today: Callable[[int], None], log_sync_result: Callable[[discord.Member, object], None], ) -> None: """Sync a newly joined member against sheet data and trigger birthday notice if needed.""" log.info("Member joined: %s (ID: %s)", member, member.id) if not sheets.get_cache(): sheets.refresh() result = await sync_member(member, member.guild) if result.not_found: try: sheets.add_new_member_row(member.name, member.id) log.info( " → %s not in sheet, added new row (Discord=%s, ID=%s)", member, member.name, member.id, ) except Exception as e: log.error(" → Failed to add sheet row for %s: %s", member, e) return log_sync_result(member, result) sheets.set_synced(member.id, result.synced) if result.birthday_soon and not has_announced_today(member.id): await announce_birthday(member, bot) mark_announced_today(member.id)