From 22a462d19300200494cb1093fc270747d99019f2 Mon Sep 17 00:00:00 2001 From: Vlad Date: Sat, 21 Sep 2024 01:13:12 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B1=D0=BD=D0=B8=D0=BA=20?= =?UTF-8?q?=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=B5=D1=82=D1=81=D1=8F=20=D0=B2?= =?UTF-8?q?=D1=81=D0=B5=D0=B3=D0=BE=20=D0=BE=D0=B4=D0=B8=D0=BD=20=D1=80?= =?UTF-8?q?=D0=B0=D0=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- handlers/__pycache__/keys.cpython-310.pyc | Bin 7362 -> 9110 bytes handlers/keys.py | 63 +++++++++++++++++++--- key_management.py | 36 ++++++++++--- 3 files changed, 85 insertions(+), 14 deletions(-) diff --git a/handlers/__pycache__/keys.cpython-310.pyc b/handlers/__pycache__/keys.cpython-310.pyc index 2099e2e5737ad00eb459de1dace594a9c00ca068..f452fd24cb1c475621ef2c0cf1a98c38622492fc 100644 GIT binary patch delta 3531 zcmaJ^TWnlM89sCN?EQAUyWWd0>rI-FE>2uKlmw#0A$IK~B(YPHreF~^>z!kFoxN%H zY#m$ctd#_%qBT;O3MAS{jzB`KTGhn_LJN_&Nfi(1?CbJ^c;f*H#0w9F^8a(zyW6da zrTKPd{+WN~%>T_dzkmDX@1OP+y5#~N&j<(FEHAee{wO?5KyQ~9rP*?|A8;#SUJIdT3P0&4eq`5dHm!#xg zK29EolQP3YXn3iX({wGB$z`>I&Oav8B*Z7>qh23a%QApVV&Uz(^4k`&mmju`kO)uP zzUYhLWZQg2*NX*~;6Jtn-{ zttqRoSCvgWRjQ;aKd>}=tyL?#&xaka)vA^^r28`M*^t-#x_8M(;owC}g_ghST_jZ> z6h9Pokt`}SxH(M1QeY`q?V%8m4Xf##NCh9-Y5$HLtOFa$j`c+eHWYdw zi8hZrvtROW<0NJD=9wf9*qvc;D&PM@`dwBh3$a` z+l%lN|ABkP-EPnDf4Hv<>_^k*5JZfuM7?&RkD5iFOB^E7ij7);VzS_pbwgexqR&R{RJ0al>HywYbo-K{N~p7Hp{|W4 z8HrStHl0mANCapLm(vZQ#yv~|RPY;(*Nv@%iTdr%XgBr*PQ!>aU{LpTg*M994f6R=Epv9w+MG7L$Qk z#>1|aTRf|se2cKBz){l0K1~`niwohUHF+W!gD2SVl(hm)<+XA-y{MVwP&&vV6s0#~ zepp)177HmL@q97OXlJz1Q-A3wD`vn^DwEFT1VP%g#~79|!1B67R*51b9~}P;TLXm6 zBOzv6g!mSWdNLti#u1+(gcEvO`m>K;^TmT#yY$Dh`c;0<*IS#dDpZL{YgXN%J9XD> zdCjJ~tG22PHG9?0rmB`r54D0u$vZ-!dpCVR7F)Zg5N!6@JNlf>K1aI`B*wDoZ&Rw^ z0G;dXSe9Ot3UNi!)slf2%;lU_2eP=+**AcbYmS=^Ax7}KOqP+eJ?#YqXI&kf zT^+tOb$)8{aze|ev$@1HKcvPz$jjCJ&w=6c6dzWH>=jfHw|U||b*OU7EaQ#Y$Po7vBmv7T7f$GzyUPJRzPq2#=uQ$y6AF6f1>0Vfc_W?DOedx{%QrK3=F<|FhyvHjQJd-5p8=5LrtvFETB$J!!7 zN2IX%5=KEFC0o!N))IrCX6k_R+Lxvk z6_!JTNFU62@Qvo~yG6zBiK_np8uqJ{KY6qdAl;B)NqS5ft^h!CU7gO2| z9iE@gtA2`0*&U8znW%Rz!>%N~T!WS&_dV3n#ycgE44~B4`M^MvebFmLMPT zSf57Ld9Ck-`BsXRv~^@k;z9H^$+hz&whj}{UL;K&Ne(WU2XI07%6JHHsY!w;pRhbX z(tqI`+S*5ww3rE(@FEVl%N6ElesqO-jlAw7VIp$2R(bx(b#}%(4%p)uyln~Yt#C}8;*j`!G#Qz44P delta 1984 zcmaJ?TTdHD7~NT~*9LYM+xTvC6(O|<0TKlS0U}BQv;>E=joLU>T;o}Ysj;ouwYbRC zRPfM7B@&&cFQ^ho?L(V~O69!|MSZR+RjRbAREeiXRn=Dg0qJ~Wb17%)G|hH&H2VgVf7loDYa!r@IJ5y9wn zAr_$z(YN%zIF1_V7h=Dvvh5opgIa<3_MeJh*-$I}M81gp^gzC%1sP+>vqjU)=SVY^ z9eu6_)QN4zZ8iJ=vu=}5z|=8m=B2ic;@kR;$wYR zsp<@99u|R`2do+2&>44xPCI>_JEpX2H|0I_ihzYlVNF{7pd{@&uv9`NanDxmwU_K< zn{GKjn!)ZZajo7|7wSvuJSu6d)z71O8}@IZHJ9mHaF-M|Rao#WG?ZMJX|!dpBtb$> z10IKtc*ch5`!!eMKOkYvjf7Q?=?4x+O70!uGjXH3JQCg%?y~Kzx!-f=?3L#dS`tda zZeUM1%8mu5e>6_Q`%>*HLJ?Z7o1*{JbqAZ+7hBTg8`C#q5@}&Cq!plz4k~fi$@@*# zS)8Ij+B@li(h+TkG3Nld&~~Gc&6uPEI?hwOI`LKv!cG7Q-~vDw0MC9AqHcg5fL;bM z5Aj2M37{VU>?fB2`T(v2+@PPU!)SmWs^@7?Q+-#Va|nRDTCtW6YE3dQ#&vpM>kVos zh+4#`D6Y5LG_f5y*TrWZ8%fZ6;l`d3HZCT{$s{DX2JpO-k^ypb-|PDx$zh0JroZ|} z>H-kn02rq)1$N{J3yYU%IS`_UfnoVoV4CQ;;G@O~7OqM|-LoTPiiI(efU2a8L9vTT z8>GJlBXj?imQ2Htim(tV0C502zzhSc#>_10?5HmmDiVX7gi8#yRdIp);egj$0I$(Z zsI_b)eo-a>|A?4jg}}rKF35=s7b9D-)2~a?GZ(sa#qo1Cal$B`_jf zAo(;~Dw$4Yv$Lu6yB~*ZQHIuqZy_D5xLmcul38kfDfwbI9>X%D`%l7Oi#_1RQv@Aj z5W$fq_W+J}Ovd5$Z3Zz!ZqtX2lP>UyBmwFHn&@HU9f`4R`vXlwDE>b-Shh^gwCn}K z9xt|pyaOrud9Rp351QNLN=?w;o1^1YDay;h(r{|U zNSgVizHBnfPL;*UC#Knas~(iomkSxP!p*Uyblxxt2F^wFLRQaZj0Yph>aBVg7Owbb zFl#dToaHczX|U<}Mn>pgp@1DW_n7|FqN8Ox*m}p)0;!<7V{*09>0WE7|5!&REidp> zg$grL41Q+Ka550rou~y#&q#{?-8wx5+=)OjTjg@#S-7@mQo&vF3#5{HDh>G&zh7ce z(m_9LTP(Aal?ToFMl5x#dJbLZAa gHK0bFf(t3gg}e-*$)aNOAf>C)oJyw$xkeTHziUgLMF0Q* diff --git a/handlers/keys.py b/handlers/keys.py index 0e1e46e8..a3281f4c 100644 --- a/handlers/keys.py +++ b/handlers/keys.py @@ -6,6 +6,7 @@ from database import get_balance, update_balance, get_trial from client import extend_client_key from config import ADMIN_USERNAME, DATABASE_URL, ADMIN_PASSWORD from auth import login_with_credentials +from client import extend_client_key, delete_client router = Router() @@ -54,12 +55,10 @@ async def process_callback_view_keys(callback_query: types.CallbackQuery): await callback_query.answer() - -# Обработка запроса на просмотр информации о ключе @router.callback_query(lambda c: c.data.startswith('view_key_')) async def process_callback_view_key(callback_query: types.CallbackQuery): tg_id = callback_query.from_user.id - key_name, client_id = callback_query.data.split('_')[2], callback_query.data.split('_')[3] # Получаем имя ключа и client_id + key_name, client_id = callback_query.data.split('_')[2], callback_query.data.split('_')[3] try: conn = await asyncpg.connect(DATABASE_URL) @@ -82,11 +81,12 @@ async def process_callback_view_key(callback_query: types.CallbackQuery): f"Дата окончания: {expiry_date.strftime('%Y-%m-%d %H:%M:%S')}\n" f"{days_left_message}") - # Кнопки для продления и инструкций + # Кнопки для продления, инструкций и удаления renew_button = types.InlineKeyboardButton(text='Продлить ключ', callback_data=f'renew_key_{client_id}') instructions_button = types.InlineKeyboardButton(text='Инструкции по использованию', callback_data='instructions') + delete_button = types.InlineKeyboardButton(text='Удалить ключ', callback_data=f'delete_key_{client_id}') back_button = types.InlineKeyboardButton(text='Назад в профиль', callback_data='view_profile') - keyboard = types.InlineKeyboardMarkup(inline_keyboard=[[renew_button], [instructions_button], [back_button]]) + keyboard = types.InlineKeyboardMarkup(inline_keyboard=[[renew_button], [instructions_button], [delete_button], [back_button]]) 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: @@ -101,7 +101,58 @@ async def process_callback_view_key(callback_query: types.CallbackQuery): await callback_query.answer() -# Обработка запроса на продление ключа +# Обработка запроса на удаление ключа +@router.callback_query(lambda c: c.data.startswith('delete_key_')) +async def process_callback_delete_key(callback_query: types.CallbackQuery): + tg_id = callback_query.from_user.id + client_id = callback_query.data.split('_')[2] # Получаем client_id + + confirmation_keyboard = types.InlineKeyboardMarkup(inline_keyboard=[ + [types.InlineKeyboardButton(text='Да, удалить', callback_data=f'confirm_delete_{client_id}')], + [types.InlineKeyboardButton(text='Нет, отменить', callback_data='view_keys')] + ]) + + await bot.send_message(tg_id, "Вы уверены, что хотите удалить ключ?", reply_markup=confirmation_keyboard) + await callback_query.answer() + +@router.callback_query(lambda c: c.data.startswith('confirm_delete_')) +async def process_callback_confirm_delete(callback_query: types.CallbackQuery): + tg_id = callback_query.from_user.id + client_id = callback_query.data.split('_')[2] # Получаем client_id + + try: + conn = await asyncpg.connect(DATABASE_URL) + try: + # Получаем email для удаления через API + record = await conn.fetchrow('SELECT email FROM keys WHERE client_id = $1', client_id) + + if record: + email = record['email'] + + # Создаем сессию для API-запросов + session = login_with_credentials(ADMIN_USERNAME, ADMIN_PASSWORD) + + # Удаляем клиента через API + success = delete_client(session, client_id) + + if success: + # Удаляем ключ из базы данных + await conn.execute('DELETE FROM keys WHERE client_id = $1', client_id) + await bot.send_message(tg_id, "Ключ был успешно удален.") + else: + await bot.send_message(tg_id, "Ошибка при удалении клиента через API.") + + else: + await bot.send_message(tg_id, "Ключ не найден или уже удален.") + + finally: + await conn.close() + + except Exception as e: + await bot.send_message(tg_id, f"Ошибка при удалении ключа: {e}") + + await callback_query.answer() + @router.callback_query(lambda c: c.data.startswith('renew_key_')) async def process_callback_renew_key(callback_query: types.CallbackQuery): tg_id = callback_query.from_user.id diff --git a/key_management.py b/key_management.py index 6a595d6c..f6a3d9df 100644 --- a/key_management.py +++ b/key_management.py @@ -28,12 +28,20 @@ class Form(StatesGroup): waiting_for_key_name = State() viewing_profile = State() -# Обработка нажатия кнопки создания ключа @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): + + # Получаем данные о trial из базы данных + conn = await asyncpg.connect(DATABASE_URL) + try: + existing_connection = await conn.fetchrow('SELECT trial FROM connections WHERE tg_id = $1', tg_id) + finally: + await conn.close() + + trial_status = existing_connection['trial'] if existing_connection else 0 + + if trial_status == 1: await callback_query.message.edit_text( "У вас уже есть активный ключ. Вы можете создать новый ключ за дополнительную плату в размере 100 рублей. " "Хотите продолжить?", @@ -49,16 +57,28 @@ async def process_callback_create_key(callback_query: CallbackQuery, state: FSMC 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): + tg_id = callback_query.from_user.id + + # Проверяем баланс перед созданием нового ключа + balance = await get_balance(tg_id) + if balance < 100: + replenish_button = InlineKeyboardButton(text='Перейти в профиль', callback_data='view_profile') + keyboard = InlineKeyboardMarkup(inline_keyboard=[[replenish_button]]) + await callback_query.message.edit_text("Недостаточно средств на балансе для создания нового ключа.", reply_markup=keyboard) + await state.clear() + return + 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, state: FSMContext): + await process_callback_view_profile(callback_query, state) await callback_query.answer() # Обработка текстовых сообщений