def confirm_email(user: User, update: Update, context: CallbackContext): available_inputs = [ user.language.get(Token.YES), user.language.get(Token.NO), user.language.get(Token.CANCEL) ] message = update.message.text if message not in available_inputs: reply_to(user, update, user.language.get(Token.ENTER_VALID_COMMAND), reply_markup=Keyboard.email_verify_keyboard(user.language)) return if message == user.language.get(Token.YES): email = context.user_data["email"] user.email = email update_user(user) _clear_context(context) reply_html(user, update, user.language.get(Token.EMAIL_SET) % email, Keyboard.main(user)) mwelog.info(f"{user.username} confirms {email} is correct") try: context.bot.send_message( mwexpress_config.moderator, f"{user.username} set their email as: {email}") except Exception as ex: mwelog.exception(ex) else: _clear_context(context) reply_to(user, update, user.language.get(Token.EMAIL_CANCELLED), Keyboard.main(user))
def ask_for_email(user: User, update: Update, context: CallbackContext): mwelog.info(f"Asked for email from {user.username}") context.user_data["sub_state"] = "typing_email" reply_html(user, update, user.language.get(Token.ADD_EMAIL_START), reply_markup=Keyboard.remove())
def unmute_everyone(): mwelog.info("Unmuting everyone") all_users = get_all_users() for user in all_users: user.muted = False session = database.get_session() database.commit(session)
def change_user_language(user: User, language: Language) -> None: session = database.get_session() user.language = language database.commit(session) mwelog.info("User {user_name} changed language to: {language}", user_name=user.username, user_id=user.id, language=str(user.language))
def language_change_handler(user: User, update: Update, context: CallbackContext) -> None: mwelog.info( "User {user_name} is changing language, current language: {language}", user_name=user.username, user_id=user.id, language=str(user.language)) set_state(context, State.CHANGING_LANGUAGE) reply_to(user, update, user.language.get(Token.SELECT_LANGUAGE), Keyboard.language_selection(user.language))
def clear_scores_for_today(): mwelog.info("Clearing scores for today") all_users = get_all_users() for user in all_users: user.score_today_en = 0 user.score_today_tr = 0 user.score_today_it = 0 session = database.get_session() database.commit(session) scoreboard.clear()
def __init__(self): self.engine = create_engine(mwexpress_config.db_connection_string, echo=False) self.Session = scoped_session(sessionmaker(bind=self.engine)) self.session = self.Session() self.commit_lock = threading.Lock() # noinspection PyUnresolvedReferences from models import User, Mwe, Submission, Review, FeedbackData, Achievement, Base # Base.metadata.drop_all(engine) Base.metadata.create_all(self.engine) mwelog.info("Database initialized.")
def reply_to(user: User, update: Update, message: str, reply_markup: Optional[ReplyMarkup] = None) -> None: """ Sends a reply back to user. :param user: User to reply to :param update: This object is used to send reply :param message: The message to reply with :param reply_markup: The keyboard markup to set with the reply """ mwelog.info("Bot replied to {user_name} with: {message}", user_name=user.username, user_id=user.id, message=message) update.message.reply_text(text=message, parse_mode=ParseMode.MARKDOWN, reply_markup=reply_markup)
def claim_email_announcement(update: Update, context: CallbackContext): mwelog.info("Sending claim email announcement to champions") user = get_user_from_update(update) if user.id == mwexpress_config.moderator or user.id == 1065263859: for user in get_all_users(): if user.became_champion: try: mwelog.info( f"Sending claim email message to {user.username}") context.bot.send_sticker(user.id, EXCITED_STICKER) context.bot.send_message( user.id, user.language.get(Token.CHAMP_BUT_NO_EMAIL)) time.sleep(0.5) except Exception as ex: mwelog.exception(str(ex))
def send_game_started_again_with_awards(update: Update, context: CallbackContext): mwelog.info("Sending game started again message to all users") user = get_user_from_update(update) if user.id == mwexpress_config.moderator or user.id == 1065263859: for user in get_all_users(): try: mwelog.info( f"Sending game started again message to {user.username}") context.bot.send_sticker(user.id, EXCITED_STICKER) send_message_to_user( context.bot, user, user.language.get(Token.GAME_STARTED_AGAIN_ANNOUNCEMENT)) time.sleep(0.5) except Exception as ex: mwelog.exception(str(ex))
def check_email_and_ask_confirmation(user: User, update: Update, context: CallbackContext): email_regex = r'(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)' email = update.message.text mwelog.info(f"Email got from {user.username}: {email}") if not re.match(email_regex, email): reply_to(user, update, user.language.get(Token.INVALID_EMAIL), reply_markup=Keyboard.remove()) else: context.user_data["sub_state"] = "confirming_email" context.user_data["email"] = email reply_html(user, update, user.language.get(Token.CONFIRM_EMAIL) % email, reply_markup=Keyboard.email_verify_keyboard(user.language))
def load_initial_data(): with open("idioms.json", encoding="utf-8") as initial_idioms_file: initial_idioms = loads(initial_idioms_file.read()) for i in range(len(initial_idioms)): initial_idioms[i]['day'] = datetime.fromisoformat( initial_idioms[i]['day']).date() if initial_idioms[i]['category'] == 'VID': initial_idioms[i]['category'] = MweCategory.VID elif initial_idioms[i]['category'] == 'VPC': initial_idioms[i]['category'] = MweCategory.VPC else: raise ValueError( f'Category cannot be {initial_idioms[i]["category"]}') for initial_mwe in initial_idioms: mwe = get_date_mwe(mwexpress_config.language, initial_mwe['day']) if mwe is None: add_mwe(initial_mwe['name'], initial_mwe['meaning'], mwexpress_config.language, initial_mwe['day'], initial_mwe['lemmas'], initial_mwe['category']) mwelog.info(f'Added mwe: {initial_mwe["name"]}')
def send_game_starting_message_to_all() -> None: mwelog.info("Sending game started message to all users") unmute_everyone() all_users = get_all_users() for user in all_users: try: mwexpress_bot.bot.send_sticker(user.id, GOOD_MORNING_STICKER) send_message_to_user(mwexpress_bot.bot, user, user.language.get(Token.GAME_STARTED)) todays_mwe = get_todays_mwe(user.language) send_message_to_user( mwexpress_bot.bot, user, user.language.get(Token.TODAYS_MWE_REPLY_TEXT) % (todays_mwe.name, todays_mwe.meaning), reply_markup=Keyboard.main(user), parse_mode=ParseMode.HTML) time.sleep(0.3) except Exception as ex: mwelog.exception(str(ex)) mwelog.info("Sent game started message to all users")
def _send_notification(self, context: CallbackContext, user_id: int, message: str, not_type: NotificationType, sticker: Optional[str] = None, parse_mode: Optional[str] = None): if not self._history_contains_notification(user_id, not_type): try: mwelog.info("Sending {not_type} to {user_id}", not_type=str(not_type), user_id=user_id) notification = SentNotification(user_id, not_type, datetime.now()) self._notification_history[user_id].append(notification) if sticker is not None: context.bot.send_sticker(user_id, sticker) context.bot.send_message(user_id, message, parse_mode=parse_mode) except Exception as ex: mwelog.exception(str(ex))
def award_champion(): mwelog.info("Awarding champion") boards = scoreboard.scoreboards for language in Language.ENGLISH, Language.TURKISH, Language.ITALIAN: if len(boards[language]) > 0: first_user = get_user(boards[language][0].user_id) mwelog.info("{username} is the champion", username=first_user.username) award_achievement(first_user, AchievementType.CHAMPION) try: mwexpress_bot.bot.send_sticker(first_user.id, ACHIEVEMENT_STICKER) send_message_to_user(mwexpress_bot.bot, first_user, first_user.language.get( Token.CHAMPION_ACH_CONGRATS_MSG), parse_mode=ParseMode.HTML) if mwexpress_config.email_enabled: if first_user.email is None: send_message_to_user( mwexpress_bot.bot, first_user, first_user.language.get( Token.TODAYS_WINNER_WITHOUT_EMAIL), parse_mode=ParseMode.HTML) else: send_message_to_user( mwexpress_bot.bot, first_user, first_user.language.get( Token.TODAYS_WINNER_WITH_EMAIL) % first_user.email, parse_mode=ParseMode.HTML) mwexpress_bot.bot.send_message( mwexpress_config.moderator, f"Todays champion is: {first_user.username}") except Exception as ex: mwelog.exception(ex)
def start(update: Update, context: CallbackContext): user = get_user_from_update(update) mwelog.info("User {user_name} started using Mwexpress", user_name=user.username, user_id=user.id) clear_state(context) context.bot.send_sticker(update.effective_chat.id, TIPS_FEDORA_STICKER) reply_to(user, update, user.language.get(Token.WELCOME_MESSAGE_1), Keyboard.remove()) time.sleep(2) reply_to(user, update, user.language.get(Token.WELCOME_MESSAGE_2), Keyboard.remove()) time.sleep(5) reply_to(user, update, user.language.get(Token.WELCOME_MESSAGE_3), Keyboard.remove()) time.sleep(3) reply_to(user, update, user.language.get(Token.WELCOME_MESSAGE_4), Keyboard.remove()) time.sleep(2) reply_to(user, update, user.language.get(Token.WELCOME_MESSAGE_5), Keyboard.remove()) time.sleep(5) reply_to(user, update, user.language.get(Token.WELCOME_MESSAGE_6), Keyboard.remove()) time.sleep(10) update.message.reply_text(text=user.language.get(Token.WELCOME_MESSAGE_7), parse_mode=ParseMode.HTML, reply_markup=Keyboard.remove()) time.sleep(5) context.bot.send_photo(user.id, open("assets/keyboard_button.png", "rb")) time.sleep(0.5) reply_to(user, update, user.language.get(Token.WELCOME_MESSAGE_8)) time.sleep(5) reply_to(user, update, user.language.get(Token.DISCLAIMER), Keyboard.main(user))
def language_update_handler(user: User, update: Update, context: CallbackContext) -> None: if update.message.text == user.language.get(Token.LANGUAGE_ENGLISH): change_user_language(user, Language.ENGLISH) clear_state(context) reply_to(user, update, user.language.get(Token.LANGUAGE_CHANGE_SUCCESSFUL), Keyboard.main(user)) elif update.message.text == user.language.get(Token.LANGUAGE_TURKISH): change_user_language(user, Language.TURKISH) clear_state(context) reply_to(user, update, user.language.get(Token.LANGUAGE_CHANGE_SUCCESSFUL), Keyboard.main(user)) else: mwelog.info( "User {user_name} entered wrong value ({message}) for language change.", user_name=user.username, user_id=user.id, message=update.message.text) reply_to(user, update, user.language.get(Token.PLEASE_SELECT_VALID_LANGUAGE), Keyboard.language_selection(user.language))
def message(update: Update, context: CallbackContext): user = get_user_from_update(update) try: mwelog.info("New message from {user_name}: {message}", user_name=user.username, message=update.message.text) if user.banned: update.message.reply_text( user.language.get(Token.USER_IS_BANNED_MESSAGE)) return if update.message.text.startswith("/flag"): flag_submission(user, int(update.message.text.replace("/flag", "")), context) return if update.message.text.startswith("/ban"): ban_user(user, int(update.message.text.replace("/ban", "")), context) return if mwexpress_config.game_stopped: update.message.reply_sticker(COFFEE_STICKER) update.message.reply_text( user.language.get(Token.GAME_TEMPORARILY_STOPPED)) update.message.reply_text(user.language.get(Token.SURVEY_MESSAGE)) return if get_state(context) != State.NONE: state = get_state(context) mwelog.info("Current state for {user_name}: {state}", user_name=user.username, state=str(state)) if state == State.SUBMISSION: main_submit_handler(user, update, context) elif state == State.CHANGING_LANGUAGE: language_update_handler(user, update, context) elif state == State.REVIEWING: main_review_handler(user, update, context) elif state == State.ADDING_EMAIL: main_email_handler(user, update, context) else: if update.message.text == user.language.get(Token.TODAYS_MWE): todays_mwe_handler(user, update) elif update.message.text == user.language.get(Token.SUBMIT): main_submit_handler(user, update, context) elif update.message.text == user.language.get( Token.CHANGE_LANGUAGE): language_change_handler(user, update, context) elif update.message.text == user.language.get(Token.HELP): help_handler(user, update, context) elif update.message.text == user.language.get(Token.REVIEW): main_review_handler(user, update, context) elif update.message.text == user.language.get(Token.FEEDBACK): feedback_handler(user, update, context) elif update.message.text == user.language.get( Token.SHOW_SCOREBOARD): scoreboard_handler(user, update, context) elif update.message.text == user.language.get(Token.ACHIEVEMENTS): achievements_handler(user, update, context) elif update.message.text == user.language.get(Token.ADD_EMAIL): main_email_handler(user, update, context) elif submission_contains_todays_mwe(user, update.message.text): context.user_data["sub_state"] = "typing_example" main_submit_handler(user, update, context) else: update.message.reply_text(user.language.get( Token.ENTER_VALID_COMMAND), parse_mode=ParseMode.MARKDOWN, reply_markup=Keyboard.main(user)) context.bot.send_photo( user.id, open("assets/keyboard_button.png", "rb")) update.message.reply_text(user.language.get( Token.WELCOME_MESSAGE_8), parse_mode=ParseMode.MARKDOWN, reply_markup=Keyboard.main(user)) except Exception as ex: clear_state(context) unmute_user(user.id) _safe_delete_context_data(context, "sub_state") _safe_delete_context_data(context, "parsed") _safe_delete_context_data(context, "submission") mwelog.error( f"erroneous message: {user.username}: {update.message.text}") mwelog.exception(str(ex)) update.message.reply_text(user.language.get(Token.ERROR_OCCURRED), reply_markup=Keyboard.main(user))
def listen(self): mwelog.info("Listening Telegram for connections...") self.updater.start_polling()
def stats(update: Update, context: CallbackContext): user = get_user_from_update(update) mwelog.info(f"Stats requested by {user.username}") today = datetime.now().date() if len(context.args) == 3: day = int(context.args[0]) month = int(context.args[1]) year = int(context.args[2]) today = datetime(year, month, day).date() update.message.reply_text(f'Stats for {today.strftime("%A, %B %d, %Y")}') session = database.get_session() all_users_count = session.query(User).filter( func.Date(User.created) <= today).count() new_users = session.query(User).filter( func.Date(User.created) == today).all() update.message.reply_text( f'{all_users_count} users (+{len(new_users)} new)') if len(new_users) > 0: update.message.reply_text( f'New users: {", ".join([x.username for x in new_users])}') all_submissions_count = session.query(Submission).filter( func.Date(Submission.created) <= today).count() new_submissions_count = session.query(Submission).filter( func.Date(Submission.created) == today).count() update.message.reply_text( f'{all_submissions_count} submissions (+{new_submissions_count} new)') all_reviews_count = session.query(Review).filter( func.Date(Review.created) <= today).count() new_reviews_count = session.query(Review).filter( func.Date(Review.created) == today).count() update.message.reply_text( f'{all_reviews_count} reviews (+{new_reviews_count} new)') all_subs = session.query(Submission).all() all_subs_today = session.query(Submission).filter( func.Date(Submission.created) == today).all() review_count_average = round( statistics.mean([x.review_count for x in all_subs]), 2) review_count_average_today = 0.0 if len(all_subs_today) > 0: review_count_average_today = round( statistics.mean([x.review_count for x in all_subs_today]), 2) update.message.reply_text( f'Review count average: {review_count_average}({review_count_average_today} today)' ) all_reviews_today = session.query(Review).filter( func.Date(Review.created) == today).all() all_submitted_users_today = set([x.user.id for x in all_subs_today]) all_reviewed_users_today = set([x.user.id for x in all_reviews_today]) update.message.reply_text( f'Users who only submitted: {len([x for x in all_submitted_users_today if x not in all_reviewed_users_today])}' ) update.message.reply_text( f'Users who only reviewed: {len([x for x in all_reviewed_users_today if x not in all_submitted_users_today])}' ) update.message.reply_text( f'Users who both submitted and reviewed: {len([x for x in all_submitted_users_today if x in all_reviewed_users_today])}' ) positive_together_count = session.query(Submission)\ .filter(Submission.category == SubmissionCategory.POSITIVE_TOGETHER)\ .filter(func.Date(Submission.created) == today)\ .count() positive_separated_count = session.query(Submission)\ .filter(Submission.category == SubmissionCategory.POSITIVE_SEPARATED)\ .filter(func.Date(Submission.created) == today)\ .count() negative_together_count = session.query(Submission)\ .filter(Submission.category == SubmissionCategory.NEGATIVE_TOGETHER)\ .filter(func.Date(Submission.created) == today)\ .count() negative_separated_count = session.query(Submission)\ .filter(Submission.category == SubmissionCategory.NEGATIVE_SEPARATED)\ .filter(func.Date(Submission.created) == today)\ .count() update.message.reply_text( f"Submission categories:\nPositive together: {positive_together_count}\n" f"Positive separated: {positive_separated_count}\n" f"Negative together: {negative_together_count}\n" f"Negative separated: {negative_separated_count}")
from bot.main import mwexpress_bot from log import mwelog from cron import schedule_jobs, run_scheduled_jobs from initial_data import load_initial_data load_initial_data() mwelog.info("Starting MWExpress...") mwexpress_bot.listen() schedule_jobs() run_scheduled_jobs()
def reply_html(user: User, update: Update, message: str, reply_markup: Optional[ReplyMarkup] = None) -> None: mwelog.info("Bot replied to {user_name} with: {message}", user_name=user.username, user_id=user.id, message=message) update.message.reply_text(text=message, parse_mode=ParseMode.HTML, reply_markup=reply_markup)
def clear_state(context: CallbackContext) -> None: set_state(context, State.NONE) mwelog.info("State cleared")
def set_state(context: CallbackContext, state: State) -> None: context.user_data["state"] = state mwelog.info("State set to: {state}", state=str(state))
def sticker(update: Update, context: CallbackContext): mwelog.info("Got sticker: {sticker_id}", sticker_id=update.message.sticker.file_id) context.bot.send_sticker(update.effective_chat.id, update.message.sticker.file_id)