mariadb -> postgres
This commit is contained in:
1 parent
21964fa986
commit
e51bb86dc0
36 files changed
+650
-464
No files matched your search
@@ -3,7 +3,7 @@ from datetime import datetime
|
||||
import traceback
|
||||
|
||||
from sanic import response
|
||||
from sqlalchemy import and_
|
||||
from sqlalchemy import and_, select, func
|
||||
from tonsdk.boc import begin_cell, begin_dict
|
||||
from tonsdk.utils import Address
|
||||
|
||||
@@ -61,9 +61,9 @@ async def s_api_v1_blockchain_send_new_content_message(request):
|
||||
assert not err, f"Invalid content CID"
|
||||
|
||||
# Поиск исходного файла загруженного
|
||||
decrypted_content = request.ctx.db_session.query(StoredContent).filter(
|
||||
StoredContent.hash == decrypted_content_cid.content_hash_b58
|
||||
).first()
|
||||
decrypted_content = (await request.ctx.db_session.execute(
|
||||
select(StoredContent).where(StoredContent.hash == decrypted_content_cid.content_hash_b58)
|
||||
)).scalars().first()
|
||||
assert decrypted_content, "No content locally found"
|
||||
assert decrypted_content.type == "local/content_bin", "Invalid content type"
|
||||
|
||||
@@ -74,9 +74,9 @@ async def s_api_v1_blockchain_send_new_content_message(request):
|
||||
if request.json['image']:
|
||||
image_content_cid, err = resolve_content(request.json['image'])
|
||||
assert not err, f"Invalid image CID"
|
||||
image_content = request.ctx.db_session.query(StoredContent).filter(
|
||||
StoredContent.hash == image_content_cid.content_hash_b58
|
||||
).first()
|
||||
image_content = (await request.ctx.db_session.execute(
|
||||
select(StoredContent).where(StoredContent.hash == image_content_cid.content_hash_b58)
|
||||
)).scalars().first()
|
||||
assert image_content, "No image locally found"
|
||||
else:
|
||||
image_content_cid = None
|
||||
@@ -105,18 +105,22 @@ async def s_api_v1_blockchain_send_new_content_message(request):
|
||||
)
|
||||
i += 1
|
||||
|
||||
promo_free_upload_available = (
|
||||
3 - (request.ctx.db_session.query(PromoAction).filter(
|
||||
PromoAction.user_internal_id == request.ctx.user.id,
|
||||
PromoAction.action_type == 'freeUpload',
|
||||
).count())
|
||||
)
|
||||
if request.ctx.db_session.query(BlockchainTask).filter(
|
||||
and_(
|
||||
BlockchainTask.user_id == request.ctx.user.id,
|
||||
BlockchainTask.status != 'done',
|
||||
_cnt = (await request.ctx.db_session.execute(
|
||||
select(func.count()).select_from(PromoAction).where(
|
||||
and_(
|
||||
PromoAction.user_internal_id == request.ctx.user.id,
|
||||
PromoAction.action_type == 'freeUpload'
|
||||
)
|
||||
)
|
||||
).first():
|
||||
)).scalar()
|
||||
promo_free_upload_available = 3 - int(_cnt or 0)
|
||||
|
||||
has_pending_task = (await request.ctx.db_session.execute(
|
||||
select(BlockchainTask).where(
|
||||
and_(BlockchainTask.user_id == request.ctx.user.id, BlockchainTask.status != 'done')
|
||||
)
|
||||
)).scalars().first()
|
||||
if has_pending_task:
|
||||
make_log("Blockchain", f"User {request.ctx.user.id} already has a pending task", level='warning')
|
||||
promo_free_upload_available = 0
|
||||
|
||||
@@ -139,7 +143,7 @@ async def s_api_v1_blockchain_send_new_content_message(request):
|
||||
begin_cell()
|
||||
.store_uint(0x5491d08c, 32)
|
||||
.store_uint(int.from_bytes(encrypted_content_cid.content_hash, "big", signed=False), 256)
|
||||
.store_address(Address(request.ctx.user.wallet_address(request.ctx.db_session)))
|
||||
.store_address(Address(await request.ctx.user.wallet_address_async(request.ctx.db_session)))
|
||||
.store_ref(
|
||||
begin_cell()
|
||||
.store_ref(
|
||||
@@ -177,7 +181,7 @@ async def s_api_v1_blockchain_send_new_content_message(request):
|
||||
user_id = request.ctx.user.id
|
||||
)
|
||||
request.ctx.db_session.add(blockchain_task)
|
||||
request.ctx.db_session.commit()
|
||||
await request.ctx.db_session.commit()
|
||||
|
||||
await request.ctx.user_uploader_wrapper.send_message(
|
||||
request.ctx.user.translated('p_uploadContentTxPromo').format(
|
||||
@@ -258,18 +262,37 @@ async def s_api_v1_blockchain_send_purchase_content_message(request):
|
||||
assert field_key in request.json, f"No {field_key} provided"
|
||||
assert field_value(request.json[field_key]), f"Invalid {field_key} provided"
|
||||
|
||||
if not request.ctx.user.wallet_address(request.ctx.db_session):
|
||||
if not (await request.ctx.user.wallet_address_async(request.ctx.db_session)):
|
||||
return response.json({"error": "No wallet address provided"}, status=400)
|
||||
|
||||
license_exist = request.ctx.db_session.query(UserContent).filter_by(
|
||||
onchain_address=request.json['content_address'],
|
||||
).first()
|
||||
from sqlalchemy import select
|
||||
license_exist = (await request.ctx.db_session.execute(select(UserContent).where(
|
||||
UserContent.onchain_address == request.json['content_address']
|
||||
))).scalars().first()
|
||||
if license_exist:
|
||||
r_content = StoredContent.from_cid(request.ctx.db_session, license_exist.content.cid.serialize_v2())
|
||||
from app.core.content.content_id import ContentId
|
||||
_cid = ContentId.deserialize(license_exist.content.cid.serialize_v2())
|
||||
r_content = (await request.ctx.db_session.execute(select(StoredContent).where(StoredContent.hash == _cid.content_hash_b58))).scalars().first()
|
||||
else:
|
||||
r_content = StoredContent.from_cid(request.ctx.db_session, request.json['content_address'])
|
||||
from app.core.content.content_id import ContentId
|
||||
_cid = ContentId.deserialize(request.json['content_address'])
|
||||
r_content = (await request.ctx.db_session.execute(select(StoredContent).where(StoredContent.hash == _cid.content_hash_b58))).scalars().first()
|
||||
|
||||
content = r_content.open_content(request.ctx.db_session)
|
||||
async def open_content_async(session, sc: StoredContent):
|
||||
if not sc.encrypted:
|
||||
decrypted = sc
|
||||
encrypted = (await session.execute(select(StoredContent).where(StoredContent.decrypted_content_id == sc.id))).scalars().first()
|
||||
else:
|
||||
encrypted = sc
|
||||
decrypted = (await session.execute(select(StoredContent).where(StoredContent.id == sc.decrypted_content_id))).scalars().first()
|
||||
assert decrypted and encrypted, "Can't open content"
|
||||
ctype = decrypted.json_format().get('content_type', 'application/x-binary')
|
||||
try:
|
||||
content_type = ctype.split('/')[0]
|
||||
except Exception:
|
||||
content_type = 'application'
|
||||
return {'encrypted_content': encrypted, 'decrypted_content': decrypted, 'content_type': content_type}
|
||||
content = await open_content_async(request.ctx.db_session, r_content)
|
||||
|
||||
licenses_cost = content['encrypted_content'].json_format()['license']
|
||||
assert request.json['license_type'] in licenses_cost
|
||||
|
||||
@@ -6,6 +6,7 @@ from base58 import b58encode, b58decode
|
||||
from sanic import response
|
||||
|
||||
from app.core.models.node_storage import StoredContent
|
||||
from sqlalchemy import select
|
||||
from app.core._blockchain.ton.platform import platform
|
||||
from app.core._crypto.signer import Signer
|
||||
from app.core._secrets import hot_pubkey, service_wallet, hot_seed
|
||||
@@ -19,10 +20,10 @@ def get_git_info():
|
||||
|
||||
|
||||
async def s_api_v1_node(request): # /api/v1/node
|
||||
last_known_index = request.ctx.db_session.query(StoredContent).filter(
|
||||
StoredContent.onchain_index != None
|
||||
).order_by(StoredContent.onchain_index.desc()).first()
|
||||
last_known_index = last_known_index.onchain_index if last_known_index else 0
|
||||
last_known_index_obj = (await request.ctx.db_session.execute(
|
||||
select(StoredContent).where(StoredContent.onchain_index != None).order_by(StoredContent.onchain_index.desc())
|
||||
)).scalars().first()
|
||||
last_known_index = last_known_index_obj.onchain_index if last_known_index_obj else 0
|
||||
last_known_index = max(last_known_index, 0)
|
||||
return response.json({
|
||||
'id': b58encode(hot_pubkey).decode(),
|
||||
@@ -39,10 +40,10 @@ async def s_api_v1_node(request): # /api/v1/node
|
||||
})
|
||||
|
||||
async def s_api_v1_node_friendly(request):
|
||||
last_known_index = request.ctx.db_session.query(StoredContent).filter(
|
||||
StoredContent.onchain_index != None
|
||||
).order_by(StoredContent.onchain_index.desc()).first()
|
||||
last_known_index = last_known_index.onchain_index if last_known_index else 0
|
||||
last_known_index_obj = (await request.ctx.db_session.execute(
|
||||
select(StoredContent).where(StoredContent.onchain_index != None).order_by(StoredContent.onchain_index.desc())
|
||||
)).scalars().first()
|
||||
last_known_index = last_known_index_obj.onchain_index if last_known_index_obj else 0
|
||||
last_known_index = max(last_known_index, 0)
|
||||
response_plain_text = f"""
|
||||
Node address: {service_wallet.address.to_string(1, 1, 1)}
|
||||
|
||||
+22
-16
@@ -37,7 +37,9 @@ async def s_api_v1_auth_twa(request):
|
||||
make_log("auth", "Invalid TWA data", level="warning")
|
||||
return response.json({"error": "Invalid TWA data"}, status=401)
|
||||
|
||||
known_user = request.ctx.db_session.query(User).filter(User.telegram_id == twa_data.user.id).first()
|
||||
known_user = (await request.ctx.db_session.execute(
|
||||
select(User).where(User.telegram_id == twa_data.user.id)
|
||||
)).scalars().first()
|
||||
if not known_user:
|
||||
new_user = User(
|
||||
telegram_id=twa_data.user.id,
|
||||
@@ -52,9 +54,11 @@ async def s_api_v1_auth_twa(request):
|
||||
created=datetime.now()
|
||||
)
|
||||
request.ctx.db_session.add(new_user)
|
||||
request.ctx.db_session.commit()
|
||||
await request.ctx.db_session.commit()
|
||||
|
||||
known_user = request.ctx.db_session.query(User).filter(User.telegram_id == twa_data.user.id).first()
|
||||
known_user = (await request.ctx.db_session.execute(
|
||||
select(User).where(User.telegram_id == twa_data.user.id)
|
||||
)).scalars().first()
|
||||
assert known_user, "User not created"
|
||||
|
||||
new_user_key = await known_user.create_api_token_v1(request.ctx.db_session, "USER_API_V1")
|
||||
@@ -65,12 +69,12 @@ async def s_api_v1_auth_twa(request):
|
||||
wallet_info.account = Account.from_dict(auth_data['ton_proof']['account'])
|
||||
wallet_info.ton_proof = TonProof.from_dict({'proof': auth_data['ton_proof']['ton_proof']})
|
||||
connection_payload = auth_data['ton_proof']['ton_proof']['payload']
|
||||
known_payload = (request.ctx.db_session.execute(select(KnownKey).where(KnownKey.seed == connection_payload))).scalars().first()
|
||||
known_payload = (await request.ctx.db_session.execute(select(KnownKey).where(KnownKey.seed == connection_payload))).scalars().first()
|
||||
assert known_payload, "Unknown payload"
|
||||
assert known_payload.meta['I_user_id'] == known_user.id, "Invalid user_id"
|
||||
assert wallet_info.check_proof(connection_payload), "Invalid proof"
|
||||
|
||||
for known_connection in (request.ctx.db_session.execute(select(WalletConnection).where(
|
||||
for known_connection in (await request.ctx.db_session.execute(select(WalletConnection).where(
|
||||
and_(
|
||||
WalletConnection.user_id == known_user.id,
|
||||
WalletConnection.network == 'ton'
|
||||
@@ -78,7 +82,7 @@ async def s_api_v1_auth_twa(request):
|
||||
))).scalars().all():
|
||||
known_connection.invalidated = True
|
||||
|
||||
for other_connection in (request.ctx.db_session.execute(select(WalletConnection).where(
|
||||
for other_connection in (await request.ctx.db_session.execute(select(WalletConnection).where(
|
||||
WalletConnection.wallet_address == Address(wallet_info.account.address).to_string(1, 1, 1)
|
||||
))).scalars().all():
|
||||
other_connection.invalidated = True
|
||||
@@ -99,12 +103,12 @@ async def s_api_v1_auth_twa(request):
|
||||
without_pk=False
|
||||
)
|
||||
request.ctx.db_session.add(new_connection)
|
||||
request.ctx.db_session.commit()
|
||||
await request.ctx.db_session.commit()
|
||||
except BaseException as e:
|
||||
make_log("auth", f"Invalid ton_proof: {e}", level="warning")
|
||||
return response.json({"error": "Invalid ton_proof"}, status=400)
|
||||
|
||||
ton_connection = (request.ctx.db_session.execute(select(WalletConnection).where(
|
||||
ton_connection = (await request.ctx.db_session.execute(select(WalletConnection).where(
|
||||
and_(
|
||||
WalletConnection.user_id == known_user.id,
|
||||
WalletConnection.network == 'ton',
|
||||
@@ -112,7 +116,7 @@ async def s_api_v1_auth_twa(request):
|
||||
)
|
||||
).order_by(WalletConnection.created.desc()))).scalars().first()
|
||||
known_user.last_use = datetime.now()
|
||||
request.ctx.db_session.commit()
|
||||
await request.ctx.db_session.commit()
|
||||
|
||||
return response.json({
|
||||
'user': known_user.json_format(),
|
||||
@@ -124,7 +128,7 @@ async def s_api_v1_auth_me(request):
|
||||
if not request.ctx.user:
|
||||
return response.json({"error": "Unauthorized"}, status=401)
|
||||
|
||||
ton_connection = (request.ctx.db_session.execute(
|
||||
ton_connection = (await request.ctx.db_session.execute(
|
||||
select(WalletConnection).where(
|
||||
and_(
|
||||
WalletConnection.user_id == request.ctx.user.id,
|
||||
@@ -132,7 +136,7 @@ async def s_api_v1_auth_me(request):
|
||||
WalletConnection.invalidated == False
|
||||
)
|
||||
).order_by(WalletConnection.created.desc())
|
||||
)).scalars().first()
|
||||
))).scalars().first()
|
||||
|
||||
return response.json({
|
||||
'user': request.ctx.user.json_format(),
|
||||
@@ -159,10 +163,12 @@ async def s_api_v1_auth_select_wallet(request):
|
||||
user = request.ctx.user
|
||||
|
||||
# Check if a WalletConnection already exists for this user with the given canonical wallet address
|
||||
existing_connection = db_session.query(WalletConnection).filter(
|
||||
WalletConnection.user_id == user.id,
|
||||
WalletConnection.wallet_address == canonical_address
|
||||
).first()
|
||||
existing_connection = (await db_session.execute(select(WalletConnection).where(
|
||||
and_(
|
||||
WalletConnection.user_id == user.id,
|
||||
WalletConnection.wallet_address == canonical_address
|
||||
)
|
||||
))).scalars().first()
|
||||
|
||||
if not existing_connection:
|
||||
return response.json({"error": "Wallet connection not found"}, status=404)
|
||||
@@ -185,6 +191,6 @@ async def s_api_v1_auth_select_wallet(request):
|
||||
without_pk=False
|
||||
)
|
||||
db_session.add(new_connection)
|
||||
db_session.commit()
|
||||
await db_session.commit()
|
||||
|
||||
return response.empty(status=200)
|
||||
+75
-36
@@ -1,5 +1,6 @@
|
||||
from datetime import datetime, timedelta
|
||||
from sanic import response
|
||||
from sqlalchemy import select, and_, func
|
||||
from aiogram import Bot, types
|
||||
from sqlalchemy import and_
|
||||
from app.core.logger import make_log
|
||||
@@ -22,13 +23,20 @@ async def s_api_v1_content_list(request):
|
||||
store = request.args.get('store', 'local')
|
||||
assert store in ('local', 'onchain'), "Invalid store"
|
||||
|
||||
content_list = request.ctx.db_session.query(StoredContent).filter(
|
||||
StoredContent.type.like(store + '%'),
|
||||
StoredContent.disabled == False
|
||||
).order_by(StoredContent.created.desc()).offset(offset).limit(limit)
|
||||
make_log("Content", f"Listed {content_list.count()} contents", level='info')
|
||||
stmt = (
|
||||
select(StoredContent)
|
||||
.where(
|
||||
StoredContent.type.like(store + '%'),
|
||||
StoredContent.disabled == False
|
||||
)
|
||||
.order_by(StoredContent.created.desc())
|
||||
.offset(offset)
|
||||
.limit(limit)
|
||||
)
|
||||
rows = (await request.ctx.db_session.execute(stmt)).scalars().all()
|
||||
make_log("Content", f"Listed {len(rows)} contents", level='info')
|
||||
result = {}
|
||||
for content in content_list.all():
|
||||
for content in rows:
|
||||
content_json = content.json_format()
|
||||
result[content_json["cid"]] = content_json
|
||||
|
||||
@@ -38,23 +46,41 @@ async def s_api_v1_content_list(request):
|
||||
async def s_api_v1_content_view(request, content_address: str):
|
||||
# content_address can be CID or TON address
|
||||
|
||||
license_exist = request.ctx.db_session.query(UserContent).filter_by(
|
||||
onchain_address=content_address,
|
||||
).first()
|
||||
license_exist = (await request.ctx.db_session.execute(
|
||||
select(UserContent).where(UserContent.onchain_address == content_address)
|
||||
)).scalars().first()
|
||||
if license_exist:
|
||||
content_address = license_exist.content.cid.serialize_v2()
|
||||
|
||||
r_content = StoredContent.from_cid(request.ctx.db_session, content_address)
|
||||
content = r_content.open_content(request.ctx.db_session)
|
||||
from app.core.content.content_id import ContentId
|
||||
cid = ContentId.deserialize(content_address)
|
||||
r_content = (await request.ctx.db_session.execute(
|
||||
select(StoredContent).where(StoredContent.hash == cid.content_hash_b58)
|
||||
)).scalars().first()
|
||||
async def open_content_async(session, sc: StoredContent):
|
||||
if not sc.encrypted:
|
||||
decrypted = sc
|
||||
encrypted = (await session.execute(select(StoredContent).where(StoredContent.decrypted_content_id == sc.id))).scalars().first()
|
||||
else:
|
||||
encrypted = sc
|
||||
decrypted = (await session.execute(select(StoredContent).where(StoredContent.id == sc.decrypted_content_id))).scalars().first()
|
||||
assert decrypted and encrypted, "Can't open content"
|
||||
ctype = decrypted.json_format().get('content_type', 'application/x-binary')
|
||||
try:
|
||||
content_type = ctype.split('/')[0]
|
||||
except Exception:
|
||||
content_type = 'application'
|
||||
return {'encrypted_content': encrypted, 'decrypted_content': decrypted, 'content_type': content_type}
|
||||
content = await open_content_async(request.ctx.db_session, r_content)
|
||||
|
||||
opts = {
|
||||
'content_type': content['content_type'], # возможно с ошибками, нужно переделать на ffprobe
|
||||
'content_address': content['encrypted_content'].meta.get('item_address', '')
|
||||
}
|
||||
if content['encrypted_content'].key_id:
|
||||
known_key = request.ctx.db_session.query(KnownKey).filter(
|
||||
KnownKey.id == content['encrypted_content'].key_id
|
||||
).first()
|
||||
known_key = (await request.ctx.db_session.execute(
|
||||
select(KnownKey).where(KnownKey.id == content['encrypted_content'].key_id)
|
||||
)).scalars().first()
|
||||
if known_key:
|
||||
opts['key_hash'] = known_key.seed_hash # нахер не нужно на данный момент
|
||||
|
||||
@@ -64,22 +90,23 @@ async def s_api_v1_content_view(request, content_address: str):
|
||||
|
||||
have_access = False
|
||||
if request.ctx.user:
|
||||
user_wallet_address = request.ctx.user.wallet_address(request.ctx.db_session)
|
||||
user_wallet_address = await request.ctx.user.wallet_address_async(request.ctx.db_session)
|
||||
have_access = (
|
||||
(content['encrypted_content'].owner_address == user_wallet_address)
|
||||
or bool(request.ctx.db_session.query(UserContent).filter_by(owner_address=user_wallet_address, status='active',
|
||||
content_id=content['encrypted_content'].id).first()) \
|
||||
or bool(request.ctx.db_session.query(StarsInvoice).filter(
|
||||
or bool((await request.ctx.db_session.execute(select(UserContent).where(
|
||||
and_(UserContent.owner_address == user_wallet_address, UserContent.status == 'active', UserContent.content_id == content['encrypted_content'].id)
|
||||
))).scalars().first()) \
|
||||
or bool((await request.ctx.db_session.execute(select(StarsInvoice).where(
|
||||
and_(
|
||||
StarsInvoice.user_id == request.ctx.user.id,
|
||||
StarsInvoice.content_hash == content['encrypted_content'].hash,
|
||||
StarsInvoice.paid == True
|
||||
)
|
||||
).first())
|
||||
))).scalars().first())
|
||||
)
|
||||
|
||||
if not have_access:
|
||||
current_star_rate = ServiceConfig(request.ctx.db_session).get('live_tonPerStar', [0, 0])[0]
|
||||
current_star_rate = (await ServiceConfig(request.ctx.db_session).get('live_tonPerStar', [0, 0]))[0]
|
||||
if current_star_rate < 0:
|
||||
current_star_rate = 0.00000001
|
||||
|
||||
@@ -88,14 +115,14 @@ async def s_api_v1_content_view(request, content_address: str):
|
||||
stars_cost = 2
|
||||
|
||||
invoice_id = f"access_{uuid.uuid4().hex}"
|
||||
exist_invoice = request.ctx.db_session.query(StarsInvoice).filter(
|
||||
exist_invoice = (await request.ctx.db_session.execute(select(StarsInvoice).where(
|
||||
and_(
|
||||
StarsInvoice.user_id == request.ctx.user.id,
|
||||
StarsInvoice.created > datetime.now() - timedelta(minutes=25),
|
||||
StarsInvoice.amount == stars_cost,
|
||||
StarsInvoice.content_hash == content['encrypted_content'].hash,
|
||||
)
|
||||
).first()
|
||||
))).scalars().first()
|
||||
if exist_invoice:
|
||||
invoice_url = exist_invoice.invoice_url
|
||||
else:
|
||||
@@ -119,7 +146,7 @@ async def s_api_v1_content_view(request, content_address: str):
|
||||
invoice_url=invoice_url
|
||||
)
|
||||
)
|
||||
request.ctx.db_session.commit()
|
||||
await request.ctx.db_session.commit()
|
||||
except BaseException as e:
|
||||
make_log("Content", f"Can't create invoice link: {e}", level='warning')
|
||||
|
||||
@@ -142,15 +169,20 @@ async def s_api_v1_content_view(request, content_address: str):
|
||||
if have_access:
|
||||
user_content_option = 'low' # TODO: подключать high если человек внезапно меломан
|
||||
|
||||
converted_content = request.ctx.db_session.query(StoredContent).filter(
|
||||
converted_content = (await request.ctx.db_session.execute(select(StoredContent).where(
|
||||
StoredContent.hash == converted_content[user_content_option]
|
||||
).first()
|
||||
))).scalars().first()
|
||||
if converted_content:
|
||||
display_options['content_url'] = converted_content.web_url
|
||||
opts['content_ext'] = converted_content.filename.split('.')[-1]
|
||||
|
||||
content_meta = content['encrypted_content'].json_format()
|
||||
content_metadata = StoredContent.from_cid(request.ctx.db_session, content_meta.get('metadata_cid') or None)
|
||||
from app.core.content.content_id import ContentId
|
||||
_mcid = content_meta.get('metadata_cid') or None
|
||||
content_metadata = None
|
||||
if _mcid:
|
||||
_cid = ContentId.deserialize(_mcid)
|
||||
content_metadata = (await request.ctx.db_session.execute(select(StoredContent).where(StoredContent.hash == _cid.content_hash_b58))).scalars().first()
|
||||
with open(content_metadata.filepath, 'r') as f:
|
||||
content_metadata_json = json.loads(f.read())
|
||||
|
||||
@@ -187,14 +219,17 @@ async def s_api_v1_content_friendly_list(request):
|
||||
</tr>
|
||||
</thead>
|
||||
"""
|
||||
for content in request.ctx.db_session.query(StoredContent).filter(
|
||||
contents = (await request.ctx.db_session.execute(select(StoredContent).where(
|
||||
StoredContent.type == 'onchain/content'
|
||||
).all():
|
||||
))).scalars().all()
|
||||
for content in contents:
|
||||
if not content.meta.get('metadata_cid'):
|
||||
make_log("Content", f"Content {content.cid.serialize_v2()} has no metadata", level='warning')
|
||||
continue
|
||||
|
||||
metadata_content = StoredContent.from_cid(request.ctx.db_session, content.meta.get('metadata_cid'))
|
||||
from app.core.content.content_id import ContentId
|
||||
_cid = ContentId.deserialize(content.meta.get('metadata_cid'))
|
||||
metadata_content = (await request.ctx.db_session.execute(select(StoredContent).where(StoredContent.hash == _cid.content_hash_b58))).scalars().first()
|
||||
with open(metadata_content.filepath, 'r') as f:
|
||||
metadata = json.loads(f.read())
|
||||
|
||||
@@ -228,10 +263,12 @@ async def s_api_v1_5_content_list(request):
|
||||
return response.json({'error': 'Invalid limit'}, status=400)
|
||||
|
||||
# Query onchain contents which are not disabled
|
||||
contents = request.ctx.db_session.query(StoredContent).filter(
|
||||
StoredContent.type == 'onchain/content',
|
||||
StoredContent.disabled == False
|
||||
).order_by(StoredContent.created.desc()).offset(offset).limit(limit).all()
|
||||
contents = (await request.ctx.db_session.execute(
|
||||
select(StoredContent)
|
||||
.where(StoredContent.type == 'onchain/content', StoredContent.disabled == False)
|
||||
.order_by(StoredContent.created.desc())
|
||||
.offset(offset).limit(limit)
|
||||
)).scalars().all()
|
||||
|
||||
result = []
|
||||
for content in contents:
|
||||
@@ -240,7 +277,9 @@ async def s_api_v1_5_content_list(request):
|
||||
if not metadata_cid:
|
||||
continue # Skip if no metadata_cid is found
|
||||
|
||||
metadata_content = StoredContent.from_cid(request.ctx.db_session, metadata_cid)
|
||||
from app.core.content.content_id import ContentId
|
||||
_cid = ContentId.deserialize(metadata_cid)
|
||||
metadata_content = (await request.ctx.db_session.execute(select(StoredContent).where(StoredContent.hash == _cid.content_hash_b58))).scalars().first()
|
||||
try:
|
||||
with open(metadata_content.filepath, 'r') as f:
|
||||
metadata = json.load(f)
|
||||
@@ -256,9 +295,9 @@ async def s_api_v1_5_content_list(request):
|
||||
preview_link = None
|
||||
converted_content = content.meta.get('converted_content')
|
||||
if converted_content:
|
||||
converted_content = request.ctx.db_session.query(StoredContent).filter(
|
||||
converted_content = (await request.ctx.db_session.execute(select(StoredContent).where(
|
||||
StoredContent.hash == converted_content['low_preview']
|
||||
).first()
|
||||
))).scalars().first()
|
||||
preview_link = converted_content.web_url
|
||||
if converted_content.filename.split('.')[-1] in ('mp4', 'mov'):
|
||||
media_type = 'video'
|
||||
|
||||
@@ -11,6 +11,7 @@ from sanic import response
|
||||
import json
|
||||
|
||||
from app.core._config import UPLOADS_DIR
|
||||
from sqlalchemy import select
|
||||
from app.core._utils.resolve_content import resolve_content
|
||||
from app.core.logger import make_log
|
||||
from app.core.models.node_storage import StoredContent
|
||||
@@ -52,7 +53,9 @@ async def s_api_v1_storage_post(request):
|
||||
try:
|
||||
file_hash_bin = hashlib.sha256(file_content).digest()
|
||||
file_hash = b58encode(file_hash_bin).decode()
|
||||
stored_content = request.ctx.db_session.query(StoredContent).filter(StoredContent.hash == file_hash).first()
|
||||
stored_content = (await request.ctx.db_session.execute(
|
||||
select(StoredContent).where(StoredContent.hash == file_hash)
|
||||
)).scalars().first()
|
||||
if stored_content:
|
||||
stored_cid = stored_content.cid.serialize_v1()
|
||||
stored_cid_v2 = stored_content.cid.serialize_v2()
|
||||
@@ -80,7 +83,7 @@ async def s_api_v1_storage_post(request):
|
||||
key_id=None,
|
||||
)
|
||||
request.ctx.db_session.add(new_content)
|
||||
request.ctx.db_session.commit()
|
||||
await request.ctx.db_session.commit()
|
||||
|
||||
file_path = os.path.join(UPLOADS_DIR, file_hash)
|
||||
async with aiofiles.open(file_path, "wb") as file:
|
||||
@@ -112,7 +115,9 @@ async def s_api_v1_storage_get(request, file_hash=None):
|
||||
return response.json({"error": errmsg}, status=400)
|
||||
|
||||
content_sha256 = b58encode(cid.content_hash).decode()
|
||||
content = request.ctx.db_session.query(StoredContent).filter(StoredContent.hash == content_sha256).first()
|
||||
content = (await request.ctx.db_session.execute(
|
||||
select(StoredContent).where(StoredContent.hash == content_sha256)
|
||||
)).scalars().first()
|
||||
if not content:
|
||||
return response.json({"error": "File not found"}, status=404)
|
||||
|
||||
@@ -139,7 +144,16 @@ async def s_api_v1_storage_get(request, file_hash=None):
|
||||
tempfile_path += "_mpeg" + (f"_{seconds_limit}" if seconds_limit else "")
|
||||
if not os.path.exists(tempfile_path):
|
||||
try:
|
||||
cover_content = StoredContent.from_cid(content.meta.get('cover_cid'))
|
||||
# Resolve cover content by CID (async)
|
||||
from app.core.content.content_id import ContentId
|
||||
try:
|
||||
_cid = ContentId.deserialize(content.meta.get('cover_cid'))
|
||||
_cover_hash = _cid.content_hash_b58
|
||||
cover_content = (await request.ctx.db_session.execute(
|
||||
select(StoredContent).where(StoredContent.hash == _cover_hash)
|
||||
)).scalars().first()
|
||||
except Exception:
|
||||
cover_content = None
|
||||
cover_tempfile_path = os.path.join(UPLOADS_DIR, f"tmp_{cover_content.hash}_jpeg")
|
||||
if not os.path.exists(cover_tempfile_path):
|
||||
cover_image = Image.open(cover_content.filepath)
|
||||
|
||||
@@ -11,6 +11,7 @@ from base58 import b58encode
|
||||
from sanic import response
|
||||
|
||||
from app.core.logger import make_log
|
||||
from sqlalchemy import select
|
||||
from app.core.models.node_storage import StoredContent
|
||||
from app.core._config import UPLOADS_DIR
|
||||
from app.core._utils.resolve_content import resolve_content
|
||||
@@ -130,7 +131,7 @@ async def s_api_v1_5_storage_post(request):
|
||||
return response.json({"error": "Failed to finalize file storage"}, status=500)
|
||||
|
||||
db_session = request.ctx.db_session
|
||||
existing = db_session.query(StoredContent).filter_by(hash=computed_hash_b58).first()
|
||||
existing = (await db_session.execute(select(StoredContent).where(StoredContent.hash == computed_hash_b58))).scalars().first()
|
||||
if existing:
|
||||
make_log("uploader_v1.5", f"File with hash {computed_hash_b58} already exists in DB", level="INFO")
|
||||
serialized_v2 = existing.cid.serialize_v2()
|
||||
@@ -156,7 +157,7 @@ async def s_api_v1_5_storage_post(request):
|
||||
created=datetime.utcnow()
|
||||
)
|
||||
db_session.add(new_content)
|
||||
db_session.commit()
|
||||
await db_session.commit()
|
||||
make_log("uploader_v1.5", f"New file stored and indexed for user {user_id} with hash {computed_hash_b58}", level="INFO")
|
||||
except Exception as e:
|
||||
make_log("uploader_v1.5", f"Database error: {e}", level="ERROR")
|
||||
@@ -191,7 +192,7 @@ async def s_api_v1_5_storage_get(request, file_hash):
|
||||
return response.json({"error": "File not found"}, status=404)
|
||||
|
||||
db_session = request.ctx.db_session
|
||||
stored = db_session.query(StoredContent).filter_by(hash=file_hash).first()
|
||||
stored = (await db_session.execute(select(StoredContent).where(StoredContent.hash == file_hash))).scalars().first()
|
||||
if stored and stored.filename:
|
||||
filename_for_mime = stored.filename
|
||||
else:
|
||||
|
||||
@@ -4,6 +4,7 @@ from aiogram.utils.web_app import safe_parse_webapp_init_data
|
||||
from sanic import response
|
||||
|
||||
from app.core._blockchain.ton.connect import TonConnect, unpack_wallet_info, WalletConnection
|
||||
from sqlalchemy import select, and_
|
||||
from app.core._config import TELEGRAM_API_KEY
|
||||
from app.core.models.user import User
|
||||
from app.core.logger import make_log
|
||||
@@ -23,8 +24,19 @@ async def s_api_v1_tonconnect_new(request):
|
||||
db_session = request.ctx.db_session
|
||||
user = request.ctx.user
|
||||
memory = request.ctx.memory
|
||||
ton_connect, ton_connection = TonConnect.by_user(db_session, user)
|
||||
await ton_connect.restore_connection()
|
||||
# Try restore last connection from DB
|
||||
ton_connection = (await db_session.execute(select(WalletConnection).where(
|
||||
and_(
|
||||
WalletConnection.user_id == user.id,
|
||||
WalletConnection.invalidated == False,
|
||||
WalletConnection.network == 'ton'
|
||||
)
|
||||
).order_by(WalletConnection.created.desc()))).scalars().first()
|
||||
if ton_connection:
|
||||
ton_connect = TonConnect.by_key(ton_connection.keys["connection_key"])
|
||||
await ton_connect.restore_connection()
|
||||
else:
|
||||
ton_connect = TonConnect()
|
||||
make_log("TonConnect_API", f"SDK connected?: {ton_connect.connected}", level='info')
|
||||
if ton_connect.connected:
|
||||
return response.json({"error": "Already connected"}, status=400)
|
||||
@@ -47,13 +59,11 @@ async def s_api_v1_tonconnect_logout(request):
|
||||
user = request.ctx.user
|
||||
memory = request.ctx.memory
|
||||
|
||||
wallet_connections = db_session.query(WalletConnection).filter(
|
||||
WalletConnection.user_id == user.id,
|
||||
WalletConnection.invalidated == False
|
||||
).all()
|
||||
result = await db_session.execute(select(WalletConnection).where(
|
||||
and_(WalletConnection.user_id == user.id, WalletConnection.invalidated == False)
|
||||
))
|
||||
wallet_connections = result.scalars().all()
|
||||
for wallet_connection in wallet_connections:
|
||||
wallet_connection.invalidated = True
|
||||
|
||||
db_session.commit()
|
||||
await db_session.commit()
|
||||
return response.json({"success": True})
|
||||
|
||||
Reference in new issue
Block a user