def warn(self, event, user, reason=None): member = None member = event.guild.get_member(user) if member: self.can_act_on(event, member.id) if event.config.notify_action_on: if event.config.notify_action_on.bans: try: event.guild.get_member(user.id).user.open_dm( ).send_message( 'You have been **Warned** in the guild **{}** for the reason: `{}`' .format(event.guild.name, reason or 'no reason specified.')) except: pass else: pass else: pass Infraction.warn(self, event, member, reason, guild=event.guild) else: raise CommandFail('invalid user') self.confirm_action( event, maybe_string( reason, u':ok_hand: warned {u} (`{o}`)', u':ok_hand: warned {u}', u=member.user if member else user, ))
def kick(self, event, user, reason=None): member = event.guild.get_member(user) if member: self.can_act_on(event, member.id) if event.config.notify_action_on and event.config.notify_action_on.kicks: try: event.guild.get_member(user.id).user.open_dm( ).send_message( 'You have been **Kicked** from the guild **{}** for `{}`' .format(event.guild.name, reason or 'no reason')) except: pass else: pass Infraction.kick(self, event, member, reason) self.confirm_action( event, maybe_string( reason, u':ok_hand: kicked {u} (`{o}`)', u':ok_hand: kicked {u}', u=member.user, )) else: raise CommandFail('invalid user')
def tempmute(self, event, user, duration, reason=None): member = event.guild.get_member(user) if member: self.can_act_on(event, member.id) if not event.config.mute_role: raise CommandFail('mute is not setup on this server') if event.config.mute_role in member.roles: raise CommandFail(u'{} is already muted'.format(member.user)) expire_dt = parse_duration(duration) # Reset the infraction task so we make sure it runs after this new infraction self.inf_task.set_next_schedule(expire_dt) # Create the infraction Infraction.tempmute(self, event, member, reason, expire_dt) if event.config.confirm_actions: event.msg.reply( maybe_string( reason, u':ok_hand: {u} is now muted for {t} (`{o}`)', u':ok_hand: {u} is now muted for {t}', u=member.user, t=humanize.naturaldelta(expire_dt - datetime.utcnow()), )) else: raise CommandFail('invalid user')
def unmute(self, event, user, reason=None): # TOOD: eventually we should pull the role from the GuildMemberBackup if they arent in server member = event.guild.get_member(user) if member: self.can_act_on(event, member.id) if not event.config.mute_role: raise CommandFail('mute is not setup on this server') if event.config.mute_role not in member.roles: raise CommandFail(u'{} is not muted'.format(member.user)) Infraction.clear_active( event, member.id, [Infraction.Types.MUTE, Infraction.Types.TEMPMUTE]) self.bot.plugins.get('ModLogPlugin').create_debounce( event, member.user.id, 'unmuted', actor=unicode(event.author), roles=[event.config.mute_role]) member.remove_role(event.config.mute_role) if event.config.confirm_actions: event.msg.reply(u':ok_hand: {} is now unmuted'.format( member.user)) else: raise CommandFail('invalid user')
def ban(self, event, user, reason=None): member = None if isinstance(user, (int, long)): self.can_act_on(event, user) Infraction.ban(self, event, user, reason, guild=event.guild) else: member = event.guild.get_member(user) if member: self.can_act_on(event, member.id) if event.config.notify_action_on and event.config.notify_action_on.bans: try: event.guild.get_member(user.id).user.open_dm( ).send_message( 'You have been **Permanently Banned** from the guild **{}** for `{}`.' .format(event.guild.name, reason or 'no reason specified.')) except: pass else: pass Infraction.ban(self, event, member, reason, guild=event.guild) else: raise CommandFail('invalid user') self.confirm_action( event, maybe_string( reason, u':ok_hand: banned {u} (`{o}`)', u':ok_hand: banned {u}', u=member.user if member else user, ))
def mute(self, event, user, reason=None): member = event.guild.get_member(user) if member: self.can_act_on(event, member.id) if not event.config.mute_role: raise CommandFail('mute is not setup on this server') existed = False # If the user is already muted check if we can take this from a temp # to perma mute. if event.config.mute_role in member.roles: existed = Infraction.clear_active(event, member.id, [Infraction.Types.TEMPMUTE]) # The user is 100% muted and not tempmuted at this point, so lets bail if not existed: raise CommandFail(u'{} is already muted'.format( member.user)) Infraction.mute(self, event, member, reason) if event.config.confirm_actions: existed = u' [was temp-muted]' if existed else '' event.msg.reply( maybe_string( reason, u':ok_hand: {u} is now muted (`{o}`)' + existed, u':ok_hand: {u} is now muted' + existed, u=member.user, )) else: raise CommandFail('invalid user')
def temprole(self, event, user, role, duration, reason=None): member = event.guild.get_member(user) if not member: raise CommandFail('invalid user') self.can_act_on(event, member.id) role_id = role if isinstance(role, (int, long)) else event.config.role_aliases.get(role.lower()) if not role_id or role_id not in event.guild.roles: raise CommandFail('invalid or unknown role') if role_id in member.roles: raise CommandFail(u'{} is already in that role'.format(member.user)) expire_dt = parse_duration(duration) Infraction.temprole(self, event, member, role_id, reason, expire_dt) self.queue_infractions() self.confirm_action(event, maybe_string( reason, u':ok_hand: {u} is now in the {r} role for {t} (`{o}`)', u':ok_hand: {u} is now in the {r} role for {t}', r=event.guild.roles[role_id].name, u=member.user, t=humanize.naturaldelta(expire_dt - datetime.utcnow()), ))
def unmute(self, event, user, reason=None): # TOOD: eventually we should pull the role from the GuildMemberBackup if they arent in server member = event.guild.get_member(user) if member: if not event.config.temp_mute_role and not event.config.mute_role: raise CommandFail('mute is not setup on this server') roles = {event.config.temp_mute_role, event.config.mute_role } & set(member.roles) if not len(roles): raise CommandFail('{} is not muted'.format(member.user)) Infraction.update(active=False).where( (Infraction.guild_id == event.guild.id) & (Infraction.user_id == member.user.id) & (Infraction.type_ == Infraction.Types.TEMPMUTE) & (Infraction.active == 1)).execute() self.bot.plugins.get('ModLogPlugin').create_debounce( event, member.user.id, 'unmuted', actor=unicode(event.author), roles=roles) for role in roles: member.remove_role(role) if event.config.confirm_actions: event.msg.reply(u':ok_hand: {} is now unmuted'.format( member.user)) else: raise CommandFail('invalid user')
def unmute(self, event, user, reason=None): # TOOD: eventually we should pull the role from the GuildMemberBackup if they arent in server member = event.guild.get_member(user) if member: self.can_act_on(event, member.id) if not event.config.mute_role: raise CommandFail('mute is not setup on this server') if event.config.mute_role not in member.roles: raise CommandFail(u'{} is not muted'.format(member.user)) Infraction.clear_active(event, member.id, [Infraction.Types.MUTE, Infraction.Types.TEMPMUTE]) self.call( 'ModLogPlugin.create_debounce', event, ['GuildMemberUpdate'], role_id=event.config.mute_role, ) member.remove_role(event.config.mute_role) self.call( 'ModLogPlugin.log_action_ext', Actions.MEMBER_UNMUTED, event.guild.id, member=member, actor=unicode(event.author) if event.author.id != member.id else 'Automatic', ) self.confirm_action(event, u':ok_hand: {} is now unmuted'.format(member.user)) else: raise CommandFail('invalid user')
def unnuke(self, event, user, reason): contents = [] for gid, guild in list(self.guilds.items()): guild = self.state.guilds[gid] perms = guild.get_permissions(self.state.me) if not perms.ban_members and not perms.administrator: contents.append(':x: {} - Could not Unban'.format(guild.name)) continue try: Infraction.create(guild_id=guild.id, user_id=user, actor_id=self.client.api.users_me_get().id, type_=Infraction.Types.UNBAN, reason=reason) GuildBan.get(user_id=user, guild_id=guild.id) guild.delete_ban(user) except: contents.append(':x: {} - Error'.format(guild.name)) self.log.exception('Failed to remove ban for %s in %s', user, gid) contents.append(':white_check_mark: {} - Fixed :heart:'.format( guild.name)) event.msg.reply('Result:\n' + '\n'.join(contents))
def nuke(self, event, user, reason): contents = [] for gid, guild in self.guilds.items(): guild = self.state.guilds[gid] perms = guild.get_permissions(self.state.me) if not perms.ban_members and not perms.administrator: contents.append(u':x: {} - No Permissions'.format(guild.name)) continue try: Infraction.ban(self.bot.plugins.get('AdminPlugin'), event, user, reason, guild=guild) except: contents.append(u':x: {} - Unknown Error'.format(guild.name)) self.log.exception('Failed to force ban %s in %s', user, gid) contents.append( u':white_check_mark: {} - :regional_indicator_f:'.format( guild.name)) event.msg.reply('Results:\n' + '\n'.join(contents))
def softban(self, event, user, reason=None): """ Ban then unban a user from the server (with an optional reason for the modlog) """ member = event.guild.get_member(user) if member: self.can_act_on(event, member.id) if event.config.notify_action_on and event.config.notify_action_on.bans: try: event.guild.get_member(user.id).user.open_dm( ).send_message( 'You have been **Kicked** from the guild **{}** for `{}`.' .format(event.guild.name, reason or 'no reason specified.')) except: pass else: pass Infraction.softban(self, event, member, reason) self.confirm_action( event, maybe_string( reason, u':ok_hand: soft-banned {u} (`{o}`)', u':ok_hand: soft-banned {u}', u=member.user, )) else: raise CommandFail('invald user')
def mkick(self, event, args): members = [] failed_ids = [] for user_id in args.users: member = event.guild.get_member(user_id) if not member: #TODO: this sucks, batch these # raise CommandFail('failed to kick {}, user not found'.format(user_id)) failed_ids.append(member) continue if not self.can_act_on(event, member, throw=False): # raise CommandFail('failed to kick {}, invalid permissions'.format(user_id)) failed_ids.append(member) continue members.append(member) msg = event.msg.reply('Ok, kick {} users for `{}`?'.format( len(members), args.reason or 'no reason')) msg.chain(False).\ add_reaction(GREEN_TICK_EMOJI).\ add_reaction(RED_TICK_EMOJI) try: mra_event = self.wait_for_event( 'MessageReactionAdd', message_id=msg.id, conditional=lambda e: (e.emoji.id in (GREEN_TICK_EMOJI_ID, RED_TICK_EMOJI_ID) and e. user_id == event.author.id)).get(timeout=10) except gevent.Timeout: return finally: msg.delete() if mra_event.emoji.id != GREEN_TICK_EMOJI_ID: return for member in members: if event.config.notify_action_on: if event.config.notify_action_on.kicks: try: member.user.open_dm().send_message( 'You have been **Kicked** from the guild **{}** for `{}`' .format(event.guild.name, reason or 'no reason')) except: pass else: pass else: pass Infraction.kick(self, event, member, args.reason) raise CommandSuccess( 'kicked {} users. Was unable to remove {} users.'.format( len(members), len(failed_ids)))
def violate(self, violation): key = 'lv:{e.member.guild_id}:{e.member.id}'.format(e=violation.event) last_violated = int(rdb.get(key) or 0) rdb.setex( 'lv:{e.member.guild_id}:{e.member.id}'.format(e=violation.event), int(time.time()), 60) if not last_violated > time.time() - 10: self.call('ModLogPlugin.log_action_ext', Actions.SPAM, violation.event.guild.id, v=violation) punishment = violation.check.punishment or violation.rule.punishment punishment_duration = violation.check.punishment_duration or violation.rule.punishment_duration if punishment == PunishmentType.MUTE: Infraction.mute( self, violation.event, violation.member, 'Spam Detected', ) elif punishment == PunishmentType.TEMPMUTE: Infraction.tempmute( self, violation.event, violation.member, 'Spam Detected', datetime.utcnow() + timedelta(seconds=punishment_duration)) elif punishment == PunishmentType.KICK: Infraction.kick(self, violation.event, violation.member, 'Spam Detected') elif punishment == PunishmentType.TEMPBAN: Infraction.tempban( self, violation.event, violation.member, 'Spam Detected', datetime.utcnow() + timedelta(seconds=punishment_duration)) elif punishment == PunishmentType.BAN: Infraction.ban(self, violation.event, violation.member, 'Spam Detected', violation.event.guild) # Clean messages if requested if punishment != PunishmentType.NONE and violation.rule.clean: msgs = Message.select(Message.id, Message.channel_id).where( (Message.guild_id == violation.event.guild.id) & (Message.author_id == violation.member.id) & (Message.timestamp > (datetime.utcnow() - timedelta( seconds=violation.rule.clean_duration)))).limit( violation.rule.clean_count).tuples() channels = defaultdict(list) for mid, chan in msgs: channels[chan].append(mid) for channel, messages in list(channels.items()): channel = self.state.channels.get(channel) if not channel: continue channel.delete_messages(messages)
def mban(self, event, args): members = [] failed_ids = [] for user_id in args.users: if not self.can_act_on(event, user_id, throw=False): # raise CommandFail('failed to kick {}, invalid permissions'.format(user_id)) failed_ids.append(user_id) continue members.append(user_id) msg = event.msg.reply('Ok, ban {} users for `{}`?'.format( len(members), args.reason or 'no reason')) msg.chain(False).\ add_reaction(GREEN_TICK_EMOJI).\ add_reaction(RED_TICK_EMOJI) try: mra_event = self.wait_for_event( 'MessageReactionAdd', message_id=msg.id, conditional=lambda e: (e.emoji.id in (GREEN_TICK_EMOJI_ID, RED_TICK_EMOJI_ID) and e. user_id == event.author.id)).get(timeout=10) except gevent.Timeout: return finally: msg.delete() if mra_event.emoji.id != GREEN_TICK_EMOJI_ID: return for user_id in members: if event.config.notify_action_on: if event.config.notify_action_on.bans: try: event.guild.get_member(user.id).user.open_dm( ).send_message( 'You have been **Permanently Banned** from the guild **{}** for `{}`.' .format(event.guild.name, reason or 'no reason specified.')) except: pass else: pass else: pass Infraction.ban(self, event, user_id, args.reason, guild=event.guild) raise CommandSuccess( 'banned {} users and failed to ban {} users.'.format( len(members), len(failed_ids)))
def tempmute(self, event, user, duration=None, reason=None): if not duration and reason: duration = parse_duration(reason.split(' ')[0], safe=True) if duration: if ' ' in reason: reason = reason.split(' ', 1)[-1] else: reason = None elif duration: duration = parse_duration(duration) member = event.guild.get_member(user) if member: self.can_act_on(event, member.id) if not event.config.mute_role: raise CommandFail('mute is not setup on this server') if event.config.mute_role in member.roles: raise CommandFail(u'{} is already muted'.format(member.user)) # If we have a duration set, this is a tempmute if duration: # Create the infraction Infraction.tempmute(self, event, member, reason, duration) self.queue_infractions() self.confirm_action(event, maybe_string( reason, u':ok_hand: {u} is now muted for {t} (`{o}`)', u':ok_hand: {u} is now muted for {t}', u=member.user, t=humanize.naturaldelta(duration - datetime.utcnow()), )) else: existed = False # If the user is already muted check if we can take this from a temp # to perma mute. if event.config.mute_role in member.roles: existed = Infraction.clear_active(event, member.id, [Infraction.Types.TEMPMUTE]) # The user is 100% muted and not tempmuted at this point, so lets bail if not existed: raise CommandFail(u'{} is already muted'.format(member.user)) Infraction.mute(self, event, member, reason) existed = u' [was temp-muted]' if existed else '' self.confirm_action(event, maybe_string( reason, u':ok_hand: {u} is now muted (`{o}`)' + existed, u':ok_hand: {u} is now muted' + existed, u=member.user, )) else: raise CommandFail('invalid user')
def kick(self, event, user, reason=None): member = event.guild.get_member(user) if member: self.can_act_on(event, member.id) Infraction.kick(self, event, member, reason) self.confirm_action(event, maybe_string( reason, u':ok_hand: kicked {u} (`{o}`)', u':ok_hand: kicked {u}', u=member.user, )) else: raise CommandFail('invalid user')
def unban(self, event, user, reason=None): try: GuildBan.get(user_id=user, guild_id=event.guild.id) event.guild.delete_ban(user) except GuildBan.DoesNotExist: raise CommandFail('user with id `{}` is not banned'.format(user)) Infraction.create(guild_id=event.guild.id, user_id=user, actor_id=event.author.id, type_=Infraction.Types.UNBAN, reason=reason) raise CommandSuccess('unbanned user with id `{}`'.format(user))
def kick(self, event, user, reason=None): member = event.guild.get_member(user) if member: Infraction.kick(self, event, member, reason) if event.config.confirm_actions: event.msg.reply( maybe_string( reason, u':ok_hand: kicked {u} (`{o}`)', u':ok_hand: kicked {u}', u=member.user, )) else: raise CommandFail('invalid user')
def on_guild_member_update(self, event): pre_member = event.guild.members.get(event.id) if not pre_member: return pre_roles = set(pre_member.roles) post_roles = set(event.roles) if pre_roles == post_roles: return removed = pre_roles - post_roles # If the user was unmuted, mark any temp-mutes as inactive if event.config.mute_role in removed: Infraction.clear_active(event, event.user.id, [Infraction.Types.TEMPMUTE])
def tempban(self, event, duration, user, reason=None): member = event.guild.get_member(user) if member: self.can_act_on(event, member.id) expires_dt = parse_duration(duration) Infraction.tempban(self, event, member, reason, expires_dt) self.queue_infractions() self.confirm_action(event, maybe_string( reason, u':ok_hand: temp-banned {u} for {t} (`{o}`)', u':ok_hand: temp-banned {u} for {t}', u=member.user, t=humanize.naturaldelta(expires_dt - datetime.utcnow()), )) else: raise CommandFail('invalid user')
def softban(self, event, user, reason=None): """ Ban then unban a user from the server (with an optional reason for the modlog) """ member = event.guild.get_member(user) if member: self.can_act_on(event, member.id) Infraction.softban(self, event, member, reason) self.confirm_action(event, maybe_string( reason, u':ok_hand: soft-banned {u} (`{o}`)', u':ok_hand: soft-banned {u}', u=member.user, )) else: raise CommandFail('invald user')
def infraction_duration(self, event, infraction, duration): try: inf = Infraction.get(id=infraction) except Infraction.DoesNotExist: raise CommandFail('invalid infraction (try `!infractions recent`)') if inf.actor_id != event.author.id and event.user_level < CommandLevels.ADMIN: raise CommandFail('only administrators can modify the duration of infractions created by other moderators') if not inf.active: raise CommandFail('that infraction is not active and cannot be updated') expires_dt = parse_duration(duration, inf.created_at) converted = False if inf.type_ in [Infraction.Types.MUTE.index, Infraction.Types.BAN.index]: inf.type_ = Infraction.Types.TEMPMUTE if inf.type_ == Infraction.Types.MUTE.index else Infraction.Types.TEMPBAN converted = True elif inf.type_ not in [Infraction.Types.TEMPMUTE.index, Infraction.Types.TEMPBAN.index, Infraction.Types.TEMPROLE.index]: raise CommandFail('cannot set the duration for that type of infraction') inf.expires_at = expires_dt inf.save() self.queue_infractions() if converted: raise CommandSuccess('ok, I\'ve made that infraction temporary, it will now expire on {}'.format( inf.expires_at.isoformat() )) else: raise CommandSuccess('ok, I\'ve updated that infractions duration, it will now expire on {}'.format( inf.expires_at.isoformat() ))
def infractions_archive(self, event): user = User.alias() actor = User.alias() q = Infraction.select(Infraction, user, actor).join( user, on=((Infraction.user_id == user.user_id).alias('user')) ).switch(Infraction).join( actor, on=((Infraction.actor_id == actor.user_id).alias('actor')) ).where(Infraction.guild_id == event.guild.id) buff = StringIO() w = csv.writer(buff) for inf in q: w.writerow([ inf.id, inf.user_id, unicode(inf.user).encode('utf-8'), inf.actor_id, unicode(inf.actor).encode('utf-8'), unicode({i.index: i for i in Infraction.Types.attrs}[inf.type_]).encode('utf-8'), unicode(inf.reason).encode('utf-8'), ]) event.msg.reply('Ok, here is an archive of all infractions', attachments=[ ('infractions.csv', buff.getvalue()) ])
def clear_infractions(self): expired = list(Infraction.select().where((Infraction.active == 1) & ( Infraction.expires_at < datetime.utcnow()))) for item in expired: guild = self.state.guilds.get(item.guild_id) if not guild: continue # TODO: hacky type_ = {i.index: i for i in Infraction.Types.attrs}[item.type_] if type_ == Infraction.Types.TEMPBAN: # TODO: debounce guild.delete_ban(item.user_id) elif type_ == Infraction.Types.TEMPMUTE: member = guild.get_member(item.user_id) if member: if item.metadata['role'] in member.roles: member.remove_role(item.metadata['role']) else: GuildMemberBackup.remove_role(item.guild_id, item.user_id, item.metadata['role']) # TODO: n+1 item.active = False item.save() self.queue_infractions()
def on_message_create(self, event): if not event.config.DONT_MENTION_B1NZY: return if B1NZY_USER_ID not in event.mentions: return member = event.guild.get_member(event.author) if not member or member.roles: return duration = datetime.utcnow() + timedelta(days=7) Infraction.tempban(self, event, member, 'AUTOBAN - mentioned b1nzy', duration) event.message.reply( u'{} pinged b1nzy for some reason, they are rip now...'.format( member))
def filter_blocked_words(self, event, config): blocked_words = config.blocked_re.findall(event.content) if config.filter_zero and u"\0" in event.content: blocked_words = blocked_words or [] blocked_words.append("[zero codepoint]") if blocked_words: if config.always_ban: member = event.guild.get_member(event.author) Infraction.ban( self, event, member, 'Bannable filtered words detected: '+str(blocked_words), event.guild) raise Censorship(CensorReason.WORD, event, ctx={ 'words': blocked_words, })
def tempban(self, event, duration, user, reason=None): member = event.guild.get_member(user) if member: expires_dt = parse_duration(duration) self.inf_task.set_next_schedule(expires_dt) Infraction.tempban(self, event, member, reason, expires_dt) if event.config.confirm_actions: event.msg.reply( maybe_string( reason, u':ok_hand: temp-banned {u} for {t} (`{o}`)', u':ok_hand: temp-banned {u} for {t}', u=member.user, t=humanize.naturaldelta(expires_dt - datetime.utcnow()), )) else: raise CommandFail('invalid user')
def infraction_search(self, event, query=None): q = (Infraction.guild_id == event.guild.id) if query and isinstance(query, list) and isinstance( query[0], DiscoUser): query = query[0].id elif query: query = ' '.join(query) if query and (isinstance(query, int) or query.isdigit()): q &= ((Infraction.id == int(query)) | (Infraction.user_id == int(query)) | (Infraction.actor_id == int(query))) elif query: q &= (Infraction.reason**query) user = User.alias() actor = User.alias() infractions = Infraction.select(Infraction, user, actor).join( user, on=((Infraction.user_id == user.user_id).alias('user') )).switch(Infraction).join( actor, on=((Infraction.actor_id == actor.user_id ).alias('actor'))).where(q).order_by( Infraction.created_at.desc()).limit(6) tbl = MessageTable() tbl.set_header('ID', 'Created', 'Type', 'User', 'Moderator', 'Active', 'Reason') last_tbl_str = None for inf in infractions: type_ = {i.index: i for i in Infraction.Types.attrs}[inf.type_] reason = inf.reason or '' if len(reason) > 256: reason = reason[:256] + '...' if inf.active: active = 'yes' if inf.expires_at: active += ' (expires in {})'.format( humanize.naturaldelta(inf.expires_at - datetime.utcnow())) else: active = 'no' tbl.add(inf.id, inf.created_at.isoformat(), str(type_), unicode(inf.user), unicode(inf.actor), active, clamp(reason, 128)) tbl_str = tbl.compile() if len(tbl_str) >= 2000: break last_tbl_str = tbl_str event.msg.reply(last_tbl_str or "No infractions found.")
def tempban(self, event, duration, user, reason=None): member = event.guild.get_member(user) if member: self.can_act_on(event, member.id) expires_dt = parse_duration(duration) if event.config.limit_temp.duration_limit_level: if event.user_level <= event.config.limit_temp.duration_limit_level: if expires_dt > parse_duration( event.config.limit_temp.maximum_limited_duration): raise CommandFail( 'You cannot temp ban users for longer than ' + event.config.limit_temp.maximum_limited_duration) if event.config.notify_action_on: if event.config.notify_action_on.bans: try: event.guild.get_member(user.id).user.open_dm( ).send_message( 'You have been **Temporarily Banned** in the guild **{}** for **{}** for `{}`' .format( event.guild.name, humanize.naturaldelta(expires_dt - datetime.utcnow()), reason or 'no reason specified.')) except: pass else: pass else: pass Infraction.tempban(self, event, member, reason, expires_dt) self.queue_infractions() self.confirm_action( event, maybe_string( reason, u':ok_hand: temp-banned {u} for {t} (`{o}`)', u':ok_hand: temp-banned {u} for {t}', u=member.user, t=humanize.naturaldelta(expires_dt - datetime.utcnow()), )) else: raise CommandFail('invalid user')