async def unmute_member(self, ctx, member: discord.Member): """Unmutes a member by removing their `Muted` role. .. Note:: Requires `Manage Roles` privilege. .. Note:: A `Muted` role must exist with the proper permissions. It's a simple role that can only read the channels and not send messages. :param ctx: The invocation context. :param member: """ user = DiscordUser(ctx.author) role = discord.utils.find(lambda r: r.name == 'Muted', ctx.guild.roles) if not role: embed = quickembed.error(desc='`Muted` role does not exist', user=user) elif role in member.roles: await member.remove_roles(role) embed = quickembed.success(desc='Unmuted {}'.format(member), user=user) else: embed = quickembed.error( desc='{} is already unmuted'.format(member), user=user) await ctx.send(embed=embed)
async def update_guild_prefix(self, ctx, prefix): """Updates the command prefix for the Discord server. .. Note:: Requires `administrator` privilege. :param ctx: The invocation context. :param prefix: The command prefix to update to. """ user = DiscordUser(ctx.author) if len(prefix) > 3: embed = quickembed.error( desc='Prefix can not be longer than 3 characters', user=user) else: user.update_guild_info(ctx.guild, prefix) stored_prefix = user.guild_info(ctx.guild.id)['prefix'] if prefix == stored_prefix: embed = quickembed.success( desc='Prefix updated to **{}**'.format(stored_prefix), user=user, ) else: embed = quickembed.error(desc='Failed to update prefix', user=user) await ctx.send(embed=embed)
async def register_user(self, ctx): """Registers the Discord user and provides a response. If the user is already registered, they will be notified. Otherwise, a confirmation request is created before registering the account. The user will have 15 seconds to respond with a `[Y/N]`. If `[Y]`, the account will attempt to register, the response is then delivered. If `[N]`, the request is cancelled. :param ctx: The invocation context. """ embed = None user = DiscordUser(ctx.author) if user.is_registered(): embed = quickembed.success( desc='Your Discord is already registered', user=user) else: text_question = ( '[Y/N]\nYour Discord is not linked to an existing ' 'Matches account (http://idleuser.com/projects/matches)\n' 'Would you like to register a new account?') embed_question = quickembed.question(user=user, desc=text_question) await ctx.send(embed=embed_question) confirm = await self.bot.wait_for('message', check=checks.confirm(ctx.author), timeout=15.0) confirm.content = confirm.content.upper() if confirm.content == 'Y': response = user.register() if response['success']: user.refresh() embed = quickembed.success(desc=response['message'], user=user) logger.info('`{}` registered'.format(user.username)) else: embed = quickembed.error(desc=response['message'], user=user) logger.warning('`{}` failed to register - {}'.format( user.username, response['message'])) elif confirm.content == 'N': embed = quickembed.error(user=user, desc='Account registration cancelled') if embed: await ctx.send(embed=embed)
async def user_join_royalrumble(self, ctx): """TODO: Enters the user into the current Royal Rumble event by providing them an entry number. :param ctx: The invocation context. """ user = DiscordUser(ctx.author) response = user.join_royalrumble() if response['success']: embed = quickembed.success(desc='Entry Number: `{}`'.format( response['message']), user=user) else: embed = quickembed.error(desc=response['message'], user=user) await ctx.send(embed=embed)
async def rate_match(self, ctx, *args): """Adds a 0-5 star rating to a `Match`. .. Note: If no `match_id` is provided, the rating will be added to the most recently closed `Match`. :param ctx: The invocation context. :param args: Must be either `[rating]` or `[match_id] [rating]`. Rating must be between 0-5. :return: """ user = DiscordUser(ctx.author) try: if len(args) == 1: match_id = None rating = float(args[0]) else: match_id = int(args[0]) rating = float(args[1]) except Exception: msg = ('Invalid `!rate` command\n' '`!rate [rating]` (rates last match)\n' '`!rate [match_id] [rating]`') embed = quickembed.error(desc=msg, user=user) await ctx.send(embed=embed) return if not match_id: rows = user.search_match_by_recent_completed() if not rows: msg = 'No current match set to rate' embed = quickembed.error(desc=msg, user=user) await ctx.send(embed=embed) return match_id = rows[0].id response = user.rate_match(match_id, rating) if response['success']: match = Match(match_id) stars = '' for i in range(1, 6): if rating >= i: stars += '★' else: stars += '☆' msg = 'Rated `Match {}` {} ({})\n{}'.format( match_id, stars, rating, match.info_text_short()) embed = quickembed.success(desc=msg, user=user) else: msg = response['message'] embed = quickembed.error(desc=msg, user=user) await ctx.send(embed=embed)
async def user_reset_password_link(self, ctx): """Sends a reset password link for the website to the user through DM. .. note:: This bypasses the login credentials by using a temporary password. The temporary password is only valid for resetting the account's password. It expires once the password has changed or 5 minutes has passed. :param ctx: The invocation context. """ user = DiscordUser(ctx.author) link = user.request_reset_password_link() msg = '<{}>\n(link expires in 5 minutes)'.format(link) await ctx.author.send(embed=quickembed.general(desc=msg, user=user)) embed = quickembed.success(user=user, desc='Link DMed') await ctx.send(embed=embed)
async def user_login_link(self, ctx): """Sends a quick login link for the website to the user through DM. .. note:: This bypasses the website login by using a temporary token. The token expires once the link is used or 5 minutes has passed. :param ctx: The invocation context. """ user = DiscordUser(ctx.author) link = user.request_login_link() msg = 'Quick login link for you! (link expires in 5 minutes)\n<{}>'.format( link) await ctx.author.send(embed=quickembed.general(desc=msg, user=user)) embed = quickembed.success(user=user, desc='Login link DMed') await ctx.send(embed=embed)
async def add_discord_command(self, ctx, command, *, response): """Inserts a quick chatroom command. :param ctx: The invocation context. :param command: The command name to add. :param response: The response for the command. """ user = DiscordUser(ctx.author) command = '!{}'.format(command.strip('!')) res = user.add_chatroom_command(command, response) if res['success']: embed = quickembed.success( desc='Command `{}` updated'.format(command), user=user) else: embed = quickembed.error(desc='Failed', user=user) await ctx.send(embed=embed)
async def royalrumble_info(self, ctx): """Provides a quick login link to the Matches website's Royal Rumble page through DM. .. Note: The hyperlink can only be used once and within a short time frame before it expires. :param ctx: The invocation context. """ # response = user.royalrumble_info() # TODO: check if available to enter user = DiscordUser(ctx.author) link = user.request_login_link() link = link.replace('projects/matches?', 'projects/matches/royalrumble?') msg = 'Join the rumble here! (link expires in 5 minutes)\n<{}>'.format( link) await ctx.author.send(embed=quickembed.general(desc=msg, user=user)) embed = quickembed.success(user=user, desc='Rumble link DMed ;)') await ctx.send(embed=embed)
async def update_discord_command(self, ctx, command, *, response): """Updates a quick chatroom command. .. Note:: Only the bot owner can use this. :param ctx: The invocation context. :param command: The command name to update. :param response: The updated response for the command. """ user = DiscordUser(ctx.author) command = '!{}'.format(command.strip('!')) res = user.update_chatroom_command(command, response) if res['success']: embed = quickembed.success( desc='Command `{}` updated'.format(command), user=user) else: embed = quickembed.error(desc='Failed', user=user) await ctx.send(embed=embed)
async def report(self, ctx, member: discord.Member, *, reason='no reason provided'): """Reports another user to the bot owner. This sends an alert to the bot owner through a log channel defined in :mod:`config`. .. note:: This should be used sparingly. If the Discord server has a lot of users, this may get annoying. :param ctx: The invocation context. :param member: The Discord user being reported. :param reason: The reason for reporting the Discord user. """ msg = '[#{}]\n{} reported {}\nReason: {}'.format( ctx.channel, ctx.author, member, reason) embed = quickembed.success(desc=msg, user=DiscordUser(ctx.author)) self.bot.log('@here', embed=embed) await ctx.send(embed=embed)
async def donate_bucks(self, ctx, amount: int, member: discord.Member): """Sends another user FJBucks from their own wallet. .. Important:: Work in progress. :param ctx: The invocation context. :param amount: The amount of FJBucks to send :param member: The Discord member to send to. """ user = DiscordUser(ctx.author) recipient = DiscordUser(member) if not recipient.is_registered(): embed = quickembed.error(desc='{} is not registered'.format( recipient.name), user=user) else: recipient.fjbucks_transaction(amount, 'owner authorized') embed = quickembed.success( desc='Donated **{} FJBucks** to {}'.format( amount, recipient.name), user=user, ) await ctx.send(embed=embed)
async def place_match_bet(self, ctx, *args): """Places a `Match` bet. .. Note: A bet requires: * The `bet amount` * The `match_id` * The `team` The user can provide them sequentially: !bet [bet_amount] [match_id] [team] Or they can insert a `Superstar`'s name (`Match` contestant): !bet [bet_amount] [contestant] The `match_id` and `team` is found by cross-referencing the `Superstar` name with open-bet `Match` contestants. :param ctx: The invocation context. :param args: Must be either `[bet_amount] [match_id] [team]` or `[bet_amount] [contestant]` """ user = DiscordUser(ctx.author) bet = None match_id = None team = None superstar_name = None try: bet = int(args[0].replace(',', '')) if len(args) == 3 and args[1].isdigit() and args[2].isdigit(): match_id = int(args[1]) team = int(args[2]) elif len(args) > 1: superstar_name = ' '.join(args[1:]) rows = user.search_match_by_open_bets_and_superstar_name( superstar_name) match_id = rows[ 0].id if rows else False # use first match found if not match_id: embed = quickembed.error( desc='Unable to find an open match for contestant `{}`' .format(superstar_name), user=user, ) await ctx.send(embed=embed) return else: raise except Exception as e: logger.debug('place_match_bet: {}'.format(e)) msg = ('Invalid `!bet` command\n' '`!bet [bet_amount] [contestant]`\n' '`!bet [bet_amount] [match_id] [team]`') await ctx.send(embed=quickembed.error(desc=msg, user=user)) return match = Match(match_id) if not team and superstar_name: team = match.team_by_contestant(superstar_name) response = user.validate_bet(match_id, team, bet) if response['success']: question_embed = quickembed.question(desc='[Y/N] Place this bet?', user=user) question_embed.add_field(name='Info', value=match.info_text_short(), inline=False) question_embed.add_field(name='Betting', value='{:,}'.format(bet), inline=True) question_embed.add_field(name='Betting On', value=match.teams[team]['members'], inline=True) await ctx.send(embed=question_embed) confirm = await self.bot.wait_for('message', check=checks.confirm(ctx.author), timeout=15.0) confirm.content = confirm.content.upper() if confirm.content == 'Y': response = user.place_bet(match_id, team, bet) if response['success']: msg = 'Placed `{:,}` point bet on `{}`'.format( bet, match.teams[team]['members']) embed = quickembed.success(desc=msg, user=user) else: embed = quickembed.error(desc=response['message'], user=user) elif confirm.content == 'N': embed = quickembed.error(desc='Bet cancelled', user=user) else: embed = quickembed.error(desc=response['message'], user=user) await ctx.send(embed=embed)