"""Share repository for database operations.""" import secrets from datetime import datetime, timedelta from typing import Optional from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.domain.models import Share class ShareRepository: """Repository for share database operations.""" def __init__(self, session: AsyncSession): """ Initialize share repository. Args: session: Database session """ self.session = session def _generate_token(self) -> str: """Generate a secure random token.""" return secrets.token_urlsafe(32) async def create( self, owner_user_id: str, asset_id: Optional[str] = None, album_id: Optional[str] = None, expires_in_seconds: Optional[int] = None, password_hash: Optional[str] = None, ) -> Share: """ Create a new share link. Args: owner_user_id: Owner user ID asset_id: Optional asset ID album_id: Optional album ID expires_in_seconds: Optional expiration time in seconds password_hash: Optional password hash Returns: Created share instance """ token = self._generate_token() expires_at = None if expires_in_seconds: expires_at = datetime.utcnow() + timedelta(seconds=expires_in_seconds) share = Share( owner_user_id=owner_user_id, asset_id=asset_id, album_id=album_id, token=token, expires_at=expires_at, password_hash=password_hash, ) self.session.add(share) await self.session.flush() await self.session.refresh(share) return share async def get_by_id(self, share_id: str) -> Optional[Share]: """ Get share by ID. Args: share_id: Share ID Returns: Share instance or None if not found """ result = await self.session.execute(select(Share).where(Share.id == share_id)) return result.scalar_one_or_none() async def get_by_token(self, token: str) -> Optional[Share]: """ Get share by token. Args: token: Share token Returns: Share instance or None if not found """ result = await self.session.execute(select(Share).where(Share.token == token)) return result.scalar_one_or_none() async def revoke(self, share: Share) -> Share: """ Revoke a share link. Args: share: Share to revoke Returns: Updated share """ share.revoked_at = datetime.utcnow() await self.session.flush() await self.session.refresh(share) return share def is_valid(self, share: Share) -> bool: """ Check if a share is valid (not revoked or expired). Args: share: Share to check Returns: True if valid, False otherwise """ if share.revoked_at: return False if share.expires_at and share.expires_at < datetime.utcnow(): return False return True