Example #1
0
    async def gitlog(self, ctx, member: discord.Member = None):
        """Displays the list of gitgud problems issued to the specified member, excluding those noguded by admins.
        If the challenge was completed, time of completion and amount of points gained will also be displayed.
        """
        def make_line(entry):
            issue, finish, name, contest, index, delta, status = entry
            problem = cf_common.cache2.problem_cache.problem_by_name[name]
            line = f"[{name}]({problem.url})\N{EN SPACE}[{problem.rating}]"
            if finish:
                time_str = cf_common.days_ago(finish)
                points = f"{_GITGUD_SCORE_DISTRIB[delta // 100 + 3]:+}"
                line += f"\N{EN SPACE}{time_str}\N{EN SPACE}[{points}]"
            return line

        def make_page(chunk):
            message = f"gitgud log for {member.display_name}"
            log_str = "\n".join(make_line(entry) for entry in chunk)
            embed = discord_common.cf_color_embed(description=log_str)
            return message, embed

        member = member or ctx.author
        data = cf_common.user_db.gitlog(member.id)
        pages = [make_page(chunk) for chunk in paginator.chunkify(data, 7)]
        paginator.paginate(
            self.bot,
            ctx.channel,
            pages,
            wait_time=5 * 60,
            set_pagenum_footers=True,
        )
Example #2
0
    async def gudgitters(self, ctx):
        """Show the list of users of gitgud with their scores."""
        res = cf_common.user_db.get_gudgitters()
        res.sort(key=lambda r: r[1], reverse=True)

        rankings = []
        for user_id, score in res:
            member = ctx.guild.get_member(int(user_id))
            if member is None:
                continue
            if score > 0:
                handle = cf_common.user_db.get_handle(user_id, ctx.guild.id)
                user = cf_common.user_db.fetch_cf_user(handle)
                if user is None:
                    continue
                discord_handle = member.display_name
                rating = user.rating
                rankings.append((index, discord_handle, handle, rating, score))
                index += 1
            if index == 10:
                break

        if not rankings:
            raise HandleCogError(
                'No one has completed a gitgud challenge, send ;gitgud to request and ;gotgud to mark it as complete'
            )
        pages = _make_pages_gudgitters(rankings, 'gudgitters')
        paginator.paginate(self.bot,
                           ctx.channel,
                           pages,
                           wait_time=_PAGINATE_WAIT_TIME,
                           set_pagenum_footers=True)
Example #3
0
    async def vshistory(self,
                        ctx,
                        member1: discord.Member = None,
                        member2: discord.Member = None):
        if not member1:
            raise DuelCogError(
                f'You need to specify one or two discord members.')

        member2 = member2 or ctx.author
        data = cf_common.user_db.get_pair_duels(member1.id, member2.id)
        w, l, d = 0, 0, 0
        for _, _, _, _, challenger, challengee, winner in data:
            if winner != Winner.DRAW:
                winnerid = challenger if winner == Winner.CHALLENGER else challengee
                if winnerid == member1.id:
                    w += 1
                else:
                    l += 1
            else:
                d += 1
        message = discord.utils.escape_mentions(
            f'`{member1.display_name}` ({w}/{d}/{l}) `{member2.display_name}`')
        pages = self._paginate_duels(data, message, ctx.guild.id, False)
        paginator.paginate(self.bot,
                           ctx.channel,
                           pages,
                           wait_time=5 * 60,
                           set_pagenum_footers=True)
Example #4
0
    async def ranklist(self, ctx):
        """Show the list of duelists with their duel rating."""
        users = [(ctx.guild.get_member(user_id), rating) for user_id, rating in cf_common.user_db.get_duelists()]
        users = [(member, cf_common.user_db.get_handle(member.id, ctx.guild.id), rating)
                 for member, rating in users
                 if member is not None and cf_common.user_db.get_num_duel_completed(member.id) > 0]

        _PER_PAGE = 10
        def make_page(chunk, page_num):
            style = table.Style('{:>}  {:<}  {:<}  {:<}')
            t = table.Table(style)
            t += table.Header('#', 'Name', 'Handle', 'Rating')
            t += table.Line()
            for index, (member, handle, rating) in enumerate(chunk):
                rating_str = f'{rating} ({rating2rank(rating).title_abbr})'
                t += table.Data(_PER_PAGE * page_num + index, f'{member.display_name}', handle, rating_str)

            table_str = f'```\n{t}\n```'
            embed = discord_common.cf_color_embed(description=table_str)
            return 'List of duelists', embed

        if not users:
            raise DuelCogError('There are no active duelists.')

        pages = [make_page(chunk, k) for k, chunk in enumerate(paginator.chunkify(users, _PER_PAGE))]
        paginator.paginate(self.bot, ctx.channel, pages, wait_time=5 * 60, set_pagenum_footers=True)
Example #5
0
    async def list(self, ctx, *countries):
        """Shows members of the server who have registered their handles and
        their Codeforces ratings. You can additionally specify a list of countries
        if you wish to display only members from those countries. Country data is
        sourced from codeforces profiles. e.g. ;handle list Croatia Slovenia
        """
        countries = [country.title() for country in countries]
        res = cf_common.user_db.get_cf_users_for_guild(ctx.guild.id)
        users = [(ctx.guild.get_member(user_id), cf_user.handle,
                  cf_user.rating) for user_id, cf_user in res
                 if not countries or cf_user.country in countries]
        users = [(member, handle, rating) for member, handle, rating in users
                 if member is not None]
        if not users:
            raise HandleCogError('No members with registered handles.')

        users.sort(
            key=lambda x:
            (1
             if x[2] is None else -x[2], x[1]))  # Sorting by (-rating, handle)
        title = 'Handles of server members'
        if countries:
            title += ' from ' + ', '.join(f'`{country}`'
                                          for country in countries)
        pages = _make_pages(users, title)
        paginator.paginate(self.bot,
                           ctx.channel,
                           pages,
                           wait_time=_PAGINATE_WAIT_TIME,
                           set_pagenum_footers=True)
Example #6
0
    async def _show_ranklist(self, channel, contest_id: int, handles: [str], ranklist, vc: bool = False, delete_after: float = None):
        contest = cf_common.cache2.contest_cache.get_contest(contest_id)
        if ranklist is None:
            raise ContestCogError('No ranklist to show')

        handle_standings = []
        for handle in handles:
            try:
                standing = ranklist.get_standing_row(handle)
            except rl.HandleNotPresentError:
                continue

            # Database has correct handle ignoring case, update to it
            # TODO: It will throw an exception if this row corresponds to a team. At present ranklist doesnt show teams.
            # It should be fixed in https://github.com/cheran-senthil/TLE/issues/72
            handle = standing.party.members[0].handle
            if vc and standing.party.participantType != 'VIRTUAL':
                continue
            handle_standings.append((handle, standing))

        if not handle_standings:
            error = f'None of the handles are present in the ranklist of `{contest.name}`'
            if vc:
                await channel.send(embed=discord_common.embed_alert(error), delete_after=delete_after)
                return
            raise ContestCogError(error)

        handle_standings.sort(key=lambda data: data[1].rank)
        deltas = None
        if ranklist.is_rated:
            deltas = [ranklist.get_delta(handle) for handle, standing in handle_standings]

        problem_indices = [problem.index for problem in ranklist.problems]
        pages = self._make_standings_pages(contest, problem_indices, handle_standings, deltas)
        paginator.paginate(self.bot, channel, pages, wait_time=_STANDINGS_PAGINATE_WAIT_TIME, delete_after=delete_after)
Example #7
0
    async def ongoing(self, ctx, member: discord.Member = None):
        def make_line(entry):
            start_time, name, challenger, challengee = entry
            problem = cf_common.cache2.problem_cache.problem_by_name[name]
            now = datetime.datetime.now().timestamp()
            when = cf_common.pretty_time_format(now - start_time,
                                                shorten=True,
                                                always_seconds=True)
            challenger = get_cf_user(challenger, ctx.guild.id)
            challengee = get_cf_user(challengee, ctx.guild.id)
            return f'[{challenger.handle}]({challenger.url}) vs [{challengee.handle}]({challengee.url}): [{name}]({problem.url}) [{problem.rating}] {when}'

        def make_page(chunk):
            message = f'List of ongoing duels:'
            log_str = '\n'.join(make_line(entry) for entry in chunk)
            embed = discord_common.cf_color_embed(description=log_str)
            return message, embed

        member = member or ctx.author
        data = cf_common.user_db.get_ongoing_duels()
        if not data:
            raise DuelCogError('There are no ongoing duels.')

        pages = [make_page(chunk) for chunk in paginator.chunkify(data, 7)]
        paginator.paginate(self.bot,
                           ctx.channel,
                           pages,
                           wait_time=5 * 60,
                           set_pagenum_footers=True)
Example #8
0
    async def vcratings(self, ctx):
        users = [(await self.member_converter.convert(ctx, str(member_id)), handle, cf_common.user_db.get_vc_rating(member_id, default_if_not_exist=False))
                 for member_id, handle in cf_common.user_db.get_handles_for_guild(ctx.guild.id)]
        # Filter only rated users. (Those who entered at least one rated vc.)
        users = [(member, handle, rating)
                 for member, handle, rating in users
                 if rating is not None]
        users.sort(key=lambda user: -user[2])

        _PER_PAGE = 10

        def make_page(chunk, page_num):
            style = table.Style('{:>}  {:<}  {:<}  {:<}')
            t = table.Table(style)
            t += table.Header('#', 'Name', 'Handle', 'Rating')
            t += table.Line()
            for index, (member, handle, rating) in enumerate(chunk):
                rating_str = f'{rating} ({cf.rating2rank(rating).title_abbr})'
                t += table.Data(_PER_PAGE * page_num + index, f'{member.display_name}', handle, rating_str)

            table_str = f'```\n{t}\n```'
            embed = discord_common.cf_color_embed(description=table_str)
            return 'VC Ratings', embed

        if not users:
            raise ContestCogError('There are no active VCers.')

        pages = [make_page(chunk, k) for k, chunk in enumerate(paginator.chunkify(users, _PER_PAGE))]
        paginator.paginate(self.bot, ctx.channel, pages, wait_time=5 * 60, set_pagenum_footers=True)
Example #9
0
    async def upsolve(self, ctx, choice: int = -1):
        """Request an unsolved problem from a contest you participated in
        delta  | -300 | -200 | -100 |  0  | +100 | +200 | +300 | +400 | +500
        points |   2  |   3  |   5  |  8  |  12  |  17  |  23  |  23  |  23
        """
        await self._validate_gitgud_status(ctx, delta=None)
        handle, = await cf_common.resolve_handles(ctx, self.converter,
                                                  ('!' + str(ctx.author), ))
        user = cf_common.user_db.fetch_cf_user(handle)
        rating = round(user.effective_rating, -2)
        resp = await cf.user.rating(handle=handle)
        contests = {change.contestId for change in resp}
        submissions = await cf.user.status(handle=handle)
        solved = {
            sub.problem.name
            for sub in submissions if sub.verdict == 'OK'
        }
        problems = [
            prob for prob in cf_common.cache2.problem_cache.problems
            if prob.name not in solved and prob.contestId in contests and (
                (prob.rating - rating) >= _GITGUD_MAX_NEG_DELTA_VALUE and
                (prob.rating - rating) <= _GITGUD_MAX_POS_DELTA_VALUE)
        ]

        if not problems:
            raise CodeforcesCogError(
                'Problems not found within the search parameters')

        problems.sort(key=lambda problem: cf_common.cache2.contest_cache.
                      get_contest(problem.contestId).startTimeSeconds,
                      reverse=True)

        if choice > 0 and choice <= len(problems):
            problem = problems[choice - 1]
            await self._gitgud(ctx, handle, problem, problem.rating - rating)
        else:
            problems = problems[:100]

            def make_line(i, prob):
                data = (f'{i + 1}: [{prob.name}]({prob.url}) [{prob.rating}]')
                return data

            def make_page(chunk, pi, num):
                title = f'Select a problem to upsolve (1-{num}):'
                msg = '\n'.join(
                    make_line(10 * pi + i, prob)
                    for i, prob in enumerate(chunk))
                embed = discord_common.cf_color_embed(description=msg)
                return title, embed

            pages = [
                make_page(chunk, pi, len(problems))
                for pi, chunk in enumerate(paginator.chunkify(problems, 10))
            ]
            paginator.paginate(self.bot,
                               ctx.channel,
                               pages,
                               wait_time=5 * 60,
                               set_pagenum_footers=True)
Example #10
0
    async def ranklist(self, ctx, contest_id: int, *handles: str):
        """Shows ranklist for the contest with given contest id. If handles contains
        '+server', all server members are included. No handles defaults to '+server'.
        """

        contest = cf_common.cache2.contest_cache.get_contest(contest_id)
        wait_msg = None
        try:
            ranklist = cf_common.cache2.ranklist_cache.get_ranklist(contest)
        except cache_system2.RanklistNotMonitored:
            if contest.phase == 'BEFORE':
                raise ContestCogError(f'Contest `{contest.id} | {contest.name}` has not started')
            wait_msg = await ctx.send('Please wait...')
            ranklist = await cf_common.cache2.ranklist_cache.generate_ranklist(contest.id,
                                                                               fetch_changes=True)

        handles = set(handles)
        if not handles:
            handles.add('+server')
        if '+server' in handles:
            handles.remove('+server')
            guild_handles = [handle for discord_id, handle
                             in cf_common.user_db.get_handles_for_guild(ctx.guild.id)]
            handles.update(guild_handles)
        handles = await cf_common.resolve_handles(ctx, self.member_converter, handles, maxcnt=None)

        handle_standings = []
        for handle in handles:
            try:
                standing = ranklist.get_standing_row(handle)
            except rl.HandleNotPresentError:
                continue

            # Database has correct handle ignoring case, update to it
            # TODO: It will throw an exception if this row corresponds to a team. At present ranklist doesnt show teams.
            # It should be fixed in https://github.com/cheran-senthil/TLE/issues/72
            handle=standing.party.members[0].handle
            handle_standings.append((handle, standing))

        if not handle_standings:
            raise ContestCogError(f'None of the handles are present in the ranklist of `{contest.name}`')

        handle_standings.sort(key=lambda data: data[1].rank)
        deltas = None
        if ranklist.is_rated:
            deltas = [ranklist.get_delta(handle) for handle, standing in handle_standings]

        problem_indices = [problem.index for problem in ranklist.problems]
        pages = self._make_standings_pages(contest, problem_indices, handle_standings, deltas)

        if wait_msg:
            try:
                await wait_msg.delete()
            except:
                pass

        await ctx.send(embed=self._make_contest_embed_for_ranklist(ranklist))
        paginator.paginate(self.bot, ctx.channel, pages, wait_time=_STANDINGS_PAGINATE_WAIT_TIME)
Example #11
0
    async def vc(self, ctx, *args: str):
        """Recommends a contest based on Codeforces rating of the handle provided.
        e.g ;vc mblazev c1729 +global +hello +goodbye +avito"""
        markers = [x for x in args if x[0] == '+']
        handles = [x for x in args if x[0] != '+'] or ('!' + str(ctx.author), )
        handles = await cf_common.resolve_handles(ctx,
                                                  self.converter,
                                                  handles,
                                                  maxcnt=25)
        info = await cf.user.info(handles=handles)
        contests = cf_common.cache2.contest_cache.get_contests_in_phase(
            'FINISHED')

        if not markers:
            divr = sum(user.effective_rating for user in info) / len(handles)
            div1_indicators = ['div1', 'global', 'avito', 'goodbye', 'hello']
            markers = [
                'div3'
            ] if divr < 1600 else ['div2'] if divr < 2100 else div1_indicators

        recommendations = {
            contest.id
            for contest in contests if contest.matches(markers)
            and not cf_common.is_nonstandard_contest(contest) and not any(
                cf_common.is_contest_writer(contest.id, handle)
                for handle in handles)
        }

        # Discard contests in which user has non-CE submissions.
        visited_contests = await cf_common.get_visited_contests(handles)
        recommendations -= visited_contests

        if not recommendations:
            raise CodeforcesCogError('Unable to recommend a contest')

        recommendations = list(recommendations)
        random.shuffle(recommendations)
        contests = [
            cf_common.cache2.contest_cache.get_contest(contest_id)
            for contest_id in recommendations[:25]
        ]

        def make_line(c):
            return f'[{c.name}]({c.url}) {cf_common.pretty_time_format(c.durationSeconds)}'

        def make_page(chunk):
            str_handles = '`, `'.join(handles)
            message = f'Recommended contest(s) for `{str_handles}`'
            vc_str = '\n'.join(make_line(contest) for contest in chunk)
            embed = discord_common.cf_color_embed(description=vc_str)
            return message, embed

        pages = [make_page(chunk) for chunk in paginator.chunkify(contests, 5)]
        paginator.paginate(self.bot,
                           ctx.channel,
                           pages,
                           wait_time=5 * 60,
                           set_pagenum_footers=True)
Example #12
0
 async def recent(self, ctx):
     data = cf_common.user_db.get_recent_duels()
     pages = self._paginate_duels(data, 'list of recent duels',
                                  ctx.guild.id, True)
     paginator.paginate(self.bot,
                        ctx.channel,
                        pages,
                        wait_time=5 * 60,
                        set_pagenum_footers=True)
Example #13
0
 async def _send_contest_list(self, ctx, contests, *, title, empty_msg):
     if contests is None:
         raise ContestCogError('Contest list not present')
     if len(contests) == 0:
         await ctx.send(embed=discord_common.embed_neutral(empty_msg))
         return
     pages = self._make_contest_pages(contests, title)
     paginator.paginate(self.bot, ctx.channel, pages, wait_time=_CONTEST_PAGINATE_WAIT_TIME,
                        set_pagenum_footers=True)
Example #14
0
 async def history(self, ctx, member: discord.Member = None):
     member = member or ctx.author
     data = cf_common.user_db.get_duels(member.id)
     message = discord.utils.escape_mentions(
         f'dueling history of `{member.display_name}`')
     pages = self._paginate_duels(data, message, ctx.guild.id, False)
     paginator.paginate(self.bot,
                        ctx.channel,
                        pages,
                        wait_time=5 * 60,
                        set_pagenum_footers=True)
Example #15
0
    async def fullsolve(self, ctx, *args: str):
        """Displays a list of contests, sorted by number of unsolved problems.
        Contest names matching any of the provided tags will be considered. e.g ;fullsolve +edu"""
        handle, = await cf_common.resolve_handles(ctx, self.converter, ('!' + str(ctx.author),))
        tags = [x for x in args if x[0] == '+']

        problem_to_contests = cf_common.cache2.problemset_cache.problem_to_contests
        contests = [contest for contest in cf_common.cache2.contest_cache.get_contests_in_phase('FINISHED')
                    if (not tags or contest.matches(tags)) and not cf_common.is_nonstandard_contest(contest)]

        # subs_by_contest_id contains contest_id mapped to [list of problem.name]
        subs_by_contest_id = defaultdict(set)
        for sub in await cf.user.status(handle=handle):
            if sub.verdict == 'OK':
                try:
                    contest = cf_common.cache2.contest_cache.get_contest(sub.problem.contestId)
                    problem_id = (sub.problem.name, contest.startTimeSeconds)
                    for contestId in problem_to_contests[problem_id]:
                        subs_by_contest_id[contestId].add(sub.problem.name)
                except cache_system2.ContestNotFound:
                    pass

        contest_unsolved_pairs = []
        for contest in contests:
            num_solved = len(subs_by_contest_id[contest.id])
            try:
                num_problems = len(cf_common.cache2.problemset_cache.get_problemset(contest.id))
                if 0 < num_solved < num_problems:
                    contest_unsolved_pairs.append((contest, num_solved, num_problems))
            except cache_system2.ProblemsetNotCached:
                # In case of recent contents or cetain bugged contests
                pass

        contest_unsolved_pairs.sort(key=lambda p: (p[2] - p[1], -p[0].startTimeSeconds))

        if not contest_unsolved_pairs:
            await ctx.send(f'`{handle}` has no contests to fullsolve :confetti_ball:')
            return

        def make_line(entry):
            contest, solved, total = entry
            return f'[{contest.name}]({contest.url})\N{EN SPACE}[{solved}/{total}]'

        def make_page(chunk):
            message = f'Fullsolve list for `{handle}`'
            full_solve_list = '\n'.join(make_line(entry) for entry in chunk)
            embed = discord_common.cf_color_embed(description=full_solve_list)
            return message, embed

        pages = [make_page(chunk) for chunk in paginator.chunkify(contest_unsolved_pairs, 10)]
        paginator.paginate(self.bot, ctx.channel, pages, wait_time=5 * 60, set_pagenum_footers=True)
Example #16
0
    async def stalk(self, ctx, *args):
        """Print problems solved by user sorted by time (default) or rating.
        All submission types are included by default (practice, contest, etc.)
        """
        (hardest, ), args = cf_common.filter_flags(args, ['+hardest'])
        filt = cf_common.SubFilter(False)
        args = filt.parse(args)
        handles = args or ('!' + str(ctx.author), )
        handles = await cf_common.resolve_handles(ctx, self.converter, handles)
        submissions = [
            await cf.user.status(handle=handle) for handle in handles
        ]
        submissions = [sub for subs in submissions for sub in subs]
        submissions = filt.filter_subs(submissions)

        if not submissions:
            raise CodeforcesCogError(
                'Submissions not found within the search parameters')

        if hardest:
            submissions.sort(
                key=lambda sub:
                (sub.problem.rating or 0, sub.creationTimeSeconds),
                reverse=True)
        else:
            submissions.sort(key=lambda sub: sub.creationTimeSeconds,
                             reverse=True)

        def make_line(sub):
            data = (f'[{sub.problem.name}]({sub.problem.url})',
                    f'[{sub.problem.rating if sub.problem.rating else "?"}]',
                    f'({cf_common.days_ago(sub.creationTimeSeconds)})')
            return '\N{EN SPACE}'.join(data)

        def make_page(chunk):
            title = '{} solved problems by `{}`'.format(
                'Hardest' if hardest else 'Recently', '`, `'.join(handles))
            hist_str = '\n'.join(make_line(sub) for sub in chunk)
            embed = discord_common.cf_color_embed(description=hist_str)
            return title, embed

        pages = [
            make_page(chunk)
            for chunk in paginator.chunkify(submissions[:100], 10)
        ]
        paginator.paginate(self.bot,
                           ctx.channel,
                           pages,
                           wait_time=5 * 60,
                           set_pagenum_footers=True)
Example #17
0
 async def history(self, ctx, member: discord.Member = None):
     member = member or ctx.author
     data = cf_common.user_db.get_duels(member.id)
     pages = self._paginate_duels(
         data,
         f"dueling history of {member.display_name}",
         ctx.guild.id,
         False,
     )
     paginator.paginate(
         self.bot,
         ctx.channel,
         pages,
         wait_time=5 * 60,
         set_pagenum_footers=True,
     )
Example #18
0
 async def list(self, ctx):
     """Shows all members of the server who have registered their handles and
     their Codeforces ratings.
     """
     res = cf_common.user_db.getallhandleswithrating()
     users = [(ctx.guild.get_member(int(user_id)), handle, rating)
              for user_id, handle, rating in res]
     users = [(member, handle, rating) for member, handle, rating in users
              if member is not None]
     users.sort(
         key=lambda x:
         (1
          if x[2] is None else -x[2], x[1]))  # Sorting by (-rating, handle)
     pages = _make_pages(users)
     paginator.paginate(self.bot,
                        ctx.channel,
                        pages,
                        wait_time=_PAGINATE_WAIT_TIME,
                        set_pagenum_footers=True)
Example #19
0
    async def registered(self, ctx):
        """Show the list of register contestants."""
        users = [(ctx.guild.get_member(user_id))
                 for user_id, aux in cf_common.user_db.get_contestants()]
        users = [(member, cf_common.user_db.get_handle(member.id,
                                                       ctx.guild.id))
                 for member in users if member is not None]
        users = [(member, handle) for member, handle in users
                 if handle is not None]

        _PER_PAGE = 10

        def make_page(chunk, page_num):
            style = table.Style("{:>}  {:<}  {:<}")
            t = table.Table(style)
            t += table.Header("#", "Name", "Handle")
            t += table.Line()
            for index, (member, handle) in enumerate(chunk):
                t += table.Data(
                    _PER_PAGE * page_num + index,
                    f"{member.display_name}",
                    handle,
                )

            table_str = f"```\n{t}\n```"
            embed = discord_common.cf_color_embed(description=table_str)
            return "List of contestants", embed

        if not users:
            raise DuelCogError("There are no registered contestants.")

        pages = [
            make_page(chunk, k)
            for k, chunk in enumerate(paginator.chunkify(users, _PER_PAGE))
        ]
        paginator.paginate(
            self.bot,
            ctx.channel,
            pages,
            wait_time=5 * 60,
            set_pagenum_footers=True,
        )
Example #20
0
    async def pending(self, ctx, member: discord.Member = None):
        """Shows current pending duels"""
        def make_line(entry):
            challenger, challengee = entry
            challenger = get_cf_user(challenger, ctx.guild.id)
            challengee = get_cf_user(challengee, ctx.guild.id)
            return f"[{challenger.handle}]({challenger.url}) vs [{challengee.handle}]({challengee.url})"

        def make_page(chunk):
            message = f"List of pending matches:"
            log_str = "\n".join(make_line(entry) for entry in chunk)
            embed = discord_common.cf_color_embed(description=log_str)
            return message, embed

        status = cf_common.user_db.get_tour_status()
        if status == 0:
            raise DuelCogError(f"Tournament is not going on :/")
        global curr_tour
        index = cf_common.user_db.get_tour_index()
        await get_tour(index)
        matches = await curr_tour.get_matches(force_update=True)
        data = []
        for match in matches:
            if match.state == "open":
                player1 = await curr_tour.get_participant(match.player1_id)
                player2 = await curr_tour.get_participant(match.player2_id)
                data.append((player1.misc, player2.misc))

        if not data:
            raise DuelCogError("There are no pending matches.")

        pages = [make_page(chunk) for chunk in paginator.chunkify(data, 7)]
        paginator.paginate(
            self.bot,
            ctx.channel,
            pages,
            wait_time=5 * 60,
            set_pagenum_footers=True,
        )
Example #21
0
    async def ranklist(self, ctx, contest_id: int, *handles: str):
        """Shows ranklist for the contest with given contest id. If handles contains
        '+server', all server members are included. No handles defaults to '+server'.
        """

        contest = cf_common.cache2.contest_cache.get_contest(contest_id)
        wait_msg = None
        try:
            ranklist = cf_common.cache2.ranklist_cache.get_ranklist(contest)
        except cache_system2.RanklistNotMonitored:
            if contest.phase == "BEFORE":
                raise ContestCogError(
                    f"Contest `{contest.id} | {contest.name}` has not started")
            wait_msg = await ctx.send("Please wait...")
            ranklist = await cf_common.cache2.ranklist_cache.generate_ranklist(
                contest.id, fetch_changes=True)

        handles = set(handles)
        if not handles:
            handles.add("+server")
        if "+server" in handles:
            handles.remove("+server")
            guild_handles = [
                handle for discord_id, handle in
                cf_common.user_db.get_handles_for_guild(ctx.guild.id)
            ]
            handles.update(guild_handles)
        handles = await cf_common.resolve_handles(ctx,
                                                  self.member_converter,
                                                  handles,
                                                  maxcnt=None)

        handle_standings = []
        for handle in handles:
            try:
                standing = ranklist.get_standing_row(handle)
            except rl.HandleNotPresentError:
                continue
            handle_standings.append((handle, standing))

        if not handle_standings:
            raise ContestCogError(
                f"None of the handles are present in the ranklist of `{contest.name}`"
            )

        handle_standings.sort(key=lambda data: data[1].rank)
        deltas = None
        if ranklist.is_rated:
            deltas = [
                ranklist.get_delta(handle)
                for handle, standing in handle_standings
            ]

        problem_indices = [problem.index for problem in ranklist.problems]
        pages = self._make_standings_pages(contest, problem_indices,
                                           handle_standings, deltas)

        if wait_msg:
            try:
                await wait_msg.delete()
            except:
                pass

        await ctx.send(embed=self._make_contest_embed_for_ranklist(ranklist))
        paginator.paginate(
            self.bot,
            ctx.channel,
            pages,
            wait_time=_STANDINGS_PAGINATE_WAIT_TIME,
        )
Example #22
0
    async def ranklist(self, ctx, contest_id: int, *handles: str):
        """Shows ranklist for the contest with given contest id. If handles contains
        '+server', all server members are included. No handles defaults to '+server'.
        """

        contest = cf_common.cache2.contest_cache.get_contest(contest_id)
        wait_msg = None
        try:
            ranklist = cf_common.cache2.ranklist_cache.get_ranklist(contest)
            deltas_status = 'Predicted'
        except cache_system2.RanklistNotMonitored:
            if contest.phase == 'BEFORE':
                raise ContestCogError(
                    f'Contest `{contest.id} | {contest.name}` has not started')
            wait_msg = await ctx.send('Please wait...')
            ranklist = await cf_common.cache2.ranklist_cache.generate_ranklist(
                contest.id, fetch_changes=True)
            deltas_status = 'Final'

        handles = set(handles)
        if not handles:
            handles.add('+server')
        if '+server' in handles:
            handles.remove('+server')
            guild_handles = [
                handle for discord_id, handle in
                cf_common.user_db.get_handles_for_guild(ctx.guild.id)
            ]
            handles.update(guild_handles)
        handles = await cf_common.resolve_handles(ctx,
                                                  self.member_converter,
                                                  handles,
                                                  maxcnt=256)

        handle_standings = []
        for handle in handles:
            try:
                standing = ranklist.get_standing_row(handle)
            except rl.HandleNotPresentError:
                continue
            handle_standings.append((handle, standing))

        if not handle_standings:
            raise ContestCogError(
                f'None of the handles are present in the ranklist of `{contest.name}`'
            )

        handle_standings.sort(key=lambda data: data[1].rank)
        deltas = None
        if ranklist.is_rated:
            deltas = [
                ranklist.get_delta(handle)
                for handle, standing in handle_standings
            ]

        problem_indices = [problem.index for problem in ranklist.problems]
        pages = self._make_standings_pages(contest, problem_indices,
                                           handle_standings, deltas)

        embed = discord_common.cf_color_embed(title=contest.name,
                                              url=contest.url)
        phase = contest.phase.capitalize().replace('_', ' ')
        embed.add_field(name='Phase', value=phase)
        if ranklist.is_rated:
            embed.add_field(name='Deltas', value=deltas_status)

        if wait_msg:
            try:
                await wait_msg.delete()
            except:
                pass

        await ctx.send(embed=embed)
        paginator.paginate(self.bot,
                           ctx.channel,
                           pages,
                           wait_time=_STANDINGS_PAGINATE_WAIT_TIME)