Ejemplo n.º 1
0
def explore_compile(update, context, user):
    """
    Handler: fsm:2.2 -> 3
    """
    language = user.settings.language
    state = user.settings.fsm_state

    text = txt['FSM'][state]['text'][language] + '\n'
    keyboard = utility.gen_keyboard(txt['FSM'][state]['markup'][language],
                                    txt['FSM'][state]['payload'])

    remove_message(update, context, user)

    search_terms = update.message.text.strip().split(
        config['TELEGRAM']['delim'])
    sources = search_sources(user, search_terms)

    if len(sources) == 0:
        text += '\n' + txt['CALLBACK']['error_no_results'][language].format(
            html.escape(update.message.text))
    else:
        for source in sources:
            text += '\n' + source.title

    try:
        context.bot.edit_message_text(chat_id=update.message.from_user.id,
                                      message_id=user.settings.last_msg_id,
                                      text=text,
                                      reply_markup=keyboard,
                                      parse_mode='HTML',
                                      disable_web_page_preview=True)
    except BadRequest:
        pass
Ejemplo n.º 2
0
def modify_channels_callback(update, context, user):
    """ Handler 3.2 -> 3 | 3.2.1 """
    # TODO: this is the same as modify_rss_callback
    # except the future_state const in 'inline' definition
    query = update.callback_query
    future_state = query.data.split(config['CB_DATA']['delim'])[1]

    if future_state == '3':
        to_menu(update, context, user)
        return

    inline = [[item.title, f'fin:3.2.1:{i}']
              for i, item in enumerate(user.subscribed.channel_list)]
    inline.append([
        txt['FSM'][future_state]['markup'][user.settings.language][0],
        txt['FSM'][future_state]['payload'][0]
    ])
    label, data = zip(*inline)

    keyboard = utility.gen_keyboard(label=label, data=data, width=2)

    query.edit_message_text(
        text=txt['FSM'][future_state]['text'][user.settings.language],
        reply_markup=keyboard,
        parse_mode='HTML')

    user.settings.fsm_state = future_state
    user.save()
Ejemplo n.º 3
0
def modify_rss_callback(update, context, user):
    """ Handler 3.1 -> 3 | 3.1.1"""
    query = update.callback_query
    future_state = query.data.split(config['CB_DATA']['delim'])[1]

    if future_state == '3':
        to_menu(update, context, user)
        return

    # TODO: I beliebe telegram allows only a certain number of
    # items as buttons... Maybe having more should be a #premium feature
    inline = [[item.title, f'fin:3.1.1:{i}']
              for i, item in enumerate(user.subscribed.rss_list)]
    # adding the "Back" button. since only one button we use index 0
    inline.append([
        txt['FSM'][future_state]['markup'][user.settings.language][0],
        txt['FSM'][future_state]['payload'][0]
    ])
    label, data = zip(*inline)

    keyboard = utility.gen_keyboard(label=label, data=data, width=2)

    query.edit_message_text(
        text=txt['FSM'][future_state]['text'][user.settings.language],
        reply_markup=keyboard,
        parse_mode='HTML')

    user.settings.fsm_state = future_state
    user.save()
Ejemplo n.º 4
0
def manual_compile(update, context, user):
    """
    Detects whether the answer to the Manual Entry is a link, or username
    """
    edit_id = user.settings.last_msg_id
    state = user.settings.fsm_state

    # entities limited to the first one to avoid excessive blocking by a single
    # user, as feed fetches take a long time
    try:
        entity, msg = next(
            iter(
                update.message.parse_entities(
                    types=['mention', 'url']).items()))
    except StopIteration:  # error raised if the parse_entity returns nothing
        entity = msg = None

    text = (txt['FSM'][state]['text'][user.settings.language] + '\n')

    keyboard = utility.gen_keyboard(
        txt['FSM'][state]['markup'][user.settings.language],
        txt['FSM'][state]['payload'])

    # the feeds the user has already entered
    first = True

    for i, sub in enumerate(user.subscribed.session_list):
        if first:
            text += '\n'
            first = False
        text += f"{i+1}. {sub}\n"

    text += '\n'

    # if there are no entities, the loop below doesn't run, so no need to
    # exit the function early.
    if not all([text, entity]):
        text += txt['CALLBACK']['error'][user.settings.language]
    else:
        if entity.type == MessageEntity.URL:
            text += rss_compile(update, context, user, msg) + '\n'
        elif entity.type == MessageEntity.MENTION:
            text += channel_compile(update, context, user, msg) + '\n'

    # almost like it "absorbs" a message
    remove_message(update, context, user)

    try:
        context.bot.edit_message_text(chat_id=update.message.from_user.id,
                                      message_id=edit_id,
                                      text=text,
                                      reply_markup=keyboard,
                                      parse_mode='HTML',
                                      disable_web_page_preview=True)
    except BadRequest:
        # if the message contents are the same
        pass
Ejemplo n.º 5
0
def general_callback(update, context, user, format_data=None):
    """
    This function can be used for general callback operations. It includes
    features such as extracting the future FSM state, and setting it for the
    user.
    """
    query = update.callback_query  # shorter var name
    future_state = query.data.split(config['CB_DATA']['delim'])[1]

    # telegram requires the server to "answer" a callback query
    context.bot.answer_callback_query(query.id)

    # the "future" FSM state now becomes the "current" FSM state
    user.settings.fsm_state = future_state
    user.save()

    if format_data:
        new_content = (
            f"{txt['FSM'][future_state]['text'][user.settings.language]}".
            format(**format_data))
    else:
        new_content = (
            f"{txt['FSM'][future_state]['text'][user.settings.language]}")

    keyboard = utility.gen_keyboard(
        txt['FSM'][future_state]['markup'][user.settings.language],
        txt['FSM'][future_state]['payload'])

    # edit the message to display the selected language
    try:
        query.edit_message_text(text=new_content,
                                reply_markup=keyboard,
                                parse_mode='HTML')
    except BadRequest:
        pass

    # if we would like to do anything with the response (save the message id)
    return update
Ejemplo n.º 6
0
def cmd_done(update, context):
    """
    Handler: command /done
    This command is, and can only be, called when the user is finished with
    the set-up process.
    """
    # in this handler, we are changing user FSM states
    # therefore, we first have to check them.

    user = User.get_user(update.message.from_user.id)
    end_fsm_states = ['2.1']

    if user.settings.fsm_state not in end_fsm_states:
        context.bot.delete_message(user.user_id, update.message.message_id)
        return

    if user.settings.fsm_state == '2.1':
        user.settings.fsm_state = FSM.DONE.value
        user.save()

    new_content = (
        f"{txt['FSM'][FSM.DONE.value]['text'][user.settings.language]}"
        .format(**user.collect_main_data())
    )

    keyboard = utility.gen_keyboard(
        txt['FSM'][FSM.DONE.value]['markup'][user.settings.language],
        txt['FSM'][FSM.DONE.value]['payload']
    )

    context.bot.send_message(
        chat_id=update.message.from_user.id,
        text=new_content,
        reply_markup=keyboard,
        parse_mode='HTML'
    )
Ejemplo n.º 7
0
def cmd_start(update, context):
    uid = update.message.from_user.id
    payload = get_payload(update.message.text)
    user = create_new_user(update)

    # "absorb" message - cleaner this way
    remove_message(update, context, user)

    main_text = ''
    lang = user.settings.language

    if user.settings.fsm_state in {'0', '1'}:
        main_text += txt['SERVICE']['start'][lang]
        markup = utility.gen_keyboard(txt['LANG_NAMES'], txt['LANG_PAYLOAD'])

        user.settings.fsm_state = FSM.LANGUAGE.value
        user.save()

    else:
        # send the main menu
        # better than sending message associated with the current state, as
        # there are messages with customized keyboards, etc..
        main_text += txt['FSM']['3']['text'][lang].format(
            **user.collect_main_data()
        )
        markup = utility.gen_keyboard(
            txt['FSM']['3']['markup'][lang],
            txt['FSM']['3']['payload']
        )

        # ensure that if user is in another state the payload isn't processed
        # just a precaution...
        payload = None

    if user.settings.last_msg_id:
        try:
            context.bot.delete_message(
                chat_id=uid,
                message_id=user.settings.last_msg_id
            )
        except BadRequest:
            try:
                context.bot.edit_message_text(
                    chat_id=uid,
                    message_id=user.settings.last_msg_id,
                    text=txt['CALLBACK']['deleted'][lang],
                    parse_mode='HTML'
                )
            except BadRequest:
                # the message can be already deleted by the user
                pass

    if payload:
        try:
            inviter = User.get_user(uid=payload)
        except LookupError:
            return

        inviter.add_to_invited(uid)
        main_text = (
            txt['SERVICE']['invited_by'][lang].format(
                user=utility.escape(context.bot.get_chat(payload).first_name),
                id=inviter.user_id
            )
            + '\n\n'
            + main_text
        )

    sent_message = context.bot.send_message(
        chat_id=uid,
        text=main_text,
        reply_markup=markup,
        parse_mode='HTML'
    )

    # bot sends a new message, so the old last_msg_id must be replaced.
    user.settings.last_msg_id = sent_message.message_id
    user.save()