You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

48 lines
1.7 KiB

from __future__ import annotations
from datetime import UTC, datetime
from typing import Any
from sqlalchemy import DateTime, ForeignKey, Index, String, UniqueConstraint
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.models.base import BaseModel, ID_TYPE, TimestampMixin
class ShareLink(BaseModel, TimestampMixin):
__tablename__ = "share_links"
__table_args__ = (
UniqueConstraint("token", name="uk_share_links_token"),
Index("idx_share_links_expires_at", "expires_at"),
Index("idx_share_links_revoked_at", "revoked_at"),
Index("idx_share_links_created_by", "created_by"),
Index("idx_share_links_updated_at", "updated_at"),
)
id: Mapped[int] = mapped_column(ID_TYPE, primary_key=True)
token: Mapped[str] = mapped_column(String(64), nullable=False)
label: Mapped[str | None] = mapped_column(String(128), nullable=True)
expires_at: Mapped[datetime] = mapped_column(DateTime, nullable=False)
revoked_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
created_by: Mapped[int | None] = mapped_column(
ID_TYPE,
ForeignKey("accounts.id", ondelete="SET NULL"),
nullable=True,
)
creator: Mapped[Any] = relationship(
"Account",
foreign_keys=[created_by],
back_populates="created_share_links",
)
@property
def is_revoked(self) -> bool:
return self.revoked_at is not None
def is_expired(self, *, now: datetime | None = None) -> bool:
current = now or datetime.now(UTC).replace(tzinfo=None)
return self.expires_at <= current
def is_active(self, *, now: datetime | None = None) -> bool:
return not self.is_revoked and not self.is_expired(now=now)