improve work
This commit is contained in:
1 parent
64491e19e1
commit
3511ebd247
23 files changed
+1595
-310
No files matched your search
@@ -11,6 +11,7 @@ import json
|
||||
import urllib
|
||||
|
||||
from app.core.models.transaction import StarsInvoice
|
||||
from app.core._utils.share_links import build_content_links
|
||||
|
||||
|
||||
class PlayerTemplates:
|
||||
@@ -59,12 +60,26 @@ class PlayerTemplates:
|
||||
cd_log += f"Can't get cover content: {e}. "
|
||||
cover_content = None
|
||||
|
||||
share_target = user_existing_license.onchain_address if user_existing_license else content.cid.serialize_v2()
|
||||
ref_id = (self.user.meta or {}).get('ref_id')
|
||||
if not ref_id:
|
||||
ref_id = self.user.ensure_ref_id()
|
||||
if self.db_session:
|
||||
await self.db_session.commit()
|
||||
|
||||
_, startapp_url, web_app_url = build_content_links(
|
||||
share_target,
|
||||
ref_id,
|
||||
project_host=PROJECT_HOST,
|
||||
bot_username=CLIENT_TELEGRAM_BOT_USERNAME
|
||||
)
|
||||
|
||||
content_share_link = {
|
||||
'text': self.user.translated('p_shareLinkContext').format(title=content_metadata_json.get('name', "")),
|
||||
'url': f"https://t.me/{CLIENT_TELEGRAM_BOT_USERNAME}/content?startapp={content.cid.serialize_v2()}"
|
||||
'url': startapp_url,
|
||||
'web_url': web_app_url,
|
||||
'ref_id': ref_id
|
||||
}
|
||||
if user_existing_license:
|
||||
content_share_link['url'] = f"https://t.me/{CLIENT_TELEGRAM_BOT_USERNAME}/content?startapp={user_existing_license.onchain_address}"
|
||||
|
||||
if cover_content:
|
||||
template_kwargs['photo'] = URLInputFile(cover_content.web_url)
|
||||
@@ -85,7 +100,8 @@ class PlayerTemplates:
|
||||
{content_hashtags}
|
||||
Этот контент был загружен в MY
|
||||
\t/ p2p content market /
|
||||
<blockquote><a href="{content_share_link['url']}">🔴 «открыть в MY»</a></blockquote>"""
|
||||
<blockquote><a href="{content_share_link['url']}">🔴 «открыть в MY»</a></blockquote>
|
||||
<blockquote><a href="{content_share_link['web_url']}">🌐 «открыть в браузере»</a></blockquote>"""
|
||||
|
||||
make_log("TG-Player", f"Send content {content_type} ({content_encoding}) to chat {self._chat_id}. {cd_log}")
|
||||
kmsgs = (await self.db_session.execute(select(KnownTelegramMessage).where(
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import os
|
||||
import traceback
|
||||
|
||||
import base58
|
||||
from sqlalchemy import and_, select
|
||||
from sqlalchemy import select
|
||||
from datetime import datetime
|
||||
|
||||
from app.core.logger import make_log
|
||||
from app.core.models import StoredContent
|
||||
@@ -42,6 +44,9 @@ class NodeStorageIndexationMixin:
|
||||
pass # async def fetch_onchain_metadata(self):
|
||||
|
||||
|
||||
MIN_ONCHAIN_INDEX = int(os.getenv("MIN_ONCHAIN_INDEX", "8"))
|
||||
|
||||
|
||||
class UserContentIndexationMixin:
|
||||
async def sync_with_chain(self, db_session):
|
||||
errored = False
|
||||
@@ -54,12 +59,29 @@ class UserContentIndexationMixin:
|
||||
cc_indexator_data = unpack_item_indexator_data(cc_indexator_result)
|
||||
assert cc_indexator_data['type'] == 1, "Type is not a content"
|
||||
assert cc_indexator_data['address'] == self.onchain_address, "Address is not equal"
|
||||
if cc_indexator_data['index'] < MIN_ONCHAIN_INDEX:
|
||||
make_log(
|
||||
"UserContent",
|
||||
f"Skip license {self.onchain_address} with index {cc_indexator_data['index']} < MIN_ONCHAIN_INDEX={MIN_ONCHAIN_INDEX}",
|
||||
level="info"
|
||||
)
|
||||
self.type = 'nft/ignored'
|
||||
self.content_id = None
|
||||
self.updated = datetime.utcnow()
|
||||
await db_session.commit()
|
||||
return
|
||||
values_slice = cc_indexator_data['values'].begin_parse()
|
||||
content_hash_b58 = base58.b58encode(bytes.fromhex(hex(values_slice.read_uint(256))[2:])).decode()
|
||||
make_log("UserContent", f"License ({self.onchain_address}) content hash: {content_hash_b58}", level="info")
|
||||
stored_content = (await db_session.execute(select(StoredContent).where(
|
||||
and_(StoredContent.type == 'onchain/content', StoredContent.hash == content_hash_b58)
|
||||
StoredContent.hash == content_hash_b58
|
||||
))).scalars().first()
|
||||
if not stored_content:
|
||||
raise AssertionError(f"Stored content not found for hash={content_hash_b58}")
|
||||
if not (stored_content.type or '').startswith('onchain/content'):
|
||||
stored_content.type = 'onchain/content' if stored_content.key_id else 'onchain/content_unknown'
|
||||
stored_content.onchain_index = stored_content.onchain_index or cc_indexator_data['index']
|
||||
stored_content.owner_address = stored_content.owner_address or cc_indexator_data['owner_address']
|
||||
trusted_cop_address_result = await toncenter.run_get_method(stored_content.meta['item_address'], 'get_nft_address_by_index', [['num', cc_indexator_data['index']]])
|
||||
assert trusted_cop_address_result.get('exit_code', -1) == 0, "Trusted cop address error"
|
||||
trusted_cop_address = Cell.one_from_boc(b64decode(trusted_cop_address_result['stack'][0][1]['bytes'])).begin_parse().read_msg_addr().to_string(1, 1, 1)
|
||||
@@ -77,5 +99,3 @@ class UserContentIndexationMixin:
|
||||
self.type = 'nft/unknown'
|
||||
self.content_id = None
|
||||
await db_session.commit()
|
||||
|
||||
|
||||
@@ -53,6 +53,11 @@ class StoredContent(AlchemyBase, AudioContentMixin):
|
||||
|
||||
@property
|
||||
def cid(self) -> ContentId:
|
||||
if self.content_id:
|
||||
try:
|
||||
return ContentId.deserialize(self.content_id)
|
||||
except Exception as exc:
|
||||
make_log("StoredContent", f"Failed to deserialize stored content_id '{self.content_id}': {exc}", level='warning')
|
||||
return ContentId(
|
||||
content_hash=b58decode(self.hash),
|
||||
onchain_index=self.onchain_index,
|
||||
|
||||
@@ -9,6 +9,10 @@ from app.core.translation import TranslationCore
|
||||
from ..base import AlchemyBase
|
||||
|
||||
|
||||
_BASE62_ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
_BASE62 = len(_BASE62_ALPHABET)
|
||||
|
||||
|
||||
class User(AlchemyBase, DisplayMixin, TranslationCore, AuthenticationMixin_V1, WalletMixin):
|
||||
LOCALE_DOMAIN = 'sanic_telegram_bot'
|
||||
|
||||
@@ -32,3 +36,26 @@ class User(AlchemyBase, DisplayMixin, TranslationCore, AuthenticationMixin_V1, W
|
||||
def __str__(self):
|
||||
return f"User, {self.id}_{self.telegram_id} | Username: {self.username} " + '\\'
|
||||
|
||||
def ensure_ref_id(self):
|
||||
"""Return a short referral identifier, generating it if missing."""
|
||||
meta = self.meta or {}
|
||||
ref_id = meta.get('ref_id')
|
||||
if isinstance(ref_id, str) and ref_id:
|
||||
return ref_id
|
||||
|
||||
ref_id = self._generate_ref_id()
|
||||
self.meta = {**meta, 'ref_id': ref_id}
|
||||
return ref_id
|
||||
|
||||
def _generate_ref_id(self):
|
||||
user_id = int(self.id or 0)
|
||||
if user_id <= 0:
|
||||
return '000'
|
||||
|
||||
value = user_id % (_BASE62 ** 3)
|
||||
chars = []
|
||||
for _ in range(3):
|
||||
chars.append(_BASE62_ALPHABET[value % _BASE62])
|
||||
value //= _BASE62
|
||||
|
||||
return ''.join(reversed(chars)) or '000'
|
||||
@@ -7,6 +7,11 @@ from tonsdk.utils import Address
|
||||
from datetime import datetime, timedelta
|
||||
from app.core.logger import make_log
|
||||
from httpx import AsyncClient
|
||||
from app.core.models.content.indexation_mixins import unpack_item_indexator_data, MIN_ONCHAIN_INDEX
|
||||
|
||||
def _platform_address_str() -> str:
|
||||
from app.core._blockchain.ton.platform import platform
|
||||
return platform.address.to_string(1, 1, 1)
|
||||
|
||||
|
||||
class WalletMixin:
|
||||
@@ -43,6 +48,43 @@ class WalletMixin:
|
||||
item_address = Address(nft_item['address']).to_string(1, 1, 1)
|
||||
owner_address = Address(nft_item['owner']['address']).to_string(1, 1, 1)
|
||||
|
||||
platform_address = _platform_address_str()
|
||||
collection_address = None
|
||||
if isinstance(nft_item, dict):
|
||||
collection_data = nft_item.get('collection')
|
||||
if isinstance(collection_data, dict):
|
||||
collection_address = collection_data.get('address')
|
||||
collection_address = collection_address or nft_item.get('collection_address')
|
||||
if collection_address:
|
||||
try:
|
||||
normalized_collection = Address(collection_address).to_string(1, 1, 1)
|
||||
except Exception:
|
||||
normalized_collection = collection_address
|
||||
if normalized_collection != platform_address:
|
||||
make_log(self, f"Skip foreign NFT {item_address} from collection {normalized_collection}", level='debug')
|
||||
continue
|
||||
|
||||
item_index = None
|
||||
# Prefer index from tonapi payload if available
|
||||
raw_index = nft_item.get('index') if isinstance(nft_item, dict) else None
|
||||
if isinstance(raw_index, int):
|
||||
item_index = raw_index
|
||||
if item_index is None:
|
||||
try:
|
||||
indexator_raw = await toncenter.run_get_method(item_address, 'indexator_data')
|
||||
if indexator_raw.get('exit_code', -1) == 0:
|
||||
item_index = unpack_item_indexator_data(indexator_raw)['index']
|
||||
except BaseException as err:
|
||||
make_log(self, f"Failed to fetch indexator data for {item_address}: {err}", level='warning')
|
||||
|
||||
if item_index is None:
|
||||
make_log(self, f"Skip NFT {item_address}: unable to resolve on-chain index", level='warning')
|
||||
continue
|
||||
|
||||
if item_index is not None and item_index < MIN_ONCHAIN_INDEX:
|
||||
make_log(self, f"Ignore NFT {item_address} with index {item_index} < MIN_ONCHAIN_INDEX={MIN_ONCHAIN_INDEX}", level='debug')
|
||||
continue
|
||||
|
||||
from sqlalchemy import select
|
||||
user_content = (await db_session.execute(select(UserContent).where(UserContent.onchain_address == item_address))).scalars().first()
|
||||
if user_content:
|
||||
@@ -83,6 +125,33 @@ class WalletMixin:
|
||||
item_address = Address(nft_item['address']).to_string(1, 1, 1)
|
||||
owner_address = Address(nft_item['owner_address']).to_string(1, 1, 1)
|
||||
|
||||
platform_address = _platform_address_str()
|
||||
collection_address = nft_item.get('collection_address') if isinstance(nft_item, dict) else None
|
||||
if collection_address:
|
||||
try:
|
||||
normalized_collection = Address(collection_address).to_string(1, 1, 1)
|
||||
except Exception:
|
||||
normalized_collection = collection_address
|
||||
if normalized_collection != platform_address:
|
||||
make_log(self, f"Skip foreign NFT {item_address} from collection {normalized_collection}", level='debug')
|
||||
continue
|
||||
|
||||
item_index = None
|
||||
try:
|
||||
indexator_raw = await toncenter.run_get_method(item_address, 'indexator_data')
|
||||
if indexator_raw.get('exit_code', -1) == 0:
|
||||
item_index = unpack_item_indexator_data(indexator_raw)['index']
|
||||
except BaseException as err:
|
||||
make_log(self, f"Failed to fetch indexator data for {item_address}: {err}", level='warning')
|
||||
|
||||
if item_index is None:
|
||||
make_log(self, f"Skip NFT {item_address}: unable to resolve on-chain index", level='warning')
|
||||
continue
|
||||
|
||||
if item_index is not None and item_index < MIN_ONCHAIN_INDEX:
|
||||
make_log(self, f"Ignore NFT {item_address} with index {item_index} < MIN_ONCHAIN_INDEX={MIN_ONCHAIN_INDEX}", level='debug')
|
||||
continue
|
||||
|
||||
from sqlalchemy import select
|
||||
user_content = (await db_session.execute(select(UserContent).where(UserContent.onchain_address == item_address))).scalars().first()
|
||||
if user_content:
|
||||
|
||||
Reference in new issue
Block a user