Skip to content

Commit

Permalink
idk some update
Browse files Browse the repository at this point in the history
  • Loading branch information
Dhruvacube committed Jan 17, 2022
1 parent f2c92a3 commit 807434a
Show file tree
Hide file tree
Showing 5 changed files with 266 additions and 213 deletions.
252 changes: 239 additions & 13 deletions minato_namikaze/bot_files/cogs/moderation/moderation.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
MemberID,
check_if_warning_system_setup,
has_permissions,
FutureTime,
format_relative
)


Expand Down Expand Up @@ -66,7 +68,7 @@ async def kick(self,
*,
reason=None):
"""A command which kicks a given user"""
member = ctx.get_user(member)

if not await ctx.prompt(
f"Are you sure that you want to **kick** {member} from the guild?",
author_id=ctx.author.id,
Expand Down Expand Up @@ -95,7 +97,7 @@ async def ban(
reason: ActionReason = None,
):
"""A command which bans a given user"""
member = ctx.get_user(member)

if not await ctx.prompt(
f"Are you sure that you want to **ban** {member} from the guild?",
author_id=ctx.author.id,
Expand Down Expand Up @@ -247,7 +249,7 @@ async def banlist(self, ctx, *, member: Optional[Union[str, MemberID,
@has_permissions(kick_members=True)
async def softban(self,
ctx,
member: MemberID,
member: Union[MemberID, discord.Member],
*,
reason: ActionReason = None):
"""Soft bans a member from the server.
Expand All @@ -261,7 +263,7 @@ async def softban(self,
To use this command you must have Kick Members permissions.
"""

member = ctx.get_user(member)

if not await ctx.prompt(
f"Are you sure that you want to **softban** {member} from the guild?",
author_id=ctx.author.id,
Expand All @@ -273,7 +275,7 @@ async def softban(self,

await ctx.guild.ban(member, reason=reason)
await ctx.guild.unban(member, reason=reason)
await ctx.send("\N{OK HAND SIGN}")
await ctx.send("\N{OK HAND SIGN}", delete_after=4)

# Unban
@commands.command()
Expand All @@ -293,8 +295,6 @@ async def unban(self,
To use this command you must have Ban Members permissions.
"""

member = ctx.get_user(member)
if not await ctx.prompt(
f"Are you sure that you want to **unban** {member} from the guild?",
author_id=ctx.author.id,
Expand All @@ -321,15 +321,15 @@ async def unban(self,
async def ar(
self,
ctx,
member: Optional[Union[MemberID, discord.Member]],
member: Union[MemberID, discord.Member],
role: Union[int, discord.Role],
*,
reason: ActionReason = None,
):
"""Adds a role to a given user"""
if member is None:
member = ctx.message.author
member = ctx.get_user(member)

role = ctx.get_roles(role)

if not await ctx.prompt(
Expand All @@ -346,6 +346,226 @@ async def ar(
description=f"I have added the role '{role.mention}' to {member.mention}!",
)
await ctx.send(embed=embed)

@commands.command()
@commands.guild_only()
@has_permissions(ban_members=True)
async def multiban(self, ctx, members: commands.Greedy[MemberID], *, reason: ActionReason = None):
"""Bans multiple members from the server.
This only works through banning via ID.
In order for this to work, the bot must have Ban Member permissions.
To use this command you must have Ban Members permission.
"""
if not await ctx.prompt(
"Are you sure that you want to **ban multiple** members?",
author_id=ctx.author.id):
return

if reason is None:
reason = f'Action done by {ctx.author} (ID: {ctx.author.id})'

total_members = len(members)
if total_members == 0:
return await ctx.send('Missing members to ban.')

confirm = await ctx.prompt(f'This will ban **{plural(total_members):member}**. Are you sure?', reacquire=False)
if not confirm:
return await ctx.send('Aborting.')

failed = 0
for member in members:
try:
await ctx.guild.ban(member, reason=reason)
except discord.HTTPException:
failed += 1

await ctx.send(f'Banned {total_members - failed}/{total_members} members.')

@commands.command()
@commands.guild_only()
@has_permissions(ban_members=True)
async def massban(self, ctx, *, args):
"""Mass bans multiple members from the server.
This command has a powerful "command line" syntax. To use this command
you and the bot must both have Ban Members permission. **Every option is optional.**
Users are only banned **if and only if** all conditions are met.
The following options are valid.
`--channel` or `-c`: Channel to search for message history.
`--reason` or `-r`: The reason for the ban.
`--regex`: Regex that usernames must match.
`--created`: Matches users whose accounts were created less than specified minutes ago.
`--joined`: Matches users that joined less than specified minutes ago.
`--joined-before`: Matches users who joined before the member ID given.
`--joined-after`: Matches users who joined after the member ID given.
`--no-avatar`: Matches users who have no avatar. (no arguments)
`--no-roles`: Matches users that have no role. (no arguments)
`--show`: Show members instead of banning them (no arguments).
Message history filters (Requires `--channel`):
`--contains`: A substring to search for in the message.
`--starts`: A substring to search if the message starts with.
`--ends`: A substring to search if the message ends with.
`--match`: A regex to match the message content to.
`--search`: How many messages to search. Default 100. Max 2000.
`--after`: Messages must come after this message ID.
`--before`: Messages must come before this message ID.
`--files`: Checks if the message has attachments (no arguments).
`--embeds`: Checks if the message has embeds (no arguments).
"""

if not await ctx.prompt(
f"Are you sure that you want to **massban**?",
author_id=ctx.author.id):
return

# For some reason there are cases due to caching that ctx.author
# can be a User even in a guild only context
# Rather than trying to work out the kink with it
# Just upgrade the member itself.
if not isinstance(ctx.author, discord.Member):
try:
author = await ctx.guild.fetch_member(ctx.author.id)
except discord.HTTPException:
return await ctx.send('Somehow, Discord does not seem to think you are in this server.')
else:
author = ctx.author

parser = Arguments(add_help=False, allow_abbrev=False)
parser.add_argument('--channel', '-c')
parser.add_argument('--reason', '-r')
parser.add_argument('--search', type=int, default=100)
parser.add_argument('--regex')
parser.add_argument('--no-avatar', action='store_true')
parser.add_argument('--no-roles', action='store_true')
parser.add_argument('--created', type=int)
parser.add_argument('--joined', type=int)
parser.add_argument('--joined-before', type=int)
parser.add_argument('--joined-after', type=int)
parser.add_argument('--contains')
parser.add_argument('--starts')
parser.add_argument('--ends')
parser.add_argument('--match')
parser.add_argument('--show', action='store_true')
parser.add_argument('--embeds', action='store_const', const=lambda m: len(m.embeds))
parser.add_argument('--files', action='store_const', const=lambda m: len(m.attachments))
parser.add_argument('--after', type=int)
parser.add_argument('--before', type=int)

try:
args = parser.parse_args(shlex.split(args))
except Exception as e:
return await ctx.send(str(e))

members = []

if args.channel:
channel = await commands.TextChannelConverter().convert(ctx, args.channel)
before = args.before and discord.Object(id=args.before)
after = args.after and discord.Object(id=args.after)
predicates = []
if args.contains:
predicates.append(lambda m: args.contains in m.content)
if args.starts:
predicates.append(lambda m: m.content.startswith(args.starts))
if args.ends:
predicates.append(lambda m: m.content.endswith(args.ends))
if args.match:
try:
_match = re.compile(args.match)
except re.error as e:
return await ctx.send(f'Invalid regex passed to `--match`: {e}')
else:
predicates.append(lambda m, x=_match: x.match(m.content))
if args.embeds:
predicates.append(args.embeds)
if args.files:
predicates.append(args.files)

async for message in channel.history(limit=min(max(1, args.search), 2000), before=before, after=after):
if all(p(message) for p in predicates):
members.append(message.author)
else:
if ctx.guild.chunked:
members = ctx.guild.members
else:
async with ctx.typing():
await ctx.guild.chunk(cache=True)
members = ctx.guild.members

# member filters
predicates = [
lambda m: isinstance(m, discord.Member) and can_execute_action(ctx, author, m), # Only if applicable
lambda m: not m.bot, # No bots
lambda m: m.discriminator != '0000', # No deleted users
]

converter = commands.MemberConverter()

if args.regex:
try:
_regex = re.compile(args.regex)
except re.error as e:
return await ctx.send(f'Invalid regex passed to `--regex`: {e}')
else:
predicates.append(lambda m, x=_regex: x.match(m.name))

if args.no_avatar:
predicates.append(lambda m: m.avatar is None)
if args.no_roles:
predicates.append(lambda m: len(getattr(m, 'roles', [])) <= 1)

now = discord.utils.utcnow()
if args.created:
def created(member, *, offset=now - datetime.timedelta(minutes=args.created)):
return member.created_at > offset
predicates.append(created)
if args.joined:
def joined(member, *, offset=now - datetime.timedelta(minutes=args.joined)):
if isinstance(member, discord.User):
# If the member is a user then they left already
return True
return member.joined_at and member.joined_at > offset
predicates.append(joined)
if args.joined_after:
_joined_after_member = await converter.convert(ctx, str(args.joined_after))
def joined_after(member, *, _other=_joined_after_member):
return member.joined_at and _other.joined_at and member.joined_at > _other.joined_at
predicates.append(joined_after)
if args.joined_before:
_joined_before_member = await converter.convert(ctx, str(args.joined_before))
def joined_before(member, *, _other=_joined_before_member):
return member.joined_at and _other.joined_at and member.joined_at < _other.joined_at
predicates.append(joined_before)

members = {m for m in members if all(p(m) for p in predicates)}
if len(members) == 0:
return await ctx.send('No members found matching criteria.')

if args.show:
members = sorted(members, key=lambda m: m.joined_at or now)
fmt = "\n".join(f'{m.id}\tJoined: {m.joined_at}\tCreated: {m.created_at}\t{m}' for m in members)
content = f'Current Time: {discord.utils.utcnow()}\nTotal members: {len(members)}\n{fmt}'
file = discord.File(io.BytesIO(content.encode('utf-8')), filename='members.txt')
return await ctx.send(file=file)

if args.reason is None:
return await ctx.send('--reason flag is required.')
else:
reason = await ActionReason().convert(ctx, args.reason)

confirm = await ctx.prompt(f'This will ban **{plural(len(members)):member}**. Are you sure?')
if not confirm:
return await ctx.send('Aborting.')

count = 0
for member in members:
try:
await ctx.guild.ban(member, reason=reason)
except discord.HTTPException:
pass
else:
count += 1

await ctx.send(f'Banned {count}/{len(members)}')

# Warn
@commands.command(pass_context=True,
Expand All @@ -359,7 +579,7 @@ async def warn(self,
*,
reason: str = None):
"""Warn a user"""
member = ctx.get_user(member)

if not await ctx.prompt(
f"Are you sure that you want to **warn** {member}?",
author_id=ctx.author.id):
Expand Down Expand Up @@ -833,11 +1053,17 @@ def predicate(m):
before=args.before,
after=args.after)

@commands.command()
@commands.command(aliases=['mute'])
@commands.guild_only()
@commands.has_guild_permissions(timeout_members=True)
async def timeout(self, ctx):
pass
@has_permissions(timeout_members=True)
async def timeout(self, ctx, duration: FutureTime, member: Union[MemberID, discord.Member], *, reason: ActionReason = None):
if not await ctx.prompt(
f"Are you sure that you want to **time out** {member} until {format_relative(duration.dt)}?",
author_id=ctx.author.id):
return
await member.edit(timed_out_until=duration.dt)
await ctx.send(embed=discord.Embed(description=f'**Timed out** {member} until {format_relative(duration.dt)}'))


def setup(bot):
Expand Down
Loading

0 comments on commit 807434a

Please sign in to comment.