from __future__ import annotations import logging from dataclasses import dataclass, field from datetime import datetime from typing import Optional logger = logging.getLogger(__name__) @dataclass(frozen=True) class NFTLicense: """ Модель NFT лицензии на доступ к контенту. Важно: - license_id: уникальный идентификатор записи лицензии в нашей системе (может совпадать с nft_address или быть внутренним UUID) - content_id: идентификатор контента (из ContentCipher, sha256 от шифроданных/метаданных) - owner_address: адрес кошелька TON владельца NFT (user) - nft_address: адрес NFT-токена лицензии (TON) - created_at: когда лицензия была создана/закуплена (по данным блокчейна/системы) - expires_at: необязательное поле срока действия (если лицензия не бессрочная) """ license_id: str content_id: str owner_address: str nft_address: str created_at: datetime = field(default_factory=lambda: datetime.utcnow()) expires_at: Optional[datetime] = None def is_active(self, now: Optional[datetime] = None) -> bool: now = now or datetime.utcnow() if self.expires_at is None: return True return now < self.expires_at def to_dict(self) -> dict: return { "license_id": self.license_id, "content_id": self.content_id, "owner_address": self.owner_address, "nft_address": self.nft_address, "created_at": self.created_at.isoformat(), "expires_at": self.expires_at.isoformat() if self.expires_at else None, } @staticmethod def from_dict(data: dict) -> "NFTLicense": try: return NFTLicense( license_id=data["license_id"], content_id=data["content_id"], owner_address=data["owner_address"], nft_address=data["nft_address"], created_at=datetime.fromisoformat(data["created_at"]) if data.get("created_at") else datetime.utcnow(), expires_at=datetime.fromisoformat(data["expires_at"]) if data.get("expires_at") else None, ) except Exception as e: logger.error("Failed to parse NFTLicense from dict: %s", e) raise