コード例 #1
0
ファイル: vk.py プロジェクト: rashidsh/coinmath
    def event_handler(self) -> None:
        convs = self.method('messages.getConversations', {
            'count': 200,
            'filter': 'unanswered'
        })['items']
        for i in convs:
            self.event_queue.append(VKMessage(i['last_message'], self))

        lp = VkBotLongPoll(self.vk, self.group_id)

        while True:
            try:
                for event in lp.check():
                    if event.type == VkBotEventType.MESSAGE_NEW:
                        self.event_queue.append(
                            VKMessage(event.raw['object']['message'], self))

                    else:
                        self.event_queue.append(event)

            except Exception as ex:
                self.logger.warning('Произошла ошибка в LongPoll', exc_info=ex)
                time.sleep(3)
コード例 #2
0
class RaidBot:
    def __init__(self, token, group_id):
        log_info(config.ver_msg)
        self.vk_session = vk_api.VkApi(token=token)
        self.longpoll = VkBotLongPoll(self.vk_session, group_id, wait=0.1)
        self.vk = self.vk_session.get_api()
        self.community_info = self.vk.groups.getById(group_id=group_id)
        self.start_listening()

    def start_raid(self, peer_id, controllers):
        working = True
        while working:
            for event in self.longpoll.check():
                # print(event)
                from_id = event.object['message']['from_id']
                message_text = event.object['message']['text']
                if event.type == VkBotEventType.MESSAGE_NEW:
                    parsed_text = utils.parse_message(message_text,
                                                      self.community_info)
                    if parsed_text == "stopRaid":
                        log_info('{} requested raid stop'.format(from_id))
                        admin_check_answer = check_admin(from_id)
                        if admin_check_answer:
                            log_info('Request approved. Starting raid.')
                            working = False
                            self.vk.messages.send(
                                peer_id=peer_id,
                                message="Raid is stopped",
                                random_id=get_random_id(),
                                keyboard=keyboard_gen.gen("startRaid"))

                        else:
                            log_info("Request denied. {} isn't in admin list.".
                                     format(from_id))
                            self.vk.messages.send(
                                peer_id=peer_id,
                                message="No access. Sosi xyi nishiy nn.",
                                random_id=get_random_id())

            if working:
                try:
                    self.vk.messages.send(
                        peer_id=peer_id,
                        message=random.choice(config.msgs),
                        random_id=get_random_id(),
                        attachment="wall-199568112_16",
                        keyboard=keyboard_gen.gen("arturyud.in vto.pe"))
                    time.sleep(config.message_delay)
                except vk_api.exceptions.ApiError:
                    working = False
                    log_error('Kicked from conversation, stopping...')

    def start_listening(self):
        for event in self.longpoll.listen():
            # print(event)
            peer_id = event.object['message']['peer_id']
            from_id = event.object['message']['from_id']

            message_text = event.object['message']['text']
            if event.type == VkBotEventType.MESSAGE_NEW:
                if message_text == '':
                    action_type = event.object['message']['action']['type']
                    if action_type == 'chat_invite_user':
                        self.vk.messages.send(
                            peer_id=peer_id,
                            message=config.ver_msg +
                            "\nTo start raid admin must click any button below!",
                            random_id=get_random_id(),
                            keyboard=keyboard_gen.gen("startRaid"))
                        log_info('Entered conversation')
                parsed_text = utils.parse_message(message_text,
                                                  self.community_info)
                if parsed_text == "ver":
                    self.vk.messages.send(peer_id=peer_id,
                                          message=config.ver_msg,
                                          random_id=get_random_id())
                if parsed_text == "startRaid":
                    log_info('{} requested raid start.'.format(from_id))
                    if check_admin(from_id):
                        log_info('Request approved. Starting raid.')
                        self.start_raid(peer_id=peer_id,
                                        controllers=config.controllers)
                    else:
                        log_info("Request denied. {} isn't in admin list.")
                        self.vk.messages.send(
                            peer_id=peer_id,
                            message="No access. Sosi xyi nishiy nn.",
                            random_id=get_random_id())
コード例 #3
0
def new_message_timeout_error(user_id):
    vk.messages.send(user_id=user_id,
                     random_id=random.getrandbits(50),
                     message='Я очень долго думаю, давайте еще раз')


def new_message_error(user_id):
    vk.messages.send(user_id=user_id,
                     random_id=random.getrandbits(50),
                     message='Что-то совсем сломалось, давайте еще раз')


if __name__ == '__main__':
    while True:
        try:
            for event in long_poll.check():
                if event.type == VkBotEventType.MESSAGE_NEW:
                    user_id = event.object.message['from_id']
                    try:
                        message_text = event.object.message['text']
                        if message_text == '/help':
                            send_help(user_id)
                        elif message_text == '/sorry':
                            user_states[user_id] = restore_state()
                            vk.messages.send(
                                user_id=user_id,
                                random_id=random.getrandbits(50),
                                message='Хорошо, давайте начнем все сначала')
                            send_state(user_id, user_states)
                        elif message_text == '/state':
                            if user_id not in user_states:
コード例 #4
0
ファイル: gui.py プロジェクト: MrOden911/GlaHa_Bot
class Gui:
    """ОБЩИЙ КЛАСС"""

    def __init__(self):
        # Токен группы VK
        self.__token = 'c9630c65f9b66f4e630558def110623447c8de90840e477bb5ece18f993c7c940c9373ac48eaf681b2349'

        # Подключение SQL
        self.sql_connect = sql.connect(os.path.join(
            os.path.realpath('bot'), 'data\\GodsDB.db'),
            check_same_thread=False
        )
        self.cursor = self.sql_connect.cursor()

        # Счетчики и словари
        self.list_action = (
            "event_listen",
            "event_read",
            "connect_vk",
        )
        self.active = dict((key, False) for key in self.list_action)
        print(self.active)
        list_action_by_ids = (
            'registration',
        )
        self.active_ids = dict((key, []) for key in list_action_by_ids)
        self.sql_lock = Lock()
        self.counters = {"event": 0,
                         }
        self.nicknames = []
        self.ignored_ids = set()
        self.df_sql = {}
        self.df_sql_writer()
        self.chat_ids = (
            2000000001,
            2000000002,
            2000000003,
        )
        self.yes = ['+', 'да', 'yes', 'y', 1, '1']
        self.no = ['-', 'нет', 'no', 'n', 0, '0']

        # Настрйока GUI
        self.window_main = tk.Tk()
        self.window_main.title("GlaHa The Bot")
        # Создание вкладок
        tab_control = ttk.Notebook(self.window_main)
        tab_main = tk.Frame(tab_control)
        tab_logs = tk.Frame(tab_control)
        tab_settings = tk.Frame(tab_control)
        tab_data = tk.Frame(tab_control)
        tab_control.add(tab_main, text="Управление")
        tab_control.add(tab_logs, text="Логи")
        tab_control.add(tab_settings, text="Настройки")
        tab_control.add(tab_data, text="База")
        # Создание фреймов на вкладке Управление
        #   Главный фрейм
        lfraim_tab_main = tk.LabelFrame(tab_main, text="Главное меню", font=('Arial', 14))
        lfraim_tab_main.grid(row=1, column=1, sticky='n')
        #       Заголовок
        lable_tab_main = tk.Label(lfraim_tab_main, text="Управление ботом в VK", font=('Papyrus', 13, "bold"))
        lable_tab_main.grid(row=1, column=1, sticky='n')
        #       Фрейм отправки сообщений
        lframe_message = tk.LabelFrame(lfraim_tab_main, text="Сообщение в чат")
        self.text_message = tk.Text(lframe_message, height=2, width=40, font='Arial 14', wrap=tk.WORD)
        button_send_message = tk.Button(lframe_message, text="Отправить")
        lframe_message.grid(row=3, column=1, sticky='n')
        self.text_message.grid(row=2, column=1)
        button_send_message.grid(row=2, column=2)
        #       Фрейм запуска и остановки
        lframe_startstop = tk.LabelFrame(lfraim_tab_main, text="Запуск")
        self.button_start = tk.Button(lframe_startstop, text='Старт', command=self.listen_to_events)
        button_login_vk = tk.Button(lframe_startstop, text='Подключение', command=self.start_bot_vk, bg='#F08080')
        button_stop = tk.Button(lframe_startstop, text='Выключение', command=self.exit)
        lframe_startstop.grid(row=2, column=1, sticky='wn')
        self.button_start.grid(row=2, column=1, padx=2, pady=2)
        button_login_vk.grid(row=1, column=1, columnspan=2)
        button_stop.grid(row=2, column=2, padx=2, pady=2)
        #       Фрейм статусов
        frame_status = tk.Frame(lfraim_tab_main)
        label_event_listen = tk.Label(frame_status, text='Прослушка', bg="#CD5C5C")
        label_event_read = tk.Label(frame_status, text='Расшифровка', bg="#CD5C5C")
        frame_status.grid(row=4, column=1)
        label_event_listen.grid(row=1, column=1)
        label_event_read.grid(row=1, column=2)

        #       Фрейм отчетов
        lframe_fastlog = tk.LabelFrame(tab_main, text='Лог')
        self.text_fastlog = tk.Text(lframe_fastlog, width=45, height=25, bg="#FAF0E6", wrap=tk.WORD, )
        scroll_fastlog = tk.Scrollbar(lframe_fastlog, command=self.text_fastlog.yview)
        scroll_fastlog.pack(side=tk.RIGHT, fill=tk.Y)
        self.text_fastlog.config(yscrollcommand=scroll_fastlog.set)
        lframe_fastlog.grid(row=1, column=3, rowspan=3)
        self.text_fastlog.pack(side=tk.LEFT)

        #   Вкладка настроек
        self.ch_send_message_to_vk = tk.BooleanVar()
        chb_send_message_to_vk = tk.Checkbutton(
            tab_settings,
            text="Отправка лога в ВК",
            onvalue=True,
            offvalue=False,
            variable=self.ch_send_message_to_vk)
        chb_send_message_to_vk.grid()

        #   Вкладка логов
        #       Лог ошибок
        lframe_errorlog = tk.LabelFrame(tab_logs, text='Лог ошибок')
        self.text_errorlog = tk.Text(lframe_errorlog, width=70, height=10, bg="#FAF0E6", wrap=tk.WORD, )
        scroll_errorlog = tk.Scrollbar(lframe_errorlog, command=self.text_errorlog.yview)
        scroll_errorlog.pack(side=tk.RIGHT, fill=tk.Y)
        self.text_errorlog.config(yscrollcommand=scroll_errorlog.set)
        lframe_errorlog.grid(row=1, column=1, sticky=tk.N, padx=5, pady=5)
        self.text_errorlog.pack(side=tk.LEFT)
        #       Лог сообщений
        lframe_income = tk.LabelFrame(tab_logs, text='Сообщения из чатов')
        self.text_income = tk.Text(lframe_income, width=45, height=28, bg="#FAF0E6", wrap=tk.WORD, )
        scroll_income = tk.Scrollbar(lframe_income, command=self.text_income.yview)
        scroll_income.pack(side=tk.RIGHT, fill=tk.Y)
        self.text_income.config(yscrollcommand=scroll_income.set)
        lframe_income.grid(row=1, column=2, rowspan=2, sticky=tk.N, padx=5, pady=5)
        self.text_income.pack(side=tk.LEFT)

        tab_control.pack(side=tk.LEFT, fill=tk.Y)

        self.list_labels = {
            'connect_vk': button_login_vk,
            'event_listen': label_event_listen,
            'event_read': label_event_read,
        }
        # Schedule функции
        sch.every(5).minutes.do(self.all_gods_data_updater)
        sch.every().hour.at(':00').do(self.zpg_warning_start, 2000000002, 2000000001)
        sch.every().hour.at(':04').do(self.zpg_warning_end, 2000000002, 2000000001)
        sch.every().hour.at(':55').do(self.zpg_warning_before, 2000000002, 2000000001)
        self.schedule_starter()

        self.status_changer()
        self.start_bot_vk()
        self.listen_to_events()
        self.window_main.mainloop()

    # БЛОК ДЕКОРАТОРОВ
    def log_error(func):
        """Декоратор обработки ошибки"""

        def wrapper(self, *args, **kwargs):
            try:
                func(self, *args, **kwargs)
            except Exception as exc:
                self.error_writer(exc)
            return

        return wrapper

    def df_sql_update(func):
        def wrapper(self, *args, **kwargs):
            func(self, *args, **kwargs)
            self.df_sql_writer()
            return

        return wrapper

    # БЛОК ФОНОВЫХ ПРОЦЕССОВ

    @new_thread
    def schedule_starter(self):
        while True:
            sch.run_pending()
            sleep(2)

    def error_writer(self, exc, fun=None):
        """Записывает ошибки в логи"""
        if fun:
            self.active[fun] = False
        exc_text = str(dt.now().time()) + '\n' + str(exc) + '\n'
        with open(os.path.join(os.path.realpath('bot'),
                               'logs\\errors\\{}'.format(dt.now().date())),
                  'a',
                  encoding='utf-8'
                  ) as file:
            try:
                self.print_fastlog('Ой, что-то пошло не так(')
                print(exc_text)
                self.print_errorlog(str(exc))
            except Exception as a:
                self.print_errorlog(str(a))
                exc_ttext = str(dt.now().time()) + '\n' + str(a) + '\n'
                print(exc_ttext, file=file)
            finally:
                print(exc_text, file=file)

    def income_writer(self, text, user_id, chat=None):
        script = "select first_name, last_name from onjoin where user_id=?"
        with self.sql_lock:
            if user_id in self.humans:
                name = " ".join(self.cursor.execute(script, (user_id,)).fetchall()[0])
            else:
                name = 'unknown'
            output_message = "{0}{1} ({2})\n{4}{3}\n\n".format(
                dt.now().strftime("%H:%M:%S "),
                name if not chat else self.api.messages.getConversationsById(
                    peer_ids=(chat,),
                    fields=('nickname',)
                )['items'][0]['chat_settings']['title'],
                self.id_to_nicknames[user_id] if user_id in self.id_to_nicknames.keys() else "unknown_god",
                text,
                "--" if not chat else name + ": "
            )
        self.print_incomelog(output_message)
        with open(os.path.join(os.path.realpath('bot'),
                               'logs\\income_messages\\{}'.format(dt.now().date())),
                  'a',
                  encoding='utf-8'
                  ) as file:
            print(output_message, file=file)
        return

    @new_thread
    def status_changer(self):
        while True:
            for action in self.list_action:
                try:
                    if self.active[action]:
                        self.list_labels[action]['bg'] = '#7FFF00'
                    else:
                        self.list_labels[action]['bg'] = '#F08080'
                except Exception as e:
                    print(e)
            sleep(2)

    def login_vk(self):
        session = vk.VkApi(token=self.__token)
        self.long_poll_bot = VkBotLongPoll(session, 169181915)
        self.active['connect_vk'] = True
        self.api = session.get_api()
        self.print_fastlog("Бот подключен!")
        self.missed_gods()
        return

    def missed_gods(self):
        """Проверка пропущенных во время бездействия богов"""
        current_ids_vk = self.api.groups.getMembers(group_id=169181915)['items']
        with self.sql_lock:
            self.cursor.execute("""SELECT user_id FROM onjoin where active = 1""")
            current_ids_db = [x[0] for x in self.cursor.fetchall()]
        if len(current_ids_db) != len(current_ids_vk):
            difference = list(set(current_ids_vk) ^ set(current_ids_db))
            self.print_fastlog('Найдены несоответствия Богов в базе и группе!')
            if len(current_ids_vk) > len(current_ids_db):
                for i in difference:
                    self.sql_add_onjoin(user_id=i)
            elif len(current_ids_vk) < len(current_ids_db):
                for i in difference:
                    self.sql_del_onjoin(user_id=i)
        return

    def start_bot_vk(self):
        self.login_vk()
        # self.button_start.grid_forget()
        return

    def exit(self):
        self.window_main.destroy()
        return

    # БЛОК ОТРАБОТКИ СОБЫТИЙ

    @new_thread
    @log_error
    def listen_to_events(self):
        """Получение ивентов от сервера"""
        fun = 'event_listen'
        try:
            if self.active[fun]:
                self.print_fastlog('Прослушка уже запущена!')
                return
            else:
                self.active['event_listen'] = True
            for event in self.long_poll_bot.listen():
                self.event_reader(event)
            self.active[fun] = False
        except Exception as exc:
            self.error_writer(exc, fun=fun)
        return

    @new_thread
    def event_reader(self, event):
        print('-------------------------MAIN-----------------------------')
        print(event.type)
        pprint(event)
        print('----------------------------------------------------------')
        if event.type == VkBotEventType.GROUP_JOIN:
            self.sql_add_onjoin(event=event)
        elif event.type == VkBotEventType.GROUP_LEAVE:
            self.sql_del_onjoin(event=event)
        elif event.type == VkBotEventType.MESSAGE_NEW:
            self.message_handler(event)
        elif event.type == VkBotEventType.MESSAGE_ALLOW:
            self.message_allow(event=event)
        elif event.type == VkBotEventType.MESSAGE_DENY:
            self.message_deny(event=event)
        return

    def message_handler(self, event):
        chat_id = None
        user_id = event.obj.from_id
        if event.from_chat:
            # Сообщения из активного чата
            chat_type = True
            chat_id = event.obj.peer_id
            peer_id = chat_id
        else:
            if user_id not in self.can_write:
                self.message_allow(user_id=user_id)
            peer_id = user_id
            chat_type = False
        message_text = message_decode(event.obj.text)
        self.income_writer(message_text, user_id, chat_id)
        if user_id in self.humans and user_id not in self.ignored_ids and (chat_id is None or chat_id in self.chat_ids):
            if (
                    message_text != ''
                    and message_text != '!'
                    and (
                    'глаш' in message_text
                    or 'глах' in message_text or
                    message_text[0] == '!'
            )
            ):
                if 'привет' in message_text:
                    self.send_message(choice(self.ans_hello), peer_id)
                elif 'спасиб' in message_text:
                    self.send_message(choice(self.ans_thanks), peer_id)
                elif 'ночи' in message_text:
                    self.send_message(choice(self.ans_goodnight), peer_id)
                elif (
                        message_text[0] == '!'
                        or 'глаша,' in message_text
                        or 'глаха,' in message_text
                        or ', глаш' in message_text
                        or ', глах' in message_text
                ):
                    if 'регистр' in message_text:
                        if user_id not in self.active_ids['registration']:
                            self.active_ids['registration'].append(user_id)
                            try:
                                if chat_type:
                                    self.send_message('Пойдем-ка поговорим..', peer_id)
                                if 'токен' in message_text:
                                    self.registration_token(user_id)
                                elif 'ник' in message_text or 'имя' in message_text:
                                    self.registration_nickname(user_id)
                                else:
                                    self.registration(user_id)
                            finally:
                                self.active_ids['registration'].remove(user_id)
                        else:
                            self.send_message('Так ты уже регистрируешься о_О', peer_id)
    #                 elif 'идея' in message_text:
    #                     if 'получить' in message_text:
    #                         self.idea_get(id_cur)
    #                     else:
    #                         self.idea_write(message_text, user_id, chat_type)
    #                 elif 'подзем' in message_text or 'подземелье' in message_text:
    #                     initiator_id_podzem = user_id
    #                     if user_id in self.active_gods:
    #                         self.podzem_start()
    #                     else:
    #                         self.send_message_chat('Не зарегистрировался? Вот и сиди без бревна!')
    #                 elif 'помощь' in message_text or 'хелп' in message_text:
    #                     self.helper(id_cur, chat_type)
    #                 elif 'прогноз' in message_text or 'астро' in message_text:
    #                     self.prognoz_start(id_cur, chat_type)
    #                 elif 'кто' in message_text or 'црщ' in message_text:
    #                     pass
    #                 elif 'база' in message_text:
    #                     self.print_base(id_cur, chat_type)
    #                 elif 'отмена' in message_text or 'отмени' in message_text:
    #                     pass
    #                 elif 'зпг' in message_text or 'язп' in message_text:
    #                     if id_cur in self.admin_id:
    #                         if 'вкл' in message_text:
    #                             self.zpg_start()
    #                         elif 'выкл' in message_text:
    #                             self.active_threads['zpg'] = False
    #                         else:
    #                             self.send_message_chat('И что мне с ним делать?')
    #                     else:
    #                         self.send_message_chat('Извини, у тебя прав маловато :3')
    #                 elif 'утра' in message_text or 'утро' in message_text or 'утре' in message_text:
    #                     self.say_utra(id_cur, chat_type)
    #                 elif 'выкл' in message_text:
    #                     if id_cur in self.admin_id:
    #                         if 'тих' in message_text:
    #                             self.exit_bot_silence()
    #                         else:
    #                             self.exit_bot()
    #                 elif chat_type:
    #                     self.send_message_chat(choice(self.ans_unready))
    #                 else:
    #                     self.send_message_person(choice(self.ans_unready), id_cur)
    #         elif 'побед' in message_text and time() - self.podzem_time < 3600 and chat_type:
    #             self.send_message_chat('Оу, вы победили? Какие молодцы :3')
    #             self.podzem_time = 0
    #         elif chat_type and (
    #                 'утра' in message_text or 'утро' in message_text or 'утре' in message_text) and time() - self.utra_time > 3600:
    #             self.send_message_chat(choice(self.ans_utra))
    #             self.utra_time = time()
    #         elif 'я спать' in message_text:
    #             self.say_goodnight(id_cur, chat_type)
    #     elif not chat_type:
    #         if 'привет' in message_text:
    #             if chat_type:
    #                 self.send_message_chat(choice(self.ans_hello))
    #             else:
    #                 self.send_message_person(choice(self.ans_hello), id_cur)
    #         elif 'спасиб' in message_text:
    #             if chat_type:
    #                 self.send_message_chat(choice(self.ans_thanks))
    #             else:
    #                 self.send_message_person(choice(self.ans_thanks), id_cur)
    #         elif 'ночи' in message_text:
    #             self.say_goodnight(id_cur, chat_type)
    #         elif message_text[
    #             0] == '!' or 'глаша,' in message_text or 'глаха,' in message_text or ', глаш' in message_text or ', глах' in message_text:
    #             if 'идея' in message_text:
    #                 if 'получить' in message_text:
    #                     self.idea_get(id_cur)
    #                 else:
    #                     self.idea_write(message_text, id_cur, chat_type)
    #             elif 'подзем' in message_text or 'подземелье' in message_text:
    #                 self.initiator_id_podzem = id_cur
    #                 if chat_type:
    #                     if id_cur in self.players_id:
    #                         self.podzem_start()
    #                     else:
    #                         self.send_message_chat('Не зарегистрировался? Вот и сиди без бревна!')
    #                 else:
    #                     self.send_message_person('Подзем можно запустить только из общего чата.', id_cur)
    #             elif 'помощь' in message_text or 'хелп' in message_text:
    #                 self.helper(id_cur, chat_type)
    #             elif 'прогноз' in message_text or 'астро' in message_text:
    #                 self.prognoz_start(id_cur, chat_type)
    #             elif 'кто' in message_text or 'who' in message_text:
    #                 pass
    #             elif 'база' in message_text:
    #                 self.print_base(id_cur, chat_type)
    #             elif 'отмена' in message_text or 'отмени' in message_text:
    #                 pass
    #             elif 'зпг' in message_text or 'язп' in message_text:
    #                 if id_cur in self.admin_id:
    #                     if 'вкл' in message_text:
    #                         self.zpg_start()
    #                     elif 'выкл' in message_text:
    #                         self.active_threads['zpg'] = False
    #                     else:
    #                         self.send_message_chat('И что мне с ним делать?')
    #                 else:
    #                     self.send_message_chat('Извини, у тебя прав маловато :3')
    #             elif 'утра' in message_text or 'утро' in message_text or 'утре' in message_text:
    #                 self.say_utra(id_cur, chat_type)
    #             elif 'выкл' in message_text:
    #                 if id_cur in self.admin_id:
    #                     if 'тих' in message_text:
    #                         self.exit_bot_silence()
    #                     else:
    #                         self.exit_bot()
    #             elif chat_type:
    #                 self.send_message_chat(choice(self.ans_unready))
    #             else:
    #                 self.send_message_person(choice(self.ans_unready), id_cur)
        else:
            return
        return

    # БЛОК ФУНКЦИЙ

    @df_sql_update
    def message_allow(self, event=None, user_id=None):
        if event:
            user_id = event.obj.user_id
        elif not user_id:
            return
        if user_id in self.humans:
            with self.sql_lock:
                self.cursor.execute('UPDATE onjoin SET can_write=1 WHERE user_id=?', (user_id,))
                self.sql_connect.commit()
        return

    @df_sql_update
    def message_deny(self, event=None, user_id=None):
        if event:
            user_id = event.obj.user_id
        elif not user_id:
            return
        if user_id in self.humans:
            with self.sql_lock:
                self.cursor.execute('UPDATE onjoin SET can_write=0 WHERE user_id=?', (user_id,))
                self.sql_connect.commit()
        return

    @new_thread
    def zpg_warning_start(self, *chat_ids):
        for chat_id in chat_ids:
            self.send_message('ZPG арена открылась!', chat_id)

    @new_thread
    def zpg_warning_end(self, *chat_ids):
        for chat_id in chat_ids:
            self.send_message('ZPG арена закрылась.', chat_id)

    @new_thread
    def zpg_warning_before(self, *chat_ids):
        for chat_id in chat_ids:
            self.send_message('ZPG арена открывается через 5 минут!', chat_id)

    def person_message_handler(self, user_id):
        while True:
            event = self.long_poll_bot.check()
            if not event:
                continue
            else:
                event = event[0]
            if event.type == VkBotEventType.MESSAGE_NEW and not event.from_chat and event.obj.from_id == user_id:
                self.ignored_ids.discard(user_id)
                return event.obj.text
            else:
                continue

    def registration(self, user_id):
        self.ignored_ids.add(user_id)
        self.send_message('Добро пожаловать, Бог.', user_id)
        if user_id in self.id_to_nicknames.keys():
            self.send_message('Упс, кажется ты уже зарегестрирован.\nХотите изменить регистрационные данные?',
                              user_id)
            while True:
                ans = self.person_message_handler(user_id).lower()
                if ans in self.yes:
                    self.send_message(
                        """
                        Выбери изменяемые данные:
                        1 - Никнейм
                        2 - Токен
                        """,
                        user_id)
                    while True:
                        ans = self.person_message_handler(user_id).lower()
                        if ans == '1' or ans.lower() == 'никнейм':
                            self.registration_nickname(user_id)
                            break
                        elif ans == '2' or ans.lower() == 'токен':
                            self.registration_token(user_id)
                            break
                        else:
                            self.send_message('Такого нет в списке(', user_id)
                    break
                elif ans in self.no:
                    self.send_message('На нет и суда нет.', user_id)
        else:
            self.registration_nickname(user_id)
            self.registration_token(user_id)
        return

    @df_sql_update
    def registration_nickname(self, user_id):
        while True:
            c = 0
            god_nickname_1 = ""
            god_nickname_2 = ""
            self.send_message('Поведай же мне имя свое!', user_id)
            while god_nickname_1 in (None, "", 0, "0", "1", 1):
                if c > 0:
                    self.send_message('Как-то слабо верится, введи еще раз..', user_id)
                c += 1
                god_nickname_1 = self.person_message_handler(user_id)
            c = 0
            self.send_message('Повтори еще раз для проверки..', user_id)
            while god_nickname_2 in (None, "", 0, "0", "1", 1):
                if c > 0:
                    self.send_message('Как-то слабо верится, введи еще раз..', user_id)
                c += 1
                god_nickname_2 = self.person_message_handler(user_id)
            if god_nickname_1 != god_nickname_2:
                self.send_message('Упс, кажется ты ошибся, придется повторить..', user_id)
                continue
            elif god_nickname_1 in self.nicknames_to_id.keys():
                self.send_message('Упс, такой ник уже существует!\n Придется повторить..', user_id)
                continue
            else:
                break
        with self.sql_lock:
            if user_id in self.id_to_nicknames.keys():
                self.cursor.execute(
                    f'UPDATE god_data SET god_nickname=? WHERE user_id=?',
                    (god_nickname_1, user_id)

                )
                self.cursor.execute(
                    f'UPDATE god_data SET approve=? WHERE user_id=?',
                    (0, user_id)
                )
                self.sql_connect.commit()
            else:
                self.cursor.execute(f'INSERT INTO god_data(user_id, god_nickname) VALUES (?,?)',
                                    (user_id, god_nickname_1))
                self.sql_connect.commit()
            self.send_message('Никнейм сохранен.', user_id)
        return

    @df_sql_update
    def registration_token(self, user_id):
        if user_id not in self.id_to_nicknames.keys():
            self.send_message('Ты еще не зарегистрировал Никнейм!', user_id)
            return
        self.send_message('Мне нужна твоя одежда, и твой токен!', user_id)
        self.send_message('''
            Шучу, в этот раз мне нужен только токен из Годвилля :3
            Токен -- это уникальный ключ доступа к данным твоего героя из Годвилля.
            С его помощью я смогу чуть более тщательно следить за его передвижениями, и предупреждать тебя о некоторых полезных событиях :3
            Торжественно клянусь, что замышляю только шало... Нет нет нет, все твои данные будут строго защищены, и никто кроме меня их не увидит.
            Иногда твой токен будет обновляться. Поэтому его придется вводить заново!
            
            Для получения токена:
            1) Открой ссылку в браузере
            https://godville.net/user/profile/settings
            2) Сгенерируй новый токен во вкладке "Ключ API", нажми "Применить"
            
            Если ты отказываешься делиться со мной своим токеном, то просто отправь мне сообщение с текстом "None", или любую белиберду.
            Если же ты все таки решился, то напиши мне свой токен.

            ''', user_id, 'photo-169181915_457239017')
        ans = self.person_message_handler(user_id)
        if ans.lower() != 'none':
            for letter in ans:
                if letter not in ascii_lowercase + '0987654321':
                    with self.sql_lock:
                        self.cursor.execute(f'UPDATE functions SET advanced=0 WHERE user_id=?', (user_id,))
                        self.cursor.execute(f'UPDATE god_data SET token=NULL WHERE user_id=?', (user_id,))
                        self.sql_connect.commit()
                    self.send_message('Токен не был записан.', user_id)
                    return
        if ans.lower() == 'none':
            with self.sql_lock:
                self.cursor.execute(f'UPDATE functions SET advanced=0 WHERE user_id=?', (user_id,))
                self.cursor.execute(f'UPDATE god_data SET token=NULL WHERE user_id=?', (user_id,))
                self.sql_connect.commit()
            self.send_message('Токен не был записан.', user_id)
        else:
            with self.sql_lock:
                self.cursor.execute(f'UPDATE functions SET advanced=1 WHERE user_id=?', (user_id,))
                self.cursor.execute(f'UPDATE god_data SET token=? WHERE user_id=?', (ans, user_id))
                self.sql_connect.commit()
            self.send_message('Записала :3', user_id)
        return

    @new_thread
    def all_gods_data_updater(self):
        for god_name in self.nicknames_to_id.keys():
            self.god_data_update(god_name)
            sleep(10)
        return

    @df_sql_update
    def god_data_update(self, god_name):
        user_id = self.nicknames_to_id[god_name]
        with self.sql_lock:
            if not self.cursor.execute(
                    f'SELECT approve FROM god_data WHERE user_id={self.nicknames_to_id[god_name]}').fetchall()[0][0]:
                self.print_fastlog(f'Бог {god_name} не подтвержден, данные не обновлены.')
                return
        if self.nicknames_to_id[god_name] in self.advanced_gods:
            token = self.cursor.execute("SELECT token FROM god_data WHERE god_nickname=?", (god_name,)).fetchall()[0][0]
            print(token)
            if token is not None:
                token = "/" + token
            else:
                token = ""
                self.send_message('Кажется твой токен устарел :(\nЗарегистрируй новый, если хочешь получать всю самую '
                                  'свежую статистику о своем герое!', self.nicknames_to_id[god_name])
                with self.sql_lock:
                    self.cursor.execute(
                        'UPDATE functions SET advanced=0 WHERE user_id=?',
                        (self.nicknames_to_id[god_name],)
                    )
                    self.sql_connect.commit()
        else:
            token = ""
        json_get = req.get(f'https://godville.net/gods/api/{god_name}{token}')
        print(type(json_get))
        pprint(json_get)
        json_get = json_get.json()
        pprint(json_get)
        if 'expired' in json_get.keys():
            self.print_fastlog(f'Данные {god_name} устарели в Годвилле!')
            return
        json_get['update_time'] = dt.now().strftime("%H:%M:%S")
        if 'activatables' in json_get.keys():
            json_get['activatables'] = str(json_get['activatables'])
        try:
            json_get.update(json_get['pet'])
        except:
            pass
        column_list = ['activatables', 'alignment', 'arena_fight', 'arena_lost', 'arena_won', 'ark_completed_at',
                       'ark_f', 'ark_m', 'aura', 'boss_name', 'boss_power', 'bricks_cnt', 'clan', 'clan_position',
                       'diary_last', 'distance', 'exp_progress', 'fight_type', 'gender', 'godpower', 'gold_approx',
                       'health', 'inventory_max_num', 'inventory_num', 'level', 'max_health', 'motto', 'name', 'quest',
                       'quest_progress', 'savings', 'savings_completed_at', 'shop_name', 't_level',
                       'temple_completed_at', 'town_name', 'wood_cnt', 'words', 'pet_class', 'pet_level', 'pet_name',
                       'wounded', 'update_time']
        result_list = []
        for i in column_list:
            if i in json_get.keys():
                result_list.append(json_get[i])
            else:
                result_list.append(None)
        res_column_list = "activatables=?"
        for column in column_list[1:]:
            res_column_list += f", {column}=?"
        with self.sql_lock:
            self.cursor.execute(f'update god_data set {res_column_list} WHERE user_id={self.nicknames_to_id[god_name]}',
                                result_list)
            self.sql_connect.commit()
        if token \
                != '' and 'distance' not in json_get.keys():
            self.send_message('Кажется твой токен устарел :(\nЗарегистрируй новый, если хочешь получать всю самую '
                              'свежую статистику о своем герое!', self.nicknames_to_id[god_name])
            with self.sql_lock:
                self.cursor.execute(
                    'UPDATE functions SET advanced=0 WHERE user_id=?',
                    (self.nicknames_to_id[god_name],)
                )
                self.cursor.execute(f'UPDATE god_data SET token=NULL WHERE user_id={user_id}')
                self.sql_connect.commit()
        return

    def send_message(self, text, peer_id, attachment=''):
        if peer_id < 2000000000 and peer_id not in self.can_write:
            self.print_fastlog(f'Не удалось написать сообщение {peer_id if peer_id not in self.id_to_nicknames else self.id_to_nicknames[peer_id]}\nПользователь не дал доступ к сообщениям!')
            return
        self.api.messages.send(peer_id=peer_id, message=text, random_id=get_random_id(), attachment=attachment)
        return

    def df_sql_writer(self):
        with self.sql_lock:
            for table in sum(self.cursor.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall(), ()):
                self.df_sql[table] = pd.read_sql_query("select * from {0}".format(table), self.sql_connect)
        df = self.df_sql['onjoin']

        self.admin_ids = []
        self.humans = []
        self.can_write = []
        for i in df[df['god_type'] == "admin"].user_id:
            self.admin_ids.append(i)
        for i in df.user_id:
            self.humans.append(i)
        for i in df[df['can_write'] == 1].user_id:
            self.can_write.append(i)
        for i in self.df_sql.values():
            print(i)

        df = self.df_sql['god_data']
        self.active_gods = []
        self.registered_gods = []
        for i in df.user_id:
            self.registered_gods.append(i)
        for i in df[df['approve'] == 1].user_id:
            self.active_gods.append(i)

        df = self.df_sql['functions']
        self.advanced_gods = []
        for i in df[df['advanced'] == 1].user_id:
            self.advanced_gods.append(i)

        self.id_to_nicknames = {}
        self.nicknames_to_id = {}
        with self.sql_lock:
            for i in self.cursor.execute('SELECT user_id, god_nickname FROM god_data').fetchall():
                self.id_to_nicknames[i[0]] = i[1]
                self.nicknames_to_id[i[1]] = i[0]
        return

    # БЛОК ЗАПИСИ ЛОГОВ
    def print_fastlog(self, text):
        self.text_fastlog.insert(tk.END, dt.now().strftime("%H:%M:%S -- ") + text + "\n")
        if self.ch_send_message_to_vk.get():
            self.api.messages.send(user_id=54228077, message=text, random_id=get_random_id())
        return

    def print_errorlog(self, text):
        self.text_errorlog.insert(tk.END, dt.now().strftime("%H:%M:%S -- ") + text + "\n")
        return

    def print_incomelog(self, output_message):
        self.text_income.insert(
            tk.END,
            output_message
        )
        return

    # БЛОК SQL

    @log_error
    def sql_execute(self, comm):
        self.cursor.execute(comm)
        self.sql_connect.commit()

    def sql_redact_onjoin(self):
        pass

    @df_sql_update
    def sql_add_onjoin(self, user_id=None, event=None):
        if event:
            user_id = int(event.obj.user_id)
        elif not user_id:
            self.print_fastlog('Нет user_id!')
            return
        if type(user_id) != int:
            user_id = int(user_id)
        data = self.api.users.get(user_ids=user_id, fields=['sex', 'first_name', 'last_name'])[0]
        if data['sex'] == 2:
            sex = 'man'
        elif data['sex'] == 1:
            sex = 'woman'
        else:
            sex = None
        with self.sql_lock:
            try:
                self.cursor.execute(
                    """INSERT INTO onjoin (user_id, first_name, last_name, sex, active) VALUES (?,?,?,?,?)""",
                    [user_id,
                     data['first_name'],
                     data['last_name'],
                     sex,
                     1])
                self.cursor.execute("""INSERT INTO functions(user_id) VALUES (?)""", user_id)
            except Exception:
                self.cursor.execute(
                    """
                    update onjoin set 
                    first_name = ?,
                    last_name = ?,
                    sex = ?,
                    'active'= ?
                    where user_id = ?""", (
                        data['first_name'],
                        data['last_name'],
                        sex,
                        True,
                        user_id))
            self.sql_connect.commit()
        self.print_fastlog('Новый Бог!')
        return

    @df_sql_update
    def sql_del_onjoin(self, user_id=None, event=None):
        if event:
            user_id = int(event.obj.user_id)
        elif not user_id:
            self.print_fastlog('Нет user_id!')
            return
        if type(user_id) != int:
            user_id = int(user_id)

        with self.sql_lock:
            self.cursor.execute("""UPDATE onjoin SET active = 0 WHERE user_id = {0}""".format(user_id))
            self.sql_connect.commit()
        self.print_fastlog('Бог ушел(')
        return
コード例 #5
0
class sorbot_core:
    def __init__(self, token, utoken=''):
        self._app_id = "2685278"
        self._vk_client_secret = "hHbJug59sKJie78wjrH8"
        if len(utoken):
            self.uvk_session = vk_api.VkApi(
                token=utoken,
                app_id=self._app_id,
                client_secret=self._vk_client_secret)
            # self.uvk_session_a.auth()
            self.uupload = vk_api.VkUpload(self.uvk_session)
            # self.audio = audio.VkAudio(self.uvk_session_a)
            self.uacc = True
        else:
            self.uacc = False
        self.vk_session = vk_api.VkApi(token=token)
        self.vk = self.vk_session.get_api()
        self.upload = vk_api.VkUpload(self.vk_session)
        '''self.vk = self.vk_session.get_api()
        self.longpoll = VkLongPoll(self.vk_session)
        self.tools = vk_api.VkTools(self.vk_session)'''
        self.longpoll = VkBotLongPoll(self.vk_session, group_id=200577613)

    def send_message(self,
                     text,
                     chat_id=-1,
                     user_id=0,
                     forward_messages=-1,
                     attachment=[],
                     delay=5):
        #time.sleep(random.random() * delay)
        if chat_id != -1:
            if forward_messages != -1:
                self.vk.messages.send(chat_id=chat_id,
                                      message=text,
                                      random_id=get_random_id(),
                                      forward_messages=forward_messages)
            else:
                self.vk.messages.send(chat_id=chat_id,
                                      message=text,
                                      random_id=get_random_id())
        else:
            if forward_messages != -1:
                self.vk.messages.send(user_id=user_id,
                                      message=text,
                                      random_id=get_random_id(),
                                      forward_messages=forward_messages)
            else:
                self.vk.messages.send(user_id=user_id,
                                      message=text,
                                      random_id=get_random_id())

    def remove_user(self, chat_id, user_id):
        self.vk_session.method('messages.removeChatUser', {
            'chat_id': chat_id,
            'user_id': user_id
        })

    def getevents(self):
        while True:
            try:
                return self.longpoll.check()
            except Exception as e:
                print('error', e)
コード例 #6
0
ファイル: HarleyBot.py プロジェクト: Mik-chan/HarleyBot
class HarleyBot:
    def __init__(self, api_token, group_id, creator_id=0):
        self.data = {}

        self.creator_id = int(creator_id)

        self.vk_session = vk_api.VkApi(token=api_token)
        self.vk_api = self.vk_session.get_api()
        self.long_poll = VkBotLongPoll(self.vk_session, group_id)

        self.rights_handler = RightsHandler(self)

        self.handlers = build_handler_list(self, [
            self.rights_handler,
        ])

        self.__stop = False
        self.__lock = threading.Lock()

        self.arts_pool = ArtsPool(self)

    @staticmethod
    def __filter_event(event):
        if 'action' in event.obj.message:
            return True
        if event.obj.message['text'].lower().startswith('харли. '):
            return True
        if event.obj.message['text'].lower().startswith('харли, '):
            return True
        if event.obj.message['text'].lower().startswith('harli. '):
            return True
        if event.obj.message['text'].lower().startswith('harli, '):
            return True

        return False

    def __start_console(self):
        print('Entered console mode')
        stop = False

        while not stop:
            cmd = input('> ')
            args = cmd.split()

            if cmd == 'quit' or cmd == 'stop':
                with self.__lock:
                    self.__stop = True

                print('Stoping...')

            elif cmd == 'data':
                print(self.data)

            elif len(args) == 2 and args[0] == 'promote':
                self.get_data_list(['admins']).append(int(args[1]))

            elif len(args) == 2 and args[0] == 'save':
                self.save(str(args[1]))

            with self.__lock:
                stop = self.__stop

    def start(self):
        self.__stop = False
        console = threading.Thread(target=self.__start_console, daemon=True)
        console.start()

        stop = False
        while not stop:
            try:
                for event in self.long_poll.check():
                    if not self.__filter_event(event):
                        continue
                    if event.type != VkBotEventType.MESSAGE_NEW:
                        continue

                    _event = self.__cleanup_event(event)
                    is_admin = self.is_admin(
                        _event['peer_id'],
                        _event['from_id']
                    )
                    _event['is_admin'] = is_admin

                    handlers = [
                            h for h in self.handlers
                            if (
                                is_admin or
                                self.rights_handler.has_rights(
                                    h,
                                    _event['from_id'],
                                    _event['peer_id']
                                )
                            ) and
                            h.trigger(_event)
                    ]

                    for handler in handlers:
                        handler.handle(_event)

            except Exception as e:
                print(e)
                traceback.print_exc()

            with self.__lock:
                stop = self.__stop

        console.join()

    def get_data_table(self, path):
        res = self.data

        for node in path:
            if not (str(node) in res):
                res[str(node)] = {}
            res = res[str(node)]

        return res

    def get_data_list(self, path):
        if len(path) < 1:
            return []

        res = self.get_data_table(path[:-1])
        if not (str(path[-1]) in res):
            res[str(path[-1])] = []

        return res[str(path[-1])]

    @staticmethod
    def __cleanup_event(event):
        res = {
            'date': event.obj.message['date'],
            'from_id': event.obj.message['from_id'],
            'id': event.obj.message['id'],
            'out': event.obj.message['out'],
            'peer_id': event.obj.message['peer_id'],
            'message': event.obj.message['text'],
            'conversation_message_id':
                event.obj.message['conversation_message_id'],
            'fwd_messages': event.obj.message['fwd_messages'],
            'important': event.obj.message['important'],
            'random_id': event.obj.message['random_id'],
            'attachments': event.obj.message['attachments'],
            'is_hidden': event.obj.message['is_hidden'],
        }

        if 'action' in event.obj.message:
            res['action'] = event.obj.message['action']
            res['args'] = []
        else:
            res['action'] = None
            res['message'] = ' '.join(res['message'].split()[1:])
            res['args'] = res['message'].split()

        return res

    def send_msg(self, peer_id, message=None,
                 attachment=None, disable_mentions=None):
        self.vk_api.messages.send(
            peer_id=int(peer_id),
            message=message,
            attachment=attachment,
            random_id=random.randint(-2135425010, 2135425010),
            disable_mentions=disable_mentions
        )

    def user_id(self, screen_name):
        if screen_name.startswith('https://vk.com/'):
            user = screen_name[15:]
        elif screen_name.startswith('[id'):
            user = screen_name.split('|')[0][1:]
        elif screen_name.startswith('id'):
            user = str(screen_name)
        else:
            user = '******' + screen_name

        resolved = self.vk_api.utils.resolveScreenName(
            screen_name=user
        )

        return resolved['object_id']

    __uinfo = {}
    __USER_FIELDS = 'sex,first_name,last_name'

    def user_info(self, user_id):
        user_id = str(user_id)
        if not (user_id in self.__uinfo):
            self.__uinfo[user_id] = self.vk_api.users.get(
                user_ids=user_id,
                fields=self.__USER_FIELDS
            )[0]
        return self.__uinfo[user_id]

    def members(self, peer_id):
        res = self.vk_api.messages.getConversationMembers(
            peer_id=peer_id,
            fields=self.__USER_FIELDS
        )

        for user in res['profiles']:
            if not (user['id'] in self.__uinfo):
                self.__uinfo[user['id']] = user

        return [item for item in res['items'] if item['member_id'] > 0]

    def is_admin(self, peer_id, user_id):
        admins = [
            item['member_id'] for item in self.members(peer_id)
            if 'is_admin' in item and item['is_admin']
        ]

        admins.extend(self.get_data_list(['peers', str(peer_id), 'admins']))
        admins.extend(self.get_data_list(['admins']))
        admins.append(self.creator_id)

        return user_id in admins

    def save(self, filename):
        with open(filename, 'w', encoding='utf-8') as fout:
            json.dump(self.data, fout, indent=4, ensure_ascii=False)

    def load(self, filename):
        try:
            with open(filename, 'r', encoding='utf-8') as fin:
                self.data = json.load(fin)
        except IOError:
            pass

    def kick(self, chat_id, user_id):
        try:
            self.vk_api.messages.removeChatUser(
                chat_id=chat_id, member_id=user_id
            )
        except Exception as e:
            print(e)
コード例 #7
0
class VkBot(IBot):
    def __init__(self, token: str, group_id: int):
        super().__init__()
        self._api = VkApi(token=token)
        self._longpoll = VkBotLongPoll(self._api, group_id=group_id)
        self._longpoll.wait = 0
        self._current_user: Union[int, None] = None

    def change_user(self, user_id: int):
        self._current_user = user_id
        self.on_new_user.notify(user_id)

    def send_message(self, message: Message):
        if self._current_user is None:
            return
        self._api.method('messages.send',
                         values={
                             'peer_id': self._current_user,
                             'message': message.text,
                             'random_id': int(getrandbits(32))
                         })

    def set_keyboard(self, keyboard: Keyboard, message: str = 'keyboard'):
        vk_keyboard = VkKeyboard(True)
        current_line = 1
        for pos, button in keyboard.all():
            row, column = pos
            if row + 1 < current_line:
                current_line += 1
                vk_keyboard.add_line()
            vk_keyboard.add_button(button.text, VK_BUTTON_COLOR[button.color])
        self._api.method('messages.send',
                         values={
                             'peer_id': self._current_user,
                             'random_id': int(getrandbits(32)),
                             'keyboard': vk_keyboard.get_keyboard(),
                             'message': message
                         })

    def get_current_user(self):
        return self._current_user

    def handle_server_event(self):
        last_notification_id = int(cfg.get('SETTINGS', 'LAST_ID'))
        data = requests.get(
            cfg.get('API', 'API_ADDRESS') +
            f'/notifications/{last_notification_id}').json()
        last_notification_id = data['meta']['last_id']
        cfg.set('SETTINGS', 'LAST_ID', str(last_notification_id))
        cfg.write(open('settings.cfg', 'w'))
        for student, notifications in data['students'].items():
            self.change_user(int(student))
            for student_data in notifications:
                current_contest = None
                for contest, contest_data in data['contests'].items():
                    if contest == str(student_data['contest']):
                        current_contest = contest_data
                        current_contest['id'] = contest
                        break
                current_stage = None
                for stage, stage_data in data['stages'].items():
                    if stage == str(student_data['stage']):
                        current_stage = stage_data
                        current_stage['id'] = stage
                        break
                self.on_event.notify({
                    'contest': current_contest,
                    'stage': current_stage,
                    'student': student
                })

    def run(self) -> NoReturn:
        print('Бот начал работу!')
        schedule.every(5).seconds.do(self.handle_server_event)
        while True:
            try:
                for event in self._longpoll.check():
                    if event.type == VkBotEventType.MESSAGE_NEW and event.from_user:
                        self.change_user(event.message.from_id)
                        self.on_new_message.notify(
                            Message(event.message.get('text', '')))
                schedule.run_pending()
            except requests.ConnectionError:
                print(f'{datetime.now()}: Не удается подключиться к серверу!')
コード例 #8
0
ファイル: bot.py プロジェクト: Rollylni/vkbot
class VkBot:
    """ Main class
    :param config: Configuration file path
    :type config: str
    
    :param logger: Logging config file path
    :type logger: str
    """
    MESSAGES = {}
    RUNNING = True
    admins = []
    prefix = None
    events = {}
    config = None
    logger = None
    lang = "rus"
    time = 0
    vk = None
    lp = None

    def __init__(self, config, logger):
        self.__load_configs(config, logger)
        self.logger = logging.getLogger(self.get_settings("logger", "vkbot"))
        self.vk = VkApi(token=self.get_settings("access_token"),
                        api_version=self.get_settings("version", 5.120))
        self.admins = self.get_settings("admins", "").split(",")
        self.prefix = self.get_settings("prefix", None)
        self.lp = VkBotLongPoll(self.vk, self.get_settings("group_id"),
                                int(self.get_settings("lp_wait", 5)))
        self.register(VkBotEventType.MESSAGE_NEW, self.cmd_event)
        self.cmd = CommandManager(self)
        self.tasks = TaskManager(self)
        th = threading.Thread(target=self.__exit)
        th.daemon = True
        th.start()

        self.logger.info(
            self.get_messages("start", id=self.get_settings("group_id")))
        self.time = utime()

    def task(self, time, repeating=0):
        """ Add task with decorator
        
        :param time: complete time
        :param repeating: repeating count
        """
        def tsk(func):
            tsk = Task(time, repeating)
            tsk.target = func
            tsk.name = func.__name__
            self.tasks.add_task(tsk)
            return func

        return tsk

    def command(self, name, **kwargs):
        """ Register command with decorator
        
        :param kwargs: Command constructor args
        """
        def cmd(func):
            cmd = Command(name=name, **kwargs)
            cmd.target = func
            self.cmd.register(cmd)
            return func

        return cmd

    def event(self, event):
        """ Register event with decorator
        
        :param event: Event type
        :type event: str
        """
        def register(func):
            self.register(event, func)
            return func

        return register

    def cmd_event(self, obj):
        user = self.get_object(obj.from_id)
        chat = self.get_chat(obj.peer_id)
        if self.prefix:
            if obj.text[:1] == self.prefix[:1]:
                self.cmd.exec(user, chat, obj, obj.text[1:])
        else:
            self.cmd.exec(user, chat, obj, obj.text)

    def get_id(self, id):
        """
        :param id: Id|domain|link
        :returns: available id
        """
        if not isinstance(id, str):
            return id

        try:
            for r in ("@", "*", "[", "]", "id", "club", "https://vk.com/"):
                id = id.replace(r, "")
            id = id.split("|")
            id = id[0]
            if not id.isnumeric():
                type = self.method("messages.getConversationsById",
                                   peer_ids=id)["items"][0]["peer"]["type"]
                if type == "group":
                    id = -self.method("groups.getById", group_ids=id)[0]["id"]
                elif type == "user":
                    id = self.method("users.get", user_ids=id)[0]["id"]
        except:
            pass
        return id

    def get_object(self, id):
        """
        :param id: id|domain|link
        :returns: User|Sender|Chat|Group
        """
        id = self.get_id(id)
        type = self.method("messages.getConversationsById", peer_ids=id)
        type = type["items"][0]["peer"]["type"]
        if type == "chat":
            return self.get_chat(id)
        elif type == "user":
            return self.get_user(id)
        elif type == "group":
            return self.get_group(id)
        return Sender(self, id)

    def get_group(self, id):
        return Group(self, self.get_id(id))

    def get_chat(self, id):
        return Chat(self, id)

    def get_user(self, id):
        return User(self, self.get_id(id))

    def method(self, method, **kwargs):
        """ Call the api method
        
        :param method: str
        :param kwargs: method params
        """
        try:
            response = self.vk.method(method, kwargs)
        except ApiError as e:
            self.logger.error(
                self.get_messages("method_error", method=method, message=e))
            seld.log_exception()
            response = []
        return response

    def register(self, event, consumer):
        """ Register event
        
        :param event: str
        :param consumer: func
        """
        if event not in self.events:
            self.events[event] = []
        self.events[event].append(consumer)

    def __handle(self, event, obj):
        if event not in self.events:
            return

        for e in self.events[event]:
            if callable(e):
                try:
                    e(obj)
                except:
                    self.logger.error(
                        self.get_messages("event_error", event=event))
                    self.log_exception()

    def start(self):
        while self.RUNNING:
            try:
                for event in self.lp.check():
                    thread = threading.Thread(target=self.__handle,
                                              args=(event.type, event.obj))
                    thread.daemon = True
                    thread.start()
            except:
                self.log_exception()
        else:
            self.logger.info(self.get_messages("stop_listen"))
            self.logger.info(self.get_messages("stop", ut=self.uptime()))

    def log_exception(self):
        self.logger.debug(format_exc())

    def get_messages(self, key, **args):
        """
        :param key: Messages key
        :type key: str
        
        :param args: kwargs
        :returns: str
        """
        if not self.config:
            return key
        else:
            try:
                msg = self.config.get("messages", key)
            except:
                msg = self.MESSAGES[self.lang].get(key)
            if msg:
                return msg.format(**args)
            else:
                return key

    def get_settings(self, key, default=None):
        """
        :param key: Settings key
        :type key: str
        
        :param default: if the key is not found in the config, it will return the default value
        :type default: mixed
        
        :returns: mixed
        """
        if not self.config:
            return default
        else:
            try:
                res = self.config.get("settings", key)
                return res
            except:
                return default

    def uptime(self):
        time = utime() - self.time
        fmt = self.get_messages("time_format").split(",")

        months = round(time / 2592000 % 999)
        weeks = round(time / 604800 % 4)
        days = round(time / 86400 % 7)
        hours = round(time / 3600 % 24)
        minutes = round(round(time / 60) % 60)

        if months > 0:
            return "{}{} {}{}".format(months, fmt[0], weeks, fmt[1])

        format = ""

        if days > 0:
            format += "{}{} ".format(days, fmt[2])
        if hours > 0:
            format += "{}{} ".format(hours, fmt[3])
        if minutes > 0:
            format += "{}{} ".format(minutes, fmt[4])
        format += "{}{}".format(round(time % 60), fmt[5])
        return format

    def __exit(self):
        input()
        self.stop()

    def stop(self):
        self.RUNNING = False

    def __load_configs(self, config, logger):
        logging.config.fileConfig(logger)
        self.config = ConfigParser()
        self.config.sections()
        self.config.read(config)

        self.MESSAGES["rus"] = {
            "start": "Бот запущен. ID:{id}",
            "stop": "Бот остановлен. Время работы: {ut}",
            "time_format": "мес.,нед.,дн.,чс.,мн.,сек.",
            "stop_listen": "Остановка прослушивания..",
            "event_error": "Не удалось обработать событие '{event}'",
            "method_error":
            "ApiError: не удалось вызвать метод '{method}' - {message}",
            "task_error": "Не удалось выполнить задачу '{task}'",
            "no_permission": "У вас недостаточно прав!",
            "command_not_found": "Комада {cmd} не найдена",
            "command_error": "При выполнении команды {cmd} произошла ошибка.",
            "group_not_use":
            "Эту команду могут использовать только пользователи!"
        }
        self.MESSAGES["eng"] = {
            "start": "Bot started. ID:{id}",
            "stop": "Bot stopped. Uptime: {ut}",
            "time_format": "mh.,w.,d.,h.,m.,s.",
            "stop_listen": "Stop listening..",
            "event_error": "Failed to execute method '{event}'",
            "method_error":
            "ApiError: Failed to call method '{method}' - {message}",
            "task_error": "failed to complete the task '{task}'",
            "no_permission": "You do not have sufficient permissions!",
            "command_not_found": "Command {cmd} not found",
            "command_error":
            "An error occurred while executing the {cmd} command.",
            "group_not_use": "This command can only be used by users!"
        }

        if not self.get_settings("access_token"):
            raise Exception("specify the access token in the config file!")
        if not self.get_settings("group_id"):
            raise Exception("specify the group id in the config file!")