aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cogs/archive.py101
-rw-r--r--src/cogs/owner/sync.py87
-rw-r--r--src/schemas/message_schema.py12
-rw-r--r--src/utils/command_tree.py19
-rw-r--r--src/utils/db.py9
5 files changed, 228 insertions, 0 deletions
diff --git a/src/cogs/archive.py b/src/cogs/archive.py
new file mode 100644
index 0000000..36c7044
--- /dev/null
+++ b/src/cogs/archive.py
@@ -0,0 +1,101 @@
+import discord
+from discord import app_commands
+from discord.ext import commands
+import aiohttp
+import random
+import string
+import os
+
+from src.utils.db import get_db
+from models import Message
+from config import BOT_COLOR
+
+
+class Archive(commands.Cog):
+ def __init__(self, bot):
+ self.bot = bot
+
+ @app_commands.command()
+ async def archive(
+ self,
+ interaction: discord.Interaction,
+ channel: discord.TextChannel,
+ amount: int,
+ ):
+ """Archive a channel's messages."""
+ if not channel.permissions_for(
+ interaction.guild.me
+ ).read_message_history:
+ return await interaction.response.send_message(
+ "I do not have permission to read message history in that"
+ " channel.",
+ ephemeral=True,
+ )
+
+ if amount < 1:
+ return await interaction.response.send_message(
+ "You must provide a number greater than 0.",
+ ephemeral=True,
+ )
+
+ await interaction.response.send_message("Archiving messages now.")
+
+ db = next(get_db())
+ count = 0
+ messages = channel.history(limit=amount)
+ async for message in messages:
+ count += 1
+
+ author = message.author
+ stickers = [sticker.name for sticker in message.stickers]
+ role_mentions = [
+ role_mention.id for role_mention in message.role_mentions
+ ]
+ mention_everyone = message.mention_everyone
+ mentions = [mention.id for mention in message.mentions]
+ attachments = [
+ attachment.url for attachment in message.attachments
+ ]
+
+ if not os.path.exists("images"):
+ os.makedirs("images")
+
+ # Download all images before saving everything to database
+ for url in attachments:
+ async with aiohttp.ClientSession() as session:
+ async with session.get(url) as response:
+ if response.status == 200:
+ # Create a randomized filename
+ filename = "".join(
+ random.choice(string.ascii_letters)
+ for i in range(10)
+ )
+
+ # Save the image to the filesystem
+ with open(f"images/{filename}.jpg", "wb") as file:
+ file.write(await response.read())
+
+ # Update the attachment URL to the new filename
+ attachments[attachments.index(url)] = (
+ f"images/{filename}.jpg"
+ )
+
+ content = message.content
+
+ db_message = Message(
+ author_id=author.id,
+ channel_id=channel.id,
+ stickers=stickers,
+ role_mentions=role_mentions,
+ mention_everyone=mention_everyone,
+ mentions=mentions,
+ attachments=attachments,
+ content=content,
+ )
+
+ db.add(db_message)
+ db.commit()
+
+
+async def setup(bot):
+ await bot.add_cog(Archive(bot))
diff --git a/src/cogs/owner/sync.py b/src/cogs/owner/sync.py
new file mode 100644
index 0000000..d6647b5
--- /dev/null
+++ b/src/cogs/owner/sync.py
@@ -0,0 +1,87 @@
+import discord
+from discord.ext import commands
+
+
+class TreeSync(commands.Cog):
+ def __init__(self, bot):
+ self.bot = bot
+
+ @commands.group(invoke_without_command=True)
+ @commands.dm_only()
+ @commands.is_owner()
+ async def tree(self, ctx):
+ await ctx.author.send(
+ "This is a group command. Use either"
+ f" `{self.bot.command_prefix}tree sync` or"
+ f" `{self.bot.command_prefix}tree clear` followed by an optional"
+ " guild ID."
+ )
+
+ @commands.dm_only()
+ @commands.is_owner()
+ @tree.command()
+ async def sync(
+ self, ctx: commands.Context, *, guild: discord.Object = None
+ ):
+ """Sync the command tree to a guild or globally."""
+ if guild:
+ self.bot.tree.copy_global_to(guild=guild)
+ await self.bot.tree.sync(guild=guild)
+ return await ctx.author.send(
+ "Synced the command tree to"
+ f" `{self.bot.get_guild(guild.id).name}`"
+ )
+ else:
+ await self.bot.tree.sync()
+ return await ctx.author.send("Synced the command tree globally.")
+
+ @sync.error
+ async def tree_sync_error(self, ctx, error):
+ if isinstance(error, commands.ObjectNotFound):
+ return await ctx.author.send(
+ "The guild you provided does not exist."
+ )
+ if isinstance(error, commands.CommandInvokeError):
+ return await ctx.author.send(
+ "Guild ID provided is not a guild that the bot is in."
+ )
+ else:
+ return await ctx.author.send(
+ "An unknown error occurred. Perhaps you've been rate limited."
+ )
+
+ @commands.dm_only()
+ @commands.is_owner()
+ @tree.command()
+ async def clear(self, ctx: commands.Context, *, guild: discord.Object):
+ """Clear the command tree from a guild."""
+ self.bot.tree.clear_commands(guild=guild)
+ await self.bot.tree.sync(guild=guild)
+ return await ctx.author.send(
+ "Cleared the command tree from"
+ f" `{self.bot.get_guild(guild.id).name}`"
+ )
+
+ @clear.error
+ async def tree_sync_error(self, ctx, error):
+ if isinstance(error, commands.MissingRequiredArgument):
+ return await ctx.author.send(
+ "You need to provide a guild ID to clear the command tree"
+ " from."
+ )
+ if isinstance(error, commands.ObjectNotFound):
+ return await ctx.author.send(
+ "The guild you provided does not exist."
+ )
+ if isinstance(error, commands.CommandInvokeError):
+ return await ctx.author.send(
+ "Guild ID provided is not a guild that the bot is in."
+ )
+ else:
+ return await ctx.author.send(
+ "An unknown error occurred. Perhaps you've been rate limited."
+ )
+
+
+async def setup(bot):
+ await bot.add_cog(TreeSync(bot))
diff --git a/src/schemas/message_schema.py b/src/schemas/message_schema.py
new file mode 100644
index 0000000..79c9659
--- /dev/null
+++ b/src/schemas/message_schema.py
@@ -0,0 +1,12 @@
+from pydantic import BaseModel
+
+
+class Message(BaseModel):
+ author_id: int
+ channel_id: int
+ stickers: list[str]
+ role_mentions: list[int]
+ mention_everyone: bool
+ mentions: list[int]
+ attachments: list[str]
+ content: str
diff --git a/src/utils/command_tree.py b/src/utils/command_tree.py
new file mode 100644
index 0000000..31ec2c1
--- /dev/null
+++ b/src/utils/command_tree.py
@@ -0,0 +1,19 @@
+import discord
+from discord import app_commands
+from discord.ext.commands.errors import *
+
+from config import create_embed
+
+
+class Tree(app_commands.CommandTree):
+ async def on_error(
+ self,
+ interaction: discord.Interaction,
+ error: app_commands.AppCommandError,
+ ):
+
+ if isinstance(error, CommandNotFound):
+ return
+
+ else:
+ raise error
diff --git a/src/utils/db.py b/src/utils/db.py
new file mode 100644
index 0000000..a6734ea
--- /dev/null
+++ b/src/utils/db.py
@@ -0,0 +1,9 @@
+from database import SessionLocal
+
+
+def get_db():
+ db = SessionLocal()
+ try:
+ yield db
+ finally:
+ db.close()