├── LICENSE ├── README.md ├── Telegram Support Bot ├── bot.py ├── config.py ├── core.py ├── markup.py └── sql.py └── image.png /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Blazzerrr 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Telegram Support Bot 2 | 3 | Telegram Support Bot для технической поддержки пользователей. 4 | Имеется три вида панели: 5 | 1. Основная - она предназначена для пользователей, которые через панель будут создавать и просматривать свои запросы. 6 | 2. Панель для сотрудников технической поддержки. Доступ к этой панели можно получить, введя пароль выданный администратором. В этой панели агент поддержки может просматривать и отвечать на все запросы пользователей. 7 | 3. Админ-панель - нужна для добавления и удаления сотрудников поддержки, генерации/удаления паролей доступа, а также для отключения бота. 8 | 9 | ## Скриншот 10 | ![Screenshot](https://github.com/Blazzerrr/TelegramSupportBot/blob/master/image.png) 11 | 12 | ## Настройка 13 | Установите все зависимости из блока ниже с помощью PIP
14 | Откройте файл config.py и по документации внутри файла, заполните все обязательные для запуска переменные. 15 | После выполнения инструкции, запустите файл sql.py 16 | ```bash 17 | cd Telegram Support Bot 18 | python3 sql.py 19 | ``` 20 | Если все выполнилось без ошибок - настройка бота завершена и вы можете переходить к запуску бота. 21 | 22 | ## Запуск 23 | ```bash 24 | cd Telegram Support Bot 25 | python3 bot.py 26 | ``` 27 | 28 | ## Зависимости 29 | - pyTelegramBotAPI 30 | - cryptography 31 | - pymysql 32 | 33 | ## Донат 34 | — USDT TRC20 / TRX : **TGGu7SE2AiTqKtyiqSn8abZeh62nLZPg7N**
35 | — USDT ERC20 / ETH : **0xD2F03940ec729BfDFA79a5b7a867e8F55E470b67**
36 | — BTC: **bc1qhajqf6k3lass7sq8y2p3jg6xav6hrnguacdgsz**
37 | — XRP: **r3do8Bp7qfobrv5QmyBqp3PzJ2k8VQtGY8**
38 | — BNB: **bnb1wv357zh590hmys3z07fv56mv8uqua4cvz2p3dw**
39 | — DOGE: **DL1vn98EWknvSsbkFeruZYk3DhSLft8QWQ** 40 | -------------------------------------------------------------------------------- /Telegram Support Bot/bot.py: -------------------------------------------------------------------------------- 1 | import config 2 | import core 3 | import telebot 4 | import random 5 | import datetime 6 | import markup 7 | import sys 8 | from telebot import apihelper 9 | 10 | if config.PROXY_URL: 11 | apihelper.proxy = {'https': config.PROXY_URL} 12 | 13 | bot = telebot.TeleBot(config.TOKEN, skip_pending=True) 14 | 15 | @bot.message_handler(commands=['start']) 16 | def start(message): 17 | bot.send_message(message.chat.id, '👋🏻 Привет! Это бот для технической поддержки пользователей.\nЕсли у тебя есть какой-либо вопрос или проблема - нажми на кнопку Написать запрос и наши сотрудники в скором времени тебе ответят!', parse_mode='html', reply_markup=markup.markup_main()) 18 | 19 | 20 | @bot.message_handler(commands=['agent']) 21 | def agent(message): 22 | user_id = message.from_user.id 23 | 24 | if core.check_agent_status(user_id) == True: 25 | bot.send_message(message.chat.id, '🔑 Вы авторизованы как Агент поддержки', parse_mode='html', reply_markup=markup.markup_agent()) 26 | 27 | else: 28 | take_password_message = bot.send_message(message.chat.id, '⚠️ Тебя нет в базе. Отправь одноразовый пароль доступа.', reply_markup=markup.markup_cancel()) 29 | 30 | bot.clear_step_handler_by_chat_id(message.chat.id) 31 | bot.register_next_step_handler(take_password_message, get_password_message) 32 | 33 | 34 | @bot.message_handler(commands=['admin']) 35 | def admin(message): 36 | user_id = message.from_user.id 37 | 38 | if str(user_id) == config.ADMIN_ID: 39 | bot.send_message(message.chat.id, '🔑 Вы авторизованы как Админ', reply_markup=markup.markup_admin()) 40 | else: 41 | bot.send_message(message.chat.id, '🚫 Эта команда доступна только администратору.') 42 | 43 | 44 | @bot.message_handler(content_types=['text']) 45 | def send_text(message): 46 | user_id = message.from_user.id 47 | 48 | if message.text == '✏️ Написать запрос': 49 | take_new_request = bot.send_message(message.chat.id, 'Введите свой запрос и наши сотрудники скоро с вами свяжутся.', reply_markup=markup.markup_cancel()) 50 | 51 | bot.clear_step_handler_by_chat_id(message.chat.id) 52 | bot.register_next_step_handler(take_new_request, get_new_request) 53 | 54 | elif message.text == '✉️ Мои запросы': 55 | markup_and_value = markup.markup_reqs(user_id, 'my_reqs', '1') 56 | markup_req = markup_and_value[0] 57 | value = markup_and_value[1] 58 | 59 | if value == 0: 60 | bot.send_message(message.chat.id, 'У вас пока ещё нет запросов.', reply_markup=markup.markup_main()) 61 | else: 62 | bot.send_message(message.chat.id, 'Ваши запросы:', reply_markup=markup_req) 63 | 64 | else: 65 | bot.send_message(message.chat.id, 'Вы возвращены в главное меню.', parse_mode='html', reply_markup=markup.markup_main()) 66 | 67 | 68 | def get_password_message(message): 69 | password = message.text 70 | user_id = message.from_user.id 71 | 72 | if password == None: 73 | send_message = bot.send_message(message.chat.id, '⚠️ Вы отправляете не текст. Попробуйте еще раз.', reply_markup=markup.markup_cancel()) 74 | 75 | bot.clear_step_handler_by_chat_id(message.chat.id) 76 | bot.register_next_step_handler(send_message, get_password_message) 77 | 78 | elif password.lower() == 'отмена': 79 | bot.send_message(message.chat.id, 'Отменено.', reply_markup=markup.markup_main()) 80 | return 81 | 82 | elif core.valid_password(password) == True: 83 | core.delete_password(password) 84 | core.add_agent(user_id) 85 | 86 | bot.send_message(message.chat.id, '🔑 Вы авторизованы как Агент поддержки', parse_mode='html', reply_markup=markup.markup_main()) 87 | bot.send_message(message.chat.id, 'Выберите раздел технической панели:', parse_mode='html', reply_markup=markup.markup_agent()) 88 | 89 | else: 90 | send_message = bot.send_message(message.chat.id, '⚠️ Неверный пароль. Попробуй ещё раз.', reply_markup=markup.markup_cancel()) 91 | 92 | bot.clear_step_handler_by_chat_id(message.chat.id) 93 | bot.register_next_step_handler(send_message, get_password_message) 94 | 95 | 96 | def get_agent_id_message(message): 97 | agent_id = message.text 98 | 99 | if agent_id == None: 100 | take_agent_id_message = bot.send_message(message.chat.id, '⚠️ Вы отправляете не текст. Попробуйте еще раз.', reply_markup=markup.markup_cancel()) 101 | 102 | bot.clear_step_handler_by_chat_id(message.chat.id) 103 | bot.register_next_step_handler(take_agent_id_message, get_agent_id_message) 104 | 105 | elif agent_id.lower() == 'отмена': 106 | bot.send_message(message.chat.id, 'Отменено.', reply_markup=markup.markup_main()) 107 | return 108 | 109 | else: 110 | core.add_agent(agent_id) 111 | bot.send_message(message.chat.id, '✅ Агент успешно добавлен.', reply_markup=markup.markup_main()) 112 | bot.send_message(message.chat.id, 'Выберите раздел админ панели:', reply_markup=markup.markup_admin()) 113 | 114 | 115 | def get_new_request(message): 116 | request = message.text 117 | user_id = message.from_user.id 118 | check_file = core.get_file(message) 119 | 120 | #Если пользователь отправляет файл 121 | if check_file != None: 122 | file_id = check_file['file_id'] 123 | file_name = check_file['file_name'] 124 | type = check_file['type'] 125 | request = check_file['text'] 126 | 127 | if str(request) == 'None': 128 | take_new_request = bot.send_message(message.chat.id, '⚠️ Вы не ввели ваш запрос. Попробуйте ещё раз, отправив текст вместе с файлом.', reply_markup=markup.markup_cancel()) 129 | 130 | bot.clear_step_handler_by_chat_id(message.chat.id) 131 | bot.register_next_step_handler(take_new_request, get_new_request) 132 | 133 | else: 134 | req_id = core.new_req(user_id, request) 135 | core.add_file(req_id, file_id, file_name, type) 136 | 137 | bot.send_message(message.chat.id, f'✅ Ваш запрос под ID {req_id} создан. Посмотреть текущие запросы можно нажав кнопку Мои текущие запросы', parse_mode='html', reply_markup=markup.markup_main()) 138 | 139 | #Если пользователь отправляет только текст 140 | else: 141 | if request == None: 142 | take_new_request = bot.send_message(message.chat.id, '⚠️ Отправляемый вами тип данных не поддерживается в боте. Попробуйте еще раз отправить ваш запрос, использовав один из доступных типов данных (текст, файлы, фото, видео, аудио, голосовые сообщения)', reply_markup=markup.markup_cancel()) 143 | 144 | bot.clear_step_handler_by_chat_id(message.chat.id) 145 | bot.register_next_step_handler(take_new_request, get_new_request) 146 | 147 | elif request.lower() == 'отмена': 148 | bot.send_message(message.chat.id, 'Отменено.', reply_markup=markup.markup_main()) 149 | return 150 | 151 | else: 152 | req_id = core.new_req(user_id, request) 153 | bot.send_message(message.chat.id, f'✅ Ваш запрос под ID {req_id} создан. Посмотреть текущие запросы можно нажав кнопку Мои текущие запросы', parse_mode='html', reply_markup=markup.markup_main()) 154 | 155 | 156 | def get_additional_message(message, req_id, status): 157 | additional_message = message.text 158 | check_file = core.get_file(message) 159 | 160 | #Если пользователь отправляет файл 161 | if check_file != None: 162 | file_id = check_file['file_id'] 163 | file_name = check_file['file_name'] 164 | type = check_file['type'] 165 | additional_message = check_file['text'] 166 | 167 | core.add_file(req_id, file_id, file_name, type) 168 | 169 | if additional_message == None: 170 | take_additional_message = bot.send_message(chat_id=message.chat.id, text='⚠️ Отправляемый вами тип данных не поддерживается в боте. Попробуйте еще раз отправить ваше сообщение, использовав один из доступных типов данных (текст, файлы, фото, видео, аудио, голосовые сообщения).', reply_markup=markup.markup_cancel()) 171 | 172 | bot.clear_step_handler_by_chat_id(message.chat.id) 173 | bot.register_next_step_handler(take_additional_message, get_additional_message, req_id, status) 174 | 175 | elif additional_message.lower() == 'отмена': 176 | bot.send_message(message.chat.id, 'Отменено.', reply_markup=markup.markup_main()) 177 | return 178 | 179 | else: 180 | if additional_message != 'None': 181 | core.add_message(req_id, additional_message, status) 182 | 183 | if check_file != None: 184 | if additional_message != 'None': 185 | text = '✅ Ваш файл и сообщение успешно отправлены!' 186 | else: 187 | text = '✅ Ваш файл успешно отправлен!' 188 | else: 189 | text = '✅ Ваше сообщение успешно отправлено!' 190 | 191 | bot.send_message(message.chat.id, text, reply_markup=markup.markup_main()) 192 | 193 | if status == 'agent': 194 | user_id = core.get_user_id_of_req(req_id) 195 | try: 196 | if additional_message == 'None': 197 | additional_message = '' 198 | 199 | bot.send_message(user_id, f'⚠️ Получен новый ответ на ваш запрос ID {req_id}!\n\n🧑‍💻 Ответ агента поддержки:\n{additional_message}', reply_markup=markup.markup_main()) 200 | 201 | if type == 'photo': 202 | bot.send_photo(user_id, photo=file_id, reply_markup=markup.markup_main()) 203 | elif type == 'document': 204 | bot.send_document(user_id, data=file_id, reply_markup=markup.markup_main()) 205 | elif type == 'video': 206 | bot.send_video(user_id, data=file_id, reply_markup=markup.markup_main()) 207 | elif type == 'audio': 208 | bot.send_audio(user_id, audio=file_id, reply_markup=markup.markup_main()) 209 | elif type == 'voice': 210 | bot.send_voice(user_id, voice=file_id, reply_markup=markup.markup_main()) 211 | else: 212 | bot.send_message(user_id, additional_message, reply_markup=markup.markup_main()) 213 | except: 214 | pass 215 | 216 | 217 | @bot.callback_query_handler(func=lambda call: True) 218 | def callback_inline(call): 219 | user_id = call.message.chat.id 220 | 221 | if call.message: 222 | if ('my_reqs:' in call.data) or ('waiting_reqs:' in call.data) or ('answered_reqs:' in call.data) or ('confirm_reqs:' in call.data): 223 | """ 224 | Обработчик кнопок для: 225 | 226 | ✉️ Мои запросы 227 | ❗️ Ожидают ответа от поддержки, 228 | ⏳ Ожидают ответа от пользователя 229 | ✅ Завершенные запросы 230 | """ 231 | 232 | parts = call.data.split(':') 233 | callback = parts[0] 234 | number = parts[1] 235 | markup_and_value = markup.markup_reqs(user_id, callback, number) 236 | markup_req = markup_and_value[0] 237 | value = markup_and_value[1] 238 | 239 | if value == 0: 240 | bot.send_message(chat_id=call.message.chat.id, text='⚠️ Запросы не обнаружены.', reply_markup=markup.markup_main()) 241 | bot.answer_callback_query(call.id) 242 | return 243 | 244 | try: 245 | bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text='Нажмите на запрос, чтобы посмотреть историю переписки, либо добавить сообщение:', reply_markup=markup_req) 246 | except: 247 | bot.send_message(chat_id=call.message.chat.id, text='Ваши запросы:', reply_markup=markup_req) 248 | 249 | bot.answer_callback_query(call.id) 250 | 251 | #Открыть запрос 252 | elif 'open_req:' in call.data: 253 | parts = call.data.split(':') 254 | req_id = parts[1] 255 | callback = parts[2] 256 | 257 | req_status = core.get_req_status(req_id) 258 | request_data = core.get_request_data(req_id, callback) 259 | len_req_data = len(request_data) 260 | 261 | i = 1 262 | for data in request_data: 263 | if i == len_req_data: 264 | markup_req = markup.markup_request_action(req_id, req_status, callback) 265 | else: 266 | markup_req = None 267 | 268 | bot.send_message(chat_id=call.message.chat.id, text=data, parse_mode='html', reply_markup=markup_req) 269 | 270 | i += 1 271 | 272 | bot.answer_callback_query(call.id) 273 | 274 | #Добавить сообщение в запрос 275 | elif 'add_message:' in call.data: 276 | parts = call.data.split(':') 277 | req_id = parts[1] 278 | status_user = parts[2] 279 | 280 | take_additional_message = bot.send_message(chat_id=call.message.chat.id, text='Отправьте ваше сообщение, использовав один из доступных типов данных (текст, файлы, фото, видео, аудио, голосовые сообщения)', reply_markup=markup.markup_cancel()) 281 | 282 | bot.register_next_step_handler(take_additional_message, get_additional_message, req_id, status_user) 283 | 284 | bot.answer_callback_query(call.id) 285 | 286 | #Завершить запрос 287 | elif 'confirm_req:' in call.data: 288 | parts = call.data.split(':') 289 | confirm_status = parts[1] 290 | req_id = parts[2] 291 | 292 | if core.get_req_status(req_id) == 'confirm': 293 | bot.send_message(chat_id=call.message.chat.id, text="⚠️ Этот запрос уже завершен.", reply_markup=markup.markup_main()) 294 | bot.answer_callback_query(call.id) 295 | 296 | return 297 | 298 | #Запросить подтверждение завершения 299 | if confirm_status == 'wait': 300 | bot.send_message(chat_id=call.message.chat.id, text="Для завершения запроса - нажмите кнопку Подтвердить", parse_mode='html', reply_markup=markup.markup_confirm_req(req_id)) 301 | 302 | #Подтвердить завершение 303 | elif confirm_status == 'true': 304 | core.confirm_req(req_id) 305 | 306 | try: 307 | bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text="✅ Запрос успешно завершён.", reply_markup=markup.markup_main()) 308 | except: 309 | bot.send_message(chat_id=call.message.chat.id, text="✅ Запрос успешно завершён.", reply_markup=markup.markup_main()) 310 | 311 | bot.answer_callback_query(call.id) 312 | 313 | #Файлы запроса 314 | elif 'req_files:' in call.data: 315 | parts = call.data.split(':') 316 | req_id = parts[1] 317 | callback = parts[2] 318 | number = parts[3] 319 | 320 | markup_and_value = markup.markup_files(number, req_id, callback) 321 | markup_files = markup_and_value[0] 322 | value = markup_and_value[1] 323 | 324 | if value == 0: 325 | bot.send_message(chat_id=call.message.chat.id, text='⚠️ Файлы не обнаружены.', reply_markup=markup.markup_main()) 326 | bot.answer_callback_query(call.id) 327 | return 328 | 329 | try: 330 | bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text='Нажмите на файл, чтобы получить его.', reply_markup=markup_files) 331 | except: 332 | bot.send_message(chat_id=call.message.chat.id, text='Нажмите на файл, чтобы получить его.', reply_markup=markup_files) 333 | 334 | bot.answer_callback_query(call.id) 335 | 336 | #Отправить файл 337 | elif 'send_file:' in call.data: 338 | parts = call.data.split(':') 339 | id = parts[1] 340 | type = parts[2] 341 | 342 | file_id = core.get_file_id(id) 343 | 344 | if type == 'photo': 345 | bot.send_photo(call.message.chat.id, photo=file_id, reply_markup=markup.markup_main()) 346 | elif type == 'document': 347 | bot.send_document(call.message.chat.id, data=file_id, reply_markup=markup.markup_main()) 348 | elif type == 'video': 349 | bot.send_video(call.message.chat.id, data=file_id, reply_markup=markup.markup_main()) 350 | elif type == 'audio': 351 | bot.send_audio(call.message.chat.id, audio=file_id, reply_markup=markup.markup_main()) 352 | elif type == 'voice': 353 | bot.send_voice(call.message.chat.id, voice=file_id, reply_markup=markup.markup_main()) 354 | 355 | bot.answer_callback_query(call.id) 356 | 357 | #Вернуться назад в панель агента 358 | elif call.data == 'back_agent': 359 | try: 360 | bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text='🔑 Вы авторизованы как Агент поддержки', parse_mode='html', reply_markup=markup.markup_agent()) 361 | except: 362 | bot.send_message(call.message.chat.id, '🔑 Вы авторизованы как Агент поддержки', parse_mode='html', reply_markup=markup.markup_agent()) 363 | 364 | bot.answer_callback_query(call.id) 365 | 366 | #Вернуться назад в панель админа 367 | elif call.data == 'back_admin': 368 | try: 369 | bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text='🔑 Вы авторизованы как Админ', parse_mode='html', reply_markup=markup.markup_admin()) 370 | except: 371 | bot.send_message(call.message.chat.id, '🔑 Вы авторизованы как Админ', parse_mode='html', reply_markup=markup.markup_admin()) 372 | 373 | bot.answer_callback_query(call.id) 374 | 375 | #Добавить агента 376 | elif call.data == 'add_agent': 377 | take_agent_id_message = bot.send_message(chat_id=call.message.chat.id, text='Чтобы добавить агента поддержки - введите его ID Telegram.', reply_markup=markup.markup_cancel()) 378 | bot.register_next_step_handler(take_agent_id_message, get_agent_id_message) 379 | 380 | #Все агенты 381 | elif 'all_agents:' in call.data: 382 | number = call.data.split(':')[1] 383 | markup_and_value = markup.markup_agents(number) 384 | markup_agents = markup_and_value[0] 385 | len_agents = markup_and_value[1] 386 | 387 | if len_agents == 0: 388 | bot.send_message(chat_id=call.message.chat.id, text='⚠️ Агенты не обнаружены.', reply_markup=markup.markup_main()) 389 | bot.answer_callback_query(call.id) 390 | return 391 | 392 | try: 393 | bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text='Нажмите на агента поддержки, чтобы удалить его', parse_mode='html', reply_markup=markup_agents) 394 | except: 395 | bot.send_message(call.message.chat.id, 'Нажмите на агента поддержки, чтобы удалить его', parse_mode='html', reply_markup=markup_agents) 396 | 397 | bot.answer_callback_query(call.id) 398 | 399 | #Удалить агента 400 | elif 'delete_agent:' in call.data: 401 | agent_id = call.data.split(':')[1] 402 | core.delete_agent(agent_id) 403 | 404 | try: 405 | bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text='Нажмите на агента поддержки, чтобы удалить его', parse_mode='html', reply_markup=markup.markup_agents('1')[0]) 406 | except: 407 | bot.send_message(call.message.chat.id, 'Нажмите на агента поддержки, чтобы удалить его', parse_mode='html', reply_markup=markup.markup_agents('1')[0]) 408 | 409 | bot.answer_callback_query(call.id) 410 | 411 | #Все пароли 412 | elif 'all_passwords:' in call.data: 413 | number = call.data.split(':')[1] 414 | markup_and_value = markup.markup_passwords(number) 415 | markup_passwords = markup_and_value[0] 416 | len_passwords = markup_and_value[1] 417 | 418 | if len_passwords == 0: 419 | bot.send_message(chat_id=call.message.chat.id, text='⚠️ Пароли не обнаружены.', reply_markup=markup.markup_main()) 420 | bot.answer_callback_query(call.id) 421 | return 422 | 423 | try: 424 | bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text='Нажмите на пароль, чтобы удалить его', parse_mode='html', reply_markup=markup_passwords) 425 | except: 426 | bot.send_message(call.message.chat.id, 'Нажмите на пароль, чтобы удалить его', parse_mode='html', reply_markup=markup_passwords) 427 | 428 | bot.answer_callback_query(call.id) 429 | 430 | #Удалить пароль 431 | elif 'delete_password:' in call.data: 432 | password = call.data.split(':')[1] 433 | core.delete_password(password) 434 | 435 | try: 436 | bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text='Нажмите на пароль, чтобы удалить его', parse_mode='html', reply_markup=markup.markup_passwords('1')[0]) 437 | except: 438 | bot.send_message(call.message.chat.id, 'Нажмите на пароль, чтобы удалить его', parse_mode='html', reply_markup=markup.markup_passwords('1')[0]) 439 | 440 | bot.answer_callback_query(call.id) 441 | 442 | #Сгенерировать пароли 443 | elif call.data == 'generate_passwords': 444 | #10 - количество паролей, 16 - длина пароля 445 | passwords = core.generate_passwords(10, 16) 446 | core.add_passwords(passwords) 447 | 448 | text_passwords = '' 449 | i = 1 450 | for password in passwords: 451 | text_passwords += f'{i}. {password}\n' 452 | i += 1 453 | 454 | bot.send_message(call.message.chat.id, f"✅ Сгенерировано {i-1} паролей:\n\n{text_passwords}", parse_mode='html', reply_markup=markup.markup_main()) 455 | bot.send_message(call.message.chat.id, 'Нажмите на пароль, чтобы удалить его', parse_mode='html', reply_markup=markup.markup_passwords('1')[0]) 456 | 457 | bot.answer_callback_query(call.id) 458 | 459 | #Остановить бота 460 | elif 'stop_bot:' in call.data: 461 | status = call.data.split(':')[1] 462 | 463 | #Запросить подтверждение на отключение 464 | if status == 'wait': 465 | try: 466 | bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text=f"Вы точно хотите отключить бота?", parse_mode='html', reply_markup=markup.markup_confirm_stop()) 467 | except: 468 | bot.send_message(call.message.chat.id, f"Вы точно хотите отключить бота?", parse_mode='html', reply_markup=markup.markup_confirm_stop()) 469 | 470 | #Подтверждение получено 471 | elif status == 'confirm': 472 | try: 473 | bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text='✅ Бот оключен.') 474 | except: 475 | bot.send_message(chat_id=call.message.chat.id, text='✅ Бот оключен.') 476 | 477 | bot.answer_callback_query(call.id) 478 | bot.stop_polling() 479 | sys.exit() 480 | 481 | 482 | if __name__ == "__main__": 483 | bot.polling(none_stop=True) -------------------------------------------------------------------------------- /Telegram Support Bot/config.py: -------------------------------------------------------------------------------- 1 | """ 2 | Для начала работы с ботом вам необходимо настроить конфигурационный файл бота - config.py 3 | Обязательными переменными является TOKEN, ADMIN_ID и MySQL. 4 | PROXY_URL вы можете оставить пустым. 5 | 6 | Описывать установку и настройку я буду для Linux, Ubuntu-based дистрибутивов. Если у вас установлен Windows, либо же другой дистрибутив, то различия с гайдом ниже вы найдете только в пунктах с установкой и настройкой MySQL. Поэтому, при возникновении проблем попробуйте найти гайд по установке MySQL конкретно под вашу ОС. 7 | 8 | 1. Сначала, проверьте установлен ли MySQL на вашем ПК. 9 | Откройте терминал и пропишите команду: mysql --version 10 | Если вы увидите сообщение похожее на: mysql Ver xx.xx ****, то можете смело переходить на пункт номер 2. 11 | 12 | 1.2. Если же MySQL не установлен, то введите несколько команд в терминал: 13 | sudo apt update 14 | sudo apt install mysql-server 15 | 16 | Возвращаемся в пункт 1 и проверяем правильно ли мы все установили. 17 | Если видите сообщение с версией установленного MySQL, то переходим дальше. 18 | Если нет - возвращаемся и проверяем, что вы сделали не так. 19 | 20 | 2. С установкой MySQL закончили, переходим к созданию пользователя и БД 21 | Введите в терминал команду mysql 22 | 23 | 2.2. После этого создайте пользователя командой: 24 | CREATE USER 'user'@'localhost' IDENTIFIED BY 'password'; 25 | 26 | Где user - имя пользователя 27 | А password - пароль 28 | 29 | 2.3. Предоставьте права пользователю: 30 | GRANT ALL PRIVILEGES ON * . * TO 'user'@'localhost'; 31 | FLUSH PRIVILEGES; 32 | 33 | Где user - имя пользователя, которое вы ввели в шаге выше 34 | 35 | 2.4. Создайте БД: 36 | CREATE DATABASE support_db; 37 | 38 | Где support_db - имя базы данных 39 | 40 | 2.5. Замените все значения в переменной MySQL 41 | localhost - оставить без изменения 42 | user - имя пользователя, которого вы создали 43 | password - пароль для пользователя 44 | support_db - имя базы данных 45 | 46 | 3. Создайте вашего бота и получите токен для него 47 | Перейдите по ссылке t.me/BotFather, либо найдите его сами в поиске по юзернейму @BotFather и введите команду /newbot 48 | Следуйте дальнейшим указаниям бота и укажите полученный токен в переменной TOKEN 49 | 50 | 4. Найдите бота, который отправит вам ваш Telegram ID 51 | Одними из таких ботов могут быть @userinfobot или @username_to_id_bot 52 | Введите полученный ID в переменную ADMIN_ID 53 | 54 | На этом, настройка конфига завершена. Можете просто сохранить и закрыть этот файл. 55 | """ 56 | 57 | MySQL = ['localhost', 'user', 'password', 'support_db'] 58 | TOKEN = '' 59 | ADMIN_ID = '' 60 | PROXY_URL = '' -------------------------------------------------------------------------------- /Telegram Support Bot/core.py: -------------------------------------------------------------------------------- 1 | import config 2 | import datetime 3 | import random 4 | import pymysql 5 | 6 | 7 | #Добавить агента 8 | def add_agent(agent_id): 9 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 10 | cur = con.cursor() 11 | 12 | cur.execute(f"INSERT INTO agents (`agent_id`) VALUES ('{agent_id}')") 13 | con.commit() 14 | 15 | cur.close() 16 | con.close() 17 | 18 | 19 | #Добавить файл 20 | def add_file(req_id, file_id, file_name, type): 21 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 22 | cur = con.cursor() 23 | 24 | cur.execute(f"INSERT INTO files (`req_id`, `file_id`, `file_name`, `type`) VALUES ('{req_id}', '{file_id}', '{file_name}', '{type}')") 25 | con.commit() 26 | 27 | cur.close() 28 | con.close() 29 | 30 | 31 | #Создать запрос 32 | def new_req(user_id, request): 33 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 34 | cur = con.cursor() 35 | 36 | #Добавить запрос в БД 37 | cur.execute(f"INSERT INTO requests (`user_id`, `req_status`) VALUES ('{user_id}', 'waiting')") 38 | 39 | #Получить айди добавленного запроса 40 | req_id = cur.lastrowid 41 | 42 | dt = datetime.datetime.now() 43 | date_now = dt.strftime('%d.%m.%Y %H:%M:%S') 44 | 45 | #Добавить сообщение для запроса 46 | cur.execute(f"INSERT INTO messages (`req_id`, `message`, `user_status`, `date`) VALUES ('{req_id}', '{request}', 'user', '{date_now}')") 47 | 48 | con.commit() 49 | 50 | cur.close() 51 | con.close() 52 | 53 | return req_id 54 | 55 | 56 | #Добавить сообщение 57 | def add_message(req_id, message, user_status): 58 | if user_status == 'user': 59 | req_status = 'waiting' 60 | elif user_status == 'agent': 61 | req_status = 'answered' 62 | 63 | dt = datetime.datetime.now() 64 | date_now = dt.strftime('%d.%m.%Y %H:%M:%S') 65 | 66 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 67 | cur = con.cursor() 68 | 69 | #Добавить сообщение для запроса 70 | cur.execute(f"INSERT INTO messages (`req_id`, `message`, `user_status`, `date`) VALUES ('{req_id}', '{message}', '{user_status}', '{date_now}')") 71 | 72 | #Изменить статус запроса 73 | cur.execute(f"UPDATE requests SET `req_status` = '{req_status}' WHERE `req_id` = '{req_id}'") 74 | 75 | con.commit() 76 | 77 | cur.close() 78 | con.close() 79 | 80 | 81 | #Добавить пароли 82 | def add_passwords(passwords): 83 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 84 | cur = con.cursor() 85 | 86 | for password in passwords: 87 | cur.execute(f"INSERT INTO passwords (`password`) VALUES ('{password}')") 88 | 89 | con.commit() 90 | 91 | cur.close() 92 | con.close() 93 | 94 | 95 | #Проверить статус агента 96 | def check_agent_status(user_id): 97 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 98 | cur = con.cursor() 99 | 100 | cur.execute(f"SELECT * FROM agents WHERE `agent_id` = '{user_id}'") 101 | agent = cur.fetchone() 102 | 103 | cur.close() 104 | con.close() 105 | 106 | if agent == None: 107 | return False 108 | else: 109 | return True 110 | 111 | 112 | #Проверить валидность пароля 113 | def valid_password(password): 114 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 115 | cur = con.cursor() 116 | 117 | cur.execute(f"SELECT * FROM passwords WHERE `password` = '{password}'") 118 | password = cur.fetchone() 119 | 120 | cur.close() 121 | con.close() 122 | 123 | if password == None: 124 | return False 125 | else: 126 | return True 127 | 128 | 129 | #Проверить отправляет ли пользователь файл, если да - вернуть его 130 | def get_file(message): 131 | """ 132 | Атрибут file_name доступен только в типах файлов - document и video. 133 | Если пользователь отправляет не документ и не видео - в качестве имени файла передать дату и время отправки (date_now) 134 | """ 135 | 136 | types = ['document', 'video', 'audio', 'voice'] 137 | dt = datetime.datetime.now() 138 | date_now = dt.strftime('%d.%m.%Y %H:%M:%S') 139 | 140 | #Сначала проверить отправляет ли пользователь фото 141 | try: 142 | return {'file_id': message.json['photo'][-1]['file_id'], 'file_name': date_now, 'type': 'photo', 'text': str(message.caption)} 143 | 144 | #Если нет - проверить отправляет ли документ, видео, аудио, голосовое сообщение 145 | except: 146 | for type in types: 147 | try: 148 | if type == 'document' or type == 'video': 149 | file_name = message.json[type]['file_name'] 150 | else: 151 | file_name = date_now 152 | 153 | return {'file_id': message.json[type]['file_id'], 'file_name': file_name, 'type': type, 'text': str(message.caption)} 154 | except: 155 | pass 156 | 157 | return None 158 | 159 | 160 | #Получить иконку статуса запроса 161 | def get_icon_from_status(req_status, user_status): 162 | if req_status == 'confirm': 163 | return '✅' 164 | 165 | elif req_status == 'waiting': 166 | if user_status == 'user': 167 | return '⏳' 168 | elif user_status == 'agent': 169 | return '❗️' 170 | 171 | elif req_status == 'answered': 172 | if user_status == 'user': 173 | return '❗️' 174 | elif user_status == 'agent': 175 | return '⏳' 176 | 177 | 178 | #Получить текст для кнопки с файлом 179 | def get_file_text(file_name, type): 180 | if type == 'photo': 181 | return f'📷 | Фото {file_name}' 182 | elif type == 'document': 183 | return f'📄 | Документ {file_name}' 184 | elif type == 'video': 185 | return f'🎥 | Видео {file_name}' 186 | elif type == 'audio': 187 | return f'🎵 | Аудио {file_name}' 188 | elif type == 'voice': 189 | return f'🎧 | Голосовое сообщение {file_name}' 190 | 191 | 192 | #Сгенерировать пароли 193 | def generate_passwords(number, lenght): 194 | chars = 'abcdefghijklnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' 195 | 196 | passsords = [] 197 | for _ in range(number): 198 | password = '' 199 | for _ in range(lenght): 200 | password += random.choice(chars) 201 | 202 | passsords.append(password) 203 | 204 | return passsords 205 | 206 | 207 | #Получить юзер айди пользователя, создавшего запрос 208 | def get_user_id_of_req(req_id): 209 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 210 | cur = con.cursor() 211 | 212 | cur.execute(f"SELECT `user_id` FROM requests WHERE `req_id` = '{req_id}'") 213 | user_id = cur.fetchone()[0] 214 | 215 | cur.close() 216 | con.close() 217 | 218 | return user_id 219 | 220 | 221 | #Получить file_id из id записи в БД 222 | def get_file_id(id): 223 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 224 | cur = con.cursor() 225 | 226 | cur.execute(f"SELECT `file_id` FROM files WHERE `id` = '{id}'") 227 | file_id = cur.fetchone()[0] 228 | 229 | cur.close() 230 | con.close() 231 | 232 | return file_id 233 | 234 | 235 | #Получить статус запроса 236 | def get_req_status(req_id): 237 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 238 | cur = con.cursor() 239 | 240 | cur.execute(f"SELECT `req_status` FROM requests WHERE `req_id` = '{req_id}'") 241 | req_status = cur.fetchone()[0] 242 | 243 | cur.close() 244 | con.close() 245 | 246 | return req_status 247 | 248 | 249 | #Удалить пароль 250 | def delete_password(password): 251 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 252 | cur = con.cursor() 253 | 254 | cur.execute(f"DELETE FROM {config.MySQL[3]}.passwords WHERE `password` = '{password}'") 255 | con.commit() 256 | 257 | cur.close() 258 | con.close() 259 | 260 | 261 | #Удалить агента 262 | def delete_agent(agent_id): 263 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 264 | cur = con.cursor() 265 | 266 | cur.execute(f"DELETE FROM {config.MySQL[3]}.agents WHERE `agent_id` = '{agent_id}'") 267 | con.commit() 268 | 269 | cur.close() 270 | con.close() 271 | 272 | 273 | #Завершить запрос 274 | def confirm_req(req_id): 275 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 276 | cur = con.cursor() 277 | 278 | cur.execute(f"UPDATE requests SET `req_status` = 'confirm' WHERE `req_id` = '{req_id}'") 279 | con.commit() 280 | 281 | cur.close() 282 | con.close() 283 | 284 | 285 | #Получить пароли с лимитом 286 | def get_passwords(number): 287 | limit = (int(number) * 10) - 10 288 | 289 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 290 | cur = con.cursor() 291 | 292 | cur.execute(f"SELECT `password` FROM passwords LIMIT {limit}, 10") 293 | passwords = cur.fetchall() 294 | 295 | cur.close() 296 | con.close() 297 | 298 | return passwords 299 | 300 | 301 | #Получить агентов с лимитом 302 | def get_agents(number): 303 | limit = (int(number) * 10) - 10 304 | 305 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 306 | cur = con.cursor() 307 | 308 | cur.execute(f"SELECT `agent_id` FROM agents LIMIT {limit}, 10") 309 | agents = cur.fetchall() 310 | 311 | cur.close() 312 | con.close() 313 | 314 | return agents 315 | 316 | 317 | #Получить мои запросы с лимитом 318 | def my_reqs(number, user_id): 319 | limit = (int(number) * 10) - 10 320 | 321 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 322 | cur = con.cursor() 323 | 324 | cur.execute(f"SELECT `req_id`, `req_status` FROM requests WHERE `user_id` = '{user_id}' ORDER BY `req_id` DESC LIMIT {limit}, 10") 325 | reqs = cur.fetchall() 326 | 327 | cur.close() 328 | con.close() 329 | 330 | return reqs 331 | 332 | 333 | #Получить запросы по статусу с лимитом 334 | def get_reqs(number, callback): 335 | limit = (int(number) * 10) - 10 336 | req_status = callback.replace('_reqs', '') 337 | 338 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 339 | cur = con.cursor() 340 | 341 | cur.execute(f"SELECT `req_id`, `req_status` FROM requests WHERE `req_status` = '{req_status}' ORDER BY `req_id` DESC LIMIT {limit}, 10") 342 | reqs = cur.fetchall() 343 | 344 | cur.close() 345 | con.close() 346 | 347 | return reqs 348 | 349 | 350 | #Получить файлы по запросу с лимитом 351 | def get_files(number, req_id): 352 | limit = (int(number) * 10) - 10 353 | 354 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 355 | cur = con.cursor() 356 | 357 | cur.execute(f"SELECT `id`, `file_name`, `type` FROM files WHERE `req_id` = '{req_id}' ORDER BY `id` DESC LIMIT {limit}, 10") 358 | files = cur.fetchall() 359 | 360 | cur.close() 361 | con.close() 362 | 363 | return files 364 | 365 | 366 | #Получить историю запроса 367 | def get_request_data(req_id, callback): 368 | if 'my_reqs' in callback: 369 | get_dialog_user_status = 'user' 370 | else: 371 | get_dialog_user_status = 'agent' 372 | 373 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 374 | cur = con.cursor() 375 | 376 | cur.execute(f"SELECT `message`, `user_status`, `date` FROM messages WHERE `req_id` = '{req_id}'") 377 | messages = cur.fetchall() 378 | 379 | cur.close() 380 | con.close() 381 | 382 | data = [] 383 | text = '' 384 | i = 1 385 | 386 | for message in messages: 387 | message_value = message[0] 388 | user_status = message[1] 389 | date = message[2] 390 | 391 | if user_status == 'user': 392 | if get_dialog_user_status == 'user': 393 | text_status = '👤 Ваше сообщение' 394 | else: 395 | text_status = '👤 Сообщение пользователя' 396 | elif user_status == 'agent': 397 | text_status = '🧑‍💻 Агент поддержки' 398 | 399 | #Бэкап для текста 400 | backup_text = text 401 | text += f'{text_status}\n{date}\n{message_value}\n\n' 402 | 403 | #Если размер текста превышает допустимый в Telegram, то добавить первую часть текста и начать вторую 404 | if len(text) >= 4096: 405 | data.append(backup_text) 406 | text = f'{text_status}\n{date}\n{message_value}\n\n' 407 | 408 | #Если сейчас последняя итерация, то проверить не является ли часть текста превыщающий допустимый размер (4096 символов). Если превышает - добавить часть и начать следующую. Если нет - просто добавить последнюю часть списка. 409 | if len(messages) == i: 410 | if len(text) >= 4096: 411 | data.append(backup_text) 412 | text = f'{text_status}\n{date}\n{message_value}\n\n' 413 | 414 | data.append(text) 415 | 416 | i += 1 417 | 418 | return data -------------------------------------------------------------------------------- /Telegram Support Bot/markup.py: -------------------------------------------------------------------------------- 1 | from telebot import types 2 | from core import my_reqs, get_reqs, get_agents, get_passwords, get_files, get_icon_from_status, get_file_text 3 | 4 | 5 | def page(markup, number, list, call, callback_cancel): 6 | if len(list) != 10: 7 | max_nums = number 8 | else: 9 | max_nums = 'None' 10 | 11 | if str(number) == '1': 12 | item1 = types.InlineKeyboardButton(f"⏹", callback_data=f'None') 13 | else: 14 | item1 = types.InlineKeyboardButton(f"◀️", callback_data=f'{call}:{int(number) - 1}') 15 | 16 | if str(number) == str(max_nums): 17 | item2 = types.InlineKeyboardButton(f"⏹", callback_data=f'None') 18 | else: 19 | item2 = types.InlineKeyboardButton(f"▶️", callback_data=f'{call}:{int(number) + 1}') 20 | 21 | item3 = types.InlineKeyboardButton("Назад", callback_data=callback_cancel) 22 | 23 | if callback_cancel != 'None': 24 | markup.add(item1, item3, item2) 25 | else: 26 | if str(number) == '1' and str(number) == str(max_nums): 27 | pass 28 | else: 29 | markup.add(item1, item2) 30 | 31 | return markup 32 | 33 | 34 | def markup_main(): 35 | markup_main = types.ReplyKeyboardMarkup(resize_keyboard=True) 36 | item1 = types.KeyboardButton("✏️ Написать запрос") 37 | item2 = types.KeyboardButton("✉️ Мои запросы") 38 | markup_main.row(item1) 39 | markup_main.row(item2) 40 | 41 | return markup_main 42 | 43 | 44 | def markup_agent(): 45 | markup_agent = types.InlineKeyboardMarkup(row_width=1) 46 | item1 = types.InlineKeyboardButton("❗️ Ожидают ответа от поддержки", callback_data='waiting_reqs:1') 47 | item2 = types.InlineKeyboardButton("⏳ Ожидают ответа от пользователя", callback_data='answered_reqs:1') 48 | item3 = types.InlineKeyboardButton("✅ Завершенные запросы", callback_data='confirm_reqs:1') 49 | markup_agent.add(item1, item2, item3) 50 | 51 | return markup_agent 52 | 53 | 54 | def markup_cancel(): 55 | markup_cancel = types.ReplyKeyboardMarkup(resize_keyboard=True) 56 | item1 = types.KeyboardButton("Отмена") 57 | markup_cancel.row(item1) 58 | 59 | return markup_cancel 60 | 61 | 62 | def markup_admin(): 63 | markup_admin = types.InlineKeyboardMarkup(row_width=1) 64 | item1 = types.InlineKeyboardButton("✅ Добавить агента поддержки", callback_data='add_agent') 65 | item2 = types.InlineKeyboardButton("🧑‍💻 Агенты поддержки", callback_data='all_agents:1') 66 | item3 = types.InlineKeyboardButton("🔑 Одноразовые пароли", callback_data='all_passwords:1') 67 | item4 = types.InlineKeyboardButton("🎲 Сгенерировать одноразовые пароли", callback_data='generate_passwords') 68 | item5 = types.InlineKeyboardButton("⛔️ Выключить бота", callback_data='stop_bot:wait') 69 | markup_admin.add(item1, item2, item3, item4, item5) 70 | 71 | return markup_admin 72 | 73 | 74 | def markup_back(back): 75 | markup_back = types.InlineKeyboardMarkup(row_width=1) 76 | item1 = types.InlineKeyboardButton("Назад", callback_data=f'back_{back}') 77 | markup_back.add(item1) 78 | 79 | return markup_back 80 | 81 | 82 | def markup_reqs(user_id, callback, number): 83 | if callback == 'my_reqs': 84 | reqs = my_reqs(number, user_id) 85 | user_status = 'user' 86 | callback_cancel = 'None' 87 | else: 88 | reqs = get_reqs(number, callback) 89 | user_status = 'agent' 90 | callback_cancel = 'back_agent' 91 | 92 | markup_my_reqs = types.InlineKeyboardMarkup(row_width=3) 93 | for req in reqs: 94 | req_id = req[0] 95 | req_status = req[1] 96 | req_icon = get_icon_from_status(req_status, user_status) 97 | #❗️, ⏳, ✅ 98 | 99 | item = types.InlineKeyboardButton(f'{req_icon} | ID: {req_id}', callback_data=f'open_req:{req_id}:{callback}-{number}') 100 | markup_my_reqs.add(item) 101 | 102 | markup_my_reqs = page(markup_my_reqs, number, reqs, callback, callback_cancel) 103 | 104 | return markup_my_reqs, len(reqs) 105 | 106 | 107 | def markup_request_action(req_id, req_status, callback): 108 | formatted_callback = callback.replace('-', ':') 109 | 110 | markup_request_action = types.InlineKeyboardMarkup(row_width=1) 111 | 112 | if req_status == 'confirm': 113 | item1 = types.InlineKeyboardButton("🗂 Показать файлы", callback_data=f'req_files:{req_id}:{callback}:1') 114 | item2 = types.InlineKeyboardButton("Назад", callback_data=formatted_callback) 115 | 116 | markup_request_action.add(item1, item2) 117 | 118 | elif req_status == 'answered' or req_status == 'waiting': 119 | if 'my_reqs:' in formatted_callback: 120 | status_user = 'user' 121 | else: 122 | status_user = 'agent' 123 | 124 | item1 = types.InlineKeyboardButton("✏️ Добавить сообщение", callback_data=f'add_message:{req_id}:{status_user}') 125 | item2 = types.InlineKeyboardButton("🗂 Показать файлы", callback_data=f'req_files:{req_id}:{callback}:1') 126 | 127 | if status_user == 'user': 128 | item3 = types.InlineKeyboardButton("✅ Завершить запрос", callback_data=f'confirm_req:wait:{req_id}') 129 | 130 | item4 = types.InlineKeyboardButton("Назад", callback_data=formatted_callback) 131 | 132 | if status_user == 'user': 133 | markup_request_action.add(item1, item2, item3, item4) 134 | else: 135 | markup_request_action.add(item1, item2, item4) 136 | 137 | return markup_request_action 138 | 139 | 140 | def markup_confirm_req(req_id): 141 | markup_confirm_req = types.InlineKeyboardMarkup(row_width=1) 142 | item1 = types.InlineKeyboardButton("✅ Подтвердить", callback_data=f'confirm_req:true:{req_id}') 143 | markup_confirm_req.add(item1) 144 | 145 | return markup_confirm_req 146 | 147 | 148 | def markup_agents(number): 149 | agents = get_agents(number) 150 | 151 | markup_agents = types.InlineKeyboardMarkup(row_width=3) 152 | for agent in agents: 153 | agent_id = agent[0] 154 | 155 | item = types.InlineKeyboardButton(f'🧑‍💻 | {agent_id}', callback_data=f'delete_agent:{agent_id}') 156 | markup_agents.add(item) 157 | 158 | markup_agents = page(markup_agents, number, agents, 'all_agents', 'back_admin') 159 | 160 | return markup_agents, len(agents) 161 | 162 | 163 | def markup_passwords(number): 164 | passwords = get_passwords(number) 165 | 166 | markup_passwords = types.InlineKeyboardMarkup(row_width=3) 167 | for password in passwords: 168 | password_value = password[0] 169 | 170 | item = types.InlineKeyboardButton(password_value, callback_data=f'delete_password:{password_value}') 171 | markup_passwords.add(item) 172 | 173 | markup_passwords = page(markup_passwords, number, passwords, 'all_passwords', 'back_admin') 174 | 175 | return markup_passwords, len(passwords) 176 | 177 | 178 | def markup_files(number, req_id, callback): 179 | files = get_files(number, req_id) 180 | 181 | markup_files = types.InlineKeyboardMarkup(row_width=3) 182 | for file in files: 183 | id = file[0] 184 | file_name = file[1] 185 | type = file[2] 186 | 187 | file_text = get_file_text(file_name, type) 188 | # 📷 | Фото 27.12.2020 14:21:50 189 | 190 | item = types.InlineKeyboardButton(file_text, callback_data=f'send_file:{id}:{type}') 191 | markup_files.add(item) 192 | 193 | markup_files = page(markup_files, number, files, f'req_files:{req_id}:{callback}', f'open_req:{req_id}:{callback}') 194 | 195 | return markup_files, len(files) 196 | markup_files('1', '1', '1') 197 | 198 | def markup_confirm_stop(): 199 | markup_confirm_stop = types.InlineKeyboardMarkup(row_width=1) 200 | item1 = types.InlineKeyboardButton("Да", callback_data='stop_bot:confirm') 201 | item2 = types.InlineKeyboardButton("Нет", callback_data='back_admin') 202 | markup_confirm_stop.add(item1, item2) 203 | 204 | return markup_confirm_stop -------------------------------------------------------------------------------- /Telegram Support Bot/sql.py: -------------------------------------------------------------------------------- 1 | import config 2 | import pymysql 3 | 4 | 5 | def create_table_agents(): 6 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 7 | cur = con.cursor() 8 | 9 | cur.execute("CREATE TABLE IF NOT EXISTS agents(id INT NOT NULL AUTO_INCREMENT, `agent_id` VARCHAR(20), PRIMARY KEY (id))") 10 | cur.execute(f"ALTER TABLE agents CONVERT TO CHARACTER SET utf8mb4") 11 | 12 | cur.close() 13 | con.close() 14 | 15 | 16 | def create_table_passwords(): 17 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 18 | cur = con.cursor() 19 | 20 | cur.execute("CREATE TABLE IF NOT EXISTS passwords(id INT NOT NULL AUTO_INCREMENT, `password` VARCHAR(20), PRIMARY KEY (id))") 21 | cur.execute(f"ALTER TABLE passwords CONVERT TO CHARACTER SET utf8mb4") 22 | 23 | cur.close() 24 | con.close() 25 | 26 | 27 | def create_table_files(): 28 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 29 | cur = con.cursor() 30 | 31 | cur.execute("CREATE TABLE IF NOT EXISTS files(id INT NOT NULL AUTO_INCREMENT, `req_id` VARCHAR(20), `file_id` VARCHAR(250), `file_name` VARCHAR(2048), `type` VARCHAR(20), PRIMARY KEY (id))") 32 | cur.execute(f"ALTER TABLE files CONVERT TO CHARACTER SET utf8mb4") 33 | 34 | cur.close() 35 | con.close() 36 | 37 | 38 | def create_table_requests(): 39 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 40 | cur = con.cursor() 41 | 42 | cur.execute("CREATE TABLE IF NOT EXISTS requests(req_id INT NOT NULL AUTO_INCREMENT, `user_id` VARCHAR(20), `req_status` VARCHAR(20), PRIMARY KEY (req_id))") 43 | cur.execute(f"ALTER TABLE requests CONVERT TO CHARACTER SET utf8mb4") 44 | 45 | cur.close() 46 | con.close() 47 | 48 | 49 | def create_table_messages(): 50 | con = pymysql.connect(host=config.MySQL[0], user=config.MySQL[1], passwd=config.MySQL[2], db=config.MySQL[3]) 51 | cur = con.cursor() 52 | 53 | cur.execute("CREATE TABLE IF NOT EXISTS messages(id INT NOT NULL AUTO_INCREMENT, `req_id` VARCHAR(20), `message` VARCHAR(4096), `user_status` VARCHAR(20), `date` VARCHAR(50), PRIMARY KEY (id))") 54 | cur.execute(f"ALTER TABLE messages CONVERT TO CHARACTER SET utf8mb4") 55 | 56 | cur.close() 57 | con.close() 58 | 59 | 60 | 61 | create_table_agents() 62 | create_table_passwords() 63 | create_table_files() 64 | create_table_requests() 65 | create_table_messages() -------------------------------------------------------------------------------- /image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Blazzerrr/TelegramSupportBot/c3f50e63ffcd0f087c3cd06f5f0fc42d2226e1b4/image.png --------------------------------------------------------------------------------