-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathceylontgbot.py
More file actions
1079 lines (929 loc) · 59.4 KB
/
ceylontgbot.py
File metadata and controls
1079 lines (929 loc) · 59.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
import telebot
import firebase_admin
from firebase_admin import credentials, db
import requests
import time
import threading
from telebot import types
import datetime
import re
BOT_TOKEN = 'YOUR_BOT_TOKEN'
ADMIN_ID = 123456789
API_BASE_URL = 'ЗДЕСЬ БЛЯТЬ API_BASE_URL'
API_PASSWORD = "А ВОТ ЗДЕСЬ API_PASSWORD"
FIREBASE_URL = 'А ЗДЕСЬ КОРОЧЕ FIREBASE_DATABASE_URL'
SERVICE_ACCOUNT_KEY_PATH = "serviceAccountKey.json"
try:
cred = credentials.Certificate(SERVICE_ACCOUNT_KEY_PATH)
firebase_admin.initialize_app(cred, {
'databaseURL': FIREBASE_URL
})
db = db
except Exception as e:
print(f"Error initializing Firebase: {e}")
print(f"Please ensure '{SERVICE_ACCOUNT_KEY_PATH}' is correct and the Firebase URL is set.")
exit()
bot = telebot.TeleBot(BOT_TOKEN)
@bot.message_handler(commands=['start'])
def start(message):
user_id = message.from_user.id
markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
markup.row(types.KeyboardButton('Ввести код доступа'))
markup.row(types.KeyboardButton('Моя подписка'), types.KeyboardButton('Поддержка'))
if user_id == ADMIN_ID:
markup.row(types.KeyboardButton('Админ-панель'))
bot.send_message(user_id,
"Добро пожаловать в бот Ceylon Client!\n\nЗдесь вы можете получить доступ к клиенту и управлять вашей подпиской.",
reply_markup=markup)
@bot.message_handler(commands=['help'])
def help_command(message):
help_text = """
Добро пожаловать! 👋
Этот бот поможет вам получить доступ к Ceylon Client.
📌 Команды:
/start -- Начать
/help -- Показать подсказки
/status -- Проверить подписку
/support -- Написать в поддержку
/minecraft_broadcast -- Отправить сообщение в Minecraft (админ)
💰 Где купить звёздочки (⭐):
1) Официально в Телеграме
2) На FunPay
3) На Fragment
📩 Нужна помощь?
-- Используйте команду /support
-- Опишите ситуацию как можно подробнее
-- При желании прикрепите скриншот
Контакт для связи: @AlliSighs
"""
bot.send_message(message.chat.id, help_text)
@bot.message_handler(commands=['status'])
def status_command(message):
user_id_str = str(message.from_user.id)
ban_ref = db.reference(f'userBans/{user_id_str}').get()
if ban_ref and ban_ref.get('banEndTime', 0) > int(time.time() * 1000):
ban_end_date_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(ban_ref.get('banEndTime') / 1000))
reason = ban_ref.get('reason', 'Без указания причины')
bot.send_message(user_id_str, f"❌ Ваш аккаунт заблокирован до {ban_end_date_str}.\nПричина: {reason}\nОбратитесь в поддержку для разъяснений.")
return
access_codes = db.reference('accessCodes').order_by_child('telegramId').equal_to(user_id_str).get()
if not access_codes:
bot.send_message(user_id_str, "У вас нет привязанного кода доступа. Введите код из клиента, используя кнопку 'Ввести код доступа'.")
return
subscriptions = db.reference('subscriptions').order_by_child('telegramId').equal_to(user_id_str).get()
has_active_subscription = False
end_time = 0
if subscriptions:
for sub_id, sub_data in subscriptions.items():
if sub_data.get('endTime', 0) > int(time.time() * 1000):
has_active_subscription = True
end_time = sub_data.get('endTime', 0)
break
if not has_active_subscription:
bot.send_message(user_id_str, "У вас нет активной подписки. Приобретите подписку с помощью кнопки 'Моя подписка'.")
return
end_date_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(end_time / 1000))
days_left = int((end_time / 1000 - time.time()) / (24 * 60 * 60))
response = f"📊 Статус вашей подписки:\n\nАктивна до: {end_date_str}\nОсталось дней: {days_left}\n\n"
response += "Для продления нажмите кнопку 'Моя подписка'"
bot.send_message(user_id_str, response)
@bot.message_handler(commands=['support'])
def support_command(message):
bot.send_message(message.chat.id, "Опишите вашу проблему, и мы постараемся помочь вам в ближайшее время:")
bot.register_next_step_handler(message, process_support_request)
def process_support_request(message):
user_id_str = str(message.from_user.id)
username = message.from_user.username or f"User_{user_id_str}"
support_text = message.text.strip()
if not support_text:
bot.send_message(user_id_str, "Сообщение не может быть пустым. Попробуйте снова:")
bot.register_next_step_handler(message, process_support_request)
return
db.reference('supportRequests').push({
'telegramId': user_id_str,
'username': username,
'message': support_text,
'timestamp': int(time.time() * 1000),
'status': 'pending'
})
bot.send_message(user_id_str, "Ваш запрос принят. Мы свяжемся с вами в ближайшее время.")
admin_message = f"Новый запрос в поддержку:\n\nОт: @{username} (ID: {user_id_str})\n\nСообщение:\n{support_text}"
markup = types.InlineKeyboardMarkup()
markup.row(types.InlineKeyboardButton("Ответить", callback_data=f"reply_{user_id_str}"))
bot.send_message(ADMIN_ID, admin_message, reply_markup=markup)
@bot.callback_query_handler(func=lambda call: call.data.startswith('reply_'))
def handle_reply_callback(call):
user_id_to_reply = call.data.split('_')[1]
bot.answer_callback_query(call.id)
bot.send_message(ADMIN_ID, f"Введите ответ для пользователя (ID: {user_id_to_reply}):")
bot.register_next_step_handler(call.message, lambda msg: send_reply_to_user(msg, user_id_to_reply))
def send_reply_to_user(message, user_id_to_reply):
reply_text = message.text.strip()
if not reply_text:
bot.send_message(ADMIN_ID, "Ответ не может быть пустым. Попробуйте снова:")
bot.register_next_step_handler(message, lambda msg: send_reply_to_user(msg, user_id_to_reply))
return
try:
bot.send_message(user_id_to_reply, f"Ответ от службы поддержки:\n\n{reply_text}")
bot.send_message(ADMIN_ID, f"Ответ пользователю (ID: {user_id_to_reply}) отправлен.")
support_requests = db.reference('supportRequests').order_by_child('telegramId').equal_to(user_id_to_reply).get()
if support_requests:
for req_id, req_data in support_requests.items():
if req_data.get('status') == 'pending':
db.reference(f'supportRequests/{req_id}').update({'status': 'answered'})
except Exception as e:
bot.send_message(ADMIN_ID, f"Ошибка при отправке ответа пользователю {user_id_to_reply}: {e}")
@bot.message_handler(commands=['minecraft_broadcast'])
def minecraft_broadcast_command(message):
if message.from_user.id != ADMIN_ID:
bot.send_message(message.chat.id, "Эта команда доступна только администратору.")
return
bot.send_message(ADMIN_ID, "Введите сообщение для рассылки всем игрокам в Minecraft:")
bot.register_next_step_handler(message, process_minecraft_broadcast)
def process_minecraft_broadcast(message):
broadcast_text = message.text.strip()
if not broadcast_text:
bot.send_message(ADMIN_ID, "Сообщение не может быть пустым. Попробуйте снова:")
bot.register_next_step_handler(message, process_minecraft_broadcast)
return
markup = types.InlineKeyboardMarkup()
markup.row(
types.InlineKeyboardButton("Подтвердить", callback_data="mc_bc_confirm"),
types.InlineKeyboardButton("Отменить", callback_data="mc_bc_cancel")
)
bot.send_message(ADMIN_ID, f"Вы собираетесь отправить следующее сообщение всем игрокам в Minecraft:\n\n{broadcast_text}", reply_markup=markup)
db.reference('temp/minecraft_broadcast_admin').set({
'message': broadcast_text,
'admin_id': message.from_user.id,
'createdAt': int(time.time() * 1000)
})
@bot.callback_query_handler(func=lambda call: call.data.startswith('mc_bc_'))
def handle_minecraft_broadcast_callback(call):
action = call.data.split('_')[2]
temp_broadcast_data = db.reference('temp/minecraft_broadcast_admin').get()
if action == 'cancel':
bot.edit_message_text("Рассылка в Minecraft отменена.", call.message.chat.id, call.message.message_id)
db.reference('temp/minecraft_broadcast_admin').delete()
bot.answer_callback_query(call.id)
return
if action == 'confirm':
if not temp_broadcast_data or temp_broadcast_data.get('admin_id') != call.from_user.id:
bot.edit_message_text("Ошибка: сообщение для рассылки не найдено или устарело.", call.message.chat.id, call.message.message_id)
bot.answer_callback_query(call.id)
return
broadcast_text = temp_broadcast_data.get('message', '')
try:
db.reference('adminBroadcasts').push({
'content': broadcast_text,
'timestamp': int(time.time() * 1000)
})
bot.edit_message_text("Сообщение поставлено в очередь на отправку в Minecraft.", call.message.chat.id, call.message.message_id)
db.reference('temp/minecraft_broadcast_admin').delete()
except Exception as e:
bot.edit_message_text(f"Ошибка при отправке сообщения в Minecraft: {e}", call.message.chat.id, call.message.message_id)
bot.answer_callback_query(call.id)
@bot.message_handler(func=lambda message: message.text == 'Ввести код доступа')
def enter_access_code(message):
bot.send_message(message.chat.id, "Введите 8-значный код доступа, который отображается в клиенте:")
bot.register_next_step_handler(message, process_access_code)
def process_access_code(message):
user_id_str = str(message.from_user.id)
access_code = message.text.strip().replace("-", "")
if not access_code.isdigit() or len(access_code) != 8:
bot.send_message(user_id_str, "Неверный формат кода. Код должен состоять из 8 цифр. Попробуйте снова:")
bot.register_next_step_handler(message, process_access_code)
return
access_code_ref = db.reference(f'accessCodes/{access_code}')
access_code_data = access_code_ref.get()
if not access_code_data:
bot.send_message(user_id_str, "Код не найден. Проверьте правильность ввода и попробуйте снова.")
return
if access_code_data.get('isLinked', False) and access_code_data.get('telegramId') != user_id_str:
bot.send_message(user_id_str, "Этот код уже привязан к другому Telegram аккаунту.")
return
username = message.from_user.username or f"User_{user_id_str}"
access_code_ref.update({
'isLinked': True,
'telegramId': user_id_str,
'linkedUsername': username,
'linkedAt': int(time.time() * 1000)
})
subscriptions = db.reference('subscriptions').order_by_child('telegramId').equal_to(user_id_str).get()
has_active_subscription = False
if subscriptions:
for sub_data in subscriptions.values():
if sub_data.get('endTime', 0) > int(time.time() * 1000):
has_active_subscription = True
break
if has_active_subscription:
bot.send_message(user_id_str, "Код доступа успешно привязан к вашему аккаунту! У вас уже есть активная подписка, можете входить в клиент.")
else:
markup = types.InlineKeyboardMarkup()
markup.row(
types.InlineKeyboardButton("3 месяца (100 ⭐)", callback_data="sub_3_100"),
types.InlineKeyboardButton("6 месяцев (355 ⭐)", callback_data="sub_6_355")
)
markup.row(types.InlineKeyboardButton("12 месяцев (888 ⭐) (СКИДКА)", callback_data="sub_12_888"))
free_trial_used_ref = db.reference(f'userProfiles/{user_id_str}/freeTrialUsed').get()
if not free_trial_used_ref:
markup.row(types.InlineKeyboardButton("🎁 2 недели бесплатно", callback_data="sub_free_14"))
bot.send_message(user_id_str, "Код доступа успешно привязан! Теперь вам нужно приобрести подписку или активировать пробный период:", reply_markup=markup)
@bot.message_handler(func=lambda message: message.text == 'Моя подписка')
def my_subscription(message):
user_id_str = str(message.from_user.id)
ban_ref = db.reference(f'userBans/{user_id_str}').get()
if ban_ref and ban_ref.get('banEndTime', 0) > int(time.time() * 1000):
ban_end_date_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(ban_ref.get('banEndTime') / 1000))
reason = ban_ref.get('reason', 'Без указания причины')
bot.send_message(user_id_str, f"❌ Ваш аккаунт заблокирован до {ban_end_date_str}.\nПричина: {reason}\nОбратитесь в поддержку.")
return
access_codes = db.reference('accessCodes').order_by_child('telegramId').equal_to(user_id_str).get()
if not access_codes:
bot.send_message(user_id_str, "У вас нет привязанного кода доступа. Сначала введите код из клиента, нажав 'Ввести код доступа'.")
return
subscriptions = db.reference('subscriptions').order_by_child('telegramId').equal_to(user_id_str).get()
has_active_subscription = False
current_end_time = 0
if subscriptions:
for sub_data in subscriptions.values():
if sub_data.get('endTime', 0) > int(time.time() * 1000):
has_active_subscription = True
current_end_time = sub_data.get('endTime', 0)
break
markup = types.InlineKeyboardMarkup()
markup.row(
types.InlineKeyboardButton("3 месяца (100 ⭐)", callback_data="sub_3_100"),
types.InlineKeyboardButton("6 месяцев (355 ⭐)", callback_data="sub_6_355")
)
markup.row(types.InlineKeyboardButton("12 месяцев (888 ⭐) (СКИДКА)", callback_data="sub_12_888"))
free_trial_used_ref = db.reference(f'userProfiles/{user_id_str}/freeTrialUsed').get()
if not free_trial_used_ref:
markup.row(types.InlineKeyboardButton("🎁 2 недели бесплатно", callback_data="sub_free_14"))
if has_active_subscription:
end_date_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(current_end_time / 1000))
days_left = int((current_end_time / 1000 - time.time()) / (24 * 60 * 60))
message_text = f"📊 Ваша подписка:\n\nАктивна до: {end_date_str}\nОсталось дней: {days_left}\n\nХотите продлить или выбрать другой план?"
bot.send_message(user_id_str, message_text, reply_markup=markup)
else:
bot.send_message(user_id_str, "У вас нет активной подписки. Выберите план:", reply_markup=markup)
@bot.callback_query_handler(func=lambda call: call.data.startswith('sub_'))
def handle_subscription_callback(call):
parts = call.data.split('_')
user_id_str = str(call.message.chat.id)
bot.answer_callback_query(call.id)
ban_ref = db.reference(f'userBans/{user_id_str}').get()
if ban_ref and ban_ref.get('banEndTime', 0) > int(time.time() * 1000):
ban_end_date_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(ban_ref.get('banEndTime') / 1000))
reason = ban_ref.get('reason', 'Без указания причины')
bot.send_message(user_id_str, f"❌ Невозможно оформить подписку. Ваш аккаунт заблокирован до {ban_end_date_str}.\nПричина: {reason}")
return
if parts[1] == "free":
days = int(parts[2])
free_trial_ref = db.reference(f'userProfiles/{user_id_str}/freeTrialUsed')
if free_trial_ref.get():
bot.send_message(user_id_str, "Вы уже использовали свой бесплатный пробный период. Пожалуйста, выберите платный тариф.")
return
bot.send_message(user_id_str, f"Вы выбрали пробный доступ на {days} дней бесплатно. Активирую...")
try:
response = requests.post(f"{API_BASE_URL}/admin", json={
"action": "createSubscription",
"telegramId": user_id_str,
"durationDays": days,
"apiPassword": API_PASSWORD,
"isFreeTrial": True
})
response.raise_for_status()
data = response.json()
if data.get("success"):
end_time = data.get('endTime', 0)
db.reference(f'userProfiles/{user_id_str}/freeTrialUsed').set(True)
db.reference(f'userProfiles/{user_id_str}/freeTrialActivatedAt').set(int(time.time() * 1000))
if end_time:
end_date_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(end_time / 1000))
bot.send_message(user_id_str, f"✅ Пробный доступ активирован! Ваша подписка активна до {end_date_str}.\nТеперь вы можете войти в клиент.")
else:
bot.send_message(user_id_str, "✅ Пробный доступ активирован! Теперь вы можете войти в клиент.")
start(call.message)
else:
error_msg = data.get("error", "Неизвестная ошибка.")
bot.send_message(user_id_str, f"⚠️ Произошла ошибка при активации пробной подписки: {error_msg}. Пожалуйста, обратитесь в поддержку.")
except requests.exceptions.HTTPError as http_err:
bot.send_message(user_id_str, f"⚠️ Ошибка сервера при активации пробной подписки: {http_err}. Пожалуйста, обратитесь в поддержку.")
except Exception as e:
bot.send_message(user_id_str, f"⚠️ Произошла ошибка: {str(e)}. Пожалуйста, обратитесь в поддержку.")
return
months = int(parts[1])
price = int(parts[2])
send_invoice(call.message.chat.id, months, price)
def send_invoice(chat_id, months, price):
title = f"Подписка Ceylon Client на {months} мес."
description = f"Доступ к Ceylon Client на {months} месяцев. После оплаты подписка активируется автоматически."
invoice_payload = f"sub_{months}_{price}_{chat_id}"
provider_token = ""
currency = "XTR"
prices = [types.LabeledPrice(label=f"Подписка на {months} мес.", amount=price)]
try:
bot.send_invoice(
chat_id,
title,
description,
invoice_payload,
provider_token,
currency,
prices,
photo_url="https://i.ibb.co/BK5jMf8c/license-bg.png",
photo_height=512,
photo_width=512,
is_flexible=False,
start_parameter=f"ceylon-sub-{months}m"
)
except Exception as e:
bot.send_message(chat_id, f"Не удалось создать счет на оплату: {e}. Попробуйте позже или свяжитесь с поддержкой.")
print(f"Error sending invoice: {e}")
@bot.pre_checkout_query_handler(func=lambda query: True)
def process_pre_checkout_query(pre_checkout_query):
bot.answer_pre_checkout_query(pre_checkout_query.id, ok=True)
@bot.message_handler(content_types=['successful_payment'])
def process_successful_payment(message):
payload_parts = message.successful_payment.invoice_payload.split('_')
if len(payload_parts) >= 3 and payload_parts[0] == "sub":
try:
months = int(payload_parts[1])
days = months * 30
user_id_str = str(message.from_user.id)
response = requests.post(f"{API_BASE_URL}/admin", json={
"action": "createSubscription",
"telegramId": user_id_str,
"durationDays": days,
"apiPassword": API_PASSWORD,
"paymentInfo": {
"amount": message.successful_payment.total_amount,
"currency": message.successful_payment.currency,
"payload": message.successful_payment.invoice_payload
}
})
response.raise_for_status()
data = response.json()
if data.get("success"):
end_time = data.get('endTime', 0)
if end_time:
end_date_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(end_time / 1000))
bot.send_message(message.chat.id, f"🎉 Спасибо за покупку! Ваша подписка на {months} мес. активна до {end_date_str}.\nТеперь вы можете войти в клиент.")
else:
bot.send_message(message.chat.id, f"🎉 Спасибо за покупку! Ваша подписка на {months} мес. активирована.")
start(message)
else:
error_msg = data.get("error", "Неизвестная ошибка.")
bot.send_message(message.chat.id, f"⚠️ Произошла ошибка при активации подписки после оплаты: {error_msg}. Пожалуйста, срочно обратитесь в поддержку, предоставив детали платежа.")
except requests.exceptions.HTTPError as http_err:
bot.send_message(message.chat.id, f"⚠️ Ошибка сервера при активации подписки после оплаты: {http_err}. Пожалуйста, срочно обратитесь в поддержку.")
except Exception as e:
bot.send_message(message.chat.id, f"⚠️ Произошла критическая ошибка обработки платежа: {str(e)}. Пожалуйста, срочно обратитесь в поддержку.")
else:
bot.send_message(message.chat.id, "Платеж получен, но не удалось распознать детали подписки. Свяжитесь с поддержкой.")
@bot.message_handler(func=lambda message: message.text == 'Админ-панель' and message.from_user.id == ADMIN_ID)
def admin_panel(message):
markup = types.ReplyKeyboardMarkup(resize_keyboard=True, row_width=2)
markup.add(
types.KeyboardButton('Статистика'), types.KeyboardButton('Список пользователей'),
types.KeyboardButton('Выдать подписку'), types.KeyboardButton('Удалить дни подписки'),
types.KeyboardButton('Забанить пользователя'), types.KeyboardButton('Разбанить пользователя'),
types.KeyboardButton('Рассылка'), types.KeyboardButton('Minecraft Broadcast'),
types.KeyboardButton('Назад')
)
bot.send_message(ADMIN_ID, "Админ-панель Ceylon Client", reply_markup=markup)
@bot.message_handler(func=lambda message: message.text == 'Статистика' and message.from_user.id == ADMIN_ID)
def admin_statistics(message):
try:
access_codes = db.reference('accessCodes').get()
access_codes_count = len(access_codes) if access_codes else 0
linked_codes_count = 0
if access_codes:
for code_data in access_codes.values():
if code_data.get('isLinked', False):
linked_codes_count += 1
active_subs_count = 0
total_users_with_subs = set()
subscriptions = db.reference('subscriptions').get()
if subscriptions:
for sub_data in subscriptions.values():
total_users_with_subs.add(sub_data.get('telegramId'))
if sub_data.get('endTime', 0) > int(time.time() * 1000):
active_subs_count += 1
banned_users_count = 0
user_bans = db.reference('userBans').get()
if user_bans:
for ban_data in user_bans.values():
if ban_data.get('banEndTime', 0) > int(time.time() * 1000):
banned_users_count +=1
stats_text = f"""
📊 Статистика Ceylon Client:
Коды доступа:
Всего сгенерировано: {access_codes_count}
Привязано к TG: {linked_codes_count}
Подписки:
Активных подписок: {active_subs_count}
Всего пользователей с подписками (когда-либо): {len(total_users_with_subs)}
Пользователи:
Забанено активных: {banned_users_count}
"""
bot.send_message(ADMIN_ID, stats_text)
except Exception as e:
bot.send_message(ADMIN_ID, f"Ошибка при получении статистики: {e}")
@bot.message_handler(func=lambda message: message.text == 'Список пользователей' and message.from_user.id == ADMIN_ID)
def admin_list_users(message):
try:
active_users_data = []
subscriptions = db.reference('subscriptions').get()
users_processed = set()
if subscriptions:
sorted_subs = sorted(subscriptions.items(), key=lambda item: item[1].get('endTime', 0), reverse=True)
for sub_id, sub_data in sorted_subs:
telegram_id_str = str(sub_data.get('telegramId'))
if telegram_id_str in users_processed:
continue
end_time_ms = sub_data.get('endTime', 0)
if end_time_ms > int(time.time() * 1000):
days_left = int((end_time_ms / 1000 - time.time()) / (24 * 60 * 60))
username = "N/A"
try:
user_info = bot.get_chat(telegram_id_str)
username = user_info.username or f"User_{telegram_id_str}"
except Exception:
username = f"User_{telegram_id_str}_(Info_Err)"
ban_info = db.reference(f'userBans/{telegram_id_str}').get()
ban_status_str = ""
if ban_info and ban_info.get('banEndTime', 0) > int(time.time() * 1000):
ban_end_date = time.strftime('%Y-%m-%d', time.localtime(ban_info.get('banEndTime',0)/1000))
ban_status_str = f" (⛔ ЗАБАНЕН до {ban_end_date})"
active_users_data.append(f"👤 @{username} (ID: {telegram_id_str}) - {days_left} дн.{ban_status_str}")
users_processed.add(telegram_id_str)
if not active_users_data:
bot.send_message(ADMIN_ID, "Активных пользователей с подпиской не найдено.")
return
response_text_header = "👥 Список активных пользователей:\n(ID пользователя кликабельно для копирования)\n\n"
formatted_lines = []
for line in active_users_data:
match = re.search(r'\(ID: (\d+)\)', line)
if match:
tg_id = match.group(1)
line_with_code_id = line.replace(f"(ID: {tg_id})", f"(ID: `{tg_id}`)")
formatted_lines.append(line_with_code_id)
else:
formatted_lines.append(line)
current_message_part = response_text_header
for line in formatted_lines:
if len(current_message_part) + len(line) + 2 > 4096:
bot.send_message(ADMIN_ID, current_message_part, parse_mode="Markdown")
current_message_part = ""
current_message_part += line + "\n"
if current_message_part:
bot.send_message(ADMIN_ID, current_message_part, parse_mode="Markdown")
except Exception as e:
bot.send_message(ADMIN_ID, f"Ошибка при получении списка пользователей: {e}")
def admin_ask_user_id(message, next_step_handler, *args):
bot.send_message(ADMIN_ID, "Введите Telegram ID пользователя:")
bot.register_next_step_handler(message, next_step_handler, *args)
def admin_validate_user_id(message, success_callback, *args):
user_id_input = message.text.strip()
if not user_id_input.isdigit():
bot.send_message(ADMIN_ID, "Неверный формат ID. Введите числовой Telegram ID:")
bot.register_next_step_handler(message, admin_validate_user_id, success_callback, *args)
return None, None
target_user_id_str = user_id_input
try:
user_info = bot.get_chat(target_user_id_str)
target_username = user_info.username or f"User_{target_user_id_str}"
bot.send_message(ADMIN_ID, f"Найден пользователь: @{target_username} (ID: {target_user_id_str}).")
return target_user_id_str, target_username
except Exception as e:
bot.send_message(ADMIN_ID, f"Пользователь с ID {target_user_id_str} не найден или произошла ошибка: {e}. Попробуйте снова:")
bot.register_next_step_handler(message, admin_validate_user_id, success_callback, *args)
return None, None
@bot.message_handler(func=lambda message: message.text == 'Выдать подписку' and message.from_user.id == ADMIN_ID)
def admin_give_subscription_start(message):
admin_ask_user_id(message, process_give_sub_get_user_id)
def process_give_sub_get_user_id(message):
target_user_id_str, target_username = admin_validate_user_id(message, process_give_sub_get_days)
if target_user_id_str:
process_give_sub_get_days(message, target_user_id_str, target_username)
def process_give_sub_get_days(message, target_user_id_str, target_username):
bot.send_message(ADMIN_ID, f"Введите количество дней подписки для @{target_username} (ID: {target_user_id_str}):")
bot.register_next_step_handler(message, process_give_sub_execute, target_user_id_str, target_username)
def process_give_sub_execute(message, target_user_id_str, target_username):
try:
days = int(message.text.strip())
if days <= 0:
bot.send_message(ADMIN_ID, "Количество дней должно быть положительным. Попробуйте снова:")
bot.register_next_step_handler(message, process_give_sub_execute, target_user_id_str, target_username)
return
response = requests.post(f"{API_BASE_URL}/admin", json={
"action": "createSubscription",
"telegramId": target_user_id_str,
"durationDays": days,
"apiPassword": API_PASSWORD,
"adminAction": True,
"grantedBy": str(ADMIN_ID)
})
response.raise_for_status()
data = response.json()
if data.get("success"):
end_time = data.get('endTime', 0)
end_date_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(end_time / 1000)) if end_time else "N/A"
admin_msg = f"Подписка для @{target_username} (ID: {target_user_id_str}) успешно выдана/продлена на {days} дней. Активна до: {end_date_str}"
user_msg = f"🎉 Администратор выдал вам подписку на {days} дней! Ваша подписка теперь активна до {end_date_str}."
bot.send_message(ADMIN_ID, admin_msg)
try:
bot.send_message(target_user_id_str, user_msg)
except Exception as e:
bot.send_message(ADMIN_ID, f"Не удалось уведомить пользователя {target_user_id_str}: {e}")
else:
bot.send_message(ADMIN_ID, f"Ошибка при выдаче подписки @{target_username}: {data.get('error', 'Неизвестная ошибка API')}")
except ValueError:
bot.send_message(ADMIN_ID, "Неверный формат. Введите число дней:")
bot.register_next_step_handler(message, process_give_sub_execute, target_user_id_str, target_username)
except requests.exceptions.HTTPError as http_err:
bot.send_message(ADMIN_ID, f"Ошибка API при выдаче подписки: {http_err}")
except Exception as e:
bot.send_message(ADMIN_ID, f"Произошла непредвиденная ошибка: {e}")
@bot.message_handler(func=lambda message: message.text == 'Удалить дни подписки' and message.from_user.id == ADMIN_ID)
def admin_remove_sub_days_start(message):
admin_ask_user_id(message, process_remove_sub_get_user_id)
def process_remove_sub_get_user_id(message):
target_user_id_str, target_username = admin_validate_user_id(message, process_remove_sub_get_days)
if target_user_id_str:
process_remove_sub_get_days(message, target_user_id_str, target_username)
def process_remove_sub_get_days(message, target_user_id_str, target_username):
bot.send_message(ADMIN_ID, f"Сколько дней подписки удалить у @{target_username} (ID: {target_user_id_str})?")
bot.register_next_step_handler(message, process_remove_sub_get_reason, target_user_id_str, target_username)
def process_remove_sub_get_reason(message, target_user_id_str, target_username):
try:
days_to_remove = int(message.text.strip())
if days_to_remove <= 0:
bot.send_message(ADMIN_ID, "Количество дней для удаления должно быть положительным. Попробуйте снова:")
bot.register_next_step_handler(message, process_remove_sub_get_reason, target_user_id_str, target_username)
return
bot.send_message(ADMIN_ID, f"Введите причину удаления {days_to_remove} дней подписки у @{target_username} (можно пропустить, нажав /skip):")
bot.register_next_step_handler(message, process_remove_sub_execute, target_user_id_str, target_username, days_to_remove)
except ValueError:
bot.send_message(ADMIN_ID, "Неверный формат. Введите число дней для удаления:")
bot.register_next_step_handler(message, process_remove_sub_get_reason, target_user_id_str, target_username)
def process_remove_sub_execute(message, target_user_id_str, target_username, days_to_remove):
reason = message.text.strip()
if reason.lower() == '/skip':
reason = "Причина не указана администратором."
try:
response = requests.post(f"{API_BASE_URL}/admin", json={
"action": "removeSubscriptionDays",
"telegramId": target_user_id_str,
"daysToRemove": days_to_remove,
"reason": reason,
"apiPassword": API_PASSWORD,
"adminId": str(ADMIN_ID)
})
response.raise_for_status()
data = response.json()
if data.get("success"):
new_end_time = data.get('newEndTime', 0)
new_end_date_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(new_end_time / 1000)) if new_end_time > 0 else "Подписка закончилась"
admin_msg = f"У пользователя @{target_username} (ID: {target_user_id_str}) удалено {days_to_remove} дней подписки.\nПричина: {reason}\nНовая дата окончания: {new_end_date_str}"
user_msg = f"⚠️ Администратор удалил {days_to_remove} дней с вашей подписки.\nПричина: {reason}\nВаша подписка теперь активна до: {new_end_date_str}"
if new_end_time <= int(time.time() * 1000) :
user_msg = f"⚠️ Администратор удалил {days_to_remove} дней с вашей подписки, и она закончилась.\nПричина: {reason}\nДля возобновления доступа приобретите новую подписку."
bot.send_message(ADMIN_ID, admin_msg)
try:
bot.send_message(target_user_id_str, user_msg)
except Exception as e:
bot.send_message(ADMIN_ID, f"Не удалось уведомить пользователя {target_user_id_str}: {e}")
else:
bot.send_message(ADMIN_ID, f"Ошибка при удалении дней подписки у @{target_username}: {data.get('error', 'Неизвестная ошибка API')}")
except requests.exceptions.HTTPError as http_err:
bot.send_message(ADMIN_ID, f"Ошибка API при удалении дней: {http_err} - {http_err.response.text}")
except Exception as e:
bot.send_message(ADMIN_ID, f"Произошла непредвиденная ошибка: {e}")
@bot.message_handler(func=lambda message: message.text == 'Забанить пользователя' and message.from_user.id == ADMIN_ID)
def admin_ban_user_start(message):
admin_ask_user_id(message, process_ban_user_get_user_id)
def process_ban_user_get_user_id(message):
target_user_id_str, target_username = admin_validate_user_id(message, process_ban_user_get_duration)
if target_user_id_str:
process_ban_user_get_duration(message, target_user_id_str, target_username)
def process_ban_user_get_duration(message, target_user_id_str, target_username):
bot.send_message(ADMIN_ID, f"На сколько дней забанить @{target_username} (ID: {target_user_id_str})? (0 для перманентного бана)")
bot.register_next_step_handler(message, process_ban_user_get_reason, target_user_id_str, target_username)
def process_ban_user_get_reason(message, target_user_id_str, target_username):
try:
duration_days = int(message.text.strip())
if duration_days < 0:
bot.send_message(ADMIN_ID, "Длительность бана не может быть отрицательной. Введите 0 или положительное число дней:")
bot.register_next_step_handler(message, process_ban_user_get_reason, target_user_id_str, target_username)
return
if duration_days == 0:
duration_days = 365 * 100
bot.send_message(ADMIN_ID, f"Введите причину бана для @{target_username} (дней: {duration_days if duration_days != 36500 else 'навсегда'}):")
bot.register_next_step_handler(message, process_ban_user_execute, target_user_id_str, target_username, duration_days)
except ValueError:
bot.send_message(ADMIN_ID, "Неверный формат. Введите число дней для бана:")
bot.register_next_step_handler(message, process_ban_user_get_reason, target_user_id_str, target_username)
def process_ban_user_execute(message, target_user_id_str, target_username, duration_days):
reason = message.text.strip()
if not reason:
bot.send_message(ADMIN_ID, "Причина бана не может быть пустой. Попробуйте снова:")
bot.register_next_step_handler(message, process_ban_user_execute, target_user_id_str, target_username, duration_days)
return
try:
response = requests.post(f"{API_BASE_URL}/admin", json={
"action": "banUser",
"telegramId": target_user_id_str,
"durationDays": duration_days,
"reason": reason,
"apiPassword": API_PASSWORD,
"bannedByAdminId": str(ADMIN_ID)
})
response.raise_for_status()
data = response.json()
if data.get("success"):
ban_end_time = data.get('banEndTime', 0)
ban_duration_str = f"{duration_days} дней" if duration_days != 36500 else "навсегда"
ban_end_date_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(ban_end_time / 1000)) if ban_end_time else "N/A"
admin_msg = f"Пользователь @{target_username} (ID: {target_user_id_str}) забанен на {ban_duration_str} (до {ban_end_date_str}).\nПричина: {reason}"
user_msg = f"❌ Ваш аккаунт был заблокирован администратором на {ban_duration_str} (до {ban_end_date_str}).\nПричина: {reason}\nДля обжалования обратитесь в поддержку."
bot.send_message(ADMIN_ID, admin_msg)
try:
bot.send_message(target_user_id_str, user_msg)
except Exception as e:
bot.send_message(ADMIN_ID, f"Не удалось уведомить пользователя {target_user_id_str} о бане: {e}")
else:
bot.send_message(ADMIN_ID, f"Ошибка при бане @{target_username}: {data.get('error', 'Неизвестная ошибка API')}")
except requests.exceptions.HTTPError as http_err:
bot.send_message(ADMIN_ID, f"Ошибка API при бане: {http_err} - {http_err.response.text}")
except Exception as e:
bot.send_message(ADMIN_ID, f"Произошла непредвиденная ошибка при бане: {e}")
@bot.message_handler(func=lambda message: message.text == 'Разбанить пользователя' and message.from_user.id == ADMIN_ID)
def admin_unban_user_start(message):
admin_ask_user_id(message, process_unban_user_get_user_id)
def process_unban_user_get_user_id(message):
target_user_id_str, target_username = admin_validate_user_id(message, process_unban_user_confirm)
if target_user_id_str:
process_unban_user_confirm(message, target_user_id_str, target_username)
def process_unban_user_confirm(message, target_user_id_str, target_username):
markup = types.InlineKeyboardMarkup()
markup.add(types.InlineKeyboardButton("Да, разбанить", callback_data=f"unban_confirm_{target_user_id_str}"))
markup.add(types.InlineKeyboardButton("Отмена", callback_data="unban_cancel"))
bot.send_message(ADMIN_ID, f"Вы уверены, что хотите разбанить @{target_username} (ID: {target_user_id_str})?", reply_markup=markup)
@bot.callback_query_handler(func=lambda call: call.data.startswith('unban_'))
def handle_unban_callback(call):
bot.answer_callback_query(call.id)
action_part = call.data.split('_')
if action_part[1] == 'cancel':
bot.edit_message_text("Разбан отменен.", call.message.chat.id, call.message.message_id)
return
if action_part[1] == 'confirm':
target_user_id_str = action_part[2]
try:
user_info = bot.get_chat(target_user_id_str)
target_username = user_info.username or f"User_{target_user_id_str}"
except:
target_username = f"User_{target_user_id_str}"
try:
response = requests.post(f"{API_BASE_URL}/admin", json={
"action": "unbanUser",
"telegramId": target_user_id_str,
"apiPassword": API_PASSWORD,
"unbannedByAdminId": str(ADMIN_ID)
})
response.raise_for_status()
data = response.json()
if data.get("success"):
admin_msg = f"Пользователь @{target_username} (ID: {target_user_id_str}) успешно разбанен."
user_msg = "🎉 Ваш аккаунт был разблокирован администратором. Теперь вы снова можете пользоваться сервисом."
bot.edit_message_text(admin_msg, call.message.chat.id, call.message.message_id)
try:
bot.send_message(target_user_id_str, user_msg)
except Exception as e:
bot.send_message(ADMIN_ID, f"Не удалось уведомить пользователя {target_user_id_str} о разбане: {e}")
else:
error_msg = data.get('error', 'Неизвестная ошибка API')
bot.edit_message_text(f"Ошибка при разбане @{target_username}: {error_msg}", call.message.chat.id, call.message.message_id)
except requests.exceptions.HTTPError as http_err:
bot.edit_message_text(f"Ошибка API при разбане: {http_err} - {http_err.response.text}",call.message.chat.id, call.message.message_id)
except Exception as e:
bot.edit_message_text(f"Произошла непредвиденная ошибка при разбане: {e}",call.message.chat.id, call.message.message_id)
@bot.message_handler(func=lambda message: message.text == 'Рассылка' and message.from_user.id == ADMIN_ID)
def broadcast_message_start(message):
bot.send_message(ADMIN_ID, "Введите сообщение для рассылки всем пользователям, которые взаимодействовали с ботом:")
bot.register_next_step_handler(message, process_broadcast_message_text)
def process_broadcast_message_text(message):
broadcast_text = message.text.strip()
if not broadcast_text:
bot.send_message(ADMIN_ID, "Сообщение не может быть пустым. Попробуйте снова:")
bot.register_next_step_handler(message, process_broadcast_message_text)
return
markup = types.InlineKeyboardMarkup()
markup.row(
types.InlineKeyboardButton("Подтвердить рассылку", callback_data="bc_confirm_users"),
types.InlineKeyboardButton("Отменить", callback_data="bc_cancel_users")
)
bot.send_message(ADMIN_ID, f"Вы собираетесь отправить следующее сообщение пользователям:\n\n{broadcast_text}", reply_markup=markup)
db.reference('temp/user_broadcast_admin').set({
'message': broadcast_text,
'admin_id': message.from_user.id,
'createdAt': int(time.time() * 1000)
})
@bot.message_handler(func=lambda message: message.text == 'Minecraft Broadcast' and message.from_user.id == ADMIN_ID)
def minecraft_broadcast_button_handler(message):
minecraft_broadcast_command(message)
@bot.callback_query_handler(func=lambda call: call.data.startswith('bc_'))
def handle_user_broadcast_callback(call):
action = call.data.split('_')[1]
temp_broadcast_data = db.reference('temp/user_broadcast_admin').get()
if action == 'cancel':
bot.edit_message_text("Рассылка пользователям отменена.", call.message.chat.id, call.message.message_id)
db.reference('temp/user_broadcast_admin').delete()
bot.answer_callback_query(call.id)
return
if action == 'confirm':
if not temp_broadcast_data or temp_broadcast_data.get('admin_id') != call.from_user.id:
bot.edit_message_text("Ошибка: сообщение для рассылки не найдено или устарело.", call.message.chat.id, call.message.message_id)
bot.answer_callback_query(call.id)
return
broadcast_text = temp_broadcast_data.get('message', '')
bot.edit_message_text("Начинаю рассылку пользователям...", call.message.chat.id, call.message.message_id)
user_ids_to_notify = set()
access_codes = db.reference('accessCodes').get()
if access_codes:
for code_data in access_codes.values():
telegram_id = code_data.get('telegramId')
if telegram_id:
user_ids_to_notify.add(str(telegram_id))
subscriptions = db.reference('subscriptions').get()
if subscriptions:
for sub_data in subscriptions.values():
telegram_id = sub_data.get('telegramId')
if telegram_id:
user_ids_to_notify.add(str(telegram_id))
successful_sends = 0
failed_sends = 0
total_users = len(user_ids_to_notify)
bot.send_message(ADMIN_ID, f"Найдено {total_users} уникальных пользователей для рассылки. Старт...")
for i, user_id_str in enumerate(user_ids_to_notify):
try:
bot.send_message(user_id_str, f"📢 Объявление от администрации Ceylon Client:\n\n{broadcast_text}")
successful_sends += 1
except telebot.apihelper.ApiTelegramException as e:
print(f"Failed to send broadcast to {user_id_str}: {e}")
failed_sends += 1
except Exception as e:
print(f"Generic error sending broadcast to {user_id_str}: {e}")
failed_sends += 1
if (i + 1) % 20 == 0:
time.sleep(1)
time.sleep(0.05)
bot.send_message(ADMIN_ID, f"Рассылка пользователям завершена.\n✅ Успешно отправлено: {successful_sends}\n❌ Не удалось отправить: {failed_sends}\n👥 Всего получателей: {total_users}")
db.reference('temp/user_broadcast_admin').delete()
bot.answer_callback_query(call.id)
@bot.callback_query_handler(func=lambda call: call.data.startswith('auth_'))
def handle_auth_callback(call):
parts = call.data.split('_')
action = parts[1]
request_id = parts[2]
bot.answer_callback_query(call.id)
auth_request_ref = db.reference(f'authRequests/{request_id}')
auth_request_data = auth_request_ref.get()
if not auth_request_data:
bot.edit_message_text("🤷 Этот запрос авторизации не найден (возможно, устарел).", call.message.chat.id, call.message.message_id)
return
if auth_request_data.get('status') not in ['pending', 'sent']:
current_status_msg = f"Статус: {auth_request_data.get('status', 'неизвестен')}"
bot.edit_message_text(f"Этот запрос авторизации уже обработан или истек. {current_status_msg}", call.message.chat.id, call.message.message_id)
return
new_status = 'approved' if action == 'yes' else 'denied'
try:
auth_request_ref.update({
'status': new_status,
'completedAt': int(time.time() * 1000),
'actionTakenBy': str(call.from_user.id)
})
response = requests.post(f"{API_BASE_URL}/admin", json={
"action": "updateAuthStatus",
"requestId": request_id,
"status": new_status,
"apiPassword": API_PASSWORD
})
response.raise_for_status()
if response.json().get("success"):
message_text = "✅ Вход подтвержден. Клиент должен разблокироваться." if action == 'yes' else "❌ Вход отклонен. Клиент останется заблокированным."
bot.edit_message_text(message_text, call.message.chat.id, call.message.message_id)
else:
auth_request_ref.update({'status': 'error_api_update_failed'})
bot.edit_message_text("⚠️ Ошибка сервера при обновлении статуса авторизации через API.", call.message.chat.id, call.message.message_id)
except requests.exceptions.HTTPError as http_err:
auth_request_ref.update({'status': 'error_api_http'})
bot.edit_message_text(f"⚠️ Ошибка сети при связи с API: {http_err}. Попробуйте снова.", call.message.chat.id, call.message.message_id)
except Exception as e:
auth_request_ref.update({'status': 'error_unknown'})
bot.edit_message_text(f"Произошла непредвиденная ошибка: {e}", call.message.chat.id, call.message.message_id)
print(f"Error updating auth status for {request_id}: {e}")
@bot.message_handler(func=lambda message: message.text == 'Назад')
def go_back(message):
start(message)
@bot.message_handler(func=lambda message: message.text == 'Поддержка')
def support_button_handler(message):
support_command(message)
def check_auth_requests():
print("Auth request checker thread started.")
while True:
try:
pending_requests_snapshot = db.reference('authRequests').order_by_child('status').equal_to('pending').get()
if pending_requests_snapshot:
for request_id, request_data in pending_requests_snapshot.items():
telegram_id_str = str(request_data.get('telegramId'))
ip_address = request_data.get('ip', 'N/A')
hwid_full = request_data.get('hwid', 'N/A')
hwid_short = hwid_full[:8] + '...' if len(hwid_full) > 8 else hwid_full
request_time_unix = request_data.get('createdAt', int(time.time() * 1000)) / 1000
request_time_str = time.strftime('%Y-%m-%d %H:%M:%S UTC', time.gmtime(request_time_unix))
markup = types.InlineKeyboardMarkup()
markup.row(
types.InlineKeyboardButton("Да, это я", callback_data=f"auth_yes_{request_id}"),
types.InlineKeyboardButton("Нет, не я", callback_data=f"auth_no_{request_id}")
)
message_to_user = (
f"❓ Запрос на вход в Ceylon Client:\n\n"
f"🌍 IP адрес: {ip_address}\n"
f"💻 ID устройства: {hwid_short}\n"
f"🕒 Время запроса: {request_time_str}\n\n"
f"Это вы пытаетесь войти?"
)