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')
Beispiel #2
0
 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()
Beispiel #4
0
 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)
Beispiel #6
0
    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
Beispiel #7
0
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'))