Well, this was at least 2 years in the making. Thanks to Sitryk who did the most work on this, and thanks to Axas for writing the original find/cmd_lookup command.
814 lines
31 KiB
Python
814 lines
31 KiB
Python
# Most of these tools are thanks to Sitryk.
|
|
# Credit for the findcog/cmd_lookup command belongs to Axas, thanks for the inspiration for
|
|
# the findcog command in Red v3.
|
|
|
|
from discord.ext import commands
|
|
from .utils.chat_formatting import pagify, box, escape_mass_mentions
|
|
from .utils.dataIO import dataIO
|
|
from .utils import checks
|
|
from __main__ import send_cmd_help
|
|
from tabulate import tabulate
|
|
import discord
|
|
import glob
|
|
import os
|
|
import datetime
|
|
import asyncio
|
|
import discord
|
|
import random
|
|
import inspect
|
|
|
|
ini = "```ini\n{0}\n```"
|
|
|
|
|
|
class Tools:
|
|
"""Mod and Admin tools."""
|
|
|
|
def __init__(self, bot):
|
|
self.bot = bot
|
|
|
|
@checks.mod_or_permissions(manage_messages=True)
|
|
@commands.group(pass_context=True, no_pm=True)
|
|
async def access(self, ctx):
|
|
"""Check channel access."""
|
|
if ctx.invoked_subcommand is None:
|
|
await send_cmd_help(ctx)
|
|
return
|
|
|
|
@checks.mod_or_permissions(manage_messages=True)
|
|
@access.command(pass_context=True)
|
|
async def compare(self, ctx, user: discord.User, server: discord.Server = None):
|
|
"""Compare channel access with [user]"""
|
|
author = ctx.message.author
|
|
if user is None:
|
|
return
|
|
if server is None:
|
|
server = ctx.message.server
|
|
|
|
text_channels = [c for c in server.channels if str(c.type) == "text"]
|
|
voice_channels = [c for c in server.channels if str(c.type) == "voice"]
|
|
|
|
author_text_channels = [
|
|
c.name for c in text_channels if c.permissions_for(author).read_messages is True
|
|
]
|
|
author_voice_channels = [
|
|
c.name for c in voice_channels if c.permissions_for(author).connect is True
|
|
]
|
|
|
|
user_text_channels = [
|
|
c.name for c in text_channels if c.permissions_for(user).read_messages is True
|
|
]
|
|
user_voice_channels = [
|
|
c.name for c in voice_channels if c.permissions_for(user).connect is True
|
|
]
|
|
|
|
author_only_t = set(author_text_channels) - set(
|
|
user_text_channels
|
|
) # text channels only the author has access to
|
|
author_only_v = set(author_voice_channels) - set(
|
|
user_voice_channels
|
|
) # voice channels only the author has access to
|
|
|
|
user_only_t = set(user_text_channels) - set(
|
|
author_text_channels
|
|
) # text channels only the user has access to
|
|
user_only_v = set(user_voice_channels) - set(
|
|
author_voice_channels
|
|
) # voice channels only the user has access to
|
|
|
|
common_t = list(
|
|
set(text_channels) - author_only_t - user_only_t
|
|
) # text channels that author and user have in common
|
|
common_v = list(
|
|
set(voice_channels) - author_only_v - user_only_v
|
|
) # voice channels that author and user have in common
|
|
|
|
msg = "```ini\n"
|
|
msg += "{} [TEXT CHANNELS IN COMMON]:\n\n{}\n\n".format(
|
|
len(common_t), ", ".join([c.name for c in common_t])
|
|
)
|
|
msg += "{} [TEXT CHANNELS {} HAS ACCESS TO]:\n\n{}\n\n".format(
|
|
len(user_only_t), user.name.upper(), ", ".join(list(user_only_t))
|
|
)
|
|
msg += "{} [TEXT CHANNELS YOU HAVE ACCESS TO]:\n\n{}\n\n".format(
|
|
len(author_only_t), ", ".join(list(author_only_t))
|
|
)
|
|
msg += "{} [VOICE CHANNELS IN COMMON]:\n\n{}\n\n".format(
|
|
len(common_v), ", ".join([c.name for c in common_v])
|
|
)
|
|
msg += "{} [VOICE CHANNELS {} HAS ACCESS TO]:\n\n{}\n\n".format(
|
|
len(user_only_v), user.name.upper(), ", ".join(list(user_only_v))
|
|
)
|
|
msg += "{} [VOICE CHANNELS YOU HAVE ACCESS TO]:\n\n{}\n\n".format(
|
|
len(author_only_v), ", ".join(list(author_only_v))
|
|
)
|
|
msg += "```"
|
|
await self.bot.say(msg)
|
|
|
|
@checks.mod_or_permissions(manage_messages=True)
|
|
@access.command(pass_context=True)
|
|
async def text(self, ctx, user: discord.Member = None, server: discord.Server = None):
|
|
"""Fetch which text channels you have access to."""
|
|
author = ctx.message.author
|
|
if server is None:
|
|
server = ctx.message.server
|
|
if user is None:
|
|
user = author
|
|
|
|
can_access = [
|
|
c.name
|
|
for c in server.channels
|
|
if c.permissions_for(user).read_messages == True and str(c.type) == "text"
|
|
]
|
|
text_channels = [c.name for c in server.channels if str(c.type) == "text"]
|
|
|
|
prefix = "You have" if user.id == author.id else user.name + " has"
|
|
msg = "```ini\n[{} access to {} out of {} text channels]\n\n".format(
|
|
prefix, len(can_access), len(text_channels)
|
|
)
|
|
|
|
msg += "[ACCESS]:\n{}\n\n".format(", ".join(can_access))
|
|
msg += "[NO ACCESS]:\n{}\n```".format(
|
|
", ".join(list(set(text_channels) - set(can_access)))
|
|
)
|
|
await self.bot.say(msg)
|
|
|
|
@checks.mod_or_permissions(manage_messages=True)
|
|
@access.command(pass_context=True)
|
|
async def voice(self, ctx, user: discord.Member = None, server: discord.Server = None):
|
|
"""Fetch which voice channels you have access to."""
|
|
author = ctx.message.author
|
|
if server is None:
|
|
server = ctx.message.server
|
|
if user is None:
|
|
user = author
|
|
|
|
can_access = [
|
|
c.name
|
|
for c in server.channels
|
|
if c.permissions_for(user).connect is True and str(c.type) == "voice"
|
|
]
|
|
voice_channels = [c.name for c in server.channels if str(c.type) == "voice"]
|
|
|
|
prefix = "You have" if user.id == author.id else user.name + " has"
|
|
msg = "```ini\n[{} access to {} out of {} voice channels]\n\n".format(
|
|
prefix, len(can_access), len(voice_channels)
|
|
)
|
|
|
|
msg += "[ACCESS]:\n{}\n\n".format(", ".join(can_access))
|
|
msg += "[NO ACCESS]:\n{}\n```".format(
|
|
", ".join(list(set(voice_channels) - set(can_access)))
|
|
)
|
|
await self.bot.say(msg)
|
|
|
|
@commands.command(pass_context=True)
|
|
@checks.admin_or_permissions(manage_server=True)
|
|
async def banlist(self, ctx):
|
|
"""Displays the server's banlist."""
|
|
try:
|
|
banlist = await self.bot.get_bans(ctx.message.server)
|
|
except discord.errors.Forbidden:
|
|
await self.bot.say("I do not have the `Ban Members` permission.")
|
|
return
|
|
bancount = len(banlist)
|
|
if bancount == 0:
|
|
banlist = "No users are banned from this server."
|
|
else:
|
|
banlist = ", ".join(map(str, banlist))
|
|
|
|
for page in pagify(banlist, ["\n"], shorten_by=13, page_length=2000):
|
|
await self.bot.say(box(page, "ini"))
|
|
|
|
@commands.command(pass_context=True, no_pm=True)
|
|
async def cid(self, ctx, channel: discord.Channel = None):
|
|
"""Shows the channel ID."""
|
|
if not channel:
|
|
channel = ctx.message.channel
|
|
await self.bot.say("**#{0.name} ID:** {0.id}".format(channel))
|
|
|
|
@commands.command(pass_context=True)
|
|
async def cinfo(self, ctx, channel: discord.Channel = None):
|
|
"""Shows channel information. Defaults to current text channel."""
|
|
yesno = {True: "Yes", False: "No"}
|
|
if not channel:
|
|
channel = ctx.message.channel
|
|
|
|
load = "```\nLoading channel info...```"
|
|
waiting = await self.bot.say(load)
|
|
|
|
try:
|
|
caller = inspect.currentframe().f_back.f_code.co_name
|
|
except:
|
|
pass
|
|
|
|
data = "```ini\n"
|
|
if caller == "whatis":
|
|
data == "[Server]: {}\n".format(channel.server.name)
|
|
data += "[Name]: {}\n".format(escape_mass_mentions(str(channel)))
|
|
data += "[ID]: {}\n".format(channel.id)
|
|
data += "[Default]: {}\n".format(yesno[channel.is_default])
|
|
data += "[Private]: {}\n".format(yesno[channel.is_private])
|
|
if str(channel.type) == "text" and channel.topic != "":
|
|
data += "[Topic]: {}\n".format(channel.topic)
|
|
data += "[Position]: {}\n".format(channel.position)
|
|
data += "[Created]: {} ago\n".format(self._dynamic_time(channel.created_at))
|
|
data += "[Type]: {}\n".format(channel.type)
|
|
if str(channel.type) == "voice":
|
|
data += "[Users]: {}\n".format(len(channel.voice_members))
|
|
data += "[User limit]: {}\n".format(channel.user_limit)
|
|
data += "[Bitrate]: {}\n".format(channel.bitrate)
|
|
data += "```"
|
|
await asyncio.sleep(2)
|
|
await self.bot.edit_message(waiting, data)
|
|
|
|
@commands.command(pass_context=True)
|
|
@checks.is_owner()
|
|
async def ecogs(self, ctx):
|
|
"""Lists status of installed cogs"""
|
|
owner_cog = self.bot.get_cog("Owner")
|
|
total_cogs = owner_cog._list_cogs()
|
|
loaded = [c.__module__.split(".")[1] for c in self.bot.cogs.values()]
|
|
unloaded = [c.split(".")[1] for c in total_cogs if c.split(".")[1] not in loaded]
|
|
if not unloaded:
|
|
unloaded = ["None"]
|
|
|
|
items = {
|
|
0: {
|
|
"cogs": sorted(loaded),
|
|
"msg": "**{} loaded:**\n".format(len(loaded)),
|
|
"colour": discord.Colour.dark_green(),
|
|
},
|
|
1: {
|
|
"cogs": sorted(unloaded),
|
|
"msg": "**{} unloaded:**\n".format(len(unloaded)),
|
|
"colour": discord.Colour.dark_red(),
|
|
},
|
|
}
|
|
for index, em in enumerate(items):
|
|
e = discord.Embed(
|
|
description=items[index]["msg"] + ", ".join(items[index]["cogs"]),
|
|
colour=items[index]["colour"],
|
|
)
|
|
await self.bot.say(embed=e)
|
|
|
|
@commands.command(pass_context=True)
|
|
async def eid(self, ctx, emoji):
|
|
"""Get an id for a custom emoji."""
|
|
if emoji[0] != "<":
|
|
await self.bot.say(
|
|
"I could not an ID for this emoji, this may be because it is not a custom emoji."
|
|
)
|
|
return
|
|
id = emoji.split(":")[2][:-1]
|
|
await self.bot.say(id)
|
|
|
|
@checks.is_owner()
|
|
@commands.command(aliases=["find", "cmd_lookup"])
|
|
async def findcog(self, command: str):
|
|
"""Cog search by command.
|
|
This is only applicable for loaded cogs that were installed through [p]cog install."""
|
|
try:
|
|
cog_name = self.bot.get_cog(self.bot.get_command(command).cog_name).__module__[5:]
|
|
except:
|
|
await self.bot.say(
|
|
"Either that command doesn't exist, or the cog this command belongs to wasn't added through the downloader cog."
|
|
)
|
|
return
|
|
repos = dataIO.load_json("data/downloader/repos.json")
|
|
cog_path = (
|
|
lambda x: "\n".join(
|
|
[
|
|
filename
|
|
for filename in glob.iglob("data/downloader/**/*.py", recursive=True)
|
|
if "{}.py".format(x) == filename[((len("{}.py".format(x))) * -1) :]
|
|
]
|
|
)
|
|
)(cog_name)
|
|
if not cog_path:
|
|
await self.bot.say("This is a command that's in a cog that's not published in a repo.")
|
|
return
|
|
if os.name == "nt":
|
|
repo = cog_path.split(os.sep)[1]
|
|
else:
|
|
repo = cog_path.split(os.sep)[2]
|
|
if "url" not in repos[repo]:
|
|
with open("data/downloader/" + repo + "/.git/config", "r") as f:
|
|
url = re.findall(r"(http(s)?:\/\/[a-zA-Z0-9\:\.\-\_\/\?\=\%]*)", f.read())[0][0]
|
|
else:
|
|
url = repos[repo]["url"]
|
|
await self.bot.say(
|
|
box(
|
|
"Command name: {}\nMade by: {}\nRepo: {}\nCog Name: {}.py".format(
|
|
command, url.split("/")[3], url, cog_name
|
|
)
|
|
)
|
|
)
|
|
|
|
@checks.admin_or_permissions(manage_roles=True)
|
|
@commands.command(pass_context=True)
|
|
async def inrole(self, ctx, *, rolename):
|
|
"""Check members in the role specified."""
|
|
await self.bot.send_typing(ctx.message.channel)
|
|
role = discord.utils.find(
|
|
lambda r: r.name.lower() == rolename.lower(), ctx.message.server.roles
|
|
)
|
|
|
|
if role is None:
|
|
roles = []
|
|
for r in ctx.message.server.roles:
|
|
if rolename.lower() in r.name.lower():
|
|
roles.append(r)
|
|
|
|
if len(roles) == 1:
|
|
role = roles[0]
|
|
elif len(roles) < 1:
|
|
await self.bot.say("no roles found")
|
|
return
|
|
else:
|
|
msg = "**Roles found with** {} **in the name.**\n\n".format(rolename)
|
|
tbul8 = []
|
|
for num, role in enumerate(roles):
|
|
tbul8.append([num + 1, role.name])
|
|
m1 = await self.bot.say(msg + tabulate(tbul8, tablefmt="plain"))
|
|
response = await self.bot.wait_for_message(
|
|
author=ctx.message.author, channel=ctx.message.channel, timeout=25
|
|
)
|
|
if response is None:
|
|
await self.bot.delete_message(m1)
|
|
return
|
|
elif response.content.isdigit():
|
|
await self.bot.delete_message(m1)
|
|
return
|
|
else:
|
|
response = int(response.content)
|
|
|
|
if response not in range(0, len(roles) + 1):
|
|
await self.bot.delete_message(m1)
|
|
return
|
|
elif response == 0:
|
|
await self.bot.delete_message(m1)
|
|
return
|
|
else:
|
|
role = roles[response - 1]
|
|
|
|
if (
|
|
role is not None
|
|
and len([m for m in ctx.message.server.members if role in m.roles]) < 50
|
|
):
|
|
awaiter = await self.bot.say(
|
|
embed=discord.Embed(description="Getting member names...")
|
|
)
|
|
await asyncio.sleep(2.5)
|
|
role_member = discord.Embed(
|
|
description="**{1} users found in the {0} role.**\n".format(
|
|
role.name, len([m for m in ctx.message.server.members if role in m.roles])
|
|
)
|
|
)
|
|
role_users = [m.display_name for m in ctx.message.server.members if role in m.roles]
|
|
if not role_users:
|
|
role_member.add_field(name="Users", value="None.")
|
|
else:
|
|
role_member.add_field(name="Users", value="\n".join(role_users))
|
|
await self.bot.edit_message(awaiter, embed=role_member)
|
|
|
|
elif len([m for m in ctx.message.server.members if role in m.roles]) > 50:
|
|
awaiter = await self.bot.say(
|
|
embed=discord.Embed(description="Getting member names...")
|
|
)
|
|
await asyncio.sleep(2.5)
|
|
await self.bot.edit_message(
|
|
awaiter,
|
|
embed=discord.Embed(
|
|
description="List is too long for **{0}** role, **{1}** members found.\n".format(
|
|
role.name, len([m.mention for m in server.members if role in m.roles])
|
|
)
|
|
),
|
|
)
|
|
else:
|
|
embed = discord.Embed(description="Role was not found.")
|
|
await self.bot.edit_message(embed=embed)
|
|
|
|
@commands.command(pass_context=True, no_pm=True)
|
|
@checks.mod_or_permissions(manage_messages=True)
|
|
async def newusers(self, ctx, count: int = 5, server: discord.Server = None):
|
|
"""Lists the newest 5 members."""
|
|
if server is None:
|
|
server = ctx.message.server
|
|
count = max(min(count, 25), 5)
|
|
members = sorted(server.members, key=lambda m: m.joined_at, reverse=True)[:count]
|
|
e = discord.Embed(title="New Members")
|
|
for member in members:
|
|
msg = "**Joined Server:** {} ago\n**Account created:** {} ago".format(
|
|
self._dynamic_time(member.joined_at), self._dynamic_time(member.created_at)
|
|
)
|
|
e.add_field(
|
|
name="{0.display_name} (ID: {0.id})".format(member), value=msg, inline=False
|
|
)
|
|
await self.bot.say(embed=e)
|
|
|
|
@commands.command(pass_context=True, no_pm=True)
|
|
async def sid(self, ctx):
|
|
"""Shows the server ID."""
|
|
await self.bot.say("**{0.name} ID:** {0.id}".format(ctx.message.server))
|
|
|
|
@commands.command(pass_context=True)
|
|
@checks.mod_or_permissions(manage_messages=True)
|
|
async def userstats(self, ctx, this_server: bool = False):
|
|
"""A small amount of user stats."""
|
|
embeds = {}
|
|
if this_server:
|
|
members = set([x for x in ctx.message.server.members])
|
|
else:
|
|
members = set([x for x in self.bot.get_all_members()])
|
|
|
|
items = {
|
|
2: {
|
|
"users": len([e.name for e in members if e.status == discord.Status.idle]),
|
|
"colour": discord.Colour.orange(),
|
|
},
|
|
3: {
|
|
"users": len([e.name for e in members if e.status == discord.Status.dnd]),
|
|
"colour": discord.Colour.red(),
|
|
},
|
|
4: {
|
|
"users": len([e.name for e in members if e.status == discord.Status.offline]),
|
|
"colour": discord.Colour.dark_grey(),
|
|
},
|
|
1: {
|
|
"users": len([e.name for e in members if e.status == discord.Status.online]),
|
|
"colour": discord.Colour.green(),
|
|
},
|
|
0: {
|
|
"users": len([e.name for e in members if e.game and e.game.url]),
|
|
"colour": discord.Colour.dark_purple(),
|
|
},
|
|
}
|
|
|
|
for item in items:
|
|
embeds[item] = discord.Embed(
|
|
description="Users: {}".format(items[item]["users"]), colour=items[item]["colour"]
|
|
)
|
|
for i, em in enumerate(embeds):
|
|
await self.bot.say(embed=embeds[i])
|
|
|
|
@commands.command(pass_context=True, no_pm=True)
|
|
async def sinfo(self, ctx, server: discord.Server = None):
|
|
"""Shows server information."""
|
|
if server is None:
|
|
server = ctx.message.server
|
|
online = str(
|
|
len(
|
|
[
|
|
m.status
|
|
for m in server.members
|
|
if str(m.status) == "online" or str(m.status) == "idle"
|
|
]
|
|
)
|
|
)
|
|
total_users = str(len(server.members))
|
|
text_channels = [x for x in server.channels if str(x.type) == "text"]
|
|
voice_channels = [x for x in server.channels if str(x.type) == "voice"]
|
|
|
|
load = "```\nLoading server info...```"
|
|
waiting = await self.bot.say(load)
|
|
|
|
data = "```ini\n"
|
|
data += "[Name]: {}\n".format(server.name)
|
|
data += "[ID]: {}\n".format(server.id)
|
|
data += "[Region]: {}\n".format(server.region)
|
|
data += "[Owner]: {}\n".format(server.owner)
|
|
data += "[Users]: {}/{}\n".format(online, total_users)
|
|
data += "[Text]: {} channels\n".format(len(text_channels))
|
|
data += "[Voice]: {} channels\n".format(len(voice_channels))
|
|
data += "[Emojis]: {}\n".format(len(server.emojis))
|
|
data += "[Roles]: {} \n".format(len(server.roles))
|
|
data += "[Created]: {} ago\n```".format(self._dynamic_time(server.created_at))
|
|
await asyncio.sleep(3)
|
|
await self.bot.edit_message(waiting, data)
|
|
|
|
@commands.command(pass_context=True, no_pm=True)
|
|
@checks.mod_or_permissions(manage_messages=True)
|
|
async def perms(self, ctx, user: discord.Member = None):
|
|
"""Fetch a specific user's permissions."""
|
|
if user is None:
|
|
user = ctx.message.author
|
|
|
|
perms = iter(ctx.message.channel.permissions_for(user))
|
|
perms_we_have = "```diff\n"
|
|
perms_we_dont = ""
|
|
for x in perms:
|
|
if "True" in str(x):
|
|
perms_we_have += "+\t{0}\n".format(str(x).split("'")[1])
|
|
else:
|
|
perms_we_dont += "-\t{0}\n".format(str(x).split("'")[1])
|
|
await self.bot.say("{0}{1}```".format(perms_we_have, perms_we_dont))
|
|
|
|
@commands.command(pass_context=True)
|
|
async def rid(self, ctx, rolename):
|
|
"""Shows the id of a role, use quotes on the role."""
|
|
await self.bot.send_typing(ctx.message.channel)
|
|
if rolename is discord.Role:
|
|
role = rolename
|
|
else:
|
|
role = self._role_from_string(ctx.message.server, rolename)
|
|
if role is None:
|
|
return await self.bot.say(embed=discord.Embed(description="Cannot find role."))
|
|
await self.bot.say(
|
|
embed=discord.Embed(description="**{}** ID: {}".format(rolename, role.id))
|
|
)
|
|
|
|
@commands.command(pass_context=True)
|
|
async def rinfo(self, ctx, rolename):
|
|
"""Shows role info, use quotes on the role."""
|
|
server = ctx.message.server
|
|
colour = str(random.randint(0, 0xFFFFFF))
|
|
colour = int(colour, 16)
|
|
await self.bot.send_typing(ctx.message.channel)
|
|
|
|
try:
|
|
caller = inspect.currentframe().f_back.f_code.co_name
|
|
except:
|
|
pass
|
|
|
|
if type(rolename) is not discord.Role:
|
|
role = discord.utils.find(
|
|
lambda r: r.name.lower() == rolename.lower(), ctx.message.server.roles
|
|
)
|
|
else:
|
|
role = rolename
|
|
if role is None:
|
|
await self.bot.say("That role cannot be found.")
|
|
return
|
|
if role is not None:
|
|
perms = iter(role.permissions)
|
|
perms_we_have = ""
|
|
perms_we_dont = ""
|
|
for x in perms:
|
|
if "True" in str(x):
|
|
perms_we_have += "{0}\n".format(str(x).split("'")[1])
|
|
else:
|
|
perms_we_dont += "{0}\n".format(str(x).split("'")[1])
|
|
msg = discord.Embed(description="Gathering role stats...", colour=role.color)
|
|
if role.color is None:
|
|
role.color = discord.Colour(value=colour)
|
|
msg2 = await self.bot.say(embed=msg)
|
|
em = discord.Embed(colour=role.colour)
|
|
if caller == "whatis":
|
|
em.add_field(name="Server", value=role.server.name)
|
|
em.add_field(name="Role Name", value=role.name)
|
|
em.add_field(name="Created", value=self._dynamic_time(role.created_at))
|
|
em.add_field(
|
|
name="Users in Role",
|
|
value=len([m for m in ctx.message.server.members if role in m.roles]),
|
|
)
|
|
em.add_field(name="Id", value=role.id)
|
|
em.add_field(name="Color", value=role.color)
|
|
em.add_field(name="Position", value=role.position)
|
|
em.add_field(name="Valid Permissons", value="{}".format(perms_we_have))
|
|
em.add_field(name="Invalid Permissons", value="{}".format(perms_we_dont))
|
|
em.set_thumbnail(url=role.server.icon_url)
|
|
try:
|
|
await self.bot.edit_message(msg2, embed=em)
|
|
except discord.HTTPException:
|
|
perms_msg = "```diff\n"
|
|
role = discord.utils.find(
|
|
lambda r: r.name.lower() == rolename.lower(), ctx.message.server.roles
|
|
)
|
|
if role is None:
|
|
await bot.say("That role cannot be found.")
|
|
return
|
|
if role is not None:
|
|
perms = iter(role.permissions)
|
|
perms_we_have2 = ""
|
|
perms_we_dont2 = ""
|
|
for x in perms:
|
|
if "True" in str(x):
|
|
perms_we_have2 += "+{0}\n".format(str(x).split("'")[1])
|
|
else:
|
|
perms_we_dont2 += "-{0}\n".format(str(x).split("'")[1])
|
|
await self.bot.say(
|
|
"{}Name: {}\nCreated: {}\nUsers in Role : {}\nId : {}\nColor : {}\nPosition : {}\nValid Perms : \n{}\nInvalid Perms : \n{}```".format(
|
|
perms_msg,
|
|
role.name,
|
|
self._dynamic_time(role.created_at),
|
|
len([m for m in server.members if role in m.roles]),
|
|
role.id,
|
|
role.color,
|
|
role.position,
|
|
perms_we_have2,
|
|
perms_we_dont2,
|
|
)
|
|
)
|
|
await self.bot.delete_message(msg2)
|
|
|
|
@commands.command(pass_context=True, hidden=True)
|
|
@checks.mod_or_permissions(manage_messages=True)
|
|
async def sharedservers(self, ctx, user: discord.Member = None):
|
|
"""Shows shared server info. Defaults to author."""
|
|
author = ctx.message.author
|
|
server = ctx.message.server
|
|
if not user:
|
|
user = author
|
|
seen = len(
|
|
set(
|
|
[
|
|
member.server.name
|
|
for member in self.bot.get_all_members()
|
|
if member.name == user.name
|
|
]
|
|
)
|
|
)
|
|
sharedservers = str(
|
|
set(
|
|
[
|
|
member.server.name
|
|
for member in self.bot.get_all_members()
|
|
if member.name == user.name
|
|
]
|
|
)
|
|
)
|
|
for shared in sharedservers:
|
|
shared = "".strip("'").join(sharedservers).strip("'")
|
|
shared = shared.strip("{").strip("}")
|
|
|
|
data = "[Servers]: {} shared\n".format(seen)
|
|
data += "[In Servers]: {}\n".format(shared)
|
|
|
|
for page in pagify(data, ["\n"], shorten_by=13, page_length=2000):
|
|
await self.bot.say(box(page, "ini"))
|
|
|
|
@commands.command(pass_context=True)
|
|
async def uinfo(self, ctx, user: discord.Member = None):
|
|
"""Shows user information. Defaults to author."""
|
|
if not user:
|
|
user = ctx.message.author
|
|
try:
|
|
caller = inspect.currentframe().f_back.f_code.co_name
|
|
except:
|
|
pass
|
|
roles = [x.name for x in user.roles if x.name != "@everyone"]
|
|
if not roles:
|
|
roles = ["None"]
|
|
seen = str(
|
|
len(
|
|
set(
|
|
[
|
|
member.server.name
|
|
for member in self.bot.get_all_members()
|
|
if member.id == user.id
|
|
]
|
|
)
|
|
)
|
|
)
|
|
|
|
load = "```\nLoading user info...```"
|
|
waiting = await self.bot.say(load)
|
|
|
|
data = "```ini\n"
|
|
data += "[Name]: {}\n".format(escape_mass_mentions(str(user)))
|
|
data += "[Nickname]: {}\n".format(escape_mass_mentions(str(user.nick)))
|
|
data += "[ID]: {}\n".format(user.id)
|
|
data += "[Status]: {}\n".format(user.status)
|
|
data += "[Servers]: {} shared\n".format(seen)
|
|
if user.game is None:
|
|
pass
|
|
elif user.game.url is None:
|
|
data += "[Playing]: {}\n".format(escape_mass_mentions(str(user.game)))
|
|
else:
|
|
data += "[Streaming]: [{}]({})\n".format(
|
|
escape_mass_mentions(str(user.game)), escape_mass_mentions(user.game.url)
|
|
)
|
|
passed = (ctx.message.timestamp - user.created_at).days
|
|
data += "[Created]: {} ago\n".format(self._dynamic_time(user.created_at))
|
|
joined_at = self.fetch_joined_at(user, ctx.message.server)
|
|
if caller != "whatis":
|
|
data += "[Joined]: {} ago\n".format(self._dynamic_time(joined_at))
|
|
data += "[Roles]: {}\n".format(", ".join(roles))
|
|
data += "[In Voice]: {}\n".format(str(user.voice_channel))
|
|
data += "[AFK]: {}\n".format(user.is_afk)
|
|
data += "```"
|
|
await asyncio.sleep(3)
|
|
await self.bot.edit_message(waiting, data)
|
|
|
|
@commands.command(pass_context=True)
|
|
async def whatis(self, ctx, id):
|
|
"""What is it?"""
|
|
server = ctx.message.server
|
|
channel = ctx.message.channel
|
|
author = ctx.message.author
|
|
|
|
it_is = False
|
|
msg = False
|
|
|
|
if server.id == id:
|
|
it_is = server
|
|
elif channel.id == id:
|
|
it_is = channel
|
|
elif author.id == id:
|
|
it_is = author
|
|
|
|
if not it_is:
|
|
for server in self.bot.servers:
|
|
if server.id == id:
|
|
it_is = server
|
|
break
|
|
if not it_is:
|
|
for emoji in self.bot.get_all_emojis():
|
|
if emoji.id == id:
|
|
it_is = emoji
|
|
break
|
|
if not it_is:
|
|
for server in self.bot.servers:
|
|
for role in server.roles:
|
|
if role.id == id:
|
|
it_is = role
|
|
break
|
|
if not it_is:
|
|
for member in self.bot.get_all_members():
|
|
if member.id == id:
|
|
it_is = member
|
|
break
|
|
if not it_is:
|
|
for channel in self.bot.get_all_channels():
|
|
if channel.id == id:
|
|
it_is = channel
|
|
break
|
|
|
|
if not msg:
|
|
if type(it_is) == discord.Channel:
|
|
await ctx.invoke(self.cinfo, it_is)
|
|
elif type(it_is) == discord.Server:
|
|
await ctx.invoke(self.sinfo, it_is)
|
|
elif type(it_is) == discord.User or type(it_is) == discord.Member:
|
|
await ctx.invoke(self.uinfo, it_is)
|
|
elif type(it_is) == discord.Role:
|
|
await ctx.invoke(self.roleinfo, it_is)
|
|
elif type(it_is) == discord.Emoji:
|
|
await self.bot.say(
|
|
"<:{0.name}:{0.id}>\n```ini\n[NAME]: {0.name}\n[SERVER]: {0.server}\n[URL]: {0.url}```".format(
|
|
it_is
|
|
)
|
|
)
|
|
else:
|
|
await self.bot.say(
|
|
"I could not find anything for this ID, I do not support Message IDs"
|
|
)
|
|
else:
|
|
await self.bot.say("```\nNothing found for this ID```")
|
|
|
|
@staticmethod
|
|
def _dynamic_time(time):
|
|
date_join = datetime.datetime.strptime(str(time), "%Y-%m-%d %H:%M:%S.%f")
|
|
date_now = datetime.datetime.now(datetime.timezone.utc)
|
|
date_now = date_now.replace(tzinfo=None)
|
|
since_join = date_now - date_join
|
|
|
|
m, s = divmod(int(since_join.total_seconds()), 60)
|
|
h, m = divmod(m, 60)
|
|
d, h = divmod(h, 24)
|
|
|
|
if d > 0:
|
|
msg = "{0}d {1}h"
|
|
elif d == 0 and h > 0:
|
|
msg = "{1}h {2}m"
|
|
elif d == 0 and h == 0 and m > 0:
|
|
msg = "{2}m {3}s"
|
|
elif d == 0 and h == 0 and m == 0 and s > 0:
|
|
msg = "{3}s"
|
|
else:
|
|
msg = ""
|
|
return msg.format(d, h, m, s)
|
|
|
|
def fetch_joined_at(self, user, server):
|
|
return user.joined_at
|
|
|
|
def _role_from_string(self, server, rolename, roles=None):
|
|
if roles is None:
|
|
roles = server.roles
|
|
role = discord.utils.find(lambda r: r.name.lower() == rolename.lower(), roles)
|
|
return role
|
|
|
|
|
|
def setup(bot):
|
|
cmds = [
|
|
"access",
|
|
"banlist",
|
|
"cid",
|
|
"cinfo",
|
|
"ecogs",
|
|
"eid",
|
|
"findcog",
|
|
"inrole",
|
|
"newusers",
|
|
"perms",
|
|
"rid",
|
|
"rinfo",
|
|
"sid",
|
|
"sinfo",
|
|
"uinfo",
|
|
"userstatst",
|
|
"whatis",
|
|
]
|
|
for cmd in cmds:
|
|
bot.remove_command(cmd)
|
|
bot.add_cog(Tools(bot))
|