- APIKey.alias (unique, required). Creating with an existing alias renews that key: same key string kept, validity reset to 15d, reactivated, name/roles updated (response has renewed=true). - get_actor(): X-API-Key -> key alias, Bearer -> 'admin'. - markdown & patch create/update record author / created_at / updated_at / last_modified_by from the actor. - Idempotent run_migrations() (information_schema-guarded ALTERs + backfill) so existing tables/data gain the new columns on startup; create_all still covers fresh DBs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
29 lines
1.2 KiB
Python
29 lines
1.2 KiB
Python
from datetime import datetime, timedelta, UTC
|
|
from sqlalchemy import Column, String, DateTime, Boolean, JSON
|
|
from db.models import Base
|
|
|
|
class APIKey(Base):
|
|
__tablename__ = 'apikey'
|
|
|
|
key = Column(String(64), primary_key=True)
|
|
# Stable human identity of the key. Unique; creating with an existing
|
|
# alias is treated as a renewal of that key (see api/apikey).
|
|
alias = Column(String(255), nullable=False, unique=True)
|
|
name = Column(String(255), nullable=False)
|
|
created_at = Column(DateTime, nullable=False, default=lambda: datetime.now(UTC))
|
|
last_used_at = Column(DateTime)
|
|
is_active = Column(Boolean, default=True)
|
|
roles = Column(JSON, nullable=False, default=list)
|
|
expire = Column(DateTime, nullable=False, default=lambda: datetime.now(UTC) + timedelta(days=15))
|
|
|
|
def to_dict(self):
|
|
return {
|
|
"key": self.key,
|
|
"alias": self.alias,
|
|
"name": self.name,
|
|
"created_at": self.created_at.isoformat() if self.created_at else None,
|
|
"last_used_at": self.last_used_at.isoformat() if self.last_used_at else None,
|
|
"is_active": self.is_active,
|
|
"roles": self.roles,
|
|
"expire": self.expire.isoformat() if self.expire else None
|
|
} |