From 3d3b80fe962b664c3f6cea6519c9068b767c1162 Mon Sep 17 00:00:00 2001 From: Chelsea Date: Tue, 17 Feb 2026 05:46:59 +0000 Subject: [PATCH] partial --- bot/bot.py | 42 +++++++++++++++--- config/.env | 4 +- core/__pycache__/postgres.cpython-312.pyc | Bin 13677 -> 13701 bytes scheduler/__pycache__/daemon.cpython-312.pyc | Bin 1476 -> 17595 bytes .../src/app/dashboard/settings/page.tsx | 11 +++++ 5 files changed, 49 insertions(+), 8 deletions(-) diff --git a/bot/bot.py b/bot/bot.py index 462f569..871fbdb 100644 --- a/bot/bot.py +++ b/bot/bot.py @@ -38,6 +38,8 @@ CACHE_FILE = "/app/user_cache.pkl" intents = discord.Intents.default() intents.message_content = True +intents.presences = True +intents.members = True client = discord.Client(intents=intents) @@ -582,14 +584,21 @@ async def beforeBackgroundLoop(): async def update_presence_tracking(): """Track Discord presence for users with presence tracking enabled.""" + print(f"[DEBUG] update_presence_tracking() called", flush=True) try: import core.adaptive_meds as adaptive_meds import core.postgres as postgres + print(f"[DEBUG] Running presence tracking. Guilds: {len(client.guilds)}", flush=True) + for guild in client.guilds: + print(f"[DEBUG] Guild: {guild.name} ({guild.id}) - Members: {guild.member_count}") + # Get all users with presence tracking enabled settings = postgres.select( "adaptive_med_settings", {"presence_tracking_enabled": True} ) + + print(f"[DEBUG] Found {len(settings)} users with presence tracking enabled") for setting in settings: user_uuid = setting.get("user_uuid") @@ -600,21 +609,35 @@ async def update_presence_tracking(): continue discord_user_id = notif_settings[0].get("discord_user_id") + print(f"[DEBUG] Looking for Discord user: {discord_user_id}", flush=True) if not discord_user_id: + print(f"[DEBUG] No Discord ID for user {user_uuid}", flush=True) continue - # Get the user from Discord + # Get the member from a shared guild (needed for presence data) try: - discord_user = await client.fetch_user(int(discord_user_id)) - if not discord_user: + member = None + target_id = int(discord_user_id) + + # Search through all guilds the bot is in + for guild in client.guilds: + member = guild.get_member(target_id) + print(f"[DEBUG] Checked guild {guild.name}, member: {member}", flush=True) + if member: + break + + if not member: + print(f"[DEBUG] User {discord_user_id} not found in any shared guild", flush=True) continue # Check if user is online - is_online = discord_user.status != discord.Status.offline + is_online = member.status != discord.Status.offline + print(f"[DEBUG] User status: {member.status}, is_online: {is_online}", flush=True) # Get current presence from DB presence = adaptive_meds.get_user_presence(user_uuid) was_online = presence.get("is_currently_online") if presence else False + print(f"[DEBUG] Previous state: {was_online}, Current: {is_online}", flush=True) # Update presence if changed if is_online != was_online: @@ -644,7 +667,12 @@ async def update_presence_tracking(): @tasks.loop(seconds=30) async def presenceTrackingLoop(): """Track Discord presence every 30 seconds.""" - await update_presence_tracking() + try: + await update_presence_tracking() + except Exception as e: + print(f"[ERROR] presenceTrackingLoop failed: {e}", flush=True) + import traceback + traceback.print_exc() @presenceTrackingLoop.before_loop @@ -711,10 +739,12 @@ async def beforeSnitchCheckLoop(): @client.event async def on_ready(): - print(f"Bot logged in as {client.user}") + print(f"Bot logged in as {client.user}", flush=True) + print(f"Connected to {len(client.guilds)} guilds", flush=True) loadCache() backgroundLoop.start() presenceTrackingLoop.start() + print(f"[DEBUG] Presence tracking loop started", flush=True) snitchCheckLoop.start() diff --git a/config/.env b/config/.env index eaf254d..f356b5e 100644 --- a/config/.env +++ b/config/.env @@ -1,4 +1,4 @@ -DISCORD_BOT_TOKEN=MTQ2NzYwMTc2ODM0NjE2MTE3Mw.G7BKQ-.kivCRj7mOl6aS5VyX4RW9hirqzm7qJ8nJOVMpE +DISCORD_BOT_TOKEN=MTQ3MDY0MjgyMDI1MDQ3MjYyMQ.Gczvus.1WuWxd72NDoLFC7BCjAixnMo5eS8wenqTIZ54I API_URL=http://app:5000 DB_HOST=db DB_PORT=5432 @@ -6,7 +6,7 @@ DB_NAME=app DB_USER=app DB_PASS=y8Khu7pJQZq6ywFDIJiqpx4zYmclHGHw JWT_SECRET=bf773b4562221bef4d304ae5752a68931382ea3e98fe38394a098f73e0c776e1 -OPENROUTER_API_KEY=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 +OPENROUTER_API_KEY=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 OPENROUTER_BASE_URL=https://openrouter.ai/api/v1 AI_CONFIG_PATH=/app/ai/ai_config.json diff --git a/core/__pycache__/postgres.cpython-312.pyc b/core/__pycache__/postgres.cpython-312.pyc index afa74986482bfc0d63d453546a1bc6b2938731b2..62bfd84d6750be58dfc849967f48c854b398989e 100644 GIT binary patch delta 51 zcmaEx)tb$HnwOW00SI2TOx(ylm040lKO;XkRX;f+HK#Z=QNOq{FS#@)zqD9?^Frn` Fh5*A=5?KHM delta 27 hcmZq8ew)R8nwOW00SGdq`ZjV;Wo8uEyp#EiApmws2xI^N diff --git a/scheduler/__pycache__/daemon.cpython-312.pyc b/scheduler/__pycache__/daemon.cpython-312.pyc index e44803e6a002246d33a990fa972d67867aade3e0..56b152f24826b6404c563b4ee835ee7fb957ddeb 100644 GIT binary patch literal 17595 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 C1g2F0 diff --git a/synculous-client/src/app/dashboard/settings/page.tsx b/synculous-client/src/app/dashboard/settings/page.tsx index 338afad..5ce5010 100644 --- a/synculous-client/src/app/dashboard/settings/page.tsx +++ b/synculous-client/src/app/dashboard/settings/page.tsx @@ -127,6 +127,17 @@ export default function SettingsPage() { .finally(() => setIsLoading(false)); }, []); + // Poll for presence updates every 10 seconds + useEffect(() => { + if (!notif.discord_enabled || !adaptiveMeds.presence_tracking_enabled) return; + + const interval = setInterval(() => { + api.adaptiveMeds.getPresence().then((data: PresenceStatus) => setPresence(data)); + }, 10000); + + return () => clearInterval(interval); + }, [notif.discord_enabled, adaptiveMeds.presence_tracking_enabled]); + const flashSaved = () => { setSaved(true); setTimeout(() => setSaved(false), 1500);