| """ |
| API Key model for AegisLM SaaS Backend. |
| |
| Production-ready SQLAlchemy model for secure |
| API key management and usage tracking. |
| """ |
|
|
| from datetime import datetime, timedelta |
| from sqlalchemy import Column, Integer, String, DateTime, Boolean, Text, ForeignKey |
| from sqlalchemy.orm import relationship |
| from sqlalchemy.sql import func |
|
|
| from core.database import Base |
|
|
|
|
| class ApiKey(Base): |
| """API Key model for programmatic access.""" |
| |
| __tablename__ = "api_keys" |
| |
| |
| id = Column(Integer, primary_key=True, index=True) |
| |
| |
| user_id = Column(Integer, ForeignKey("users.id"), nullable=False, index=True) |
| |
| |
| key = Column(String(255), unique=True, index=True, nullable=False) |
| name = Column(String(255), nullable=False) |
| description = Column(Text, nullable=True) |
| |
| |
| is_active = Column(Boolean, default=True, nullable=False) |
| expires_at = Column(DateTime(timezone=True), nullable=True) |
| |
| |
| last_used_at = Column(DateTime(timezone=True), nullable=True) |
| usage_count = Column(Integer, default=0, nullable=False) |
| |
| |
| created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False, index=True) |
| updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False) |
| |
| |
| user = relationship("User", back_populates="api_keys") |
| |
| def __repr__(self): |
| return f"<ApiKey(id={self.id}, name={self.name}, user_id={self.user_id})>" |
| |
| def to_dict(self, include_key: bool = False): |
| """Convert API key to dictionary.""" |
| data = { |
| "id": self.id, |
| "user_id": self.user_id, |
| "name": self.name, |
| "description": self.description, |
| "is_active": self.is_active, |
| "expires_at": self.expires_at.isoformat() if self.expires_at else None, |
| "last_used_at": self.last_used_at.isoformat() if self.last_used_at else None, |
| "usage_count": self.usage_count, |
| "created_at": self.created_at.isoformat() if self.created_at else None, |
| "updated_at": self.updated_at.isoformat() if self.updated_at else None, |
| } |
| |
| if include_key: |
| data["key"] = self.key |
| |
| return data |
| |
| def is_expired(self) -> bool: |
| """Check if API key is expired.""" |
| if self.expires_at is None: |
| return False |
| return datetime.utcnow() > self.expires_at |
| |
| def is_valid(self) -> bool: |
| """Check if API key is valid and active.""" |
| return ( |
| self.is_active |
| and not self.is_expired() |
| ) |
| |
| def update_usage(self): |
| """Update usage tracking.""" |
| self.last_used_at = datetime.utcnow() |
| self.usage_count += 1 |
| self.updated_at = datetime.utcnow() |
| |
| @classmethod |
| def create_expiration_date(cls, days: int = 365) -> datetime: |
| """Create expiration date for API key.""" |
| return datetime.utcnow() + timedelta(days=days) |
|
|