Example #1
0
 async def init_post_result(self, ctx, match_id):
     """Allows referees to post the result of a match"""
     tournament = self.get_tournament(ctx.guild.id)
     for bracket in tournament.brackets:
         schedules_spreadsheet = bracket.schedules_spreadsheet
         if not schedules_spreadsheet:
             continue
         try:
             MatchInfo.from_id(schedules_spreadsheet, match_id)
         except MatchIdNotFound:
             continue
         return tournament, bracket
     raise tosurnament.InvalidMatchId()
Example #2
0
 async def take_or_drop_match_in_spreadsheets(self,
                                              match_ids,
                                              user_details,
                                              take,
                                              left_match_ids,
                                              *schedules_spreadsheets,
                                              retry=False):
     """Takes or drops matches of a bracket, if possible."""
     user_details.clear_matches()
     left_match_ids.clear()
     left_match_ids.update(match_ids)
     for schedules_spreadsheet in schedules_spreadsheets:
         await schedules_spreadsheet.get_spreadsheet()
         for match_id in left_match_ids.copy():
             try:
                 match_info = MatchInfo.from_id(schedules_spreadsheet,
                                                match_id, False)
             except MatchIdNotFound:
                 continue
             self.take_match_for_roles(schedules_spreadsheet, match_info,
                                       user_details, take)
             left_match_ids.remove(match_id)
     if left_match_ids and not retry:
         return False
     for schedules_spreadsheet in schedules_spreadsheets:
         self.add_update_spreadsheet_background_task(schedules_spreadsheet)
     return True
Example #3
0
 async def step8_per_bracket(self, ctx, post_result_message, tournament):
     bracket = tournament.current_bracket
     schedules_spreadsheet = bracket.schedules_spreadsheet
     if not schedules_spreadsheet:
         raise tosurnament.NoSpreadsheet("schedules")
     await schedules_spreadsheet.get_spreadsheet()
     match_info = MatchInfo.from_id(schedules_spreadsheet,
                                    post_result_message.match_id, False)
     if tournament.staff_channel_id:
         error_channel = self.bot.get_channel(tournament.staff_channel_id)
     else:
         error_channel = ctx
     prbuilder = await self.create_prbuilder(ctx, post_result_message,
                                             tournament, bracket,
                                             match_info, error_channel)
     if tournament.post_result_message:
         result_string = tournament.post_result_message
     else:
         result_string = self.get_string("post_result", "default")
     result_string = prbuilder.build(result_string, self, tournament)
     if bracket.challonge:
         await self.step8_challonge(ctx, tournament, error_channel,
                                    prbuilder)
     await self.step8_write_in_spreadsheet(bracket, match_info, prbuilder)
     post_result_channel = ctx
     if bracket.post_result_channel_id:
         post_result_channel = self.bot.get_channel(
             bracket.post_result_channel_id)
     await post_result_channel.send(result_string)
Example #4
0
    async def step7_send_message(self, channel, tournament,
                                 post_result_message):
        bracket = self.bot.session.query(Bracket).where(
            Bracket.id == post_result_message.bracket_id).first()
        if not bracket:
            self.bot.session.delete(post_result_message)
            raise tosurnament.NoBracket()
        schedules_spreadsheet = bracket.schedules_spreadsheet
        if not schedules_spreadsheet:
            raise tosurnament.NoSpreadsheet("schedules")
        await schedules_spreadsheet.get_spreadsheet()
        match_info = MatchInfo.from_id(schedules_spreadsheet,
                                       post_result_message.match_id, False)
        prbuilder = await self.create_prbuilder(None, post_result_message,
                                                tournament, bracket,
                                                match_info, channel)
        if tournament.post_result_message:
            result_string = tournament.post_result_message
        else:
            result_string = self.get_string("post_result", "default")
        result_string = prbuilder.build(result_string, self, tournament)

        await self.update_post_result_setup_message(post_result_message,
                                                    channel, 8)

        preview_message = await self.send_reply(channel, "post_result",
                                                "preview", result_string)
        post_result_message.preview_message_id = preview_message.id
Example #5
0
 async def get_next_matches_info_for_bracket(self, tournament, bracket):
     matches_data = []
     schedules_spreadsheet = bracket.schedules_spreadsheet
     if not schedules_spreadsheet:
         return matches_data
     await schedules_spreadsheet.get_spreadsheet()
     match_ids_cells = schedules_spreadsheet.spreadsheet.get_cells_with_value_in_range(
         schedules_spreadsheet.range_match_id)
     now = datetime.datetime.utcnow()
     matches_to_ignore = tournament.matches_to_ignore.split("\n")
     for match_id_cell in match_ids_cells:
         if match_id_cell.value in matches_to_ignore:
             continue
         match_info = MatchInfo.from_match_id_cell(schedules_spreadsheet,
                                                   match_id_cell)
         date_format = "%d %B"
         if schedules_spreadsheet.date_format:
             date_format = schedules_spreadsheet.date_format
         match_date = tournament.parse_date(
             match_info.get_datetime(),
             date_formats=list(filter(None, [date_format + " %H:%M"])))
         if not match_date or match_date < now:
             continue
         matches_data.append((match_info, match_date))
     return matches_data
Example #6
0
 async def allow_next_reschedule(self,
                                 ctx,
                                 match_id: str,
                                 allowed_hours: int = 24):
     """Allows a match to be reschedule without any time constraint applied."""
     tournament = self.get_tournament(ctx.guild.id)
     tosurnament_guild = self.get_guild(ctx.guild.id)
     admin_role = tosurnament.get_role(ctx.author.roles,
                                       tosurnament_guild.admin_role_id)
     referee_role = tosurnament.get_role(ctx.author.roles,
                                         tournament.referee_role_id,
                                         "Referee")
     if not admin_role and not ctx.guild.owner == ctx.author and not referee_role:
         raise tosurnament.NotRequiredRole("Referee")
     match_found = False
     for bracket in tournament.brackets:
         schedules_spreadsheet = bracket.schedules_spreadsheet
         if not schedules_spreadsheet:
             continue
         await schedules_spreadsheet.get_spreadsheet()
         try:
             match_info = MatchInfo.from_id(schedules_spreadsheet, match_id)
         except (tosurnament.SpreadsheetHttpError, InvalidWorksheet) as e:
             await self.on_cog_command_error(ctx, ctx.command.name, e)
             continue
         except MatchIdNotFound as e:
             self.bot.info(str(type(e)) + ": " + str(e))
             continue
         match_found = True
         if admin_role or ctx.guild.owner == ctx.author:
             break
         user = tosurnament.UserAbstraction.get_from_ctx(ctx)
         is_referee_of_match = False
         for referee_cell in match_info.referees:
             if referee_cell.has_value(user.name):
                 is_referee_of_match = True
                 break
         if not is_referee_of_match:
             raise tosurnament.NotRefereeOfMatch()
     if not match_found:
         raise MatchIdNotFound(match_id)
     team1 = await self.get_team_mention(ctx.guild,
                                         bracket.players_spreadsheet,
                                         match_info.team1.value)
     team2 = await self.get_team_mention(ctx.guild,
                                         bracket.players_spreadsheet,
                                         match_info.team2.value)
     allowed_reschedule = AllowedReschedule(tournament_id=tournament.id,
                                            match_id=match_id,
                                            allowed_hours=allowed_hours)
     self.bot.session.add(allowed_reschedule)
     await self.send_reply(ctx, ctx.command.name, "success", match_id,
                           allowed_hours, team1, team2)
Example #7
0
 async def init_post_result(self, ctx, match_id):
     """Allows referees to post the result of a match"""
     tournament = self.get_tournament(ctx.guild.id)
     for bracket in tournament.brackets:
         schedules_spreadsheet = bracket.schedules_spreadsheet
         if not schedules_spreadsheet:
             continue
         await schedules_spreadsheet.get_spreadsheet()
         try:
             MatchInfo.from_id(schedules_spreadsheet, match_id)
         except MatchIdNotFound:
             continue
         return tournament, bracket
     raise tosurnament.InvalidMatchId()
     post_result_message = (self.bot.session.query(PostResultMessage).where(
         PostResultMessage.tournament_id == tournament.id).where(
             PostResultMessage.referee_id == ctx.author.id).first())
     if post_result_message:
         # TODO Raise error
         ctx.send(
             "You cannot start multiple post_result at the same time. Please finish your previous one or cancel it."
         )
Example #8
0
 def take_matches(self, bracket, match_ids, staff_name, user_roles, take, invalid_match_ids):
     """Takes or drops matches of a bracket, if possible."""
     schedules_spreadsheet = bracket.schedules_spreadsheet
     if not schedules_spreadsheet:
         return
     write_cells = False
     for match_id in match_ids:
         try:
             match_info = MatchInfo.from_id(schedules_spreadsheet, match_id, False)
         except MatchIdNotFound:
             invalid_match_ids.append(match_id)
             continue
         write_cells |= self.take_match_for_roles(schedules_spreadsheet, match_info, staff_name, user_roles, take,)
     return write_cells
Example #9
0
 async def get_match_infos_from_id(self, bracket, match_ids):
     schedules_spreadsheet = bracket.schedules_spreadsheet
     if not schedules_spreadsheet:
         return []
     await schedules_spreadsheet.get_spreadsheet()
     match_ids_cells = schedules_spreadsheet.spreadsheet.get_cells_with_value_in_range(
         schedules_spreadsheet.range_match_id)
     match_infos = []
     for match_id_cell in match_ids_cells:
         if match_id_cell.value.lower() in match_ids:
             match_infos.append(
                 MatchInfo.from_match_id_cell(schedules_spreadsheet,
                                              match_id_cell))
             match_ids.remove(match_id_cell.value.lower())
     return match_infos
Example #10
0
 async def match_notification(self, guild, tournament):
     player_match_notification_channel = None
     if tournament.match_notification_channel_id:
         player_match_notification_channel = self.bot.get_channel(
             tournament.match_notification_channel_id)
     staff_channel = None
     if tournament.staff_channel_id:
         staff_channel = self.bot.get_channel(tournament.staff_channel_id)
     if not player_match_notification_channel and not staff_channel:
         return
     matches_to_ignore = [
         match_id.upper()
         for match_id in tournament.matches_to_ignore.split("\n")
     ]
     for bracket in tournament.brackets:
         schedules_spreadsheet = bracket.schedules_spreadsheet
         if not schedules_spreadsheet:
             continue
         await schedules_spreadsheet.get_spreadsheet(retry=True)
         now = datetime.datetime.utcnow()
         match_ids = schedules_spreadsheet.spreadsheet.get_cells_with_value_in_range(
             schedules_spreadsheet.range_match_id)
         for match_id_cell in match_ids:
             if match_id_cell.value.upper() in matches_to_ignore:
                 continue
             match_info = MatchInfo.from_match_id_cell(
                 schedules_spreadsheet, match_id_cell)
             date_format = "%d %B"
             if schedules_spreadsheet.date_format:
                 date_format = schedules_spreadsheet.date_format
             match_date = tournament.parse_date(
                 match_info.get_datetime(),
                 date_formats=list(filter(None, [date_format + " %H:%M"])),
                 to_timezone="UTC",
             )
             if match_date:
                 delta = match_date - now
                 if player_match_notification_channel:
                     await self.player_match_notification(
                         guild, tournament, bracket,
                         player_match_notification_channel, match_info,
                         delta)
                 if staff_channel:
                     await self.referee_match_notification(
                         guild, tournament, bracket, staff_channel,
                         match_info, delta, match_date)
Example #11
0
 def fill_matches_info_for_roles(self, ctx, bracket, matches_to_ignore,
                                 user_roles, user_name):
     team_name = None
     if user_roles.player:
         team_name = self.find_player_identification(
             ctx, bracket, user_name)
     schedules_spreadsheet = bracket.schedules_spreadsheet
     if not schedules_spreadsheet:
         return
     match_ids_cells = schedules_spreadsheet.worksheet.get_cells_with_value_in_range(
         schedules_spreadsheet.range_match_id)
     now = datetime.datetime.utcnow()
     for match_id_cell in match_ids_cells:
         if match_id_cell.value in matches_to_ignore:
             continue
         match_info = MatchInfo.from_match_id_cell(schedules_spreadsheet,
                                                   match_id_cell)
         date_format = "%d %B"
         if schedules_spreadsheet.date_format:
             date_format = schedules_spreadsheet.date_format
         match_date = dateparser.parse(
             match_info.get_datetime(),
             date_formats=list(filter(None, [date_format + " %H:%M"])),
         )
         if not match_date:
             continue
         if match_date < now:
             continue
         if (user_roles.player and team_name
                 and (match_info.team1.has_value(team_name)
                      or match_info.team2.has_value(team_name))):
             user_roles.player.taken_matches.append(
                 (bracket.name, match_info, match_date))
         for referee_cell in match_info.referees:
             if user_roles.referee and referee_cell.has_value(user_name):
                 user_roles.referee.taken_matches.append(
                     (bracket.name, match_info, match_date))
         for streamer_cell in match_info.streamers:
             if user_roles.streamer and streamer_cell.has_value(user_name):
                 user_roles.streamer.taken_matches.append(
                     (bracket.name, match_info, match_date))
         for commentator_cell in match_info.commentators:
             if user_roles.commentator and commentator_cell.has_value(
                     user_name):
                 user_roles.commentator.taken_matches.append(
                     (bracket.name, match_info, match_date))
Example #12
0
 def find_matches_to_notify(self, bracket):
     matches_info = []
     now = datetime.datetime.utcnow()
     schedules_spreadsheet = bracket.schedules_spreadsheet
     match_ids = bracket.schedules_spreadsheet.worksheet.get_cells_with_value_in_range(
         bracket.schedules_spreadsheet.range_match_id
     )
     for match_id_cell in match_ids:
         match_info = MatchInfo.from_match_id_cell(schedules_spreadsheet, match_id_cell)
         date_format = "%d %B"
         if schedules_spreadsheet.date_format:
             date_format = schedules_spreadsheet.date_format
         match_date = dateparser.parse(
             match_info.get_datetime(), date_formats=list(filter(None, [date_format + " %H:%M"])),
         )
         if match_date:
             delta = match_date - now
             if delta.days == 0 and delta.seconds >= 900 and delta.seconds < 1800:
                 matches_info.append(match_info)
     return matches_info
Example #13
0
    async def step7_send_message(self, ctx, tournament, post_result_message):
        bracket = self.bot.session.query(Bracket).where(Bracket.id == post_result_message.bracket_id).first()
        if not bracket:
            self.bot.session.delete(post_result_message)
            raise tosurnament.NoBracket()
        schedules_spreadsheet = bracket.schedules_spreadsheet
        if not schedules_spreadsheet:
            raise tosurnament.NoSpreadsheet("schedules")
        match_info = MatchInfo.from_id(schedules_spreadsheet, post_result_message.match_id, False)
        prbuilder = await self.create_prbuilder(post_result_message, tournament, bracket, match_info, ctx)
        if tournament.post_result_message:
            result_string = tournament.post_result_message
        else:
            result_string = self.get_string("post_result", "default")
        result_string = prbuilder.build(result_string, self, tournament)
        message = await self.send_reply(
            ctx,
            "post_result",
            "step8",
            post_result_message.match_id,
            post_result_message.best_of,
            post_result_message.roll_team1,
            post_result_message.roll_team2,
            post_result_message.n_warmup,
            osu.build_mp_links(post_result_message.mp_links.split("\n")),
            post_result_message.bans_team1,
            post_result_message.bans_team2,
            post_result_message.tb_bans_team1,
            post_result_message.tb_bans_team2,
        )
        post_result_message.setup_message_id = message.id
        post_result_message.step = 8

        preview_message = await self.send_reply(ctx, "post_result", "preview", result_string)
        post_result_message.preview_message_id = preview_message.id

        return message
Example #14
0
    async def agree_to_reschedule(self, reschedule_message, guild, channel,
                                  user, tournament):
        """Updates the schedules spreadsheet with reschedule time."""
        schedules_spreadsheet = tournament.current_bracket.schedules_spreadsheet
        if not schedules_spreadsheet:
            raise tosurnament.NoSpreadsheet(tournament.current_bracket.name,
                                            "schedules")
        await schedules_spreadsheet.get_spreadsheet()
        match_id = reschedule_message.match_id
        match_info = MatchInfo.from_id(schedules_spreadsheet, match_id)

        if reschedule_message.previous_date:
            previous_date = datetime.datetime.strptime(
                reschedule_message.previous_date,
                tosurnament.DATABASE_DATE_FORMAT)
            previous_date_string = tosurnament.get_pretty_date(
                tournament, previous_date)
        else:
            previous_date_string = "**No previous date**"
        new_date = datetime.datetime.strptime(reschedule_message.new_date,
                                              tosurnament.DATABASE_DATE_FORMAT)
        date_format = "%d %B"
        if schedules_spreadsheet.date_format:
            date_format = schedules_spreadsheet.date_format
        if schedules_spreadsheet.range_date and schedules_spreadsheet.range_time:
            match_info.date.value = new_date.strftime(date_format)
            match_info.time.value = new_date.strftime("%H:%M")
        elif schedules_spreadsheet.range_date:
            match_info.date.value = new_date.strftime(date_format + " %H:%M")
        elif schedules_spreadsheet.range_time:
            match_info.time.value = new_date.strftime(date_format + " %H:%M")
        else:
            raise tosurnament.UnknownError("No date range")

        self.add_update_spreadsheet_background_task(schedules_spreadsheet)
        self.bot.session.delete(reschedule_message)

        ally_to_mention = None
        if reschedule_message.ally_team_role_id:
            ally_to_mention = tosurnament.get_role(
                guild.roles, reschedule_message.ally_team_role_id)
        if not ally_to_mention:
            ally_to_mention = guild.get_member(reschedule_message.ally_user_id)
        if ally_to_mention:
            await self.send_reply(channel, "reschedule", "accepted",
                                  ally_to_mention.mention, match_id)
        else:
            # TODO not raise
            raise tosurnament.OpponentNotFound(user.mention)

        referees_to_ping, _ = self.find_staff_to_ping(guild,
                                                      match_info.referees)
        streamers_to_ping, _ = self.find_staff_to_ping(guild,
                                                       match_info.streamers)
        commentators_to_ping, _ = self.find_staff_to_ping(
            guild, match_info.commentators)

        new_date_string = tosurnament.get_pretty_date(tournament, new_date)
        staff_channel = None
        if tournament.staff_channel_id:
            staff_channel = self.bot.get_channel(tournament.staff_channel_id)
        if referees_to_ping + streamers_to_ping + commentators_to_ping:
            if staff_channel:
                to_channel = staff_channel
            else:
                to_channel = channel
            sent_message = await self.send_reply(
                to_channel,
                "reschedule",
                "staff_notification",
                match_id,
                match_info.team1.value,
                match_info.team2.value,
                previous_date_string,
                new_date_string,
                " / ".join([referee.mention for referee in referees_to_ping]),
                " / ".join(
                    [streamer.mention for streamer in streamers_to_ping]),
                " / ".join([
                    commentator.mention for commentator in commentators_to_ping
                ]),
            )
            staff_reschedule_message = StaffRescheduleMessage(
                tournament_id=reschedule_message.tournament_id,
                bracket_id=tournament.current_bracket.id,
                message_id=sent_message.id,
                team1=match_info.team1.value,
                team2=match_info.team2.value,
                match_id=match_id,
                previous_date=reschedule_message.previous_date,
                new_date=reschedule_message.new_date,
                referees_id="\n".join(
                    [str(referee.id) for referee in referees_to_ping]),
                streamers_id="\n".join(
                    [str(streamer.id) for streamer in streamers_to_ping]),
                commentators_id="\n".join([
                    str(commentator.id) for commentator in commentators_to_ping
                ]),
            )
            self.bot.session.add(staff_reschedule_message)
        elif staff_channel and tournament.notify_no_staff_reschedule:
            await self.send_reply(
                staff_channel,
                "reschedule",
                "no_staff_notification",
                match_id,
                match_info.team1.value,
                match_info.team2.value,
                previous_date_string,
                new_date_string,
            )
        allowed_reschedules = (self.bot.session.query(AllowedReschedule).where(
            AllowedReschedule.tournament_id == tournament.id).all())
        for allowed_reschedule in allowed_reschedules:
            if allowed_reschedule.match_id.upper() == match_id.upper():
                self.bot.session.delete(allowed_reschedule)
Example #15
0
 async def reaction_on_staff_reschedule_message(self, message_id, emoji,
                                                guild, channel, user):
     """Removes the referee from the schedule spreadsheet"""
     staff_reschedule_message = (
         self.bot.session.query(StaffRescheduleMessage).where(
             StaffRescheduleMessage.message_id == message_id).first())
     if not staff_reschedule_message or staff_reschedule_message.in_use:
         return
     if user.id != staff_reschedule_message.staff_id:
         return
     if emoji.name != "❌":
         return
     try:
         tosurnament_user = self.get_verified_user(user.id)
         osu_name = tosurnament_user.osu_name
     except (tosurnament.UserNotLinked, tosurnament.UserNotVerified
             ):  # ! Temporary for nik's tournament
         osu_name = user.display_name
     staff_reschedule_message.in_use = True
     self.bot.session.update(staff_reschedule_message)
     try:
         tournament = self.get_tournament(guild.id)
         bracket = self.bot.session.query(Bracket).where(
             Bracket.id == staff_reschedule_message.bracket_id).first()
         if not bracket:
             raise tosurnament.UnknownError("Bracket not found")
         schedules_spreadsheet = bracket.schedules_spreadsheet
         if not schedules_spreadsheet:
             raise tosurnament.NoSpreadsheet()
         match_id = staff_reschedule_message.match_id
         match_info = MatchInfo.from_id(schedules_spreadsheet, match_id)
         staff_cells = match_info.referees + match_info.streamers + match_info.commentators
         for staff_cell in staff_cells:
             if staff_cell.has_value(osu_name):
                 if schedules_spreadsheet.use_range:
                     staff_cell.value = ""
                 else:
                     staffs = staff_cell.value.split("/")
                     if len(staffs) == 2 and staffs[0].strip() == osu_name:
                         staff_cell.value = staffs[1].strip()
                     elif len(staffs) == 2 and staffs[1].strip == osu_name:
                         staff_cell.value = staffs[0].strip()
                     elif len(
                             staffs) == 1 and staffs[0].strip() == osu_name:
                         staff_cell.value = ""
         try:
             schedules_spreadsheet.spreadsheet.update()
         except HttpError as e:
             raise tosurnament.SpreadsheetHttpError(e.code, e.operation,
                                                    bracket.name,
                                                    "schedules")
         to_channel = channel
         staff_channel = self.bot.get_channel(tournament.staff_channel_id)
         if staff_channel:
             to_channel = staff_channel
         await self.send_reply(
             to_channel,
             "reschedule",
             "removed_from_match",
             user.mention,
             match_id,
         )
         self.bot.session.delete(staff_reschedule_message)
     except Exception as e:
         staff_reschedule_message.in_use = False
         self.bot.session.update(staff_reschedule_message)
         await self.reaction_on_staff_reschedule_message_handler(channel, e)
Example #16
0
    async def agree_to_reschedule(self, reschedule_message, guild, channel,
                                  user, tournament):
        """Updates the schedules spreadsheet with reschedule time."""
        schedules_spreadsheet = tournament.current_bracket.schedules_spreadsheet
        if not schedules_spreadsheet:
            raise tosurnament.NoSpreadsheet(tournament.current_bracket.name,
                                            "schedules")
        match_id = reschedule_message.match_id
        match_info = MatchInfo.from_id(schedules_spreadsheet, match_id)

        previous_date = datetime.datetime.strptime(
            reschedule_message.previous_date, tosurnament.DATABASE_DATE_FORMAT)
        new_date = datetime.datetime.strptime(reschedule_message.new_date,
                                              tosurnament.DATABASE_DATE_FORMAT)
        date_format = "%d %B"
        if schedules_spreadsheet.date_format:
            date_format = schedules_spreadsheet.date_format
        if schedules_spreadsheet.range_date and schedules_spreadsheet.range_time:
            match_info.date.value = new_date.strftime(date_format)
            match_info.time.value = new_date.strftime("%H:%M")
        elif schedules_spreadsheet.range_date:
            match_info.date.value = new_date.strftime(date_format + " %H:%M")
        elif schedules_spreadsheet.range_time:
            match_info.time.value = new_date.strftime(date_format + " %H:%M")
        else:
            raise tosurnament.UnknownError("No date range")

        staff_name_to_ping = set()
        staff_cells = match_info.referees + match_info.streamers + match_info.commentators
        for staff_cell in staff_cells:
            if schedules_spreadsheet.use_range:
                staff_name_to_ping.add(staff_cell.value)
            else:
                staffs = staff_cell.value.split("/")
                for staff in staffs:
                    staff_name_to_ping.add(staff.strip())
        staff_to_ping = list(
            filter(
                None,
                [guild.get_member_named(name) for name in staff_name_to_ping]))

        try:
            schedules_spreadsheet.spreadsheet.update()
        except HttpError as e:
            raise tosurnament.SpreadsheetHttpError(
                e.code, e.operation, tournament.current_bracket.name,
                "schedules")

        self.bot.session.delete(reschedule_message)

        ally_to_mention = None
        if reschedule_message.ally_team_role_id:
            ally_to_mention = tosurnament.get_role(
                guild.roles, reschedule_message.ally_team_role_id)
        if not ally_to_mention:
            ally_to_mention = guild.get_member(reschedule_message.ally_user_id)
        if ally_to_mention:
            await self.send_reply(
                channel,
                "reschedule",
                "accepted",
                ally_to_mention.mention,
                match_id,
            )
        else:
            raise tosurnament.OpponentNotFound(user.mention)

        previous_date_string = previous_date.strftime(
            tosurnament.PRETTY_DATE_FORMAT)
        new_date_string = new_date.strftime(tosurnament.PRETTY_DATE_FORMAT)
        staff_channel = None
        if tournament.staff_channel_id:
            staff_channel = self.bot.get_channel(tournament.staff_channel_id)
        if staff_to_ping:
            if staff_channel:
                to_channel = staff_channel
            else:
                to_channel = channel
            for staff in staff_to_ping:
                sent_message = await self.send_reply(
                    to_channel,
                    "reschedule",
                    "staff_notification",
                    staff.mention,
                    match_id,
                    match_info.team1.value,
                    match_info.team2.value,
                    previous_date_string,
                    new_date_string,
                )
                staff_reschedule_message = StaffRescheduleMessage(
                    tournament_id=reschedule_message.tournament_id,
                    bracket_id=tournament.current_bracket.id,
                    message_id=sent_message.id,
                    match_id=match_id,
                    new_date=reschedule_message.new_date,
                    staff_id=staff.id,
                )
                self.bot.session.add(staff_reschedule_message)
        elif staff_channel:
            await self.send_reply(
                staff_channel,
                "reschedule",
                "no_staff_notification",
                match_id,
                match_info.team1.value,
                match_info.team2.value,
                previous_date_string,
                new_date_string,
            )
        allowed_reschedules = (self.bot.session.query(AllowedReschedule).where(
            AllowedReschedule.tournament_id == tournament.id).all())
        for allowed_reschedule in allowed_reschedules:
            if allowed_reschedule.match_id.upper() == match_id.upper():
                self.bot.session.delete(allowed_reschedule)
Example #17
0
    async def reschedule(self, ctx, match_id: str, *, date: str):
        """Allows players to reschedule their matches."""
        try:
            new_date = dateparser.parse(date)
        except ValueError:
            raise commands.UserInputError()
        tournament = self.get_tournament(ctx.guild.id)
        skip_deadline_validation = False
        allowed_reschedule_match_ids = [
            allowed_reschedule.match_id.upper() for allowed_reschedule in
            self.bot.session.query(AllowedReschedule).where(
                AllowedReschedule.tournament_id == tournament.id).all()
        ]
        if match_id.upper() in allowed_reschedule_match_ids:
            skip_deadline_validation = True

        now = datetime.datetime.utcnow()
        self.validate_new_date(tournament, now, new_date,
                               skip_deadline_validation)
        try:
            tosurnament_user = self.get_verified_user(ctx.author.id)
            user_name = tosurnament_user.osu_name
        except (tosurnament.UserNotLinked, tosurnament.UserNotVerified
                ):  # ! Temporary for nik's tournament
            user_name = ""
        for bracket in tournament.brackets:
            schedules_spreadsheet = bracket.schedules_spreadsheet
            if not schedules_spreadsheet:
                continue
            try:
                match_info = MatchInfo.from_id(schedules_spreadsheet, match_id)
            except tosurnament.SpreadsheetHttpError as e:
                await self.on_cog_command_error(ctx, ctx.command.name, e)
                continue
            except DuplicateMatchId:
                await self.send_reply(ctx, ctx.command.name,
                                      "duplicate_match_id", match_id)
                continue
            except (InvalidWorksheet, MatchIdNotFound):
                continue
            match_id = match_info.match_id.value

            players_spreadsheet = bracket.players_spreadsheet
            if players_spreadsheet and players_spreadsheet.range_team_name:
                try:
                    team1_info = TeamInfo.from_team_name(
                        players_spreadsheet, match_info.team1.value)
                    team2_info = TeamInfo.from_team_name(
                        players_spreadsheet, match_info.team2.value)
                except tosurnament.SpreadsheetHttpError as e:
                    await self.on_cog_command_error(ctx, ctx.command.name, e)
                    continue
                except (InvalidWorksheet, TeamNotFound, DuplicateTeam):
                    continue
                if user_name in [cell.value for cell in team1_info.players]:
                    team_name = team1_info.team_name.value
                    opponent_team_name = team2_info.team_name.value
                    opponent_team_captain_name = team2_info.players[0].value
                else:
                    team_name = team2_info.team_name.value
                    opponent_team_name = team1_info.team_name.value
                    opponent_team_captain_name = team1_info.players[0].value
            else:
                # ! Temporary
                try:
                    team1_info = TeamInfo.from_team_name(
                        players_spreadsheet, match_info.team1.value)
                    team2_info = TeamInfo.from_team_name(
                        players_spreadsheet, match_info.team2.value)
                except tosurnament.SpreadsheetHttpError as e:
                    await self.on_cog_command_error(ctx, ctx.command.name, e)
                    continue
                except (InvalidWorksheet, DuplicateTeam):
                    continue
                except TeamNotFound:
                    raise tosurnament.InvalidMatch()
                if team1_info.discord[0] == str(ctx.author):
                    user_name = team1_info.players[0].value
                    opponent_team_captain = ctx.guild.get_member_named(
                        team2_info.discord[0])
                elif team2_info.discord[0] == str(ctx.author):
                    user_name = team2_info.players[0].value
                    opponent_team_captain = ctx.guild.get_member_named(
                        team1_info.discord[0])
                else:
                    raise tosurnament.InvalidMatch()
                # ! Temporary
                team_name = user_name
                if match_info.team1.value == user_name:
                    opponent_team_name = match_info.team2.value
                    opponent_team_captain_name = opponent_team_name
                elif match_info.team2.value == user_name:
                    opponent_team_name = match_info.team1.value
                    opponent_team_captain_name = opponent_team_name
                else:
                    raise tosurnament.InvalidMatch()

            previous_date = self.validate_reschedule_feasibility(
                tournament, schedules_spreadsheet, match_info, now, new_date,
                skip_deadline_validation)

            if not opponent_team_captain:  # ! Temporary
                opponent_team_captain = ctx.guild.get_member_named(
                    opponent_team_captain_name)
            if not opponent_team_captain:
                raise tosurnament.OpponentNotFound(ctx.author.mention)

            reschedule_message = RescheduleMessage(tournament_id=tournament.id,
                                                   bracket_id=bracket.id,
                                                   in_use=False)

            opponent_to_ping = opponent_team_captain
            if tournament.reschedule_ping_team:
                role = tosurnament.get_role(ctx.guild.roles, None,
                                            opponent_team_name)
                if role:
                    opponent_to_ping = role
                role = tosurnament.get_role(ctx.guild.roles, None, team_name)
                if role:
                    reschedule_message.ally_team_role_id = role.id

            reschedule_message.match_id = match_id
            reschedule_message.ally_user_id = ctx.author.id
            reschedule_message.opponent_user_id = opponent_team_captain.id
            previous_date_string = previous_date.strftime(
                tosurnament.PRETTY_DATE_FORMAT)
            reschedule_message.previous_date = previous_date.strftime(
                tosurnament.DATABASE_DATE_FORMAT)
            new_date_string = new_date.strftime(tosurnament.PRETTY_DATE_FORMAT)
            reschedule_message.new_date = new_date.strftime(
                tosurnament.DATABASE_DATE_FORMAT)
            sent_message = await self.send_reply(
                ctx,
                ctx.command.name,
                "success",
                opponent_to_ping.mention,
                escape_markdown(user_name),
                match_id,
                previous_date_string,
                new_date_string,
            )
            reschedule_message.message_id = sent_message.id
            self.bot.session.add(reschedule_message)
            await sent_message.add_reaction("👍")
            await sent_message.add_reaction("👎")
            return
        raise tosurnament.InvalidMatchId()
Example #18
0
    async def reschedule_for_bracket(
        self,
        ctx,
        tournament,
        bracket,
        schedules_spreadsheet,
        players_spreadsheet,
        match_id,
        new_date,
        user,
        skip_deadline_validation,
        retry=False,
    ):
        try:
            match_info = MatchInfo.from_id(schedules_spreadsheet, match_id)
        except (tosurnament.SpreadsheetHttpError, InvalidWorksheet) as e:
            if retry:
                await self.on_cog_command_error(ctx, ctx.command.name, e)
            return False
        except MatchIdNotFound as e:
            if retry:
                self.bot.info_exception(e)
            return False
        match_id = match_info.match_id.value

        players_spreadsheet = bracket.players_spreadsheet
        if players_spreadsheet:
            await players_spreadsheet.get_spreadsheet()
            if not user.verified:
                # TODO find player_name from discord_id in players_spreadsheet
                pass
            ally_team_info, opponent_team_info = await self.get_teams_info(
                ctx, tournament, players_spreadsheet, match_info, user)
            if not ally_team_info:
                return False
            team_name = ally_team_info.team_name.value
            opponent_team_name = opponent_team_info.team_name.value
            opponent_user = tosurnament.UserAbstraction.get_from_osu_name(
                ctx.bot, opponent_team_info.players[0].value,
                opponent_team_info.discord[0].value)
        else:
            team_name = user.name
            if team_name == match_info.team1.value:
                opponent_team_name = match_info.team2.value
            elif team_name == match_info.team2.value:
                opponent_team_name = match_info.team1.value
            else:
                raise tosurnament.InvalidMatch()
            opponent_user = tosurnament.UserAbstraction.get_from_osu_name(
                ctx.bot, opponent_team_name)

        now = datetime.datetime.utcnow()
        new_date = self.validate_new_date(ctx, tournament,
                                          schedules_spreadsheet, match_info,
                                          now, new_date,
                                          skip_deadline_validation)
        previous_date = self.validate_reschedule_feasibility(
            ctx, tournament, schedules_spreadsheet, match_info, now, new_date,
            skip_deadline_validation)

        opponent_team_captain = opponent_user.get_member(ctx.guild)
        if not opponent_team_captain:
            raise tosurnament.OpponentNotFound(ctx.author.mention)

        opponent_to_ping = opponent_team_captain
        if players_spreadsheet and players_spreadsheet.range_team_name and tournament.reschedule_ping_team:
            role = tosurnament.get_role(ctx.guild.roles, None,
                                        opponent_team_name)
            if role:
                opponent_to_ping = role

        reschedule_message = RescheduleMessage(tournament_id=tournament.id,
                                               bracket_id=bracket.id,
                                               in_use=False)
        role = tosurnament.get_role(ctx.guild.roles, None, team_name)
        if role:
            reschedule_message.ally_team_role_id = role.id
        reschedule_message.match_id = match_id
        reschedule_message.match_id_hash = match_id
        reschedule_message.ally_user_id = ctx.author.id
        reschedule_message.opponent_user_id = opponent_team_captain.id
        if previous_date:
            previous_date_string = tosurnament.get_pretty_date(
                tournament, previous_date)
            reschedule_message.previous_date = previous_date.strftime(
                tosurnament.DATABASE_DATE_FORMAT)
        else:
            previous_date_string = "**No previous date**"
            reschedule_message.previous_date = ""
        new_date_string = tosurnament.get_pretty_date(tournament, new_date)
        reschedule_message.new_date = new_date.strftime(
            tosurnament.DATABASE_DATE_FORMAT)
        sent_message = await self.send_reply(
            ctx,
            ctx.command.name,
            "success",
            opponent_to_ping.mention,
            escape_markdown(team_name),
            match_id,
            previous_date_string,
            new_date_string,
        )
        reschedule_message.message_id = sent_message.id

        previous_reschedule_message = (
            self.bot.session.query(RescheduleMessage).where(
                RescheduleMessage.tournament_id == tournament.id).where(
                    RescheduleMessage.match_id_hash == match_id).first())
        if previous_reschedule_message:
            self.bot.session.delete(previous_reschedule_message)

        self.bot.session.add(reschedule_message)
        await sent_message.add_reaction("👍")
        await sent_message.add_reaction("👎")
        return True