from __future__ import annotations import json from datetime import datetime, timezone from . import db def utc_now() -> datetime: return datetime.now(timezone.utc) def serialize_datetime(value: datetime | None) -> str | None: if value is None: return None if value.tzinfo is None: value = value.replace(tzinfo=timezone.utc) return value.astimezone(timezone.utc).isoformat().replace("+00:00", "Z") class RedemptionCode(db.Model): __tablename__ = "redemption_codes" id = db.Column(db.Integer, primary_key=True) code = db.Column(db.String(64), unique=True, nullable=False, index=True) status = db.Column(db.String(16), nullable=False, default="available") created_at = db.Column(db.DateTime, nullable=False, default=utc_now) used_at = db.Column(db.DateTime, nullable=True) used_by_username = db.Column(db.String(256), nullable=True) used_by_principal_name = db.Column(db.String(256), nullable=True) def to_dict(self): return { "id": self.id, "code": self.code, "status": self.status, "createdAt": serialize_datetime(self.created_at), "usedAt": serialize_datetime(self.used_at), "usedByUsername": self.used_by_username, "usedByPrincipalName": self.used_by_principal_name, } class AuditEvent(db.Model): __tablename__ = "audit_events" id = db.Column(db.Integer, primary_key=True) event_type = db.Column(db.String(64), nullable=False, index=True) status = db.Column(db.String(16), nullable=False, default="success", index=True) actor = db.Column(db.String(128), nullable=False, default="system") code = db.Column(db.String(64), nullable=True, index=True) username = db.Column(db.String(256), nullable=True) principal_name = db.Column(db.String(256), nullable=True) details = db.Column(db.Text, nullable=True) created_at = db.Column(db.DateTime, nullable=False, default=utc_now, index=True) def to_dict(self): parsed_details = None if self.details: try: parsed_details = json.loads(self.details) except ValueError: parsed_details = {"raw": self.details} return { "id": self.id, "eventType": self.event_type, "status": self.status, "actor": self.actor, "code": self.code, "username": self.username, "principalName": self.principal_name, "details": parsed_details, "createdAt": serialize_datetime(self.created_at), }