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.')
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.')
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.' )
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