33from pathlib import Path
44import getpass
55import argparse
6+ import logging
67
78# Add project root to sys.path
89project_root = Path (__file__ ).resolve ().parent .parent
910if str (project_root ) not in sys .path :
1011 sys .path .insert (0 , str (project_root ))
1112
13+ from telethon .sessions import StringSession
14+ from telethon .errors import SessionPasswordNeededError
15+
16+ from userbot import FAKE , TelegramClient
1217from userbot .src .db .session import get_db , initialize_database
1318import userbot .src .db_manager as db_manager
1419from userbot .src .encrypt import encryption_manager
15- from userbot import FAKE
20+
21+ # Configure logging to suppress noisy output from libraries
22+ logging .basicConfig (level = logging .WARNING )
23+ logger = logging .getLogger ('manage_account_cli' )
24+ logger .setLevel (logging .INFO )
1625
1726async def add_account_logic (args ):
18- """Logic to add a new account."""
19- print (f"--- Adding new account: { args .name } ---" )
20- async with get_db () as db :
21- if await db_manager .get_account (db , args .name ):
22- print (f"Error: Account '{ args .name } ' already exists." )
23- return
27+ """
28+ Logic to add a new account with a full interactive Telethon login session.
29+ """
30+ logger .info (f"--- Adding new account: { args .name } ---" )
31+
32+ temp_client = None
33+ try :
34+ async with get_db () as db :
35+ if await db_manager .get_account (db , args .name ):
36+ logger .error (f"Error: Account '{ args .name } ' already exists." )
37+ return
38+
39+ api_id = input ("Enter API ID: " ).strip ()
40+ api_hash = getpass .getpass ("Enter API Hash: " ).strip ()
41+
42+ if not api_id .isdigit () or not api_hash :
43+ logger .error ("Error: API ID must be a number and API Hash cannot be empty." )
44+ return
45+
46+ logger .info ("Initializing temporary session to verify credentials..." )
47+ temp_client = TelegramClient (StringSession (), int (api_id ), api_hash )
48+ await temp_client .connect ()
49+
50+ if not await temp_client .is_user_authorized ():
51+ phone_number = input ("Session not found. Please enter your phone number (e.g., +1234567890): " ).strip ()
52+ await temp_client .send_code_request (phone_number )
53+ code = input ("Please enter the code you received: " ).strip ()
54+ try :
55+ await temp_client .sign_in (phone_number , code )
56+ except SessionPasswordNeededError :
57+ two_fa_password = getpass .getpass ("2FA Password required: " ).strip ()
58+ await temp_client .sign_in (password = two_fa_password )
59+
60+ me = await temp_client .get_me ()
61+ user_id = me .id
62+ logger .info (f"Successfully logged in as { me .first_name } (ID: { user_id } )." )
63+
64+ # Check for duplicates by Telegram User ID
65+ existing_by_id = await db_manager .get_account_by_user_id (db , user_id )
66+ if existing_by_id :
67+ logger .error (f"Error: This Telegram account (ID: { user_id } ) already exists in the database as '{ existing_by_id .account_name } '." )
68+ return
69+
70+ # Collect remaining information
71+ lang_code = input (f"Enter language code (e.g., ru, en) [default: ru]: " ).strip () or 'ru'
72+ is_enabled = (input ("Enable this account now? (yes/no) [default: yes]: " ).strip ().lower () or 'yes' ).startswith ('y' )
73+
74+ device_model = FAKE .user_agent ()
75+ system_version = f"SDK { FAKE .random_int (min = 28 , max = 33 )} "
76+ app_version = f"{ FAKE .random_int (min = 9 , max = 10 )} .{ FAKE .random_int (min = 0 , max = 9 )} .{ FAKE .random_int (min = 0 , max = 9 )} "
77+
78+ new_account = await db_manager .add_account (
79+ db , args .name , api_id , api_hash , lang_code , is_enabled ,
80+ device_model , system_version , app_version , user_id
81+ )
82+ if new_account :
83+ logger .info (f"\n Success! Account '{ args .name } ' was added. Restart the bot to activate the session." )
84+ else :
85+ logger .error ("\n Failed to add the account to the database." )
86+
87+ except Exception as e :
88+ logger .error (f"\n An unexpected error occurred: { e } " , exc_info = False )
89+ finally :
90+ if temp_client and temp_client .is_connected ():
91+ await temp_client .disconnect ()
2492
25- api_id = input ("Enter API ID: " ).strip ()
26- api_hash = getpass .getpass ("Enter API Hash: " ).strip ()
27- lang_code = input ("Enter language code (e.g., ru, en) [ru]: " ).strip () or 'ru'
28- is_enabled = input ("Enable this account now? (yes/no) [yes]: " ).strip ().lower () != 'no'
29-
30- device_model = FAKE .user_agent ()
31- system_version = f"SDK { FAKE .random_int (min = 28 , max = 33 )} "
32- app_version = f"{ FAKE .random_int (min = 9 , max = 10 )} .{ FAKE .random_int (min = 0 , max = 9 )} .{ FAKE .random_int (min = 0 , max = 9 )} "
33-
34- new_account = await db_manager .add_account (
35- db , args .name , api_id , api_hash , lang_code , is_enabled ,
36- device_model , system_version , app_version
37- )
38- if new_account :
39- print (f"\n Success! Account '{ args .name } ' was added." )
40- else :
41- print ("\n Failed to add the account." )
4293
4394async def toggle_account_logic (args ):
4495 """Logic to toggle an account's status."""
45- print (f"--- Toggling account: { args .name } ---" )
96+ logger . info (f"--- Toggling account: { args .name } ---" )
4697 async with get_db () as db :
4798 new_status = await db_manager .toggle_account_status (db , args .name )
4899 if new_status is None :
49- print (f"Error: Account '{ args .name } ' not found." )
100+ logger . error (f"Error: Account '{ args .name } ' not found." )
50101 else :
51102 status_str = "ENABLED" if new_status else "DISABLED"
52- print (f"Success! Account '{ args .name } ' is now { status_str } ." )
103+ logger . info (f"Success! Account '{ args .name } ' is now { status_str } ." )
53104
54105async def delete_account_logic (args ):
55106 """Logic to delete an account."""
56- print (f"--- Deleting account: { args .name } ---" )
107+ logger . info (f"--- Deleting account: { args .name } ---" )
57108 confirm = input (f"Are you sure you want to permanently delete '{ args .name } '? (yes/no): " ).lower ()
58109 if confirm == 'yes' :
59110 async with get_db () as db :
60111 if await db_manager .delete_account (db , args .name ):
61- print (f"Success! Account '{ args .name } ' has been deleted." )
112+ logger . info (f"Success! Account '{ args .name } ' has been deleted." )
62113 else :
63- print (f"Error: Account '{ args .name } ' not found." )
114+ logger . error (f"Error: Account '{ args .name } ' not found." )
64115 else :
65- print ("Deletion cancelled." )
116+ logger . info ("Deletion cancelled." )
66117
67118async def edit_account_logic (args ):
68119 """Logic to edit an account's properties."""
69- print (f"--- Editing account: { args .name } ---" )
120+ logger . info (f"--- Editing account: { args .name } ---" )
70121 async with get_db () as db :
71122 account = await db_manager .get_account (db , args .name )
72123 if not account :
73- print (f"Error: Account '{ args .name } ' not found." )
124+ logger . error (f"Error: Account '{ args .name } ' not found." )
74125 return
75126
76127 updated_fields = []
@@ -95,6 +146,10 @@ async def edit_account_logic(args):
95146 account .proxy_password = None
96147 updated_fields .append ("Proxy settings CLEARED" )
97148 elif args .proxy_type :
149+ # Requires all proxy args
150+ if not (args .proxy_ip and args .proxy_port ):
151+ logger .error ("Error: --proxy-ip and --proxy-port are required when setting a proxy." )
152+ return
98153 account .proxy_type = args .proxy_type
99154 account .proxy_ip = args .proxy_ip
100155 account .proxy_port = args .proxy_port
@@ -103,18 +158,18 @@ async def edit_account_logic(args):
103158 updated_fields .append ("Proxy settings UPDATED" )
104159
105160 if updated_fields :
106- print ("Success! The following fields were updated:" )
161+ logger . info ("Success! The following fields were updated:" )
107162 for field in updated_fields :
108- print (f"- { field } " )
163+ logger . info (f"- { field } " )
109164 else :
110- print ("No changes specified. Use --help for options." )
165+ logger . info ("No changes specified. Use --help for options." )
111166
112167async def main ():
113168 """Main function to parse arguments and dispatch commands."""
114169 parser = argparse .ArgumentParser (description = "DeBot Account Management CLI" )
115170 subparsers = parser .add_subparsers (dest = "command" , required = True )
116171
117- parser_add = subparsers .add_parser ("add" , help = "Add a new account" )
172+ parser_add = subparsers .add_parser ("add" , help = "Add a new account via interactive login " )
118173 parser_add .add_argument ("name" , help = "Unique name for the new account" )
119174 parser_add .set_defaults (func = add_account_logic )
120175
@@ -149,4 +204,9 @@ async def main():
149204 await args .func (args )
150205
151206if __name__ == "__main__" :
152- asyncio .run (main ())
207+ try :
208+ asyncio .run (main ())
209+ except (KeyboardInterrupt , EOFError ):
210+ logger .info ("\n Operation cancelled by user." )
211+ except Exception as e :
212+ logger .error (f"A critical error occurred: { e } " , exc_info = True )
0 commit comments