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()
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
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()
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()
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()
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()
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()
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()
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()