-
Notifications
You must be signed in to change notification settings - Fork 8
/
main.py
278 lines (235 loc) · 10.3 KB
/
main.py
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
import time
import threading
import psycopg2
from random import randint
from datetime import datetime, timedelta
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, ChatPermissions
from telegram.ext import Updater, BaseFilter, MessageHandler, CallbackQueryHandler, CommandHandler
from telegram.error import BadRequest
class FilterNewChatMembers(BaseFilter):
''' Фильтрация сообщений о входе '''
def __init__(self):
# Пользователи проходящие проверку капчей
self.status_members = ['member', 'restricted', 'left', 'kicked']
def __call__(self, update):
user_id = update.effective_user.id
chat_id = update.effective_chat.id
message = update.effective_message
if message.new_chat_members:
# Проверка, если пользователю уже давалась капча
with con.cursor() as cur:
cur.execute('SELECT * FROM banlist WHERE chat_id=%s AND user_id=%s',
(chat_id, user_id))
if cur.fetchone():
return False
member_status = message.bot.getChatMember(chat_id, user_id)['status']
if member_status in self.status_members:
return True
return False
def banUser():
'''
Работает второстепенным потоком, банит
пользователей не ответивших или ответивших
неправильно, по истечению времени указанного в бд
'''
while True:
time.sleep(60)
with con.cursor() as cur:
cur.execute('SELECT * FROM banlist WHERE time<LOCALTIMESTAMP')
for banrecord in cur.fetchall():
ban = {
"id_record": banrecord[0],
"user_id": banrecord[1],
"chat_id": banrecord[3],
"captcha_message_id": banrecord[4]
}
cur.execute('DELETE FROM banlist WHERE id=%s', (ban['id_record'], ))
con.commit()
dispatcher.bot.kick_chat_member(
ban['chat_id'],
ban['user_id']
)
def captcha(update, context):
'''
Создаёт капчу, и отсылает пользователю,
при этом заносит его в базу данных, если не
ответит на неё в течении дня - будет кикнут
'''
user = update.effective_user
chat = update.effective_chat
captcha_answer = randint(1, 8)
kick_date = (update.message.date + timedelta(days=1)).replace(tzinfo=None)
if update.effective_user.username:
username = "@" + user.username
else:
try:
username = " ".join([user.first_name, user.last_name])
except:
username = "*какая-то дичь, а не ник*"
keyboard = InlineKeyboardMarkup([[
InlineKeyboardButton(i, callback_data=str(i)) for i in range(1, 9)
]])
captcha_msg = update.message.reply_text(
'%s, выбери цифру %s' % (username, captcha_answers[captcha_answer]),
reply_markup=keyboard
)
with con.cursor() as cur:
cur.execute(
'INSERT INTO banlist (user_id, time, chat_id, captcha_message_id, answer) VALUES (%s, %s, %s, %s, %s)',
(user.id, kick_date, chat.id, captcha_msg.message_id, captcha_answer)
)
con.commit()
context.bot.restrictChatMember(
chat.id, user.id,
permissions=ChatPermissions(can_send_messages=False)
)
def checkCorrectlyCaptcha(update, context):
'''
Проверяю правильность ответа пользователя на капчу,
если ответ правильный, то ограничение readonly снимается,
если нет, то кик через 3-ок суток и отправляется сообщение
с направлением к админу за разблокировкой
'''
chat = update.effective_chat
user = update.effective_user
message_id = update.callback_query.message.message_id
user_captcha_answer = update.callback_query.data
with con.cursor() as cur:
cur.execute(
'SELECT answer FROM banlist WHERE user_id=%s AND captcha_message_id=%s AND chat_id=%s',
(user.id, message_id, chat.id)
)
record = cur.fetchone()
if record:
# Удаляю сообщение с капчей
context.bot.delete_message(chat.id, message_id)
# Проверяю ответ пользователя на капчу
if user_captcha_answer == str(record[0]):
cur.execute(
'DELETE FROM banlist WHERE user_id=%s AND chat_id=%s',
(user.id, chat.id)
)
context.bot.restrictChatMember(
chat.id, user.id,
permissions=ChatPermissions(
can_send_messages=True,
can_send_media_messages=True,
can_send_polls=True,
can_send_other_messages=True,
can_add_web_page_previews=True,
)
)
# Если после входа пользователя в чат вы хотите что-то ему сказать - раскомментируйте фрагмент кода ниже
# try:
# if update.effective_user.username:
# username = "@" + user.username
# else:
# username = " ".join([user.first_name, user.last_name])
# except:
# username = "*какая-то дичь, а не ник*"
#
# context.bot.send_message(
# chat_id=update.effective_chat.id,
# text="%s, добро пожаловать в чатик. Будь добр(а) прочесть правила" % username
# )
else:
if update.effective_user.username:
username = "@" + user.username
else:
try:
username = " ".join([user.first_name, user.last_name])
except:
username = "*какая-то дичь, а не ник*"
context.bot.send_message(
chat_id=update.effective_chat.id,
text="%s, капча введена не правильно, обратитесь к админу в течение 3-х дней для разблокировки." % username
)
cur.execute(
'UPDATE banlist SET time=%s WHERE user_id=%s AND chat_id=%s',
(datetime.now(tz=None)+timedelta(days=3), user.id, chat.id)
)
con.commit()
def unban(update, context):
''' Убирает из бани пользователя '''
chat = update.effective_chat
command_user = update.effective_user
message = update.effective_message
member_status = message.bot.getChatMember(chat.id, command_user.id)['status']
# Будет выполнено только если комманду прислал администратор
if member_status in ['owner', 'administrator', 'creator']:
# Ищем Id пользователя для разбана, либо в
# пересланном сообщении либо указанное аргументом в комманде
command = message['text'].split(" ")
if len(command) > 1:
user_id = command[1]
elif 'reply_to_message' in message.to_dict():
user_id = message.reply_to_message.to_dict()['from']['id']
else:
return
# Снимаем бан и возвращаем права
context.bot.unban_chat_member(chat.id, user_id, only_if_banned=True)
context.bot.restrictChatMember(
chat.id, user_id,
permissions=ChatPermissions(
can_send_messages=True,
can_send_media_messages=True,
can_send_polls=True,
can_send_other_messages=True,
can_add_web_page_previews=True,
)
)
# Убираем из бд оставшиеся записи бана
with con.cursor() as cur:
cur.execute(
'SELECT captcha_message_id FROM banlist WHERE user_id=%s AND chat_id=%s',
(user_id, chat.id)
)
captcha_message_id = cur.fetchone()
if captcha_message_id:
try:
context.bot.delete_message(chat.id, captcha_message_id[0])
except BadRequest:
pass
cur.execute(
'DELETE FROM banlist WHERE user_id=%s AND chat_id=%s',
(user_id, chat.id)
)
con.commit()
def main():
global dispatcher
'''
Запускаем бота, создаём вебхуки,
привязываем обработчики и фильтры.
'''
updater = Updater(token="your_token")
dispatcher = updater.dispatcher
filter = FilterNewChatMembers()
dispatcher.add_handler(MessageHandler(filter, captcha))
dispatcher.add_handler(CallbackQueryHandler(checkCorrectlyCaptcha))
dispatcher.add_handler(CommandHandler('unban', unban))
updater.start_polling()
updater.idle()
if __name__ == "__main__":
# Connect to DB
con = psycopg2.connect(
database="database",
user="user",
password="password",
host="host",
port="5432"
)
# Словарь для конвертация цифр на слова
captcha_answers = {
1: "один",
2: "два",
3: "три",
4: "четыре",
5: "пять",
6: "шесть",
7: "семь",
8: "восемь"
}
# Второстепенный поток бана пользователей
threading.Thread(target=banUser).start()
# Тело бота
main()