From fe6fef3174cbf31e5d217e5f7b45a4366c629719 Mon Sep 17 00:00:00 2001 From: Vlad Date: Fri, 20 Sep 2024 05:48:09 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B4=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=BA=D0=BE=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + database.py | 14 ++-- handlers/__pycache__/keys.cpython-310.pyc | Bin 6180 -> 7656 bytes handlers/__pycache__/pay.cpython-310.pyc | Bin 8690 -> 8705 bytes handlers/keys.py | 66 +++++++++++---- handlers/pay.py | 64 +++++++++----- key_management.py | 97 +++++++++++++++++++--- 7 files changed, 190 insertions(+), 52 deletions(-) diff --git a/.gitignore b/.gitignore index 0b7bcc7b..fb38d4ca 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ /database.db /bot_old.py /bot_old_2.py +/database.db \ No newline at end of file diff --git a/database.py b/database.py index eae9071c..4c9ea929 100644 --- a/database.py +++ b/database.py @@ -11,17 +11,18 @@ async def init_db(): client_id TEXT NOT NULL, email TEXT NOT NULL, expiry_time INTEGER NOT NULL, - balance REAL NOT NULL DEFAULT 0.0, -- Добавлено поле для баланса + balance REAL NOT NULL DEFAULT 0.0, PRIMARY KEY (tg_id, client_id) ) ''') await db.execute(''' CREATE TABLE IF NOT EXISTS keys ( + tg_id INTEGER NOT NULL, -- Добавлено поле tg_id client_id TEXT NOT NULL, email TEXT NOT NULL, created_at INTEGER NOT NULL, key TEXT NOT NULL, - PRIMARY KEY (client_id) + PRIMARY KEY (tg_id, client_id) -- Изменено на (tg_id, client_id) ) ''') await db.commit() @@ -34,12 +35,12 @@ async def add_connection(tg_id: int, client_id: str, email: str, expiry_time: in ''', (tg_id, client_id, email, expiry_time, balance)) await db.commit() -async def store_key(client_id: str, email: str, key: str): +async def store_key(tg_id: int, client_id: str, email: str, key: str): async with aiosqlite.connect(DATABASE_PATH) as db: await db.execute(''' - INSERT INTO keys (client_id, email, created_at, key) - VALUES (?, ?, ?, ?) - ''', (client_id, email, int(datetime.utcnow().timestamp() * 1000), key)) + INSERT INTO keys (tg_id, client_id, email, created_at, key) + VALUES (?, ?, ?, ?, ?) + ''', (tg_id, client_id, email, int(datetime.utcnow().timestamp() * 1000), key)) await db.commit() async def get_keys(tg_id: int): @@ -51,7 +52,6 @@ async def get_keys(tg_id: int): ''', (tg_id,)) as cursor: return await cursor.fetchall() - async def has_active_key(tg_id: int) -> bool: async with aiosqlite.connect(DATABASE_PATH) as db: async with db.execute("SELECT COUNT(*) FROM connections WHERE tg_id = ? AND expiry_time > ?", diff --git a/handlers/__pycache__/keys.cpython-310.pyc b/handlers/__pycache__/keys.cpython-310.pyc index db258c309a002ec63c7261460326dbb5bd03a626..c2051196a6f9e2643a96414a38fb276a95a85631 100644 GIT binary patch delta 2942 zcmZ{mO>7&-6@Yh!yUXQrwGw|sk&3NQj_sPZVmU#765DX?I*z62$8F*?mK&R0aaJm6 zie!h&+7fmxIT6}JD>u$uiUtO#peSIpXze;~ou*C?xdiBi>aE)XIR&VT^iUK%6^Q%Z zQa_fUt}u@?@4cCwee=FI`q`nsA2F*P9l8Y1H~;e4)S;(um^-LWZVdc#l6A4zqI5oG z$C_~#XOTr|nK0cZrNk6v36@-x-z4XI0&DjcYl`&**7Ul6nq?N{^BLCLUX#&Rq}&sC zljH)KH{jj4fsdfo&k;$wMqH^Rm54{?<{jD$Ir1|3qBJZqX-N8M(W5SHDvY>fiY(K0 z{g4-OLrryg)z6b%nGa7(p5n?cNEcF`>Z*)pBroiQOPU*IAvgSvbdxgq=o0lbS7}CE zZJI0-B7HXpF1o8QWr=tZrh0mXvaqK+(URfnE^e-)WV#WiEy?0eq*qk+C@Bgn_N1uk z`ux?)um=83KzmK9^vRObIr}b=yeN_8;!YQ?z#?uGU;k#P{aNTa0Uzi^uSP3M`}Z=r zEV)uMw)RN`><~45d~QU~Zh2lgHG1mg*{nTd(PCK)MEmDAxp0W8s`e5by$`7)w_n`CRZ0nC;`f%l1>klB`fd1`NwspVtU}X`;3!uHd@_iWJKP+BU zpQ5>tIG*Yjo;utW_ajrhI+JhIZSK<|6X9@9gDr6iuND7NdrqoWt!7u4pBxT0HnO^} zF^gYn)VPe_6|-5<$_nO7s_$UdYt0U(FB9lT0|HdfaLiICGgt>Rfy9nr)Csi*N2W7@#u$_z9Cm`S%k7vZ zt_iJknoNgS0wC>jVx_oi1ZXBoNwzE!P>Kq?wOZk0hWQ4rQO)J zSjMi#0xaQo70aG2SZ2n3l7EN?HTSXjhx`j8dt&^BY~dgv2}IsdekG{SE=(TRPZnu61?Y(U4H)|9v0x2J?{Kz)~Tx+~KRV>?lC%F6a(AlxkoXnquL6F+K zAJuxz;&nSeQ)PDJE4b`WwxWlOez=Y;5d4MK1LXJty!(BC_#XBS-U>ao@@ZJ8F(UGb zjQF`4KeG+Zo0mMC&87J++}KknVjz5_UMm+Jz8e*LP++a+dqId?`1zLu%K1Lj?MHz$ z^8+XbP-IbH{_}$<20`TF0ml3gDv&|`42ow_dq9U`^y8!rzp5Djr3%8Y0rncv zNh&A;@*_&s&rPtHBu%n(2c--9KMjgO-+D2afW-<3|Js9n71~G8>KM*z#DTlerLN=- zkrFKhU@ysQ$sODYp>h5qxN_VYq{lXKgrf~&hDDGMh&yH?fkDOB*U_CWWC=eg-q-e! zlj0MtpIp34B4d=C5ND#Frv8JKW+PeoDH!sd;<#}={Wa*$$wvn#j|E%EQI3hj`^6{5 zbNP*Q*d_(|OX#Se7zN=+oFY_h$C|0Nj~~ywogqPT1ZfgR-3W?t5MnYsa3RQ$T*qU1 zu{kCDNTFP`D-M=@C7_Xi9p?H5lz&JOCy%e?=TH@%w8~bcU(Uz-_i5jy;sB;Eb9*%un%UxndAto#r0PT}7| zfkS>A#R(LzgUAs+CVJyz(L8E8QS1~vevb6t{Zsq|IlU2K1diiv?T3n$ZJFB=aQMofLV29fbiX3f^~PBjnzJHVy91wLNDsSE{1nA;%y zPK<(mrB>v#L8N`TPz4gF(ALH6TG_4?>)%-=lD{TpVPg9*>Tsb0t$w)PC={T-dMaYP zdyp)OtKBnXR(#fdHnCB&a_VZ~5EoM!wH+GarFwfTcv}FJ1|49RWQqKUTjE!#u`aZ= zi3z^^JhHJL+4vY*9Z{qUCP|T8uOGIG)oE_cw6hXP<-5g1Pq`PbbdD^wD-~u4pG9E_ bzh^JmD@ZyW%f^Xzz)<4E*b^sR#|-6voVN4z delta 1695 zcma)*O>7%Q6vyZ7hrM2}o%kc)O$cd2>n1cM6dKylsz5)YG@(&TODh^MB=~&Bo3v_bDXsF#ID|N-@KW9 zGxMJ}za9KwZ?qJN=tMlucfU{Z?boB*q+iJO{@cT5tP-bB9o;QX$Z%6_;2K=3^;>>RPW6yn4$e-Ffq09lMX3Go-9O>P7yzarNYijn8V zuD!^c5lh|pF2DkDNhP_tO%VO!0Gh}7ANq0ry3)eG(Nlwe;wh}%T>EV8D`8*y#v6Ha zAzfyrseIAA1%5-`D&{RSJ!@XhmNJYke$CH@KISp~3;v_hlk}AnXU0z6l6<|KVYZo` zD^Zij)sZ7jerSr7=F;=F$$TkKnIz`%lOwfkqxEEC88$m#el+^RyyKKCKC7nqq%p|P zCi?kbYENI3wPFg@nNH`auWc^KmuS`xFfEt*%AKBDMbk9ZPc zAod^z5Gvv+0YBvA=SatPH zcM>tg2itp~kH6ABF#15UrVYtZF<&VQA^a%KT(;9rDQ#YIOp89OBc>Tcj3ZD`_A>vW zz2nF!;rfltEEi2HZ_lK&wR-l$*-UP>-l&UhixbY5EI(+^=W@c|RDFBL08H}J9dj@v zR6n!i2XiwS2g_cs7lrUsfsL&caArJvu~@TcI^q)63uj9#p(@@TmfS)UdRR3#h1r^b zxF*mI%Kch2hv&Tc$o%bX!;}9lv6ReebyZ7SQ}mJC`^Dey3$p_P(sC4v)FVD-3i1DqBi4x{!Zr;(9Q33wubxSVD!eJ@sOeZ3xs)@<^TWy diff --git a/handlers/__pycache__/pay.cpython-310.pyc b/handlers/__pycache__/pay.cpython-310.pyc index 78eea876806acff4b90e65e08a43eb6beb293f06..7845c031a1b9d03c58c8fb0f418413d975a02694 100644 GIT binary patch delta 1282 zcmZuxO>7%Q6rMLb-d(TPYuB|M$3KnTKk5>Ms{Ydhphi$C9GKDj=I#6D z&3kV&Zy%ps9&_e`L5tw{{P#bne|_POQ`I0S>)I>!H)vc2PZMt~o{&Fl=cqU-Lo97i z63>_*jJU?aggnBILr2cAjMe$Bv);LjvL>7CrC7GRjQV=#PWO|}8gdUhYuQ8cA=`g6 zKf1|vuXP)pZ;?@~@?Fbz?)I7G?$yqE_xh&SgY0V)=aPyQ4u?*9s% z#hVBvim)|8sHi*s0j2ht9FNZ}d6b*Oq|R{lkJ^1cori} zjts?@uFeAxHQzyTL!QxuL8yQm<~9#PBXFdj{XVxhHyC^MX9KqHVGLvX%zHcGl$=e=pkT9K{;^JifAB z#U!a7$0rwC_zOtg0kRl$<9x_-FgR^u8IxE9N9KxC&GpxLm?zZ~-c;fOy#eCC#D_82 zBqn=iN471MZEAIAxWg*k4Oloe2$T;!3Nz)Y3hx=Ex$1O9T#`?cqw?$F-;6wn5qu-^%jA3QRw@UE$l|BS z$@TP$OH8Rg1&)G!3ic{Epg{FS&sVxwE(q~D>iLj3q3q8oIHE|sP;x7C)n4Fott>G7 zRLvFQT}5+68w0b*E0a(r%8NatSh!fImdZU@&Fp2Wv*h*6^SXNIwQ2c%Cib=oCiWN| zG>WN3A&m3TGl$ul0|zzLI+kjZr;dS*gj!;|k?2!PPeKG(BTTdX=0d*+h^G7?l$NLW zT!TmLhkIOrEAm+O)uBf!tc^e$CdDJc+(>KUWBFNz# S7%Q6rMM`UT@axwd?pN{tFx0CQTI~q5=}C1VxENdI*);LyCHc9FH40Z5_Ja zC_ft4PJ$3WwG?T%(5S-Z!i7UxD+p9*g`ys~L~8*TAGmS>AvkeB4R7N72&prA-_E`_ z^WOK~%v&A*d(4^-1`UGa+0);zzkK$ARZ_qb73G5Y1u9p8E6$~rQSqZPVK;nS<^DOX z2u-+17)%f#Q-u4k5S6(8<#)t+^;M{f+iF&ProK)`Z1J0Vs`Z9%2C}{At863CnyON; zzyOs-Ax`^1)ml5+c{TOgzE!6d)qx&O^IuaFR-gzM#Zq7i@vi`f$yUjXE83)VdPaO4 z8dm$MGcDR$R9xuSTfc;o8jOoSWAQYlkilpv&}(!rqC~);IQHT?rD8BXbLt+ta4sX{ zDZ=5fa3O25gHrxbd=;NJTtBBwPm*;I1Bt}w4p*3QgF1h>dZWiRn(zw2ijWC%FIDlo z0j!g@PP-bw3N=jeQDUg-E&^c9fV_+12D!Q}>xic+x~p(9N9KS9xVA}{$@NWgU**7p zOsT7fo?NRD;wrQD_k`{%&Epu*2saNnRC;(%;{*#gp<-~u`FX{3t+@zStK48G>PJVW zNGXXI*Sq`^kV*i^O3;n62oGRjx{gGrkS0URoj}Rg{Vu{Habv8PMOmy)E2bOg<}Azt zi`StN#2}Jff(Kb&T{)y&N@J;#H|Pd9)#EHvm|6NcnPrYMLV9N*Y=N~vb~0DRJZTixcedQ`u5QNzW0sysD1aP zVQ^l+Fs)D110bGcMym2V$w_!r6rN2YpBnwT_EHq-IX{expiry_date.strftime('%Y-%m-%d %H:%M:%S')}\n" f"{days_left_message}") - else: - response_message = "У вас нет ключей." + # Кнопки для продления и инструкций + renew_button = types.InlineKeyboardButton(text='Продлить ключ', callback_data='renew_key') + instructions_button = types.InlineKeyboardButton(text='Инструкции по использованию', callback_data='instructions') + back_button = types.InlineKeyboardButton(text='Назад в профиль', callback_data='view_profile') + keyboard = types.InlineKeyboardMarkup(inline_keyboard=[[renew_button], [instructions_button], [back_button]]) - await delete_previous_message(callback_query) - await bot.send_message(tg_id, response_message, parse_mode="HTML", reply_markup=keyboard) + await bot.edit_message_text(response_message, chat_id=tg_id, message_id=callback_query.message.message_id, reply_markup=keyboard, parse_mode="HTML") + else: + await bot.edit_message_text("Информация о ключе не найдена.", chat_id=tg_id, message_id=callback_query.message.message_id, parse_mode="HTML") except Exception as e: - await handle_error(tg_id, callback_query, f"Ошибка при получении ключей: {e}") + await handle_error(tg_id, callback_query, f"Ошибка при получении информации о ключе: {e}") await callback_query.answer() +# Остальные функции остаются без изменений... + +# Обработка ошибок +async def handle_error(tg_id, callback_query, message): + await bot.edit_message_text(message, chat_id=tg_id, message_id=callback_query.message.message_id, parse_mode="HTML") + + # Обработка запроса на продление ключа @router.callback_query(lambda c: c.data == 'renew_key') async def process_callback_renew_key(callback_query: types.CallbackQuery): diff --git a/handlers/pay.py b/handlers/pay.py index cb6d4376..2ad6a0e9 100644 --- a/handlers/pay.py +++ b/handlers/pay.py @@ -10,7 +10,6 @@ from handlers.profile import process_callback_view_profile router = Router() -# Определение состояний class ReplenishBalanceState(StatesGroup): choosing_transfer_method = State() choosing_amount = State() @@ -18,7 +17,7 @@ class ReplenishBalanceState(StatesGroup): async def send_message_with_deletion(chat_id, text, reply_markup=None, state=None, message_key='last_message_id'): """ - Отправляет сообщение и удаляет предыдущее, если оно существует. + Отправляет новое сообщение и удаляет предыдущее сообщение (если оно существует), сохраненное в состоянии FSM. """ if state: try: @@ -29,7 +28,8 @@ async def send_message_with_deletion(chat_id, text, reply_markup=None, state=Non await bot.delete_message(chat_id=chat_id, message_id=previous_message_id) sent_message = await bot.send_message(chat_id=chat_id, text=text, reply_markup=reply_markup) - await state.update_data({message_key: sent_message.message_id}) + if state: + await state.update_data({message_key: sent_message.message_id}) except Exception as e: print(f"Ошибка при удалении/отправке сообщения: {e}") @@ -43,12 +43,7 @@ async def process_callback_replenish_balance(callback_query: types.CallbackQuery key_count = await get_key_count(tg_id) if key_count <= 0: - await send_message_with_deletion( - tg_id, - "У вас нет ключей. Пополнение баланса возможно только при наличии ключа.", - state=state, - message_key='key_error_message_id' - ) + await send_message_with_deletion(tg_id, "У вас нет ключей. Пополнение баланса возможно только при наличии ключа.", state=state, message_key='key_error_message_id') create_key_button = InlineKeyboardButton(text='Создать ключ', callback_data='create_key') keyboard = InlineKeyboardMarkup(inline_keyboard=[[create_key_button]]) @@ -61,7 +56,7 @@ async def process_callback_replenish_balance(callback_query: types.CallbackQuery await state.set_state(ReplenishBalanceState.choosing_transfer_method) keyboard = InlineKeyboardMarkup(inline_keyboard=[ [InlineKeyboardButton(text='По реквизитам', callback_data='transfer_method_requisites')], - [InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_profile')] + [InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_profile')] # Кнопка "Назад" ]) await callback_query.message.edit_text( @@ -74,6 +69,8 @@ async def process_callback_replenish_balance(callback_query: types.CallbackQuery async def back_to_profile_handler(callback_query: types.CallbackQuery, state: FSMContext): await process_callback_view_profile(callback_query, state) + + @router.callback_query(lambda c: c.data.startswith('transfer_method_')) async def process_transfer_method_selection(callback_query: types.CallbackQuery, state: FSMContext): data = callback_query.data.split('_', 2) @@ -89,7 +86,7 @@ async def process_transfer_method_selection(callback_query: types.CallbackQuery, [InlineKeyboardButton(text='100 RUB', callback_data='amount_100')], [InlineKeyboardButton(text='300 RUB', callback_data='amount_300')], [InlineKeyboardButton(text='500 RUB', callback_data='amount_500')], - [InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_profile')] + [InlineKeyboardButton(text='⬅️ Назад', callback_data='back_to_profile')] # Кнопка "Назад" ]) await callback_query.message.edit_text( @@ -98,8 +95,11 @@ async def process_transfer_method_selection(callback_query: types.CallbackQuery, ) await state.update_data(transfer_method=transfer_method) await state.set_state(ReplenishBalanceState.choosing_amount) + else: await send_message_with_deletion(callback_query.from_user.id, "Неверный метод перевода.", state=state, message_key='transfer_method_error_message_id') + return + @router.callback_query(lambda c: c.data.startswith('amount_')) async def process_amount_selection(callback_query: types.CallbackQuery, state: FSMContext): @@ -112,16 +112,18 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F amount_str = data[1] amount = int(amount_str) - # Удаляем сообщение с кнопками выбора суммы + # Получаем ID сообщения с кнопками выбора суммы state_data = await state.get_data() amount_selection_message_id = state_data.get('amount_selection_message_id') + # Удаляем сообщение с кнопками выбора суммы if amount_selection_message_id: try: await bot.delete_message(chat_id=callback_query.from_user.id, message_id=amount_selection_message_id) except Exception as e: print(f"Ошибка при удалении сообщения: {e}") + # Обновляем состояние и сохраняем выбранную сумму await state.update_data(amount=amount) await state.set_state(ReplenishBalanceState.waiting_for_admin_confirmation) @@ -134,7 +136,11 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F "После перевода отправьте чек и дождитесь подтверждения." ) - await callback_query.message.edit_text(text=message, reply_markup=None) + # Редактируем текущее сообщение + await callback_query.message.edit_text( + text=message, + reply_markup=None # Или добавьте клавиатуру, если нужно + ) admin_keyboard = InlineKeyboardMarkup(inline_keyboard=[ [InlineKeyboardButton(text='Подтвердить', callback_data=f'admin_confirm_{callback_query.from_user.id}_{transfer_method}_{amount}')], @@ -151,6 +157,8 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F await send_message_with_deletion(ADMIN_ID, admin_message, reply_markup=admin_keyboard, state=state, message_key='admin_request_message_id') await callback_query.answer() + + @router.callback_query(lambda c: c.data.startswith('admin_')) async def process_admin_confirmation(callback_query: types.CallbackQuery, state: FSMContext): if callback_query.from_user.id != ADMIN_ID: @@ -164,20 +172,38 @@ async def process_admin_confirmation(callback_query: types.CallbackQuery, state: return action = data[1] - user_id = int(data[2]) + user_id_str = data[2] transfer_method = data[3] amount = int(data[4]) try: + user_id = int(user_id_str) + + # Получаем данные из состояния для удаления сообщения с реквизитами + state_data = await state.get_data() + requisites_message_id = state_data.get('requisites_message_id') + + if action == 'confirm': async with aiosqlite.connect(DATABASE_PATH) as db: await update_balance(user_id, amount) await db.commit() balance = await get_balance(user_id) - + + # Создаем клавиатуру с кнопкой "Профиль" + profile_button = InlineKeyboardButton(text='Профиль', callback_data='view_profile') + profile_keyboard = InlineKeyboardMarkup(inline_keyboard=[[profile_button]]) + + # Отправляем уведомление с кнопкой "Профиль" администратору await send_message_with_deletion(callback_query.from_user.id, f"Баланс пользователя успешно пополнен на {amount} RUB.\nТекущий баланс: {balance}", state=state, message_key='admin_confirm_message_id') - await bot.send_message(user_id, f"Ваш баланс был успешно пополнен на {amount} RUB.") + + # Отправляем уведомление пользователю с кнопкой "Профиль" + await bot.send_message( + user_id, + f"Ваш баланс был успешно пополнен на {amount} RUB.", + reply_markup=profile_keyboard + ) # Удаляем сообщение с реквизитами state_data = await state.get_data() @@ -188,10 +214,6 @@ async def process_admin_confirmation(callback_query: types.CallbackQuery, state: except Exception as e: print(f"Ошибка при удалении сообщения с реквизитами: {e}") - profile_button = InlineKeyboardButton(text='Профиль', callback_data='view_profile') - profile_keyboard = InlineKeyboardMarkup(inline_keyboard=[[profile_button]]) - await bot.send_message(user_id, "После пополнения баланса вы можете просмотреть свой профиль.", reply_markup=profile_keyboard) - elif action == 'decline': await send_message_with_deletion(callback_query.from_user.id, "Пополнение баланса отклонено.", state=state, message_key='admin_decline_message_id') await bot.send_message(user_id, "Ваш запрос на пополнение баланса был отклонен.") @@ -203,6 +225,8 @@ async def process_admin_confirmation(callback_query: types.CallbackQuery, state: await state.clear() await callback_query.answer() + + @router.message(lambda m: m.text and m.text.startswith('Недостаточно средств для продления')) async def handle_insufficient_funds(message: types.Message): user_id = message.from_user.id diff --git a/key_management.py b/key_management.py index 3f45b3f5..e0c3443d 100644 --- a/key_management.py +++ b/key_management.py @@ -33,10 +33,44 @@ class Form(StatesGroup): # Обработка нажатия кнопки создания ключа @dp.callback_query(F.data == 'create_key') async def process_callback_create_key(callback_query: CallbackQuery, state: FSMContext): - await callback_query.message.edit_text("Вам будет выдан пробный ключ. Пожалуйста, выберите имя для вашего ключа:") - await state.set_state(Form.waiting_for_key_name) + tg_id = callback_query.from_user.id + + if await has_active_key(tg_id): + await callback_query.message.edit_text( + "У вас уже есть активный ключ. Вы можете создать новый ключ за дополнительную плату в размере 100 рублей. " + "Хотите продолжить?", + reply_markup=InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text='Да, создать новый ключ', callback_data='confirm_create_new_key')], + [InlineKeyboardButton(text='Назад', callback_data='cancel_create_key')] # Изменили текст на "Назад" + ]) + ) + await state.update_data(creating_new_key=True) # Сохраняем состояние создания нового ключа + else: + await callback_query.message.edit_text("Вам будет выдан пробный ключ. Пожалуйста, выберите имя для вашего ключа:") + await state.set_state(Form.waiting_for_key_name) + await callback_query.answer() +@dp.callback_query(F.data == 'cancel_create_key') +async def cancel_create_key(callback_query: CallbackQuery, state: FSMContext): + await process_callback_view_profile(callback_query, state) # Возвращаем в профиль + await callback_query.answer() + + + +@dp.callback_query(F.data == 'confirm_create_new_key') +async def confirm_create_new_key(callback_query: CallbackQuery, state: FSMContext): + await callback_query.message.edit_text("Пожалуйста, выберите имя для вашего нового ключа:") + await state.set_state(Form.waiting_for_key_name) + await state.update_data(creating_new_key=True) # Убедитесь, что это состояние сохранено + await callback_query.answer() + +@dp.callback_query(F.data == 'cancel_create_key') +async def cancel_create_key(callback_query: CallbackQuery): + await callback_query.message.edit_text("Создание нового ключа отменено.") + await callback_query.answer() + + # Обработка текстовых сообщений @dp.message() async def handle_text(message: Message, state: FSMContext): @@ -63,22 +97,18 @@ async def handle_text(message: Message, state: FSMContext): if current_state == Form.waiting_for_key_name.state: await handle_key_name_input(message, state) -# Обработка ввода имени ключа async def handle_key_name_input(message: Message, state: FSMContext): tg_id = message.from_user.id key_name = sanitize_key_name(message.text) if not key_name: - await message.reply("Имя профиля не указано. Введите имя на английском языке.") + await message.reply("Имя ключа не указано. Введите имя на английском языке.") await state.clear() return - if await has_active_key(tg_id): - await message.reply("У вас уже есть активный ключ. Вы не можете создать новый.") - await state.clear() - return - - await state.update_data(key_name=key_name, tg_id=tg_id) + # Получаем данные состояния + data = await state.get_data() + creating_new_key = data.get('creating_new_key', False) session = login_with_credentials(ADMIN_USERNAME, ADMIN_PASSWORD) client_id = str(uuid.uuid4()) @@ -86,13 +116,24 @@ async def handle_key_name_input(message: Message, state: FSMContext): current_time = datetime.utcnow() expiry_time = int((current_time + timedelta(days=1)).timestamp() * 1000) + if creating_new_key: + balance = await get_balance(tg_id) + if balance < 100: + replenish_button = InlineKeyboardButton(text='Перейти в профиль', callback_data='view_profile') + keyboard = InlineKeyboardMarkup(inline_keyboard=[[replenish_button]]) + await message.reply("Недостаточно средств на балансе для создания нового ключа.", reply_markup=keyboard) + await state.clear() + return + + await update_balance(tg_id, -100) # Списание 100 рублей за новый ключ + try: # Создание клиента и получение ссылки add_client(session, client_id, email, tg_id, limit_ip=1, total_gb=0, expiry_time=expiry_time, enable=True, flow="xtls-rprx-vision") connection_link = link(session, client_id, email) await add_connection(tg_id, client_id, email, expiry_time, 0) - await store_key(client_id, email, connection_link) + await store_key(tg_id, client_id, email, connection_link) keyboard = InlineKeyboardMarkup(inline_keyboard=[ [InlineKeyboardButton(text='Инструкции по использованию', callback_data='instructions')], @@ -107,6 +148,40 @@ async def handle_key_name_input(message: Message, state: FSMContext): await state.clear() + +# Обработка нажатия кнопки создания ключа +@dp.callback_query(F.data == 'create_key') +async def process_callback_create_key(callback_query: CallbackQuery, state: FSMContext): + tg_id = callback_query.from_user.id + + if await has_active_key(tg_id): + await callback_query.message.edit_text( + "У вас уже есть активный ключ. Вы можете создать новый ключ за дополнительную плату в размере 100 рублей. " + "Хотите продолжить?", + reply_markup=InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text='Да, создать новый ключ', callback_data='confirm_create_new_key')], + [InlineKeyboardButton(text='Нет, оставить текущий', callback_data='cancel_create_key')] + ]) + ) + await state.update_data(creating_new_key=True) # Сохраняем состояние создания нового ключа + else: + await callback_query.message.edit_text("Вам будет выдан пробный ключ. Пожалуйста, выберите имя для вашего ключа:") + await state.set_state(Form.waiting_for_key_name) + + await callback_query.answer() + + +@dp.callback_query(F.data == 'confirm_create_new_key') +async def confirm_create_new_key(callback_query: CallbackQuery, state: FSMContext): + await callback_query.message.edit_text("Пожалуйста, выберите имя для вашего нового ключа:") + await state.set_state(Form.waiting_for_key_name) + await callback_query.answer() + +@dp.callback_query(F.data == 'cancel_create_key') +async def cancel_create_key(callback_query: CallbackQuery): + await callback_query.message.edit_text("Создание нового ключа отменено.") + await callback_query.answer() + # Обработка кнопки "Инструкции" @dp.callback_query(F.data == 'instructions') async def handle_instructions(callback_query: CallbackQuery):