|
|
|
|
from googleapiclient.discovery import build
|
|
|
|
|
from google.oauth2.service_account import Credentials
|
|
|
|
|
import asyncio
|
|
|
|
|
from aiogram.types import WebAppInfo
|
|
|
|
|
import logging
|
|
|
|
|
from aiogram import Bot, Dispatcher, types
|
|
|
|
|
from aiogram.utils import executor
|
|
|
|
|
from aiogram.types import ChatType
|
|
|
|
|
from aiogram.utils.exceptions import BadRequest
|
|
|
|
|
from aiogram.types import ReplyKeyboardMarkup, KeyboardButton
|
|
|
|
|
from aiogram.utils.exceptions import MessageCantBeDeleted
|
|
|
|
|
import gspread
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
from google.oauth2 import service_account
|
|
|
|
|
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton, WebAppInfo, ReplyKeyboardMarkup, KeyboardButton
|
|
|
|
|
import sentry_sdk
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sentry_sdk.init(
|
|
|
|
|
dsn="https://697d3f2b6cb54a78202eeae0cb8c1f65@sentry.pirogov.ai/15",
|
|
|
|
|
# Set traces_sample_rate to 1.0 to capture 100%
|
|
|
|
|
# of transactions for performance monitoring.
|
|
|
|
|
traces_sample_rate=1.0,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Настройки бота
|
|
|
|
|
API_TOKEN = '7414018470:AAGYF77aCd1BQpRnf38ys05ijkYJ25sNBuU'
|
|
|
|
|
ADMIN_ID = 766945900 # ID администратора, которому будет приходить уведомление
|
|
|
|
|
SPREADSHEET_ID = '128R3An6fb2PFGlzYMKb4SvEaSYCWUHHFVvial7llGno' # ID вашей Google Таблицы
|
|
|
|
|
RANGE_NAME = 'Лист1!A1:O' # Диапазон данных в таблице
|
|
|
|
|
CHAT_IDS = [-1002306913175, -1002266505101] # Замените на ID чатов, где бот администратор
|
|
|
|
|
|
|
|
|
|
# Логирование
|
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
|
|
|
|
|
|
bot = Bot(token=API_TOKEN)
|
|
|
|
|
dp = Dispatcher(bot)
|
|
|
|
|
|
|
|
|
|
# Настройки для Google Sheets API
|
|
|
|
|
SCOPES = ['https://www.googleapis.com/auth/spreadsheets']
|
|
|
|
|
SERVICE_ACCOUNT_FILE = 'botforclinic-436512-0c117dd103a8.json'
|
|
|
|
|
|
|
|
|
|
credentials = Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
|
|
|
|
|
service = build('sheets', 'v4', credentials=credentials)
|
|
|
|
|
|
|
|
|
|
# Настройка API для работы с документами
|
|
|
|
|
SCOPES = ['https://www.googleapis.com/auth/documents', 'https://www.googleapis.com/auth/drive']
|
|
|
|
|
SERVICE_ACCOUNT_FILE = 'botforclinic-436512-0c117dd103a8.json'
|
|
|
|
|
|
|
|
|
|
credentials = service_account.Credentials.from_service_account_file(
|
|
|
|
|
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
|
|
|
|
|
|
|
|
|
|
docs_service = build('docs', 'v1', credentials=credentials)
|
|
|
|
|
drive_service = build('drive', 'v3', credentials=credentials)
|
|
|
|
|
|
|
|
|
|
# Идентификатор Google Документа (шаблона трудового договора)
|
|
|
|
|
TEMPLATE_DOC_ID = '1xi4YiPNBEDvODS0SaVb0wgKZ_b_OBkas'
|
|
|
|
|
|
|
|
|
|
# Словарь для хранения сотрудников, которых уже обработали
|
|
|
|
|
known_employees = set()
|
|
|
|
|
|
|
|
|
|
def create_contract_google(employee_data):
|
|
|
|
|
# Копирование шаблона
|
|
|
|
|
file_metadata = {
|
|
|
|
|
'name': f"ТД_{employee_data[0]}_{datetime.now().strftime('%Y%m%d%H%M%S')}",
|
|
|
|
|
'mimeType': 'application/vnd.google-apps.document',
|
|
|
|
|
'parents': ['1fyA5btnwCQC-juE40T-uLSVHVIB-I2Ny']
|
|
|
|
|
}
|
|
|
|
|
copied_file = drive_service.files().copy(
|
|
|
|
|
fileId=TEMPLATE_DOC_ID, body=file_metadata).execute()
|
|
|
|
|
document_id = copied_file['id']
|
|
|
|
|
|
|
|
|
|
# Замены текста в шаблоне
|
|
|
|
|
replacements = {
|
|
|
|
|
"{{ФИО}}": employee_data[0],
|
|
|
|
|
"{{Серия паспорта}}": employee_data[3],
|
|
|
|
|
"{{Номер паспорта}}": employee_data[4],
|
|
|
|
|
"{{Кем выдан}}": employee_data[5],
|
|
|
|
|
"{{Дата выдачи}}": employee_data[6],
|
|
|
|
|
"{{Адрес}}": employee_data[8],
|
|
|
|
|
"{{Дата рождения}}": employee_data[12],
|
|
|
|
|
"{{ИНН}}": employee_data[11],
|
|
|
|
|
"{{СНИЛС}}": employee_data[10],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
requests = [{"replaceAllText": {
|
|
|
|
|
"containsText": {"text": key, "matchCase": True},
|
|
|
|
|
"replaceText": value
|
|
|
|
|
}} for key, value in replacements.items()]
|
|
|
|
|
|
|
|
|
|
docs_service.documents().batchUpdate(
|
|
|
|
|
documentId=document_id, body={'requests': requests}).execute()
|
|
|
|
|
|
|
|
|
|
return f"https://docs.google.com/document/d/{document_id}/edit"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Словарь с соответствием специальности и ссылки на чат
|
|
|
|
|
specialty_chat_links = {
|
|
|
|
|
"Врачи": "https://t.me/botclinic",
|
|
|
|
|
"Медсёстры": "https://t.me/+DcZn0yBO0RFjZTY6",
|
|
|
|
|
"Санитарки": "https://t.me/joinchat/{chat_id_orderlies}",
|
|
|
|
|
"Администраторы": "https://t.me/joinchat/{chat_id_admins}",
|
|
|
|
|
"Операторы КЦ": "https://t.me/joinchat/{chat_id_operators}",
|
|
|
|
|
"АУП": "https://t.me/joinchat/{chat_id_aap}"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Функция для отправки сообщения о новом сотруднике с клавиатурой для выбора специальности
|
|
|
|
|
async def notify_admin_about_new_employee(entry):
|
|
|
|
|
full_name = entry[0] if entry else "Без имени"
|
|
|
|
|
new_employee_id = entry[13] if len(entry) > 13 else None
|
|
|
|
|
|
|
|
|
|
if new_employee_id:
|
|
|
|
|
# Отправляем уведомление админу о новом сотруднике с клавишами выбора специальности
|
|
|
|
|
keyboard = create_employee_keyboard()
|
|
|
|
|
|
|
|
|
|
await bot.send_message(
|
|
|
|
|
ADMIN_ID,
|
|
|
|
|
f"Зарегистрирован новый сотрудник: {full_name}\nTelegram ID сотрудника: {new_employee_id}",
|
|
|
|
|
reply_markup=keyboard
|
|
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
logging.error("Не удалось найти Telegram ID сотрудника.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Функция для проверки новых сотрудников
|
|
|
|
|
async def check_for_new_entries():
|
|
|
|
|
sheet = service.spreadsheets()
|
|
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
try:
|
|
|
|
|
result = sheet.values().get(spreadsheetId=SPREADSHEET_ID, range=RANGE_NAME).execute()
|
|
|
|
|
values = result.get('values', [])
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logging.error(f"Ошибка при чтении таблицы: {e}")
|
|
|
|
|
await asyncio.sleep(30) # Ждем перед следующей попыткой
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
# Проверяем каждую запись на наличие нового сотрудника
|
|
|
|
|
for entry in values:
|
|
|
|
|
full_name = entry[0] if entry else "Без имени"
|
|
|
|
|
new_employee_id = entry[13] if len(entry) > 13 else None # Telegram ID сотрудника
|
|
|
|
|
|
|
|
|
|
if full_name and full_name not in known_employees:
|
|
|
|
|
known_employees.add(full_name)
|
|
|
|
|
|
|
|
|
|
# Генерация трудового договора
|
|
|
|
|
try:
|
|
|
|
|
contract_url = create_contract_google(entry)
|
|
|
|
|
|
|
|
|
|
# Уведомление для администратора
|
|
|
|
|
await bot.send_message(
|
|
|
|
|
ADMIN_ID,
|
|
|
|
|
f"Зарегистрирован новый сотрудник: {full_name}\nТрудовой договор: {contract_url}",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Уведомление для сотрудника
|
|
|
|
|
if new_employee_id:
|
|
|
|
|
welcome_message = f"Большое спасибо! Мы получили данные для заключения трудового договора с вами."
|
|
|
|
|
await bot.send_message(
|
|
|
|
|
new_employee_id,
|
|
|
|
|
welcome_message,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Оповещаем админа и отправляем клавиатуру для выбора специальности
|
|
|
|
|
await notify_admin_about_new_employee(entry)
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logging.error(f"Ошибка при создании трудового договора: {e}")
|
|
|
|
|
await bot.send_message(ADMIN_ID, "Произошла ошибка при создании трудового договора.")
|
|
|
|
|
|
|
|
|
|
await asyncio.sleep(10) # Проверяем таблицу каждые 10 секунд
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Функция отправки сообщения о прохождении инструктажа
|
|
|
|
|
async def send_fire_safety_instructions(employee_id, full_name, employee_data):
|
|
|
|
|
message_text = f"""
|
|
|
|
|
{full_name}, добрый день. Вы приглашены на корпоративный канал Клиники в Telegram. В закрепленном сообщении на этом канале Вы сможете ознакомиться с такими разделами:
|
|
|
|
|
|
|
|
|
|
👉[Наши сотрудники](https://t.me/c/1414064442/5) - актуальный список всех сотрудников Клиники;
|
|
|
|
|
👉[Контакты сотрудников](https://t.me/c/1414064442/39) - номера телефонов сотрудников для скачивания в телефонную книгу;
|
|
|
|
|
👉[История клиники](https://t.me/c/1414064442/6)
|
|
|
|
|
👉[Структура рабочих чатов](https://t.me/c/1414064442/10)
|
|
|
|
|
👉[Инструктаж по пожарной безопасности в Клинике ухо, горло, нос](https://disk.yandex.ru/i/i1k41Z2SznfpOA)
|
|
|
|
|
👉[Обратная связь](https://forms.gle/Dfjrb8K1NzzjmW5j7) - оставить предложение, пожелание или задать вопрос руководству (анонимно).
|
|
|
|
|
|
|
|
|
|
**ВАЖНО:**
|
|
|
|
|
В разделе [Инструктаж по пожарной безопасности в Клинике ухо, горло, нос](https://disk.yandex.ru/i/i1k41Z2SznfpOA) Вам необходимо изучить материалы по Пожарной безопасности, уделить особое внимание теме - порядок действий и по каким номерам звонить в случае пожароопасной ситуации.
|
|
|
|
|
|
|
|
|
|
После этого пройти тестирование по данной теме (21 вопрос - зачет 70% правильных ответов):
|
|
|
|
|
👉[Тестирование по пожарной безопасности](https://forms.gle/VLEx2Gf1h8grpXXu5)
|
|
|
|
|
|
|
|
|
|
**Срок обучения и прохождения тестирования** - до начала выполнения трудовой функции!
|
|
|
|
|
|
|
|
|
|
Спасибо!
|
|
|
|
|
|
|
|
|
|
С уважением,
|
|
|
|
|
Жуланова Наталья Александровна,
|
|
|
|
|
помощник генерального директора ООО "Клиника ухо, горло, нос им. проф. Е.Н.Оленевой" (г. Пермь)
|
|
|
|
|
📞 +7 (902) 64-54-648
|
|
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
# Отправка сообщения сотруднику
|
|
|
|
|
await bot.send_message(employee_id, message_text, parse_mode="Markdown")
|
|
|
|
|
logging.info(f"Сообщение о пожарной безопасности отправлено {full_name}.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logging.error(f"Ошибка при отправке инструктажа или документа: {e}")
|
|
|
|
|
await bot.send_message(ADMIN_ID, "Произошла ошибка при отправке инструктажа или документа.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Обработчик нажатия на кнопки выбора специальности
|
|
|
|
|
|
|
|
|
|
@dp.message_handler(lambda message: message.text in specialty_chat_links.keys(), chat_type=types.ChatType.PRIVATE)
|
|
|
|
|
async def handle_specialty_selection(message: types.Message):
|
|
|
|
|
selected_specialty = message.text
|
|
|
|
|
data = sheet.get_all_values()
|
|
|
|
|
last_employee_row = len(data)
|
|
|
|
|
|
|
|
|
|
if last_employee_row < 2:
|
|
|
|
|
await message.answer("В таблице пока нет сотрудников для назначения специальности.")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
new_employee_id = data[last_employee_row - 1][13]
|
|
|
|
|
full_name = data[last_employee_row - 1][0]
|
|
|
|
|
|
|
|
|
|
if not new_employee_id:
|
|
|
|
|
await message.answer("Не удалось найти Telegram ID сотрудника в таблице.")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
sheet.update_cell(last_employee_row, 16, selected_specialty)
|
|
|
|
|
await message.answer(f"Специальность сотрудника обновлена на: {selected_specialty}")
|
|
|
|
|
|
|
|
|
|
chat_invite_link = specialty_chat_links.get(selected_specialty)
|
|
|
|
|
if chat_invite_link:
|
|
|
|
|
await bot.send_message(
|
|
|
|
|
new_employee_id,
|
|
|
|
|
f"Поздравляем! Вы были добавлены в нашу команду как {selected_specialty}. Вот ссылка на вашу беседу: {chat_invite_link}"
|
|
|
|
|
)
|
|
|
|
|
await message.answer(f"Ссылка на беседу отправлена сотруднику.")
|
|
|
|
|
|
|
|
|
|
# Отправка сообщения о прохождении инструктажа
|
|
|
|
|
await send_fire_safety_instructions(new_employee_id, full_name, data[last_employee_row - 1])
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
await message.answer(f"Ошибка при обновлении таблицы: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Функция для генерации клавиатуры с кнопками типа сотрудника
|
|
|
|
|
def create_employee_keyboard():
|
|
|
|
|
keyboard = ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=False)
|
|
|
|
|
button_doctors = KeyboardButton("Врачи")
|
|
|
|
|
button_nurses = KeyboardButton("Медсёстры")
|
|
|
|
|
button_orderlies = KeyboardButton("Санитарки")
|
|
|
|
|
button_admins = KeyboardButton("Администраторы")
|
|
|
|
|
button_operators = KeyboardButton("Операторы КЦ")
|
|
|
|
|
button_aap = KeyboardButton("АУП")
|
|
|
|
|
|
|
|
|
|
keyboard.add(button_doctors, button_nurses)
|
|
|
|
|
keyboard.add(button_orderlies, button_admins)
|
|
|
|
|
keyboard.add(button_operators, button_aap)
|
|
|
|
|
|
|
|
|
|
return keyboard
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Обработчик команды /start
|
|
|
|
|
@dp.message_handler(commands=['start'], chat_type=types.ChatType.PRIVATE)
|
|
|
|
|
async def send_welcome(message: types.Message):
|
|
|
|
|
user_id = message.from_user.id
|
|
|
|
|
|
|
|
|
|
# Отправка фото
|
|
|
|
|
photo_path = r'D:\Users\Maxim\PycharmProjectsbot\Bot_for_clinic\start_foto.png'
|
|
|
|
|
await bot.send_photo(user_id, types.InputFile(photo_path))
|
|
|
|
|
|
|
|
|
|
# Отправка текста с кнопкой
|
|
|
|
|
await bot.send_message(
|
|
|
|
|
user_id,
|
|
|
|
|
"Добрый день, этот бот нужен Вам для начала прохождения процедуры трудоустройства в "
|
|
|
|
|
"Общество с ограниченной ответственностью «Клиника ухо, горло, нос имени профессора Е.Н. Оленевой».\n"
|
|
|
|
|
"Нажмите, пожалуйста, на команду 👉 /registration",
|
|
|
|
|
reply_markup=get_registration_button()
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Обработчик команды регистрации
|
|
|
|
|
@dp.message_handler(commands=['registration'], chat_type=types.ChatType.PRIVATE)
|
|
|
|
|
async def send_welcome(message: types.Message):
|
|
|
|
|
await message.answer(
|
|
|
|
|
"▪️В соответствии с требованиями статьи 9 Федерального закона от 27.07.2006 г. «О персональных данных» № 152-ФЗ даю согласие на обработку своих персональных данных.\n"
|
|
|
|
|
"▪️Наименование и адрес оператора, получающего согласие субъекта персональных данных: Общество с ограниченной ответственностью «Клиника ухо, горло, нос имени профессора Е.Н. Оленевой».\n"
|
|
|
|
|
"▪️Цель обработки персональных данных: организация труда и осуществление иных, связанных с этим мероприятий.",
|
|
|
|
|
reply_markup=get_consent_keyboard()
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Обработчик ответа пользователя
|
|
|
|
|
@dp.message_handler(lambda message: message.text in ["✅ Даю согласие на обработку своих персональных данных", "❌ Не даю согласие на обработку своих персональных данных"])
|
|
|
|
|
async def process_consent(message: types.Message):
|
|
|
|
|
user_id = message.from_user.id
|
|
|
|
|
|
|
|
|
|
if message.text == "✅ Даю согласие на обработку своих персональных данных":
|
|
|
|
|
form_url = f"https://tgbotkugn.pirogov.ai/?user_id={user_id}"
|
|
|
|
|
form_keyboard = InlineKeyboardMarkup().add(
|
|
|
|
|
InlineKeyboardButton(
|
|
|
|
|
text="Ввести персональные данные", web_app=WebAppInfo(url=form_url)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
await message.answer(
|
|
|
|
|
"Спасибо за согласие! Нажмите кнопку ниже, чтобы ввести персональные данные:",
|
|
|
|
|
reply_markup=form_keyboard
|
|
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
await message.answer(
|
|
|
|
|
"Вы не дали согласие на обработку персональных данных.\n"
|
|
|
|
|
"Вы не можете продолжить регистрацию.",
|
|
|
|
|
reply_markup=get_consent_keyboard()
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@dp.message_handler(commands=['getchatid'], chat_type=[ChatType.GROUP, ChatType.SUPERGROUP])
|
|
|
|
|
async def get_chat_id(message: types.Message):
|
|
|
|
|
# Проверяем статус пользователя в чате
|
|
|
|
|
chat_member = await bot.get_chat_member(message.chat.id, message.from_user.id)
|
|
|
|
|
if chat_member.status not in ['administrator', 'creator']:
|
|
|
|
|
# Отправляем предупреждение о недостатке прав
|
|
|
|
|
warning_message = await message.answer("У вас нет прав на выполнение этой команды.")
|
|
|
|
|
|
|
|
|
|
# Удаляем команду /getchatid через 1 секунду
|
|
|
|
|
await asyncio.sleep(1)
|
|
|
|
|
try:
|
|
|
|
|
await message.delete()
|
|
|
|
|
except MessageCantBeDeleted:
|
|
|
|
|
logging.warning("Не удалось удалить сообщение с командой /getchatid")
|
|
|
|
|
|
|
|
|
|
# Удаляем предупреждение через 5 секунд
|
|
|
|
|
await asyncio.sleep(5)
|
|
|
|
|
try:
|
|
|
|
|
await warning_message.delete()
|
|
|
|
|
except MessageCantBeDeleted:
|
|
|
|
|
logging.warning("Не удалось удалить сообщение с предупреждением")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# Отправляем ID и название чата администратору бота
|
|
|
|
|
chat_id = message.chat.id
|
|
|
|
|
chat_title = message.chat.title or "Без названия"
|
|
|
|
|
await bot.send_message(ADMIN_ID, f"ID чата: {chat_id}\nНазвание чата: {chat_title}")
|
|
|
|
|
|
|
|
|
|
# Удаляем команду /getchatid через 1 секунду
|
|
|
|
|
await asyncio.sleep(1)
|
|
|
|
|
try:
|
|
|
|
|
await message.delete()
|
|
|
|
|
except MessageCantBeDeleted:
|
|
|
|
|
logging.warning("Не удалось удалить сообщение с командой /getchatid")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Инициализация доступа к Google Sheets
|
|
|
|
|
gc = gspread.service_account(filename=SERVICE_ACCOUNT_FILE)
|
|
|
|
|
sheet = gc.open_by_key(SPREADSHEET_ID).sheet1 # Открываем первую таблицу
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dp.message_handler(commands=['kick'], chat_type=types.ChatType.PRIVATE)
|
|
|
|
|
async def kick_user(message: types.Message):
|
|
|
|
|
if message.from_user.id != ADMIN_ID:
|
|
|
|
|
await message.answer("Эта команда доступна только администратору бота.")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# Получаем ФИО из сообщения
|
|
|
|
|
full_name = message.get_args().strip()
|
|
|
|
|
if not full_name:
|
|
|
|
|
await message.answer("Пожалуйста, укажите ФИО пользователя для кика.")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# Поиск ID пользователя по ФИО в Google Таблице
|
|
|
|
|
try:
|
|
|
|
|
data = sheet.get_all_values() # Получаем все значения в таблице
|
|
|
|
|
except Exception as e:
|
|
|
|
|
await message.answer("Не удалось получить данные из таблицы.")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
user_id = None
|
|
|
|
|
for row in data:
|
|
|
|
|
if row and row[0] == full_name: # ФИО в первом столбце
|
|
|
|
|
user_id = row[13] # ID в 14-м столбце (индекс 13)
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
if user_id is None:
|
|
|
|
|
await message.answer(f"Пользователь с ФИО '{full_name}' не найден в таблице.")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
errors = [] # Список для хранения ошибок
|
|
|
|
|
for chat_id in CHAT_IDS:
|
|
|
|
|
try:
|
|
|
|
|
await bot.kick_chat_member(chat_id, user_id)
|
|
|
|
|
except BadRequest as e:
|
|
|
|
|
errors.append(f"Ошибка в чате {chat_id}: {e}")
|
|
|
|
|
|
|
|
|
|
# Отправляем сообщение админу один раз
|
|
|
|
|
if errors:
|
|
|
|
|
await bot.send_message(
|
|
|
|
|
ADMIN_ID,
|
|
|
|
|
f"Пользователь с ID {user_id} был исключён из чатов, "
|
|
|
|
|
f"но произошли ошибки: {'; '.join(errors)}"
|
|
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
await bot.send_message(ADMIN_ID, f"Пользователь с ID {user_id} был исключён из всех чатов.")
|
|
|
|
|
|
|
|
|
|
await message.answer(f"Команда на кик пользователя с ФИО '{full_name}' отправлена во все чаты.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_registration_button():
|
|
|
|
|
keyboard = ReplyKeyboardMarkup(resize_keyboard=True)
|
|
|
|
|
registration_button = KeyboardButton("/registration")
|
|
|
|
|
keyboard.add(registration_button)
|
|
|
|
|
return keyboard
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_consent_keyboard():
|
|
|
|
|
keyboard = ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True)
|
|
|
|
|
consent_button = KeyboardButton("✅ Даю согласие на обработку своих персональных данных")
|
|
|
|
|
deny_button = KeyboardButton("❌ Не даю согласие на обработку своих персональных данных")
|
|
|
|
|
keyboard.add(consent_button, deny_button)
|
|
|
|
|
return keyboard
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
# Запускаем отслеживание таблицы и бота
|
|
|
|
|
loop = asyncio.get_event_loop()
|
|
|
|
|
loop.create_task(check_for_new_entries())
|
|
|
|
|
executor.start_polling(dp, skip_updates=True)
|