feat(repairs): add status timeline and public link preparation
This commit is contained in:
parent
e9ec207617
commit
09cce1f2b6
22 changed files with 1027 additions and 28 deletions
|
|
@ -3,7 +3,7 @@ from datetime import UTC, datetime
|
|||
from sqlalchemy import Select, func, or_, select
|
||||
from sqlalchemy.orm import Session, selectinload
|
||||
|
||||
from app.models.repair import Repair, RepairIntakeEvent, RepairStatusHistory
|
||||
from app.models.repair import Repair, RepairIntakeEvent, RepairNotificationEvent, RepairPublicAccessToken, RepairStatusHistory
|
||||
from app.schemas.repair import RepairCreate, RepairStatusUpdate, RepairUpdate
|
||||
|
||||
|
||||
|
|
@ -158,11 +158,22 @@ class RepairRepository:
|
|||
return list(
|
||||
db.scalars(
|
||||
select(RepairStatusHistory)
|
||||
.options(selectinload(RepairStatusHistory.actor))
|
||||
.where(RepairStatusHistory.repair_id == repair_id)
|
||||
.order_by(RepairStatusHistory.created_at.desc(), RepairStatusHistory.id.desc())
|
||||
)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_history_public(db: Session, repair_id: int) -> list[RepairStatusHistory]:
|
||||
return list(
|
||||
db.scalars(
|
||||
select(RepairStatusHistory)
|
||||
.where(RepairStatusHistory.repair_id == repair_id)
|
||||
.order_by(RepairStatusHistory.created_at.asc(), RepairStatusHistory.id.asc())
|
||||
)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def count_by_status(db: Session, status: str) -> int:
|
||||
return db.scalar(select(func.count(Repair.id)).where(Repair.status == status)) or 0
|
||||
|
|
@ -203,6 +214,110 @@ class RepairRepository:
|
|||
db.refresh(event)
|
||||
return event
|
||||
|
||||
@staticmethod
|
||||
def get_active_public_link(db: Session, repair_id: int) -> RepairPublicAccessToken | None:
|
||||
now = datetime.now(UTC)
|
||||
return db.scalar(
|
||||
select(RepairPublicAccessToken)
|
||||
.where(RepairPublicAccessToken.repair_id == repair_id)
|
||||
.where(RepairPublicAccessToken.is_active.is_(True))
|
||||
.where(or_(RepairPublicAccessToken.expires_at.is_(None), RepairPublicAccessToken.expires_at > now))
|
||||
.order_by(RepairPublicAccessToken.created_at.desc(), RepairPublicAccessToken.id.desc())
|
||||
.limit(1)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_public_link_by_hash(db: Session, token_hash: str) -> RepairPublicAccessToken | None:
|
||||
now = datetime.now(UTC)
|
||||
return db.scalar(
|
||||
select(RepairPublicAccessToken)
|
||||
.options(selectinload(RepairPublicAccessToken.repair))
|
||||
.where(RepairPublicAccessToken.token_hash == token_hash)
|
||||
.where(RepairPublicAccessToken.is_active.is_(True))
|
||||
.where(or_(RepairPublicAccessToken.expires_at.is_(None), RepairPublicAccessToken.expires_at > now))
|
||||
.limit(1)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def create_public_link(
|
||||
db: Session,
|
||||
*,
|
||||
repair_id: int,
|
||||
token_hash: str,
|
||||
token_hint: str,
|
||||
expires_at: datetime | None = None,
|
||||
) -> RepairPublicAccessToken:
|
||||
RepairRepository.revoke_public_links(db, repair_id=repair_id, commit=False)
|
||||
public_link = RepairPublicAccessToken(
|
||||
repair_id=repair_id,
|
||||
token_hash=token_hash,
|
||||
token_hint=token_hint,
|
||||
expires_at=expires_at,
|
||||
)
|
||||
db.add(public_link)
|
||||
db.commit()
|
||||
db.refresh(public_link)
|
||||
return public_link
|
||||
|
||||
@staticmethod
|
||||
def revoke_public_links(db: Session, *, repair_id: int, commit: bool = True) -> None:
|
||||
now = datetime.now(UTC)
|
||||
links = list(
|
||||
db.scalars(
|
||||
select(RepairPublicAccessToken)
|
||||
.where(RepairPublicAccessToken.repair_id == repair_id)
|
||||
.where(RepairPublicAccessToken.is_active.is_(True))
|
||||
)
|
||||
)
|
||||
for link in links:
|
||||
link.is_active = False
|
||||
link.revoked_at = now
|
||||
if commit:
|
||||
db.commit()
|
||||
|
||||
@staticmethod
|
||||
def mark_public_link_used(db: Session, public_link: RepairPublicAccessToken) -> None:
|
||||
public_link.last_used_at = datetime.now(UTC)
|
||||
db.commit()
|
||||
|
||||
@staticmethod
|
||||
def list_notification_events(db: Session, repair_id: int) -> list[RepairNotificationEvent]:
|
||||
return list(
|
||||
db.scalars(
|
||||
select(RepairNotificationEvent)
|
||||
.where(RepairNotificationEvent.repair_id == repair_id)
|
||||
.order_by(RepairNotificationEvent.created_at.desc(), RepairNotificationEvent.id.desc())
|
||||
)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def create_notification_event(
|
||||
db: Session,
|
||||
*,
|
||||
repair_id: int,
|
||||
event_type: str,
|
||||
channel: str,
|
||||
recipient: str,
|
||||
subject: str,
|
||||
status: str,
|
||||
error_message: str | None = None,
|
||||
sent_at: datetime | None = None,
|
||||
) -> RepairNotificationEvent:
|
||||
event = RepairNotificationEvent(
|
||||
repair_id=repair_id,
|
||||
event_type=event_type,
|
||||
channel=channel,
|
||||
recipient=recipient,
|
||||
subject=subject,
|
||||
status=status,
|
||||
error_message=error_message,
|
||||
sent_at=sent_at,
|
||||
)
|
||||
db.add(event)
|
||||
db.commit()
|
||||
db.refresh(event)
|
||||
return event
|
||||
|
||||
@staticmethod
|
||||
def _payload_data(payload: RepairCreate | RepairUpdate) -> dict:
|
||||
data = payload.model_dump()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue