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
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)
|
|
|