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 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()
Example #3
0
    def upload_result(result: Result, at_row=None):
        try:
            cfg = get_config()
            if not cfg.spreadsheet_results_sheet:
                hr_logger.error(
                    'Не вдалося надіслати результат матчу в гуглтаблицю - у налаштуваннях відсутня назва листа')
                logger.error('Cannot insert result into a google sheet - sheet name is missing')
                return

            if at_row is None:
                results = ResultsSheet.get_all_successful_results()
                if results is None:
                    results = []
                at_row = len(results) + 2

            if result.result in (RESULT.A_WINS, RESULT.B_WINS):
                winner = result.player_a.fetch() if result.result == RESULT.A_WINS else result.player_b.fetch()
                looser = result.player_b.fetch() if result.result == RESULT.A_WINS else result.player_a.fetch()
                score = result.repr_score()

                update_data(
                    cfg.spreadsheet_id,
                    f'{cfg.spreadsheet_results_sheet}!A{at_row}:E',
                    values=[
                        [
                            mongo_time_to_local(result.date, tz=_k_tz).strftime('%d/%m/%Y'),
                            winner.name,
                            score,
                            looser.name,
                            result.level_change or '-'
                        ]
                    ]
                )
            else:
                logger.error(f"Wrong method called for result {result.id}. Call upload_canceled_result instead")
        except:
            logger.exception('Exception occurred while uploading match result')
Example #4
0
 def end_vacation(self, message: Message, user: User, bot: TeleBot, competitor: Competitor):
     if competitor.status != COMPETITOR_STATUS.VACATION:
         return RET.OK, None, None, None
     if not competitor.vacation_started_at:
         logger.error(f"Cannot calculate user's ({user.user_id}) time on vacation - cannot find vacation_started_at")
         delta = 0
     else:
         tz = timezone('Europe/Kiev')
         now = datetime.now(tz=tz)
         delta = now - mongo_time_to_local(competitor.vacation_started_at, tz)
         delta = delta.total_seconds()
     if competitor.used_vacation_time is None:
         competitor.used_vacation_time = delta
     else:
         competitor.used_vacation_time += delta
     competitor.change_status(competitor.previous_status)
     competitor.save()
     bot.send_message(
         message.chat.id,
         get_translation_for('menu_on_vacation_end_manual_msg'),
         reply_markup=self.__base_keyboard(status=competitor.status)
     )
     LogsSheet.glog(get_translation_for('gsheet_log_player_finished_vacation').format(competitor.name))
     return RET.OK, None, None, None
    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})'
                )
Example #6
0
    def synchronize_results(max_delta=None):
        all_finished_matches = ResultsSheet.get_all_successful_results()
        all_canceled_matches = ResultsSheet.get_all_canceled_results()

        stored_results = []
        for result in Result.objects(confirmed=True):
            stored_results.append(result)

        for sr in stored_results:
            sr: Result
            score = sr.repr_score()
            date = mongo_time_to_local(sr.date, _k_tz).strftime('%d/%m/%Y')

            if sr.result == RESULT.A_WINS:
                winner = sr.player_a_s
                loser = sr.player_b_s
            elif sr.result == RESULT.B_WINS:
                winner = sr.player_b_s
                loser = sr.player_a_s
            else:
                logger.error(f'INCONSISTENT RESULT OF A MATCH RESULT: {sr.id} {sr.result} {sr.player_a_s} {sr.player_b_s}')
                continue

            found = False
            for fm in all_finished_matches:
                if fm[0] == date and \
                        fm[1] == winner and \
                        fm[2] == score and \
                        fm[3] == loser:
                    found = True
                    all_finished_matches.remove(fm)
                    break
            if not found:
                if sr.deletion_marker:
                    logger.error(f'Again cannot find result info in gsheet: {sr.id}. Deleting')
                    sr.delete()
                else:
                    logger.error(f'Cannot find result info in gsheet: {sr.id}. {sr.result} - {sr.date}; {sr.player_a_s} - {sr.player_b_s}; {score} - {date}')
                    sr.deletion_marker = True
                    sr.save()

            else:
                sr.deletion_marker = False
                sr.save()

        now = datetime.now(tz=_k_tz)
        tbot = None
        for new_record in all_finished_matches:
            try:
                nr_date = new_record[0]
                try:
                    nr_date = datetime.strptime(nr_date, '%d/%m/%Y')
                except ValueError:
                    nr_date = datetime.strptime(nr_date, '%m/%d/%Y')
                nr_date = _k_tz.localize(nr_date)
                score = Result.try_to_parse_score(new_record[2])
                score_s = None
                if score is None:
                    score_s = new_record[2]
                    score = []
                new_res = Result(
                    player_a_s = new_record[1],
                    player_b_s = new_record[3],
                    scores=score,
                    scores_s=score_s,
                    confirmed=True,
                    level_change=new_record[4] if new_record[4] != '-' else None,
                    date=nr_date,
                    result=RESULT.A_WINS
                )
                new_res.save()

                cfg = get_config()
                if cfg.group_chat_id and (nr_date > now or (max_delta and (now - nr_date) < max_delta)):
                    if tbot is None:
                        tbot = TeleBot(BOT_TOKEN, threaded=False)

                    score = new_res.repr_score()
                    gmsg = get_translation_for('group_chat_match_result_msg').format(new_res.player_a_s,
                                                                                     new_res.player_b_s,
                                                                                     score)
                    if new_res.level_change:
                        gmsg += '.\n'
                        gmsg += get_translation_for('group_chat_players_level_changed').format(new_res.level_change)

                    try:
                        tbot.send_message(
                            cfg.group_chat_id,
                            gmsg,
                            parse_mode='html'
                        )
                    except:
                        logger.exception('Exception occurred while sending message to group chat')
            except:
                logger.exception(f'Exception occurred while checking new_record: {new_record}')

        # CANCELED CHECKS

        stored_results = []
        for result in Result.objects(canceled=True):
            stored_results.append(result)

        for sr in stored_results:
            sr: Result
            date = mongo_time_to_local(sr.date, _k_tz).strftime('%d/%m/%Y')
            alternative_date = mongo_time_to_local(sr.date, _k_tz).strftime('%m/%d/%Y')

            found = False
            # logger.warning('----------------------------')
            # logger.warning(f'{date}, {alternative_date}, {sr.player_a_s}, {sr.player_b_s}')
            for fm in all_canceled_matches:
                is_ignored = fm[2].find('игнор') != -1 or fm[2].find('проігнор') != -1 \
                             or fm[2].find(get_translation_for('gsheet_technical_win_ignored_str')) != -1
                is_dismissed = fm[2].find('повторн') != -1 or fm[2].find('відмов') != -1 \
                               or fm[2].find(get_translation_for('gsheet_technical_win_dismissed_str')) != -1
                # logger.warning(f'Is_ignore: {is_ignored} - {sr.result==RESULT.IGNORED}, is_dismissed: {is_dismissed} - {sr.result==RESULT.DISMISSED}')
                # logger.warning(fm)
                # logger.warning(f'{fm[0] == date} | {fm[0] == alternative_date} | {fm[3] == sr.player_a_s} | {fm[1] == sr.player_b_s}')
                # logger.warning(f'{(is_dismissed and sr.result == RESULT.DISMISSED) or (is_ignored and sr.result == RESULT.IGNORED)}')

                winner = sr.player_a_s
                loser = sr.player_b_s

                if fm[0] in (date, alternative_date) and \
                        fm[3] == winner and \
                        fm[1] == loser and \
                        ((is_dismissed and sr.result == RESULT.DISMISSED) or (is_ignored and sr.result == RESULT.IGNORED)):
                    found = True
                    all_canceled_matches.remove(fm)
                    break
            if not found:
                if sr.deletion_marker:
                    logger.error(f'Again cannot find result (canceled) info in gsheet: {sr.id}. Deleting')
                    sr.delete()
                else:
                    logger.error(
                        f'Cannot find result (canceled) info in gsheet: {sr.id}. {sr.result} - {sr.date}; {sr.player_a_s} - {sr.player_b_s}; {date}')
                    sr.deletion_marker = True
                    sr.save()
            else:
                sr.deletion_marker = False
                sr.save()

        for new_record in all_canceled_matches:
            try:
                nr_date = new_record[0]
                try:
                    nr_date = datetime.strptime(nr_date, '%d/%m/%Y')
                except ValueError:
                    nr_date = datetime.strptime(nr_date, '%m/%d/%Y')
                nr_date = _k_tz.localize(nr_date)
                is_ignored = new_record[2].find('игнор') != -1 or new_record[2].find('проігнор') != -1
                #is_dismissed = new_record[2].find('повторн') != -1 or new_record[2].find('відмов') != -1
                new_res = Result(
                    player_a_s = new_record[3],
                    player_b_s = new_record[1],
                    canceled=True,
                    level_change=new_record[4],
                    date=nr_date,
                    result=RESULT.IGNORED if is_ignored else RESULT.DISMISSED
                )
                new_res.save()

                cfg = get_config()
                if cfg.group_chat_id and (nr_date > now or (max_delta and (now - nr_date) < max_delta)):
                    if tbot is None:
                        tbot = TeleBot(BOT_TOKEN, threaded=False)

                    if is_ignored:
                        gmsg = get_translation_for('gsheet_log_player_ignored_challenge_from_player').format(
                            new_res.player_b_s,
                            new_res.player_a_s
                        )
                    else:
                        gmsg = get_translation_for('gsheet_log_player_dismissed_challenge_from_player').format(
                            new_res.player_b_s,
                            new_res.player_a_s
                        )

                    if new_res.level_change:
                        gmsg += '.\n'
                        gmsg += get_translation_for('group_chat_players_level_changed').format(new_res.level_change)

                    try:
                        tbot.send_message(
                            cfg.group_chat_id,
                            gmsg,
                            parse_mode='html'
                        )
                    except:
                        logger.exception('Exception occurred while sending message to group chat')
            except:
                logger.exception(f'Exception occurred while checking new_record: {new_record}')