def start_state(bot, update, context):
    chat = update.effective_chat
    chat_id = chat.id
    user = user_service.create_or_get_user(chat)

    if is_callback(update):
        deserialized = deserialize_data(update.callback_query.data)
        action = deserialized[CallbackData.ACTION]

        if action is Action.SELECTED_LANG:
            lang = deserialized[CallbackData.DATA]
            context[CONTEXT_LANG] = Language(lang)

    lang = context[CONTEXT_LANG]
    welcome_text = concat_username(
        emoji_rocket + '*', user,
        ', ' + message_source[lang]['state.start_state.welcome'])

    num_all, num_upcoming, num_completed = task_service.find_stats_for_user(
        chat_id)
    bot_ver = 19  # because why not? :)
    completed_percent = 0 if 0 == num_all else int(num_completed / num_all *
                                                   100)
    num_completed = f'{num_completed} ({completed_percent} %)'
    num_upcoming = f'{num_upcoming} ({0 if 0 == num_all else (100 - completed_percent)} %)'
    welcome_text = welcome_text.format(num_upcoming, num_completed, num_all,
                                       bot_ver)

    bot.send_message(chat_id=chat_id,
                     text=emojize(welcome_text, use_aliases=True),
                     parse_mode=ParseMode.MARKDOWN,
                     reply_markup=kb.StartStateKb(lang).build())
def select_lang_state(bot, update, context):
    chat = update.effective_chat
    chat_id = chat.id

    user = user_service.create_or_get_user(chat)

    action = None
    if is_callback(update):
        deserialized = deserialize_data(update.callback_query.data)
        action = deserialized[CallbackData.ACTION]

    # find out what are we doing now? selecting lang or just showing available langs
    text = None
    if action is Action.SELECTED_LANG:
        deserialized = deserialize_data(update.callback_query.data)
        lang_string = deserialized[CallbackData.DATA]
        lang = Language(lang_string)
        context[CONTEXT_LANG] = lang

        text = message_source[lang]['btn.select_lang.' + lang_string +
                                    '.result']
        buttons = kb.StartStateKb(lang).build()

    elif action is Action.VIEW_LANG:
        # It's callback. nevertheless just show available langs
        lang = context[CONTEXT_LANG]
        text = concat_username(
            emoji_globe + '*', user,
            ', ' + message_source[lang]['state.select_lang'])
        buttons = kb.SelectLangKb(lang).build()

    else:
        # It's not callback. just show available langs
        lang = context[CONTEXT_LANG]
        text = concat_username(
            emoji_globe + '*', user,
            ', ' + message_source[lang]['state.select_lang'])
        buttons = kb.SelectLangKb(lang).build()

    bot.send_message(chat_id=chat_id,
                     text=emojize(text, use_aliases=True),
                     parse_mode=ParseMode.MARKDOWN,
                     reply_markup=buttons)
def all_tasks_state(bot, update, context):
    chat = update.effective_chat
    chat_id = chat.id
    lang = context[CONTEXT_LANG]
    user = user_service.create_or_get_user(chat)
    user_id = chat_id

    action = None
    if is_callback(update):
        deserialized = deserialize_data(update.callback_query.data)
        action = deserialized[CallbackData.ACTION]

    tasks = []
    text = None
    if not is_callback(update) or action is Action.LIST_ALL:
        tasks = task_service.find_tasks_by_user_id(user_id)
        text = concat_username(
            emoji_all + '*', user,
            ', ' + message_source[lang]['state.all_tasks.tasks.all'])

    elif action is Action.LIST_UPCOMING:
        tasks = task_service.find_upcoming_tasks_by_user_id(user_id)
        text = concat_username(
            emoji_upcoming + '*', user,
            ', ' + message_source[lang]['state.all_tasks.tasks.upcoming'])

    elif action is Action.LIST_COMPLETED:
        tasks = task_service.find_completed_tasks_by_user_id(user_id)
        text = concat_username(
            emoji_completed + '*', user,
            ', ' + message_source[lang]['state.all_tasks.tasks.completed'])

    if 0 == len(tasks):
        text_no_tasks = message_source[lang]['state.all_tasks.no_tasks_yet']
        notes = message_source[lang]['state.all_tasks.notes.no_tasks_yet']
        text = concat_username(emoji_search + '*', user,
                               ', ' + text_no_tasks + notes)

    else:
        text += message_source[lang]['state.all_tasks.notes']

    tasks = sorted(tasks, key=lambda t: t.get_create_date())
    bot.send_message(chat_id=chat_id,
                     text=emojize(text, use_aliases=True),
                     parse_mode=ParseMode.MARKDOWN,
                     reply_markup=kb.TasksAsButtons(tasks, lang).build())
def view_task_state(bot, update, context):
    chat = update.effective_chat
    chat_id = chat.id
    lang = context[CONTEXT_LANG]

    task_id = None
    action = None
    if is_callback(update):
        deserialized = deserialize_data(update.callback_query.data)
        task_id = deserialized[CallbackData.DATA]
        action = deserialized[CallbackData.ACTION]

        if action is Action.TASK_PROJECT_SELECTED:
            task = context[CONTEXT_TASK]
            # if bot was restarted then it has not tasks in context. then get latest task
            if task is None:
                task = task_service.find_latest_task_by_user_id(chat_id)

            task_id = task.get_id()

    else:
        args = update.message.text.split()
        task_id = args[1]

    user = user_service.create_or_get_user(chat)
    task = task_service.find_task_by_id_and_user_id(task_id, user.get_id())

    # if task was removed do not show anything
    if task and task.is_flag_active():
        reply_text, reply_markup = view_task_template_and_markup(
            lang, task, State.VIEW_TASK)

        if action is Action.TASK_MARK_AS_DONE:
            reply_markup = None
            if task.is_task_completed():
                task.mark_as_not_completed()
                reply_text = message_source[lang][
                    'btn.view_task.mark_undone.result']

            else:
                task.mark_as_completed()
                reply_text = message_source[lang][
                    'btn.view_task.mark_as_done.result']

            text_on_edit, markup_on_edit = view_task_template_and_markup(
                lang, task, State.VIEW_TASK)
            bot.edit_message_text(
                chat_id=chat_id,
                message_id=update.effective_message.message_id,
                text=emojize(text_on_edit, use_aliases=True),
                parse_mode=ParseMode.MARKDOWN,
                reply_markup=markup_on_edit)

        elif action is Action.TASK_DISABLE:
            reply_markup = None
            if task.is_task_enabled():
                task.mark_as_disabled()
                reply_text = message_source[lang][
                    'btn.view_task.disable_notify.result'].format(
                        task.get_description())

            else:
                task.mark_as_enabled()
                reply_text = message_source[lang][
                    'btn.view_task.enable_notify.result'].format(
                        task.get_description())

            text_on_edit, markup_on_edit = view_task_template_and_markup(
                lang, task, State.VIEW_TASK)
            bot.edit_message_text(
                chat_id=chat_id,
                message_id=update.effective_message.message_id,
                text=emojize(text_on_edit, use_aliases=True),
                parse_mode=ParseMode.MARKDOWN,
                reply_markup=markup_on_edit)

        elif action is Action.TASK_DELETE:
            task.mark_as_inactive()
            reply_text = message_source[lang][
                'btn.view_task.delete_task.result'].format(task.get_id())
            reply_markup = None

            bot.delete_message(
                chat_id=chat_id,
                message_id=update.callback_query.message.message_id)

        elif action is Action.TASK_VIEW:
            # It's not callback, then just render the state
            reply_text, reply_markup = view_task_template_and_markup(
                lang, task, State.VIEW_TASK)

        # set project id by editing current TASK_VIEW
        elif action is Action.TASK_PROJECT_SELECTED:
            deserialized = deserialize_data(update.callback_query.data)
            project_value = deserialized[CallbackData.DATA]

            project_selected = project_service.create_or_get_project(
                user.get_id(), project_value)
            task.set_project_id(project_selected.get_id())
            task_service.update_task(task)

            context[CONTEXT_TASK] = task

            text_on_edit, markup_on_edit = view_task_template_and_markup(
                lang, task, State.VIEW_TASK)
            bot.edit_message_text(
                chat_id=chat_id,
                message_id=update.callback_query.message.message_id,
                text=emojize(text_on_edit, use_aliases=True),
                parse_mode=ParseMode.MARKDOWN,
                reply_markup=markup_on_edit)
            return

        # update task
        task_service.update_task(task)

        # set updated task to context
        context[CONTEXT_TASK] = task

        bot.send_message(chat_id=chat_id,
                         text=emojize(reply_text, use_aliases=True),
                         parse_mode=ParseMode.MARKDOWN,
                         reply_markup=reply_markup)

    else:
        task_inactive = message_source[lang]['state.view_task.inactive']
        bot.send_message(chat_id=chat_id,
                         text=emojize(task_inactive, use_aliases=True))
Example #5
0
def handle(bot, update):
    chat = update.effective_chat
    chat_id = chat.id
    curr_context = None
    try:
        curr_command = None
        curr_action = None
        if is_callback(update):
            # Callback handling
            log.info(f'--> Callback from {chat.username} ({chat.id})')

            data = update.callback_query.data
            deserialized = deserialize_data(update.callback_query.data)

            curr_command = deserialized[CallbackData.COMMAND]
            curr_action = deserialized[CallbackData.ACTION]

        else:
            # Regular message/command handling
            log.info(f'--> Message from {chat.username} ({chat.id})')
            text = update.message.text

            if command_filter.known_command(text) is False:
                # check if user is admin
                if chat_id in ADMINS:
                    if '/stats' == text:
                        bot.send_message(chat_id=chat_id,
                                         text=json.dumps(ERR_COUNTER,
                                                         indent=2))
                        return

                    elif text.startswith('/notify_all'):
                        cmd = text.split(' ')
                        text_to_send = ' '.join(cmd[1:])
                        welcome_back(bot, text_to_send)
                        return

                else:
                    if text.startswith('/suggest'):
                        cmd = text.split(' ')
                        text_to_send = ' '.join(cmd[1:])
                        log.warning(
                            f'-->--> Suggest from {chat.username} ({chat_id}): {text}'
                        )
                        bot.send_message(chat_id=ADMINS[0], text=text_to_send)
                        bot.send_message(chat_id=chat_id,
                                         text='Thanks for feedback :)')
                        return

                reply_on_unknown(bot, chat_id)
                return

            curr_command = get_command_type(text)

        # get all params needed to render state
        curr_state = g.automata.get_state(chat_id)
        curr_context = g.automata.get_context(chat_id)
        log.info(f'curr_state: {curr_state}, curr_command: {curr_command}')

        # find out state to be rendered
        next_state = g.automata.get_transition(curr_state, curr_command)
        if g.dev_mode:
            bot.send_message(
                chat_id=chat_id,
                text=f'prev state: {curr_state.name} ({curr_state.value})\n'
                f'cmd: {curr_command.name} ({curr_command.value})\n'
                f'new state: {next_state.name} ({next_state.value})')

        # get state from service and render
        handler = state_service.states()[next_state]
        log.info(f'rendering state: {handler.__name__}')
        handler(bot, update, curr_context)

        # update params
        log.info(f'Updating state to: {next_state.name}')
        g.automata.set_state(chat.id, next_state)
        curr_context[CONTEXT_COMMANDS].append(curr_command)
        curr_context[CONTEXT_ACTION].append(curr_action)

        if g.dev_mode:
            print_dev_info(bot, chat_id, curr_context)

    except Exception as e:
        try:
            ERR_COUNTER[str(len(ERR_COUNTER.values()) + 1)] = {
                'datetime': str(datetime.datetime.now()),
                'chat': chat_id,
                'error': str(e),
                'context': str(curr_context)
            }
        except Exception:
            pass
        log.error('Error has been caught in handler: ', e)
        lang = curr_context[
            CONTEXT_LANG] if curr_context is not None else Language.ENG.value
        text = message_source[lang]['error']
        bot.send_message(chat_id=chat_id,
                         text=emojize(text, use_aliases=True),
                         parse_mode=ParseMode.MARKDOWN)

    else:
        log.info('<-- Successfully handled')