def start(self, bot, update, user_data):
        if not update.message.chat.type == 'private':
            update.message.reply_text(
                'This command can only be used in a private conversation')
            return ConversationHandler.END

        user_data['stack'] = []
        user_data['acc'] = None
        user_data['user_msg'] = False
        user = update.message.from_user
        message = update.message
        Logger.log_debug("User %s started config conversation." %
                         user.first_name)

        chats = list(Cache.get_admin_chats(message.from_user.id))
        chat_names = [(chat_id, Cache.get_chat_title(chat_id))
                      for chat_id in chats]

        global_button = [[
            InlineKeyboardButton(text='Global config',
                                 callback_data=HandlerGroup.GLOBAL)
        ]] if str(self.bot.admin_chat) in chats else []
        buttons = [[InlineKeyboardButton(text=name, callback_data=str(id))]
                   for (id, name) in chat_names]
        buttons.append(
            [InlineKeyboardButton(text='Exit', callback_data=str(self.EXIT))])
        reply_markup = InlineKeyboardMarkup(global_button + buttons)

        message.reply_text('Select a chat to configure',
                           reply_markup=reply_markup)
        return self.SELECT_CHAT
    def remove_end(self, bot, update, user_data):
        if update.callback_query.data[1] == '3':
            self.send_or_edit(bot, user_data, update.callback_query.message,
                              'Maybe next time')
            return ConversationHandler.END
        try:
            idx = int(update.callback_query.data[3:])
            chat_id = user_data['chat_id']

            if update.callback_query.data[1] == '0':
                handler_group = self.bot.message_handlers
            elif update.callback_query.data[1] == '1':
                handler_group = self.bot.tick_handlers
            else:
                handler_group = self.bot.button_handlers

            name, _ = handler_group.list(chat_id)[idx]
            handler_group.remove(chat_id, name)

            Logger.log_info('Removed \'%s\'' % name)
            self.send_or_edit(bot, user_data, update.callback_query.message,
                              'Removed \'%s\'' % name)
            return ConversationHandler.END
        except:
            traceback.print_exc()
Example #3
0
    def update_cache(self):
        Logger.log_debug('Updating cache')

        self.message_handlers.update()
        self.button_handlers.update()
        self.tick_handlers.update()

        Cache.store_cache()
        Config.store_config(self)
Example #4
0
 def propagate(self, bot, message, target, exclude):
     res = []
     do_copy = len(self.children) > 1
     for child in self.children:
         res2 = child.call(bot, copy.copy(message) if do_copy else message, target, copy.copy(exclude) if do_copy else exclude)
         if res2 is None:
             Logger.log_error(msg='Handler %s returned None instead of [..]' % type(child).__name__, chat=message.chat.id)
         else:
             res.extend(res2)
     return res
Example #5
0
 def set_config_location(cls, loc):
     Logger.log_trace('Config location set to \'%s\'' % loc)
     if not os.path.exists(loc):
         os.makedirs(loc)
     if os.path.isfile(loc):
         Logger.log_error(
             'The specified config location must be a folder, \'%s\' is a file'
             % loc)
         raise Exception()
     cls.config_location = os.path.join(loc, 'bot_config.json')
Example #6
0
 def on_receive_message(self, bot, message):
     """
     Global message handler.
     Forwards the messages to the other handlers if applicable.
     Always calls the handler that checks if the bot was added to a group.
     """
     try:
         for handler in self._global_handlers:
             self.message_handlers._call_handler(handler, bot, message)
         self.message_handlers.call(bot, message)
     except:
         Logger.log_error('Exception while handling message')
         traceback.print_exc()
        def applicator(*args, **kwargs):
            try:
                return function(*args, **kwargs)
            except Exception as ex:
                has_chat_info = (len(args) > 2 and isinstance(args[2], Update)
                                 and args[2].effective_chat)
                chat_id = args[2].effective_chat.id if has_chat_info else None

                Logger.log_exception(
                    ex,
                    'Exception while handling conversation in \'%s\'' %
                    function.__name__,
                    chat=chat_id)
                traceback.print_exc()
                return ConversationHandler.END
Example #8
0
 def on_receive_tick(self, bot, job):
     try:
         time = datetime.now()
         text = time.strftime('%Y-%m-%d %H:%M:%S')
         messages = [
             Message(-1,
                     None,
                     time,
                     Chat(chat_id, 'tick_group %s' % chat_id),
                     text=text) for chat_id in Cache.list_chat_ids()
         ]
         self.tick_handlers.call(bot, messages)
     except:
         Logger.log_error('Exception while handling tick')
         traceback.print_exc()
Example #9
0
    def store_config(cls, bot):
        Logger.log_debug('Serializing config')
        message_handlers, global_message_handlers = bot.message_handlers.to_dict(
        )
        button_handlers, global_button_handlers = bot.button_handlers.to_dict()
        tick_handlers, global_tick_handlers = bot.tick_handlers.to_dict()

        config = {
            'handlers': message_handlers,
            'handlers_global': global_message_handlers,
            'tick_handlers': tick_handlers,
            'tick_handlers_global': global_tick_handlers,
            'button_handlers': button_handlers,
            'button_handlers_global': global_button_handlers
        }
        with open(cls.config_location, 'w') as config_file:
            Logger.log_debug('Writing config to disk')
            json.dump(config, config_file)
Example #10
0
    def on_receive_callback(self, bot, update):
        try:
            query = update.callback_query
            if query.message.reply_to_message:
                reply_to = query.message.reply_to_message
                text = '%s_%s' % (query.data,
                                  query.message.reply_to_message.text)
            else:
                reply_to = None
                text = query.data

            message = Message(-1,
                              query.from_user,
                              query.message.date,
                              query.message.chat,
                              text=text,
                              reply_to_message=reply_to)
            self.button_handlers.call(bot, message)
        except:
            Logger.log_error('Exception while handling button event')
            traceback.print_exc()
Example #11
0
    def load_config(cls, bot):
        if os.path.exists(cls.config_location):
            with open(cls.config_location, 'r') as config_file:
                Logger.log_debug('Loading config')
                content = config_file.read()
                try:
                    config = json.loads(content)
                except json.JSONDecodeError:
                    config = {}
                    Logger.log_error('Malformed config file')

                message_handlers = config[
                    'handlers'] if 'handlers' in config else {}
                global_message_handlers = config[
                    'handlers_global'] if 'handlers_global' in config else {}
                button_handlers = config[
                    'button_handlers'] if 'button_handlers' in config else {}
                global_button_handlers  = config['button_handlers_global'] if 'button_handlers_global' in config else {}
                tick_handlers = config[
                    'tick_handlers'] if 'tick_handlers' in config else {}
                global_tick_handlers    = config['tick_handlers_global']   if 'tick_handlers_global'   in config else {}

                bot.message_handlers.from_dict(message_handlers,
                                               global_message_handlers)
                bot.button_handlers.from_dict(button_handlers,
                                              global_button_handlers)
                bot.tick_handlers.from_dict(tick_handlers,
                                            global_tick_handlers)

        else:
            Logger.log_error(
                'Config file does not exist (This error can be ignored on the initial run)'
            )
        bot.init_global_handlers()
Example #12
0
    def start(self):
        """
        Start the bot.
        """
        self.updater.start_polling()

        # Set up the tick trigger
        self.dispatcher.job_queue.run_repeating(
            self.on_receive_tick,
            timedelta(minutes=1),
            first=timedelta(seconds=60 - datetime.now().second))
        self.dispatcher.job_queue.run_repeating(
            lambda b, j, self=self: self.update_cache(),
            timedelta(days=1),
            first=timedelta(hours=24 - datetime.now().hour))

        Logger.log_info('%s started' % self.bot.first_name)

        Cache.store_cache()
        Config.store_config(self)

        self.updater.idle()
Example #13
0
    def _handle_stack(self, bot, msg, user_data):
        stack = user_data['stack']
        if not stack:
            handler = user_data['acc']
            chat_id = user_data['chat_id']
            name = user_data['name']
            type = user_data['type']
            if type == 'tick':
                self.bot.tick_handlers.register(chat=chat_id,
                                                handler=handler,
                                                name=name)
                Logger.log_info('Added tick handler \'%s\'' % name)
            elif type == 'msg':
                self.bot.message_handlers.register(chat=chat_id,
                                                   name=name,
                                                   handler=handler)
                Logger.log_info('Added message handler \'%s\'' % name)
            elif type == 'button':
                self.bot.button_handlers.register(chat=chat_id,
                                                  name=name,
                                                  handler=handler)
                Logger.log_info('Added button handler \'%s\'' % name)
            else:
                message = 'Unknown handler type %s' % type
                Logger.log_error(message)
                self.send_or_edit(bot, user_data, msg, message)
                return ConversationHandler.END
            self.send_or_edit(bot, user_data, msg, 'Hander added!')
            return ConversationHandler.END

        (stage, data, idx) = stack[-1]
        try:
            current = self.HANDLERS[idx]
            (stage, data, res) = current.create(stage, data, user_data['acc'])
            stack[-1] = (stage, data, idx)
            user_data['acc'] = None

            if isinstance(res, Send):
                self.send_or_edit(bot, user_data, msg, res.msg, res.buttons)
                return self.ADD_HANDLER_STEP

            elif isinstance(res, Done):
                user_data['acc'] = res.handler
                user_data['stack'] = user_data['stack'][:-1]
                return self._handle_stack(bot, msg, user_data)

            elif isinstance(res, AskChild):
                name = current.get_name()
                message = 'Do you want to add a child handler for \'%s\'' % name
                buttons = [[
                    InlineKeyboardButton(text='yes', callback_data='-2'),
                    InlineKeyboardButton(text='no', callback_data='-1')
                ]]

                if msg.text != message:
                    self.send_or_edit(bot, user_data, msg, message, buttons)
                else:
                    print('Not sending duplicate message')
                return self.ADD_HANDLER_CHILD

            elif isinstance(res, AskCacheKey):
                user_data['acc'] = res.default
                buttons = [[
                    InlineKeyboardButton(text='Create own key',
                                         callback_data=str(self.ADD))
                ],
                           [
                               InlineKeyboardButton(text='Use existing key',
                                                    callback_data=str(
                                                        self.COPY))
                           ]]

                self.send_or_edit(bot, user_data, msg,
                                  'Select a cache key, or create a new one',
                                  buttons)
                return self.ADD_HANDLER_CACHE_KEY

            elif isinstance(res, AskAPIKey):
                stack = user_data['stack']
                stack.append((0, None, stack[-1][2]))
                buttons = [[
                    InlineKeyboardButton(text='Create own API key',
                                         callback_data=str(self.ADD))
                ],
                           [
                               InlineKeyboardButton(
                                   text='Use existing API key',
                                   callback_data=str(self.COPY))
                           ]]

                self.send_or_edit(bot, user_data, msg,
                                  'Select an API key, or create a new one',
                                  buttons)
                return self.ADD_HANDLER_API_KEY
            else:
                raise Exception('Unknown response: %s' % res)
        except CreateException as ex:
            traceback.print_exc()
            self.send_or_edit(
                bot, user_data, msg,
                'Implementation missing! Please report your steps to the developer'
            )
            return ConversationHandler.END
        except Exception as ex:
            traceback.print_exc()
            self.send_or_edit(
                bot, user_data, msg,
                'Error while processing handler create event! Please report your steps to the developer'
            )
            return ConversationHandler.END
Example #14
0
 def call(self, bot, message, target, exclude):
     Logger.log_info('Added %s as bot admin' % message.from_user.first_name)
     Cache.add_chat_admin(message.chat.id, message.from_user.id)
     return []
Example #15
0
 def init_logger(self):
     config = {}
     if self.admin_chat:
         config[str(self.admin_chat)] = 2
     Logger.init(self.bot, config)
Example #16
0
 def on_exit(self):
     Logger.log_info(msg='Shutting down')
     Cache.store_cache()
     Config.store_config(self)