128 lines
5.8 KiB
Python
128 lines
5.8 KiB
Python
import logging
|
|
import hmac
|
|
import hashlib
|
|
import json
|
|
from aiohttp import web
|
|
from aiogram import Bot
|
|
from sqlalchemy.orm import sessionmaker
|
|
|
|
from config.settings import Settings
|
|
from bot.middlewares.i18n import JsonI18n
|
|
from bot.services.subscription_service import SubscriptionService
|
|
from bot.services.panel_api_service import PanelApiService
|
|
from bot.services.referral_service import ReferralService
|
|
from db.dal import payment_dal, user_dal, subscription_dal
|
|
|
|
async def tribute_webhook_route(request: web.Request):
|
|
bot: Bot = request.app['bot']
|
|
settings: Settings = request.app['settings']
|
|
i18n: JsonI18n = request.app['i18n']
|
|
async_session_factory: sessionmaker = request.app['async_session_factory']
|
|
panel_service: PanelApiService = request.app['panel_service']
|
|
subscription_service: SubscriptionService = request.app['subscription_service']
|
|
referral_service: ReferralService = request.app['referral_service']
|
|
|
|
raw_body = await request.read()
|
|
signature_header = request.headers.get('trbt-signature')
|
|
if settings.TRIBUTE_API_KEY:
|
|
if not signature_header:
|
|
return web.Response(status=403, text="no_signature")
|
|
expected_sig = hmac.new(
|
|
settings.TRIBUTE_API_KEY.encode(), raw_body, hashlib.sha256
|
|
).hexdigest()
|
|
if not hmac.compare_digest(expected_sig, signature_header):
|
|
return web.Response(status=403, text="invalid_signature")
|
|
|
|
try:
|
|
payload = json.loads(raw_body.decode())
|
|
except Exception:
|
|
return web.Response(status=400, text="bad_request")
|
|
|
|
event_name = payload.get('name')
|
|
data = payload.get('payload', {})
|
|
user_id = data.get('telegram_user_id')
|
|
price_val = data.get('price')
|
|
|
|
if not user_id or price_val is None:
|
|
return web.Response(status=200, text="ok_missing_fields")
|
|
|
|
months_map = {int(v): m for m, v in settings.subscription_options.items()}
|
|
price_rub = price_val / 100
|
|
months = months_map.get(int(price_rub))
|
|
if not months:
|
|
logging.warning(f"Tribute webhook: price {price_val} not mapped to months")
|
|
return web.Response(status=200, text="ok_price_unmapped")
|
|
|
|
async with async_session_factory() as session:
|
|
if event_name == 'new_subscription':
|
|
payment_record = await payment_dal.create_payment_record(
|
|
session,
|
|
{
|
|
'user_id': user_id,
|
|
'amount': float(price_rub),
|
|
'currency': 'RUB',
|
|
'status': 'succeeded',
|
|
'description': 'Tribute subscription',
|
|
'subscription_duration_months': months,
|
|
'provider_payment_id': str(data.get('subscription_id')),
|
|
'provider': 'tribute',
|
|
},
|
|
)
|
|
activation_details = await subscription_service.activate_subscription(
|
|
session,
|
|
user_id,
|
|
months,
|
|
float(price_rub),
|
|
payment_record.payment_id,
|
|
provider='tribute',
|
|
)
|
|
referral_bonus = await referral_service.apply_referral_bonuses_for_payment(
|
|
session, user_id, months
|
|
)
|
|
await session.commit()
|
|
|
|
db_user = await user_dal.get_user_by_id(session, user_id)
|
|
lang = db_user.language_code if db_user and db_user.language_code else settings.DEFAULT_LANGUAGE
|
|
_ = lambda k, **kw: i18n.gettext(lang, k, **kw)
|
|
|
|
applied_ref_days = referral_bonus.get('referee_bonus_applied_days') if referral_bonus else None
|
|
final_end = referral_bonus.get('referee_new_end_date') if referral_bonus else activation_details.get('end_date')
|
|
|
|
if final_end:
|
|
if applied_ref_days:
|
|
inviter_name_display = _('friend_placeholder')
|
|
if db_user and db_user.referred_by_id:
|
|
inviter = await user_dal.get_user_by_id(session, db_user.referred_by_id)
|
|
if inviter and inviter.first_name:
|
|
inviter_name_display = inviter.first_name
|
|
elif inviter and inviter.username:
|
|
inviter_name_display = f"@{inviter.username}"
|
|
success_msg = _("payment_successful_with_referral_bonus",
|
|
months=months,
|
|
base_end_date=activation_details["end_date"].strftime('%Y-%m-%d'),
|
|
bonus_days=applied_ref_days,
|
|
final_end_date=final_end.strftime('%Y-%m-%d'),
|
|
inviter_name=inviter_name_display)
|
|
else:
|
|
success_msg = _("payment_successful", months=months,
|
|
end_date=final_end.strftime('%Y-%m-%d'))
|
|
|
|
try:
|
|
await bot.send_message(user_id, success_msg)
|
|
except Exception as e:
|
|
logging.error(f"Failed to send Tribute payment success message to user {user_id}: {e}")
|
|
elif event_name == 'cancelled_subscription':
|
|
db_user = await user_dal.get_user_by_id(session, user_id)
|
|
lang = db_user.language_code if db_user and db_user.language_code else settings.DEFAULT_LANGUAGE
|
|
_ = lambda k, **kw: i18n.gettext(lang, k, **kw)
|
|
try:
|
|
await bot.send_message(user_id, _("subscription_cancelled_notification"))
|
|
except Exception as e:
|
|
logging.warning(f"Failed to notify user {user_id} about cancellation: {e}")
|
|
await subscription_dal.set_skip_notifications_for_provider(
|
|
session, user_id, 'tribute', False)
|
|
await session.commit()
|
|
else:
|
|
await session.commit()
|
|
return web.Response(status=200, text="ok")
|