Example #1
0
    async def toggleprivaterank(self, ctx: SlashContext, programme: str = None, year: int = None):
        user = ctx.author
        user_id = str(user.id)

        if year is None:
            year = constants.current_year

        async with (await self.bot.get_db_conn()).acquire() as connection:
            ranks = ranks_service.RanksService(connection)

            if programme is None and await ranks.get_has_only_one_rank(user_id, year):
                is_private = await ranks.get_is_private(user_id, year)
                await ranks.set_is_private(user_id, not is_private, year)
            else:
                if programme is None:
                    await ctx.send(user.mention + ' Please specify the programme of the rank you wish to '
                                                  'toggle the visibility of.')
                    return

                is_private = await ranks.get_is_private_programme(user_id, programme, year)
                if is_private is None:
                    await ctx.send(user.mention + ' You haven\'t set your ranking number for this programme yet.')
                    return

                await ranks.set_is_private_programme(user_id, not is_private, programme, year)

            await ctx.send(user.mention + f' Your rank is {"no longer" if is_private else "now"} hidden from `.ranks`')
    async def ranks(self, ctx: SlashContext, year: int = None, public: bool = False):

        if year is None:
            year = constants.current_year

        async with (await self.bot.get_db_conn()).acquire() as connection:
            ranks = ranks_service.RanksService(connection)
            grouped_ranks = await ranks.get_top_ranks(year)

        is_bot_channel = not ctx.guild or 'bot' in ctx.channel.name
        if is_bot_channel:
            public = True

        group_truncated = {}

        if not is_bot_channel:
            for i in range(len(grouped_ranks)):
                group_name = grouped_ranks[i][0]
                truncated_list = grouped_ranks[i][1][:10]
                group_truncated[group_name] = len(grouped_ranks[i][1]) - 10
                grouped_ranks[i] = (group_name, truncated_list)

        embed_dict = dict()

        for group in grouped_ranks:
            programme = programmes_helper.programmes[group[0]]
            group_name = f'**{programme.icon} {programme.uni_name}\n{programme.display_name.ljust(33, " ")}**'
            group_list = list(('`' + (' ' * (3 - len(str(x[1])))) + str(x[1]) + f' {x[0]}`')
                              for x in group[1])
            if not is_bot_channel and group_truncated[group[0]] > 0:
                group_list.append(f'\n**_+ {group_truncated[group[0]]} more..._**')

            embed_dict[group_name] = group_list

        embed = discord.Embed(title=f"Ranking numbers ({year})", color=0x36bee6)

        embed.add_field(name='Note: Not everyone in this list has received an offer.',
                        value='To view the highest known ranking numbers with offers, use `/offers`.',
                        inline=False)

        build_embed_groups(embed, embed_dict)

        if any(x > 0 for x in group_truncated.values()):
            embed.add_field(name='**_List is truncated_**',
                            value='To view the full list, please use this command in a bot channel, such as '
                                  '<#556533405794172939>\n',
                            inline=False)

        embed.add_field(name='To set your ranking number, use `/setrank`.',
                        value='_Please note: This command is purely for fun, the ranking numbers do not'
                              ' represent performance at university_',
                        inline=False)

        await ctx.send(embed=embed, hidden=not public)
    async def addmanualdate(self,
                            ctx: SlashContext,
                            programme: str,
                            rank: int,
                            day: int,
                            month: int,
                            source: str = None,
                            year: int = None):
        user = ctx.author

        if not ctx.guild:
            await ctx.send(
                user.mention +
                ' You don\'t have permission to execute this command via DM')
            return

        if not source:
            source = 'manual'

        if year is None:
            year = constants.current_year

        async with (await self.bot.get_db_conn()).acquire() as connection:
            ranks = ranks_service.RanksService(connection)

            tr = connection.transaction()
            await tr.start()

            try:
                offer_date = date(year, month, day)
                await ranks.add_rank(rank,
                                     programme,
                                     year,
                                     offer_date=offer_date,
                                     source=source)

                if rank <= programmes_helper.programmes[programme].places[year]:
                    raise DateIncorrectError

                await tr.commit()
                await ctx.send(user.mention + ' Rank and offer date added.')

            except DateIncorrectError:
                await tr.rollback()
                await ctx.send(
                    user.mention +
                    ' There\'s no need to set this offer date as this rank is '
                    'within the programme limit.')
            except ValueError:
                await tr.rollback()
                await ctx.send(user.mention + ' Invalid command arguments.')
            except:
                await tr.rollback()
                raise
    async def deleterank(self, ctx: SlashContext, programme: str, year: int):
        user = ctx.author

        if programme == 'all':
            programme = None

        async with (await self.bot.get_db_conn()).acquire() as connection:
            ranks = ranks_service.RanksService(connection)

            await ranks.delete_rank(str(user.id), programme, year)

        await ctx.send(user.mention + ' Rank deleted.')
Example #5
0
    async def setrank(self,
                      ctx: SlashContext,
                      rank: int,
                      programme: str,
                      year: int = None):
        user = ctx.author
        user_id = str(user.id)

        if year is None:
            year = constants.current_year

        async with (await self.bot.get_db_conn()).acquire() as connection:
            ranks = ranks_service.RanksService(connection)
            users = user_data_service.UserDataService(connection)

            tr = connection.transaction()
            await tr.start()

            try:
                try:
                    await ranks.add_rank(rank,
                                         programme,
                                         year,
                                         user_id,
                                         source='command')
                except ValueError:
                    await ctx.send(user.mention +
                                   ' Invalid command arguments.')
                    await tr.rollback()
                    return
                except EntryAlreadyExistsError:
                    await ctx.send(
                        user.mention +
                        ' You have already set your ranking number. To set a different one, '
                        'clear it using `/clearrank` and try setting it again.'
                    )
                    await tr.rollback()
                    return

                await users.add_user(user_id, user.name)

            except:
                await tr.rollback()
                raise

            await tr.commit()
        await ctx.send(user.mention + ' Rank set.')
    async def setofferdate(self,
                           ctx: SlashContext,
                           day: int,
                           month: int,
                           programme: str,
                           year: int = None):
        if year is None:
            year = constants.current_year

        user = ctx.author

        try:
            offer_date = date(year, month, day)
        except ValueError:
            await ctx.send(user.mention + ' Invalid command arguments.')
            return

        async with (await self.bot.get_db_conn()).acquire() as connection:
            ranks = ranks_service.RanksService(connection)

            try:
                await ranks.set_offer_date(str(user.id), programme, offer_date,
                                           year)
            except EntryNotFoundError:
                await ctx.send(
                    user.mention +
                    ' Before setting an offer date, please set your rank first using '
                    '`/setrank`')
                return
            except DateIncorrectError:
                await ctx.send(
                    user.mention +
                    ' There\'s no need to set the offer date as your rank is within the '
                    'programme limit.')
                return

        await ctx.send(user.mention + ' Offer date set. Thank you.')
Example #7
0
    async def setrank(self,
                      ctx: SlashContext,
                      rank: int,
                      programme: str,
                      year: int = None):
        user = ctx.author
        user_id = str(user.id)

        if year is None:
            year = constants.current_year

        async with (await self.bot.get_db_conn()).acquire() as connection:
            ranks = ranks_service.RanksService(connection)
            users = user_data_service.UserDataService(connection)

            curr_rank_details = await ranks.get_rank_details_for_programme_and_user(
                programme, year, user_id)

            if curr_rank_details:
                curr_rank, curr_is_private = curr_rank_details
                if rank == curr_rank:
                    if not curr_is_private:
                        await ctx.send(
                            user.mention +
                            ' You have already set your ranking number. It can be seen via `/ranks`. '
                            'If you\'re trying to set an offer date, use `/setofferdate`.'
                        )
                    else:
                        await ranks.set_is_private_programme(
                            user_id, False, programme, year)
                        await ctx.send(
                            user.mention +
                            ' You have already set your ranking number, but it was private (you\'ve likely '
                            'set it by replying to a direct message by the bot).\nIt has now been made '
                            'visible and you can see it via `/ranks`. '
                            'If you want to make it private again, you can use `/toggleprivaterank`.\n'
                            'If you\'re trying to set an offer date, you can use `/setofferdate`.'
                        )
                else:
                    if not curr_is_private:
                        await ctx.send(
                            user.mention +
                            f' You have already set a different ranking number (**{curr_rank}**). '
                            'To change it, first clear the old one using `/clearrank` and then try setting '
                            'the new one again.')
                    else:
                        await ctx.send(
                            user.mention +
                            ' You have already set a different ranking number, but it is private (you\'ve '
                            'likely set it by replying to a direct message by the bot). '
                            'To change it, first clear the old one using `/clearrank` and then try setting '
                            'the new one again.')

                return

            tr = connection.transaction()
            await tr.start()

            try:
                try:
                    await ranks.add_rank(rank,
                                         programme,
                                         year,
                                         user_id,
                                         source='command')
                except ValueError:
                    await ctx.send(user.mention +
                                   ' Invalid command arguments.')
                    await tr.rollback()
                    return
                except EntryAlreadyExistsError:
                    await ctx.send(
                        user.mention +
                        ' You have already set your ranking number. To set a different one, '
                        'clear it using `/clearrank` and try setting it again.'
                    )
                    await tr.rollback()
                    return

                await users.add_user(user_id, user.name)

            except:
                await tr.rollback()
                raise

            await tr.commit()
        await ctx.send(
            user.mention +
            ' Your ranking number was successfully added. It is now set as public and can be '
            'seen via `/ranks`. If you want to make it private, you can use '
            '`/toggleprivaterank.`\n'
            'If you have received an offer, please use `/setofferdate` to set it.'
        )
Example #8
0
    async def import_ranks_from_csv(self, csv_data: str, source: str,
                                    all_members):
        """
        This method imports data into "ranks" in the following format:
        programme_id(str),ranking_number(int),offer_date(dd/mm),year(int),is_private(bool),discord_tag(Optional;User#1234)
        :param csv_data: The rows of the CSV, separated by '\n'
        :param all_members: bot.get_all_members()
        :param source: data source
        :return: None
        """

        ranks = ranks_service.RanksService(self.db_conn)
        users = user_data_service.UserDataService(self.db_conn)

        rows = csv_data.split('\n')

        i = 0
        skipped = 0
        unknown_user = 0
        inserted = 0
        for row_str in rows:
            if len(row_str) == 0:
                continue

            try:
                i += 1
                row = row_str.split(',')

                programme = programmes_helper.programmes[row[0]]
                ranking_number = int(row[1])
                offer_date_arr = row[2].split('/')
                offer_date = offer_date_util.parse_offer_date(
                    offer_date_arr[0], offer_date_arr[1])
                year = int(row[3])
                is_private = row[4].lower() == 'true'
                discord_tag = row[5].split('#') if len(row[4]) > 0 else None

                # If the ranking number is below the programme limit and discord_tag is null, do not import it
                if ranking_number <= programme.places[
                        year] and discord_tag is None:
                    skipped += 1
                    continue

                discord_id = None

                # If discord_tag is not null, try to find the user id using the Discord API
                if discord_tag is not None:
                    user = get(all_members,
                               name=discord_tag[0],
                               discriminator=discord_tag[1])

                    if user:
                        discord_id = str(user.id)
                        await users.add_user(discord_id, user.name)
                    else:
                        print("Can't find user " + row[4])
                        unknown_user += 1
                        if ranking_number <= programme.places[year]:
                            skipped += 1
                            continue

                try:
                    await ranks.add_rank(
                        ranking_number, programme.id, year, discord_id,
                        offer_date if ranking_number > programme.places[year]
                        else None, source, is_private)
                except EntryAlreadyExistsError:
                    skipped += 1
                    continue

                inserted += 1

            except Exception as inner:
                raise RuntimeError(
                    f'An exception occurred while processing row {i}'
                ) from inner

        return inserted, skipped, unknown_user