Coverage for polar/models/customer_session.py: 83%
30 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 12:42 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 12:42 +0000
1from datetime import datetime
2from urllib.parse import urlencode
3from uuid import UUID
5from sqlalchemy import CHAR, TIMESTAMP, ForeignKey, String, Uuid
6from sqlalchemy.orm import Mapped, declared_attr, mapped_column, relationship
8from polar.config import settings
9from polar.kit.db.models.base import RecordModel
10from polar.kit.utils import utc_now
12from .customer import Customer
15def get_expires_at() -> datetime:
16 return utc_now() + settings.CUSTOMER_SESSION_TTL
19class CustomerSession(RecordModel):
20 __tablename__ = "customer_sessions"
22 token: Mapped[str] = mapped_column(CHAR(64), unique=True, nullable=False)
23 expires_at: Mapped[datetime] = mapped_column(
24 TIMESTAMP(timezone=True), nullable=False, index=True, default=get_expires_at
25 )
26 return_url: Mapped[str | None] = mapped_column(String, nullable=True, default=None)
28 customer_id: Mapped[UUID] = mapped_column(
29 Uuid, ForeignKey("customers.id", ondelete="cascade"), nullable=False, index=True
30 )
32 @declared_attr
33 def customer(cls) -> Mapped[Customer]:
34 return relationship(Customer, lazy="joined")
36 @property
37 def raw_token(self) -> str | None:
38 return getattr(self, "_raw_token", None)
40 @raw_token.setter
41 def raw_token(self, value: str) -> None:
42 self._raw_token = value
44 @property
45 def customer_portal_url(self) -> str:
46 query_string = urlencode(
47 {"customer_session_token": self.raw_token, "email": self.customer.email}
48 )
49 return settings.generate_frontend_url(
50 f"/{self.customer.organization.slug}/portal?{query_string}"
51 )