diff --git a/bot/commands/medications.py b/bot/commands/medications.py index 60f3420..b521062 100644 --- a/bot/commands/medications.py +++ b/bot/commands/medications.py @@ -1,6 +1,4 @@ -""" -Medications command handler - bot-side hooks for medication management -""" + import asyncio import re @@ -30,10 +28,8 @@ def _get_nearest_scheduled_time(times, user_tz=None): # If user_tz is an offset in minutes, convert to timezone object # Positive offset means behind UTC, so we need to use Etc/GMT+N # where N = -offset_minutes/60 (because Etc/GMT+5 means 5 hours behind UTC) - from pytz import timezone as pytz_timezone - offset_hours = -user_tz // 60 - user_tz = pytz_timezone(f"Etc/GMT+{offset_hours}") + user_tz = pytz.timezone(f"Etc/GMT+{offset_hours}") now = datetime.now(user_tz) now_minutes = now.hour * 60 + now.minute @@ -61,10 +57,6 @@ def _get_nearest_scheduled_time(times, user_tz=None): # If no time within window, use the most recent past time if best_time is None: - # Get current time in user's timezone again for reference - now = datetime.now(user_tz) - now_minutes = now.hour * 60 + now.minute - # Find the most recent past time past_times = [] for time_str in times: @@ -86,23 +78,7 @@ def _get_nearest_scheduled_time(times, user_tz=None): past_times.sort() best_time = past_times[-1][1] - return best_time - if not best_time: - for time_str in times: - try: - hour, minute = map(int, time_str.split(":")) - time_minutes = hour * 60 + minute - - # If this time was earlier today, it's a candidate - if time_minutes <= now_minutes: - diff = now_minutes - time_minutes - if diff < best_diff: - best_diff = diff - best_time = time_str - except (ValueError, AttributeError): - continue - - # If still no time found, use the first scheduled time + # Fallback: if still no time found, use the first scheduled time if not best_time and times: best_time = times[0] @@ -110,38 +86,7 @@ def _get_nearest_scheduled_time(times, user_tz=None): async def _get_user_timezone(message, session, token): - """Get user's timezone offset. Returns offset_minutes or None if not set. - - Also checks for pending timezone confirmation in session. - """ - # Check if there's a pending timezone confirmation - pending = session.get("pending_confirmations", {}).get("timezone") - if pending: - # User just replied with timezone info - user_response = message.content.strip() - - # Try to parse common timezone formats - # Format: "UTC-8", "PST", "EST", "-8", "+5:30", etc. - offset = _parse_timezone(user_response) - if offset is not None: - # Save to API - resp, status = api_request( - "put", "/api/preferences", token, {"timezone_offset": offset} - ) - if status == 200: - # Remove pending confirmation - del session["pending_confirmations"]["timezone"] - return offset - - # Invalid timezone format - await message.channel.send( - "I didn't understand that timezone format. Please say something like:\n" - '- "UTC-8" or "-8" for Pacific Time\n' - '- "UTC+1" or "+1" for Central European Time\n' - '- "PST", "EST", "CST", "MST" for US timezones' - ) - return None - + """Get user's timezone offset. Returns offset_minutes or None if not set.""" # Check if user has timezone set in preferences resp, status = api_request("get", "/api/preferences", token) if status == 200 and resp: @@ -149,7 +94,7 @@ async def _get_user_timezone(message, session, token): if offset is not None: return offset - # No timezone set - need to ask user + # No timezone set return None @@ -267,10 +212,74 @@ async def _get_scheduled_time_from_context(message, med_name): async def handle_medication(message, session, parsed): - action = parsed.get("action", "unknown") token = session["token"] user_uuid = session["user_uuid"] + # --- PENDING CONFIRMATION HANDLER --- + # Check if we are waiting for a response (e.g., timezone, yes/no confirmation) + pending = session.get("pending_confirmations", {}) + + # 1. Handle Pending Timezone + if "timezone" in pending: + user_response = message.content.strip() + offset = _parse_timezone(user_response) + + if offset is not None: + # Save to API + resp, status = api_request( + "put", "/api/preferences", token, {"timezone_offset": offset} + ) + if status == 200: + # Retrieve the stored action context + prev_context = pending["timezone"] + del session["pending_confirmations"]["timezone"] + + await message.channel.send(f"✅ Timezone set successfully.") + + # Restore the previous action so we can resume it + # We merge the context into 'parsed' so the logic below continues correctly + parsed = prev_context + else: + await message.channel.send("Error saving timezone. Please try again.") + return + else: + await message.channel.send( + "I didn't understand that timezone format. Please say something like:\n" + '- "UTC-8" or "-8" for Pacific Time\n' + '- "UTC+1" or "+1" for Central European Time\n' + '- "PST", "EST", "CST", "MST" for US timezones' + ) + return + + # 2. Handle Generic Yes/No Confirmations (Add/Delete meds) + # Find keys that look like confirmations (excluding timezone) + confirm_keys = [k for k in pending if k.startswith("med_")] + if confirm_keys: + text = message.content.strip().lower() + key = confirm_keys[0] # Handle one confirmation at a time + stored_action = pending[key] + + if text in ["yes", "y", "confirm"]: + del session["pending_confirmations"][key] + # Resume the action with confirmation bypassed + parsed = stored_action + # Force needs_confirmation to False just in case + parsed["needs_confirmation"] = False + + elif text in ["no", "n", "cancel"]: + del session["pending_confirmations"][key] + await message.channel.send("Okay, cancelled.") + return + else: + # User said something else, remind them + await message.channel.send( + "I'm waiting for a confirmation. Please reply **yes** to proceed or **no** to cancel." + ) + return + + # --- MAIN ACTION HANDLER --- + action = parsed.get("action", "unknown") + if action == "list": resp, status = api_request("get", "/api/medications", token) if status == 200: @@ -767,4 +776,4 @@ def validate_medication_json(data): register_module("medication", handle_medication) -ai_parser.register_validator("medication", validate_medication_json) +ai_parser.register_validator("medication", validate_medication_json) \ No newline at end of file