import logging import time from enum import Enum import httpx logger = logging.getLogger(__name__) REMINDERS_PERMISSION = "alexa::alerts:reminders:skill:readwrite" class RecurrenceFreq(str, Enum): DAILY = "DAILY" WEEKLY = "WEEKLY" MONTHLY = "MONTHLY" YEARLY = "YEARLY" class RemindersService: def __init__(self, account=None): self._account = account self._enabled = getattr(account, "reminders_enabled", False) if account else False @property def enabled(self) -> bool: return self._enabled @staticmethod def check_permission(handler_input) -> bool: try: permissions = ( handler_input.request_envelope.context.system.user.permissions ) if permissions and permissions.consent_token: return True except Exception: pass return False async def create_absolute_reminder( self, api_access_token: str, api_endpoint: str, user_id: str, message: str, scheduled_time: str, timezone_id: str = "Asia/Shanghai", locale: str = "zh-CN", ) -> bool: body = self._build_base_body(message, locale) body["trigger"] = { "type": "SCHEDULED_ABSOLUTE", "scheduledTime": scheduled_time, "timeZoneId": timezone_id, } return await self._send(api_access_token, api_endpoint, user_id, body, scheduled_time) async def create_relative_reminder( self, api_access_token: str, api_endpoint: str, user_id: str, message: str, offset_seconds: int, timezone_id: str = "Asia/Shanghai", locale: str = "zh-CN", ) -> bool: body = self._build_base_body(message, locale) body["trigger"] = { "type": "SCHEDULED_RELATIVE", "offsetInSeconds": offset_seconds, "timeZoneId": timezone_id, } return await self._send( api_access_token, api_endpoint, user_id, body, f"in {offset_seconds}s" ) async def create_recurring_reminder( self, api_access_token: str, api_endpoint: str, user_id: str, message: str, scheduled_time: str, frequency: RecurrenceFreq, timezone_id: str = "Asia/Shanghai", locale: str = "zh-CN", ) -> bool: body = self._build_base_body(message, locale) body["trigger"] = { "type": "SCHEDULED_ABSOLUTE", "scheduledTime": scheduled_time, "timeZoneId": timezone_id, "recurrence": { "freq": frequency.value, }, } return await self._send(api_access_token, api_endpoint, user_id, body, scheduled_time) async def create_reminder( self, api_access_token: str, api_endpoint: str, user_id: str, message: str, scheduled_time: str, timezone_id: str = "Asia/Shanghai", locale: str = "zh-CN", ) -> bool: return await self.create_absolute_reminder( api_access_token=api_access_token, api_endpoint=api_endpoint, user_id=user_id, message=message, scheduled_time=scheduled_time, timezone_id=timezone_id, locale=locale, ) def _build_base_body(self, message: str, locale: str) -> dict: return { "requestTime": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), "alertInfo": { "spokenInfo": { "content": [ { "locale": locale, "text": message, } ] } }, "pushNotification": { "status": "ENABLED", }, } async def _send( self, api_access_token: str, api_endpoint: str, user_id: str, body: dict, label: str, ) -> bool: if not self._enabled: logger.debug("Reminders disabled, skipping create") return False if not api_access_token or not api_endpoint: logger.warning("Missing API credentials for reminder creation") return False url = f"{api_endpoint}/v1/alerts/reminders" async with httpx.AsyncClient(timeout=httpx.Timeout(10.0)) as client: try: resp = await client.post( url, json=body, headers={ "Authorization": f"Bearer {api_access_token}", "Content-Type": "application/json", }, ) if resp.status_code in (200, 201): logger.info("Reminder created for user %s at %s", user_id, label) return True logger.warning( "Reminder API returned %d: %s", resp.status_code, resp.text[:200], ) except Exception: logger.exception("Reminder creation failed") return False