Refactored EVERYTHING

No more converting to strings and back to ints
Moving on from MariaD to PostGresSQL (THANK THE GODS)
Storing modmail in cache
Close to implementing circular queue for member cache
FULLY REDID COMMENTARY
Updated Version Number to 0.8.2 (Closer to v1 release!)
Gonna test commands for the cache within main.py
pull/8/head
sgoudham 4 years ago
parent ac0163e54c
commit 4003967af0

@ -19,7 +19,7 @@ import os
import random import random
import aiohttp import aiohttp
import aiomysql import asyncpg as asyncpg
import discord import discord
from decouple import config from decouple import config
from discord import Colour, Embed from discord import Colour, Embed
@ -44,7 +44,7 @@ port = config('DB_PORT')
db = config('DB_NAME') db = config('DB_NAME')
disc_bots_gg_auth = config('DISCORD_BOTS_BOTS_AUTH') 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') API_TOKEN = config('DISCORD_TOKEN')
@ -53,20 +53,21 @@ class Bot(commands.Bot):
async def get_prefix(bot, message): async def get_prefix(bot, message):
"""Allow the commands to be used with mentioning the bot""" """Allow the commands to be used with mentioning the bot"""
if message.guild is None: if message.guild is None:
return "~" return "."
return when_mentioned_or(self.get_prefix_for_guild(str(message.guild.id)))(bot, message) return when_mentioned_or(self.get_prefix_for_guild(message.guild.id))(bot, message)
super().__init__(command_prefix=get_prefix, **options) super().__init__(command_prefix=get_prefix, **options)
self.db = None 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.owner_id = 154840866496839680 # Your unique User ID
self.case_insensitive = True # Commands are now Case Insensitive self.case_insensitive = True # Commands are now Case Insensitive
self.admin_colour = Colour(0x62167a) # Admin Embed Colour 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 self.remove_command("help") # Remove default help command
# Define variables that are for Enso only # Instance variables for Enso
self.hammyMention = '<@154840866496839680>' self.hammyMention = '<@154840866496839680>'
self.hammy_role_ID = "<@&715412394968350756>" self.hammy_role_ID = "<@&715412394968350756>"
self.blank_space = "\u200b" self.blank_space = "\u200b"
@ -80,74 +81,66 @@ class Bot(commands.Bot):
self.enso_modmail_ID = 728083016290926623 self.enso_modmail_ID = 728083016290926623
self.enso_feedback_ID = 739807803438268427 self.enso_feedback_ID = 739807803438268427
# Instance variables for cache
self.enso_cache = {} self.enso_cache = {}
self.member_cache = MyCoolCache(1000) self.modmail_cache = {}
self.member_cache = MyCoolCache(2)
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)
async def create_connection(): async def create_connection():
"""Setting up connection using pool/aiomysql""" """Setting up connection using pool/aiomysql"""
self.db = await aiomysql.create_pool( self.db = await asyncpg.create_pool(
host=host, host=host,
port=int(port), port=int(port),
user=user, user=user,
password=password, password=password,
db=db, database=db,
loop=self.loop) loop=self.loop,
command_timeout=60)
async def startup_cache_log(): 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 pool = self.db
# Setup up pool connection and cursor
async with pool.acquire() as conn: 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 # Query to get all records of guilds that the bot is in
await cur.execute(select_query) try:
results = await cur.fetchall() 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: 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()) self.loop.run_until_complete(create_connection())
# Load Information Into Cache
self.loop.run_until_complete(startup_cache_log()) self.loop.run_until_complete(startup_cache_log())
async def post_bot_stats(): 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: async with aiohttp.ClientSession() as session:
await session.post(f"https://discord.bots.gg/api/v1/bots/{self.user.id}/stats", 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) @tasks.loop(minutes=10, reconnect=True)
async def change_status(): async def change_status():
"""Creating Custom Statuses as a Background Task""" """Creating custom statuses as background task"""
global counter global counter
# Waiting for the bot to ready # Waiting for the bot to ready
await self.wait_until_ready() await self.wait_until_ready()
# Update Guild Count on discord.bots.gg # Update guild count on discord.bots.gg
await post_bot_stats() await post_bot_stats()
# Define array of statuses # Define array of statuses
@ -178,7 +171,7 @@ class Bot(commands.Bot):
discord.Activity( discord.Activity(
type=discord.ActivityType.watching, type=discord.ActivityType.watching,
name=f"Hamothy Program | {self.version}"), 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 # Check if the counter is at the end of the array
@ -197,10 +190,12 @@ class Bot(commands.Bot):
# --------------------------------------------!Cache Section!------------------------------------------------------- # --------------------------------------------!Cache Section!-------------------------------------------------------
def store_cache(self, guild_id, prefix, channel, rolespersist): def store_cache(self, guild_id, prefix, modlogs, roles_persist):
"""Storing GuildID, Modlogs Channel and Prefix in Cache""" """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): def del_cache(self, guild_id):
"""Deleting the entry of the guild within the cache""" """Deleting the entry of the guild within the cache"""
@ -209,6 +204,35 @@ class Bot(commands.Bot):
# --------------------------------------------!End Cache Section!--------------------------------------------------- # --------------------------------------------!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!------------------------------------------------- # --------------------------------------------!RolePersist Section!-------------------------------------------------
def get_roles_persist(self, guild_id): def get_roles_persist(self, guild_id):
@ -216,57 +240,67 @@ class Bot(commands.Bot):
return self.enso_cache[guild_id]["roles_persist"] 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)""" """Update the rolepersist value of the guild (Enabled or Disabled)"""
self.enso_cache[guild_id]["roles_persist"] = value # Setup up pool connection
pool = self.db
# Setup up pool connection and cursor
async with pool.acquire() as conn: 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 # Query for updating rolepersist values For guilds
await cur.execute(update_query, update_vals) try:
await conn.commit() 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!--------------------------------------------- # --------------------------------------------!End RolePersist Section!---------------------------------------------
# --------------------------------------------!ModLogs 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""" """Updating the modlog within the dict and database"""
self.enso_cache[str(ctx.guild.id)]["modlogs"] = channel_id # Setup up pool connection
pool = self.db
# Setup up pool connection and cursor
async with pool.acquire() as conn: 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: # Query to update modlogs within the database
# Send confirmation that modmail channel has been setup try:
await self.bot.generate_embed(ctx, desc=f"**Modlogs Channel** successfully setup in <#{channel_id}>" + update_query = """UPDATE guilds SET modlogs = $1 WHERE guild_id = $2"""
f"\nPlease refer to **{ctx.prefix}help** for any information") rowcount = await conn.execute(update_query, channel_id, ctx.guild.id)
else:
# Let the user know that the guild modlogs channel has been updated # Catch errors
channel = ctx.guild.get_channel(channel_id) except asyncpg.PostgresError as e:
await self.generate_embed(ctx, print("PostGres Error: Modlogs Value In Guilds Table Could Not Be Updated/Setup", e)
desc=f"Modlog Channel for **{ctx.guild.name}** has been updated to {channel.mention}")
# 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): def remove_modlog_channel(self, guild_id):
"""Remove the value of modlog for the guild specified""" """Remove the value of modlog for the guild specified"""
@ -283,33 +317,42 @@ class Bot(commands.Bot):
# --------------------------------------------!Prefixes Section!---------------------------------------------------- # --------------------------------------------!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""" """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
pool = self.db
# Setup up pool connection and cursor
async with pool.acquire() as conn: 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 # Query to update the existing prefix within the database
await cur.execute(update_query, update_vals) try:
await conn.commit() update_query = """UPDATE guilds SET prefix = $1 WHERE guild_id = $2"""
print(cur.rowcount, f"Guild prefix has been updated for guild {ctx.guild.name}")
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 # 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}`**") 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): def get_prefix_for_guild(self, guild_id):
"""Get the prefix of the guild that the user is in""" """Get the prefix of the guild that the user is in"""
prefix = self.enso_cache[guild_id]["prefix"] prefix = self.enso_cache[guild_id]["prefix"]
if prefix is not None: if prefix:
return prefix return prefix
return "~" return "."
# --------------------------------------------!End Prefixes Section!------------------------------------------------ # --------------------------------------------!End Prefixes Section!------------------------------------------------
@ -322,7 +365,7 @@ class Bot(commands.Bot):
return Colour(random.randint(0, 0xFFFFFF)) return Colour(random.randint(0, 0xFFFFFF))
async def generate_embed(self, ctx, desc): async def generate_embed(self, ctx, desc):
"""Generate Embed""" """Generate embed"""
embed = Embed(description=desc, embed = Embed(description=desc,
colour=self.admin_colour) colour=self.admin_colour)
@ -330,40 +373,55 @@ class Bot(commands.Bot):
await ctx.send(embed=embed) await ctx.send(embed=embed)
async def storeRoles(self, target, ctx, member): async def storeRoles(self, target, ctx, member):
"""Storing User Roles within Database""" """Storing user roles within database"""
pool = self.db
role_ids = ", ".join([str(r.id) for r in target.roles]) 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 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 # Query to store existing roles of the member within the database
await cur.execute(update_query, update_vals) try:
await conn.commit() update_query = """UPDATE members SET muted_roles = $1 WHERE guild_id = $2 AND member_id = $3"""
print(cur.rowcount, f"Roles Added For User {member} in {ctx.guild.name}") 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): async def clearRoles(self, member):
"""Clear the roles when the user has been unmuted""" """Clear the roles when the user has been unmuted"""
# Setup up pool connection
pool = self.db pool = self.db
# Setup up pool connection and cursor
async with pool.acquire() as conn: 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 # Query to clear the existing role of the member from the database
await cur.execute(update_query, update_vals) try:
await conn.commit() update_query = """UPDATE members SET muted_roles = NULL WHERE guild_id = $1 AND member_id = $2"""
print(cur.rowcount, f"Roles Cleared For User {member} in {member.guild.name}") 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!-------------------------------------- # --------------------------------------------!End Roles/Colour/Embed Section!--------------------------------------
@ -379,7 +437,8 @@ class Bot(commands.Bot):
@staticmethod @staticmethod
async def on_ready(): async def on_ready():
"""Displaying if Bot is Ready""" """Display Startup Message"""
print("UvU Senpaiii I'm ready\n") print("UvU Senpaiii I'm ready\n")
async def on_guild_join(self, guild): async def on_guild_join(self, guild):
@ -388,70 +447,81 @@ class Bot(commands.Bot):
Store prefix/modlogs in the cache Store prefix/modlogs in the cache
""" """
# Store guildID, modlogs channel and prefix to cache # Store every single record into an array
self.store_cache(str(guild.id), channel=None, prefix="~", rolespersist=0) records = [(member.id, None, None, guild.id, None, None) for member in guild.members]
# Setup pool # Setup up pool connection
pool = self.db pool = self.db
async with pool.acquire() as conn:
# Grabbing the values to be inserted # Query to insert the guild information into guilds table
records = ", ".join(map(lambda m: f"({guild.id}, {m.id})", guild.members)) 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 # Catch errors
async with pool.acquire() as conn: except asyncpg.PostgresError as e:
async with conn.cursor() as cur: print(f"PostGres Error: Guild {guild.id} Could Not Be Inserted Into Guilds Table", e)
# 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)""" # Print success
val = guild.id, else:
print(rowcount, f"Record(s) inserted successfully into {guild}")
# Execute the query
await cur.execute(insert_query, val) # Query to insert all the member details to members table
await conn.commit() try:
print(cur.rowcount, f"Record(s) inserted successfully into Guilds from {guild.name}") rowcount = await conn.copy_records_to_table("members", records=records)
async with conn.cursor() as cur: # Catch errors
# Define the insert statement that will insert the user's information except asyncpg.PostgresError as e:
insert = """INSERT INTO members (guildID, discordID) VALUES {} print(f"PostGres Error: Members Could Not Be Inserted Into Members Table For Guild {guild.id}", e)
ON DUPLICATE KEY UPDATE guildID = VALUES(guildID), discordID = VALUES(discordID)""".format(
records) # Store in cache
else:
# Execute the query print(rowcount, f"Record(s) inserted successfully into Members from {guild}")
await cur.execute(insert) self.store_cache(guild.id, modlogs=None, prefix=".", roles_persist=0)
await conn.commit()
print(cur.rowcount, f"Record(s) inserted successfully into Members from {guild.name}") # Release connection back to pool
await pool.release(conn)
async def on_guild_remove(self, guild): async def on_guild_remove(self, guild):
""" """
Remove users in the database for the guild Remove users in the database for the guild
Remove the modlogs/guild from the cache 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 pool = self.db
# Setup pool connection and cursor
async with pool.acquire() as conn: 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 the guild information as the bot leaves the server
delete_query = """DELETE FROM guilds WHERE guildID = %s""" try:
val = guild.id, delete_query = """DELETE FROM guilds WHERE guild_id = $1"""
rowcount = await conn.execute(delete_query, guild.id)
# Execute the query
await cur.execute(delete_query, val) # Catch errors
await conn.commit() except asyncpg.PostgresError as e:
print(cur.rowcount, f"Record deleted successfully from Guild {guild.name}") print(f"PostGres Error: On Guild Remove Event Record Was Not Deleted For {guild.id}", e)
async with conn.cursor() as cur: # Delete the key - value pair for the guild
# Delete the record of the member as the bot leaves the server else:
delete_query = """DELETE FROM members WHERE guildID = %s""" print(rowcount, f"Record deleted successfully from Guild {guild}")
vals = guild.id, self.del_cache(guild.id)
# Execute the query # Delete the record of the member as the bot leaves the server
await cur.execute(delete_query, vals) try:
await conn.commit() delete_query = """DELETE FROM members WHERE guild_id = $1"""
print(cur.rowcount, f"Record(s) deleted successfully from Members from {guild.name}") 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): 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 In the Enso guild, it will send an introduction embed
""" """
# Ignoring bots
if member.bot: return if member.bot: return
# Get the guild # Get the guild and role persist value of the guild
guild = member.guild guild = member.guild
role_persist = self.get_roles_persist(guild.id)
# Setup pool # Setup pool connection
pool = self.db 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 rowcount = await conn.execute(insert_query, member.guild.id, member.id)
async with pool.acquire() as conn:
async with conn.cursor() as cur: # Catch errors
# Define the insert statement that will insert the user's information except asyncpg.PostgresError as e:
insert_query = """INSERT INTO members (guildID, discordID) VALUES (%s, %s) print(f"PostGres Error: Member {member.id} was not be able to be added to Guild {member.guild.id}", e)
ON DUPLICATE KEY UPDATE guildID = VALUES(guildID), discordID = VALUES(discordID)"""
vals = member.guild.id, member.id, # Print success
else:
# Execute the SQL Query print(rowcount, f"{member} Joined {member.guild}, Record Inserted Into Members")
await cur.execute(insert_query, vals)
await conn.commit() # Get the roles of the user from the database
print(cur.rowcount, f"{member} Joined {member.guild.name}, Record Inserted Into Members") try:
select_query = """SELECT * FROM members WHERE guild_id = $1 AND member_id = $2"""
async with conn.cursor() as cur:
# Get the roles of the user from the database user_joined = await conn.fetchrow(select_query, member.guild.id, member.id)
select_query = """SELECT * FROM members WHERE guildID = (%s) AND discordID = (%s)""" role_ids = user_joined[5]
vals = member.guild.id, member.id,
# Catch errors
# Execute the SQL Query except asyncpg.PostgresError as e:
await cur.execute(select_query, vals) print(f"PostGres Error: Member {member} Record Not Found", e)
result = await cur.fetchone()
role_ids = result[5]
# Give roles back to the user if role persist is enabled
else:
if role_persist == 1: if role_persist == 1:
# Get Enso Chan # Get Enso Chan
bot = guild.get_member(self.user.id) bot = guild.get_member(self.user.id)
# Check permissions of Enso # 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 # 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_)] roles = [member.guild.get_role(int(id_)) for id_ in role_ids.split(", ") if len(id_)]
# Give the member their roles back # Give the member their roles back
await member.edit(roles=roles) 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: else:
print(f"Insufficient Permissions to Add Roles to {member} in {member.guild.name}") print(f"Insufficient Permissions to Add Roles to Member {member.id} in Guild {member.guild.id}")
# Reset the roles entry for the database # Reset the roles entry for the database
update_query = """UPDATE members SET roles = NULL WHERE guildID = (%s) AND discordID = (%s)""" try:
update_vals = member.guild.id, member.id, 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)
# Execute the query
await cur.execute(update_query, update_vals) # Catch errors
await conn.commit() except asyncpg.PostgresError as e:
print(cur.rowcount, f"Roles Cleared For {member} in {member.guild.name}") print(f"PostGres Error: Clearing Member {member.id} Roles in Guild {member.guild.id}", e)
# Make sure the guild is Enso # Print success
if guild.id == self.enso_guild_ID: else:
# Set the channel id to "newpeople" print(rowcount, f"Roles Cleared For {member} in {member.guild}")
new_people = guild.get_channel(self.enso_newpeople_ID)
# Release connection back to pool
# Set the enso server icon and the welcoming gif await pool.release(conn)
server_icon = guild.icon_url
welcome_gif = "https://cdn.discordapp.com/attachments/669808733337157662/730186321913446521/NewPeople.gif" # Make sure the guild is Enso and send welcoming embed to the server
if guild.id == self.enso_guild_ID:
# Set up embed for the #newpeople channel new_people = guild.get_channel(self.enso_newpeople_ID)
embed = Embed(title="\n**Welcome To Ensō!**",
colour=self.admin_colour, server_icon = guild.icon_url
timestamp=datetime.datetime.utcnow()) welcome_gif = "https://cdn.discordapp.com/attachments/669808733337157662/730186321913446521/NewPeople.gif"
embed.set_thumbnail(url=server_icon) embed = Embed(title="\n**Welcome To Ensō!**",
embed.set_image(url=welcome_gif) colour=self.admin_colour,
embed.add_field( timestamp=datetime.datetime.utcnow())
name=self.blank_space,
value=f"Hello {member.mention}! We hope you enjoy your stay in this server! ", embed.set_thumbnail(url=server_icon)
inline=False) embed.set_image(url=welcome_gif)
embed.add_field( embed.add_field(
name=self.blank_space, 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! ", value=f"Hello {member.mention}! We hope you enjoy your stay in this server!",
inline=False) inline=False)
embed.add_field( embed.add_field(
name=self.blank_space, name=self.blank_space,
value=f"Last but not least, feel free to go into <#669775971297132556> to introduce yourself!", 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) inline=False)
embed.add_field(
# Send embed to #newpeople name=self.blank_space,
await new_people.send(embed=embed) 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): 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 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]) role_ids = ", ".join([str(r.id) for r in member.roles if not r.managed])
# Setup pool # Setup pool connection
pool = self.db pool = self.db
# Setup pool connection and cursor
async with pool.acquire() as conn: 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 # Store member roles within the database
await cur.execute(update_query, vals) try:
await conn.commit() update_query = """UPDATE members SET roles = $1 WHERE guild_id = $2 AND member_id = $3"""
print(cur.rowcount, f"{member} Left {member.guild.name}, Roles stored into Members") 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!---------------------------------------------- # --------------------------------------------!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): def execute(self):
"""Load the cogs and then run the bot""" """Load the cogs and then run the bot"""

@ -39,10 +39,10 @@ class CachingCircularQueue:
def remove(self, value): def remove(self, value):
# To my knowledge, this method can be called when deleting a single member and many members??? # 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: with self.threadLock:
# Remove the value inside the array (value will be a tuple that is passed in) # 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) self.values.remove(value)
# As you said, to ensure concurrency, set the current size back to the length of the array # 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): def store_cache(self, key, dict_item):
with self.threadLock: with self.threadLock:
# TODO: Changed == to >= just incase of concurrency issue meaning size exceeds maximum, thats my fault has_key = True
if len(self.queue.values) >= self.MAX_SIZE: # Assume the key exists in the cache
key_to_delete = None if key in self.cache:
if key in self.cache: # If the key is None, aka removed
if self.cache[key] is None: if self.cache[key] is None:
key_to_delete = self.queue.push(key) has_key = False
else: else:
key_to_delete = self.queue.push(key) # 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: if key_to_delete is not None:
self.cache[key_to_delete] = None self.cache[key_to_delete] = None
else: self.cache[key] = dict_item
self.cache[key] = dict_item
self.queue.push(key)
def remove_many(self, in_guild_id): def remove_many(self, in_guild_id):
# This method is to be used for when the bot has left a guild # 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 every member within the cache
for (member_id, guild_id) in self.cache: for (member_id, guild_id) in self.cache:
# if the guild_id passed in is equal to the guild_id within the 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: if in_guild_id == guild_id:
# set that entry to be equal to none # When removing a value from the cache due to a guild leave, permanently remove all values
# TODO: 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
# TODO: 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
# TODO: 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.cache.pop((member_id, guild_id))
self.queue.remove((member_id, guild_id)) self.queue.remove((member_id, guild_id))

@ -120,7 +120,7 @@ class Enso(Cog):
# Making sure this command only works in Enso # Making sure this command only works in Enso
if not ctx.guild.id == self.bot.enso_guild_ID: 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 return
# If the channel that the command has been sent is in the list of accepted channels # 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 # Send the list of available members to the channel
nice = string.capwords(', '.join(map(str, enso_people()))) nice = string.capwords(', '.join(map(str, enso_people())))
# Send error message saying that the person isn't recognised # 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!" await self.bot.generate_embed(ctx,
f"\n{nice}") desc=f"Sorry! That person doesn't exist! Try the names listed below!"
f"\n{nice}")
else: else:
@ -180,8 +181,8 @@ class Enso(Cog):
# Send the list of available members to the channel # Send the list of available members to the channel
nice = string.capwords(', '.join(map(str, enso_people()))) nice = string.capwords(', '.join(map(str, enso_people())))
# Send error message saying that the person isn't recognised # Send error message saying that the person isn't recognised
await ctx.send(f"Try the names listed below!" await self.bot.generate_embed(ctx, desc=f"Try the names listed below!"
f"\n{nice}") f"\n{nice}")
@command(name="rules") @command(name="rules")
@cooldown(1, 5, BucketType.user) @cooldown(1, 5, BucketType.user)
@ -190,7 +191,7 @@ class Enso(Cog):
# Making sure this command only works in Enso # Making sure this command only works in Enso
if not ctx.guild.id == self.bot.enso_guild_ID: 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 return
# Define Izzy's roles ID # Define Izzy's roles ID
@ -284,7 +285,7 @@ class Enso(Cog):
"""Leveled role/xp system for Ensō""" """Leveled role/xp system for Ensō"""
if not ctx.guild.id == self.bot.enso_guild_ID: 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 return
# Get the url of the leveled roles image # 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) role = discord.utils.find(lambda r: r.name == payload.emoji.name, guild.roles)
# if the role does exist # 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 to me that the role was found and display the id of the role
print(role.name + " was found!") print(role.name + " was found!")
print(role.id) print(role.id)
@ -437,7 +438,7 @@ class Enso(Cog):
role = discord.utils.find(lambda r: r.name == payload.emoji.name, guild.roles) role = discord.utils.find(lambda r: r.name == payload.emoji.name, guild.roles)
# if the role does exist # 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 # 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) member = discord.utils.find(lambda m: m.id == payload.user_id, guild.members)

@ -19,6 +19,7 @@ import datetime
import io import io
import random import random
import asyncpg
import discord import discord
from discord import Embed, TextChannel from discord import Embed, TextChannel
from discord import File from discord import File
@ -188,7 +189,7 @@ class Guild(Cog):
async def rp_status(self, ctx): async def rp_status(self, ctx):
"""Showing the status of the role persist within the guild""" """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}**") await self.bot.generate_embed(ctx, desc=f"**Role Persist is currently disabled within {ctx.guild}**")
else: else:
await self.bot.generate_embed(ctx, desc=f"**Role Persist is currently enabled within {ctx.guild}**") 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): async def rp_enable(self, ctx):
"""Enabling role persist within the guild""" """Enabling role persist within the guild"""
pool = self.bot.db if self.bot.get_roles_persist(ctx.guild.id) == 0:
await self.bot.update_role_persist(ctx.guild.id, value=1)
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)
await self.bot.generate_embed(ctx, desc=f"**Role Persist has been enabled within {ctx.guild}!**") await self.bot.generate_embed(ctx, desc=f"**Role Persist has been enabled within {ctx.guild}!**")
else: else:
await self.bot.generate_embed(ctx, desc=f"**Role Persist is already enabled within {ctx.guild}!**") 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): async def rp_disable(self, ctx):
"""Disabling role persist within the guild""" """Disabling role persist within the guild"""
pool = self.bot.db if self.bot.get_roles_persist(ctx.guild.id) == 1:
await self.bot.update_role_persist(ctx.guild.id, value=0)
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)
await self.bot.generate_embed(ctx, desc=f"**Role Persist has been disabled within {ctx.guild}!**") await self.bot.generate_embed(ctx, desc=f"**Role Persist has been disabled within {ctx.guild}!**")
else: else:
await self.bot.generate_embed(ctx, desc=f"**Role Persist is already disabled within {ctx.guild}!**") 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) @bot_has_permissions(administrator=True)
async def modlogs(self, ctx): 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 current modlogs channel only if it is setup
# Send error if no modlogs channel has been 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 # 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}**" text = f"**The current modlogs channel is set to {channel.mention}**"
await self.bot.generate_embed(ctx, desc=text) await self.bot.generate_embed(ctx, desc=text)
@ -250,105 +247,114 @@ class Guild(Cog):
@has_permissions(manage_guild=True) @has_permissions(manage_guild=True)
@bot_has_permissions(administrator=True) @bot_has_permissions(administrator=True)
async def mlsetup(self, ctx, user_channel: TextChannel): 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 pool = self.bot.db
# Setup pool connection and cursor
async with pool.acquire() as conn: 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 # Get the row of the guild from database
await cur.execute(select_query, val) try:
result = await cur.fetchone() 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 # Catch errors
if result[2] is not None: except asyncpg.PostgresError as e:
text = "**Modlogs Channel** already set up!" \ print("PostGres Error: Guild Record Could Not Be Retrieved For Modlog Setup", e)
f"\nDo **{ctx.prefix}help modlogs** to find out more!"
await self.bot.generate_embed(ctx, desc=text)
return
else: # Throw error if the modlog channel already exists
# Set up the modlogs channel within the guild else:
mod_log_setup = True if result["modlogs"]:
await self.bot.storage_modlog_for_guild(self.bot.db, ctx, user_channel.id, mod_log_setup) 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") @modlogs.command(name="update")
@has_permissions(manage_guild=True) @has_permissions(manage_guild=True)
@bot_has_permissions(administrator=True) @bot_has_permissions(administrator=True)
async def mlupdate(self, ctx, user_channel: TextChannel): 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 pool = self.bot.db
# Setup up pool connection and cursor
async with pool.acquire() as conn: 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: # Get the guilds row from the guilds table
# Update the modlog channel within the database and cache try:
mod_log_setup = False select_query = """SELECT * FROM guilds WHERE guild_id = $1"""
await self.bot.storage_modlog_for_guild(self.bot.db, ctx, user_channel.id, mod_log_setup) 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") @modlogs.command("delete")
@has_permissions(manage_guild=True) @has_permissions(manage_guild=True)
@bot_has_permissions(administrator=True) @bot_has_permissions(administrator=True)
async def mldelete(self, ctx): 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 pool = self.bot.db
# Setup up pool connection and cursor
async with pool.acquire() as conn: 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 # Get the guilds row from the guilds table
async with pool.acquire() as conn: try:
async with conn.cursor() as cur: select_query = """SELECT * FROM guilds WHERE guild_id = $1"""
# Update the existing prefix within the database result = await conn.fetchrow(select_query, ctx.guild.id)
update_query = """UPDATE guilds SET modlogs = NULL WHERE guildID = (%s)"""
update_vals = 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 # Delete channel from cache
await cur.execute(update_query, update_vals) else:
await conn.commit() self.bot.remove_modlog_channel(ctx.guild.id)
# Delete channel from cache # Release the connection back to the pool
self.bot.remove_modlog_channel(str(ctx.guild.id)) await pool.release(conn)
text = "**Modlogs System** successfully deleted!" \ text = "**Modlogs System** successfully deleted!" \
f"\nDo **{ctx.prefix}help modlogs** to setup Modlogs again!" f"\nDo **{ctx.prefix}help modlogs** to setup Modlogs again!"
@ -366,155 +372,195 @@ class Guild(Cog):
@modmail.command(name="setup") @modmail.command(name="setup")
@has_permissions(manage_guild=True) @has_permissions(manage_guild=True)
@bot_has_permissions(administrator=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 Setup Modmail System
First Argument: Input Channel(Mention or ID) where members can send modmail 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 Second Argument: Input Channel(Mention or ID) where the members mail should be sent
""" """
# Setup pool # Setup up pool connection
pool = self.bot.db pool = self.bot.db
# Setup up pool connection and cursor
async with pool.acquire() as conn: 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!" \ desc = "React to this message if you want to send a message to the Staff Team!" \
"\n\n**React with ✅**" \ "\n\n**React with ✅**" \
"\n\nWe encourage all suggestions/thoughts and opinions on the server!" \ "\n\nWe encourage all suggestions/thoughts and opinions on the server!" \
"\nAs long as it is **valid** criticism." \ "\nAs long as it is **valid** criticism." \
"\n\n\n**Purely negative feedback will not be considered.**" "\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!**", ModMail = Embed(title="**Welcome to Modmail!**",
description=desc, description=desc,
colour=self.bot.admin_colour, colour=self.bot.admin_colour,
timestamp=datetime.datetime.utcnow()) timestamp=datetime.datetime.utcnow())
ModMail.set_thumbnail(url=self.bot.user.avatar_url) ModMail.set_thumbnail(url=self.bot.user.avatar_url)
modmail_message = await user_channel.send(embed=ModMail) # Send modmail embed to the specified channel and auto add the ✅ reaction
modmail_message = await modmail.send(embed=ModMail)
# Auto add the ✅ reaction
await modmail_message.add_reaction('') await modmail_message.add_reaction('')
# Setup up pool connection and cursor # Setup up pool connection
async with pool.acquire() as conn: 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 # Insert the information about the modmail system into database
await cur.execute(insert_query, vals) try:
await conn.commit() 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!" \ # Store into cache
f"\nRefer to **{ctx.prefix}help modmail** for more information" self.bot.cache_store_modmail(ctx.guild.id, modmail.id, modmail_message.id, modmail_logging.id)
await self.bot.generate_embed(ctx, desc=text)
# Release connection back into pool
finally:
await pool.release(conn)
@modmail.command(name="update") @modmail.command(name="update")
@has_permissions(manage_guild=True) @has_permissions(manage_guild=True)
@bot_has_permissions(administrator=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 Update the Channel that the Modmail is logged to
You can Mention or use the Channel ID You can Mention or use the Channel ID
""" """
# Setup pool # Setup up pool connection
pool = self.bot.db 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 # Setup up pool connection and cursor
async with pool.acquire() as conn: async with pool.acquire() as conn:
async with conn.cursor() as cur:
# Get the author's row from the Members Table # Update the modmail channel in the database
select_query = """SELECT * FROM moderatormail WHERE guildID = (%s)""" try:
vals = ctx.guild.id, 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)
# Execute the SQL Query
await cur.execute(select_query, vals) # Catch errors
result = await cur.fetchone() except asyncpg.PostgresError as e:
print(f"PostGres Error: Modmail System Record Could Not Be Updated For Guild {ctx.guild.id}", e)
# Throw error if the guild already exists and then stop the function
if result is None: # Send confirmation that the channel has been updated
text = "**Modmail System** not set up!" \ else:
f"\nDo **{ctx.prefix}help modmail** to find out more!" text = "**Channel Updated**" \
f"\nNew Modmail will be sent to {modmail_logging_channel.mention}"
await self.bot.generate_embed(ctx, desc=text) await self.bot.generate_embed(ctx, desc=text)
return
# Setup up pool connection and cursor # Update cache
async with pool.acquire() as conn: self.bot.update_modmail(ctx.guild.id, modmail_logging_channel.id)
async with conn.cursor() as cur:
# Define the update statement that will insert information about the modmail channel # Release connection back to pool
update_query = """UPDATE moderatormail SET modmailChannelID = (%s) WHERE guildID = (%s)""" finally:
vals = modmail_channel.id, ctx.guild.id await pool.release(conn)
# 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)
@modmail.command(name="delete") @modmail.command(name="delete")
@has_permissions(manage_guild=True) @has_permissions(manage_guild=True)
@bot_has_permissions(administrator=True) @bot_has_permissions(administrator=True)
async def mmdelete(self, ctx): 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 pool = self.bot.db
# Setup up pool connection and cursor
async with pool.acquire() as conn: 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 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 # Remove the moderatormail record from the database
await cur.execute(delete_query, vals) try:
await conn.commit() 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 # Sending confirmation message that the modmail system has been deleted
text = "**Modmail System** successfully deleted!" \ else:
f"\nDo **{ctx.prefix}help modmail** to find out more!" text = "**Modmail System** successfully deleted!" \
await self.bot.generate_embed(ctx, desc=text) 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() @Cog.listener()
async def on_raw_reaction_add(self, payload): 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 ['', '']: if payload.member.bot or str(payload.emoji) not in ['', '']:
return return
# Find a role corresponding to the Emoji name. # Get the modmail information from cache
guildid = payload.guild_id modmail = self.bot.get_modmail(payload.guild_id)
if modmail:
# Setup pool channel_id = modmail["modmail_channel_id"]
pool = self.bot.db message_id = modmail["message_id"]
modmail_channel_id = modmail["modmail_logging_channel_id"]
# Setup up pool connection and cursor else:
async with pool.acquire() as conn: return
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])
# Bunch of checks to make sure it has the right guild, channel, message and reaction # 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 # Get the guild
guild = self.bot.get_guild(payload.guild_id) guild = self.bot.get_guild(payload.guild_id)

@ -657,16 +657,17 @@ class Help(Cog):
# As long as a new prefix has been given and is less than 5 characters # As long as a new prefix has been given and is less than 5 characters
if new and len(new) <= 5: if new and len(new) <= 5:
# Store the new prefix in the dictionary and update the database # 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 # Making sure that errors are handled if prefix is above 5 characters
elif new and len(new) > 5: 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 # if no prefix was provided
elif not new: elif not new:
# Grab the current prefix for the guild within the cached dictionary # 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") @command(name="support")
async def support(self, ctx): async def support(self, ctx):

@ -17,6 +17,7 @@
import datetime import datetime
import random import random
import asyncpg
from discord import Embed, Member from discord import Embed, Member
from discord.ext.commands import cooldown, command, BucketType, bot_has_permissions, Cog 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""" """Printing out that Cog is ready on startup"""
print(f"{self.__class__.__name__} Cog has been loaded\n-----") print(f"{self.__class__.__name__} Cog has been loaded\n-----")
# TODO: MAKE EVERYTHING IN HERE ASYNCHRONOUS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
@command(name="kiss") @command(name="kiss")
@bot_has_permissions(embed_links=True) @bot_has_permissions(embed_links=True)
@cooldown(1, 3, BucketType.user) @cooldown(1, 3, BucketType.user)
async def kiss(self, ctx, member: Member): async def kiss(self, ctx, member: Member):
"""Kiss your Partner""" """Kiss your partner"""
# Get the guild # Get the guild
guild = ctx.author.guild guild = ctx.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]
# Error handling to make sure that the user can kiss themselves # Error handling to make sure that the user can kiss themselves
if member.id == ctx.author.id: if member.id == ctx.author.id:
@ -75,21 +63,35 @@ class Interactive(Cog):
kiss = True kiss = True
title = f":kissing_heart: :kissing_heart: | **{ctx.author.display_name}** kissed **{member.display_name}**" title = f":kissing_heart: :kissing_heart: | **{ctx.author.display_name}** kissed **{member.display_name}**"
try: # Setup pool connection
# Make sure the user isn't trying to kiss someone else besides their partner pool = self.bot.db
if married_user is None and kiss: async with pool.acquire() as conn:
await ctx.send("Σ(‘◉⌓◉’) You need to be married in order to use this command! Baka!")
return # Get the author's row from the members table
# Make sure that the married people can only kiss their partner try:
elif not str(member.id) == married_user and kiss: select_query = """SELECT * FROM members WHERE member_id = $1 and guild_id = $2"""
await ctx.send("Σ(‘◉⌓◉’) You can only kiss your partner! Baka!") result = await conn.fetchrow(select_query, ctx.author.id, guild.id)
return
except Exception as ex: # Catch errors
print(ex) except asyncpg.PostgresError as e:
print("PostGres Error: Member Record Could Not Be Retrieved For Kiss Command", e)
# Surround with try/except to catch any exceptions that may occur
try: # 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 # Open the file containing the kissing gifs
with open('images/FunCommands/kissing.txt') as file: with open('images/FunCommands/kissing.txt') as file:
# Store content of the file in kissing_array # Store content of the file in kissing_array
@ -116,25 +118,10 @@ class Interactive(Cog):
@bot_has_permissions(embed_links=True) @bot_has_permissions(embed_links=True)
@cooldown(1, 3, BucketType.user) @cooldown(1, 3, BucketType.user)
async def cuddle(self, ctx, member: Member): async def cuddle(self, ctx, member: Member):
"""Cuddle your Partner""" """Cuddle your partner"""
# Get the guild # Get the guild
guild = ctx.author.guild guild = ctx.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]
# Error handling to make sure that the user can cuddle themselves # Error handling to make sure that the user can cuddle themselves
if member.id == ctx.author.id: if member.id == ctx.author.id:
@ -144,19 +131,30 @@ class Interactive(Cog):
cuddle = True cuddle = True
title = f":blush: :blush: | **{ctx.author.display_name}** cuddled **{member.display_name}**" title = f":blush: :blush: | **{ctx.author.display_name}** cuddled **{member.display_name}**"
try: # Setup pool connection
# Make sure the user isn't trying to cuddle someone else besides their partner pool = self.bot.db
if married_user is None and cuddle: async with pool.acquire() as conn:
await ctx.send("Σ(‘◉⌓◉’) You need to be married in order to use this command! Baka!")
return # Get the author's row from the members table
# Make sure that the married people can only cuddle their partner try:
elif not str(member.id) == married_user and cuddle: select_query = """SELECT * FROM members WHERE member_id = $1 and guild_id = $2"""
await ctx.send("Σ(‘◉⌓◉’) You can only cuddle your partner! Baka!") result = await conn.fetchrow(select_query, ctx.author.id, guild.id)
return
except Exception as ex: # Catch errors
print(ex) except asyncpg.PostgresError as e:
print("PostGres Error: Member Record Could Not Be Retrieved For Cuddle Command", e)
# Surround with try/except to catch any exceptions that may occur
# 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: try:
# Open the file containing the cuddling gifs # Open the file containing the cuddling gifs
@ -185,14 +183,13 @@ class Interactive(Cog):
@bot_has_permissions(embed_links=True) @bot_has_permissions(embed_links=True)
@cooldown(1, 3, BucketType.user) @cooldown(1, 3, BucketType.user)
async def kill(self, ctx, member: Member): async def kill(self, ctx, member: Member):
"""Kill a Member""" """Kill a member"""
if member is ctx.author: if member is ctx.author:
title = f":scream: :scream: | **{ctx.author.display_name}** killed **themselves**" title = f":scream: :scream: | **{ctx.author.display_name}** killed **themselves**"
else: else:
title = f":scream: :scream: | **{ctx.author.display_name}** killed **{member.display_name}**" title = f":scream: :scream: | **{ctx.author.display_name}** killed **{member.display_name}**"
# Surround with try/except to catch any exceptions that may occur
try: try:
# Open the file containing the killing gifs # Open the file containing the killing gifs
@ -221,14 +218,13 @@ class Interactive(Cog):
@bot_has_permissions(embed_links=True) @bot_has_permissions(embed_links=True)
@cooldown(1, 3, BucketType.user) @cooldown(1, 3, BucketType.user)
async def slap(self, ctx, member: Member): async def slap(self, ctx, member: Member):
"""Slap a Member""" """Slap a member"""
if member is ctx.author: if member is ctx.author:
title = f":cold_sweat: :cold_sweat: | **{ctx.author.display_name}** slapped **themselves**" title = f":cold_sweat: :cold_sweat: | **{ctx.author.display_name}** slapped **themselves**"
else: else:
title = f":cold_sweat: :cold_sweat: | **{ctx.author.display_name}** slapped **{member.display_name}**" 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: try:
# Open the file containing the cuddling gifs # Open the file containing the cuddling gifs
@ -257,14 +253,13 @@ class Interactive(Cog):
@bot_has_permissions(embed_links=True) @bot_has_permissions(embed_links=True)
@cooldown(1, 3, BucketType.user) @cooldown(1, 3, BucketType.user)
async def pat(self, ctx, member: Member): async def pat(self, ctx, member: Member):
"""Pat a Member""" """Pat a member"""
if member is ctx.author: if member is ctx.author:
title = f"👉 👈 | **{ctx.author.display_name}** patted **themselves**" title = f"👉 👈 | **{ctx.author.display_name}** patted **themselves**"
else: else:
title = f"👉 👈 | **{ctx.author.display_name}** patted **{member.display_name}**" title = f"👉 👈 | **{ctx.author.display_name}** patted **{member.display_name}**"
# Surround with try/except to catch any exceptions that may occur
try: try:
# Open the file containing the patting gifs # Open the file containing the patting gifs
@ -293,7 +288,7 @@ class Interactive(Cog):
@bot_has_permissions(embed_links=True) @bot_has_permissions(embed_links=True)
@cooldown(1, 3, BucketType.user) @cooldown(1, 3, BucketType.user)
async def lemon(self, ctx, member: Member): async def lemon(self, ctx, member: Member):
"""Give Lemon to Member""" """Give Lemon to member"""
if member is ctx.author: if member is ctx.author:
title = f":relaxed: :relaxed: | **{ctx.author.display_name}** gave a lemon to **themselves**" 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/669812887564320769/720093575492272208/lemon2.gif",
"https://media.discordapp.net/attachments/718484280925224981/719629805263257630/lemon.gif"] "https://media.discordapp.net/attachments/718484280925224981/719629805263257630/lemon.gif"]
# Surround with try/except to catch any exceptions that may occur
try: try:
# Get the member and the userAvatar # Get the member and the userAvatar
@ -328,14 +322,13 @@ class Interactive(Cog):
@bot_has_permissions(embed_links=True) @bot_has_permissions(embed_links=True)
@cooldown(1, 3, BucketType.user) @cooldown(1, 3, BucketType.user)
async def choke(self, ctx, member: Member): async def choke(self, ctx, member: Member):
"""Choke a Member""" """Choke a member"""
if member is ctx.author: if member is ctx.author:
title = f":confounded: :confounded: | **{ctx.author.display_name}** choked **themselves**" title = f":confounded: :confounded: | **{ctx.author.display_name}** choked **themselves**"
else: else:
title = f":confounded: :confounded: | **{ctx.author.display_name}** choked **{member.display_name}**" title = f":confounded: :confounded: | **{ctx.author.display_name}** choked **{member.display_name}**"
# Surround with try/except to catch any exceptions that may occur
try: try:
# Open the file containing the choking gifs # Open the file containing the choking gifs
with open('images/FunCommands/choking.txt') as file: with open('images/FunCommands/choking.txt') as file:
@ -363,14 +356,13 @@ class Interactive(Cog):
@bot_has_permissions(embed_links=True) @bot_has_permissions(embed_links=True)
@cooldown(1, 3, BucketType.user) @cooldown(1, 3, BucketType.user)
async def hug(self, ctx, member: Member): async def hug(self, ctx, member: Member):
"""Hug a Member""" """Hug a member"""
if member is ctx.author: if member is ctx.author:
title = f":smiling_face_with_3_hearts: :smiling_face_with_3_hearts: | **{ctx.author.display_name}** hugged **themselves**" title = f":smiling_face_with_3_hearts: :smiling_face_with_3_hearts: | **{ctx.author.display_name}** hugged **themselves**"
else: else:
title = f":smiling_face_with_3_hearts: :smiling_face_with_3_hearts: | **{ctx.author.display_name}** hugged **{member.display_name}**" 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: try:
# Open the file containing the hug gifs # Open the file containing the hug gifs

@ -35,11 +35,11 @@ async def send_to_modlogs(self, ctx, target, reason, action):
""" """
# Get the channel of the modlog within the guild # 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}", embed = Embed(title=f"Member {action}",
colour=self.bot.admin_colour, 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: for target in targets:
if (ctx.guild.me.top_role.position > target.top_role.position if (ctx.guild.me.top_role.position > target.top_role.position
and not target.guild_permissions.administrator): 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 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 # Get the roles of the user from the database
await cur.execute(select_query, select_vals) try:
result = await cur.fetchone() select_query = """SELECT * FROM members WHERE guild_id = $1 AND member_id = $2"""
role_ids = result[4] 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 # 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 # Release connection back to pool
await self.bot.clearRoles(member=target) finally:
await pool.release(conn)
# Clear all the roles of the user
await self.bot.clearRoles(member=target)
await target.edit(roles=roles) 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! ✅", embed = Embed(description=f"✅ **{target}** Was Muted! ✅",
colour=self.bot.admin_colour) 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**", 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." 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." "\nAllowing the user to bypass the Mute by leaving and rejoining."
@ -409,12 +413,12 @@ class Moderation(Cog):
"""Logging Bulk Message Deletion from Server""" """Logging Bulk Message Deletion from Server"""
# Get the channel within the cache # 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 # 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 # 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) 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**" 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): async def on_member_remove(self, member):
"""Log Member Leaves from Server""" """Log Member Leaves from Server"""
if member == self.bot.user: return
# Get the channel within the cache # 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 # When no modlogs channel is returned, do nothing
if channel is not None: if channel:
# Get the modlogs 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}**", embed = Embed(description=f"**{member.mention}** | **{member}**",
colour=self.bot.admin_colour, colour=self.bot.admin_colour,
@ -453,12 +459,12 @@ class Moderation(Cog):
"""Log Member Joins to Server""" """Log Member Joins to Server"""
# Get the channel within the cache # 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 # When no modlogs channel is returned, do nothing
if channel is not None: if channel:
# Get the modlogs 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}**", embed = Embed(description=f"**{member.mention}** | **{member}**",
colour=self.bot.admin_colour, colour=self.bot.admin_colour,
@ -477,12 +483,12 @@ class Moderation(Cog):
"""Logs Member Bans to Server""" """Logs Member Bans to Server"""
# Get the channel within the cache # 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 # When no modlogs channel is returned, do nothing
if channel is not None: if channel:
# Get the modlogs 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}**", embed = Embed(description=f"{user.mention} | **{user}**",
colour=self.bot.admin_colour, colour=self.bot.admin_colour,
@ -498,12 +504,12 @@ class Moderation(Cog):
"""Logs Member Unbans to Server""" """Logs Member Unbans to Server"""
# Get the channel within the cache # 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 # When no modlogs channel is returned, do nothing
if channel is not None: if channel:
# Get the modlogs 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}**", embed = Embed(description=f"{user.mention} | **{user}**",
colour=self.bot.admin_colour, colour=self.bot.admin_colour,
@ -519,12 +525,12 @@ class Moderation(Cog):
"""Logging Member Profile Updates""" """Logging Member Profile Updates"""
# Get the channel within the cache # 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 # When no modlogs channel is returned, do nothing
if channel is not None: if channel:
# Get the modlogs channel # Get the modlogs channel
modlogs_channel = self.bot.get_channel(int(channel)) modlogs_channel = self.bot.get_channel(channel)
# Logging Nickname Updates # Logging Nickname Updates
if before.nick != after.nick: if before.nick != after.nick:
@ -586,19 +592,19 @@ class Moderation(Cog):
async def on_message_edit(self, before, after): async def on_message_edit(self, before, after):
"""Logging Message Edits (Within Cache)""" """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 # Get the channel within the cache
if not isinstance(msg_channel, DMChannel): if not isinstance(msg_channel, DMChannel):
# Get the channel within the cache # 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: else:
return return
# When no modlogs channel is returned, do nothing # When no modlogs channel is returned, do nothing
if channel is not None: if channel:
# Get the modlogs channel # Get the modlogs channel
modlogs_channel = self.bot.get_channel(int(channel)) modlogs_channel = self.bot.get_channel(channel)
# Logging Message Content Edits # Logging Message Content Edits
# Not logging any message edits from bots # Not logging any message edits from bots
@ -629,16 +635,17 @@ class Moderation(Cog):
# Get the channel within the cache # Get the channel within the cache
if not isinstance(msg_channel, DMChannel): 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: else:
return return
# Only log this message if the message does not exist within the internal cache and modlogs channel is set up # Only log this message edit when the message does not exist within the internal cache
if channel is not None and not payload.cached_message: # and modlogs channel is set up
if channel and not payload.cached_message:
# Get the modlogs channel # 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, embed = Embed(description=desc,
colour=self.bot.admin_colour, colour=self.bot.admin_colour,
timestamp=datetime.datetime.utcnow()) timestamp=datetime.datetime.utcnow())
@ -652,12 +659,12 @@ class Moderation(Cog):
"""Logging Message Deletions (Within Cache)""" """Logging Message Deletions (Within Cache)"""
# Get the channel within the 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 # 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 # Get the modlogs channel
modlogs_channel = self.bot.get_channel(int(channel)) modlogs_channel = self.bot.get_channel(channel)
if not message.attachments: if not message.attachments:
desc = f"**Message Sent By {message.author.mention} Deleted In {message.channel.mention}" \ 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) 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): def setup(bot):
bot.add_cog(Moderation(bot)) bot.add_cog(Moderation(bot))

@ -13,7 +13,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
import asyncpg
from discord import Member from discord import Member
from discord.ext.commands import Cog, command, is_owner from discord.ext.commands import Cog, command, is_owner
@ -45,7 +45,7 @@ class Owner(Cog):
@command(name="restart", hidden=True) @command(name="restart", hidden=True)
@is_owner() @is_owner()
async def restart(self, ctx): async def restart(self, ctx):
"""Restart the Bot""" """Restart the bot"""
await self.bot.generate_embed(ctx, desc="**Success Senpai!" await self.bot.generate_embed(ctx, desc="**Success Senpai!"
"\nMy Reboot Had No Problems** <a:ThumbsUp:737832825469796382>") "\nMy Reboot Had No Problems** <a:ThumbsUp:737832825469796382>")
@ -62,21 +62,29 @@ class Owner(Cog):
# Setup pool # Setup pool
pool = self.bot.db 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 # Setup up pool connection and cursor
async with pool.acquire() as conn: async with pool.acquire() as conn:
async with conn.cursor() as cur: # Define the insert statement that will insert the user's information
# Define the insert statement that will insert the user's information try:
insert = """INSERT INTO members (guildID, discordID) VALUES """ + ", ".join( insert_query = """INSERT INTO members (guild_id, member_id) VALUES ($1, $2)
map(lambda m: f"({ctx.guild.id}, {m.id})", ON CONFLICT (guild_id, member_id) DO NOTHING"""
ctx.guild.members)) + """ ON DUPLICATE KEY UPDATE guildID = VALUES(guildID), discordID = VALUES(discordID)"""
await conn.executemany(insert_query, records)
# Execute the insert statement
await cur.execute(insert) # Catch errors
await conn.commit() except asyncpg.PostgresError as e:
print(cur.rowcount, f"Record(s) inserted successfully into Members from {ctx.guild.name}") print(f"PostGres Error: Member(s) were not be able to be added to Guild", e)
# Sending confirmation message # Print success
await ctx.send(f"Database Reloaded Successfully for **{ctx.guild.name}**") else:
print(f"Record(s) Inserted Into Members")
finally:
# Release connection back to pool
await pool.release(conn)
def setup(bot): def setup(bot):

@ -17,6 +17,7 @@
import asyncio import asyncio
import datetime import datetime
import asyncpg
from discord import Member, Embed from discord import Member, Embed
from discord.ext.commands import BucketType, command, cooldown, bot_has_permissions, Cog 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!**") await self.bot.generate_embed(ctx, desc="**Senpaii! ˭̡̞(◞⁎˃ᆺ˂)◞*✰ You can't possibly marry yourself!**")
return return
# TODO: Probably will need to get rid of this in favour of getting from cache
# Setup pool connection and cursor # Setup pool connection and cursor
async with pool.acquire() as conn: async with pool.acquire() as conn:
async with conn.cursor() as author_cursor: # Get the author's/members row from the Members Table
# Get the author's/members row from the Members Table select_query = """SELECT * FROM members WHERE member_id = $1 and guild_id = $2"""
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
# Set up new cursor for member row # Execute the Author SQL Query
async with conn.cursor() as member_cursor: db_author = await conn.fetchrow(select_query, ctx.author.id, guild.id)
# Execute the Member SQL Query married_user = db_author["married"]
await member_cursor.execute(select_query, member_val)
member_result = await member_cursor.fetchone() # Make sure that the person is not already married to someone else within the server
target_user = member_result[1] if married_user:
member = guild.get_member(married_user)
if target_user is not None: await self.bot.generate_embed(ctx, desc=f"**((╬◣﹏◢)) You're already married to {member.mention}!**")
member = guild.get_member(int(target_user)) return
await self.bot.generate_embed(ctx,
desc=f"**Sorry! That user is already married to {member.mention}**") # Execute the Member SQL Query
return 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. # 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}" 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 # Setup pool connection and cursor
async with pool.acquire() as conn: 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 message_time = msg.created_at.strftime("%a, %b %d, %Y")
await cur.execute(update_query, proposer) # Update the existing records in the database with the user that they are marrying along with the time of the accepted proposal
await cur.execute(update_query, proposee) update_query = """UPDATE members SET married = $1, married_date = $2 WHERE member_id = $3 AND guild_id = $4"""
await conn.commit()
print(cur.rowcount, "2 people have been married!") # 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! # Congratulate them!
desc = f"**Congratulations! 。゚( ゚^∀^゚)゚。 {ctx.author.mention} and {member.mention} are now married to each other!**" 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!**") await self.bot.generate_embed(ctx, desc="**Senpaii! ˭̡̞(◞⁎˃ᆺ˂)◞*✰ You can't possibly divorce yourself!**")
return 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 # Setup pool connection and cursor
async with pool.acquire() as conn: async with pool.acquire() as conn:
async with conn.cursor() as cur: async with conn.cursor() as cur:
# Get the author's row from the Members Table # Get the author's row from the Members Table
select_query = """SELECT * FROM members WHERE discordID = (%s) and guildID = (%s)""" select_query = """SELECT * FROM members WHERE member_id = $1 and guild_id = $1"""
val = ctx.author.id, guild.id,
# Execute the SQL Query # Execute the SQL Query
await cur.execute(select_query, val) result = await cur.fetchrow(select_query, ctx.author.id, guild.id)
result = await cur.fetchone() married_user = result["married"]
married_user = result[1]
# Make sure that the person trying to divorce is actually married to the user # Make sure that the person trying to divorce is actually married to the user
if married_user is None: if married_user is None:
@ -200,8 +202,8 @@ class Relationship(Cog):
return return
# Make sure the person is married to the person that they're trying to divorce # Make sure the person is married to the person that they're trying to divorce
elif married_user != str(member.id): elif married_user != member.id:
member = guild.get_member(int(married_user)) member = guild.get_member(married_user)
desc = f"**( ゜口゜) You can only divorce the person that you're married!" \ desc = f"**( ゜口゜) You can only divorce the person that you're married!" \
f"\n That person is {member.mention}**" f"\n That person is {member.mention}**"
@ -228,17 +230,19 @@ class Relationship(Cog):
# Setup pool connection and cursor # Setup pool connection and cursor
async with pool.acquire() as conn: 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 # Execute the SQL Query's
await cur.execute(update_query, divorcer) await conn.execute(update_query, ctx.author.id, guild.id)
await cur.execute(update_query, divorcee) await conn.execute(update_query, member.id, guild.id)
await conn.commit() except asyncpg.PostgresError as e:
print(cur.rowcount, "2 Members have been divorced :(!") 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! # Congratulate them!
desc = f"**૮( ´⁰▱๋⁰ )ა {ctx.author.mention} and {member.mention} are now divorced." \ desc = f"**૮( ´⁰▱๋⁰ )ა {ctx.author.mention} and {member.mention} are now divorced." \
@ -277,29 +281,28 @@ class Relationship(Cog):
# Setup pool # Setup pool
pool = self.bot.db pool = self.bot.db
# TODO: Replace this entire section with retrieving from cache
# Setup pool connection and cursor # Setup pool connection and cursor
async with pool.acquire() as conn: async with pool.acquire() as conn:
async with conn.cursor() as cur: # Get the author's row from the Members Table
# Get the author's row from the Members Table select_query = """SELECT * FROM members WHERE member_id = $1 and guild_id = $2"""
select_query = """SELECT * FROM members WHERE discordID = (%s) and guildID = (%s)"""
val = member.id, guild.id, # Execute the SQL Query
result = await conn.fetchrow(select_query, member.id, guild.id)
# Execute the SQL Query user = result["married"]
await cur.execute(select_query, val) marriage_date = result["married_date"]
result = await cur.fetchone()
user = result[1] # Set empty values for non-married users
marriage_date = result[2] if not user:
married = False
# Set empty values for non-married users marriedUser = ""
if user is None: marriedDate = ""
married = False # Set the member, date married and setting married status
marriedUser = "" else:
marriedDate = "" married = True
# Set the member, date married and setting married status marriedUser = guild.get_member(user)
else: marriedDate = marriage_date
marriedUser = guild.get_member(int(user))
marriedDate = marriage_date
married = True
# Get the current date of the message sent by the user # Get the current date of the message sent by the user
currentDate = ctx.message.created_at.strftime("%a, %b %d, %Y") currentDate = ctx.message.created_at.strftime("%a, %b %d, %Y")

@ -14,10 +14,29 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
from discord.ext.commands import is_owner
from bot import Bot from bot import Bot
# Initiating Bot Object As Client # Initiating Bot Object As Client
client = Bot() 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 # Run the bot
client.execute() client.execute()

Loading…
Cancel
Save