async def cleanup(ctx, target=None, history=100): start = analytics.getEventTime() if common.isDiscordRegulator(ctx.message.author) != True: return #make user input something usable first, conform outlandish commands to be sane if target is None and history is None: await discord.bot.say("Syntax: `!cleanup @mention <1-1000>` where # is last x chat messages to check per channel. Defaults to 100.") return elif target is None: await discord.bot.say("Error: You must target a user by `@mention` or raw ID.") return elif history > 1000: await discord.bot.say("Warning: This command only supports up to the last 1000 channel messages. Limiting your request to 1000.") history = 1000 else: pass #get the raw mention or just pass the ID depending on what the use supplied. member only needed for protection target_id = discord.get_targeted_id(ctx) target_member = discord.default_server.get_member(target_id) # Only use the Member lookup for Reg/Admin protection #if xiphirx = soy if target_id == discord.bot.user.id: await discord.bot.say("⚠️{0.message.author.mention} you are not allowed to cleanup after the bot!".format(ctx)) return #dont allow this to be called on regulators/administrators if target_member is not None: if common.isDiscordRegulator(target_member): logger.warn("cleanup() called and is exiting: ID:{0.message.author.id} attempted to call cleanup on ID:{1} but was denied by: IS_REGULATOR_PROTECTED".format(ctx, target_id)) await discord.bot.say("⚠️{0.message.author.mention} you are not allowed to call that on other admins/regulators!".format(ctx)) return #while this runs lets not flood the mod channel with messages deleted.IGNORE_IDS.append(target_id) await discord.bot.say("{0.message.author.mention} starting now ID:`{1}` and will @ you when task completed.".format(ctx, target_id)) logger.info("cleanup() {0.message.author.name} started deletion on ID:{1}. Checking all channels last {2} messages.".format(ctx, target_id, history)) for channel in ctx.message.server.channels: if channel.type == discord.discord.ChannelType.text: logger.info("cleanup() {0.message.author.name} started deletion on channel ID: {0.message.channel.id} for user ID:{1}".format(ctx, target_id)) await delete_messages_from_channel(ctx, channel, target_id, history) #no need to keep the id around deleted.IGNORE_IDS.remove(target_id) #create both a journal entry for the user targeted journal.update_journal_event(module=__name__, event="MESSAGE_CLEANUP_MODERATOR", userid=target_id, contents="Invoked by: {0.author.name} in channel {0.channel}".format(ctx.message)) journal.update_journal_regulator(invoker=ctx.message.author.id, target=target_id, eventdata=history, action="MESSAGE_CLEANUP_MODERATOR", messageid=ctx.message.id) secs_taken = int(analytics.getEventTime() - start) await discord.bot.say("{0.message.author.mention} cleanup on ID `{1}` completed! Took ~{2} seconds".format(ctx, target_id, secs_taken))
async def gamerword_debug(ctx, target): if not common.isDiscordRegulator(ctx.message.author): return target_id = discord.get_targeted_id(ctx) # get the forgiveness value and get how far back we should look cutoff = int(time.time() - config.cfg['automod']['forgiveness_days'] * 86400) database.cursor.execute( 'SELECT score_final,score_regex,score_prev_infractions,multiply_age_member,multiply_age_account,action from automod_gamerwords WHERE id_targeted=%s AND time>%s', (target_id, cutoff)) dbres = database.cursor.fetchall() if len(dbres) == 0: await discord.bot.say( "{0.message.author.mention} no actions found in the last {1[automod][forgiveness_days]} days." .format(ctx, config.cfg)) else: table_result = common.dbtable_to_strtable(dbres) if table_result: await discord.bot.say( "Last {0[automod][forgiveness_days]} days of automoderation against ID:{1} ```{2}```" .format(config.cfg, target_id, table_result)) else: await discord.bot.say( "{0.message.author.mention} unable to retrieve table, result too big or something broke." .format(ctx))
def allow_regulation(ctx, target_id): #has to be a regulator+ if common.isDiscordRegulator(ctx.message.author) == True: pass else: logger.info( "allow_regulation() attempted to invoke but was rejected for: no permission, Invoker: {}, Target:{}" .format(ctx.message.author.id, target_id)) return False #we need an ID to be able to work with, this should already be caught if target_id is None: return False #dont let the user try to play themselves if target_id == ctx.message.author.id: logger.info( "allow_regulation() attempted to invoke but was rejected for: attempted self harm, Invoker: {}, Target:{}" .format(ctx.message.author.id, target_id)) return False #if the user is an admin process it bypassing permissions if common.isDiscordAdministrator(ctx.message.author) == True: return True #convert the target_id into a member object, or at least try. This is to cacluate if the user can be touched target_member = discord.default_server.get_member(target_id) if target_member is None: logger.info( "allow_regulation() bypassing action restriction since Member object cannot be created. Invoker: {}, Target: {}" .format(ctx.message.author.id, target_id)) return True #get the assigned role IDs target_roles = [] for role in target_member.roles: target_roles.append(role.id) #convert the lists to sets target_set = set(target_roles) untouchable_set = set(untouchable_roles) #if they intersect, they should not be touched allowed_set = untouchable_set.intersection(target_set) if len(allowed_set) == 0: return True else: logger.info( "allow_regulation() attempted to invoke but was rejected for: protected role, Invoker: {}, Target:{}" .format(ctx.message.author.id, target_id)) return False #failsafe to no if my bad logic fails logger.info( "allow_regulation() attempted to invoke but was rejected for: failsafe, Invoker: {}, Target:{}" .format(ctx.message.author.id, target_id)) return False
async def kill(ctx): if not common.isDiscordRegulator(ctx.message.author): return # get the current PID to tell the use pid = os.getpid() await discord.bot.say( "{0.message.author.mention} Freezing all motor functions for PID:`{1}`. See you again soon <3" .format(ctx, pid)) # commit sudoku sys.exit()
async def remind(ctx, duration, *, text): if common.isDiscordMainServer(ctx.message.server) is not True: return #set a cap of max 5 currently waiting jobs, regs+ are exempt if not common.isDiscordRegulator(ctx.message.author): database.cursor.execute("SELECT * FROM scheduled_tasks WHERE exec_run=0 AND event_type='POST_MESSAGE' AND id_targeted = %s", (ctx.message.author.id,)) waiting_work_count = database.cursor.fetchall() if len(waiting_work_count) >= 5: await discord.bot.say("⚠️{0.message.author.mention} you already have 5 waiting reminders. View them via `!todo`".format(ctx)) return #get the user input to seconds duration_length = scheduler.user_duration_to_seconds(duration) if duration_length is False: await discord.bot.say("⚠️{0.message.author.mention} unable to decode message length. Should be `!remind 60s|1m|4d don't forget about the potatoes`".format(ctx)) return elif duration_length is None: await discord.bot.say("⚠️{0.message.author.mention} unable to decode message length. allowed: seconds (s), minutes (m), hours (h), days (d), weeks (w), years (y)".format(ctx)) return duration_inrange = scheduler.verify_reminder_duration_length(duration_length) if duration_inrange is False: await discord.bot.say("⚠️{0.message.author.mention} Reminder is out of expected range. Current Range {1}m to {2}d".format(ctx, config.cfg['scheduler']['time_range_min_mins'], int(config.cfg['scheduler']['time_range_max_mins'] / 1440))) return #dont allow abusive calls to be made, these should just make API calls to kick the user if "@everyone" in text.lower(): return elif "@here" in text.lower(): return else: text = text.replace("`","'") #limit message to have 3 mentions if len(ctx.message.mentions) > 3: return #calculate the time it should fire now = int(time.time()) time_to_fire = now + duration_length #set the reminder scheduler.set_future_task( invoker=ctx.message.author.id, channel=ctx.message.channel.id, timestamp=time_to_fire, event="POST_MESSAGE", msg=text) when = time.strftime("%A, %B %d %Y %H:%M %Z", time.localtime(time_to_fire)) await discord.bot.say("✔️{0.message.author.mention} reminder set for `{1}`! I'll try not to forget about this, I promise.".format(ctx, when))
async def warn(ctx, target, *, reason): if common.isDiscordRegulator(ctx.message.author) != True: return # convert the target into a usable ID target_id = discord.get_targeted_id(ctx) target_member = await discord.get_user_info(target_id) if target_member is None: await discord.bot.say( "{} тЪая╕П I was not able to lookup that user ID.".format( ctx.message.author.mention)) return # warn reason has to have at least a word in it if len(reason) < 4: await discord.bot.say( "тЪая╕П Warning reason must be longer than 4 characters. `!warn @username reason goes here`" ) return # warn reason has to be a reasonable length if len(reason) > 200: await discord.bot.say( "тЪая╕П Reason too long - please limit to 200 characters or less.") return if allow_regulation(ctx, target_id): # return what is happening in the same channel to alert the user await discord.bot.say( "тЬФя╕П {} is warning {} with the reason of `{}`.".format( ctx.message.author.mention, target_member.mention, reason)) # update the internal bot log journal.update_journal_regulator(invoker=ctx.message.author.id, target=target_id, eventdata=reason, action="WARN_MEMBER", messageid=ctx.message.id) # update the internal user log journal.update_journal_event(module=__name__, event="ON_MEMBER_WARN", userid=target_id, contents="{0.name}#{0.discriminator} " "warned by {1.name}#{1.discriminator} " "with reason '{2}'".format( target_member, ctx.message.author, reason)) else: await discord.bot.say( "ЁЯЫС {} unable to moderate user. Either you failed to tag the user properly or the member is protected from regulators." .format(ctx.message.author.mention))
async def stats(ctx, more=None): if common.isDiscordRegulator(ctx.message.author) is False: return if more == None: #get the avg without numpy because I dont want to import useless shit but will do it anyway in 3 months <-- haha I did exactly this check git emd = discord.embeds.Embed(color=0xE79015) emd.add_field(name="Bot Uptime", value=analytics.getRuntime()) emd.add_field(name="Messages Processed", value="{:,d}".format(analytics.messages_processed)) emd.add_field(name="Unique Users", value="{:,d}".format( len(analytics.messages_processed_users))) emd.add_field(name="Unique Channels", value="{:,d}".format( len(analytics.messages_processed_perchannel))) emd.add_field(name="on_message() Statistics", value=analytics.get_onMessageProcessTime()) emd.add_field(name="on_member() Statistics", value=analytics.get_onMemberProcessTime()) await discord.bot.say(embed=emd) elif more.startswith("c"): sorted_channels = sorted( analytics.messages_processed_perchannel.items(), key=lambda x: x[1], reverse=True) msg = "" for channel in sorted_channels: msg = msg + "#{0}: {1:,d}\n".format( discord.bot.get_channel(channel[0]), channel[1]) await discord.bot.say( "Most active channels since bot reboot, {}:\n```{}```".format( analytics.getRuntime(), msg)) elif more.startswith("u"): sorted_users = sorted(analytics.messages_processed_users.items(), key=lambda x: x[1], reverse=True) server = discord.bot.get_server(config.cfg['discord']['server']) msg = "" for user in sorted_users[:10]: msg = msg + "{0}: {1:,d}\n".format(server.get_member(user[0]), user[1]) await discord.bot.say( "Top 10 talkative users since bot reboot, {}:\n```{}```".format( analytics.getRuntime(), msg)) else: await discord.bot.say("Unknown subcommand. Try `channel | user`")
async def kick(ctx, target, *, reason): if common.isDiscordRegulator(ctx.message.author) != True: return #convert the target into a usable ID target_id = discord.get_targeted_id(ctx) target_member = discord.default_server.get_member(target_id) if target_member is None: await discord.bot.say( "{} тЪая╕П I was not able to lookup that user ID.".format( ctx.message.author.mention)) return #kick reason has to have at least a word in it if len(reason) < 4: await discord.bot.say( "тЪая╕П Kick reason must be longer than 4 characters. `!kick @username reason goes here`" ) return # kick reason has to be a reasonable length if len(reason) > 200: await discord.bot.say( "тЪая╕П Reason too long - please limit to 200 characters or less.") return if allow_regulation(ctx, target_id): #return what is happening in the same channel to alert the user, wait 5 seconds and fire the kick command await discord.bot.say( "тЬФя╕П {} is kicking {} with the reason of `{}`.".format( ctx.message.author.mention, target_member.mention, reason)) await asyncio.sleep(5) await discord.bot.kick(target_member) #update the internal bot log, since we cant send kick reasons via this api version #TODO: in rewrite add that journal.update_journal_regulator(invoker=ctx.message.author.id, target=target_id, eventdata=reason, action="KICK_MEMBER", messageid=ctx.message.id) else: await discord.bot.say( "ЁЯЫС {} unable to moderate user. Either you failed to tag the user properly or the member is protected from regulators." .format(ctx.message.author.mention))
async def journal(ctx, user: str): if common.isDiscordRegulator(ctx.message.author) is False: return target_id = discord.get_targeted_id(ctx) target_member = await discord.get_user_info(target_id) if target_id is None: database.cursor.execute( 'SELECT * from journal_events WHERE userid=%s ORDER BY time DESC LIMIT 5', (target_id, )) emd = discord.embeds.Embed( title='Last 5 events for ({0})'.format(user), color=0xE79015) else: database.cursor.execute( 'SELECT * from journal_events WHERE userid=%s ORDER BY time DESC LIMIT 5', (target_id, )) emd = discord.embeds.Embed( title='Last 5 events for "{0.name}" ({0.id})'.format( target_member), color=0xE79015) dbres = database.cursor.fetchall() if len(dbres) == 0: await discord.bot.say("Not found in my journal :(") return else: for row in dbres: emd.add_field( inline=False, name="{}".format( datetime.fromtimestamp(float(row['time'])).isoformat()), value="{0[event]} ({0[module]}) Result: {0[contents]}\n". format(row)) await discord.bot.say(embed=emd)
async def rapsheet(ctx): if common.isDiscordRegulator(ctx.message.author) is False: return # Get the member target_id = discord.get_targeted_id(ctx) target_member = await discord.get_user_info(target_id) # Pull all their regulator actions, ignoring un-silence events. database.cursor.execute( 'SELECT * from journal_regulators WHERE id_targeted=%s AND NOT action = \'VOICE_UNSILENCE\' ORDER BY time DESC', (target_id, )) dbres = database.cursor.fetchall() # Get the first event in the logs for the user as a "first seen" date database.cursor.execute( 'SELECT MIN(time) AS \'time\' FROM journal_events WHERE userid = %s', (target_id, )) first_seen = database.cursor.fetchall() # If no events are returned, generate and send a clean rapsheet if len(dbres) == 0: emd = discord.embeds.Embed(title="__Moderation Statistics__", colour=discord.discord.Color.green(), timestamp=datetime.utcnow()) emd.set_author(name="{0} (ID: {1})".format(target_member.name, target_member.id), icon_url=target_member.avatar_url) emd.set_thumbnail(url=target_member.avatar_url) if first_seen[0]['time'] is None: emd.add_field( name="No previous moderation actions found for user.", value="First Seen - Unknown") else: emd.add_field( name="No previous moderation actions found for user.", value="First Seen - {0}".format( datetime.fromtimestamp(first_seen[0]['time']).strftime( '%Y-%m-%d @ %H:%M:%S'))) await discord.bot.say(embed=emd) return # Otherwise, total up all the events, generate, and send a dirty rapsheet else: emd = discord.embeds.Embed(title="__Moderation Statistics__", colour=discord.discord.Color.red(), timestamp=datetime.utcnow()) emd.set_author(name="{0} (ID: {1})".format(target_member.name, target_member.id), icon_url=target_member.avatar_url) emd.set_thumbnail(url=target_member.avatar_url) warnCount, muteCount, kickCount, banCount = 0, 0, 0, 0 warns, mutes, kicks, bans = "", "", "", "" for row in dbres: invoker = await discord.get_user_info(row['id_invoker']) if row['action'] == "WARN_MEMBER": warnCount += 1 warns += "{0} - {1} --- *{2}*\n".format( datetime.fromtimestamp(float( row['time'])).date().isoformat(), invoker.mention, row['id_message']) elif row['action'] == "VOICE_SILENCE": muteCount += 1 mutes += "{0} - {1} --- *{2}*\n".format( datetime.fromtimestamp(float( row['time'])).date().isoformat(), invoker.mention, row['id_message']) elif row['action'] == "KICK_MEMBER": kickCount += 1 kicks += "{0} - {1} --- *{2}*\n".format( datetime.fromtimestamp(float( row['time'])).date().isoformat(), invoker.mention, row['id_message']) elif row['action'] == "BAN_MEMBER": banCount += 1 bans += "{0} - {1} --- *{2}*\n".format( datetime.fromtimestamp(float( row['time'])).date().isoformat(), invoker.mention, row['id_message']) if warns == "": emd.add_field(name="Warnings: {0}".format(warnCount), value="N/A", inline=False) else: emd.add_field(name="Warnings: {0}".format(warnCount), value=warns, inline=False) if mutes == "": emd.add_field(name="Mutes: {0}".format(muteCount), value="N/A", inline=False) else: emd.add_field(name="Mutes: {0}".format(muteCount), value=mutes, inline=False) if kicks == "": emd.add_field(name="Kicks: {0}".format(kickCount), value="N/A", inline=False) else: emd.add_field(name="Kicks: {0}".format(kickCount), value=kicks, inline=False) if bans == "": emd.add_field(name="Bans: {0}".format(banCount), value="N/A", inline=False) else: emd.add_field(name="Bans: {0}".format(banCount), value=bans, inline=False) emd.add_field( name="First Seen", value=datetime.fromtimestamp( first_seen[0]['time']).strftime('%Y-%m-%d @ %H:%M:%S'), inline=True) emd.add_field( name="Time Since Moderation", value=str(datetime.now() - datetime.fromtimestamp(float(dbres[0]['time']))).split( '.')[0], inline=True) await discord.bot.say(embed=emd)
async def isregulator(ctx): if common.isDiscordRegulator(ctx.message.author): await discord.bot.say("{0.message.author.mention} is a regulator, and is ready to abuse all powers granted by the admins™.".format(ctx))
async def unban(ctx, target): target_id = discord.get_targeted_id(ctx) target_member = discord.default_server.get_member(target_id) if common.isDiscordAdministrator(ctx.message.author): #if the user is an admin, let them blindly call IDs, unban blindly from discord unban_status_discord = await common.unban_id(target_id) #also check the retroactive table, this can be useful if the user was retro banned but never rejoied database.cursor.execute('SELECT * FROM bans_retroactive WHERE id=%s', (target_id, )) unban_status_retroactive = database.cursor.fetchone() if unban_status_retroactive is None: unban_status_retroactive = False else: database.cursor.execute('DELETE FROM bans_retroactive WHERE id=%s', (target_id, )) database.connection.commit() #unban message logic if unban_status_discord is False and unban_status_retroactive is False: await discord.bot.say( "тЪая╕П Unable to find ID in either Discord or Retroactive table. Try again?" ) elif unban_status_discord is True and unban_status_retroactive is False: await discord.bot.say( "тЬФя╕П User was found banned on Discord. Removed ban.") elif unban_status_discord is False and unban_status_retroactive is True: await discord.bot.say( "тЬФя╕П User was found banned in Retroactive table. Removed from database." ) else: await discord.bot.say( "тЬФя╕П User was found banned on Discord and Retroactive ban table. Removed ban and database entry." ) elif common.isDiscordRegulator(ctx.message.author): #regulators have a slightly different logic to follow to allow. Use internal audit log to make decisions database.cursor.execute( 'SELECT * FROM journal_regulators WHERE id_targeted=%s AND id_invoker=%s AND action="BAN_MEMBER" ORDER BY time ASC', (target_id, ctx.message.author.id)) regulator_target_history = database.cursor.fetchone() #if there is nothing in the database there is no reason to even try with the logic if regulator_target_history is None: logger.warn( "{0} attempted unban of {1} ID but failed due to reason: DB_RETURNED_NONE" .format(ctx.message.author.id, target_id)) await discord.bot.say( "тЪая╕П {0.message.author.mention} Unable to find any record of you banning ID `{1}` (ever). You can only unban people you yourself banned." .format(ctx, target_id)) return #get how many mins ago the ban was to see if they are able to be unbanned banned_mins_ago = int( (time.time() - regulator_target_history['time']) / 60) #handle if we should process the unban_id() if banned_mins_ago > config.cfg['regulators']['unban_grace_mins']: over_grace_mins = int(banned_mins_ago - config.cfg['regulators']['unban_grace_mins']) logger.warn( "{0} attempted unban of {1} ID but failed due to reason: OVER_GRACE_PERIOD by {2} minutes" .format(ctx.message.author.id, target_id, over_grace_mins)) await discord.bot.say( "тЪая╕П {0.message.author.mention} The user ID `{1}` is over the grace period for regulator unbans by `{2}` minutes. Contact an Administrator." .format(ctx, target_id, over_grace_mins)) else: unban_status_discord = await common.unban_id(target_id) if unban_status_discord is False: logger.warn( "{0} attempted unban of {1} ID but failed due to reason: DISCORD_RETURNED_NOT_BANNED" .format(ctx.message.author.id, target_id)) await discord.bot.say( "тЪая╕П {0.message.author.mention} Discord returned no ban found for ID `{1}` (ever). The user was already unbanned or something is wrong :/" .format(ctx, target_id)) else: logger.info( "{0} unbanned {1}. Time elapsed since ban {2}".format( ctx.message.author.id, target_id, banned_mins_ago)) await discord.bot.say( "тЬФя╕П {0.message.author.mention} ID `{1}` has been unbanned!" .format(ctx, target)) journal.update_journal_regulator(invoker=ctx.message.author.id, target=target_id, eventdata=banned_mins_ago, action="UNBAN_MEMBER_GRACE", messageid=ctx.message.id)
async def inviteban(ctx, target, *, reason): if common.isDiscordRegulator(ctx.message.author) != True: return # ban reason has to be a reasonable length if len(reason) > 200: await discord.bot.say( "тЪая╕П Invite ban reason must be longer than 4 characters. `!inviteban inviteCode reason goes here`" ) return # ban reason has to be a reasonable length if len(reason) > 200: await discord.bot.say( "тЪая╕П Reason too long - please limit to 200 characters or less.") return #get anyone who joined via the invite database.cursor.execute( "SELECT * FROM journal_events WHERE event='ON_MEMBER_JOINED_WITH_INVITE' AND contents=%s", (target, )) invitees = database.cursor.fetchall() #if there is not anyone, dont even do anything if len(invitees) == 0 or target.lower() == "none": await discord.bot.say( "тЪая╕П {} Invalid invite code! 0 members joined via internal journal. Retype invite or bother Cake." .format(ctx.message.author.mention)) return #get the invite data, make sure it is valid and then get who made it. They purge first. try: invite = await discord.bot.get_invite(target) except Exception as e: invite = None await discord.bot.say( "тЪая╕П {} unable to look up invite code: {} for ownership! Moving on to blind mode!" .format(ctx.message.author.mention, e)) #ban the inviter if we know who they are if invite is not None: banned_inviter = await common.ban_verbose( invite.inviter, "{} from invite {} - '{}'".format(ctx.message.author.name, target, reason)) if banned_inviter == False: pass await discord.bot.say( "тЭУ Something's f****d! Unable to issue ban to Discord API for root invite creator. Bother cake. (protected user?)" ) else: journal.update_journal_regulator( invoker=ctx.message.author.id, target=invite.inviter.id, eventdata=target, action="BAN_MEMBER_VIA_INVITE_MAKER", messageid=ctx.message.id) await discord.bot.say( "тЬФя╕П {} is dropping the hammer on {} and anyone who joined via their invite `{}`. Let the bombs drop! " .format(ctx.message.author.mention, invite.inviter.mention, target)) for invited in invitees: #attempt to turn the ID into a valid member object server = discord.bot.get_server(config.cfg['discord']['server']) invited_member = server.get_member(str(invited['userid'])) #if that cant happen, the user probably left or was banned already. Add to retroactive table (TODO) if invited_member == None: database.cursor.execute( 'INSERT IGNORE INTO bans_retroactive(id, name, reason) VALUES(%s,%s,%s)', (invited['userid'], "UNKNOWN_INVITEBAN_CALLED", reason)) database.connection.commit() await discord.bot.say( "тЪая╕П `{}` is getting banned for joining on invite `{}` (retroactive fallback. User either left or already banned) " .format(invited['userid'], target)) else: banned_inviter = await common.ban_verbose( invited_member, "{} inviteban via {} - '{}'".format(ctx.message.author.name, target, reason)) if banned_inviter == False: await discord.bot.say( "тЭУ Something's f****d! Unable to issue ban to Discord API for {}. Bother cake." .format(invited_member.mention)) else: await discord.bot.say( "тЬФя╕П {} is getting banned for joining on invite `{}` ". format(invited_member.mention, target)) #take a break between to prevent r8 limited await asyncio.sleep(2) await discord.bot.say( "Invite ban completed. {} members removed. Thanks for playing!".format( len(invitees)))
async def timedban(ctx, target, duration, *, reason): if common.isDiscordRegulator(ctx.message.author) != True: return #convert the target into a usable ID target_id = discord.get_targeted_id(ctx) target_member = discord.default_server.get_member(target_id) #ban reason has to have at least a word in it if len(reason) < 4: await discord.bot.say( "тЪая╕П {0.message.author.mention} ban reason must be longer than 4 characters. `!ban @username 1d reason goes here`" .format(ctx)) return #if the user cannot be banned if allow_regulation(ctx, target_id) is False: await discord.bot.say( "ЁЯЫС {0.message.author.mention} unable to moderate user. (no permissions)" .format(ctx)) return #verify the ban duration, and get the durations in seconds duration_length = scheduler.user_duration_to_seconds(duration) if duration_length is False: await discord.bot.say( "тЪая╕П{0.message.author.mention} unable to decode message length. Should be `!ban @username 60s|1m|7d could not stop using gamer words`" .format(ctx)) return elif duration_length is None: await discord.bot.say( "тЪая╕П{0.message.author.mention} unable to decode message length. allowed: seconds (s), minutes (m), hours (h), days (d), weeks (w), years (y)" .format(ctx)) return duration_inrange = scheduler.verify_reminder_duration_length( duration_length) if duration_inrange is False: await discord.bot.say( "тЪая╕П{0.message.author.mention} Ban duration is out of range. Have some mercy! Current range {1}m to {2}d" .format(ctx, config.cfg['scheduler']['time_range_min_mins'], int(config.cfg['scheduler']['time_range_max_mins'] / 1440)) ) return #if we have a Member object, it is not retroactive and can be run live against discord if target_member is not None: #get the time to unban, make a db entry for unban now = int(time.time()) time_to_fire = now + duration_length when_nice = time.strftime("%A, %B %d %Y %H:%M %Z", time.localtime(time_to_fire)) scheduler.set_future_task(invoker=ctx.message.author.id, target=target_member.id, channel=ctx.message.channel.id, timestamp=time_to_fire, event="UNBAN_MEMBER", msg=reason) await discord.bot.say( "тЬФя╕П {0.message.author.mention} is **BANNING** {1} with the reason of `{2}`. (Duration: {3}, Unban at:`{4}`)" .format(ctx, target_member.mention, reason, duration, when_nice)) await asyncio.sleep(5) #ship the ban off to discord res = await common.ban_verbose( target_member, "{0.message.author.name} - '{1}'".format(ctx, reason)) if res is False: await discord.bot.say( "тЭУ Something's f****d! Unable to issue ban to Discord API. Bother <@{}>" .format(config.cfg['bernard']['owner'])) else: journal.update_journal_regulator(invoker=ctx.message.author.id, target=target_id, eventdata=reason, action="BAN_MEMBER", messageid=ctx.message.id) #if a raw mention exists but not the Member object, handle it as retroactive elif target_id is not None and target_member is None: await discord.bot.say( "тЪая╕П {0.message.author.mention} You cannot issue retroactive timed bans. Please use normal !ban." .format(ctx)) else: await discord.bot.say( "ЁЯЫС {0.message.author.mention} unable to moderate user. Target did not resolve to a valid Discord Member." .format(ctx))
async def ban(ctx, target, *, reason): if common.isDiscordRegulator(ctx.message.author) != True: return #convert the target into a usable ID target_id = discord.get_targeted_id(ctx) target_member = discord.default_server.get_member(target_id) #ban reason has to have at least a word in it if len(reason) < 4: await discord.bot.say( "тЪая╕П ban reason must be longer than 4 characters. `!ban @username reason goes here`" ) return # ban reason has to be a reasonable length if len(reason) > 200: await discord.bot.say( "тЪая╕П Reason too long - please limit to 200 characters or less.") return #if the user cannot be banned if allow_regulation(ctx, target_id) is False: await discord.bot.say( "ЁЯЫС {} unable to moderate user. (no permissions)".format( ctx.message.author.mention)) return #if we have a Member object, it is not retroactive and can be run live against discord if target_member is not None: await discord.bot.say( "тЬФя╕П {} is **BANNING** {} with the reason of `{}`.".format( ctx.message.author.mention, target_member.mention, reason)) await asyncio.sleep(5) res = await common.ban_verbose( target_member, "{} - '{}'".format(ctx.message.author.name, reason)) if res is False: await discord.bot.say( "тЭУ Something's f****d! Unable to issue ban to Discord API. Bother <@{}>" .format(config.cfg['bernard']['owner'])) else: journal.update_journal_regulator(invoker=ctx.message.author.id, target=target_id, eventdata=reason, action="BAN_MEMBER", messageid=ctx.message.id) #if a raw mention exists but not the Member object, handle it as retroactive and log who did it. elif target_id is not None and target_member is None: await discord.bot.say( "тЬФя╕П {} is (retroactive) **BANNING** userid `{}` with the reason of `{}`." .format(ctx.message.author.mention, target_id, reason)) journal.update_journal_regulator(invoker=ctx.message.author.id, target=target_id, eventdata=reason, action="BAN_MEMBER_RETROACTIVE", messageid=ctx.message.id) retroactive_reason = "VIA_RETROACTIVE: {} - '{}'".format( ctx.message.author.name, reason) database.cursor.execute( 'INSERT INTO bans_retroactive (id, name, reason) VALUES (%s,%s,%s)', (target_id, "N/A", retroactive_reason)) database.connection.commit() else: await discord.bot.say( "ЁЯЫС {} unable to moderate user. Target did not resolve to a valid Discord Member." .format(ctx.message.author.mention))
async def getid(ctx, target): if common.isDiscordRegulator(ctx.message.author): id = discord.get_targeted_id(ctx) await discord.bot.say(id)