Merge pull request #18 from machka-pasla/codex/implement-user-creation-and-subscription-updates

Improve panel user handling and promo code activation
This commit is contained in:
Machka Pasla
2025-06-26 01:28:36 +03:00
committed by GitHub
3 changed files with 63 additions and 39 deletions
+1 -6
View File
@@ -5,7 +5,7 @@ from aiogram import Bot
from config.settings import Settings
from db.dal import promo_code_dal, user_dal, subscription_dal
from db.dal import promo_code_dal, user_dal
from db.models import PromoCode, User
from .subscription_service import SubscriptionService
@@ -40,11 +40,6 @@ class PromoCodeService:
return False, _("promo_code_already_used_by_user",
code=code_input_upper)
active_sub = await subscription_dal.get_active_subscription_by_user_id(
session, user_id)
if not active_sub:
return False, _("promo_code_no_active_subscription")
bonus_days = promo_data.bonus_days
new_end_date = await self.subscription_service.extend_active_subscription_days(
+47 -33
View File
@@ -520,36 +520,63 @@ class SubscriptionService:
reason: str = "bonus",
) -> Optional[datetime]:
user = await user_dal.get_user_by_id(session, user_id)
if not user or not user.panel_user_uuid:
if not user:
logging.warning(
f"Cannot extend subscription for user {user_id}: User or panel_user_uuid not found."
f"Cannot extend subscription for user {user_id}: user not found."
)
return None
panel_uuid, panel_sub_uuid, _, _ = await self._get_or_create_panel_user_link_details(
session, user_id, user
)
if not panel_uuid or not panel_sub_uuid:
logging.error(
f"Failed to ensure panel user for subscription extension of user {user_id}."
)
return None
active_sub = await subscription_dal.get_active_subscription_by_user_id(
session, user_id, user.panel_user_uuid
session, user_id, panel_uuid
)
if not active_sub or not active_sub.end_date:
logging.info(
f"No active extendable subscription found for user {user_id} (panel: {user.panel_user_uuid}) for reason: {reason}."
f"No active subscription found for user {user_id}. Creating new one for {bonus_days} days.""
)
return None
start_date = datetime.now(timezone.utc)
new_end_date_obj = start_date + timedelta(days=bonus_days)
bonus_sub_payload = {
"user_id": user_id,
"panel_user_uuid": panel_uuid,
"panel_subscription_uuid": panel_sub_uuid,
"start_date": start_date,
"end_date": new_end_date_obj,
"duration_months": 0,
"is_active": True,
"status_from_panel": "ACTIVE_BONUS",
"traffic_limit_bytes": self.settings.PANEL_USER_DEFAULT_TRAFFIC_BYTES,
}
await subscription_dal.deactivate_other_active_subscriptions(
session, panel_uuid, panel_sub_uuid
)
updated_sub_model = await subscription_dal.upsert_subscription(
session, bonus_sub_payload
)
else:
current_end_date = active_sub.end_date
now_utc = datetime.now(timezone.utc)
start_point_for_bonus = (
current_end_date if current_end_date > now_utc else now_utc
)
new_end_date_obj = start_point_for_bonus + timedelta(days=bonus_days)
current_end_date = active_sub.end_date
now_utc = datetime.now(timezone.utc)
start_point_for_bonus = (
current_end_date if current_end_date > now_utc else now_utc
)
new_end_date_obj = start_point_for_bonus + timedelta(days=bonus_days)
updated_sub_model = await subscription_dal.update_subscription_end_date(
session, active_sub.subscription_id, new_end_date_obj
)
updated_sub_model = await subscription_dal.update_subscription_end_date(
session, active_sub.subscription_id, new_end_date_obj
)
if updated_sub_model:
panel_update_success = (
await self.panel_service.update_user_details_on_panel(
user.panel_user_uuid,
panel_uuid,
{
"expireAt": new_end_date_obj.isoformat(
timespec="milliseconds"
@@ -559,7 +586,7 @@ class SubscriptionService:
)
if not panel_update_success:
logging.warning(
f"Panel expiry update failed for {user.panel_user_uuid} after {reason} bonus. Local DB was updated to {new_end_date_obj}."
f"Panel expiry update failed for {panel_uuid} after {reason} bonus. Local DB was updated to {new_end_date_obj}."
)
logging.info(
@@ -590,23 +617,10 @@ class SubscriptionService:
if not panel_user_data:
logging.warning(
f"Panel user {panel_user_uuid} not found on panel for user {user_id}. Using local data if available."
f"Panel user {panel_user_uuid} not found on panel for user {user_id}. Clearing local linkage."
)
if (
local_active_sub
and local_active_sub.end_date
and local_active_sub.end_date > datetime.now(timezone.utc)
):
return {
"end_date": local_active_sub.end_date,
"status_from_panel": local_active_sub.status_from_panel
or "UNKNOWN",
"config_link": None,
"traffic_limit_bytes": local_active_sub.traffic_limit_bytes,
"traffic_used_bytes": local_active_sub.traffic_used_bytes,
"user_bot_username": db_user.username,
"is_panel_data": False,
}
await subscription_dal.deactivate_all_user_subscriptions(session, user_id)
await user_dal.update_user(session, user_id, {"panel_user_uuid": None})
return None
if local_active_sub:
+15
View File
@@ -129,6 +129,21 @@ async def deactivate_other_active_subscriptions(
)
async def deactivate_all_user_subscriptions(
session: AsyncSession, user_id: int) -> int:
stmt = (
update(Subscription)
.where(Subscription.user_id == user_id, Subscription.is_active == True)
.values(is_active=False, status_from_panel="INACTIVE_USER_NOT_FOUND")
)
result = await session.execute(stmt)
if result.rowcount > 0:
logging.info(
f"Deactivated {result.rowcount} subscriptions for user {user_id} due to missing panel user."
)
return result.rowcount
async def update_subscription_end_date(
session: AsyncSession, subscription_id: int,
new_end_date: datetime) -> Optional[Subscription]: