async def unmonitor(self, ctx, mention): """Admin command: unmonitor a user. Args: ctx (Context) mention (Member) Returns: None """ target_user = ctx.message.mentions[0] if not is_admin(ctx.author): if ctx.author == target_user: notifications_channel = find_channel(ctx.guild, CONFIG['NotificationsChannel']) cap(ctx, ctx.author) await ctx.send("`!unmonitor`: This is an admin-only command. {} has been capped for trying to use it.".format(ctx.author.display_name)) await notifications_channel.send('{} was capped by the `!unmonitor` command!') return if len(ctx.message.mentions) == 0: await ctx.send("`!unmonitor`: The user to be monitored must be @-mentioned as the first argument.") return if target_user in CONFIG['DATA']['monitor']: unwatch(ctx, target_user) await ctx.send('`!unmonitor`: {} has been removed from watch.'.format(target_user.display_name)) CONFIG['DATA']['monitor'].remove(target_user) save_data(CONFIG['DATAFILE']) else: await ctx.send('`!unmonitor`: {} is not on watch.'.format(target_user.display_name))
async def setname(self, ctx, user, *, name): """Mod command: change a user's nickname on this server. Args: user (Member): The user whose nickname will be updated. name (String): String to which to set the user's nickname. """ if is_admin(ctx.author) or is_mod(ctx.author): if len(ctx.message.mentions) == 0: await ctx.send( "`!setname`: The user whose name you wish to change must be mentioned as the first argument." ) return target_user = ctx.message.mentions[0] old_name = target_user.display_name await target_user.edit(nick=name) await send_notification( ctx.guild, "{} updated {}'s nickname to {}!".format( ctx.author.display_name, old_name, name)) else: await ctx.send( "`!setname`: You do not have the privileges to use this command." )
async def crap(self, ctx, mention, *, reason='no reason'): """Admin command: Crap a mentioned user. Args: mention (User) The user to crap. Returns: None """ if not is_admin(ctx.author): await ctx.send('No.') return if len(ctx.message.mentions) == 0: await ctx.send("`!crap`: The user to be crapped must be @-mentioned as the first argument.") return target_user = ctx.message.mentions[0] crap_role = find_role(ctx.guild, CONFIG['CrapRole']) notifications_channel = find_channel(ctx.guild, CONFIG['NotificationsChannel']) if not crap_role: await ctx.send('`!crap`: There was an error attempting to crap {}.'.format(target_user.display_name)) return if user_has_role(target_user, CONFIG['CrapRole']): await ctx.send('`!crap`: {} has been double-crapped!'.format(target_user.display_name)) else: await target_user.add_roles(crap_role) await ctx.send('💩💩💩') await notifications_channel.send('{} has been crapped for {}'.format( target_user.display_name, reason))
async def uncrap(self, ctx, mention): """Admin command: Uncrap a mentioned user. Args: mention (User) The user to uncrap. Returns: None """ if not is_admin(ctx.author): await ctx.send('Nope.') return if len(ctx.message.mentions) == 0: await ctx.send("`!uncrap`: The user to be uncrapped must be @-mentioned as the first argument.") return target_user = ctx.message.mentions[0] crap_role = find_role(ctx.guild, CONFIG['CrapRole']) notifications_channel = find_channel(ctx.guild, CONFIG['NotificationsChannel']) if not crap_role: await ctx.send('`!uncrap`: There was an error attempting to uncrap {}.'.format(target_user.display_name)) return if user_has_role(target_user, CONFIG['CrapRole']): await target_user.remove_roles(crap_role) await ctx.send('🚫💩') await notifications_channel.send('{} has been uncrapped.'.format(target_user.display_name)) else: await ctx.send('`!uncrap`: {} doesn\'t appear to be crapped.'.format(target_user.display_name))
async def uncap(self, ctx, mention): """Mod command: Remove the dunce cap from a mentioned user. Args: mention (User) The user to uncap. Returns: None """ if len(ctx.message.mentions) == 0: await ctx.send( "`!uncap`: The user to be uncapped must be @-mentioned as the first argument." ) return target_user = ctx.message.mentions[0] cap_role = find_role(ctx.guild, CONFIG['CapRole']) staff_channel = find_channel(ctx.guild, CONFIG['StaffChannel']) notifications_channel = find_channel(ctx.guild, CONFIG['NotificationsChannel']) if not cap_role: await ctx.send( '`!uncap`: There was an error attempting to uncap {}.'.format( target_user.mention)) return # Moderator uses !cap if is_admin(ctx.author) or is_mod(ctx.author): if not user_has_role(target_user, CONFIG['CapRole']): await ctx.send( 'Are you blind, {}? You can\'t uncap {} '.format( ctx.author.mention, target_user.display_name) + 'if they\'re not wearing the Dunce Cap!') else: await target_user.remove_roles(cap_role) await target_user.send('Your dunce cap is lifted.') await staff_channel.send('{} has been uncapped by {}!'.format( target_user.mention, ctx.author.mention)) await notifications_channel.send( '{} has been uncapped by {}!'.format( target_user.display_name, ctx.author.display_name)) return else: # Non-moderator attempts to use !uncap if not user_has_role(target_user, CONFIG['CapRole']): await ctx.send( '`!uncap`: How can you uncap someone who isn\'t ' + 'wearing a cap to begin with? Reconsider your life choices.' ) else: await ctx.send( '`!uncap`: You are not strong enough to discard the mighty cap.' )
async def write(self, ctx): """Admin command: write out current state of persistent data.""" if not is_admin(ctx.author): await ctx.send('`!write`: This is an admin-only command.') else: save_data(CONFIG['DATAFILE']) await ctx.send('`!write`: Persistent store updated.')
async def addchannel(self, ctx, name, category): """Admin command: Create a new channel with the correct permissions. Args: name (String) The name of the new channel. category(String) The name of one of the existing categories to place the new channel in. Returns: None """ if not is_admin(ctx.author): await ctx.send('`!addchannel`: Only admins may use this command.') return if not name: await ctx.send('`!addchannel`: You must specify a name for the new channel.') return if not category: await ctx.send('`!addchannel`: You must specify a category for the new channel.') return channel_list = ctx.guild.text_channels for channel in channel_list: if channel.name == name: await ctx.send('`!addchannel`: A channel with this name already exists.') return category_list = ctx.guild.categories target_category = None for cat in category_list: if cat.name == category: target_category = cat if not target_category: await ctx.send('`!addchannel`: This category could not be found.') return new_channel = await ctx.guild.create_text_channel(name, category=target_category) if not isinstance(new_channel, discord.TextChannel): await ctx.send('`!addchannel`: Unable to add new channel.') cap_role = find_role(ctx.guild, CONFIG['CapRole']) await new_channel.set_permissions(cap_role, send_messages=False) if not new_channel.overwrites_for(cap_role): await ctx.send('`!addchannel`: Cap role overwrite not effective.') await ctx.send('`!addchannel`: {} created in {}!'.format(name, category))
async def echo(self, ctx, *, message): """Admin command: make the bot say something. Args: message (String) The string to be said by the bot. Returns: None """ if is_admin(ctx.author): await ctx.message.delete() await ctx.send(message)
async def prune(self, ctx, limit=90, exec=False): """Admin command: prune users Arg: limit (Int): number of days of inactivity for pruning exec (Bool): whether or not to execute pruning Return: None """ if not is_admin(ctx.author): await ctx.send('`!prune`: Only admins may use this command.') return await ctx.send( 'Generating list of users who have not posted in {} days...'. format(limit)) month_ago = datetime.now() - timedelta(days=limit) count = Counter() for channel in ctx.guild.channels: if isinstance(channel, discord.TextChannel): async for post in channel.history(limit=None, after=month_ago): count[post.author] += 1 prune_list = [] to_prune = '' for member in ctx.guild.members: if not count[member] and not member.id in CONFIG['PruneProtect']: prune_list.append(member) to_prune += '{} [{}]\n'.format(member.display_name, member.name) await ctx.send('{} users to be pruned:\n{}'.format( len(prune_list), to_prune)) if exec: pass return
async def watchlist(self, ctx): """Admin command: list users on the watchlist.""" if not is_admin(ctx.author): await ctx.send('`!watchlist`: This is an admin-only command.') else: if CONFIG['DATA']['monitor'] == []: await ctx.send('`!watchlist`: No users currently on watch.') return else: watched = '' for member in CONFIG['DATA']['monitor']: if member == CONFIG['DATA']['monitor'][0]: watched += '{}'.format(member.display_name) else: watched += ', {}'.format(member.display_name) await ctx.send('`!watchlist`: {}'.format(watched))
async def release(self, ctx): """Claim an event channel, if it is not previously claimed.""" channel = ctx.message.channel if not CONFIG['EventChannelPrefix'] in channel.name: await ctx.send('`!release`: This command can only be used in an event channel.') return pins = await channel.pins() if not pins: await ctx.send('`!release`: This channel does not appear to have an active claim to release.') return if pins[0].author == ctx.author or is_admin(ctx.author) or is_mod(ctx.author): await pins[0].unpin() await ctx.send('{0} has released this event channel! It is now open to be claimed for other events'. format(ctx.author.display_name)) else: await ctx.send('`!release`: You do not appear to be the user who claimed this channel.') return
async def cap(self, ctx, mention, *, reason='N/A'): """Mod command: Dunce cap a mentioned user. Args: mention (User) The user to cap. Returns: None """ if len(ctx.message.mentions) == 0: await ctx.send( "`!cap`: The user to be capped must be @-mentioned as the first argument." ) return target_user = ctx.message.mentions[0] cap_role = find_role(ctx.guild, CONFIG['CapRole']) staff_channel = find_channel(ctx.guild, CONFIG['StaffChannel']) notifications_channel = find_channel(ctx.guild, CONFIG['NotificationsChannel']) if not cap_role: await ctx.send( '`!cap`: There was an error attempting to cap {}.'.format( target_user.mention)) return # Attempt to cap the Admin if is_admin(target_user): await ctx.author.add_roles(cap_role) await ctx.author.send( 'You have been dunce capped for attempting to dunce cap the admin. ' + 'While you are dunce capped, you will not be able to send messages, ' + 'but you will be able to add reactions to other users\' messages. ' + 'Your dunce cap will be removed after a certain amount of time.' ) await ctx.send( '{} has been capped for trying to cap {} - hoisted by your own petard!' .format(ctx.author.mention, target_user.mention)) await staff_channel.send( '{} has been capped for attempting to cap {}!'.format( ctx.author.mention, target_user.mention)) return # Moderator uses !cap if is_admin(ctx.author) or is_mod(ctx.author): if user_has_role(target_user, CONFIG['CapRole']): await ctx.send('`!cap`: {} is already capped!'.format( target_user.display_name)) else: await target_user.add_roles(cap_role) await ctx.send('WEE WOO WEE WOO') await target_user.send( 'You have been dunce capped for violating a rule. While you are ' + 'dunce capped, you will not be able to send messages, but you will ' + 'be able to add reactions to other users\' messages. The offending ' + 'violation must be remediated, and your dunce cap will be removed ' + 'after a certain amount of time.') await staff_channel.send( '{} has been dunce capped by {} for {}!'.format( target_user.mention, ctx.author.mention, reason)) await notifications_channel.send( '{} has been dunce capped by {}!'.format( target_user.display_name, ctx.author.display_name)) user = get_db_user(conn, cursor, target_user) if not user: cmd = '''INSERT INTO users VALUES (?, ?, 0, 0, 1)''' params = (target_user.id, target_user.name) else: cmd = '''UPDATE users SET times_capped = ? WHERE id == ?''' params = (user[4] + 1, target_user.id) cursor.execute(cmd, params) conn.commit() cmd = '''INSERT INTO notes VALUES (NULL, ?, ?, ?, ?, ?)''' params = (datetime.now(), target_user.id, target_user.name, 'cap', reason) cursor.execute(cmd, params) conn.commit() # Non-moderator uses !cap else: await ctx.send( '`!cap`: You are not worthy to wield the mighty cap.')
async def stats(self, ctx, num: int=5, range: str='month'): """Admin command: generate post stats. Args: num (Int, optional) The number of top posters to find. Defaults to 5. range (String, optional) One of {all, month}. Defaults to month. Returns: None """ if not is_admin(ctx.author): await ctx.send('`!stats`: This is an admin-only command.') return if range != 'month' and range != 'all': await ctx.send('`!stats`: Range must be `month` or `all`.') return await ctx.send('`!stats`: Calculating post statistics. This will take some time.') start_time = time() channels = ctx.guild.channels count = Counter() target_date = datetime.now() - timedelta(days=30) for channel in channels: if isinstance(channel, discord.TextChannel): if channel.category.name not in CONFIG['StatsCategories']: continue if range == 'all': async for post in channel.history(limit=None): count[post.author] += 1 elif range == 'month': async for post in channel.history(limit=None, after=target_date): count[post.author] += 1 max_name_width = 0 max_num_width = 0 top_list = count.most_common(num) for member, posts_num in top_list: first_name = member.display_name.split()[0] if first_name[-1] == ':': first_name = first_name[:-1] name_len = len(first_name) if name_len > max_name_width: max_name_width = name_len num_len = len('{}'.format(posts_num)) if num_len > max_num_width: max_num_width = num_len output_text = '' for member, posts_num in top_list: first_name = member.display_name.split()[0] if first_name[-1] == ':': first_name = first_name[:-1] output_text += '\n `{0:.<{name}}..{1:.>{num}d}`'.format( first_name, posts_num, name=max_name_width, num=max_num_width) end_time = time() time_output = 'This command executed in {:.2f} seconds'.format( end_time - start_time) if range == 'month': await ctx.send('The top posters for the past 30 days are: {} \n {}'.format( output_text, time_output)) elif range == 'all': await ctx.send('The top posters of all time are: {} \n {}'.format( output_text, time_output))