Migrating to Postgres from sqlite3
This commit is contained in:
@@ -1,48 +1,39 @@
|
||||
import logging
|
||||
import aiosqlite
|
||||
from typing import Optional, Dict, Callable, Any, TYPE_CHECKING, Tuple
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from typing import Optional, Dict, Any
|
||||
from aiogram import Bot
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone, timedelta
|
||||
|
||||
from config.settings import Settings
|
||||
from db.database import get_user
|
||||
from db.dal import user_dal
|
||||
from db.models import User
|
||||
from db.dal import subscription_dal
|
||||
from bot.middlewares.i18n import JsonI18n
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .subscription_service import SubscriptionService
|
||||
from .subscription_service import SubscriptionService
|
||||
|
||||
|
||||
class ReferralService:
|
||||
|
||||
def __init__(self, db_conn_provider: Callable[[], Any], settings: Settings,
|
||||
subscription_service_instance: 'SubscriptionService',
|
||||
bot: Bot, i18n: JsonI18n):
|
||||
self.db_conn_provider = db_conn_provider
|
||||
def __init__(self, settings: Settings,
|
||||
subscription_service: SubscriptionService, bot: Bot,
|
||||
i18n: JsonI18n):
|
||||
self.settings = settings
|
||||
self.subscription_service = subscription_service_instance
|
||||
self.subscription_service = subscription_service
|
||||
self.bot = bot
|
||||
self.i18n = i18n
|
||||
|
||||
async def process_new_user_referral(self, referee_user_id: int,
|
||||
inviter_user_id: Optional[int]):
|
||||
if inviter_user_id and referee_user_id != inviter_user_id:
|
||||
|
||||
logging.info(
|
||||
f"Referral link used: User {referee_user_id} was invited by {inviter_user_id}."
|
||||
)
|
||||
|
||||
pass
|
||||
|
||||
async def apply_referral_bonuses_for_payment(
|
||||
self, referee_user_id: int, purchased_subscription_months: int,
|
||||
db_conn: aiosqlite.Connection) -> Dict[str, Any]:
|
||||
"""Applies bonuses. Notifies inviter. Returns referee bonus details."""
|
||||
self, session: AsyncSession, referee_user_id: int,
|
||||
purchased_subscription_months: int) -> Dict[str, Any]:
|
||||
|
||||
referee_final_end_date: Optional[datetime] = None
|
||||
referee_bonus_applied_days: Optional[int] = None
|
||||
inviter_bonus_successfully_applied = False
|
||||
|
||||
try:
|
||||
referee_user_row = await get_user(referee_user_id, db_conn=db_conn)
|
||||
if not referee_user_row or referee_user_row[
|
||||
'referred_by_id'] is None:
|
||||
referee_user_model = await user_dal.get_user_by_id(
|
||||
session, referee_user_id)
|
||||
if not referee_user_model or referee_user_model.referred_by_id is None:
|
||||
logging.debug(
|
||||
f"User {referee_user_id} not referred or inviter ID missing. No referral bonuses."
|
||||
)
|
||||
@@ -51,75 +42,177 @@ class ReferralService:
|
||||
"referee_new_end_date": None
|
||||
}
|
||||
|
||||
inviter_user_id = referee_user_row['referred_by_id']
|
||||
inviter_user_row = await get_user(inviter_user_id, db_conn=db_conn)
|
||||
inviter_user_id = referee_user_model.referred_by_id
|
||||
inviter_user_model = await user_dal.get_user_by_id(
|
||||
session, inviter_user_id)
|
||||
|
||||
referee_name = referee_user_row[
|
||||
'first_name'] or f"User {referee_user_id}"
|
||||
referee_name_for_msg = referee_user_model.first_name or f"User {referee_user_id}"
|
||||
|
||||
default_lang_for_placeholder = getattr(self.settings,
|
||||
'DEFAULT_LANGUAGE', 'en')
|
||||
inviter_name = inviter_user_row[
|
||||
'first_name'] if inviter_user_row else self.i18n.gettext(
|
||||
default_lang_for_placeholder, "friend_placeholder")
|
||||
default_lang_for_placeholder = self.settings.DEFAULT_LANGUAGE
|
||||
inviter_name_for_referee_msg = (
|
||||
inviter_user_model.first_name if inviter_user_model
|
||||
and inviter_user_model.first_name else self.i18n.gettext(
|
||||
default_lang_for_placeholder, "friend_placeholder"))
|
||||
|
||||
inviter_bonus = self.settings.referral_bonus_inviter.get(
|
||||
inviter_bonus_days = self.settings.referral_bonus_inviter.get(
|
||||
purchased_subscription_months)
|
||||
referee_bonus = self.settings.referral_bonus_referee.get(
|
||||
referee_bonus_days = self.settings.referral_bonus_referee.get(
|
||||
purchased_subscription_months)
|
||||
|
||||
if inviter_bonus and inviter_bonus > 0 and inviter_user_row:
|
||||
new_end_date_inviter = await self.subscription_service.extend_subscription_for_referral(
|
||||
user_id=inviter_user_id,
|
||||
bonus_days=inviter_bonus,
|
||||
db_conn=db_conn)
|
||||
if new_end_date_inviter:
|
||||
logging.info(
|
||||
f"Bonus applied for inviter {inviter_user_id}.")
|
||||
try:
|
||||
inviter_lang = inviter_user_row.get(
|
||||
'language_code', default_lang_for_placeholder)
|
||||
_i = lambda k, **kw: self.i18n.gettext(
|
||||
inviter_lang, k, **kw)
|
||||
await self.bot.send_message(
|
||||
inviter_user_id,
|
||||
_i("referral_bonus_inviter_notification_extended",
|
||||
days=inviter_bonus,
|
||||
referee_name=referee_name,
|
||||
new_end_date=new_end_date_inviter.strftime(
|
||||
'%Y-%m-%d')))
|
||||
except Exception as e:
|
||||
logging.error(
|
||||
f"Failed to send bonus notification to inviter {inviter_user_id}: {e}"
|
||||
)
|
||||
else:
|
||||
if inviter_bonus_days and inviter_bonus_days > 0:
|
||||
if not inviter_user_model:
|
||||
|
||||
logging.warning(
|
||||
f"Failed to apply bonus subscription extension for inviter {inviter_user_id}."
|
||||
f"Inviter user {inviter_user_id} not found in local DB. Cannot apply inviter bonus."
|
||||
)
|
||||
|
||||
if referee_bonus and referee_bonus > 0:
|
||||
new_end_date_referee = await self.subscription_service.extend_subscription_for_referral(
|
||||
user_id=referee_user_id,
|
||||
bonus_days=referee_bonus,
|
||||
db_conn=db_conn,
|
||||
is_referee_bonus=True)
|
||||
if new_end_date_referee:
|
||||
logging.info(
|
||||
f"Bonus applied for referee {referee_user_id}.")
|
||||
referee_final_end_date = new_end_date_referee
|
||||
referee_bonus_applied_days = referee_bonus
|
||||
else:
|
||||
|
||||
inviter_panel_uuid, inviter_panel_sub_link_id, _, _ = await self.subscription_service._get_or_create_panel_user_link_details(
|
||||
session, inviter_user_id, inviter_user_model)
|
||||
|
||||
if not inviter_panel_uuid:
|
||||
logging.warning(
|
||||
f"Failed to get/create panel link for inviter {inviter_user_id}. Cannot apply inviter bonus directly to panel."
|
||||
)
|
||||
|
||||
else:
|
||||
new_end_date_inviter = await self.subscription_service.extend_active_subscription_days(
|
||||
session=session,
|
||||
user_id=inviter_user_id,
|
||||
bonus_days=inviter_bonus_days,
|
||||
reason=f"referral bonus from {referee_name_for_msg}"
|
||||
)
|
||||
|
||||
if new_end_date_inviter:
|
||||
inviter_bonus_successfully_applied = True
|
||||
logging.info(
|
||||
f"Bonus of {inviter_bonus_days} days successfully applied/extended for inviter {inviter_user_id}."
|
||||
)
|
||||
|
||||
try:
|
||||
inviter_lang = inviter_user_model.language_code or default_lang_for_placeholder
|
||||
_i = lambda k, **kw: self.i18n.gettext(
|
||||
inviter_lang, k, **kw)
|
||||
await self.bot.send_message(
|
||||
inviter_user_id,
|
||||
_i("referral_bonus_inviter_notification_extended",
|
||||
days=inviter_bonus_days,
|
||||
referee_name=referee_name_for_msg,
|
||||
new_end_date=new_end_date_inviter.
|
||||
strftime('%Y-%m-%d')))
|
||||
except Exception as e_notify_inviter:
|
||||
logging.error(
|
||||
f"Failed to send bonus notification to inviter {inviter_user_id}: {e_notify_inviter}"
|
||||
)
|
||||
else:
|
||||
|
||||
logging.info(
|
||||
f"Inviter {inviter_user_id} has no active sub to extend. Creating new bonus subscription for {inviter_bonus_days} days."
|
||||
)
|
||||
|
||||
bonus_start_date = datetime.now(timezone.utc)
|
||||
bonus_end_date = bonus_start_date + timedelta(
|
||||
days=inviter_bonus_days)
|
||||
|
||||
if not inviter_panel_sub_link_id:
|
||||
logging.error(
|
||||
f"Cannot create bonus subscription for inviter {inviter_user_id}: panel_sub_link_id is missing even after link detail fetch."
|
||||
)
|
||||
else:
|
||||
bonus_sub_payload = {
|
||||
"user_id":
|
||||
inviter_user_id,
|
||||
"panel_user_uuid":
|
||||
inviter_panel_uuid,
|
||||
"panel_subscription_uuid":
|
||||
inviter_panel_sub_link_id,
|
||||
"start_date":
|
||||
bonus_start_date,
|
||||
"end_date":
|
||||
bonus_end_date,
|
||||
"duration_months":
|
||||
0,
|
||||
"is_active":
|
||||
True,
|
||||
"status_from_panel":
|
||||
"ACTIVE_BONUS",
|
||||
"traffic_limit_bytes":
|
||||
self.settings.
|
||||
PANEL_USER_DEFAULT_TRAFFIC_BYTES,
|
||||
}
|
||||
try:
|
||||
await subscription_dal.deactivate_other_active_subscriptions(
|
||||
session, inviter_panel_uuid,
|
||||
inviter_panel_sub_link_id)
|
||||
bonus_sub = await subscription_dal.upsert_subscription(
|
||||
session, bonus_sub_payload)
|
||||
|
||||
panel_update_success = await self.subscription_service.panel_service.update_user_details_on_panel(
|
||||
inviter_panel_uuid, {
|
||||
"expireAt":
|
||||
bonus_end_date.isoformat(
|
||||
timespec='milliseconds').
|
||||
replace('+00:00', 'Z'),
|
||||
"status":
|
||||
"ACTIVE",
|
||||
})
|
||||
if panel_update_success:
|
||||
inviter_bonus_successfully_applied = True
|
||||
logging.info(
|
||||
f"New bonus subscription for {inviter_bonus_days} days created for inviter {inviter_user_id}."
|
||||
)
|
||||
|
||||
inviter_lang = inviter_user_model.language_code or default_lang_for_placeholder
|
||||
_i = lambda k, **kw: self.i18n.gettext(
|
||||
inviter_lang, k, **kw)
|
||||
await self.bot.send_message(
|
||||
inviter_user_id,
|
||||
_i("referral_bonus_inviter_notification_new_sub",
|
||||
days=inviter_bonus_days,
|
||||
referee_name=
|
||||
referee_name_for_msg,
|
||||
new_end_date=bonus_end_date.
|
||||
strftime('%Y-%m-%d')))
|
||||
else:
|
||||
logging.warning(
|
||||
f"Failed to update panel for new bonus subscription for inviter {inviter_user_id}. Local bonus sub created (ID: {bonus_sub.subscription_id}) but may not be active on panel."
|
||||
)
|
||||
|
||||
except Exception as e_create_bonus_sub:
|
||||
logging.error(
|
||||
f"Failed to create new bonus subscription for inviter {inviter_user_id}: {e_create_bonus_sub}",
|
||||
exc_info=True)
|
||||
|
||||
if referee_bonus_days and referee_bonus_days > 0:
|
||||
|
||||
new_end_date_referee = await self.subscription_service.extend_active_subscription_days(
|
||||
session=session,
|
||||
user_id=referee_user_id,
|
||||
bonus_days=referee_bonus_days,
|
||||
reason=
|
||||
f"referee bonus (invited by {inviter_name_for_referee_msg})"
|
||||
)
|
||||
if new_end_date_referee:
|
||||
referee_final_end_date = new_end_date_referee
|
||||
referee_bonus_applied_days = referee_bonus_days
|
||||
logging.info(
|
||||
f"Bonus of {referee_bonus_days} days successfully applied to referee {referee_user_id}."
|
||||
)
|
||||
else:
|
||||
|
||||
logging.warning(
|
||||
f"Failed to apply bonus subscription extension for referee {referee_user_id}."
|
||||
f"Failed to apply referee bonus for {referee_user_id} (could not extend their new subscription)."
|
||||
)
|
||||
|
||||
return {
|
||||
"referee_bonus_applied_days": referee_bonus_applied_days,
|
||||
"referee_new_end_date": referee_final_end_date
|
||||
"referee_new_end_date": referee_final_end_date,
|
||||
"inviter_bonus_applied_flag":
|
||||
inviter_bonus_successfully_applied
|
||||
}
|
||||
except Exception as e:
|
||||
logging.error(
|
||||
f"Error in apply_referral_bonuses_for_payment (db_conn: {db_conn is not None}): {e}",
|
||||
f"Error in apply_referral_bonuses_for_payment for referee {referee_user_id}: {e}",
|
||||
exc_info=True)
|
||||
|
||||
raise
|
||||
|
||||
Reference in New Issue
Block a user