Exemple #1
0
        def wrapper(update, context):
            session = get_session()
            try:
                user = get_user(session, update)
                if not is_allowed(user, update):
                    return

                func(context.bot, update, session, user)

                session.commit()
            # Handle all not telegram relatated exceptions
            except Exception as e:
                if not ignore_exception(e):
                    if config['logging']['debug']:
                        traceback.print_exc()
                    sentry.captureException()

                if hasattr(update, 'callback_query'
                           ) and update.callback_query is not None:
                    locale = 'English'
                    if user is not None:
                        locale = user.locale
                    update.callback_query.answer(
                        i18n.t('callback.error', locale=locale))
            finally:
                session.close()
Exemple #2
0
def get_priority_buttons(poll, user):
    """Create the keyboard for priority poll. Only show the deeplink, if not in a direct conversation."""
    if user is None:
        bot_name = config["telegram"]["bot_name"]
        payload = get_start_button_payload(poll, StartAction.vote)
        url = f"http://t.me/{bot_name}?start={payload}"
        buttons = [[
            InlineKeyboardButton(i18n.t("keyboard.vote", locale=poll.locale),
                                 url=url)
        ]]

        return buttons

    buttons = []
    options = get_sorted_options(poll)
    vote_button_type = CallbackType.vote.value
    vote_increase = CallbackResult.increase_priority.value
    vote_decrease = CallbackResult.decrease_priority.value
    session = get_session()
    votes = (session.query(Vote).filter(Vote.poll == poll).filter(
        Vote.user == user).order_by(Vote.priority.asc()).options(
            joinedload(Vote.option)).all())

    indices = get_option_indices(options)
    for index, vote in enumerate(votes):
        option = vote.option
        if not poll.compact_buttons:
            name_row = [
                InlineKeyboardButton(f"{option.name}",
                                     callback_data=IGNORE_PAYLOAD)
            ]
            buttons.append(name_row)
        name_hint_payload = (
            f"{CallbackType.show_option_name.value}:{poll.id}:{option.id}")
        increase_payload = f"{vote_button_type}:{option.id}:{vote_increase}"
        decrease_payload = f"{vote_button_type}:{option.id}:{vote_decrease}"
        ignore_payload = f"{CallbackType.ignore.value}:0:0"

        vote_row = []
        if poll.compact_buttons:
            vote_row.append(
                InlineKeyboardButton(f"{indices[index]})",
                                     callback_data=name_hint_payload))

        if index != len(votes) - 1:
            vote_row.append(
                InlineKeyboardButton("▼", callback_data=decrease_payload))
        else:
            vote_row.append(
                InlineKeyboardButton(" ", callback_data=ignore_payload))

        if index != 0:
            vote_row.append(
                InlineKeyboardButton("▲", callback_data=increase_payload))
        else:
            vote_row.append(
                InlineKeyboardButton(" ", callback_data=ignore_payload))

        buttons.append(vote_row)
    return buttons
Exemple #3
0
        def wrapper(update, context):
            session = get_session()
            try:
                user = get_user(session, update)
                if not is_allowed(user, update):
                    return

                func(context.bot, update, session, user)

                session.commit()
            # Raise all telegram errors and let the generic error_callback handle it


#            except TelegramError as e:
#                raise e
# Handle all not telegram relatated exceptions
            except:
                traceback.print_exc()
                sentry.captureException()
                if hasattr(update, 'callback_query'
                           ) and update.callback_query is not None:
                    locale = 'English'
                    if user is not None:
                        locale = user.locale
                    update.callback_query.answer(
                        i18n.t('callback.error', locale=locale))
            finally:
                session.close()
Exemple #4
0
        def wrapper(context):
            session = get_session()
            try:
                func(context, session)

                session.commit()
            except:  # noqa
                # Capture all exceptions from jobs. We need to handle those inside the jobs
                traceback.print_exc()
                sentry.captureException()
            finally:
                session.close()
Exemple #5
0
    def wrapper(update, context):
        user = None
        if context.user_data.get("ban"):
            return

        temp_ban_time = context.user_data.get("temporary-ban-time")
        if temp_ban_time is not None and temp_ban_time == date.today():
            update.callback_query.answer(i18n.t("callback.spam"))
            return

        session = get_session()
        try:
            user, statistic = get_user(session,
                                       update.callback_query.from_user)
            # Cache ban value, so we don't have to lookup the value in our database
            if user.banned:
                context.user_data["ban"] = True
                return

            # Cache temporary-ban time, so we don't have to create a connection to our database
            if statistic.votes > config["telegram"]["max_user_votes_per_day"]:
                update.callback_query.answer(
                    i18n.t("callback.spam", locale=user.locale))
                context.user_data["temporary-ban-time"] = date.today()
                return

            func(context.bot, update, session, user)

            session.commit()

        except RollbackException as e:
            session.rollback()

            update.callback_query.answer(e.message)

        except Exception as e:
            if not ignore_exception(e):
                if config["logging"]["debug"]:
                    traceback.print_exc()

                with configure_scope() as scope:
                    scope.set_tag("handler", "callback_query")
                    sentry.capture_exception()

                locale = "English"
                if user is not None:
                    locale = user.locale
                update.callback_query.answer(
                    i18n.t("callback.error", locale=locale))

        finally:
            session.close()
    def wrapper(context):
        session = get_session()
        try:
            func(context, session)

            session.commit()
        except Exception as e:
            # Capture all exceptions from jobs. We need to handle those inside the jobs
            if not ignore_job_exception(e):
                if config["logging"]["debug"]:
                    traceback.print_exc()
                sentry.captureException()
        finally:
            session.close()
Exemple #7
0
        def wrapper(update, context):
            session = get_session()
            try:
                user = get_user(session, update)
                if not is_allowed(user, update, private=private):
                    return

                if hasattr(update, 'message') and update.message:
                    message = update.message
                elif hasattr(update,
                             'edited_message') and update.edited_message:
                    message = update.edited_message

                if not is_allowed(user, update, private=private):
                    return

                response = func(context.bot, update, session, user)

                session.commit()
                # Respond to user
                if hasattr(update, 'message') and response is not None:
                    message.chat.send_message(response)

            # A user banned the bot
            except Unauthorized:
                pass

            # Raise all telegram errors and let the generic error_callback handle it


#            except TelegramError as e:
#                raise e

# Handle all not telegram relatated exceptions
            except:
                traceback.print_exc()
                sentry.captureException()
                if send_message:
                    locale = 'english'
                    if user is not None:
                        locale = user.locale
                    session.close()
                    message.chat.send_message(
                        i18n.t('misc.error', locale=locale),
                        parse_mode='markdown',
                        disable_web_page_preview=True,
                    )

            finally:
                session.close()
        def wrapper(update, context):
            user = None
            session = get_session()
            try:
                if hasattr(update, "message") and update.message:
                    message = update.message
                elif hasattr(update,
                             "edited_message") and update.edited_message:
                    message = update.edited_message
                else:
                    raise Exception("Got an update without a message")

                user, _ = get_user(session, message.from_user)
                if user.banned:
                    return

                if private and message.chat.type != "private":
                    message.chat.send_message(
                        "Please do this in a direct conversation with me.")
                    return

                response = func(context.bot, update, session, user)

                session.commit()

                # Respond to user
                if response is not None:
                    message.chat.send_message(response)

            except Exception as e:
                if not ignore_exception(e):
                    if config["logging"]["debug"]:
                        traceback.print_exc()
                    sentry.captureException()

                    locale = "English"
                    if user is not None:
                        locale = user.locale

                    message.chat.send_message(
                        i18n.t("misc.error", locale=locale),
                        parse_mode="markdown",
                        disable_web_page_preview=True,
                    )

                session.close()

            finally:
                session.close()
    def wrapper(update, context):
        session = get_session()
        try:
            user, _ = get_user(session, update.chosen_inline_result.from_user)
            if user.banned:
                return

            func(context.bot, update, session, user)

            session.commit()
        except Exception as e:
            if not ignore_exception(e):
                if config["logging"]["debug"]:
                    traceback.print_exc()
                    sentry.captureException()

        finally:
            session.close()
    def wrapper(update, context):
        session = get_session()
        try:
            user, statistic = get_user(session, update.inline_query.from_user)
            if user.banned:
                return

            func(context.bot, update, session, user)

            session.commit()
        except Exception as e:
            if not ignore_exception(e):
                if config["logging"]["debug"]:
                    traceback.print_exc()

                sentry.capture_exception(tags={"handler": "inline_query"})

        finally:
            session.close()
Exemple #11
0
        def wrapper(update, context):
            session = get_session()
            try:
                user = get_user(session, update)
                if not is_allowed(user, update, private=private):
                    return

                if hasattr(update, 'message') and update.message:
                    message = update.message
                elif hasattr(update,
                             'edited_message') and update.edited_message:
                    message = update.edited_message

                if not is_allowed(user, update, private=private):
                    return

                response = func(context.bot, update, session, user)

                session.commit()
                # Respond to user
                if hasattr(update, 'message') and response is not None:
                    message.chat.send_message(response)

            # Handle all not telegram relatated exceptions
            except Exception as e:
                if not ignore_exception(e):
                    if config['logging']['debug']:
                        traceback.print_exc()
                    sentry.captureException()

                if send_message:
                    locale = 'English'
                    if user is not None:
                        locale = user.locale
                    session.close()
                    message.chat.send_message(
                        i18n.t('misc.error', locale=locale),
                        parse_mode='markdown',
                        disable_web_page_preview=True,
                    )

            finally:
                session.close()
Exemple #12
0
def session(connection, monkeypatch):
    """Return an sqlalchemy session, and after the test tear down everything properly."""
    # Begin the nested transaction
    transaction = connection.begin()
    # Use the connection with the already started transaction
    session = Session(bind=connection)

    def get_session():
        return session

    from pollbot import db

    monkeypatch.setattr(db, "get_session", get_session)
    assert session == db.get_session()

    yield session

    # Since we are not committing things to the database directly when
    # testing, initially deferred constraints are not checked. The
    # following statement makes the DB check these constraints. We are
    # executing this command AFTER the tests and NOT BEFORE, because
    # within a transaction the DB is allowed to take temporarily
    # invalid state. Read
    # https://www.postgresql.org/docs/current/static/sql-set-constraints.html
    # for details.
    try:
        connection.execute("SET CONSTRAINTS ALL IMMEDIATE")
    except InternalError:
        # This is the case when we are doing something in the tests
        # that we expect it to fail by executing the statement above.
        # In this case, the transaction will be in an already failed
        # state, executing further SQL statements are ignored and doing
        # so raises an exception.
        pass

    session.close()
    # Roll back the broader transaction
    transaction.rollback()
    # Put back the connection to the connection pool
    connection.close()
#!/usr/bin/env python
"""Small helper script for debugging stuff."""

from pollbot.db import get_session
from pollbot.helper.plot import get_user_activity


session = get_session()
image = get_user_activity(session)
        def wrapper(update: Update, context: CallbackContext):
            # The user has been banned and already got a message regarding this issue
            if context.user_data.get("banned-message-sent"):
                return

            user = None
            session = get_session()
            try:
                if hasattr(update, "message") and update.message:
                    message = update.message
                elif hasattr(update, "edited_message") and update.edited_message:
                    message = update.edited_message

                user, _ = get_user(session, message.from_user)

                # Send a message explaining the user, why they cannot use the bot.
                # Also set a flag, which prevents sending this messages multiple times and thereby prevents DOS attacks.
                if user.banned:
                    if not context.user_data.get("banned-message-sent"):
                        context.user_data["banned-message-sent"] = True

                    message.chat.send_message(
                        "You have been permanently banned from using this bot, either due to spamming or inappropriate behavior."
                        "Please refrain from asking questions in the support group or on Github. There's nothing we can do about this."
                    )
                    return

                # Show an error message, if the users uses the bot in a public chat,
                # when he shouldn't. Also check if we're even allowed to send a message.
                if private and message.chat.type != "private":
                    chat = context.bot.getChat(message.chat.id)
                    if chat.permissions.can_send_messages:
                        message.chat.send_message(
                            "Please do this in a direct conversation with me."
                        )
                    return

                response = func(context.bot, update, session, user)

                session.commit()

                # Respond to user
                if response is not None:
                    message.chat.send_message(response)

            except RollbackException as e:
                session.rollback()

                message.chat.send_message(
                    e.message, parse_mode="markdown", disable_web_page_preview=True,
                )

            except Exception as e:
                if not ignore_exception(e):
                    if config["logging"]["debug"]:
                        traceback.print_exc()

                    sentry.capture_exception(
                        tags={"handler": "message",},
                        extra={"update": update.to_dict(), "function": func.__name__},
                    )

                    locale = "English"
                    if user is not None:
                        locale = user.locale

                    message.chat.send_message(
                        i18n.t("misc.error", locale=locale),
                        parse_mode="markdown",
                        disable_web_page_preview=True,
                    )

            finally:
                # The session might not be there yet
                # We're checking for bans inside this try/catch, which has to
                # happen before session initialization due to performance reasons
                if "session" in locals():
                    session.close()
    def wrapper(update, context):
        user = None
        if context.user_data.get("ban"):
            return

        try:
            # Check if the user is temporarily banned and send a message.
            # The check is done via the local telegram cache. This way we can prevent
            # opening a new DB connection for each spam request. (lots of performance)
            temp_ban_time = context.user_data.get("temporary-ban-time")
            if temp_ban_time is not None and temp_ban_time == date.today():
                update.callback_query.answer(i18n.t("callback.spam"))
                return

            session = get_session()

            user, statistic = get_user(session, update.callback_query.from_user)
            # Cache ban value, so we don't have to lookup the value in our database on each request
            if user.banned:
                context.user_data["ban"] = True
                return

            # Cache temporary-ban time, so we don't have to create a connection to our database
            if statistic.votes > config["telegram"]["max_user_votes_per_day"]:
                update.callback_query.answer(
                    i18n.t("callback.spam", locale=user.locale)
                )
                context.user_data["temporary-ban-time"] = date.today()
                return

            func(context.bot, update, session, user)

            session.commit()

        except RollbackException as e:
            session.rollback()

            update.callback_query.answer(e.message)

        except Exception as e:
            if not ignore_exception(e):
                if config["logging"]["debug"]:
                    traceback.print_exc()

                sentry.capture_exception(
                    tags={"handler": "callback_query",},
                    extra={"query": update.callback_query,},
                )

                locale = "English"
                if user is not None:
                    locale = user.locale
                try:
                    update.callback_query.answer(
                        i18n.t("callback.error", locale=locale)
                    )
                except BadRequest as e:
                    # Check if this is a simple query timeout exception
                    if not ignore_exception(e):
                        raise e

        finally:
            # The session might not be there yet
            # We're checking for bans inside this try/catch, which has to
            # happen before session initialization due to performance reasons
            if "session" in locals():
                session.close()
Exemple #16
0
        def wrapper(update: Update, context: CallbackContext):
            user = None
            session = get_session()
            try:
                if hasattr(update, "message") and update.message:
                    message = update.message
                elif hasattr(update,
                             "edited_message") and update.edited_message:
                    message = update.edited_message
                else:
                    with configure_scope() as scope:
                        scope.set_extra("calling_function", func.__name__)
                        scope.set_extra("update", update.to_dict())
                        sentry.capture_message(
                            "Got an update without a message")
                    return

                user, _ = get_user(session, message.from_user)
                if user.banned:
                    return

                if private and message.chat.type != "private":
                    message.chat.send_message(
                        "Please do this in a direct conversation with me.")
                    return

                response = func(context.bot, update, session, user)

                session.commit()

                # Respond to user
                if response is not None:
                    message.chat.send_message(response)

            except RollbackException as e:
                session.rollback()

                message.chat.send_message(
                    e.message,
                    parse_mode="markdown",
                    disable_web_page_preview=True,
                )

            except Exception as e:
                if not ignore_exception(e):
                    if config["logging"]["debug"]:
                        traceback.print_exc()

                    with configure_scope() as scope:
                        scope.set_tag("handler", "message")
                        sentry.capture_exception()

                    locale = "English"
                    if user is not None:
                        locale = user.locale

                    message.chat.send_message(
                        i18n.t("misc.error", locale=locale),
                        parse_mode="markdown",
                        disable_web_page_preview=True,
                    )

            finally:
                session.close()