commit ae115cfbcbb2952b6ebe9b562cb6c0a9d869fadc Author: Kavalar Date: Fri Dec 6 14:20:29 2024 +0300 first diff --git a/DaHandler.py b/DaHandler.py new file mode 100644 index 0000000..5b8ae33 --- /dev/null +++ b/DaHandler.py @@ -0,0 +1,4 @@ +class DaHandler: + + def __init__(self): + pass diff --git a/DaMsg.py b/DaMsg.py new file mode 100644 index 0000000..3597788 --- /dev/null +++ b/DaMsg.py @@ -0,0 +1,107 @@ +import emoji + + +class DaMsg: + + def __init__(self, telegram_message): + self.telegram_message = telegram_message + self.text = self.telegram_message.text + self.caption = self.telegram_message.caption + self.stylizedText = self.telegram_message.text + self.stylizedCaption = self.telegram_message.caption + self.m = Markdown() + self.add_styles() + + @staticmethod + def get_msg(data=None) -> str: + pass + + def add_styles(self): + print(self.telegram_message.entities) + if self.telegram_message.entities: + self.stylizedText = self.m.add_entities_to_text(self.text, self.telegram_message.entities) + + if self.telegram_message.caption_entities: + self.stylizedCaption = self.m.add_entities_to_text(self.caption, self.telegram_message.caption_entities) + + +class Markdown: + + def __init__(self): + pass + + def add_entities_to_text(self, text: str, entities_list): + offset_correction = 0 + for ent in entities_list: + ent.offset += offset_correction + if ent.type == "bold": + text = self.bold(text, ent) + offset_correction += 7 + if ent.type == "italic": + text = self.italic(text, ent) + offset_correction += 7 + if ent.type == "underline": + text = self.underline(text, ent) + offset_correction += 7 + if ent.type == "strikethrough": + text = self.strikethrough(text, ent) + offset_correction += 7 + + return text + + @staticmethod + def bold(text: str, entities): + start = entities.offset - Markdown.get_emoji_offset(text) + text = text[:start] + "" + text[start:] + end = entities.offset + entities.length - Markdown.get_emoji_offset(text) + 3 + text = text[:end] + "" + text[end:] + + return text + + @staticmethod + def italic(text: str, entities): + start = entities.offset - Markdown.get_emoji_offset(text) + text = text[:start] + "" + text[start:] + end = entities.offset + entities.length - Markdown.get_emoji_offset(text) + 3 + text = text[:end] + "" + text[end:] + + return text + + @staticmethod + def underline(text: str, entities): + start = entities.offset - Markdown.get_emoji_offset(text) + text = text[:start] + "" + text[start:] + end = entities.offset + entities.length - Markdown.get_emoji_offset(text) + 3 + text = text[:end] + "" + text[end:] + + return text + + @staticmethod + def strikethrough(text: str, entities): + start = entities.offset - Markdown.get_emoji_offset(text) + text = text[:start] + "" + text[start:] + end = entities.offset + entities.length - Markdown.get_emoji_offset(text) + 3 + text = text[:end] + "" + text[end:] + + return text + + @staticmethod + def get_emoji_offset(text: str): + offset = 0 + emoji_list = emoji.distinct_emoji_list(text) + for em in emoji_list: + if em in Markdown.exclude_slim_emoji_pool(): + continue + if len(em) >= 2: + offset += 2 + else: + offset += 1 + + return offset + + @staticmethod + def exclude_slim_emoji_pool(): + return [ + '\u2757', + '\u2764\ufe0f', + ] diff --git a/GuildBot.py b/GuildBot.py new file mode 100644 index 0000000..19155dd --- /dev/null +++ b/GuildBot.py @@ -0,0 +1,235 @@ +from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update, ReplyKeyboardMarkup, ReplyKeyboardRemove +from telegram.ext import Updater, CommandHandler, CallbackQueryHandler, ConversationHandler, MessageHandler, ChatMemberHandler, filters, ApplicationBuilder +from bot import config, text_msg_handlers, photo_msg_handlers, video_msg_handlers, da_text_msg_scenario +import re +from urllib.parse import urlparse +from bot.DaMsg import DaMsg +from datetime import datetime, timedelta + +from bot.handlers.AdminActionsHandler import AdminActionsHandler +from bot.handlers.SuperAdminHandler import SuperAdminHandler +from db.models.Chat import Chat +from db.models.Booking import Booking +from db.services.ChatService import ChatService +from db.services.BookingService import BookingService +from bot.keyboards.AdminAnswerToBooking import AdminAnswerToBooking +from bot.keyboards.GetTableListKeyboard import GetTableListKeyboard +from bot.handlers.BookingHandler import BookingHandler +from bot.handlers.SetRoleHandler import SetRoleHandler +from bot.handlers.AuthHandler import AuthHandler +from bot.handlers.AdminHandler import AdminHandler +from bot.keyboards.FirstStepKeyboard import FirstStepKeyboard +from bot.msg.UserMsg import HelloMsg +from itguild_api import client +from bot.keyboards.FirstStepDeveloper import FirstStepDeveloper +from bot.keyboards.FirstStepPartner import FirstStepPartner +from bot import FIRST, SECOND, SET_EMAIL_STEP, REQUEST_CODE_STEP + + +class GuildBot: + + def __init__(self): + self.add_new_flag = 0 + self.add_photo_flag = 0 + self.add_new_pool = [] + self.add_photo_pool = [] + self.add_video_pool = [] + self.event_pool = {} + self.booking_pool = [] + + def run(self): + TOKEN = config['TELEGRAM_TOKEN'] + + application = ApplicationBuilder().token(TOKEN).build() + + conv_handler = ConversationHandler( + entry_points=[ + CommandHandler('start', self.start), + CommandHandler('menu', self.get_menu), + CommandHandler('show_menu', self.show_menu), + CallbackQueryHandler(AdminHandler.accept_booking, pattern='^accept=\d+$'), + CallbackQueryHandler(AdminActionsHandler.admin_respond_to_vacancy, pattern='^admin_respond_to_vacancy?\S{3,}'), + CallbackQueryHandler(AdminActionsHandler.request_sent, pattern='^request_sent?\S{3,}'), + MessageHandler(filters.TEXT, SuperAdminHandler.super_admin_text) + ], + states={ # словарь состояний разговора, возвращаемых callback функциями + FIRST: [ + CallbackQueryHandler(AuthHandler.request_code, pattern='^request_code'), + CallbackQueryHandler(SetRoleHandler.set_developer, pattern='^set_developer'), + MessageHandler(filters.TEXT, SuperAdminHandler.super_admin_text) + ], + SECOND: [ + CallbackQueryHandler(self.start_over, pattern='^start_menu'), + CallbackQueryHandler(self.thx, pattern='^thx$'), + ], + SET_EMAIL_STEP: [ + MessageHandler(filters.TEXT, SetRoleHandler.set_email) + ], + REQUEST_CODE_STEP: [ + MessageHandler(filters.TEXT, AuthHandler.add_user_at_dialog) + ], + }, + fallbacks=[CommandHandler('start', self.start)], + ) + + application.add_handler(conv_handler) + + text_handler = MessageHandler(filters.TEXT & (~filters.COMMAND), self.text_msg) + application.add_handler(text_handler) + + application.run_polling() + + def welcome(self, update, context): + update.message.reply_text( + """Привет. Это новостной бот канала "проСМИсь» Присылайте фото, видео, сводки и любую информацию, о которой хотите рассказать. Мы все обязательно изучим.""") + + async def start(self, update, context): + # `bot.send_message` это метод Telegram API + # `update.effective_chat.id` - определяем `id` чата, + # откуда прилетело сообщение + + dialog = client.tgBot.set_dialog({ + 'dialog_id': update.effective_chat.id, + 'username': update.effective_chat.username if update.effective_chat.username else "", + 'first_name': update.effective_chat.first_name if update.effective_chat.first_name else "", + 'last_name': update.effective_chat.last_name if update.effective_chat.last_name else "", + }) + + reply_markup = FirstStepKeyboard() + + print(update.effective_chat) + print(dialog) + + await update.message.reply_text(HelloMsg.get_msg(), reply_markup=reply_markup.create_keyboard(), parse_mode="html") + + # reaply_k = [['/start', '/menu']] + # markup = ReplyKeyboardMarkup(reaply_k, one_time_keyboard=False) + # update.message.reply_text('Пожалуйста, выберите:', reply_markup=markup) + + return FIRST + + def start_over(self, update, context): + """Тот же текст и клавиатура, что и при `/start`, но не как новое сообщение""" + # Получаем `CallbackQuery` из обновления `update` + query = update.callback_query + # На запросы обратного вызова необходимо ответить, + # даже если уведомление для пользователя не требуется. + # В противном случае у некоторых клиентов могут возникнуть проблемы. + query.answer() + + reply_markup = FirstStepKeyboard() + # Отредактируем сообщение, вызвавшее обратный вызов. + # Это создает ощущение интерактивного меню. + query.edit_message_text( + 'Пожалуйста, выберите:', reply_markup=reply_markup.create_keyboard() + ) + # Сообщаем `ConversationHandler`, что сейчас находимся в состоянии `FIRST` + return FIRST + + def show_menu(self, update, context): + reply_markup = FirstStepKeyboard() + update.message.reply_text('Пожалуйста, выберите:', reply_markup=reply_markup.create_keyboard()) + # context.bot.send_message(chat_id=update.effective_chat.id, text="Здесь будет меню") + + return FIRST + + def thx(self, update, context): + query = update.callback_query + query.answer() + query.edit_message_text(text="Спасибо!") + return ConversationHandler.END + + def run_text_handlers(self, update, context): + for handler in self.get_scenario(update, context): + handler.handler(update, context) + + @staticmethod + def get_last_step(): + keyboard = [ + [ + InlineKeyboardButton("Меню", callback_data='start_menu'), + InlineKeyboardButton("Завершить", callback_data='thx') + ], + ] + return keyboard + + @staticmethod + def get_time_variants(): + time = datetime(2024, 1, 1, 15, 00) + keyboard = [] + for i in range(1, 15): + keyboard.append( + [ + InlineKeyboardButton(time.strftime("%H:%M"), + callback_data="set_time={time}".format(time=time.strftime("%H:%M"))) + ] + ) + time = time + timedelta(minutes=30) + + keyboard.append( + [ + InlineKeyboardButton("Назад", callback_data="set_time=back") + ] + ) + return keyboard + + + @staticmethod + def get_date_to_booking(): + current_day = datetime.now() + keyboard = [] + for i in range(1, 8): + keyboard.append( + [ + InlineKeyboardButton(current_day.strftime("%d.%m.%Y"), + callback_data="set_date={date}".format(date=current_day.strftime("%d.%m.%Y"))) + ] + ) + current_day = current_day + timedelta(days=1) + keyboard.append( + [ + InlineKeyboardButton("Назад", callback_data="set_date=back") + ] + ) + return keyboard + + @staticmethod + def send_admins_notif(context, text, photo=None, video=None): + admins = ChatService.get_admins() + + for admin in admins: + context.bot.send_message(chat_id=admin, text=text) + if photo: + context.bot.send_photo(chat_id=admin, photo=photo) + if video: + context.bot.send_video(chat_id=admin, video=video) + + @staticmethod + def send_booking_notif(context, book: Booking): + admins = ChatService.get_admins() + + text = "Новое бронирование:\nСтол: {table} \nДата и время: {d} \nТелефон: {p} \nПожелания: {c}".format( + table=book.table, + d=book.booking_date, + p=book.phone, + c=book.comments + ) + + reply_markup = AdminAnswerToBooking() + reply_markup.add_option("book_id", book.id) + + for admin in admins: + context.bot.send_message(chat_id=admin.chat_id, text=text, reply_markup=reply_markup.create_keyboard()) + + return ConversationHandler.END + + @staticmethod + def send_user_booking_notif(context, chat_id, book: Booking): + text = "Спасибо \nВаша заявка принята в обработку.\nСтол: {table} \nДата и время: {d} \nТелефон: {p} \nПожелания: {c}".format( + table=book.table, + d=book.booking_date, + p=book.phone, + c=book.comments + ) + + context.bot.send_message(chat_id=chat_id, text=text) diff --git a/Handler.py b/Handler.py new file mode 100644 index 0000000..665f8a8 --- /dev/null +++ b/Handler.py @@ -0,0 +1,15 @@ +class Handler: + + def __init__(self): + pass + + @staticmethod + def load_callback_query(callback_query: str): + command, query = callback_query.split("?") + params_str = query.split("&") + params = {} + for param in params_str: + t = param.split("=") + params[t[0]] = t[1] + + return [command, params] diff --git a/HtmlMsg.py b/HtmlMsg.py new file mode 100644 index 0000000..bcab1d0 --- /dev/null +++ b/HtmlMsg.py @@ -0,0 +1,51 @@ +import re +import emoji + + +class HtmlMsg: + + def get_msg(self, data=None) -> str: + pass + + def get_stylized_msg(self, msg): + msg = self.replace_tag_tag(msg, "p") + msg = self.replace_tag_tag(msg, "h1") + msg = self.replace_tag_tag(msg, "secure") + + return msg + + def replace_tag_p(self, msg: str): + msg = msg.replace("

", "") + msg = msg.replace("

", "") + + return msg + + def replace_tag_tag(self, msg: str, tag: str): + msg = msg.replace("<{tag}>".format(tag=tag), "") + msg = msg.replace("".format(tag=tag), "") + + return msg + + def replace_single_tag(self, msg: str, tag: str): + msg = msg.replace("<{tag}>".format(tag=tag), "") + + return msg + + def replace_tag_with_content(self, msg: str, tag: str): + msg = msg.replace("\r\n", "
") + msg = re.sub("<{tag}>.*?".format(tag=tag), '', msg, 0) + msg = msg.replace("
", "\r\n") + + return msg + + @staticmethod + def remove_emoji(string): + emoji_pattern = re.compile("[" + u"\U0001F600-\U0001F64F" # emoticons + u"\U0001F300-\U0001F5FF" # symbols & pictographs + u"\U0001F680-\U0001F6FF" # transport & map symbols + u"\U0001F1E0-\U0001F1FF" # flags (iOS) + u"\U00002702-\U000027B0" + u"\U000024C2-\U0001F251" + "]+", flags=re.UNICODE) + return emoji_pattern.sub(r'', string) \ No newline at end of file diff --git a/Keyboard.py b/Keyboard.py new file mode 100644 index 0000000..6af9906 --- /dev/null +++ b/Keyboard.py @@ -0,0 +1,30 @@ +from telegram import InlineKeyboardButton, InlineKeyboardMarkup + + +class Keyboard: + + def __init__(self): + self.keyboard = [] + self.options = [] + + def get_keyboard(self): + return self.keyboard + + def add_to_keyboard(self, data: InlineKeyboardButton | list): + self.keyboard.append(data) + + def clear_keyboard(self): + self.keyboard = [] + + def create_keyboard(self): + return InlineKeyboardMarkup(self.get_keyboard()) + + def add_option(self, key, value): + self.options.append({key: value}) + + def get_option(self, key: str): + for option in self.options: + if key in option: + return option[key] + + return None diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..8b64cfe --- /dev/null +++ b/__init__.py @@ -0,0 +1,53 @@ +from dotenv import dotenv_values +# from bot.handlers.MainChannelHandler import MainChannelHandler +# from bot.handlers.TestChannelHandler import TestChannelHandler +# from bot.handlers.TestChannelPhotoHandler import TestChannelPhotoHandler +# from bot.handlers.MainChannelPhotoHandler import MainChannelPhotoHandler +# from bot.handlers.TestChannelVideoHandler import TestChannelVideoHandler +# from bot.handlers.MainChannelVideoHandler import MainChannelVideoHandler +# from bot.handlers.CopyFromMainChannelHandler import CopyFromMainChannelHandler +# from bot.handlers.CopyFromMainChannelPhotoHandler import CopyFromMainChannelPhotoHandler +# from bot.handlers.CopyFromMainChannelVideoHandler import CopyFromMainChannelVideoHandler +# from bot.handlers.CopyFromTestChannelHandler import CopyFromTestChannelHandler +# from bot.handlers.TestChannelDaLinkHandler import TestChannelDaLinkHandler +# from bot.handlers.MainChannelDaLinkHandler import MainChannelDaLinkHandler + +FIRST, SECOND = range(2) +SET_DATE_STEP = 3 +SET_TIME_STEP = 4 +SET_PHONE_STEP = 5 +SET_COMMENT_STEP = 6 +SET_TABLE_STEP = 7 +ACCEPT_BOOKING_STEP = 8 +REQUEST_CODE_STEP: int = 9 +AUTH_FINISH: int = 10 +BACK_STEP = 99 + +SET_EMAIL_STEP = 3 + +config = dotenv_values(".env") + +text_msg_handlers = [ + # MainChannelHandler(), + # TestChannelHandler(), + # CopyFromMainChannelHandler(), + # CopyFromTestChannelHandler() +] + +da_text_msg_scenario = [ + # MainChannelDaLinkHandler(), + # TestChannelDaLinkHandler() +] + +photo_msg_handlers = [ + # TestChannelPhotoHandler(), + # MainChannelPhotoHandler(), + # # CopyFromMainChannelPhotoHandler(), + # CopyFromTestChannelHandler() +] + +video_msg_handlers = [ + # TestChannelVideoHandler(), + # MainChannelVideoHandler(), + # # CopyFromMainChannelVideoHandler() +] diff --git a/handlers/AdminActionsHandler.py b/handlers/AdminActionsHandler.py new file mode 100644 index 0000000..c64a78a --- /dev/null +++ b/handlers/AdminActionsHandler.py @@ -0,0 +1,58 @@ +from bot.Handler import Handler +from telegram.constants import ParseMode +from bot import FIRST +from bot.keyboards.VacancyNotificationToAdminKeyboard import VacancyNotificationToAdminKeyboard +from bot.msg.AdminNotifMsg import AdminNotifMsg +from itguild_api import client + + +class AdminActionsHandler(Handler): + @staticmethod + async def admin_respond_to_vacancy(update, context): + query = update.callback_query + query.answer() + + command, params = Handler.load_callback_query(query.data) + print(command, params) + + admins = client.tgBot.get_admins() + recipient = client.tgBot.get_dialog(params['dialog_id']) + post = client.tgParsing.get_by_id(params['ig_post_id']) + anm = AdminNotifMsg() + + for admin in admins: + if admin['status'] == 2: + reply_markup = VacancyNotificationToAdminKeyboard() + reply_markup.add_option("post", post) + reply_markup.add_option("recipient", admin) + msg = anm.get_msg({'admin': admin, 'post': post, 'recipient': recipient, 'recipient_respond': True}) + await context.bot.send_message(chat_id=admin['dialog_id'], text=msg, parse_mode=ParseMode.HTML, reply_markup=reply_markup.create_keyboard()) + + await context.bot.send_message(chat_id=update.effective_chat.id, text="Отклик отправлен", parse_mode=ParseMode.HTML) + + return FIRST + + @staticmethod + async def request_sent(update, context): + query = update.callback_query + # query.answer() + + data = query.data + command, params = Handler.load_callback_query(data) + + user = client.tgBot.get_dialog(update.effective_chat.id) + post = client.tgParsing.get_by_id(params['ig_post_id']) + + reply_markup = VacancyNotificationToAdminKeyboard() + reply_markup.add_option("post", post) + reply_markup.add_option("recipient", user) + + client.tgParsing.update({'id': int(post['id']), 'status': 5}) + post['status'] = 5 + + msg = AdminNotifMsg() + text = msg.get_msg({"post": post, "admin": user, "status": "Запрос отправлен"}) + + await query.edit_message_text(text=text, parse_mode=ParseMode.HTML, reply_markup=reply_markup.create_keyboard()) + + return FIRST diff --git a/handlers/AdminHandler.py b/handlers/AdminHandler.py new file mode 100644 index 0000000..04dea5b --- /dev/null +++ b/handlers/AdminHandler.py @@ -0,0 +1,36 @@ +from bot.Handler import Handler +from db.services.BookingService import BookingService +from db.services.ChatService import ChatService +from bot import FIRST + + +class AdminHandler(Handler): + + @staticmethod + def accept_booking(update, context): + query = update.callback_query + query.answer() + + variant = query.data + command, book_id = variant.split("=") + + book = BookingService.get_booking_by_id(book_id) + BookingService.edit(book, "status", BookingService.STATUS_ACCEPTED) + + context.bot.send_message(chat_id=book.chat_id, text="Администратор принял заявку") + + admin = ChatService.get_by_chat_id(update.effective_chat.id) + + name = "Неизвестный" + if hasattr(admin, "username"): + name = admin.username + elif hasattr(admin, "first_name"): + name = admin.first_name + + admins = ChatService.get_admins() + + for admin in admins: + context.bot.send_message(chat_id=admin.chat_id, + text="Администратор {name} принял заявку.".format(name=name)) + + return FIRST diff --git a/handlers/AuthHandler.py b/handlers/AuthHandler.py new file mode 100644 index 0000000..b19d3f3 --- /dev/null +++ b/handlers/AuthHandler.py @@ -0,0 +1,35 @@ +from bot.Handler import Handler +from bot import SET_DATE_STEP, SET_TABLE_STEP, REQUEST_CODE_STEP, FIRST, AUTH_FINISH, config +from bot.keyboards.DateToBookingKeyboard import DateToBookingKeyboard +from bot.keyboards.FirstStepKeyboard import FirstStepKeyboard +from bot.keyboards.GetTableListKeyboard import GetTableListKeyboard +from itguild_api import client +from bot.DaMsg import DaMsg + + +class AuthHandler(Handler): + + @staticmethod + async def request_code(update, context): + await context.bot.send_message(chat_id=update.effective_chat.id, text="Введите код:") + + return REQUEST_CODE_STEP + + @staticmethod + async def add_user_at_dialog(update, context): + msg = DaMsg(update.effective_message) + + user = client.tgBot.get_user({'token': msg.text}) + + if "error" in user: + reply_markup = FirstStepKeyboard() + await context.bot.send_message(chat_id=update.effective_chat.id, + text="Пользователь не найден. Проверте верность введенного кода.", + reply_markup=reply_markup.create_keyboard()) + else: + dialog = client.tgBot.set_user_at_dialog({'dialog_id': update.effective_chat.id, 'user_id': user['id']}) + await context.bot.send_message(chat_id=update.effective_chat.id, + text="Авторизация прошла успешно.") + + print(user) + return FIRST diff --git a/handlers/BookingHandler.py b/handlers/BookingHandler.py new file mode 100644 index 0000000..b829d32 --- /dev/null +++ b/handlers/BookingHandler.py @@ -0,0 +1,31 @@ +from bot.Handler import Handler +from bot import SET_DATE_STEP, SET_TABLE_STEP +from bot.keyboards.DateToBookingKeyboard import DateToBookingKeyboard +from bot.keyboards.GetTableListKeyboard import GetTableListKeyboard + + +class BookingHandler(Handler): + + @staticmethod + def booking_vip(update, context): + query = update.callback_query + query.answer() + + reply_markup = DateToBookingKeyboard() + query.edit_message_text( + 'Выберите удобную дату:', reply_markup=reply_markup.create_keyboard() + ) + + return SET_DATE_STEP + + @staticmethod + def booking_table(update, context): + query = update.callback_query + query.answer() + + reply_markup = GetTableListKeyboard() + query.edit_message_text( + 'Выберите удобный стол:', reply_markup=reply_markup.create_keyboard() + ) + + return SET_TABLE_STEP \ No newline at end of file diff --git a/handlers/CopyFromMainChannelHandler.py b/handlers/CopyFromMainChannelHandler.py new file mode 100644 index 0000000..61fc200 --- /dev/null +++ b/handlers/CopyFromMainChannelHandler.py @@ -0,0 +1,13 @@ +from bot.DaHandler import DaHandler +from telegram import ParseMode +import bot + + +class CopyFromMainChannelHandler(DaHandler): + + def handler(self, update, context): + if bot.config['MAIN_CANNEL_ID'] == str(update.effective_chat.id): + text = "{text} \n\n {bot_link}".format(text=update.effective_message.text, + bot_link="👉 Предложить новость") + + context.bot.send_message(chat_id=bot.config['NEW_MAIN_CHANNEL_ID'], text=text, parse_mode=ParseMode.HTML) \ No newline at end of file diff --git a/handlers/CopyFromMainChannelPhotoHandler.py b/handlers/CopyFromMainChannelPhotoHandler.py new file mode 100644 index 0000000..b054548 --- /dev/null +++ b/handlers/CopyFromMainChannelPhotoHandler.py @@ -0,0 +1,14 @@ +from bot.DaHandler import DaHandler +from telegram import ParseMode +import bot + + +class CopyFromMainChannelPhotoHandler(DaHandler): + + def handler(self, update, context): + if bot.config['MAIN_CANNEL_ID'] == str(update.effective_chat.id): + if update.effective_message.caption is not None: + text = "{text} \n\n {bot_link}".format(text=update.effective_message.caption, + bot_link="👉 Предложить новость") + + context.bot.send_message(chat_id=bot.config['NEW_MAIN_CHANNEL_ID'], text=text, parse_mode=ParseMode.HTML) \ No newline at end of file diff --git a/handlers/CopyFromMainChannelVideoHandler.py b/handlers/CopyFromMainChannelVideoHandler.py new file mode 100644 index 0000000..906f656 --- /dev/null +++ b/handlers/CopyFromMainChannelVideoHandler.py @@ -0,0 +1,14 @@ +from bot.DaHandler import DaHandler +from telegram import ParseMode +import bot + + +class CopyFromMainChannelVideoHandler(DaHandler): + + def handler(self, update, context): + if bot.config['TEST_CHANNEL_ID'] == str(update.effective_chat.id): + if update.effective_message.caption is not None: + text = "{text} \n\n {bot_link}".format(text=update.effective_message.caption, + bot_link="👉 Предложить новость") + + context.bot.send_message(chat_id=bot.config['NEW_MAIN_CHANNEL_ID'], text=text, parse_mode=ParseMode.HTML) \ No newline at end of file diff --git a/handlers/CopyFromTestChannelHandler.py b/handlers/CopyFromTestChannelHandler.py new file mode 100644 index 0000000..0447319 --- /dev/null +++ b/handlers/CopyFromTestChannelHandler.py @@ -0,0 +1,15 @@ +from bot.DaHandler import DaHandler +from telegram import ParseMode +import bot + + +class CopyFromTestChannelHandler(DaHandler): + + def handler(self, update, context): + if bot.config['TEST_CHANNEL_ID'] == str(update.effective_chat.id): + print(update) + print(context) + context.bot.copy_message(from_chat_id=update.effective_chat.id, + chat_id=1078162189, + message_id=update.effective_message.message_id, + parse_mode=ParseMode.HTML) diff --git a/handlers/MainChannelDaLinkHandler.py b/handlers/MainChannelDaLinkHandler.py new file mode 100644 index 0000000..dd904a6 --- /dev/null +++ b/handlers/MainChannelDaLinkHandler.py @@ -0,0 +1,25 @@ +from bot.DaHandler import DaHandler +from telegram import ParseMode +import bot +import re +from urllib.parse import urlparse + + +class MainChannelDaLinkHandler(DaHandler): + + def handler(self, update, context): + if bot.config['MAIN_CANNEL_ID'] == str(update.effective_chat.id): + if update.effective_message.text is not None: + text = update.effective_message.text + s = re.search("(?Phttps?://[^\s]+)", text) + if s is not None: + link = s.group("url") + domain = urlparse(link).netloc + if domain == bot.config['MAP_DOMAIN']: + final_text = "{text}".format( + text="🗺 Смотреть на карте".format(link=link)) + update.effective_message.text = final_text + + context.bot.editMessageText(chat_id=update.effective_chat.id, + message_id=update.effective_message.message_id, + text=final_text, parse_mode=ParseMode.HTML) diff --git a/handlers/MainChannelHandler.py b/handlers/MainChannelHandler.py new file mode 100644 index 0000000..b5243e4 --- /dev/null +++ b/handlers/MainChannelHandler.py @@ -0,0 +1,17 @@ +from bot.DaHandler import DaHandler +from telegram import ParseMode +import bot +from bot.DaMsg import DaMsg + + +class MainChannelHandler(DaHandler): + + def handler(self, update, context): + if bot.config['MAIN_CANNEL_ID'] == str(update.effective_chat.id): + da_msg = DaMsg(update.effective_message) + text = "{text} \n\n {bot_link}".format(text=da_msg.stylizedText, + bot_link="👉 Предложить новость") + + context.bot.editMessageText(chat_id=update.effective_chat.id, + message_id=update.effective_message.message_id, + text=text, parse_mode=ParseMode.HTML) diff --git a/handlers/MainChannelPhotoHandler.py b/handlers/MainChannelPhotoHandler.py new file mode 100644 index 0000000..90a583a --- /dev/null +++ b/handlers/MainChannelPhotoHandler.py @@ -0,0 +1,18 @@ +from bot.DaHandler import DaHandler +from telegram import ParseMode +import bot +from bot.DaMsg import DaMsg + + +class MainChannelPhotoHandler(DaHandler): + + def handler(self, update, context): + if bot.config['MAIN_CANNEL_ID'] == str(update.effective_chat.id): + if update.effective_message.caption is not None: + da_msg = DaMsg(update.effective_message) + text = "{text} \n\n {bot_link}".format(text=da_msg.stylizedCaption, + bot_link="👉 Предложить новость") + + context.bot.editMessageCaption(chat_id=update.effective_chat.id, + message_id=update.effective_message.message_id, + caption=text, parse_mode=ParseMode.HTML) \ No newline at end of file diff --git a/handlers/MainChannelVideoHandler.py b/handlers/MainChannelVideoHandler.py new file mode 100644 index 0000000..993a714 --- /dev/null +++ b/handlers/MainChannelVideoHandler.py @@ -0,0 +1,16 @@ +from bot.DaHandler import DaHandler +from telegram import ParseMode +import bot + + +class MainChannelVideoHandler(DaHandler): + + def handler(self, update, context): + if bot.config['MAIN_CANNEL_ID'] == str(update.effective_chat.id): + if update.effective_message.caption is not None: + text = "{text} \n\n {bot_link}".format(text=update.effective_message.caption, + bot_link="👉 Предложить новость") + + context.bot.editMessageCaption(chat_id=update.effective_chat.id, + message_id=update.effective_message.message_id, + caption=text, parse_mode=ParseMode.HTML) \ No newline at end of file diff --git a/handlers/SetRoleHandler.py b/handlers/SetRoleHandler.py new file mode 100644 index 0000000..b774351 --- /dev/null +++ b/handlers/SetRoleHandler.py @@ -0,0 +1,40 @@ +from bot.Handler import Handler +from db.services.ChatService import ChatService +from bot import SET_EMAIL_STEP +from bot.DaMsg import DaMsg +from bot.msg.SetEmailMsg import SetEmailMsg + + +class SetRoleHandler(Handler): + + @staticmethod + async def set_partner(update, context): + chat = ChatService.get_by_chat_id(update.effective_chat.id) + ChatService.edit(chat, "status", 20) + + msg = SetEmailMsg(update.effective_message) + + await context.bot.send_message(chat_id=update.effective_chat.id, text=msg.get_msg()) + + return SET_EMAIL_STEP + + @staticmethod + async def set_developer(update, context): + chat = ChatService.get_by_chat_id(update.effective_chat.id) + ChatService.edit(chat, "status", 10) + + msg = SetEmailMsg(update.effective_message) + + await context.bot.send_message(chat_id=update.effective_chat.id, text=msg.get_msg()) + + return SET_EMAIL_STEP + + @staticmethod + async def set_email(update, context): + chat = ChatService.get_by_chat_id(update.effective_chat.id) + msg = DaMsg(update.effective_message) + ChatService.edit(chat, "email", msg.text) + + await context.bot.send_message(chat_id=update.effective_chat.id, text="Спасибо)") + + return SET_EMAIL_STEP diff --git a/handlers/SuperAdminHandler.py b/handlers/SuperAdminHandler.py new file mode 100644 index 0000000..e27a076 --- /dev/null +++ b/handlers/SuperAdminHandler.py @@ -0,0 +1,16 @@ +from bot.DaMsg import DaMsg +from bot.Handler import Handler +from bot import config, FIRST +from itguild_api import client + +class SuperAdminHandler(Handler): + + @staticmethod + async def super_admin_text(update, context): + if int(update.effective_chat.id) == int(config['SUPER_ADMINS']): + all = client.tgBot.get_all() + for user in all: + if int(user['dialog_id']) != int(config['SUPER_ADMINS']): + await context.bot.send_message(chat_id=user['dialog_id'], text=update.effective_message.text) + + return FIRST diff --git a/handlers/TestChannelDaLinkHandler.py b/handlers/TestChannelDaLinkHandler.py new file mode 100644 index 0000000..651c346 --- /dev/null +++ b/handlers/TestChannelDaLinkHandler.py @@ -0,0 +1,25 @@ +from bot.DaHandler import DaHandler +from telegram import ParseMode +import bot +import re +from urllib.parse import urlparse + + +class TestChannelDaLinkHandler(DaHandler): + + def handler(self, update, context): + if bot.config['TEST_CHANNEL_ID'] == str(update.effective_chat.id): + if update.effective_message.text is not None: + text = update.effective_message.text + s = re.search("(?Phttps?://[^\s]+)", text) + if s is not None: + link = s.group("url") + domain = urlparse(link).netloc + if domain == bot.config['MAP_DOMAIN']: + final_text = "{text}".format( + text="🗺 Смотреть на карте".format(link=link)) + update.effective_message.text = final_text + + context.bot.editMessageText(chat_id=update.effective_chat.id, + message_id=update.effective_message.message_id, + text=final_text, parse_mode=ParseMode.HTML) diff --git a/handlers/TestChannelHandler.py b/handlers/TestChannelHandler.py new file mode 100644 index 0000000..61554e7 --- /dev/null +++ b/handlers/TestChannelHandler.py @@ -0,0 +1,19 @@ +import emoji + +from bot.DaHandler import DaHandler +from telegram import ParseMode +import bot +from bot.DaMsg import DaMsg + + +class TestChannelHandler(DaHandler): + + def handler(self, update, context): + if bot.config['TEST_CHANNEL_ID'] == str(update.effective_chat.id): + da_msg = DaMsg(update.effective_message) + text = "{text} \n\n {bot_link}".format(text=da_msg.stylizedText, + bot_link="👉 Предложить новость") + + context.bot.editMessageText(chat_id=update.effective_chat.id, + message_id=update.effective_message.message_id, + text=text, parse_mode=ParseMode.HTML) diff --git a/handlers/TestChannelPhotoHandler.py b/handlers/TestChannelPhotoHandler.py new file mode 100644 index 0000000..e835268 --- /dev/null +++ b/handlers/TestChannelPhotoHandler.py @@ -0,0 +1,18 @@ +from bot.DaHandler import DaHandler +from telegram import ParseMode +import bot +from bot.DaMsg import DaMsg + + +class TestChannelPhotoHandler(DaHandler): + + def handler(self, update, context): + if bot.config['TEST_CHANNEL_ID'] == str(update.effective_chat.id): + if update.effective_message.caption is not None: + da_msg = DaMsg(update.effective_message) + text = "{text} \n\n {bot_link}".format(text=da_msg.stylizedCaption, + bot_link="👉 Предложить новость") + + context.bot.editMessageCaption(chat_id=update.effective_chat.id, + message_id=update.effective_message.message_id, + caption=text, parse_mode=ParseMode.HTML) \ No newline at end of file diff --git a/handlers/TestChannelVideoHandler.py b/handlers/TestChannelVideoHandler.py new file mode 100644 index 0000000..4019beb --- /dev/null +++ b/handlers/TestChannelVideoHandler.py @@ -0,0 +1,16 @@ +from bot.DaHandler import DaHandler +from telegram import ParseMode +import bot + + +class TestChannelVideoHandler(DaHandler): + + def handler(self, update, context): + if bot.config['TEST_CHANNEL_ID'] == str(update.effective_chat.id): + if update.effective_message.caption is not None: + text = "{text} \n\n {bot_link}".format(text=update.effective_message.caption, + bot_link="👉 Предложить новость") + + context.bot.editMessageCaption(chat_id=update.effective_chat.id, + message_id=update.effective_message.message_id, + caption=text, parse_mode=ParseMode.HTML) \ No newline at end of file diff --git a/keyboards/AdminAnswerToBooking.py b/keyboards/AdminAnswerToBooking.py new file mode 100644 index 0000000..99c9242 --- /dev/null +++ b/keyboards/AdminAnswerToBooking.py @@ -0,0 +1,13 @@ +from bot.Keyboard import Keyboard +from telegram import InlineKeyboardButton, InlineKeyboardMarkup + +class AdminAnswerToBooking(Keyboard): + + def get_keyboard(self): + book_id = self.get_option("book_id") + return [ + [ + InlineKeyboardButton("Принять", callback_data="accept={book_id}".format(book_id=book_id)), + # InlineKeyboardButton("Ответить", callback_data="answer={book_id}".format(book_id=book_id)) + ], + ] diff --git a/keyboards/DateToBookingKeyboard.py b/keyboards/DateToBookingKeyboard.py new file mode 100644 index 0000000..02c7653 --- /dev/null +++ b/keyboards/DateToBookingKeyboard.py @@ -0,0 +1,25 @@ +from datetime import datetime, timedelta + +from bot.Keyboard import Keyboard +from telegram import InlineKeyboardButton, InlineKeyboardMarkup + + +class DateToBookingKeyboard(Keyboard): + + def get_keyboard(self): + current_day = datetime.now() + keyboard = [] + for i in range(1, 8): + keyboard.append( + [ + InlineKeyboardButton(current_day.strftime("%d.%m.%Y"), + callback_data="set_date={date}".format(date=current_day.strftime("%d.%m.%Y"))) + ] + ) + current_day = current_day + timedelta(days=1) + keyboard.append( + [ + InlineKeyboardButton("Назад", callback_data="set_date=back") + ] + ) + return keyboard diff --git a/keyboards/FirstStepDeveloper.py b/keyboards/FirstStepDeveloper.py new file mode 100644 index 0000000..4eb931c --- /dev/null +++ b/keyboards/FirstStepDeveloper.py @@ -0,0 +1,18 @@ +from bot.Keyboard import Keyboard +from telegram import InlineKeyboardButton, InlineKeyboardMarkup + + +class FirstStepDeveloper(Keyboard): + + def get_keyboard(self): + return [ + [ + InlineKeyboardButton("Последние проекты", callback_data='get_last_projects') + ], + # [ + # InlineKeyboardButton("Стать разработчиком", callback_data='set_developer') + # ], + # [ + # InlineKeyboardButton("Меню заведения", callback_data='get_menu') + # ], + ] diff --git a/keyboards/FirstStepKeyboard.py b/keyboards/FirstStepKeyboard.py new file mode 100644 index 0000000..6a28e54 --- /dev/null +++ b/keyboards/FirstStepKeyboard.py @@ -0,0 +1,18 @@ +from bot.Keyboard import Keyboard +from telegram import InlineKeyboardButton, InlineKeyboardMarkup + + +class FirstStepKeyboard(Keyboard): + + def get_keyboard(self): + return [ + [ + InlineKeyboardButton("Авторизация", callback_data='request_code') + ], + # [ + # InlineKeyboardButton("Стать разработчиком", callback_data='set_developer') + # ], + # [ + # InlineKeyboardButton("Меню заведения", callback_data='get_menu') + # ], + ] diff --git a/keyboards/FirstStepPartner.py b/keyboards/FirstStepPartner.py new file mode 100644 index 0000000..3a3b44c --- /dev/null +++ b/keyboards/FirstStepPartner.py @@ -0,0 +1,18 @@ +from bot.Keyboard import Keyboard +from telegram import InlineKeyboardButton, InlineKeyboardMarkup + + +class FirstStepPartner(Keyboard): + + def get_keyboard(self): + return [ + [ + InlineKeyboardButton("Запросить кандидатов", callback_data='get_developers') + ], + # [ + # InlineKeyboardButton("Стать разработчиком", callback_data='set_developer') + # ], + # [ + # InlineKeyboardButton("Меню заведения", callback_data='get_menu') + # ], + ] diff --git a/keyboards/GetTableListKeyboard.py b/keyboards/GetTableListKeyboard.py new file mode 100644 index 0000000..4781fe3 --- /dev/null +++ b/keyboards/GetTableListKeyboard.py @@ -0,0 +1,23 @@ +from bot.Keyboard import Keyboard +from telegram import InlineKeyboardButton, InlineKeyboardMarkup + + +class GetTableListKeyboard(Keyboard): + + def get_keyboard(self): + keyboard = [] + for i in range(1, 8): + keyboard.append( + [ + InlineKeyboardButton("Стол {t}".format(t=i), + callback_data="set_table={t}".format(t=i)) + ] + ) + + keyboard.append( + [ + InlineKeyboardButton("Назад", callback_data="set_table=back") + ] + ) + + return keyboard diff --git a/keyboards/VacancyNotificationToAdminKeyboard.py b/keyboards/VacancyNotificationToAdminKeyboard.py new file mode 100644 index 0000000..d8f8767 --- /dev/null +++ b/keyboards/VacancyNotificationToAdminKeyboard.py @@ -0,0 +1,34 @@ +from bot.Keyboard import Keyboard +from telegram import InlineKeyboardButton + + +class VacancyNotificationToAdminKeyboard(Keyboard): + + def get_keyboard(self): + keyboard = [] + + recipient = self.get_option("recipient") + post = self.get_option("post") + channel_link = post['channel_link'][1:] + channel_link = "https://t.me/{cl}".format(cl=channel_link) + post_link = "{channel_link}/{post_id}".format(channel_link=channel_link, post_id=post['post_id']) + recipient_role = recipient['status'] + + if recipient_role != 2: + keyboard.append([InlineKeyboardButton("Откликнуться", + callback_data='admin_respond_to_vacancy?ig_post_id={post_id}&dialog_id={dialog_id}'.format( + post_id=post['id'], dialog_id=recipient['dialog_id']) + ) + ]) + + if recipient_role == 2: + keyboard.append([InlineKeyboardButton("Открыть канал", url=channel_link)]) + keyboard.append([InlineKeyboardButton("Открыть пост", url=post_link)]) + if post['status'] != 5: + keyboard.append([InlineKeyboardButton("Запрос отправлен", + callback_data='request_sent?ig_post_id={post_id}'.format( + post_id=post['id']) + ) + ]) + + return keyboard diff --git a/msg/AdminNotifMsg.py b/msg/AdminNotifMsg.py new file mode 100644 index 0000000..f32c56d --- /dev/null +++ b/msg/AdminNotifMsg.py @@ -0,0 +1,22 @@ +from bot.HtmlMsg import HtmlMsg + + +class AdminNotifMsg(HtmlMsg): + + def get_msg(self, data=None) -> str: + if data is None: + data = {} + cl = "" + recipient = "" + status = "" + if data['admin']['status'] == 2: + cl = "Ссылка: {channel_link}\n".format(channel_link=data['post']['channel_link']) + if 'recipient_respond' in data: + recipient = "Эксперт @{username} откликнулся на вакансию\n".format(username=data['recipient']['username']) + if 'status' in data: + status = "Статус: {status}\n".format(status=data['status']) + ct = "Название: {channel_title}\n".format(channel_title=data['post']['channel_title']) + content = "Текст:\n{content}".format(content=data['post']['content']) + msg = "{recipient}{status}{cl}{ct}{content}".format(cl=cl, ct=ct, content=content, recipient=recipient, status=status) + + return self.get_stylized_msg(msg) diff --git a/msg/CryptocurrencyMsg.py b/msg/CryptocurrencyMsg.py new file mode 100644 index 0000000..859bdb3 --- /dev/null +++ b/msg/CryptocurrencyMsg.py @@ -0,0 +1,22 @@ +from bot.DaMsg import DaMsg +from pycoingecko import CoinGeckoAPI + +from bot import config + + +class CryptocurrencyMsg(DaMsg): + + @staticmethod + def get_msg(data=None) -> str: + if data is None: + data = {} + cg = CoinGeckoAPI() + codes = config['CRYPTO_CHARCODES'].split(" ") + res = cg.get_price(ids=codes, vs_currencies=['usd']) + msg = '📈 Курс криптовалют на сегодня:\n\n' + for currency in codes: + msg = msg + "" + currency + ": " + str(res[currency]['usd']) + "$\n\n" + + msg = msg + "👉 Предложить новость" + + return msg \ No newline at end of file diff --git a/msg/ExchangeMsg.py b/msg/ExchangeMsg.py new file mode 100644 index 0000000..81ef1f1 --- /dev/null +++ b/msg/ExchangeMsg.py @@ -0,0 +1,35 @@ +from bot.DaMsg import DaMsg +from exchange.Cbr import Cbr + + +class ExchangeMsg(DaMsg): + + @staticmethod + def get_msg(data=None) -> str: + if data is None: + data = {} + cbr = Cbr() + currencies = cbr.get_by_codes() + msg = '📈 Курс валют ЦБ РФ на сегодня:\n\n' + for currency in currencies: + circle = ExchangeMsg.get_circle(currency['Value'], currency['Previous']) + arrow = ExchangeMsg.get_arrow(currency['Value'], currency['Previous']) + msg = msg + "{n}: {c} {v} {a}\n\n".format(n=currency['Name'], c=circle, v=currency['Value'], a=arrow) + + msg = msg + "👉 Предложить новость" + + return msg + + @staticmethod + def get_arrow(value, previous) -> str: + if value > previous: + return "⬆" + + return "⬇" + + @staticmethod + def get_circle(value, previous) -> str: + if value > previous: + return "🟢" + + return "🔴" diff --git a/msg/SetEmailMsg.py b/msg/SetEmailMsg.py new file mode 100644 index 0000000..bbb48b9 --- /dev/null +++ b/msg/SetEmailMsg.py @@ -0,0 +1,7 @@ +from bot.DaMsg import DaMsg + + +class SetEmailMsg(DaMsg): + + def get_msg(data=None) -> str: + return "Укажите пожалуйста email, который вы используете на ITGuild, если у вас нет учетной записи, то мы ее создадим." \ No newline at end of file diff --git a/msg/UserMsg.py b/msg/UserMsg.py new file mode 100644 index 0000000..3e575e8 --- /dev/null +++ b/msg/UserMsg.py @@ -0,0 +1,9 @@ +from bot.DaMsg import DaMsg + + +class HelloMsg(DaMsg): + + def get_msg(data=None) -> str: + return ("Здравствуйте. Для более удобной работы с нашим ботом, вам необходимо авторизироваться. " + "Перейдите по сслыки https://itguild.info/profile/settings, " + "в блоке «Телеграмм бот» нажмите на кнопку «Сгенерировать», полученный код отправте в телеграмм бот.") \ No newline at end of file diff --git a/msg/UserPostMsg.py b/msg/UserPostMsg.py new file mode 100644 index 0000000..052c344 --- /dev/null +++ b/msg/UserPostMsg.py @@ -0,0 +1,13 @@ +from bot.HtmlMsg import HtmlMsg + + +class UserPostMsg(HtmlMsg): + + def get_msg(self, data=None) -> str: + if data is None: + data = {} + content = "{content}".format(content=data['post']['content']) + msg = "{content}".format(content=content) + + msg = self.replace_tag_with_content(msg, "secure") + return self.get_stylized_msg(msg)