165 lines
11 KiB
Python
165 lines
11 KiB
Python
import logging
|
|
from aiogram import Router ,F ,types ,Bot
|
|
from aiogram .filters import CommandStart ,Command
|
|
from aiogram .fsm .context import FSMContext
|
|
from typing import Optional ,Dict ,Any ,Callable ,Awaitable
|
|
from datetime import datetime ,timezone ,timedelta
|
|
|
|
from db .database import add_user_if_not_exists ,update_user_language_code
|
|
from bot .keyboards .inline .user_keyboards import get_main_menu_inline_keyboard ,get_language_selection_keyboard
|
|
from bot .services .subscription_service import SubscriptionService
|
|
from bot .services .panel_api_service import PanelApiService
|
|
from bot .services .referral_service import ReferralService
|
|
from bot .services .promo_code_service import PromoCodeService
|
|
from config .settings import Settings
|
|
from bot .middlewares .i18n import JsonI18n
|
|
from aiogram .types import InlineKeyboardMarkup
|
|
|
|
router =Router (name ="user_start_router")
|
|
|
|
async def send_main_menu (message_or_callback :types .Message |types .CallbackQuery ,settings :Settings ,i18n_data :dict ,show_trial_button_flag :bool ,is_edit :bool =False ):
|
|
current_lang =i18n_data .get ("current_language",getattr (settings ,'DEFAULT_LANGUAGE','en'))
|
|
i18n :Optional [JsonI18n ]=i18n_data .get ("i18n_instance")
|
|
answered_callback_internally =False
|
|
|
|
if not i18n :
|
|
logging .error ("i18n_instance missing in send_main_menu")
|
|
target_mc_for_error =message_or_callback if isinstance (message_or_callback ,types .Message )else message_or_callback .message
|
|
error_text_fallback ="Error: Language service unavailable."
|
|
if target_mc_for_error :
|
|
try :await target_mc_for_error .answer (error_text_fallback )
|
|
except Exception as e_ans :logging .error (f"Failed to send error message in send_main_menu: {e_ans}")
|
|
if isinstance (message_or_callback ,types .CallbackQuery ):await message_or_callback .answer ();answered_callback_internally =True
|
|
return
|
|
|
|
_ =lambda key ,**kwargs :i18n .gettext (current_lang ,key ,**kwargs )
|
|
user_full_name =message_or_callback .from_user .full_name
|
|
text =_ (key ="main_menu_greeting",user_name =user_full_name )
|
|
reply_markup :Optional [InlineKeyboardMarkup ]=get_main_menu_inline_keyboard (current_lang ,i18n ,settings ,show_trial_button_flag )
|
|
target_message :Optional [types .Message ]=None
|
|
if isinstance (message_or_callback ,types .Message ):target_message =message_or_callback
|
|
elif isinstance (message_or_callback ,types .CallbackQuery ):target_message =message_or_callback .message
|
|
|
|
if not target_message :
|
|
logging .error (f"send_main_menu: target_message is None for event from user {message_or_callback.from_user.id}.")
|
|
if isinstance (message_or_callback ,types .CallbackQuery )and not answered_callback_internally :await message_or_callback .answer ("Error displaying menu.");answered_callback_internally =True
|
|
return
|
|
|
|
try :
|
|
if is_edit :
|
|
await target_message .edit_text (text ,reply_markup =reply_markup )
|
|
else :
|
|
await target_message .answer (text ,reply_markup =reply_markup )
|
|
|
|
if isinstance (message_or_callback ,types .CallbackQuery )and not answered_callback_internally :
|
|
await message_or_callback .answer ()
|
|
answered_callback_internally =True
|
|
except Exception as e_send_edit :
|
|
logging .warning (f"Failed to send/edit main menu (user: {message_or_callback.from_user.id}): {e_send_edit}.")
|
|
if is_edit :
|
|
try :await target_message .answer (text ,reply_markup =reply_markup )
|
|
except Exception as e_send_new :logging .error (f"Also failed to send new main menu message: {e_send_new}")
|
|
if isinstance (message_or_callback ,types .CallbackQuery )and not answered_callback_internally :
|
|
await message_or_callback .answer ()
|
|
answered_callback_internally =True
|
|
|
|
|
|
if isinstance (message_or_callback ,types .CallbackQuery )and not answered_callback_internally :
|
|
logging .warning (f"Callback {message_or_callback.id} was not answered in send_main_menu main logic paths.")
|
|
await message_or_callback .answer ()
|
|
|
|
|
|
@router .message (CommandStart ())
|
|
async def start_command_handler (message :types .Message ,state :FSMContext ,settings :Settings ,i18n_data :dict ,subscription_service :SubscriptionService ,bot :Bot ):
|
|
|
|
await state .clear ();current_lang =i18n_data .get ("current_language",settings .DEFAULT_LANGUAGE )
|
|
i18n :Optional [JsonI18n ]=i18n_data .get ("i18n_instance")
|
|
if not i18n :logging .error ("i18n_instance not found");await message .answer ("Language service error.");return
|
|
_ =lambda key ,**kwargs :i18n .gettext (current_lang ,key ,**kwargs )
|
|
user_id =message .from_user .id ;referred_by_user_id :Optional [int ]=None ;args =message .text .split ()
|
|
if len (args )>1 and args [0 ]=="/start":
|
|
try :
|
|
referral_param =args [1 ]
|
|
if referral_param .startswith ("ref_")and referral_param .split ("_")[1 ].isdigit ():
|
|
potential_referrer_id =int (referral_param .split ("_")[1 ])
|
|
if potential_referrer_id !=user_id :referred_by_user_id =potential_referrer_id
|
|
except (ValueError ,IndexError )as e :logging .warning (f"Could not parse referral: '{args[1]}' - {e}")
|
|
db_op_success ,was_new_bot_user =await add_user_if_not_exists (user_id =user_id ,username =message .from_user .username ,first_name =message .from_user .first_name ,last_name =message .from_user .last_name ,lang_code =current_lang ,referred_by_id =referred_by_user_id )
|
|
if not db_op_success :await message .answer (_ ("error_occurred_processing_request"));return
|
|
if referred_by_user_id :logging .info (f"User {user_id} started with referral from {referred_by_user_id}.")
|
|
await message .answer (_ (key ="welcome",user_name =message .from_user .full_name ))
|
|
show_trial_button_in_menu =False
|
|
if settings .TRIAL_ENABLED :
|
|
if not await subscription_service .has_had_any_subscription (user_id ):
|
|
show_trial_button_in_menu =True
|
|
logging .info (f"User {user_id} is eligible for a trial button.")
|
|
|
|
else :logging .info (f"User {user_id} not eligible for trial button (already had a subscription).")
|
|
else :logging .info (f"Trial period is disabled in settings. No trial button.")
|
|
await send_main_menu (message ,settings ,i18n_data ,show_trial_button_flag =show_trial_button_in_menu )
|
|
|
|
|
|
@router .message (Command ("language"))
|
|
@router .callback_query (F .data =="main_action:language")
|
|
async def language_command_handler (event :types .Message |types .CallbackQuery ,i18n_data :dict ,settings :Settings ):
|
|
|
|
current_lang =i18n_data .get ("current_language",settings .DEFAULT_LANGUAGE );i18n :Optional [JsonI18n ]=i18n_data .get ("i18n_instance")
|
|
target_message_for_reply :Optional [types .Message ]=None ;is_callback =isinstance (event ,types .CallbackQuery );answered_callback =False
|
|
if is_callback :await event .answer ();answered_callback =True ;target_message_for_reply =event .message
|
|
else :target_message_for_reply =event
|
|
if not i18n :
|
|
logging .error ("i18n instance is missing in language_command_handler.");error_message_text ="Language service error."
|
|
if target_message_for_reply :await target_message_for_reply .answer (error_message_text )
|
|
return
|
|
_ =lambda key ,**kwargs :i18n .gettext (current_lang ,key ,**kwargs );text_to_send =_ (key ="choose_language");reply_markup_to_send =get_language_selection_keyboard (i18n ,current_lang )
|
|
if not target_message_for_reply :logging .warning ("language_command_handler: No target message.");return
|
|
if is_callback :
|
|
try :await target_message_for_reply .edit_text (text_to_send ,reply_markup =reply_markup_to_send )
|
|
except Exception as e :logging .info (f"Could not edit for lang selection: {e}. Sending new.");await target_message_for_reply .answer (text_to_send ,reply_markup =reply_markup_to_send )
|
|
else :await target_message_for_reply .answer (text_to_send ,reply_markup =reply_markup_to_send )
|
|
|
|
|
|
@router .callback_query (F .data .startswith ("set_lang_"))
|
|
async def select_language_callback_handler (callback :types .CallbackQuery ,i18n_data :dict ,settings :Settings ,subscription_service :SubscriptionService ):
|
|
i18n :Optional [JsonI18n ]=i18n_data .get ("i18n_instance")
|
|
if not i18n or not callback .message :
|
|
await callback .answer ("Language service error.",show_alert =True );return
|
|
|
|
lang_code =callback .data .split ("_")[2 ];user_id =callback .from_user .id
|
|
await update_user_language_code (user_id ,lang_code );i18n_data ["current_language"]=lang_code
|
|
_ =lambda key ,**kwargs :i18n .gettext (lang_code ,key ,**kwargs )
|
|
|
|
|
|
await callback .answer (_ (key ="language_set_alert"))
|
|
|
|
show_trial_button_after_lang_change =False
|
|
if settings .TRIAL_ENABLED and not await subscription_service .has_had_any_subscription (user_id ):
|
|
show_trial_button_after_lang_change =True
|
|
|
|
|
|
await send_main_menu (callback ,settings ,i18n_data ,show_trial_button_flag =show_trial_button_after_lang_change ,is_edit =True )
|
|
|
|
|
|
@router .callback_query (F .data .startswith ("main_action:"))
|
|
async def main_action_callback_handler (
|
|
|
|
callback :types .CallbackQuery ,state :FSMContext ,settings :Settings ,i18n_data :dict ,bot :Bot ,
|
|
subscription_service :SubscriptionService ,referral_service :ReferralService ,
|
|
panel_service :PanelApiService ,promo_code_service :PromoCodeService
|
|
):
|
|
|
|
action =callback .data .split (":")[1 ];from .import subscription as user_subscription_handlers ;from .import referral as user_referral_handlers ;from .import promo_user as user_promo_handlers ;from .import trial_handler as user_trial_handlers
|
|
if not callback .message :logging .error (f"Callback {callback.id} no message for {action}");await callback .answer ("Error.");return
|
|
|
|
if action =="subscribe":await user_subscription_handlers .display_subscription_options (callback ,i18n_data ,settings )
|
|
elif action =="my_subscription":await user_subscription_handlers .my_subscription_command_handler (callback ,i18n_data ,settings ,panel_service ,subscription_service )
|
|
elif action =="referral":await user_referral_handlers .referral_command_handler (callback ,settings ,i18n_data ,referral_service ,bot )
|
|
elif action =="apply_promo":await user_promo_handlers .prompt_promo_code_input (callback ,state ,i18n_data ,settings )
|
|
elif action =="request_trial":await user_trial_handlers .request_trial_confirmation_handler (callback ,settings ,i18n_data ,subscription_service )
|
|
elif action =="language":await language_command_handler (callback ,i18n_data ,settings )
|
|
elif action =="back_to_main":
|
|
show_trial_button_on_back =False
|
|
if settings .TRIAL_ENABLED and not await subscription_service .has_had_any_subscription (callback .from_user .id ):
|
|
show_trial_button_on_back =True
|
|
await send_main_menu (callback ,settings ,i18n_data ,show_trial_button_flag =show_trial_button_on_back ,is_edit =True )
|
|
else :await callback .answer ("Unknown action.",show_alert =True ) |