diff --git a/cogs/channels.py b/cogs/channels.py index ef2aa78..c2c4d66 100644 --- a/cogs/channels.py +++ b/cogs/channels.py @@ -1,8 +1,10 @@ import os -import discord -from discord.ext import commands -from discord import utils + import discord.emoji +from discord import utils +from discord.ext import commands + +from embed import default_embed class Channels(commands.Cog): @@ -21,9 +23,7 @@ def get_news_role(ctx, channel: discord.TextChannel = None): async def leaderboard(self, ctx): roles = [(r.name, len(r.members)) for r in ctx.guild.roles if 'news' in r.name] roles.sort(key=lambda x: x[1], reverse=True) - embed = discord.Embed() - embed.set_author(name="Subscriber Leaderboards", - icon_url="https://cdn.discordapp.com/attachments/336577284322623499/683028692133216300/ac6e275e1f638f4e19af408d8440e1d1.png") + embed = default_embed('Subscriber Leaderboards') for i, r in enumerate(roles): embed.add_field(name=f"{i + 1}. {r[0]}", value=f"**Subscribers:** {r[1]}") await ctx.send(embed=embed) @@ -56,11 +56,9 @@ async def subscribe(self, ctx, channel: discord.TextChannel = None): async def poll(self, ctx, *, args): role = self.get_news_role(ctx) await role.edit(mentionable=True) - await ctx.send(f'{role.mention}') + await ctx.send(role.mention) await role.edit(mentionable=False) - embed = discord.Embed(Title="Poll") - embed.set_author(name="Poll", - icon_url="https://cdn.discordapp.com/attachments/336577284322623499/683028692133216300/ac6e275e1f638f4e19af408d8440e1d1.png") + embed = default_embed('Poll', title='Poll') hasEmojis = ((args.find('[') and args.find(']')) != -1) # Regex? if hasEmojis: diff --git a/cogs/logging.py b/cogs/logging.py index 50be27f..9cbd322 100644 --- a/cogs/logging.py +++ b/cogs/logging.py @@ -1,50 +1,39 @@ import os -import discord + +from discord import TextChannel from discord.ext import commands +from embed import footer_embed + class Logging(commands.Cog): def __init__(self, bot): self.bot = bot + self.log_ch: TextChannel = self.bot.get_channel(int(os.getenv("MESSAGE_LOGS_CHANNEL"))) # Message Logging @commands.Cog.listener() async def on_message_delete(self, message): - channel = self.bot.get_channel(int(os.getenv("MESSAGE_LOGS_CHANNEL"))) # message-logs channel + emb = footer_embed(message, 'Message (Delete)', message.author.avatar_url) # Avoid duplicate channel; i.e message delete from log channel - if message.channel == channel: + if message.channel == self.log_ch: return - # Check Audit logs to find out who deleted the message - entries = await message.guild.audit_logs(limit=None, action=discord.AuditLogAction.message_delete).flatten() - base_entry = entries[0] - - emb = discord.Embed() - emb.set_author(name="Message (Delete)", - icon_url="https://cdn.discordapp.com/attachments/336577284322623499/683028692133216300/ac6e275e1f638f4e19af408d8440e1d1.png") - emb.set_footer(text=f'{message.author}\t\t\t\t\t\tTimestamp: {message.created_at}', - icon_url=message.author.avatar_url) emb.add_field(name="Message", value=message.content) - await channel.send(embed=emb) + await self.log_ch.send(embed=emb) @commands.Cog.listener() async def on_message_edit(self, before, after): - channel = self.bot.get_channel(int(os.getenv("MESSAGE_LOGS_CHANNEL"))) # message-logs channel - # If message data is malformed or blank, return if (before.content == "") or (after.content == ""): return - emb = discord.Embed() - emb.set_author(name="Message (Edit)", - icon_url="https://cdn.discordapp.com/attachments/336577284322623499/683028692133216300/ac6e275e1f638f4e19af408d8440e1d1.png") - emb.set_footer(text=f'{before.author}\t\t\t\t\t\tTimestamp: {after.created_at}', - icon_url=before.author.avatar_url) - emb.add_field(name="Before", value=(before.content), inline=False) - emb.add_field(name="After", value=(after.content), inline=False) - await channel.send(embed=emb) + emb = footer_embed(after, 'Message (Edit)', before.author.avatar_url) + emb.add_field(name="Before", value=before.content, inline=False) + emb.add_field(name="After", value=after.content, inline=False) + await self.log_ch.send(embed=emb) def setup(bot): diff --git a/cogs/maintenance.py b/cogs/maintenance.py index 26e193f..4131087 100644 --- a/cogs/maintenance.py +++ b/cogs/maintenance.py @@ -17,11 +17,12 @@ async def reload(self, ctx, *, name: str): await ctx.send(f'Error: {error}') else: await ctx.send(f'Reloaded: {name}') - + @commands.command() @commands.has_role("Moderator") async def restart(self, ctx): await self.bot.logout() + def setup(bot): bot.add_cog(Maintenance(bot)) diff --git a/cogs/moderation.py b/cogs/moderation.py index ef6399d..67c9ae3 100644 --- a/cogs/moderation.py +++ b/cogs/moderation.py @@ -1,16 +1,42 @@ import os + import discord -from discord.ext import commands from discord import utils +from discord.ext import commands + +import embed from .data import Data db = Data() # Initialize database +def prepare_action(ctx, name: str): + role = utils.get(ctx.guild.roles, name=name) + # Create default embed + emb = embed.footer_embed(ctx.message, 'Moderation') + channel = ctx.message.channel + return role, emb, channel + + +def process_action(ctx, title, emb, member: discord.Member, msg, duration=None): + emb.add_field(name=title, value=f'{member.mention} ({member.id})', inline=False) + if duration: + emb.add_field(name='Duration', value=f'{duration}', inline=False) + emb.add_field(name="Reason", value=f'{msg}', inline=False) + emb.add_field(name="Moderator", + value=ctx.message.author.mention, + inline=False) + # Add data to database + # (Action, Duration, Reason, Moderator, Target, Date) + db.modEntry.insert(title, duration, msg, ctx.message.author.id, member.id, + ctx.message.created_at) + + class Moderation(commands.Cog): def __init__(self, bot): self.bot = bot + self.log_ch: discord.TextChannel = self.bot.get_channel(int(os.getenv("MODERATION_LOGS_CHANNEL"))) @commands.command() @commands.has_role("Moderator") @@ -21,123 +47,54 @@ async def ping_library_developers(self, ctx, title, *, message): await role.edit(mentionable=False) @commands.command() - @commands.has_role("Library Developer" or "Moderator") + @commands.has_any_role("Library Developer", "Moderator") async def mute(self, ctx, member: discord.Member, duration, *, message): - role = utils.get(ctx.guild.roles, name="Muted") - channel = ctx.message.channel - log_channel = self.bot.get_channel(int(os.getenv("MODERATION_LOGS_CHANNEL"))) # moderation-logs channel - - # Create default embed - emb = discord.Embed() - emb.set_author(name="Moderation", - icon_url="https://cdn.discordapp.com/attachments/336577284322623499/683028692133216300/ac6e275e1f638f4e19af408d8440e1d1.png") - emb.set_footer(text=f'\t\t\t\t\t\t\tTimestamp: {ctx.message.created_at}') + role, emb, channel = prepare_action(ctx, 'Muted') # If Moderator invokes, mute from server and not just channel - if ((utils.get(ctx.guild.roles, name="Moderator") in ctx.message.author.roles)): - emb.add_field(name="Mute (Server)", value=f'{member.mention} ({member.id})', inline=False) - emb.add_field(name="Duration", value=f'{duration}', inline=False) - emb.add_field(name="Reason", value=f'{message}', inline=False) - emb.add_field(name="Moderator", - value=f'{ctx.message.author}#{ctx.message.author.discriminator} ({ctx.message.author.id})', - inline=False) + if utils.get(ctx.guild.roles, name='Moderator') in ctx.message.author.roles: + process_action(ctx, 'Mute (Server)', emb, member, message, duration) await member.add_roles(role) - # Add data to database - # (Action, Duration, Reason, Moderator, Target, Date) - db.modEntry.insert("Mute (Server)", duration, message, ctx.message.author.id, member.id, - ctx.message.created_at) - # If Library Developer invokes, mute from channel and not server - elif ((utils.get(ctx.guild.roles, name="Library Developer") in ctx.message.author.roles) and ( + if ((utils.get(ctx.guild.roles, name="Library Developer") in ctx.message.author.roles) and ( channel.category.name == "libraries" or channel.category.name == "frameworks")): - emb.add_field(name="Mute (Channel)", value=f'{member.mention} ({member.id})', inline=False) - emb.add_field(name="Duration", value=f'n/a', inline=False) - emb.add_field(name="Reason", value=f'n/a', inline=False) - emb.add_field(name="Moderator", - value=f'{ctx.message.author}#{ctx.message.author.discriminator} ({ctx.message.author.id})', - inline=False) + process_action(ctx, 'Mute (Channel)', emb, member, 'n/a') await channel.set_permissions(member, read_messages=True, send_messages=False) - # Add data to database - # (Action, Duration, Reason, Moderator, Target, Date) - db.modEntry.insert("Mute (Channel)", duration, message, ctx.message.author.id, member.id, - ctx.message.created_at) - await ctx.message.add_reaction('👍') - await log_channel.send(embed=emb) + await self.log_ch.send(embed=emb) @commands.command() - @commands.has_role("Library Developer" or "Moderator") + @commands.has_any_role("Library Developer", "Moderator") async def unmute(self, ctx, member: discord.Member, *, message): - role = utils.get(ctx.guild.roles, name="Muted") - channel = ctx.message.channel - log_channel = self.bot.get_channel(int(os.getenv("MODERATION_LOGS_CHANNEL"))) # moderation-logs channel - - # Create default embed - emb = discord.Embed() - emb.set_author(name="Moderation", - icon_url="https://cdn.discordapp.com/attachments/336577284322623499/683028692133216300/ac6e275e1f638f4e19af408d8440e1d1.png") - emb.set_footer(text=f'\t\t\t\t\t\t\tTimestamp: {ctx.message.created_at}') + role, emb, channel = prepare_action(ctx, 'Muted') # If Moderator invokes, unmute from server and not just channel - if ((utils.get(ctx.guild.roles, name="Moderator") in ctx.message.author.roles)): - emb.add_field(name="Unmute (Server)", value=f'{member.mention} ({member.id})', inline=False) - emb.add_field(name="Reason", value=f'{message}', inline=False) - emb.add_field(name="Moderator", - value=f'{ctx.message.author}#{ctx.message.author.discriminator} ({ctx.message.author.id})', - inline=False) + if utils.get(ctx.guild.roles, name="Moderator") in ctx.message.author.roles: + process_action(ctx, 'Unmute (Server)', emb, member, message) await member.remove_roles(role) - # Add data to database - # (Action, Duration, Reason, Moderator, Target, Date) - db.modEntry.insert("Unmute (Server)", None, message, ctx.message.author.id, member.id, - ctx.message.created_at) - # If Library Developer invokes, unmute from channel and not server elif ((utils.get(ctx.guild.roles, name="Library Developer") in ctx.message.author.roles) and ( channel.category.name == "libraries" or channel.category.name == "frameworks")): - emb.add_field(name="Unmute (Channel)", value=f'{member.mention} ({member.id})', inline=False) - emb.add_field(name="Reason", value=f'{message}', inline=False) - emb.add_field(name="Moderator", - value=f'{ctx.message.author}#{ctx.message.author.discriminator} ({ctx.message.author.id})', - inline=False) + process_action(ctx, 'Unmute (Channel)', emb, member, message) await channel.set_permissions(member, overwrite=None) - # Add data to database - # (Action, Duration, Reason, Moderator, Target, Date) - db.modEntry.insert("Unmute (Channel)", None, message, ctx.message.author.id, member.id, - ctx.message.created_at) - await ctx.message.add_reaction('👍') - await log_channel.send(embed=emb) + await self.log_ch.send(embed=emb) @commands.command() - @commands.has_role("Library Developer" or "Moderator") + @commands.has_role("Moderator") async def warn(self, ctx, member: discord.Member, *, message): - channel = ctx.message.channel - log_channel = self.bot.get_channel(int(os.getenv("MODERATION_LOGS_CHANNEL"))) # moderation-logs channel - - # Create default embed - emb = discord.Embed() - emb.set_author(name="Moderation", - icon_url="https://cdn.discordapp.com/attachments/336577284322623499/683028692133216300/ac6e275e1f638f4e19af408d8440e1d1.png") - emb.set_footer(text=f'\t\t\t\t\t\t\tTimestamp: {ctx.message.created_at}') - emb.add_field(name="Warn", value=f'{member.mention} ({member.id})', inline=False) - emb.add_field(name="Reason", value=f'{message}', inline=False) - emb.add_field(name="Moderator", - value=f'{ctx.message.author}#{ctx.message.author.discriminator} ({ctx.message.author.id})', - inline=False) - - # Add data to database - # (Action, Duration, Reason, Moderator, Target, Date) - db.modEntry.insert("Warn", None, message, ctx.message.author.id, member.id, ctx.message.created_at) + _, emb, channel = prepare_action(ctx, '') + process_action(ctx, 'Warn', emb, member, message) await ctx.message.add_reaction('👍') - await log_channel.send(embed=emb) + await self.log_ch.send(embed=emb) @commands.command() - @commands.has_role("Library Developer" or "Moderator") + @commands.has_any_role("Library Developer", "Moderator") async def infractions(self, ctx, member: discord.Member): i = 0 @@ -149,14 +106,12 @@ async def infractions(self, ctx, member: discord.Member): await ctx.send(f'User "{member.id}" has no infractions.') return - emb = discord.Embed() - emb.set_author(name="Moderation", - icon_url="https://cdn.discordapp.com/attachments/336577284322623499/683028692133216300/ac6e275e1f638f4e19af408d8440e1d1.png") - emb.set_footer(text=f'\t\t\t\t\t\t\tTimestamp: {ctx.message.created_at}') + _, emb, _ = prepare_action(ctx, '') for case in query: emb.add_field(name=f'Case Number: {case["index"]}', - value=f'Action: {case["action"]}\nDuration: {case["duration"]}\nUser: {case["target"]}\nReason: {case["reason"]}\nModerator: {case["moderator"]}\n Date: {case["date"]}', + value=f'Action: {case["action"]}\nDuration: {case["duration"]}\nUser: {case["target"]}\n' + f'Reason: {case["reason"]}\nModerator: {case["moderator"]}\n Date: {case["date"]}', inline=False) if i >= 25: await ctx.send(embed=emb) @@ -184,37 +139,24 @@ async def duration(self, ctx, id, *, _duration): @commands.command() @commands.has_role("Moderator") - async def clean(self, ctx, amount, member: discord.Member = None): - log_channel = self.bot.get_channel(int(os.getenv("MODERATION_LOGS_CHANNEL"))) # moderation-logs channel - emb = discord.Embed() - emb.set_author(name="Moderation", - icon_url="https://cdn.discordapp.com/attachments/336577284322623499/683028692133216300/ac6e275e1f638f4e19af408d8440e1d1.png") - emb.set_footer(text=f'\t\t\t\t\t\t\tTimestamp: {ctx.message.created_at}') - - # If specific memeber is not specified - if not member: - emb.add_field(name="Message (Clean)", value=f'<#{ctx.message.channel.id}>', inline=False) - emb.add_field(name="Amount", value=f'{amount}', inline=False) - emb.add_field(name="Moderator", - value=f'{ctx.message.author}#{ctx.message.author.discriminator} ({ctx.message.author.id})', - inline=False) - await ctx.message.channel.purge(limit=int(amount) + 1) - await log_channel.send(embed=emb) - return - - # If specific member is specified - emb.add_field(name="Message (Clean)", value=f'<#{ctx.message.channel.id}>', inline=False) - emb.add_field(name="Amount", value=f'{amount}', inline=False) - emb.add_field(name="From", value=f'{member.mention} ({member.id})', inline=False) - emb.add_field(name="Moderator", - value=f'{ctx.message.author}#{ctx.message.author.discriminator} ({ctx.message.author.id})', - inline=False) - - def is_member(message): - return message.author.id == member.id - - await ctx.message.channel.purge(limit=int(amount) + 1, check=is_member) - await log_channel.send(embed=emb) + async def clean(self, ctx, amount: int, member: discord.Member = None): + _, emb, ch = prepare_action(ctx, '') + emb.add_field(name='Message (Clean)', value=ch.mention, inline=False) + + if member: + emb.add_field(name="From", value=member.mention, inline=False) + + def is_member(message): + return message.author.id == member.id + + msgs = await ctx.message.channel.purge(limit=amount + 1, check=is_member) + amount = len(msgs) - 1 + # If specific member is not specified + else: + await ctx.message.channel.purge(limit=amount + 1) + emb.insert_field_at(1, name="Amount", value=str(amount), inline=False) + emb.add_field(name="Moderator", value=ctx.message.author.mention, inline=False) + await self.log_ch.send(embed=emb) def setup(bot): diff --git a/cogs/tagging.py b/cogs/tagging.py index 1122f56..1317edd 100644 --- a/cogs/tagging.py +++ b/cogs/tagging.py @@ -21,14 +21,14 @@ async def tag(self, ctx, name=None): return emb = discord.Embed() emb.set_footer(text=f'\t\t\t\t\t\t\tTimestamp: {result["date"]}', - icon_url="https://cdn.discordapp.com/attachments/336577284322623499/683028692133216300/ac6e275e1f638f4e19af408d8440e1d1.png") + icon_url='https://avatars1.githubusercontent.com/u/42101452?s=200&v=4') emb.add_field(name=f'{name}', value=result["content"], inline=False) await ctx.send(embed=emb) else: result = db.taggingEntry.fetch_all(ctx.message.channel.id) i = 0 if len(result) == 0: - await ctx.send(f'Tags in this channel "<#{ctx.message.channel.id}>" does not exist.') + await ctx.send(f'Tags in this channel "{ctx.channel.mention}" does not exist.') return emb = discord.Embed(title="Available tags for channel") for entry in result: diff --git a/cogs/utility.py b/cogs/utility.py index 1a6f1ed..b9caa6e 100644 --- a/cogs/utility.py +++ b/cogs/utility.py @@ -3,74 +3,86 @@ import yaml import aiohttp +from embed import default_embed + session = aiohttp.ClientSession() +async def check_doc_exists(ctx, doc, version): + base = f'https://{doc}.roblox.com' + async with session.get(f'{base}/docs/json/{version}') as r: + # throws ClientConnectException if base is not a valid subdomain e.g. xx.roblox.com + if r.status != 200: + await ctx.send("Sorry, those docs don't exist.") + return + else: + data = await r.json() + return data, discord.Embed(description=base) + + +async def fetch_embed(filename: str, author: str): + with open(f'yaml/{filename}.yml') as file: + j = file.read() + d = yaml.load(j, Loader=yaml.FullLoader) + emb = discord.Embed.from_dict(d) + emb.set_author(name=author, icon_url='https://avatars1.githubusercontent.com/u/42101452?s=200&v=4') + return emb, d + + class Utility(commands.Cog): def __init__(self, bot): self.bot = bot - async def fetch_embed(self, filename: str): - with open(f'yaml/{filename}.yml') as file: - j = file.read() - d = yaml.load(j, Loader=yaml.FullLoader) - return discord.Embed.from_dict(d), d - - async def check_doc_exists(self, ctx, doc, version): - base = f'https://{doc}.roblox.com' - async with session.get(f'{base}/docs/json/{version}') as r: - if r.status != 200: - return await ctx.send("Sorry, those docs don't exist."), None - else: - data = await r.json() - return data, discord.Embed(description=base) - @commands.command() async def ping(self, ctx): resp = await ctx.send('Pong! Loading...', delete_after=1.0) diff = resp.created_at - ctx.message.created_at totalms = 1000 * diff.total_seconds() - emb = discord.Embed() - emb.set_author(name="Pong!", - icon_url="https://cdn.discordapp.com/attachments/336577284322623499/683028692133216300/ac6e275e1f638f4e19af408d8440e1d1.png") - emb.add_field(name="Message time", value=f"{totalms}ms") - emb.add_field(name="API latency", value=f"{(1000 * self.bot.latency):.1f}ms") + emb = default_embed('Pong!') + emb.add_field(name="Message response time", value=f"{totalms}ms") # Time for receive+process+reply cmd + emb.add_field(name="API latency", value=f"{(1000 * self.bot.latency):.1f}ms") # Official heartbeat latency await ctx.send(embed=emb) @commands.command(aliases=["libs", "libraries", "librarylist"]) - async def list(self, ctx): - embed, yml = await self.fetch_embed('libs') - embed.set_author(name="Libraries", - icon_url="https://cdn.discordapp.com/attachments/336577284322623499/683028692133216300/ac6e275e1f638f4e19af408d8440e1d1.png") - for lang in yml["list"]: - for lib in lang['libs']: - user = self.bot.get_user(lib["uid"]) - embed.add_field(name=f'{lib["name"]}({lang["lang"]})', value=f'{lib["author"]}(@{user}) - {lib["url"]}') - await ctx.send(embed=embed) + async def list(self, ctx, lang: str): + _, yml = await fetch_embed('libs', 'Libraries') + libs = next( + (lang_lib for lang_lib in yml['list'] for lang_str in lang_lib['lang'] if lang.lower() == lang_str.lower()), + None) + if libs: + emb = default_embed(f'{libs["lang"][0]} libraries/frameworks') + for lib in libs['libs']: + # It can only get users/channels that have mutual servers with the bot + # use fetch_xx() if want to fetch users/channels that don't have mutual servers + ch = self.bot.get_channel(lib['chid']) + value = f"[Repo]({lib['url']}) {ch.mention} |" + for uid in lib['uid']: + user = self.bot.get_user(uid) + value += f' {user.mention}' + emb.add_field(name=lib['name'], value=value, inline=False) + await ctx.send(embed=emb) + else: + await ctx.send('Unknown language.') @commands.command(aliases=["codeblocks"]) async def codeblock(self, ctx): - emb, _ = await self.fetch_embed('codeblock') - emb.set_author(name="Codeblocks", - icon_url="https://cdn.discordapp.com/attachments/336577284322623499/683028692133216300/ac6e275e1f638f4e19af408d8440e1d1.png") + emb, _ = await fetch_embed('codeblock', 'Codeblocks') await ctx.send(embed=emb) @commands.command(aliases=["cookies"]) async def cookie(self, ctx): - emb, _ = await self.fetch_embed('cookie') - emb.set_author(name="Cookies", - icon_url="https://cdn.discordapp.com/attachments/336577284322623499/683028692133216300/ac6e275e1f638f4e19af408d8440e1d1.png") + emb, _ = await fetch_embed('cookie', 'Cookies') await ctx.send(embed=emb) @commands.command() async def docs(self, ctx, doc: str, version: str): - data, embed = await self.check_doc_exists(ctx, doc, version) + data, embed = await check_doc_exists(ctx, doc, version) if embed is None: return i = 0 embed.set_author(name=f'{doc.capitalize()} {version}', - icon_url="https://cdn.discordapp.com/attachments/336577284322623499/683028692133216300/ac6e275e1f638f4e19af408d8440e1d1.png") + icon_url="https://avatars1.githubusercontent.com/u/42101452?s=200&v=4") for path in data['paths']: for method in data['paths'][path]: docs = data['paths'][path][method] @@ -85,11 +97,11 @@ async def docs(self, ctx, doc: str, version: str): @commands.command() async def doc(self, ctx, doc: str, version: str, *, args): - data, embed = await self.check_doc_exists(ctx, doc, version) + data, embed = await check_doc_exists(ctx, doc, version) if embed is None: return embed.set_author(name=f'{doc.capitalize()} {version}', - icon_url="https://cdn.discordapp.com/attachments/336577284322623499/683028692133216300/ac6e275e1f638f4e19af408d8440e1d1.png") + icon_url="https://avatars1.githubusercontent.com/u/42101452?s=200&v=4") embed.set_footer(text=f'Keyword(s): {args}') for path in data['paths']: for method in data['paths'][path]: @@ -103,16 +115,12 @@ async def doc(self, ctx, doc: str, version: str, *, args): @commands.command(aliases=["apisites", "robloxapi", "references", "reference"]) async def api(self, ctx): - emb, _ = await self.fetch_embed('endpoints') - emb.set_author(name="References", - icon_url="https://cdn.discordapp.com/attachments/336577284322623499/683028692133216300/ac6e275e1f638f4e19af408d8440e1d1.png") + emb, _ = await fetch_embed('endpoints', 'References') await ctx.send(embed=emb) @commands.command() async def resources(self, ctx): - emb, _ = await self.fetch_embed('resources') - emb.set_author(name="Resources", - icon_url="https://cdn.discordapp.com/attachments/336577284322623499/683028692133216300/ac6e275e1f638f4e19af408d8440e1d1.png") + emb, _ = await fetch_embed('resources', 'Resources') await ctx.send(embed=emb) diff --git a/cogs/verification.py b/cogs/verification.py index 91f7d20..670e20a 100644 --- a/cogs/verification.py +++ b/cogs/verification.py @@ -7,6 +7,8 @@ import random from datetime import datetime +from embed import footer_embed + db = Data() # Initialize database available_words = ["apple", "orange", "pear", "boat", "ship", "car", "plane", "train", "turtle", "cow", "frog", @@ -44,7 +46,8 @@ async def on_member_join(self, member): else: channel_dm = await member.create_dm() await channel_dm.send( - f'It appears that you are not verified with RoVer or our own database. A keyphrase has been sent to your dms. Please verify w/ ``?verify`` in our server.') + f'It appears that you are not verified with RoVer or our own database. A keyphrase has been sent to ' + f'your dms. Please verify w/ ``?verify`` in our server.') @commands.command() async def verify(self, ctx, username: str = None, *, keyPhrase: str = None): @@ -82,7 +85,8 @@ async def verify(self, ctx, username: str = None, *, keyPhrase: str = None): await channel.send( f'Here is your passphrase to verify. Please place this string of text (without quotes) "{temp_passphrase}" in your roblox profile blurb.') await ctx.send( - f'It appears that you are not verified with RoVer or our own database. A keyphrase has been sent to your dms. Please reverify w/ ``?verify ``') + f'It appears that you are not verified with RoVer or our own database. A keyphrase has been sent ' + f'to your dms. Please reverify w/ ``?verify ``') # Custom Verify (Custom solution) elif username and keyPhrase: @@ -111,10 +115,7 @@ async def info(self, ctx, member: discord.Member): await ctx.send(f'User "{member.id}" is not verified.') return - emb = discord.Embed() - emb.set_author(name="Information", - icon_url="https://cdn.discordapp.com/attachments/336577284322623499/683028692133216300/ac6e275e1f638f4e19af408d8440e1d1.png") - emb.set_footer(text=f'\t\t\t\t\t\t\tTimestamp: {ctx.message.created_at}') + emb = footer_embed(ctx.message, 'Information') emb.add_field(name=f'**{member.display_name}**', value=f'Discord Id: {query["discordid"]}\nUsername: {query["username"]}\nUser Id: {query["userid"]}\nDate: {query["date"]}', inline=False) diff --git a/embed.py b/embed.py new file mode 100644 index 0000000..a81e1f7 --- /dev/null +++ b/embed.py @@ -0,0 +1,14 @@ +from discord import Embed + + +def default_embed(author: str, **kwargs): + emb = Embed(**kwargs) + emb.set_author(name=author, icon_url="https://avatars1.githubusercontent.com/u/42101452?s=200&v=4") + return emb + + +def footer_embed(message, author: str, icon_url: str = ''): + emb = default_embed(author) + emb.set_footer(text=f'\t\t\t\t\t\t\tTimestamp: {message.created_at}', icon_url=icon_url) + return emb + diff --git a/generate.py b/generate.py index cbe2b62..c988b9a 100644 --- a/generate.py +++ b/generate.py @@ -1,10 +1,10 @@ import requests import os + # Requirements install per every bot start / restart def install_requirements(): - with open('requirements.txt','r',encoding='utf-8') as file: - + with open('requirements.txt', 'r', encoding='utf-8') as file: # Hacky way to get rid of '/n' in list items requirements = list(map(lambda requirement: requirement.strip(), file.readlines())) for requirement in requirements: @@ -12,10 +12,10 @@ def install_requirements(): # File dynamically loads from git so repo changes are made near constantly -def generate(file,**kwargs): +def generate(file, **kwargs): directory = kwargs.get("directory", None) encoding = kwargs.get("encoding", 'utf-8') - location = file[file.find("/")+1:] + location = file[file.find("/") + 1:] # If directory, append to location if directory: @@ -27,35 +27,35 @@ def generate(file,**kwargs): exit() response = requests.get(f'https://raw.githubusercontent.com/RbxAPI/Docs-Bot/{file}') - with open(location,'w+',encoding=encoding) as file: + with open(location, 'w+', encoding=encoding) as file: file.write(response.text) file.close() # Windows to Mac / Linux / Unix Encoding if os.name == "nt": - with open(location,'rb') as file: + with open(location, 'rb') as file: content = file.read() content.replace(b'\r\n', b'\n') - with open(location,'wb') as file: + with open(location, 'wb') as file: file.write(content) file.close() - + # Mac / Linux / Unix to Windows Encoding elif os.name == "posix": - with open(location,'rb') as file: + with open(location, 'rb') as file: content = file.read() content.replace(b'\n', b'\r\n') - with open(location,'wb') as file: + with open(location, 'wb') as file: file.write(content) file.close() - + # Unsupported Operating System else: print(f'Your operating system "{os.name}" is not supported.') exit() -if __name__ == '__main__': +if __name__ == '__main__': # Install requirements first (add check??) generate('rewrite/requirements.txt') install_requirements() @@ -66,9 +66,10 @@ def generate(file,**kwargs): generate('rewrite/yaml/libs.yml') generate('rewrite/yaml/resources.yml') generate('rewrite/yaml/cookie.yml') - + # Cached Main file generate('rewrite/main.py') + generate('rewrite/embed.py') # Database Interface generate('rewrite/cogs/data.py') @@ -80,4 +81,4 @@ def generate(file,**kwargs): generate('rewrite/cogs/channels.py') generate('rewrite/cogs/moderation.py') generate('rewrite/cogs/verification.py') - generate('rewrite/cogs/tagging.py') \ No newline at end of file + generate('rewrite/cogs/tagging.py') diff --git a/main.py b/main.py index cf23377..4e7a5b8 100644 --- a/main.py +++ b/main.py @@ -1,54 +1,64 @@ -import os -import traceback - -import discord -from discord.ext import commands - -from dotenv import load_dotenv -load_dotenv() - -# A list containing all cogs that we want to load -available_cogs = ['cogs.maintenance', 'cogs.logging', 'cogs.utility', 'cogs.channels', 'cogs.moderation', 'cogs.tagging'] - -# Disabled Cogs -# 'cogs.verification' - -# Bot Init -description = "Roblox API Server Documentation Bot" -bot = commands.Bot(command_prefix='?', description=description, help_command=None) - -# Client Login -@bot.event -async def on_ready(): - print(f"Logged in as {bot.user.name}, id: {bot.user.id}") - print("--") - -# Event Error -@bot.event -async def on_error(event, *args, **kwargs): - channel = channel = bot.get_channel(os.getenv("ERROR_LOGS_CHANNEL")) - emb = discord.Embed(color=discord.Color.red()) - emb.set_author(name="Error (Event)", icon_url="https://cdn.discordapp.com/attachments/336577284322623499/683028692133216300/ac6e275e1f638f4e19af408d8440e1d1.png") - emb.add_field(name="Event", value=event, inline=False) - emb.add_field(name="Traceback", value=traceback.format_exc(), inline=False) - await channel.send(embed=emb) - -# Command Error -@bot.event -async def on_command_error(ctx, error): - channel = channel = bot.get_channel(os.getenv("ERROR_LOGS_CHANNEL")) - emb = discord.Embed(color=discord.Color.red()) - emb.set_author(name="Error (Commands)", icon_url="https://cdn.discordapp.com/attachments/336577284322623499/683028692133216300/ac6e275e1f638f4e19af408d8440e1d1.png") - emb.add_field(name="Error", value=error, inline=False) - emb.add_field(name="Command", value=ctx.command, inline=False) - emb.add_field(name="Message", value=ctx.message.content, inline=False) - await channel.send(embed=emb) - -if __name__ == '__main__': - - # Load Cogs in list - for cog in available_cogs: - bot.load_extension(cog) - - # Run Bot - bot.run(os.getenv("DISCORD_TOKEN")) +import os +import traceback + +import discord +from discord.ext import commands + +from dotenv import load_dotenv + +from embed import default_embed + +load_dotenv() + +# A list containing all cogs that we want to load +available_cogs = ['cogs.maintenance', 'cogs.logging', 'cogs.utility', 'cogs.channels', 'cogs.moderation', + 'cogs.tagging'] + +# Disabled Cogs +# 'cogs.verification' + +# Bot Init +description = "Roblox API Server Documentation Bot" +intent = discord.Intents.default() +intent.members = True +bot = commands.Bot(command_prefix='?', description=description, help_command=None) + + +# Client Login +@bot.event +async def on_ready(): + print(f"Logged in as {bot.user.name}, id: {bot.user.id}") + print("--") + + +# Event Error. the args are required +@bot.event +async def on_error(event, *args, **kwargs): + channel = bot.get_channel(int(os.getenv('ERROR_LOGS_CHANNEL'))) + emb = default_embed('Error (Event)', color=discord.Color.red()) + emb.add_field(name="Event", value=event, inline=False) + emb.add_field(name="Traceback", value=traceback.format_exc(), inline=False) + await channel.send(embed=emb) + + +# Command Error +@bot.event +async def on_command_error(ctx, error): + channel = bot.get_channel(int(os.getenv('ERROR_LOGS_CHANNEL'))) + emb = default_embed('Error (Commands)', color=discord.Color.red()) + emb.add_field(name="Error", value=error, inline=False) + emb.add_field(name="Command", value=ctx.command, inline=False) + emb.add_field(name="Message", value=ctx.message.content, inline=False) + await channel.send(embed=emb) + + +if __name__ == '__main__': + async def prep(): + await bot.wait_until_ready() + # Load Cogs in list + for cog in available_cogs: + bot.load_extension(cog) + + # Run Bot + bot.loop.create_task(prep()) + bot.run(os.getenv("DISCORD_TOKEN")) diff --git a/requirements.txt b/requirements.txt index 3950e4f..c412d83 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ PyYAML -discord.py +discord.py>=1.5 emoji python-dotenv requests diff --git a/yaml/libs.yml b/yaml/libs.yml index 551713f..d0fbf53 100644 --- a/yaml/libs.yml +++ b/yaml/libs.yml @@ -1,112 +1,74 @@ -description: General library list and frameworks specific to this server -thumbnail: - url: https://avatars1.githubusercontent.com/u/42101452?s=200&v=4 - list: - - lang: Python + - lang: [Python, py] libs: - name: Pyblox - author: Sanjay-B - uid: 179201489363795968 + dev: https://github.com/Sanjay-B + uid: [179201489363795968] + chid: 332928926857035776 url: https://github.com/RbxAPI/Pyblox - - name: Robloxlib - author: NoahCristino - uid: 283667489471332354 - url: https://github.com/NoahCristino/robloxlib - - - name: RobloxAPI - author: iranathan - uid: 427040024513609729 - url: https://github.com/iranathan/robloxapi + - name: ro.py + dev: https://github.com/jmk-developer + uid: [197683356643753984, 427040024513609729] + chid: 785226119602241536 + url: https://github.com/rbx-libdev/ro.py - - lang: JavaScript + - lang: [JavaScript, js] libs: - - name: Roblox.js - author: sentanos - uid: 137543748434395136 - url: https://github.com/sentanos/roblox-js - - name: Nodeblox.js - author: suufi - uid: 88410718314971136 + uid: [88410718314971136] + chid: 429453333640773638 url: https://github.com/suufi/noblox.js - name: Bloxy - author: MartinRBX - uid: 211122613429338112 + uid: [211122613429338112] + chid: 465546625406730262 url: https://github.com/MartinRBX/bloxy - - lang: TypeScript - libs: - - name: TSBlox - author: Dionysusnu - uid: 214262712753061889 - url: https://github.com/Dionysusnu/tsblox + - name: rbxdatastoreservice + uid: [360078081224081409] + chid: 798107527467368478 + url: https://github.com/nsg-mfd/RbxDataStoreService - - lang: Lua + - lang: [Lua] libs: - - name: RobloxCommunication - author: CrescentCode - uid: 131823956255571969 - url: https://github.com/CrescentCode/RobloxCommunication + - name: rbx.lua + uid: [335248825880936448] + chid: 771903890144100353 + url: https://github.com/iiToxicity/rbx.lua - name: RoStrap - author: RoStrap - uid: 127858186530062336 + uid: [127858186530062336] + chid: 336144578619113483 url: https://github.com/RoStrap/RoStrapUI - name: Overture - author: devSparkle - uid: 196716483567419403 + uid: [196716483567419403] + chid: 564233540095705089 url: https://github.com/devSparkle/Overture - - name: MaterialR - author: fivefactor - uid: 609167831950557348 - url: https://devforum.roblox.com/t/materialr-ui-framework/330396 + - name: MaterialPlus + uid: [609167831950557348] + chid: 611760560853352473 + url: https://devforum.roblox.com/t/materialplus-documentation/588828 - - lang: C# + - lang: [C#, csharp, cs] libs: - name: RobloxAPI - author: gamenew09 - uid: 125802100373454848 + uid: [125802100373454848] + chid: 336634936025022475 url: https://github.com/gamenew09/RobloxAPI - - lang: PHP + - lang: [Java, jar] libs: - - name: Roblophp - author: WebDevTrop - uid: 217971702733209600 - url: https://github.com/WebDevTrop/roblophp - - - lang: Java - libs: - - name: Javablox - author: Pythonic-Rainbow - uid: 264756129916125184 - url: https://github.com/RbxAPI/Javablox - - name: Roblox4j - author: PizzaCrust - uid: 185697212976726018 + uid: [185697212976726018] + chid: 430023138550611974 url: https://github.com/PizzaCrust/Roblox4j - - lang: Kotlin - libs: - - name: KotlinRoblox - author: PizzaCrust - uid: 185697212976726018 - url: https://github.com/PizzaCrust/KotlinRoblox - - - name: Roblox.kt - author: FreeLineTM - uid: 179256560139108352 - url: https://github.com/FreeLineTM/roblox.kt - - - lang: C++ + - lang: [C++, cpp] libs: - name: Cblox - author: Meqolo - uid: 298012370217992192 + uid: [298012370217992192] + chid: 571877645797687355 url: https://github.com/Meqolo/cblox