""" DDNS Service - Dynamic DNS update service. A daemon that accepts HTTP(S) requests to dynamically update DNS entries. Includes CLI administration tools for user and hostname management. """ import datetime __version__ = "1.0.1" __author__ = "Thomas Oettli " __all__ = [ "app", "cleanup", "cli", "config", "datetime_aware_utc", "datetime_naive_utc", "datetime_str", "dns", "email", "logging", "main", "models", "now_utc", "ratelimit", "server", "STATUS_GOOD", "STATUS_NOCHG", "STATUS_BADAUTH", "STATUS_NOHOST", "STATUS_DNSERR", "STATUS_ABUSE", "STATUS_BADIP", ] # DynDNS-compatible response statuses STATUS_GOOD = "good" STATUS_NOCHG = "nochg" STATUS_BADAUTH = "badauth" STATUS_NOHOST = "nohost" STATUS_DNSERR = "dnserr" STATUS_ABUSE = "abuse" STATUS_BADIP = "badip" DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S %Z" # Datetime convention: # All datetime objects in this codebase are timezone-aware. # - now_utc(): returns timezone-aware UTC datetime # - datetime_str(): converts naive UTC (adds tzinfo for formatting) # or timezone-aware datetime to display string # - Database stores/returns naive datetimes (always UTC by convention) # - Database models automatically convert between naive/timezone-aware datetimes def now_utc(): """ Get current date and time in UTC. Returns: Timezone-aware datetime object in UTC. """ return datetime.datetime.now(datetime.UTC) def datetime_naive_utc(dt): """ Convert datetime to naive UTC datetime. Args: dt: Datetime object (naive UTC or timezone-aware or None). Returns: Naive datetime object in UTC or None if dt is not a datetime. """ if not isinstance(dt, datetime.datetime): return None if not dt.tzinfo: return dt return dt.astimezone(datetime.UTC).replace(tzinfo=None) def datetime_aware_utc(dt): """ Convert datetime to UTC datetime. Args: dt: Datetime object (naive UTC or timezone-aware or None). Returns: Timzone-aware datetime object in UTC or None if dt is not a datetime. """ if not isinstance(dt, datetime.datetime): return None if not dt.tzinfo: return dt.replace(tzinfo=datetime.UTC) if dt.tzinfo == datetime.UTC: return dt return dt.astimezone(datetime.UTC) def datetime_str(dt, utc=False): """ Convert datetime to display string. Assumes naive datetimes are UTC per codebase convention. Args: dt: Datetime object (naive UTC or timezone-aware). utc: If True, display in UTC; otherwise convert to local timezone. Returns: Formatted datetime string, or "Never" if dt is not a datetime. """ if not isinstance(dt, datetime.datetime): return "Never" aware_dt = dt.replace(tzinfo=datetime.UTC) if not dt.tzinfo else dt if utc: return aware_dt.strftime(DATETIME_FORMAT) else: return aware_dt.astimezone().strftime(DATETIME_FORMAT)