diff --git a/bot/__init__.py b/bot/__init__.py
index d2101537..65afb06b 100644
--- a/bot/__init__.py
+++ b/bot/__init__.py
@@ -19,7 +19,7 @@ import os
import random
import aiohttp
-import aiomysql
+import asyncpg as asyncpg
import discord
from decouple import config
from discord import Colour, Embed
@@ -44,7 +44,7 @@ port = config('DB_PORT')
db = config('DB_NAME')
disc_bots_gg_auth = config('DISCORD_BOTS_BOTS_AUTH')
-# Getting the Bot token from Environment Variables
+# Getting the bot token from environment variables
API_TOKEN = config('DISCORD_TOKEN')
@@ -53,20 +53,21 @@ class Bot(commands.Bot):
async def get_prefix(bot, message):
"""Allow the commands to be used with mentioning the bot"""
+
if message.guild is None:
- return "~"
- return when_mentioned_or(self.get_prefix_for_guild(str(message.guild.id)))(bot, message)
+ return "."
+ return when_mentioned_or(self.get_prefix_for_guild(message.guild.id))(bot, message)
super().__init__(command_prefix=get_prefix, **options)
self.db = None
- self.description = 'All current available commands within Ensō~Chan', # Set a description for the bot
+ self.description = 'All current available commands within Ensō~Chan',
self.owner_id = 154840866496839680 # Your unique User ID
self.case_insensitive = True # Commands are now Case Insensitive
self.admin_colour = Colour(0x62167a) # Admin Embed Colour
- self.version = "0.7.2" # Version number of Ensō~Chan
+ self.version = "0.8.2" # Version number of Ensō~Chan
self.remove_command("help") # Remove default help command
- # Define variables that are for Enso only
+ # Instance variables for Enso
self.hammyMention = '<@154840866496839680>'
self.hammy_role_ID = "<@&715412394968350756>"
self.blank_space = "\u200b"
@@ -80,74 +81,66 @@ class Bot(commands.Bot):
self.enso_modmail_ID = 728083016290926623
self.enso_feedback_ID = 739807803438268427
+ # Instance variables for cache
self.enso_cache = {}
- self.member_cache = MyCoolCache(1000)
-
- async def check_cache(member_id, guild_id):
-
- pool = self.db
-
- # If the key is within the cache already
- if (member_id, guild_id) in self.member_cache.cache:
- return self.member_cache.cache[member_id, guild_id]
-
- else:
- # fetch data from database
- # Setup pool connection and cursor
- async with pool.acquire() as conn:
- async with conn.cursor() as author_cursor:
- # Get the author's/members row from the Members Table
- select_query = """SELECT * FROM members WHERE discordID = (%s) and guildID = (%s)"""
- member_val = member_id, guild_id,
-
- # Execute The SQL Query
- await author_cursor.execute(select_query, member_val)
- result = await author_cursor.fetchone()
-
- # Store it in cache
- dict_items = {"married": result[1],
- "marriage_date": result[2],
- "muted_roles": result[4],
- "roles": result[5]}
- self.member_cache.store_cache([member_id, guild_id], dict_items)
+ self.modmail_cache = {}
+ self.member_cache = MyCoolCache(2)
async def create_connection():
"""Setting up connection using pool/aiomysql"""
- self.db = await aiomysql.create_pool(
+ self.db = await asyncpg.create_pool(
host=host,
port=int(port),
user=user,
password=password,
- db=db,
- loop=self.loop)
+ database=db,
+ loop=self.loop,
+ command_timeout=60)
async def startup_cache_log():
- """Store the modlogs/prefixes in cache from the database on startup"""
+ """Store the guilds/modmail systems in cache from the database on startup"""
- # Setup pool
+ # Setup up pool connection
pool = self.db
-
- # Setup up pool connection and cursor
async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Grab the prefix of the server from the database
- select_query = """SELECT * FROM guilds"""
- # Execute the query
- await cur.execute(select_query)
- results = await cur.fetchall()
+ # Query to get all records of guilds that the bot is in
+ try:
+ results = await conn.fetch("""SELECT * FROM guilds""")
- # Store the guildID's, modlog channels and prefixes within cache
+ # Store the guilds information within cache
+ for row in results:
+ self.enso_cache[row[0]] = {"prefix": row[1],
+ "modlogs": row[2],
+ "roles_persist": row[3]}
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print("PostGres Error: Guild Records Could Not Be Loaded Into Cache On Startup", e)
+
+ # Query to get all records of modmails within guilds
+ try:
+ results = await conn.fetch("""SELECT * FROM moderatormail""")
+
+ # Store the information for modmail within cache
for row in results:
- self.enso_cache[row[0]] = {"prefix": row[1], "modlogs": row[2], "roles_persist": row[3]}
+ self.modmail_cache[row[0]] = {"modmail_channel_id": row[1],
+ "message_id": row[2],
+ "modmail_logging_channel_id": row[3]}
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print("PostGres Error: Modmail Records Could Not Be Loaded Into Cache On Startup", e)
- # Make sure the connection is setup before the bot is ready
+ # Release connection back to pool
+ await pool.release(conn)
+
+ # Establish Database Connection
self.loop.run_until_complete(create_connection())
+ # Load Information Into Cache
self.loop.run_until_complete(startup_cache_log())
async def post_bot_stats():
- """Method To Update Guild Count On discord.bots.gg"""
+ """Update guild count on discord.bots.gg"""
async with aiohttp.ClientSession() as session:
await session.post(f"https://discord.bots.gg/api/v1/bots/{self.user.id}/stats",
@@ -158,13 +151,13 @@ class Bot(commands.Bot):
@tasks.loop(minutes=10, reconnect=True)
async def change_status():
- """Creating Custom Statuses as a Background Task"""
+ """Creating custom statuses as background task"""
global counter
# Waiting for the bot to ready
await self.wait_until_ready()
- # Update Guild Count on discord.bots.gg
+ # Update guild count on discord.bots.gg
await post_bot_stats()
# Define array of statuses
@@ -178,7 +171,7 @@ class Bot(commands.Bot):
discord.Activity(
type=discord.ActivityType.watching,
name=f"Hamothy Program | {self.version}"),
- discord.Game(name=f"~help | {self.version}")
+ discord.Game(name=f".help | {self.version}")
]
# Check if the counter is at the end of the array
@@ -197,10 +190,12 @@ class Bot(commands.Bot):
# --------------------------------------------!Cache Section!-------------------------------------------------------
- def store_cache(self, guild_id, prefix, channel, rolespersist):
- """Storing GuildID, Modlogs Channel and Prefix in Cache"""
+ def store_cache(self, guild_id, prefix, modlogs, roles_persist):
+ """Storing guild information within cache"""
- self.enso_cache[guild_id] = {"prefix": prefix, "modlogs": channel, "roles_persist": rolespersist}
+ self.enso_cache[guild_id] = {"prefix": prefix,
+ "modlogs": modlogs,
+ "roles_persist": roles_persist}
def del_cache(self, guild_id):
"""Deleting the entry of the guild within the cache"""
@@ -209,6 +204,35 @@ class Bot(commands.Bot):
# --------------------------------------------!End Cache Section!---------------------------------------------------
+ # --------------------------------------------!Modmail Section!-----------------------------------------------------
+
+ def cache_store_modmail(self, guild_id, modmail_channel, message, modmail_logging_channel):
+ """Storing all modmail channels within cache"""
+
+ self.modmail_cache[guild_id] = {"modmail_channel_id": modmail_channel,
+ "message_id": message,
+ "modmail_logging_channel_id": modmail_logging_channel}
+
+ def get_modmail(self, guild_id):
+ """Returning the modmail system of the guild"""
+
+ if guild_id in self.modmail_cache:
+ return self.modmail_cache[guild_id]
+ else:
+ return None
+
+ def update_modmail(self, guild_id, channel_id):
+ """Update the modmail channel"""
+
+ self.modmail_cache[guild_id]["roles_persist"] = channel_id
+
+ def delete_modmail(self, guild_id):
+ """Deleting the modmail system of the guild within the Cache"""
+
+ del self.modmail_cache[guild_id]
+
+ # --------------------------------------------!EndModmail Section!--------------------------------------------------
+
# --------------------------------------------!RolePersist Section!-------------------------------------------------
def get_roles_persist(self, guild_id):
@@ -216,57 +240,67 @@ class Bot(commands.Bot):
return self.enso_cache[guild_id]["roles_persist"]
- async def update_role_persist(self, guild_id, value, pool):
+ async def update_role_persist(self, guild_id, value):
"""Update the rolepersist value of the guild (Enabled or Disabled)"""
- self.enso_cache[guild_id]["roles_persist"] = value
-
- # Setup up pool connection and cursor
+ # Setup up pool connection
+ pool = self.db
async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Update the existing prefix within the database
- update_query = """UPDATE guilds SET rolespersist = (%s) WHERE guildID = (%s)"""
- update_vals = value, guild_id,
- # Execute the query
- await cur.execute(update_query, update_vals)
- await conn.commit()
+ # Query for updating rolepersist values For guilds
+ try:
+ update_query = """UPDATE guilds SET roles_persist = $1 WHERE guild_id = $2"""
+ await conn.execute(update_query, value, guild_id)
+
+ # Catch error
+ except asyncpg.PostgresError as e:
+ print(f"PostGres Error: RolePersist For Guild {guild_id} Could Not Be Updated", e)
+
+ # Store in cache
+ else:
+ self.enso_cache[guild_id]["roles_persist"] = value
+
+ # Release connection back to pool
+ finally:
+ await pool.release(conn)
# --------------------------------------------!End RolePersist Section!---------------------------------------------
# --------------------------------------------!ModLogs Section!-----------------------------------------------------
- async def storage_modlog_for_guild(self, pool, ctx, channel_id, setup):
+ async def storage_modlog_for_guild(self, ctx, channel_id, setup):
"""Updating the modlog within the dict and database"""
- self.enso_cache[str(ctx.guild.id)]["modlogs"] = channel_id
-
- # Setup up pool connection and cursor
+ # Setup up pool connection
+ pool = self.db
async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Update the existing modlogs channel within the database
- update_query = """UPDATE guilds SET modlogs = (%s) WHERE guildID = (%s)"""
- update_vals = channel_id, ctx.guild.id,
-
- # Execute the query
- await cur.execute(update_query, update_vals)
- await conn.commit()
-
- # Send custom confirmation messages to log based on the command update or setup
- if setup:
- print(cur.rowcount, f"Modlog channel for guild {ctx.guild.name} has been Setup")
- else:
- print(cur.rowcount, f"Modlog channel for guild {ctx.guild.name} has been Updated")
- if setup:
- # Send confirmation that modmail channel has been setup
- await self.bot.generate_embed(ctx, desc=f"**Modlogs Channel** successfully setup in <#{channel_id}>" +
- f"\nPlease refer to **{ctx.prefix}help** for any information")
- else:
- # Let the user know that the guild modlogs channel has been updated
- channel = ctx.guild.get_channel(channel_id)
- await self.generate_embed(ctx,
- desc=f"Modlog Channel for **{ctx.guild.name}** has been updated to {channel.mention}")
+ # Query to update modlogs within the database
+ try:
+ update_query = """UPDATE guilds SET modlogs = $1 WHERE guild_id = $2"""
+ rowcount = await conn.execute(update_query, channel_id, ctx.guild.id)
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print("PostGres Error: Modlogs Value In Guilds Table Could Not Be Updated/Setup", e)
+
+ # Let the user know that modlogs channel has been updated/setup
+ else:
+ if setup:
+ print(rowcount, f"Modlog channel for guild {ctx.guild} has been Setup")
+ await self.generate_embed(ctx, desc=f"**Modlogs Channel** successfully setup in <#{channel_id}>" +
+ f"\nPlease refer to **{ctx.prefix}help** for any information")
+ else:
+ print(rowcount, f"Modlog channel for guild {ctx.guild} has been Updated")
+ await self.generate_embed(ctx,
+ desc=f"Modlog Channel for **{ctx.guild}** has been updated to <#{channel_id}>")
+
+ # Store in cache
+ self.enso_cache[ctx.guild.id]["modlogs"] = channel_id
+
+ # Release connection back to pool
+ finally:
+ await pool.release(conn)
def remove_modlog_channel(self, guild_id):
"""Remove the value of modlog for the guild specified"""
@@ -283,33 +317,42 @@ class Bot(commands.Bot):
# --------------------------------------------!Prefixes Section!----------------------------------------------------
- async def storage_prefix_for_guild(self, pool, ctx, prefix):
+ async def storage_prefix_for_guild(self, ctx, prefix):
"""Updating the prefix within the dict and database when the method is called"""
- self.enso_cache[str(ctx.guild.id)]["prefix"] = prefix
-
- # Setup up pool connection and cursor
+ # Setup up pool connection
+ pool = self.db
async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Update the existing prefix within the database
- update_query = """UPDATE guilds SET prefix = (%s) WHERE guildID = (%s)"""
- update_vals = prefix, ctx.guild.id,
- # Execute the query
- await cur.execute(update_query, update_vals)
- await conn.commit()
- print(cur.rowcount, f"Guild prefix has been updated for guild {ctx.guild.name}")
+ # Query to update the existing prefix within the database
+ try:
+ update_query = """UPDATE guilds SET prefix = $1 WHERE guild_id = $2"""
+
+ rowcount = await conn.execute(update_query, prefix, ctx.guild.id)
+ print(rowcount, f"Guild prefix has been updated for guild {ctx.guild}")
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print(f"PostGres Error: Prefix For Guild {ctx.guild.id} Could Not Be Updated", e)
- # Let the user know that the guild prefix has been updated
- await self.generate_embed(ctx, desc=f"**Guild prefix has been updated to `{prefix}`**")
+ # Let the user know that the guild prefix has been updated
+ else:
+ await self.generate_embed(ctx, desc=f"Guild prefix has been updated to **{prefix}**")
+
+ # Store in cache
+ self.enso_cache[ctx.guild.id]["prefix"] = prefix
+
+ # Release connection back to pool
+ finally:
+ await pool.release(conn)
def get_prefix_for_guild(self, guild_id):
"""Get the prefix of the guild that the user is in"""
prefix = self.enso_cache[guild_id]["prefix"]
- if prefix is not None:
+ if prefix:
return prefix
- return "~"
+ return "."
# --------------------------------------------!End Prefixes Section!------------------------------------------------
@@ -322,7 +365,7 @@ class Bot(commands.Bot):
return Colour(random.randint(0, 0xFFFFFF))
async def generate_embed(self, ctx, desc):
- """Generate Embed"""
+ """Generate embed"""
embed = Embed(description=desc,
colour=self.admin_colour)
@@ -330,40 +373,55 @@ class Bot(commands.Bot):
await ctx.send(embed=embed)
async def storeRoles(self, target, ctx, member):
- """Storing User Roles within Database"""
-
- pool = self.db
+ """Storing user roles within database"""
role_ids = ", ".join([str(r.id) for r in target.roles])
- # Setup up pool connection and cursor
+ # Setup up pool connection
+ pool = self.db
async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Store the existing roles of the user within the database
- update_query = """UPDATE members SET mutedroles = (%s) WHERE guildID = (%s) AND discordID = (%s)"""
- update_vals = role_ids, ctx.guild.id, member.id
- # Execute the query
- await cur.execute(update_query, update_vals)
- await conn.commit()
- print(cur.rowcount, f"Roles Added For User {member} in {ctx.guild.name}")
+ # Query to store existing roles of the member within the database
+ try:
+ update_query = """UPDATE members SET muted_roles = $1 WHERE guild_id = $2 AND member_id = $3"""
+ rowcount = await conn.execute(update_query, role_ids, ctx.guild.id, member.id)
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print(f"PostGres Error: Roles Could Not Be Stored For Member {member.id} in Guild {member.guild.id}", e)
+
+ # Print success
+ else:
+ print(rowcount, f"Roles Added For User {member} in {ctx.guild}")
+
+ # Release connection back to pool
+ finally:
+ await pool.release(conn)
async def clearRoles(self, member):
"""Clear the roles when the user has been unmuted"""
+ # Setup up pool connection
pool = self.db
-
- # Setup up pool connection and cursor
async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Clear the existing roles of the user from the database
- update_query = """UPDATE members SET mutedroles = NULL WHERE guildID = (%s) AND discordID = (%s)"""
- update_vals = member.guild.id, member.id
- # Execute the query
- await cur.execute(update_query, update_vals)
- await conn.commit()
- print(cur.rowcount, f"Roles Cleared For User {member} in {member.guild.name}")
+ # Query to clear the existing role of the member from the database
+ try:
+ update_query = """UPDATE members SET muted_roles = NULL WHERE guild_id = $1 AND member_id = $2"""
+ rowcount = await conn.execute(update_query, member.guild.id, member.id)
+
+ # Catch error
+ except asyncpg.PostgresError as e:
+ print(f"PostGres Error: Roles Could Not Be Cleared for Member {member.id} in Guild {member.guild.id}",
+ e)
+
+ # Print success
+ else:
+ print(rowcount, f"Roles Cleared For User {member} in {member.guild.name}")
+
+ # Release connection back to pool
+ finally:
+ await pool.release(conn)
# --------------------------------------------!End Roles/Colour/Embed Section!--------------------------------------
@@ -379,7 +437,8 @@ class Bot(commands.Bot):
@staticmethod
async def on_ready():
- """Displaying if Bot is Ready"""
+ """Display Startup Message"""
+
print("UvU Senpaiii I'm ready\n")
async def on_guild_join(self, guild):
@@ -388,70 +447,81 @@ class Bot(commands.Bot):
Store prefix/modlogs in the cache
"""
- # Store guildID, modlogs channel and prefix to cache
- self.store_cache(str(guild.id), channel=None, prefix="~", rolespersist=0)
+ # Store every single record into an array
+ records = [(member.id, None, None, guild.id, None, None) for member in guild.members]
- # Setup pool
+ # Setup up pool connection
pool = self.db
+ async with pool.acquire() as conn:
- # Grabbing the values to be inserted
- records = ", ".join(map(lambda m: f"({guild.id}, {m.id})", guild.members))
+ # Query to insert the guild information into guilds table
+ try:
+ insert_query = """INSERT INTO guilds VALUES ($1, $2, $3, $4) ON CONFLICT (guild_id) DO NOTHING"""
+ rowcount = await conn.execute(insert_query, guild.id, ".", None, 0)
- # Setup up pool connection and cursor
- async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Define the insert statement for inserting the guild into the guilds table
- insert_query = """INSERT INTO guilds (guildID) VALUES (%s) ON DUPLICATE KEY UPDATE guildID = VALUES(guildID)"""
- val = guild.id,
-
- # Execute the query
- await cur.execute(insert_query, val)
- await conn.commit()
- print(cur.rowcount, f"Record(s) inserted successfully into Guilds from {guild.name}")
-
- async with conn.cursor() as cur:
- # Define the insert statement that will insert the user's information
- insert = """INSERT INTO members (guildID, discordID) VALUES {}
- ON DUPLICATE KEY UPDATE guildID = VALUES(guildID), discordID = VALUES(discordID)""".format(
- records)
-
- # Execute the query
- await cur.execute(insert)
- await conn.commit()
- print(cur.rowcount, f"Record(s) inserted successfully into Members from {guild.name}")
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print(f"PostGres Error: Guild {guild.id} Could Not Be Inserted Into Guilds Table", e)
+
+ # Print success
+ else:
+ print(rowcount, f"Record(s) inserted successfully into {guild}")
+
+ # Query to insert all the member details to members table
+ try:
+ rowcount = await conn.copy_records_to_table("members", records=records)
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print(f"PostGres Error: Members Could Not Be Inserted Into Members Table For Guild {guild.id}", e)
+
+ # Store in cache
+ else:
+ print(rowcount, f"Record(s) inserted successfully into Members from {guild}")
+ self.store_cache(guild.id, modlogs=None, prefix=".", roles_persist=0)
+
+ # Release connection back to pool
+ await pool.release(conn)
async def on_guild_remove(self, guild):
"""
Remove users in the database for the guild
Remove the modlogs/guild from the cache
"""
- # Delete the key - value pairs for the guild
- self.del_cache(str(guild.id))
- # Setup pool
+ # Setup pool connection
pool = self.db
-
- # Setup pool connection and cursor
async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Delete the guild and prefix information as the bot leaves the server
- delete_query = """DELETE FROM guilds WHERE guildID = %s"""
- val = guild.id,
-
- # Execute the query
- await cur.execute(delete_query, val)
- await conn.commit()
- print(cur.rowcount, f"Record deleted successfully from Guild {guild.name}")
-
- async with conn.cursor() as cur:
- # Delete the record of the member as the bot leaves the server
- delete_query = """DELETE FROM members WHERE guildID = %s"""
- vals = guild.id,
-
- # Execute the query
- await cur.execute(delete_query, vals)
- await conn.commit()
- print(cur.rowcount, f"Record(s) deleted successfully from Members from {guild.name}")
+
+ # Delete the guild information as the bot leaves the server
+ try:
+ delete_query = """DELETE FROM guilds WHERE guild_id = $1"""
+ rowcount = await conn.execute(delete_query, guild.id)
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print(f"PostGres Error: On Guild Remove Event Record Was Not Deleted For {guild.id}", e)
+
+ # Delete the key - value pair for the guild
+ else:
+ print(rowcount, f"Record deleted successfully from Guild {guild}")
+ self.del_cache(guild.id)
+
+ # Delete the record of the member as the bot leaves the server
+ try:
+ delete_query = """DELETE FROM members WHERE guild_id = $1"""
+ rowcount = await conn.execute(delete_query, guild.id)
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print(f"PostGres Error: All Members Could Not Be Deleted From {guild.id}", e)
+
+ # Print success
+ else:
+ print(rowcount, f"Record(s) deleted successfully from Members from {guild}")
+
+ # Release connection back to pool
+ await pool.release(conn)
async def on_member_join(self, member):
"""
@@ -459,120 +529,177 @@ class Bot(commands.Bot):
In the Enso guild, it will send an introduction embed
"""
+ # Ignoring bots
if member.bot: return
- # Get the guild
+ # Get the guild and role persist value of the guild
guild = member.guild
+ role_persist = self.get_roles_persist(guild.id)
- # Setup pool
+ # Setup pool connection
pool = self.db
+ async with pool.acquire() as conn:
- role_persist = self.get_roles_persist(str(guild.id))
+ # Define the insert statement that will insert the user's information
+ try:
+ insert_query = """INSERT INTO members (guild_id, member_id) VALUES ($1, $2)
+ ON CONFLICT (guild_id, member_id) DO NOTHING"""
- # Setup pool connection and cursor
- async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Define the insert statement that will insert the user's information
- insert_query = """INSERT INTO members (guildID, discordID) VALUES (%s, %s)
- ON DUPLICATE KEY UPDATE guildID = VALUES(guildID), discordID = VALUES(discordID)"""
- vals = member.guild.id, member.id,
-
- # Execute the SQL Query
- await cur.execute(insert_query, vals)
- await conn.commit()
- print(cur.rowcount, f"{member} Joined {member.guild.name}, Record Inserted Into Members")
-
- async with conn.cursor() as cur:
- # Get the roles of the user from the database
- select_query = """SELECT * FROM members WHERE guildID = (%s) AND discordID = (%s)"""
- vals = member.guild.id, member.id,
-
- # Execute the SQL Query
- await cur.execute(select_query, vals)
- result = await cur.fetchone()
- role_ids = result[5]
+ rowcount = await conn.execute(insert_query, member.guild.id, member.id)
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print(f"PostGres Error: Member {member.id} was not be able to be added to Guild {member.guild.id}", e)
+
+ # Print success
+ else:
+ print(rowcount, f"{member} Joined {member.guild}, Record Inserted Into Members")
+
+ # Get the roles of the user from the database
+ try:
+ select_query = """SELECT * FROM members WHERE guild_id = $1 AND member_id = $2"""
+
+ user_joined = await conn.fetchrow(select_query, member.guild.id, member.id)
+ role_ids = user_joined[5]
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print(f"PostGres Error: Member {member} Record Not Found", e)
+ # Give roles back to the user if role persist is enabled
+ else:
if role_persist == 1:
# Get Enso Chan
bot = guild.get_member(self.user.id)
# Check permissions of Enso
- if bot.guild_permissions.manage_roles and role_ids is not None:
+ if bot.guild_permissions.manage_roles and role_ids:
# Get all the roles of the user before they were muted from the database
roles = [member.guild.get_role(int(id_)) for id_ in role_ids.split(", ") if len(id_)]
# Give the member their roles back
await member.edit(roles=roles)
- print(f"{member} Had Their Roles Given Back In {member.guild.name}")
+ print(f"{member} Had Their Roles Given Back In {member.guild}")
else:
- print(f"Insufficient Permissions to Add Roles to {member} in {member.guild.name}")
-
- # Reset the roles entry for the database
- update_query = """UPDATE members SET roles = NULL WHERE guildID = (%s) AND discordID = (%s)"""
- update_vals = member.guild.id, member.id,
-
- # Execute the query
- await cur.execute(update_query, update_vals)
- await conn.commit()
- print(cur.rowcount, f"Roles Cleared For {member} in {member.guild.name}")
-
- # Make sure the guild is Enso
- if guild.id == self.enso_guild_ID:
- # Set the channel id to "newpeople"
- new_people = guild.get_channel(self.enso_newpeople_ID)
-
- # Set the enso server icon and the welcoming gif
- server_icon = guild.icon_url
- welcome_gif = "https://cdn.discordapp.com/attachments/669808733337157662/730186321913446521/NewPeople.gif"
-
- # Set up embed for the #newpeople channel
- embed = Embed(title="\n**Welcome To Ensō!**",
- colour=self.admin_colour,
- timestamp=datetime.datetime.utcnow())
-
- embed.set_thumbnail(url=server_icon)
- embed.set_image(url=welcome_gif)
- embed.add_field(
- name=self.blank_space,
- value=f"Hello {member.mention}! We hope you enjoy your stay in this server! ",
- inline=False)
- embed.add_field(
- name=self.blank_space,
- value=f"Be sure to check out our <#669815048658747392> channel to read the rules and <#683490529862090814> channel to get caught up with any changes! ",
- inline=False)
- embed.add_field(
- name=self.blank_space,
- value=f"Last but not least, feel free to go into <#669775971297132556> to introduce yourself!",
- inline=False)
-
- # Send embed to #newpeople
- await new_people.send(embed=embed)
+ print(f"Insufficient Permissions to Add Roles to Member {member.id} in Guild {member.guild.id}")
+
+ # Reset the roles entry for the database
+ try:
+ update_query = """UPDATE members SET roles = NULL WHERE guild_id = $1 AND member_id = $2"""
+ rowcount = await conn.execute(update_query, member.guild.id, member.id)
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print(f"PostGres Error: Clearing Member {member.id} Roles in Guild {member.guild.id}", e)
+
+ # Print success
+ else:
+ print(rowcount, f"Roles Cleared For {member} in {member.guild}")
+
+ # Release connection back to pool
+ await pool.release(conn)
+
+ # Make sure the guild is Enso and send welcoming embed to the server
+ if guild.id == self.enso_guild_ID:
+ new_people = guild.get_channel(self.enso_newpeople_ID)
+
+ server_icon = guild.icon_url
+ welcome_gif = "https://cdn.discordapp.com/attachments/669808733337157662/730186321913446521/NewPeople.gif"
+
+ embed = Embed(title="\n**Welcome To Ensō!**",
+ colour=self.admin_colour,
+ timestamp=datetime.datetime.utcnow())
+
+ embed.set_thumbnail(url=server_icon)
+ embed.set_image(url=welcome_gif)
+ embed.add_field(
+ name=self.blank_space,
+ value=f"Hello {member.mention}! We hope you enjoy your stay in this server!",
+ inline=False)
+ embed.add_field(
+ name=self.blank_space,
+ value=f"Be sure to check out our <#669815048658747392> channel to read the rules and <#683490529862090814> channel to get caught up with any changes! ",
+ inline=False)
+ embed.add_field(
+ name=self.blank_space,
+ value=f"Last but not least, feel free to go into <#669775971297132556> to introduce yourself!",
+ inline=False)
+
+ # Send embed to #newpeople
+ await new_people.send(embed=embed)
async def on_member_remove(self, member):
- """Storing User Roles within Database When User Leaves Guild"""
+ """Storing member roles within the database when the member leaves"""
+ # Ignoring bots
if member.bot: return
+ # Store member roles within a string to insert into database
role_ids = ", ".join([str(r.id) for r in member.roles if not r.managed])
- # Setup pool
+ # Setup pool connection
pool = self.db
-
- # Setup pool connection and cursor
async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Define the insert statement that will insert the user's information
- update_query = """UPDATE members SET roles = (%s) WHERE guildID = (%s) AND discordID = (%s)"""
- vals = role_ids, member.guild.id, member.id,
- # Execute the SQL Query
- await cur.execute(update_query, vals)
- await conn.commit()
- print(cur.rowcount, f"{member} Left {member.guild.name}, Roles stored into Members")
+ # Store member roles within the database
+ try:
+ update_query = """UPDATE members SET roles = $1 WHERE guild_id = $2 AND member_id = $3"""
+ rowcount = await conn.execute(update_query, role_ids, member.guild.id, member.id)
+
+ # Catch Error
+ except asyncpg.PostgresError as e:
+ print(f"PostGres Error: Roles Could Not Be Added To {member} When Leaving {member.guild.id}", e)
+
+ # Print success
+ else:
+ print(rowcount, f"{member} Left {member.guild.name}, Roles stored into Members")
+
+ finally:
+ # Release connection back to pool
+ await pool.release(conn)
# --------------------------------------------!End Events Section!----------------------------------------------
+ async def check_cache(self, member_id, guild_id):
+ """Checks if member is in the member cache"""
+
+ # Return key-value pair if member is already in the cache
+ if (member_id, guild_id) in self.member_cache.cache:
+ return self.member_cache.cache[member_id, guild_id]
+
+ else:
+
+ # Setup pool connection
+ pool = self.db
+ async with pool.acquire() as conn:
+
+ # Get the author's/members row from the Members Table
+ try:
+ select_query = """SELECT * FROM members WHERE member_id = $1 and guild_id = $2"""
+ member_val = member_id, guild_id,
+
+ result = await conn.fetchrow(select_query, member_val)
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print(f"PostGres Error: Member {member_id} From Guild {guild_id}"
+ "Record Could Not Be Retrieved When Checking Cache", e)
+
+ # Store it in cache
+ else:
+ dict_items = {"married": result[1],
+ "marriage_date": result[2],
+ "muted_roles": result[4],
+ "roles": result[5]}
+ self.member_cache.store_cache((member_id, guild_id), dict_items)
+
+ return self.member_cache.cache[(member_id, guild_id)]
+
+ # Release connection back to pool
+ finally:
+ await pool.release(conn)
+
def execute(self):
"""Load the cogs and then run the bot"""
diff --git a/bot/libs/cache.py b/bot/libs/cache.py
index 570c6560..93c29584 100644
--- a/bot/libs/cache.py
+++ b/bot/libs/cache.py
@@ -39,10 +39,10 @@ class CachingCircularQueue:
def remove(self, value):
# To my knowledge, this method can be called when deleting a single member and many members???
- # TODO: So this should only be called to remove a single member at a time
+ # So this should only be called to remove a single member at a time
with self.threadLock:
# Remove the value inside the array (value will be a tuple that is passed in)
- # TODO: PRECONDITION, VALUE EXISTS IN CACHE, SO SHOULD EXIST IN LIST
+ # PRECONDITION, VALUE EXISTS IN CACHE, SO SHOULD EXIST IN LIST
self.values.remove(value)
# As you said, to ensure concurrency, set the current size back to the length of the array
@@ -57,19 +57,25 @@ class MyCoolCache:
def store_cache(self, key, dict_item):
with self.threadLock:
- # TODO: Changed == to >= just incase of concurrency issue meaning size exceeds maximum, thats my fault
- if len(self.queue.values) >= self.MAX_SIZE:
- key_to_delete = None
- if key in self.cache:
- if self.cache[key] is None:
- key_to_delete = self.queue.push(key)
- else:
- key_to_delete = self.queue.push(key)
+ has_key = True
+ # Assume the key exists in the cache
+ if key in self.cache:
+ # If the key is None, aka removed
+ if self.cache[key] is None:
+ has_key = False
+ else:
+ # Or doesn't exist
+ has_key = False
+
+ # Then we don't have the key.
+ # In this case, we have to check if adding a key will exceed max size
+ if not has_key:
+ key_to_delete = self.queue.push(key)
+ # If the key is not None, that means the queue was full. We must delete an item.
+
if key_to_delete is not None:
self.cache[key_to_delete] = None
- else:
- self.cache[key] = dict_item
- self.queue.push(key)
+ self.cache[key] = dict_item
def remove_many(self, in_guild_id):
# This method is to be used for when the bot has left a guild
@@ -77,11 +83,9 @@ class MyCoolCache:
# For every member within the cache
for (member_id, guild_id) in self.cache:
# if the guild_id passed in is equal to the guild_id within the cache
- # TODO: Changed 'in' to ==, remember you're comparing one entry at a time
if in_guild_id == guild_id:
- # set that entry to be equal to none
- # TODO: When removing a value from the cache due to a guild leave, permanently remove all values
- # TODO: Yes it is expensive, however as this can run concurrently and we won't need the data available
- # TODO: For this guild, it doesn't matter how long it takes, and will save in memory in the long term
+ # When removing a value from the cache due to a guild leave, permanently remove all values
+ # Yes it is expensive, however as this can run concurrently and we won't need the data available
+ # For this guild, it doesn't matter how long it takes, and will save in memory in the long term
self.cache.pop((member_id, guild_id))
self.queue.remove((member_id, guild_id))
diff --git a/cogs/enso.py b/cogs/enso.py
index 7d0b84ac..caee928f 100644
--- a/cogs/enso.py
+++ b/cogs/enso.py
@@ -120,7 +120,7 @@ class Enso(Cog):
# Making sure this command only works in Enso
if not ctx.guild.id == self.bot.enso_guild_ID:
- await ctx.send("**Sorry! That command is only for a certain guild!**")
+ await self.bot.generate_embed(ctx, desc="**Sorry! That command is only for a certain guild!**")
return
# If the channel that the command has been sent is in the list of accepted channels
@@ -143,8 +143,9 @@ class Enso(Cog):
# Send the list of available members to the channel
nice = string.capwords(', '.join(map(str, enso_people())))
# Send error message saying that the person isn't recognised
- await ctx.send(f"Sorry! That person doesn't exist! Try the names listed below!"
- f"\n{nice}")
+ await self.bot.generate_embed(ctx,
+ desc=f"Sorry! That person doesn't exist! Try the names listed below!"
+ f"\n{nice}")
else:
@@ -180,8 +181,8 @@ class Enso(Cog):
# Send the list of available members to the channel
nice = string.capwords(', '.join(map(str, enso_people())))
# Send error message saying that the person isn't recognised
- await ctx.send(f"Try the names listed below!"
- f"\n{nice}")
+ await self.bot.generate_embed(ctx, desc=f"Try the names listed below!"
+ f"\n{nice}")
@command(name="rules")
@cooldown(1, 5, BucketType.user)
@@ -190,7 +191,7 @@ class Enso(Cog):
# Making sure this command only works in Enso
if not ctx.guild.id == self.bot.enso_guild_ID:
- await ctx.send("**Sorry! That command is only for a certain guild!**")
+ await self.bot.generate_embed(ctx, desc="**Sorry! That command is only for a certain guild!**")
return
# Define Izzy's roles ID
@@ -284,7 +285,7 @@ class Enso(Cog):
"""Leveled role/xp system for Ensō"""
if not ctx.guild.id == self.bot.enso_guild_ID:
- await ctx.send("**Sorry! That command is only for a certain guild!**")
+ await self.bot.generate_embed(ctx, desc="**Sorry! That command is only for a certain guild!**")
return
# Get the url of the leveled roles image
@@ -400,7 +401,7 @@ class Enso(Cog):
role = discord.utils.find(lambda r: r.name == payload.emoji.name, guild.roles)
# if the role does exist
- if role is not None:
+ if role:
# Print to me that the role was found and display the id of the role
print(role.name + " was found!")
print(role.id)
@@ -437,7 +438,7 @@ class Enso(Cog):
role = discord.utils.find(lambda r: r.name == payload.emoji.name, guild.roles)
# if the role does exist
- if role is not None:
+ if role:
# Find the member that has the role which the emoji is connected to
member = discord.utils.find(lambda m: m.id == payload.user_id, guild.members)
diff --git a/cogs/guild.py b/cogs/guild.py
index 16934873..eb2e3fee 100644
--- a/cogs/guild.py
+++ b/cogs/guild.py
@@ -19,6 +19,7 @@ import datetime
import io
import random
+import asyncpg
import discord
from discord import Embed, TextChannel
from discord import File
@@ -188,7 +189,7 @@ class Guild(Cog):
async def rp_status(self, ctx):
"""Showing the status of the role persist within the guild"""
- if self.bot.get_roles_persist(str(ctx.guild.id)) == 0:
+ if self.bot.get_roles_persist(ctx.guild.id) == 0:
await self.bot.generate_embed(ctx, desc=f"**Role Persist is currently disabled within {ctx.guild}**")
else:
await self.bot.generate_embed(ctx, desc=f"**Role Persist is currently enabled within {ctx.guild}**")
@@ -199,10 +200,8 @@ class Guild(Cog):
async def rp_enable(self, ctx):
"""Enabling role persist within the guild"""
- pool = self.bot.db
-
- if self.bot.get_roles_persist(str(ctx.guild.id)) == 0:
- await self.bot.update_role_persist(str(ctx.guild.id), value=1, pool=pool)
+ if self.bot.get_roles_persist(ctx.guild.id) == 0:
+ await self.bot.update_role_persist(ctx.guild.id, value=1)
await self.bot.generate_embed(ctx, desc=f"**Role Persist has been enabled within {ctx.guild}!**")
else:
await self.bot.generate_embed(ctx, desc=f"**Role Persist is already enabled within {ctx.guild}!**")
@@ -213,10 +212,8 @@ class Guild(Cog):
async def rp_disable(self, ctx):
"""Disabling role persist within the guild"""
- pool = self.bot.db
-
- if self.bot.get_roles_persist(str(ctx.guild.id)) == 1:
- await self.bot.update_role_persist(str(ctx.guild.id), value=0, pool=pool)
+ if self.bot.get_roles_persist(ctx.guild.id) == 1:
+ await self.bot.update_role_persist(ctx.guild.id, value=0)
await self.bot.generate_embed(ctx, desc=f"**Role Persist has been disabled within {ctx.guild}!**")
else:
await self.bot.generate_embed(ctx, desc=f"**Role Persist is already disabled within {ctx.guild}!**")
@@ -226,17 +223,17 @@ class Guild(Cog):
@bot_has_permissions(administrator=True)
async def modlogs(self, ctx):
"""
- Show Current Modlogs Channel (If Setup)
+ Show current modlogs channel
"""
- ml_channel = self.bot.get_modlog_for_guild(str(ctx.guild.id))
+ ml_channel = self.bot.get_modlog_for_guild(ctx.guild.id)
# Send current modlogs channel only if it is setup
# Send error if no modlogs channel has been setup
- if ml_channel is not None:
+ if ml_channel:
# Get the modlog channel for the current guild
- channel = ctx.guild.get_channel(int(ml_channel))
+ channel = ctx.guild.get_channel(ml_channel)
text = f"**The current modlogs channel is set to {channel.mention}**"
await self.bot.generate_embed(ctx, desc=text)
@@ -250,105 +247,114 @@ class Guild(Cog):
@has_permissions(manage_guild=True)
@bot_has_permissions(administrator=True)
async def mlsetup(self, ctx, user_channel: TextChannel):
- """Setup a Channel for the Kick/Ban/Mute Actions to be Logged In"""
+ """Setup a channel for Kick/Ban/Mute actions to be logged"""
- # Setup pool
+ # Setup pool connection
pool = self.bot.db
-
- # Setup pool connection and cursor
async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Get the row of the guild
- select_query = """SELECT * FROM guilds WHERE guildID = (%s)"""
- val = ctx.guild.id,
- # Execute the SQL Query
- await cur.execute(select_query, val)
- result = await cur.fetchone()
+ # Get the row of the guild from database
+ try:
+ select_query = """SELECT * FROM guilds WHERE guild_id = $1"""
+ result = await conn.fetchrow(select_query, ctx.guild.id)
- # Throw error if the modlog channel already exists and then stop the function
- if result[2] is not None:
- text = "**Modlogs Channel** already set up!" \
- f"\nDo **{ctx.prefix}help modlogs** to find out more!"
- await self.bot.generate_embed(ctx, desc=text)
- return
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print("PostGres Error: Guild Record Could Not Be Retrieved For Modlog Setup", e)
- else:
- # Set up the modlogs channel within the guild
- mod_log_setup = True
- await self.bot.storage_modlog_for_guild(self.bot.db, ctx, user_channel.id, mod_log_setup)
+ # Throw error if the modlog channel already exists
+ else:
+ if result["modlogs"]:
+ text = "**Modlogs Channel** already set up!" \
+ f"\nDo **{ctx.prefix}help modlogs** to find out more!"
+ await self.bot.generate_embed(ctx, desc=text)
+
+ # Set up the modlogs channel within the guild
+ else:
+ mod_log_setup = True
+ await self.bot.storage_modlog_for_guild(ctx, user_channel.id, mod_log_setup)
+
+ # Release the connection back to the pool
+ finally:
+ await pool.release(conn)
@modlogs.command(name="update")
@has_permissions(manage_guild=True)
@bot_has_permissions(administrator=True)
async def mlupdate(self, ctx, user_channel: TextChannel):
- """Change the Channel that your Modlogs are Sent to"""
+ """Change the channel that your modlogs are sent to"""
- # Setup pool
+ # Setup up pool connectionF
pool = self.bot.db
-
- # Setup up pool connection and cursor
async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Get the guilds row from the guilds table
- select_query = """SELECT * FROM guilds WHERE guildID = (%s)"""
- vals = ctx.guild.id,
-
- # Execute the SQL Query
- await cur.execute(select_query, vals)
- result = await cur.fetchone()
-
- # Throw error if the modlog channel already exists and then stop the function
- if result[2] is None:
- text = "**Modlogs Channel** not set up!" \
- f"\nDo **{ctx.prefix}help modlogs** to find out more!"
- await self.bot.generate_embed(ctx, desc=text)
- else:
- # Update the modlog channel within the database and cache
- mod_log_setup = False
- await self.bot.storage_modlog_for_guild(self.bot.db, ctx, user_channel.id, mod_log_setup)
+ # Get the guilds row from the guilds table
+ try:
+ select_query = """SELECT * FROM guilds WHERE guild_id = $1"""
+ result = await conn.fetchrow(select_query, ctx.guild.id)
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print("PostGres Error: Guild Record Could Not Be Retrieved For Modlog Update", e)
+
+ # Throw error if the modlog channel already exists
+ else:
+ if result["married"] is None:
+ text = "**Modlogs Channel** not set up!" \
+ f"\nDo **{ctx.prefix}help modlogs** to find out more!"
+ await self.bot.generate_embed(ctx, desc=text)
+
+ # Update the modlog channel within the database and cache
+ else:
+ mod_log_setup = False
+ await self.bot.storage_modlog_for_guild(ctx, user_channel.id, mod_log_setup)
+
+ # Release the connection back to the pool
+ finally:
+ await pool.release(conn)
@modlogs.command("delete")
@has_permissions(manage_guild=True)
@bot_has_permissions(administrator=True)
async def mldelete(self, ctx):
- """Delete the Existing Modlogs System"""
+ """Delete the existing modlogs channel"""
- # Setup pool
+ # Setup up pool connection
pool = self.bot.db
-
- # Setup up pool connection and cursor
async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Get the guilds row from the guilds table
- select_query = """SELECT * FROM guilds WHERE guildID = (%s)"""
- vals = ctx.guild.id,
-
- # Execute the SQL Query
- await cur.execute(select_query, vals)
- result = await cur.fetchone()
-
- # Throw error is modlogs error has not been setup before performing a delete action
- if result[2] is None:
- text = "**Modlogs Channel** not set up!" \
- f"\nDo **{ctx.prefix}help modlogs** to find out more!"
- await self.bot.generate_embed(ctx, desc=text)
- return
- # Setup up pool connection and cursor
- async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Update the existing prefix within the database
- update_query = """UPDATE guilds SET modlogs = NULL WHERE guildID = (%s)"""
- update_vals = ctx.guild.id,
+ # Get the guilds row from the guilds table
+ try:
+ select_query = """SELECT * FROM guilds WHERE guild_id = $1"""
+ result = await conn.fetchrow(select_query, ctx.guild.id)
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print("PostGres Error: Guild Record Could Not Be Retrieved For Modlog Delete", e)
+
+ # Throw error that modlogs have not been setup
+ else:
+ if result["married"] is None:
+ text = "**Modlogs Channel** not set up!" \
+ f"\nDo **{ctx.prefix}help modlogs** to find out more!"
+ await self.bot.generate_embed(ctx, desc=text)
+ return
+
+ # Update the existing modlogs for guild
+ try:
+ update_query = """UPDATE guilds SET modlogs = NULL WHERE guild_id = $1"""
+ await conn.execute(update_query, ctx.guild.id)
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print(f"PostGres Error: Guild Modlogs Could Not Be Updated For {ctx.guild.id}", e)
- # Execute the query
- await cur.execute(update_query, update_vals)
- await conn.commit()
+ # Delete channel from cache
+ else:
+ self.bot.remove_modlog_channel(ctx.guild.id)
- # Delete channel from cache
- self.bot.remove_modlog_channel(str(ctx.guild.id))
+ # Release the connection back to the pool
+ await pool.release(conn)
text = "**Modlogs System** successfully deleted!" \
f"\nDo **{ctx.prefix}help modlogs** to setup Modlogs again!"
@@ -366,155 +372,195 @@ class Guild(Cog):
@modmail.command(name="setup")
@has_permissions(manage_guild=True)
@bot_has_permissions(administrator=True)
- async def mmsetup(self, ctx, user_channel: TextChannel, modmail_channel: TextChannel):
+ async def mmsetup(self, ctx, modmail: TextChannel, modmail_logging: TextChannel):
"""
Setup Modmail System
First Argument: Input Channel(Mention or ID) where members can send modmail
Second Argument: Input Channel(Mention or ID) where the members mail should be sent
"""
- # Setup pool
+ # Setup up pool connection
pool = self.bot.db
-
- # Setup up pool connection and cursor
async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Get the author's row from the Members Table
- select_query = """SELECT * FROM moderatormail WHERE guildID = (%s)"""
- val = ctx.guild.id,
-
- # Execute the SQL Query
- await cur.execute(select_query, val)
- result = await cur.fetchone()
-
- # Throw error if the guild already exists and then stop the function
- if result is not None:
- text = "**Modmail System** already set up!" \
- f"\nDo **{ctx.prefix}help modmail** to find out more!"
- await self.bot.generate_embed(ctx, desc=text)
- return
+ # Get the author's row from the members table
+ try:
+ select_query = """SELECT * FROM moderatormail WHERE guild_id = $1"""
+ result = await conn.fetchrow(select_query, ctx.guild.id)
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print("PostGres Error: ModeratorMail Record Could Not Be Retrieved For Modmail Setup", e)
+
+ # Throw error if the guild already exists
+ else:
+ if result:
+ text = "**Modmail System** already set up!" \
+ f"\nDo **{ctx.prefix}help modmail** to find out more!"
+ await self.bot.generate_embed(ctx, desc=text)
+ return
+
+ # Release the connection back to the pool
+ finally:
+ await pool.release(conn)
+
+ # Set up embed to let the user how to start sending modmail
desc = "React to this message if you want to send a message to the Staff Team!" \
"\n\n**React with ✅**" \
"\n\nWe encourage all suggestions/thoughts and opinions on the server!" \
"\nAs long as it is **valid** criticism." \
"\n\n\n**Purely negative feedback will not be considered.**"
- # Set up embed to let the user how to start sending modmail
ModMail = Embed(title="**Welcome to Modmail!**",
description=desc,
colour=self.bot.admin_colour,
timestamp=datetime.datetime.utcnow())
ModMail.set_thumbnail(url=self.bot.user.avatar_url)
- modmail_message = await user_channel.send(embed=ModMail)
-
- # Auto add the ✅ reaction
+ # Send modmail embed to the specified channel and auto add the ✅ reaction
+ modmail_message = await modmail.send(embed=ModMail)
await modmail_message.add_reaction('✅')
- # Setup up pool connection and cursor
+ # Setup up pool connection
async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Define the insert statement that will insert information about the modmail channel
- insert_query = """INSERT INTO moderatormail (guildID, channelID, messageID, modmailChannelID) VALUES (%s, %s, %s, %s)"""
- vals = ctx.guild.id, user_channel.id, modmail_message.id, modmail_channel.id,
- # Execute the SQL Query
- await cur.execute(insert_query, vals)
- await conn.commit()
+ # Insert the information about the modmail system into database
+ try:
+ insert_query = """INSERT INTO moderatormail (guild_id, modmail_channel_id, message_id, modmail_logging_channel_id)
+ VALUES ($1, $2, $3, $4)"""
+ await conn.execute(insert_query, ctx.guild.id, modmail.id, modmail_message.id, modmail_logging.id)
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print(f"PostGres Error: Modmail System Record Could Not Be Inserted For Guild {ctx.guild.id}", e)
+
+ # Send confirmation message
+ else:
+ text = "**Modmail System** is successfully set up!" \
+ f"\nRefer to **{ctx.prefix}help modmail** for more information"
+ await self.bot.generate_embed(ctx, desc=text)
- text = "**Modmail System** is successfully set up!" \
- f"\nRefer to **{ctx.prefix}help modmail** for more information"
- await self.bot.generate_embed(ctx, desc=text)
+ # Store into cache
+ self.bot.cache_store_modmail(ctx.guild.id, modmail.id, modmail_message.id, modmail_logging.id)
+
+ # Release connection back into pool
+ finally:
+ await pool.release(conn)
@modmail.command(name="update")
@has_permissions(manage_guild=True)
@bot_has_permissions(administrator=True)
- async def mmupdate(self, ctx, modmail_channel: TextChannel):
+ async def mmupdate(self, ctx, modmail_logging_channel: TextChannel):
"""
Update the Channel that the Modmail is logged to
You can Mention or use the Channel ID
"""
- # Setup pool
+ # Setup up pool connection
pool = self.bot.db
+ async with pool.acquire() as conn:
+
+ # Get the moderatormail record from the guilds table
+ try:
+ select_query = """SELECT * FROM moderatormail WHERE guild_id = $1"""
+ result = await conn.fetchrow(select_query, ctx.guild.id)
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print("PostGres Error: ModeratorMail Record Could Not Be Retrieved For Modmail Update", e)
+
+ # Throw error if the guild already exists
+ else:
+ if not result:
+ text = "**Modmail System** not set up!" \
+ f"\nDo **{ctx.prefix}help modmail** to find out more!"
+ await self.bot.generate_embed(ctx, desc=text)
+ return
+
+ # Release connection back to pool
+ finally:
+ await pool.release(conn)
# Setup up pool connection and cursor
async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Get the author's row from the Members Table
- select_query = """SELECT * FROM moderatormail WHERE guildID = (%s)"""
- vals = ctx.guild.id,
-
- # Execute the SQL Query
- await cur.execute(select_query, vals)
- result = await cur.fetchone()
-
- # Throw error if the guild already exists and then stop the function
- if result is None:
- text = "**Modmail System** not set up!" \
- f"\nDo **{ctx.prefix}help modmail** to find out more!"
+
+ # Update the modmail channel in the database
+ try:
+ update_query = """UPDATE moderatormail SET modmail_logging_channel_id = $1 WHERE guild_id = $2"""
+ await conn.execute(update_query, modmail_logging_channel.id, ctx.guild.id)
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print(f"PostGres Error: Modmail System Record Could Not Be Updated For Guild {ctx.guild.id}", e)
+
+ # Send confirmation that the channel has been updated
+ else:
+ text = "**Channel Updated**" \
+ f"\nNew Modmail will be sent to {modmail_logging_channel.mention}"
await self.bot.generate_embed(ctx, desc=text)
- return
- # Setup up pool connection and cursor
- async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Define the update statement that will insert information about the modmail channel
- update_query = """UPDATE moderatormail SET modmailChannelID = (%s) WHERE guildID = (%s)"""
- vals = modmail_channel.id, ctx.guild.id
-
- # Execute the SQL Query
- await cur.execute(update_query, vals)
- await conn.commit()
-
- # Send confirmation that the channel has been updated
- text = "**Channel Updated**" \
- f"\nNew Modmail will be sent to {modmail_channel.mention}"
- await self.bot.generate_embed(ctx, desc=text)
+ # Update cache
+ self.bot.update_modmail(ctx.guild.id, modmail_logging_channel.id)
+
+ # Release connection back to pool
+ finally:
+ await pool.release(conn)
@modmail.command(name="delete")
@has_permissions(manage_guild=True)
@bot_has_permissions(administrator=True)
async def mmdelete(self, ctx):
- """Delete the Entire Modmail System from the Guild"""
+ """Delete the entire modmail system from the guild"""
- # Setup pool
+ # Setup up pool connection
pool = self.bot.db
-
- # Setup up pool connection and cursor
async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Get the author's row from the Members Table
- select_query = """SELECT * FROM moderatormail WHERE guildID = (%s)"""
- vals = ctx.author.guild.id,
-
- # Execute the SQL Query
- await cur.execute(select_query, vals)
- result = await cur.fetchone()
-
- # Throw error if modmail system does not exist already
- if result is None:
- text = "**Modmail System** not set up!" \
- f"\nDo **{ctx.prefix}help modmail** to find out more!"
- await self.bot.generate_embed(ctx, desc=text)
- return
- # Setup up pool connection and cursor
+ # Get the moderatormail record from the guilds table
+ try:
+ select_query = """SELECT * FROM moderatormail WHERE guild_id = $1"""
+ result = await conn.fetchrow(select_query, ctx.guild.id)
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print("PostGres Error: ModeratorMail Record Could Not Be Retrieved For Modmail Delete", e)
+
+ else:
+ # Throw error if modmail system does not exist already
+ if result is None:
+ text = "**Modmail System** not set up!" \
+ f"\nDo **{ctx.prefix}help modmail** to find out more!"
+ await self.bot.generate_embed(ctx, desc=text)
+ return
+
+ # Release connection back to pool
+ finally:
+ await pool.release(conn)
+
+ # Setup up pool connection
async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Define the delete statement to remove all information about the guild
- delete_query = """DELETE FROM moderatormail WHERE guildID = (%s)"""
- vals = ctx.author.guild.id,
- # Execute the SQL Query
- await cur.execute(delete_query, vals)
- await conn.commit()
+ # Remove the moderatormail record from the database
+ try:
+ delete_query = """DELETE FROM moderatormail WHERE guild_id = $1"""
+ await conn.execute(delete_query, ctx.guild.id)
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print(f"PostGres Error: ModeratorMail Record Could Not Be Deleted for Guild {ctx.guild.id}", e)
# Sending confirmation message that the modmail system has been deleted
- text = "**Modmail System** successfully deleted!" \
- f"\nDo **{ctx.prefix}help modmail** to find out more!"
- await self.bot.generate_embed(ctx, desc=text)
+ else:
+ text = "**Modmail System** successfully deleted!" \
+ f"\nDo **{ctx.prefix}help modmail** to find out more!"
+ await self.bot.generate_embed(ctx, desc=text)
+
+ # Delete from cache
+ self.bot.delete_modmail(ctx.guild.id)
+
+ # Release connection back to pool
+ finally:
+ await pool.release(conn)
@Cog.listener()
async def on_raw_reaction_add(self, payload):
@@ -525,35 +571,17 @@ class Guild(Cog):
if payload.member.bot or str(payload.emoji) not in ['✅', '❌']:
return
- # Find a role corresponding to the Emoji name.
- guildid = payload.guild_id
-
- # Setup pool
- pool = self.bot.db
-
- # Setup up pool connection and cursor
- async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Get the author's row from the Members Table
- select_query = """SELECT * FROM moderatormail WHERE guildID = (%s)"""
- val = guildid,
-
- # Execute the SQL Query
- await cur.execute(select_query, val)
- result = await cur.fetchone()
-
- # Adding error handling
- if result is None:
- return
-
- # Define variables
- guild_id = int(result[0])
- channel_id = int(result[1])
- message_id = int(result[2])
- modmail_channel_id = int(result[3])
+ # Get the modmail information from cache
+ modmail = self.bot.get_modmail(payload.guild_id)
+ if modmail:
+ channel_id = modmail["modmail_channel_id"]
+ message_id = modmail["message_id"]
+ modmail_channel_id = modmail["modmail_logging_channel_id"]
+ else:
+ return
# Bunch of checks to make sure it has the right guild, channel, message and reaction
- if payload.guild_id == guild_id and payload.channel_id == channel_id and payload.message_id == message_id and payload.emoji.name == "✅":
+ if payload.channel_id == channel_id and payload.message_id == message_id and payload.emoji.name == "✅":
# Get the guild
guild = self.bot.get_guild(payload.guild_id)
diff --git a/cogs/help.py b/cogs/help.py
index 53e90d28..d73c947c 100644
--- a/cogs/help.py
+++ b/cogs/help.py
@@ -657,16 +657,17 @@ class Help(Cog):
# As long as a new prefix has been given and is less than 5 characters
if new and len(new) <= 5:
# Store the new prefix in the dictionary and update the database
- await self.bot.storage_prefix_for_guild(self.bot.db, ctx, new)
+ await self.bot.storage_prefix_for_guild(ctx, new)
# Making sure that errors are handled if prefix is above 5 characters
elif new and len(new) > 5:
- await ctx.send("The guild prefix must be less than or equal to **5** characters!")
+ await self.bot.generate_embed(ctx, desc="The guild prefix must be less than or equal to **5** characters!")
# if no prefix was provided
elif not new:
# Grab the current prefix for the guild within the cached dictionary
- await ctx.send(f"**The current guild prefix is `{self.bot.get_prefix_for_guild(str(ctx.guild.id))}`**")
+ await self.bot.generate_embed(ctx,
+ desc=f"**The current guild prefix is `{self.bot.get_prefix_for_guild(ctx.guild.id)}`**")
@command(name="support")
async def support(self, ctx):
diff --git a/cogs/interactive.py b/cogs/interactive.py
index 877d46d8..91ae820a 100644
--- a/cogs/interactive.py
+++ b/cogs/interactive.py
@@ -17,6 +17,7 @@
import datetime
import random
+import asyncpg
from discord import Embed, Member
from discord.ext.commands import cooldown, command, BucketType, bot_has_permissions, Cog
@@ -43,29 +44,16 @@ class Interactive(Cog):
"""Printing out that Cog is ready on startup"""
print(f"{self.__class__.__name__} Cog has been loaded\n-----")
+ # TODO: MAKE EVERYTHING IN HERE ASYNCHRONOUS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
@command(name="kiss")
@bot_has_permissions(embed_links=True)
@cooldown(1, 3, BucketType.user)
async def kiss(self, ctx, member: Member):
- """Kiss your Partner"""
+ """Kiss your partner"""
# Get the guild
- guild = ctx.author.guild
-
- # Setup pool
- pool = self.bot.db
-
- # Setup pool connection and cursor
- async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Get the author's row from the Members Table
- select_query = """SELECT * FROM members WHERE discordID = (%s) and guildID = (%s)"""
- val = ctx.author.id, guild.id,
-
- # Execute the SQL Query
- await cur.execute(select_query, val)
- result = await cur.fetchone()
- married_user = result[1]
+ guild = ctx.guild
# Error handling to make sure that the user can kiss themselves
if member.id == ctx.author.id:
@@ -75,21 +63,35 @@ class Interactive(Cog):
kiss = True
title = f":kissing_heart: :kissing_heart: | **{ctx.author.display_name}** kissed **{member.display_name}**"
- try:
- # Make sure the user isn't trying to kiss someone else besides their partner
- if married_user is None and kiss:
- await ctx.send("Σ(‘◉⌓◉’) You need to be married in order to use this command! Baka!")
- return
- # Make sure that the married people can only kiss their partner
- elif not str(member.id) == married_user and kiss:
- await ctx.send("Σ(‘◉⌓◉’) You can only kiss your partner! Baka!")
- return
- except Exception as ex:
- print(ex)
-
- # Surround with try/except to catch any exceptions that may occur
- try:
+ # Setup pool connection
+ pool = self.bot.db
+ async with pool.acquire() as conn:
+
+ # Get the author's row from the members table
+ try:
+ select_query = """SELECT * FROM members WHERE member_id = $1 and guild_id = $2"""
+ result = await conn.fetchrow(select_query, ctx.author.id, guild.id)
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print("PostGres Error: Member Record Could Not Be Retrieved For Kiss Command", e)
+
+ # Checking conditions to make sure user is married/kissing their partner
+ else:
+ married_user = result["married"]
+
+ if married_user is None and kiss:
+ await ctx.send("Σ(‘◉⌓◉’) You need to be married in order to use this command! Baka!")
+ return
+ elif not member.id == married_user and kiss:
+ await ctx.send("Σ(‘◉⌓◉’) You can only kiss your partner! Baka!")
+ return
+
+ # Release connection back to pool
+ finally:
+ await pool.release(conn)
+ try:
# Open the file containing the kissing gifs
with open('images/FunCommands/kissing.txt') as file:
# Store content of the file in kissing_array
@@ -116,25 +118,10 @@ class Interactive(Cog):
@bot_has_permissions(embed_links=True)
@cooldown(1, 3, BucketType.user)
async def cuddle(self, ctx, member: Member):
- """Cuddle your Partner"""
+ """Cuddle your partner"""
# Get the guild
- guild = ctx.author.guild
-
- # Setup pool
- pool = self.bot.db
-
- # Setup pool connection and cursor
- async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Get the author's row from the Members Table
- select_query = """SELECT * FROM members WHERE discordID = (%s) and guildID = (%s)"""
- val = ctx.author.id, guild.id
-
- # Execute the SQL Query
- await cur.execute(select_query, val)
- result = await cur.fetchone()
- married_user = result[1]
+ guild = ctx.guild
# Error handling to make sure that the user can cuddle themselves
if member.id == ctx.author.id:
@@ -144,19 +131,30 @@ class Interactive(Cog):
cuddle = True
title = f":blush: :blush: | **{ctx.author.display_name}** cuddled **{member.display_name}**"
- try:
- # Make sure the user isn't trying to cuddle someone else besides their partner
- if married_user is None and cuddle:
- await ctx.send("Σ(‘◉⌓◉’) You need to be married in order to use this command! Baka!")
- return
- # Make sure that the married people can only cuddle their partner
- elif not str(member.id) == married_user and cuddle:
- await ctx.send("Σ(‘◉⌓◉’) You can only cuddle your partner! Baka!")
- return
- except Exception as ex:
- print(ex)
-
- # Surround with try/except to catch any exceptions that may occur
+ # Setup pool connection
+ pool = self.bot.db
+ async with pool.acquire() as conn:
+
+ # Get the author's row from the members table
+ try:
+ select_query = """SELECT * FROM members WHERE member_id = $1 and guild_id = $2"""
+ result = await conn.fetchrow(select_query, ctx.author.id, guild.id)
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print("PostGres Error: Member Record Could Not Be Retrieved For Cuddle Command", e)
+
+ # Checking conditions to make sure user is married/cuddling their partner
+ else:
+ married_user = result["married"]
+
+ if married_user is None and cuddle:
+ await ctx.send("Σ(‘◉⌓◉’) You need to be married in order to use this command! Baka!")
+ return
+ elif not member.id == married_user and cuddle:
+ await ctx.send("Σ(‘◉⌓◉’) You can only cuddle your partner! Baka!")
+ return
+
try:
# Open the file containing the cuddling gifs
@@ -185,14 +183,13 @@ class Interactive(Cog):
@bot_has_permissions(embed_links=True)
@cooldown(1, 3, BucketType.user)
async def kill(self, ctx, member: Member):
- """Kill a Member"""
+ """Kill a member"""
if member is ctx.author:
title = f":scream: :scream: | **{ctx.author.display_name}** killed **themselves**"
else:
title = f":scream: :scream: | **{ctx.author.display_name}** killed **{member.display_name}**"
- # Surround with try/except to catch any exceptions that may occur
try:
# Open the file containing the killing gifs
@@ -221,14 +218,13 @@ class Interactive(Cog):
@bot_has_permissions(embed_links=True)
@cooldown(1, 3, BucketType.user)
async def slap(self, ctx, member: Member):
- """Slap a Member"""
+ """Slap a member"""
if member is ctx.author:
title = f":cold_sweat: :cold_sweat: | **{ctx.author.display_name}** slapped **themselves**"
else:
title = f":cold_sweat: :cold_sweat: | **{ctx.author.display_name}** slapped **{member.display_name}**"
- # Surround with try/except to catch any exceptions that may occur
try:
# Open the file containing the cuddling gifs
@@ -257,14 +253,13 @@ class Interactive(Cog):
@bot_has_permissions(embed_links=True)
@cooldown(1, 3, BucketType.user)
async def pat(self, ctx, member: Member):
- """Pat a Member"""
+ """Pat a member"""
if member is ctx.author:
title = f"👉 👈 | **{ctx.author.display_name}** patted **themselves**"
else:
title = f"👉 👈 | **{ctx.author.display_name}** patted **{member.display_name}**"
- # Surround with try/except to catch any exceptions that may occur
try:
# Open the file containing the patting gifs
@@ -293,7 +288,7 @@ class Interactive(Cog):
@bot_has_permissions(embed_links=True)
@cooldown(1, 3, BucketType.user)
async def lemon(self, ctx, member: Member):
- """Give Lemon to Member"""
+ """Give Lemon to member"""
if member is ctx.author:
title = f":relaxed: :relaxed: | **{ctx.author.display_name}** gave a lemon to **themselves**"
@@ -304,7 +299,6 @@ class Interactive(Cog):
"https://media.discordapp.net/attachments/669812887564320769/720093575492272208/lemon2.gif",
"https://media.discordapp.net/attachments/718484280925224981/719629805263257630/lemon.gif"]
- # Surround with try/except to catch any exceptions that may occur
try:
# Get the member and the userAvatar
@@ -328,14 +322,13 @@ class Interactive(Cog):
@bot_has_permissions(embed_links=True)
@cooldown(1, 3, BucketType.user)
async def choke(self, ctx, member: Member):
- """Choke a Member"""
+ """Choke a member"""
if member is ctx.author:
title = f":confounded: :confounded: | **{ctx.author.display_name}** choked **themselves**"
else:
title = f":confounded: :confounded: | **{ctx.author.display_name}** choked **{member.display_name}**"
- # Surround with try/except to catch any exceptions that may occur
try:
# Open the file containing the choking gifs
with open('images/FunCommands/choking.txt') as file:
@@ -363,14 +356,13 @@ class Interactive(Cog):
@bot_has_permissions(embed_links=True)
@cooldown(1, 3, BucketType.user)
async def hug(self, ctx, member: Member):
- """Hug a Member"""
+ """Hug a member"""
if member is ctx.author:
title = f":smiling_face_with_3_hearts: :smiling_face_with_3_hearts: | **{ctx.author.display_name}** hugged **themselves**"
else:
title = f":smiling_face_with_3_hearts: :smiling_face_with_3_hearts: | **{ctx.author.display_name}** hugged **{member.display_name}**"
- # Surround with try/except to catch any exceptions that may occur
try:
# Open the file containing the hug gifs
diff --git a/cogs/moderation.py b/cogs/moderation.py
index a2b268b2..7895c2f2 100644
--- a/cogs/moderation.py
+++ b/cogs/moderation.py
@@ -35,11 +35,11 @@ async def send_to_modlogs(self, ctx, target, reason, action):
"""
# Get the channel of the modlog within the guild
- modlog = self.bot.get_modlog_for_guild(str(ctx.guild.id))
+ modlog = self.bot.get_modlog_for_guild(ctx.guild.id)
- if modlog is not None:
+ if modlog:
- channel = ctx.guild.get_channel(int(modlog))
+ channel = ctx.guild.get_channel(modlog)
embed = Embed(title=f"Member {action}",
colour=self.bot.admin_colour,
@@ -87,30 +87,34 @@ async def ummute_members(self, ctx, targets, reason):
"""
- # Setup pool
- pool = self.bot.db
-
for target in targets:
if (ctx.guild.me.top_role.position > target.top_role.position
and not target.guild_permissions.administrator):
- # Setup up pool connection and cursor
+ # Setup up pool connection
+ pool = self.bot.db
async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Get the roles of the user from the database
- select_query = """SELECT * FROM members WHERE guildID = (%s) AND discordID = (%s)"""
- select_vals = ctx.guild.id, target.id,
- # Execute the SQL Query
- await cur.execute(select_query, select_vals)
- result = await cur.fetchone()
- role_ids = result[4]
+ # Get the roles of the user from the database
+ try:
+ select_query = """SELECT * FROM members WHERE guild_id = $1 AND member_id = $2"""
+ result = await conn.fetchrow(select_query, ctx.guild.id, target.id)
+
+ # Catch Errors
+ except Exception as e:
+ print("PostGres Error: Record Not Found For Unmuting Members", e)
# Get all the roles of the user before they were muted from the database
- roles = [ctx.guild.get_role(int(id_)) for id_ in role_ids.split(", ") if len(id_)]
+ else:
+ role_ids = result["muted_roles"]
+ roles = [ctx.guild.get_role(int(id_)) for id_ in role_ids.split(", ") if len(id_)]
- # Clear all the roles of the user
- await self.bot.clearRoles(member=target)
+ # Release connection back to pool
+ finally:
+ await pool.release(conn)
+
+ # Clear all the roles of the user
+ await self.bot.clearRoles(member=target)
await target.edit(roles=roles)
@@ -159,7 +163,7 @@ async def mute_members(self, ctx, targets, reason, muted):
embed = Embed(description=f"✅ **{target}** Was Muted! ✅",
colour=self.bot.admin_colour)
- if self.bot.get_roles_persist(str(ctx.guild.id)) == 0:
+ if self.bot.get_roles_persist(ctx.guild.id) == 0:
embed.add_field(name="**WARNING: ROLE PERSIST NOT ENABLED**",
value="The bot **will not give** the roles back to the user if they leave the server."
"\nAllowing the user to bypass the Mute by leaving and rejoining."
@@ -409,12 +413,12 @@ class Moderation(Cog):
"""Logging Bulk Message Deletion from Server"""
# Get the channel within the cache
- channel = self.bot.get_modlog_for_guild(str(payload.guild_id))
+ channel = self.bot.get_modlog_for_guild(payload.guild_id)
# When no modlogs channel is returned, do nothing
- if channel is not None:
+ if channel:
# Get the modlogs channel and channel that the messages were deleted in
- modlogs_channel = self.bot.get_channel(int(channel))
+ modlogs_channel = self.bot.get_channel(channel)
deleted_msgs_channel = self.bot.get_channel(payload.channel_id)
desc = f"**Bulk Delete in {deleted_msgs_channel.mention} | {len(payload.message_ids)} messages deleted**"
@@ -431,13 +435,15 @@ class Moderation(Cog):
async def on_member_remove(self, member):
"""Log Member Leaves from Server"""
+ if member == self.bot.user: return
+
# Get the channel within the cache
- channel = self.bot.get_modlog_for_guild(str(member.guild.id))
+ channel = self.bot.get_modlog_for_guild(member.guild.id)
# When no modlogs channel is returned, do nothing
- if channel is not None:
+ if channel:
# Get the modlogs channel
- modlogs_channel = self.bot.get_channel(int(channel))
+ modlogs_channel = self.bot.get_channel(channel)
embed = Embed(description=f"**{member.mention}** | **{member}**",
colour=self.bot.admin_colour,
@@ -453,12 +459,12 @@ class Moderation(Cog):
"""Log Member Joins to Server"""
# Get the channel within the cache
- channel = self.bot.get_modlog_for_guild(str(member.guild.id))
+ channel = self.bot.get_modlog_for_guild(member.guild.id)
# When no modlogs channel is returned, do nothing
- if channel is not None:
+ if channel:
# Get the modlogs channel
- modlogs_channel = self.bot.get_channel(int(channel))
+ modlogs_channel = self.bot.get_channel(channel)
embed = Embed(description=f"**{member.mention}** | **{member}**",
colour=self.bot.admin_colour,
@@ -477,12 +483,12 @@ class Moderation(Cog):
"""Logs Member Bans to Server"""
# Get the channel within the cache
- channel = self.bot.get_modlog_for_guild(str(guild.id))
+ channel = self.bot.get_modlog_for_guild(guild.id)
# When no modlogs channel is returned, do nothing
- if channel is not None:
+ if channel:
# Get the modlogs channel
- modlogs_channel = self.bot.get_channel(int(channel))
+ modlogs_channel = self.bot.get_channel(channel)
embed = Embed(description=f"{user.mention} | **{user}**",
colour=self.bot.admin_colour,
@@ -498,12 +504,12 @@ class Moderation(Cog):
"""Logs Member Unbans to Server"""
# Get the channel within the cache
- channel = self.bot.get_modlog_for_guild(str(guild.id))
+ channel = self.bot.get_modlog_for_guild(guild.id)
# When no modlogs channel is returned, do nothing
- if channel is not None:
+ if channel:
# Get the modlogs channel
- modlogs_channel = self.bot.get_channel(int(channel))
+ modlogs_channel = self.bot.get_channel(channel)
embed = Embed(description=f"{user.mention} | **{user}**",
colour=self.bot.admin_colour,
@@ -519,12 +525,12 @@ class Moderation(Cog):
"""Logging Member Profile Updates"""
# Get the channel within the cache
- channel = self.bot.get_modlog_for_guild(str(after.guild.id))
+ channel = self.bot.get_modlog_for_guild(after.guild.id)
# When no modlogs channel is returned, do nothing
- if channel is not None:
+ if channel:
# Get the modlogs channel
- modlogs_channel = self.bot.get_channel(int(channel))
+ modlogs_channel = self.bot.get_channel(channel)
# Logging Nickname Updates
if before.nick != after.nick:
@@ -586,19 +592,19 @@ class Moderation(Cog):
async def on_message_edit(self, before, after):
"""Logging Message Edits (Within Cache)"""
- msg_channel = self.bot.get_channel(int(after.channel.id))
+ msg_channel = self.bot.get_channel(after.channel.id)
# Get the channel within the cache
if not isinstance(msg_channel, DMChannel):
# Get the channel within the cache
- channel = self.bot.get_modlog_for_guild(str(after.guild.id))
+ channel = self.bot.get_modlog_for_guild(after.guild.id)
else:
return
# When no modlogs channel is returned, do nothing
- if channel is not None:
+ if channel:
# Get the modlogs channel
- modlogs_channel = self.bot.get_channel(int(channel))
+ modlogs_channel = self.bot.get_channel(channel)
# Logging Message Content Edits
# Not logging any message edits from bots
@@ -629,16 +635,17 @@ class Moderation(Cog):
# Get the channel within the cache
if not isinstance(msg_channel, DMChannel):
- channel = self.bot.get_modlog_for_guild(payload.data["guild_id"])
+ channel = self.bot.get_modlog_for_guild(int(payload.data["guild_id"]))
else:
return
- # Only log this message if the message does not exist within the internal cache and modlogs channel is set up
- if channel is not None and not payload.cached_message:
+ # Only log this message edit when the message does not exist within the internal cache
+ # and modlogs channel is set up
+ if channel and not payload.cached_message:
# Get the modlogs channel
- modlogs_channel = self.bot.get_channel(int(channel))
+ modlogs_channel = self.bot.get_channel(channel)
- desc = f"**Message Edited Within <#{payload.channel_id}>\nMessage Content Not Displayable**"
+ desc = f"**Message Edited Within {msg_channel.mention}\nMessage Content Not Displayable**"
embed = Embed(description=desc,
colour=self.bot.admin_colour,
timestamp=datetime.datetime.utcnow())
@@ -652,12 +659,12 @@ class Moderation(Cog):
"""Logging Message Deletions (Within Cache)"""
# Get the channel within the cache
- channel = self.bot.get_modlog_for_guild(str(message.guild.id))
+ channel = self.bot.get_modlog_for_guild(message.guild.id)
# When no modlogs channel is returned, do nothing
- if channel is not None and not message.author.bot:
+ if channel and not message.author.bot:
# Get the modlogs channel
- modlogs_channel = self.bot.get_channel(int(channel))
+ modlogs_channel = self.bot.get_channel(channel)
if not message.attachments:
desc = f"**Message Sent By {message.author.mention} Deleted In {message.channel.mention}" \
@@ -677,6 +684,33 @@ class Moderation(Cog):
await modlogs_channel.send(embed=embed)
+ @Cog.listener()
+ async def on_raw_message_delete(self, payload):
+ """Logging Message Deletions Not Stored Within Internal Cache"""
+
+ msg_channel = self.bot.get_channel(payload.channel_id)
+
+ # Get the channel within the cache
+ if not isinstance(msg_channel, DMChannel):
+ channel = self.bot.get_modlog_for_guild(payload.guild_id)
+ else:
+ return
+
+ # Only log this message deletion when the message does not exist within the internal cache
+ # and modlogs channel is set up
+ if channel and not payload.cached_message:
+ # Get the modlogs channel
+ modlogs_channel = self.bot.get_channel(channel)
+
+ desc = f"**Message Deleted Within {msg_channel.mention}\nMessage Content Not Displayable**"
+ embed = Embed(description=desc,
+ colour=self.bot.admin_colour,
+ timestamp=datetime.datetime.utcnow())
+ embed.set_author(name=modlogs_channel.guild.name, icon_url=modlogs_channel.guild.icon_url)
+ embed.set_footer(text=f"Message ID: {payload.message_id}")
+
+ await modlogs_channel.send(embed=embed)
+
def setup(bot):
bot.add_cog(Moderation(bot))
diff --git a/cogs/owner.py b/cogs/owner.py
index 3d62e3e5..72bd8ce5 100644
--- a/cogs/owner.py
+++ b/cogs/owner.py
@@ -13,7 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-
+import asyncpg
from discord import Member
from discord.ext.commands import Cog, command, is_owner
@@ -45,7 +45,7 @@ class Owner(Cog):
@command(name="restart", hidden=True)
@is_owner()
async def restart(self, ctx):
- """Restart the Bot"""
+ """Restart the bot"""
await self.bot.generate_embed(ctx, desc="**Success Senpai!"
"\nMy Reboot Had No Problems** ")
@@ -62,21 +62,29 @@ class Owner(Cog):
# Setup pool
pool = self.bot.db
+ # Store every single record into an array
+ records = [(ctx.guild.id, member.id) for member in ctx.guild.members]
+
# Setup up pool connection and cursor
async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Define the insert statement that will insert the user's information
- insert = """INSERT INTO members (guildID, discordID) VALUES """ + ", ".join(
- map(lambda m: f"({ctx.guild.id}, {m.id})",
- ctx.guild.members)) + """ ON DUPLICATE KEY UPDATE guildID = VALUES(guildID), discordID = VALUES(discordID)"""
-
- # Execute the insert statement
- await cur.execute(insert)
- await conn.commit()
- print(cur.rowcount, f"Record(s) inserted successfully into Members from {ctx.guild.name}")
-
- # Sending confirmation message
- await ctx.send(f"Database Reloaded Successfully for **{ctx.guild.name}**")
+ # Define the insert statement that will insert the user's information
+ try:
+ insert_query = """INSERT INTO members (guild_id, member_id) VALUES ($1, $2)
+ ON CONFLICT (guild_id, member_id) DO NOTHING"""
+
+ await conn.executemany(insert_query, records)
+
+ # Catch errors
+ except asyncpg.PostgresError as e:
+ print(f"PostGres Error: Member(s) were not be able to be added to Guild", e)
+
+ # Print success
+ else:
+ print(f"Record(s) Inserted Into Members")
+
+ finally:
+ # Release connection back to pool
+ await pool.release(conn)
def setup(bot):
diff --git a/cogs/relationship.py b/cogs/relationship.py
index 00dbbc09..e560bfa4 100644
--- a/cogs/relationship.py
+++ b/cogs/relationship.py
@@ -17,6 +17,7 @@
import asyncio
import datetime
+import asyncpg
from discord import Member, Embed
from discord.ext.commands import BucketType, command, cooldown, bot_has_permissions, Cog
@@ -80,37 +81,35 @@ class Relationship(Cog):
await self.bot.generate_embed(ctx, desc="**Senpaii! ˭̡̞(◞⁎˃ᆺ˂)◞*✰ You can't possibly marry yourself!**")
return
+ # TODO: Probably will need to get rid of this in favour of getting from cache
+
# Setup pool connection and cursor
async with pool.acquire() as conn:
- async with conn.cursor() as author_cursor:
- # Get the author's/members row from the Members Table
- select_query = """SELECT * FROM members WHERE discordID = (%s) and guildID = (%s)"""
- author_val = ctx.author.id, guild.id,
- member_val = member.id, guild.id,
-
- # Execute the Author SQL Query
- await author_cursor.execute(select_query, author_val)
- author_result = await author_cursor.fetchone()
- married_user = author_result[1]
-
- # Make sure that the person is not already married to someone else within the server
- if married_user is not None:
- member = guild.get_member(int(married_user))
- await self.bot.generate_embed(ctx, desc=f"**((╬◣﹏◢)) You're already married to {member.mention}!**")
- return
+ # Get the author's/members row from the Members Table
+ select_query = """SELECT * FROM members WHERE member_id = $1 and guild_id = $2"""
- # Set up new cursor for member row
- async with conn.cursor() as member_cursor:
- # Execute the Member SQL Query
- await member_cursor.execute(select_query, member_val)
- member_result = await member_cursor.fetchone()
- target_user = member_result[1]
-
- if target_user is not None:
- member = guild.get_member(int(target_user))
- await self.bot.generate_embed(ctx,
- desc=f"**Sorry! That user is already married to {member.mention}**")
- return
+ # Execute the Author SQL Query
+ db_author = await conn.fetchrow(select_query, ctx.author.id, guild.id)
+ married_user = db_author["married"]
+
+ # Make sure that the person is not already married to someone else within the server
+ if married_user:
+ member = guild.get_member(married_user)
+ await self.bot.generate_embed(ctx, desc=f"**((╬◣﹏◢)) You're already married to {member.mention}!**")
+ return
+
+ # Execute the Member SQL Query
+ db_member = await conn.fetchrow(select_query, member.id, guild.id)
+ target_user = db_member["married"]
+
+ if target_user:
+ member = guild.get_member(target_user)
+ await self.bot.generate_embed(ctx,
+ desc=f"**Sorry! That user is already married to {member.mention}**")
+ return
+
+ # Release connection back to pool
+ await pool.release(conn)
# Send a message to the channel mentioning the author and the person they want to wed.
await self.bot.generate_embed(ctx, desc=f"{ctx.author.mention} **Proposes To** {member.mention}"
@@ -132,18 +131,20 @@ class Relationship(Cog):
# Setup pool connection and cursor
async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- message_time = msg.created_at.strftime("%a, %b %d, %Y")
- # Update the existing records in the database with the user that they are marrying along with the time of the accepted proposal
- update_query = """UPDATE members SET married = (%s), marriedDate = (%s) WHERE discordID = (%s) AND guildID = (%s)"""
- proposer = member.id, message_time, ctx.author.id, guild.id,
- proposee = ctx.author.id, message_time, member.id, guild.id,
- # Execute the SQL Query's
- await cur.execute(update_query, proposer)
- await cur.execute(update_query, proposee)
- await conn.commit()
- print(cur.rowcount, "2 people have been married!")
+ message_time = msg.created_at.strftime("%a, %b %d, %Y")
+ # Update the existing records in the database with the user that they are marrying along with the time of the accepted proposal
+ update_query = """UPDATE members SET married = $1, married_date = $2 WHERE member_id = $3 AND guild_id = $4"""
+
+ # Execute the SQL Query's
+ try:
+ await conn.execute(update_query, member.id, message_time, ctx.author.id, guild.id)
+ await conn.execute(update_query, ctx.author.id, message_time, member.id, guild.id)
+ except asyncpg.PostgresError as e:
+ print(f"PostGres Error: {member.id} and {ctx.author.id} Could Not Be Married", e)
+ else:
+ # TODO: Update the cache that the users have been married
+ pass
# Congratulate them!
desc = f"**Congratulations! 。゚( ゚^∀^゚)゚。 {ctx.author.mention} and {member.mention} are now married to each other!**"
@@ -180,17 +181,18 @@ class Relationship(Cog):
await self.bot.generate_embed(ctx, desc="**Senpaii! ˭̡̞(◞⁎˃ᆺ˂)◞*✰ You can't possibly divorce yourself!**")
return
+ # TODO: Probably will need to get rid of this in favour of getting from cache
+ # TODO: Not gonna bother refactoring this db statement
+
# Setup pool connection and cursor
async with pool.acquire() as conn:
async with conn.cursor() as cur:
# Get the author's row from the Members Table
- select_query = """SELECT * FROM members WHERE discordID = (%s) and guildID = (%s)"""
- val = ctx.author.id, guild.id,
+ select_query = """SELECT * FROM members WHERE member_id = $1 and guild_id = $1"""
# Execute the SQL Query
- await cur.execute(select_query, val)
- result = await cur.fetchone()
- married_user = result[1]
+ result = await cur.fetchrow(select_query, ctx.author.id, guild.id)
+ married_user = result["married"]
# Make sure that the person trying to divorce is actually married to the user
if married_user is None:
@@ -200,8 +202,8 @@ class Relationship(Cog):
return
# Make sure the person is married to the person that they're trying to divorce
- elif married_user != str(member.id):
- member = guild.get_member(int(married_user))
+ elif married_user != member.id:
+ member = guild.get_member(married_user)
desc = f"**(ノ ゜口゜)ノ You can only divorce the person that you're married!" \
f"\n That person is {member.mention}**"
@@ -228,17 +230,19 @@ class Relationship(Cog):
# Setup pool connection and cursor
async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Update the existing records in the database with the user that they are marrying along with the time of the accepted proposal
- update_query = """UPDATE members SET married = null, marriedDate = null WHERE discordID = (%s) and guildID = (%s)"""
- divorcer = ctx.author.id, guild.id,
- divorcee = member.id, guild.id,
+ # Update the existing records in the database with the user that they are marrying along with the time of the accepted proposal
+ update_query = """UPDATE members SET married = NULL, married_date = NULL WHERE member_id = $1 and guild_id = $2"""
+
+ try:
# Execute the SQL Query's
- await cur.execute(update_query, divorcer)
- await cur.execute(update_query, divorcee)
- await conn.commit()
- print(cur.rowcount, "2 Members have been divorced :(!")
+ await conn.execute(update_query, ctx.author.id, guild.id)
+ await conn.execute(update_query, member.id, guild.id)
+ except asyncpg.PostgresError as e:
+ print(f"PostGres Error: {member.id} and {ctx.author.id} Could Not Be Divorced", e)
+ else:
+ # TODO: Update the cache that the users have been divorced
+ pass
# Congratulate them!
desc = f"**૮( ´⁰▱๋⁰ )ა {ctx.author.mention} and {member.mention} are now divorced." \
@@ -277,29 +281,28 @@ class Relationship(Cog):
# Setup pool
pool = self.bot.db
+ # TODO: Replace this entire section with retrieving from cache
+
# Setup pool connection and cursor
async with pool.acquire() as conn:
- async with conn.cursor() as cur:
- # Get the author's row from the Members Table
- select_query = """SELECT * FROM members WHERE discordID = (%s) and guildID = (%s)"""
- val = member.id, guild.id,
-
- # Execute the SQL Query
- await cur.execute(select_query, val)
- result = await cur.fetchone()
- user = result[1]
- marriage_date = result[2]
-
- # Set empty values for non-married users
- if user is None:
- married = False
- marriedUser = ""
- marriedDate = ""
- # Set the member, date married and setting married status
- else:
- marriedUser = guild.get_member(int(user))
- marriedDate = marriage_date
- married = True
+ # Get the author's row from the Members Table
+ select_query = """SELECT * FROM members WHERE member_id = $1 and guild_id = $2"""
+
+ # Execute the SQL Query
+ result = await conn.fetchrow(select_query, member.id, guild.id)
+ user = result["married"]
+ marriage_date = result["married_date"]
+
+ # Set empty values for non-married users
+ if not user:
+ married = False
+ marriedUser = ""
+ marriedDate = ""
+ # Set the member, date married and setting married status
+ else:
+ married = True
+ marriedUser = guild.get_member(user)
+ marriedDate = marriage_date
# Get the current date of the message sent by the user
currentDate = ctx.message.created_at.strftime("%a, %b %d, %Y")
diff --git a/main.py b/main.py
index ced34949..6d4656a5 100644
--- a/main.py
+++ b/main.py
@@ -14,10 +14,29 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
+from discord.ext.commands import is_owner
from bot import Bot
# Initiating Bot Object As Client
client = Bot()
+
+
+@client.command()
+@is_owner()
+async def test(ctx):
+ # Alt Account
+ testing1 = await client.check_cache(556665878662348811, 621621615930638336)
+ print(client.member_cache.cache)
+
+ # My Account on the same guild as Alt
+ testing3 = await client.check_cache(154840866496839680, 621621615930638336)
+ print(client.member_cache.cache)
+
+ # Me in another guild
+ testing4 = await client.check_cache(154840866496839680, 663651584399507476)
+ print(client.member_cache.cache)
+
+
# Run the bot
client.execute()