def daily_task_check(): try: config = get_config_document() n = datetime.now(tz=tz) if config.latest_daily_check: lc = mongo_time_to_local(config.latest_daily_check, tz) if (n - lc) > timedelta(hours=1): if 8 <= n.hour <= 21: logger.debug(f'Performing vacation check task at {n}') config.latest_daily_check = n config.save() daily_task() else: config.latest_daily_check = n config.save() config.reload() if config.latest_monthly_check: lc = mongo_time_to_local(config.latest_monthly_check, tz) if (n - lc) > timedelta(days=1): if n.day == 1: hr_logger.info(f'Performing monthly task at {n}') config.latest_monthly_check = n config.save() monthly_task() else: config.latest_monthly_check = n config.save() except KeyboardInterrupt: return except: logger.exception('Exception occurred while performing daily check')
def __get_or_register_user(self, chat_id, tg_user: TGUser): user = User.objects(user_id=chat_id).first() if user is None: user = User( user_id=chat_id, user_id_s=str(chat_id), username=tg_user.username, first_name=tg_user.first_name, last_name=tg_user.last_name, states=[self.__start_state], language='ww', ) user.save() hr_logger.info(f'Новий користувач бота: {user.str_repr()}') return user
def post_fork(server, worker): if forked == workers: from time import sleep from telebot import TeleBot from config import BOT_TOKEN from time import sleep from scheduler_controller import schedule_controller from logger_settings import hr_logger hr_logger.info('Сервіс запущено') bot = TeleBot(BOT_TOKEN, threaded=False) bot.remove_webhook() sleep(1) bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH, certificate=open(WEBHOOK_SSL_CERT, 'r')) schedule_controller()
def update_model(cleanse=True): data = UsersSheet.get_all_users() if not data: pass else: stored_in_sheet_records = set() row_num = 1 for row in data: existing_data = Competitor.objects( name=row[1], legacy_number=row[0] ).first() if existing_data is None: cfg = get_config() new_data = Competitor( legacy_number=row[0], name=row[1], status=COMPETITOR_STATUS.UNAUTHORIZED, level=to_int(row[3], None), matches=to_int(row[4]), wins=to_int(row[5]), losses=to_int(row[6]), performance=to_int(row[7]), used_vacation_time=0 ) new_data.save() new_data.reload() stored_in_sheet_records.add(new_data.id) else: stored_in_sheet_records.add(existing_data.id) UsersSheet.update_competitor_db_record(row, existing_data) row_num += 1 for new_record in Competitor.objects(id__not__in=stored_in_sheet_records): if not cleanse: row_num += 1 UsersSheet.insert_competitor_in_table(new_record, at_row=row_num) else: new_record.delete() hr_logger.info('Оновлено список гравців з гугл-таблиці')
def __scheduler_run(cease_run, interval=60): from models import Competitor, COMPETITOR_STATUS, User, RESULT, Result from config import BOT_TOKEN from telebot import TeleBot from localization.translations import get_translation_for from bot.keyboards import get_menu_keyboard from bot.bot_methods import get_opponent_and_opponent_user from google_integration.sheets.users import UsersSheet from google_integration.sheets.matches import ResultsSheet from google_integration.sheets.logs import LogsSheet from config import DB_PASSWORD, DB_USER, DB_AUTH hr_logger.info('*Scheduler started*') db.disconnect() db.connect(PROJECT_NAME, username=DB_USER, password=DB_PASSWORD, authentication_source=DB_AUTH or 'admin') tz = timezone('Europe/Kiev') def monthly_task(): for competitor in Competitor.objects(): competitor.used_vacation_time = 0 if competitor.status == COMPETITOR_STATUS.VACATION: competitor.vacation_started_at = datetime.now(tz=tz) competitor.save() def daily_task(): now = datetime.now(tz=tz) tbot = None bconfig = get_config() for competitor in Competitor.objects( status=COMPETITOR_STATUS.VACATION): if competitor.vacation_started_at: delta = now - mongo_time_to_local( competitor.vacation_started_at, tz) delta = delta.total_seconds() if competitor.used_vacation_time is not None: delta += competitor.used_vacation_time if timedelta(seconds=delta).days > bconfig.vacation_time: competitor.change_status(competitor.previous_status or COMPETITOR_STATUS.ACTIVE) competitor.save() relevant_user: User = User.objects( associated_with=competitor).first() if relevant_user is not None: if not tbot: tbot = TeleBot(BOT_TOKEN, threaded=False) smwae_check( relevant_user.user_id, get_translation_for('menu_on_vacation_end_msg'), relevant_user, reply_markup=get_menu_keyboard( status=competitor.status)) else: competitor.vacation_started_at = now competitor.used_vacation_time = delta competitor.save() else: logger.error( f"Cannot find vacation_started_at for competitor {competitor.name} (on vacation). Saved current time" ) competitor.vacation_started_at = now competitor.save() def daily_task_check(): try: config = get_config_document() n = datetime.now(tz=tz) if config.latest_daily_check: lc = mongo_time_to_local(config.latest_daily_check, tz) if (n - lc) > timedelta(hours=1): if 8 <= n.hour <= 21: logger.debug(f'Performing vacation check task at {n}') config.latest_daily_check = n config.save() daily_task() else: config.latest_daily_check = n config.save() config.reload() if config.latest_monthly_check: lc = mongo_time_to_local(config.latest_monthly_check, tz) if (n - lc) > timedelta(days=1): if n.day == 1: hr_logger.info(f'Performing monthly task at {n}') config.latest_monthly_check = n config.save() monthly_task() else: config.latest_monthly_check = n config.save() except KeyboardInterrupt: return except: logger.exception('Exception occurred while performing daily check') def check_challenges(): bconfig = get_config() n = datetime.now(tz=tz) tbot = None for competitor in Competitor.objects( status=COMPETITOR_STATUS.CHALLENGE_NEED_RESPONSE): try: if not competitor.latest_challenge_received_at: logger.error( f'Competitor {competitor.name} {competitor.legacy_number} has no latest_challenge_received_at' ) competitor.latest_challenge_received_at = datetime.now( tz=tz) competitor.save() continue cs = mongo_time_to_local( competitor.latest_challenge_received_at, tz) if (n - cs) > timedelta(days=max( 0, bconfig.time_to_accept_challenge - bconfig.accept_challenge_reminder )) and not competitor.challenge_remainder_sent: if tbot is None: tbot = TeleBot(PROJECT_NAME, threaded=False) cuser = User.objects(associated_with=competitor).first() if cuser is None: continue if not smwae_check( cuser.user_id, get_translation_for( 'remainder_challenge_accept_msg').format( bconfig.accept_challenge_reminder), cuser): opponent, opponent_user = get_opponent_and_opponent_user( competitor) if opponent and opponent_user: teardown_challenge( opponent, None, opponent_user, tbot, 'error_bot_blocked_by_opponent_challenge_canceled_msg' ) continue competitor.reload() competitor.challenge_remainder_sent = True competitor.save() elif (n - cs) > timedelta(days=bconfig.time_to_accept_challenge): if tbot is None: tbot = TeleBot(PROJECT_NAME, threaded=False) cuser = User.objects(associated_with=competitor).first() skip_comp = False if cuser is None: skip_comp = True opponent_user: User opponent, opponent_user = get_opponent_and_opponent_user( competitor) prev_level, new_level = None, None level_change = None if opponent and opponent.level > competitor.level: new_level = competitor.level prev_level = opponent.level level_change = f'{prev_level}->{new_level}' ResultsSheet.upload_canceled_result(opponent, competitor, level_change, was_ignored=True) if opponent: config = get_config() if config.group_chat_id: gmsg = get_translation_for( 'group_chat_technical_win_report_msg').format( opponent.name, competitor.name) if level_change: gmsg += '.\n' gmsg += get_translation_for( 'group_chat_players_level_changed').format( level_change) LogsSheet.glog( get_translation_for( 'gsheet_log_player_ignored_challenge_from_player' ).format(competitor.name, opponent.name) + '. ' + get_translation_for( 'group_chat_players_level_changed'). format(level_change)) else: LogsSheet.glog( get_translation_for( 'gsheet_log_player_ignored_challenge_from_player' ).format(competitor.name, opponent.name)) try: tbot.send_message(config.group_chat_id, gmsg, parse_mode='html') except: logger.exception( 'Exception occurred while sending message to group chat' ) res = Result(player_a=opponent, player_a_s=opponent.name, player_b=competitor, player_b_s=competitor.name, result=RESULT.IGNORED, canceled=True, date=datetime.now(tz=tz), level_change=level_change) res.save() competitor.in_challenge_with = None competitor.change_status(competitor.previous_status) competitor.previous_status = None competitor.latest_challenge_received_at = None if prev_level: competitor.level = prev_level competitor.challenges_ignored = ( competitor.challenges_ignored + 1) if competitor.challenges_ignored is not None else 1 competitor.challenges_ignored_total = ( competitor.challenges_ignored_total + 1 ) if competitor.challenges_ignored_total is not None else 1 competitor.losses = competitor.losses + 1 if competitor.losses is not None else 1 competitor.matches = competitor.matches + 1 if competitor.matches is not None else 1 if competitor.challenges_ignored >= bconfig.maximum_challenges_ignored: competitor.change_status(COMPETITOR_STATUS.INACTIVE) LogsSheet.glog( get_translation_for( 'gsheet_log_player_moved_to_inactive').format( competitor.name)) competitor.save() UsersSheet.update_competitor_table_record(competitor) t = get_translation_for( 'challenge_was_ignored_msg').format( competitor.challenges_ignored, bconfig.maximum_challenges_ignored) if not skip_comp: if competitor.status == COMPETITOR_STATUS.INACTIVE: t += '.\n<b>' t += get_translation_for( 'user_was_moved_to_inactive') t += '</b>' elif prev_level: t += '.\n' t += get_translation_for( 'your_level_changed_str').format( new_level, prev_level) smwae_check(cuser.user_id, t, cuser, reply_markup=get_menu_keyboard( status=competitor.status), parse_mode='html') if opponent: opponent.reload() opponent.in_challenge_with = None if opponent.status != COMPETITOR_STATUS.INACTIVE: opponent.change_status(opponent.previous_status) opponent.previous_status = None opponent.latest_challenge_received_at = None opponent.wins = opponent.wins + 1 if opponent.wins is not None else 1 opponent.matches = opponent.matches + 1 if opponent.matches is not None else 1 opponent.level = new_level opponent.save() UsersSheet.update_competitor_table_record(opponent) t = get_translation_for( 'challenge_was_ignored_opponent_msg') if prev_level: t += '\n' t += get_translation_for( 'your_level_changed_str').format( prev_level, new_level) if opponent_user: smwae_check(opponent_user.user_id, t, opponent_user, reply_markup=get_menu_keyboard( status=opponent.status), parse_mode='html') except: logger.exception( f'Exception occurred while checking challenge requests for competitor {competitor.name} {competitor.legacy_number}' ) for competitor in Competitor.objects(status__in=( COMPETITOR_STATUS.CHALLENGE_STARTER, COMPETITOR_STATUS.CHALLENGE_RECEIVER, COMPETITOR_STATUS.CHALLENGE_NEED_RESULTS_CONFIRMATION, COMPETITOR_STATUS.CHALLENGE_NEED_CANCELLATION_CONFIRMATION)): try: if not competitor.challenge_started_at: logger.error( f'Competitor {competitor.name} {competitor.legacy_number} has no challenge_started_at' ) competitor.challenge_started_at = datetime.now(tz=tz) competitor.save() continue cs = mongo_time_to_local(competitor.challenge_started_at, tz) if (n - cs) > timedelta(days=max( 0, bconfig.time_to_play_challenge - bconfig.challenge_play_reminder )) and not competitor.challenge_remainder_sent: if tbot is None: tbot = TeleBot(PROJECT_NAME, threaded=False) cuser = User.objects(associated_with=competitor).first() if cuser is None: continue if not smwae_check( cuser.user_id, get_translation_for('remainder_challenge_play_msg') .format(bconfig.challenge_play_reminder), cuser): opponent, opponent_user = get_opponent_and_opponent_user( competitor) if opponent and opponent_user: teardown_challenge( opponent, None, opponent_user, tbot, 'error_bot_blocked_by_opponent_challenge_canceled_msg' ) continue competitor.reload() competitor.challenge_remainder_sent = True competitor.save() elif (n - cs) > timedelta(days=bconfig.time_to_play_challenge): # TODO pass except: logger.exception( f'Exception occurred while checking challenges in progress (for competitor {competitor.name} {competitor.legacy_number})' ) def check_results(): try: ResultsSheet.synchronize_results(timedelta(days=1)) except KeyboardInterrupt: return except: logger.exception('Exception occurred while checking results') schedule.logger.setLevel(logging.WARNING) schedule.every(5).minutes.do(daily_task_check) schedule.every(10).minutes.do(check_challenges) schedule.every(3).minutes.do(check_results) while not cease_run.is_set(): schedule.run_pending() sleep(interval)
def process_callback(self, callback: CallbackQuery, user, bot: TeleBot): data = callback.data if data.find('auth_') != 0: return RET.ANSWER_CALLBACK, None, callback, user data = data.replace('auth_', '') if data.find('user='******'=') if len(ds) == 2: competitor_id = ds[1] try: competitor = Competitor.objects(id=competitor_id).first() if competitor is not None: competitor.change_status(COMPETITOR_STATUS.ACTIVE) competitor.associated_user_vanished = False competitor.save() user.associated_with = competitor user.save() competitor.reload() hr_logger.info( f'Користувач {user.str_repr()} аутентифікувався як {competitor.name}' ) return RET.ANSWER_AND_GO_TO_STATE, 'MenuState', callback, user else: hr_logger.error( f'Сталася помилка при аутентифікації користувача {user.str_repr()} - не вдається знайти в базі обраного ним гравця' ) return RET.ANSWER_CALLBACK, get_translation_for( 'authentication_specified_competitor_not_found_clb' ), callback, user except ValidationError: logger.exception( f'Incorrect competitor_id: {competitor_id} from user with user_id: {user.user_id}' ) elif data.find('paginate=') == 0: ds = data.split('=') if len(ds) == 2: page = ds[1] page = to_int(page, 1) try: available_competitors = Competitor.objects( status=COMPETITOR_STATUS.UNAUTHORIZED).paginate( page=page, per_page=10) except NotFound: logger.exception( f'User {user.user_id} tried to switch to nonexistent page {page}' ) available_competitors = Competitor.objects( status=COMPETITOR_STATUS.UNAUTHORIZED).paginate( page=1, per_page=10) if not render_pagination( available_competitors, callback.message, bot, get_translation_for('authentication_msg'), self.__base_keyboard, update=True): bot.send_message( callback.message.chat.id, get_translation_for( 'authentication_cannot_find_competitors_msg')) hr_logger.error( f'При авторизації користувача {user.str_repr()} не вдалося знайти жодного гравця' ) elif data.find('none') == 0: return RET.ANSWER_CALLBACK, None, callback, user elif data.find('refresh') == 0: if guard.get_allowed()[0] and guard.update_allowed()[0]: UsersSheet.update_model() available_competitors = Competitor.objects( status=COMPETITOR_STATUS.UNAUTHORIZED).paginate(page=1, per_page=10) if not render_pagination( available_competitors, callback.message, bot, get_translation_for('authentication_msg'), self.__base_keyboard, ): bot.send_message( callback.message.chat.id, get_translation_for( 'authentication_cannot_find_competitors_msg')) hr_logger.error( f'При авторизації користувача {user.str_repr()} не вдалося знайти жодного гравця' ) return RET.ANSWER_CALLBACK, None, callback, user
app.config['FLASK_ADMIN_SWATCH'] = 'flatly' app.register_blueprint(bot_blueprint) #app.register_blueprint(admin_blueprint) admin.init_app(app) login.init_app(app) #create_translation() if __name__ == "__main__": from google_integration.sheets.users import UsersSheet from scheduler_controller import schedule_controller from logger_settings import hr_logger if not args: raise ValueError("Args not found") hr_logger.info('Сервіс запущено') UsersSheet.update_model() if args.bot: bot_handler.bot.remove_webhook() bot_handler.bot.polling(none_stop=True) elif args.web_server: app.run(debug=True) elif args.scheduler: schedule_controller() elif args.web_server_with_hooks: bot_handler.bot.remove_webhook() sleep(1) bot_handler.bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH, certificate=open(WEBHOOK_SSL_CERT, 'r'))