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: for row in results:
self.enso_cache[row[0]] = {"prefix": row[1], "modlogs": row[2], "roles_persist": row[3]} 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""")
# Make sure the connection is setup before the bot is ready # Store the information for modmail within cache
for row in results:
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)
# 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 # Query to update modlogs within the database
await cur.execute(update_query, update_vals) try:
await conn.commit() update_query = """UPDATE guilds SET modlogs = $1 WHERE guild_id = $2"""
rowcount = await conn.execute(update_query, channel_id, ctx.guild.id)
# Send custom confirmation messages to log based on the command update or setup # Catch errors
if setup: except asyncpg.PostgresError as e:
print(cur.rowcount, f"Modlog channel for guild {ctx.guild.name} has been Setup") print("PostGres Error: Modlogs Value In Guilds Table Could Not Be Updated/Setup", e)
else:
print(cur.rowcount, f"Modlog channel for guild {ctx.guild.name} has been Updated")
# Let the user know that modlogs channel has been updated/setup
else:
if setup: if setup:
# Send confirmation that modmail channel has been setup print(rowcount, f"Modlog channel for guild {ctx.guild} has been Setup")
await self.bot.generate_embed(ctx, desc=f"**Modlogs Channel** successfully setup in <#{channel_id}>" + await self.generate_embed(ctx, desc=f"**Modlogs Channel** successfully setup in <#{channel_id}>" +
f"\nPlease refer to **{ctx.prefix}help** for any information") f"\nPlease refer to **{ctx.prefix}help** for any information")
else: else:
# Let the user know that the guild modlogs channel has been updated print(rowcount, f"Modlog channel for guild {ctx.guild} has been Updated")
channel = ctx.guild.get_channel(channel_id)
await self.generate_embed(ctx, await self.generate_embed(ctx,
desc=f"Modlog Channel for **{ctx.guild.name}** has been updated to {channel.mention}") 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)"""
val = guild.id,
# Execute the query # Print success
await cur.execute(insert_query, val) else:
await conn.commit() print(rowcount, f"Record(s) inserted successfully into {guild}")
print(cur.rowcount, f"Record(s) inserted successfully into Guilds from {guild.name}")
async with conn.cursor() as cur: # Query to insert all the member details to members table
# Define the insert statement that will insert the user's information try:
insert = """INSERT INTO members (guildID, discordID) VALUES {} rowcount = await conn.copy_records_to_table("members", records=records)
ON DUPLICATE KEY UPDATE guildID = VALUES(guildID), discordID = VALUES(discordID)""".format(
records)
# Execute the query # Catch errors
await cur.execute(insert) except asyncpg.PostgresError as e:
await conn.commit() print(f"PostGres Error: Members Could Not Be Inserted Into Members Table For Guild {guild.id}", e)
print(cur.rowcount, f"Record(s) inserted successfully into Members from {guild.name}")
# Store in cache
else:
print(rowcount, f"Record(s) inserted successfully into Members from {guild}")
self.store_cache(guild.id, modlogs=None, prefix=".", roles_persist=0)
# Release connection back to pool
await pool.release(conn)
async def on_guild_remove(self, guild): 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_query = """DELETE FROM guilds WHERE guildID = %s"""
val = guild.id,
# Execute the query # Delete the guild information as the bot leaves the server
await cur.execute(delete_query, val) try:
await conn.commit() delete_query = """DELETE FROM guilds WHERE guild_id = $1"""
print(cur.rowcount, f"Record deleted successfully from Guild {guild.name}") rowcount = await conn.execute(delete_query, guild.id)
# Catch errors
except asyncpg.PostgresError as e:
print(f"PostGres Error: On Guild Remove Event Record Was Not Deleted For {guild.id}", e)
# Delete the key - value pair for the guild
else:
print(rowcount, f"Record deleted successfully from Guild {guild}")
self.del_cache(guild.id)
async with conn.cursor() as cur:
# Delete the record of the member as the bot leaves the server # Delete the record of the member as the bot leaves the server
delete_query = """DELETE FROM members WHERE guildID = %s""" try:
vals = guild.id, delete_query = """DELETE FROM members WHERE guild_id = $1"""
rowcount = await conn.execute(delete_query, guild.id)
# Execute the query # Catch errors
await cur.execute(delete_query, vals) except asyncpg.PostgresError as e:
await conn.commit() print(f"PostGres Error: All Members Could Not Be Deleted From {guild.id}", e)
print(cur.rowcount, f"Record(s) deleted successfully from Members from {guild.name}")
# 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,74 +529,84 @@ 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
role_persist = self.get_roles_persist(str(guild.id))
# 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 # Define the insert statement that will insert the user's information
insert_query = """INSERT INTO members (guildID, discordID) VALUES (%s, %s) try:
ON DUPLICATE KEY UPDATE guildID = VALUES(guildID), discordID = VALUES(discordID)""" insert_query = """INSERT INTO members (guild_id, member_id) VALUES ($1, $2)
vals = member.guild.id, member.id, ON CONFLICT (guild_id, member_id) DO NOTHING"""
rowcount = await conn.execute(insert_query, member.guild.id, member.id)
# Execute the SQL Query # Catch errors
await cur.execute(insert_query, vals) except asyncpg.PostgresError as e:
await conn.commit() print(f"PostGres Error: Member {member.id} was not be able to be added to Guild {member.guild.id}", e)
print(cur.rowcount, f"{member} Joined {member.guild.name}, Record Inserted Into Members")
# Print success
else:
print(rowcount, f"{member} Joined {member.guild}, Record Inserted Into Members")
async with conn.cursor() as cur:
# Get the roles of the user from the database # Get the roles of the user from the database
select_query = """SELECT * FROM members WHERE guildID = (%s) AND discordID = (%s)""" try:
vals = member.guild.id, member.id, select_query = """SELECT * FROM members WHERE guild_id = $1 AND member_id = $2"""
user_joined = await conn.fetchrow(select_query, member.guild.id, member.id)
role_ids = user_joined[5]
# Execute the SQL Query # Catch errors
await cur.execute(select_query, vals) except asyncpg.PostgresError as e:
result = await cur.fetchone() print(f"PostGres Error: Member {member} Record Not Found", e)
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 # Catch errors
await cur.execute(update_query, update_vals) except asyncpg.PostgresError as e:
await conn.commit() print(f"PostGres Error: Clearing Member {member.id} Roles in Guild {member.guild.id}", e)
print(cur.rowcount, f"Roles Cleared For {member} in {member.guild.name}")
# Make sure the guild is Enso # Print success
else:
print(rowcount, f"Roles Cleared For {member} in {member.guild}")
# Release connection back to pool
await pool.release(conn)
# Make sure the guild is Enso and send welcoming embed to the server
if guild.id == self.enso_guild_ID: if guild.id == self.enso_guild_ID:
# Set the channel id to "newpeople"
new_people = guild.get_channel(self.enso_newpeople_ID) new_people = guild.get_channel(self.enso_newpeople_ID)
# Set the enso server icon and the welcoming gif
server_icon = guild.icon_url server_icon = guild.icon_url
welcome_gif = "https://cdn.discordapp.com/attachments/669808733337157662/730186321913446521/NewPeople.gif" welcome_gif = "https://cdn.discordapp.com/attachments/669808733337157662/730186321913446521/NewPeople.gif"
# Set up embed for the #newpeople channel
embed = Embed(title="\n**Welcome To Ensō!**", embed = Embed(title="\n**Welcome To Ensō!**",
colour=self.admin_colour, colour=self.admin_colour,
timestamp=datetime.datetime.utcnow()) timestamp=datetime.datetime.utcnow())
@ -535,7 +615,7 @@ class Bot(commands.Bot):
embed.set_image(url=welcome_gif) embed.set_image(url=welcome_gif)
embed.add_field( embed.add_field(
name=self.blank_space, name=self.blank_space,
value=f"Hello {member.mention}! We hope you enjoy your stay in this server! ", 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,
@ -550,29 +630,76 @@ class Bot(commands.Bot):
await new_people.send(embed=embed) 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:
# 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) 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,7 +143,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"Sorry! That person doesn't exist! Try the names listed below!" await self.bot.generate_embed(ctx,
desc=f"Sorry! That person doesn't exist! Try the names listed below!"
f"\n{nice}") f"\n{nice}")
else: else:
@ -180,7 +181,7 @@ 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")
@ -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)
# Catch errors
except asyncpg.PostgresError as e:
print("PostGres Error: Guild Record Could Not Be Retrieved For Modlog Setup", e)
# Throw error if the modlog channel already exists and then stop the function # Throw error if the modlog channel already exists
if result[2] is not None: else:
if result["modlogs"]:
text = "**Modlogs Channel** already set up!" \ text = "**Modlogs Channel** already set up!" \
f"\nDo **{ctx.prefix}help modlogs** to find out more!" f"\nDo **{ctx.prefix}help modlogs** to find out more!"
await self.bot.generate_embed(ctx, desc=text) await self.bot.generate_embed(ctx, desc=text)
return
else:
# Set up the modlogs channel within the guild # Set up the modlogs channel within the guild
else:
mod_log_setup = True mod_log_setup = True
await self.bot.storage_modlog_for_guild(self.bot.db, ctx, user_channel.id, mod_log_setup) 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 # Get the guilds row from the guilds table
select_query = """SELECT * FROM guilds WHERE guildID = (%s)""" try:
vals = ctx.guild.id, select_query = """SELECT * FROM guilds WHERE guild_id = $1"""
result = await conn.fetchrow(select_query, ctx.guild.id)
# Execute the SQL Query # Catch errors
await cur.execute(select_query, vals) except asyncpg.PostgresError as e:
result = await cur.fetchone() print("PostGres Error: Guild Record Could Not Be Retrieved For Modlog Update", e)
# Throw error if the modlog channel already exists and then stop the function # Throw error if the modlog channel already exists
if result[2] is None: else:
if result["married"] is None:
text = "**Modlogs Channel** not set up!" \ text = "**Modlogs Channel** not set up!" \
f"\nDo **{ctx.prefix}help modlogs** to find out more!" f"\nDo **{ctx.prefix}help modlogs** to find out more!"
await self.bot.generate_embed(ctx, desc=text) await self.bot.generate_embed(ctx, desc=text)
else:
# Update the modlog channel within the database and cache # Update the modlog channel within the database and cache
else:
mod_log_setup = False mod_log_setup = False
await self.bot.storage_modlog_for_guild(self.bot.db, ctx, user_channel.id, mod_log_setup) 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 # Get the guilds row from the guilds table
select_query = """SELECT * FROM guilds WHERE guildID = (%s)""" try:
vals = ctx.guild.id, select_query = """SELECT * FROM guilds WHERE guild_id = $1"""
result = await conn.fetchrow(select_query, ctx.guild.id)
# Execute the SQL Query # Catch errors
await cur.execute(select_query, vals) except asyncpg.PostgresError as e:
result = await cur.fetchone() print("PostGres Error: Guild Record Could Not Be Retrieved For Modlog Delete", e)
# Throw error is modlogs error has not been setup before performing a delete action # Throw error that modlogs have not been setup
if result[2] is None: else:
if result["married"] is None:
text = "**Modlogs Channel** not set up!" \ text = "**Modlogs Channel** not set up!" \
f"\nDo **{ctx.prefix}help modlogs** to find out more!" f"\nDo **{ctx.prefix}help modlogs** to find out more!"
await self.bot.generate_embed(ctx, desc=text) await self.bot.generate_embed(ctx, desc=text)
return return
# Setup up pool connection and cursor # Update the existing modlogs for guild
async with pool.acquire() as conn: try:
async with conn.cursor() as cur: update_query = """UPDATE guilds SET modlogs = NULL WHERE guild_id = $1"""
# Update the existing prefix within the database await conn.execute(update_query, ctx.guild.id)
update_query = """UPDATE guilds SET modlogs = NULL WHERE guildID = (%s)"""
update_vals = ctx.guild.id,
# Execute the query # Catch errors
await cur.execute(update_query, update_vals) except asyncpg.PostgresError as e:
await conn.commit() print(f"PostGres Error: Guild Modlogs Could Not Be Updated For {ctx.guild.id}", e)
# Delete channel from cache # Delete channel from cache
self.bot.remove_modlog_channel(str(ctx.guild.id)) else:
self.bot.remove_modlog_channel(ctx.guild.id)
# Release the connection back to the pool
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,133 +372,160 @@ 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 # Get the author's row from the members table
await cur.execute(select_query, val) try:
result = await cur.fetchone() 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 and then stop the function # Throw error if the guild already exists
if result is not None: else:
if result:
text = "**Modmail System** already set up!" \ text = "**Modmail System** already set up!" \
f"\nDo **{ctx.prefix}help modmail** to find out more!" f"\nDo **{ctx.prefix}help modmail** to find out more!"
await self.bot.generate_embed(ctx, desc=text) await self.bot.generate_embed(ctx, desc=text)
return 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!" \ text = "**Modmail System** is successfully set up!" \
f"\nRefer to **{ctx.prefix}help modmail** for more information" f"\nRefer to **{ctx.prefix}help modmail** for more information"
await self.bot.generate_embed(ctx, desc=text) await self.bot.generate_embed(ctx, desc=text)
# Store into cache
self.bot.cache_store_modmail(ctx.guild.id, modmail.id, modmail_message.id, modmail_logging.id)
# Release connection back into pool
finally:
await pool.release(conn)
@modmail.command(name="update") @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
# 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.guild.id,
# Execute the SQL Query # Get the moderatormail record from the guilds table
await cur.execute(select_query, vals) try:
result = await cur.fetchone() select_query = """SELECT * FROM moderatormail WHERE guild_id = $1"""
result = await conn.fetchrow(select_query, ctx.guild.id)
# Throw error if the guild already exists and then stop the function # Catch errors
if result is None: 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!" \ text = "**Modmail System** not set up!" \
f"\nDo **{ctx.prefix}help modmail** to find out more!" f"\nDo **{ctx.prefix}help modmail** to find out more!"
await self.bot.generate_embed(ctx, desc=text) await self.bot.generate_embed(ctx, desc=text)
return 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:
# Define the update statement that will insert information about the modmail channel
update_query = """UPDATE moderatormail SET modmailChannelID = (%s) WHERE guildID = (%s)"""
vals = modmail_channel.id, ctx.guild.id
# Execute the SQL Query # Update the modmail channel in the database
await cur.execute(update_query, vals) try:
await conn.commit() update_query = """UPDATE moderatormail SET modmail_logging_channel_id = $1 WHERE guild_id = $2"""
await conn.execute(update_query, modmail_logging_channel.id, ctx.guild.id)
# Catch errors
except asyncpg.PostgresError as e:
print(f"PostGres Error: Modmail System Record Could Not Be Updated For Guild {ctx.guild.id}", e)
# Send confirmation that the channel has been updated # Send confirmation that the channel has been updated
else:
text = "**Channel Updated**" \ text = "**Channel Updated**" \
f"\nNew Modmail will be sent to {modmail_channel.mention}" 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)
# Update cache
self.bot.update_modmail(ctx.guild.id, modmail_logging_channel.id)
# Release connection back to pool
finally:
await pool.release(conn)
@modmail.command(name="delete") @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 # Get the moderatormail record from the guilds table
await cur.execute(select_query, vals) try:
result = await cur.fetchone() 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 # Throw error if modmail system does not exist already
if result is None: if result is None:
text = "**Modmail System** not set up!" \ text = "**Modmail System** not set up!" \
@ -500,22 +533,35 @@ class Guild(Cog):
await self.bot.generate_embed(ctx, desc=text) await self.bot.generate_embed(ctx, desc=text)
return return
# Setup up pool connection and cursor # 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
else:
text = "**Modmail System** successfully deleted!" \ text = "**Modmail System** successfully deleted!" \
f"\nDo **{ctx.prefix}help modmail** to find out more!" f"\nDo **{ctx.prefix}help modmail** to find out more!"
await self.bot.generate_embed(ctx, desc=text) 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):
"""Listen for reactions for modmail channel""" """Listen for reactions for modmail channel"""
@ -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:
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 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}**"
# Setup pool connection
pool = self.bot.db
async with pool.acquire() as conn:
# Get the author's row from the members table
try: try:
# Make sure the user isn't trying to kiss someone else besides their partner select_query = """SELECT * FROM members WHERE member_id = $1 and guild_id = $2"""
result = await conn.fetchrow(select_query, ctx.author.id, guild.id)
# Catch errors
except asyncpg.PostgresError as e:
print("PostGres Error: Member Record Could Not Be Retrieved For Kiss Command", e)
# Checking conditions to make sure user is married/kissing their partner
else:
married_user = result["married"]
if married_user is None and kiss: if married_user is None and kiss:
await ctx.send("Σ(‘◉⌓◉’) You need to be married in order to use this command! Baka!") await ctx.send("Σ(‘◉⌓◉’) You need to be married in order to use this command! Baka!")
return return
# Make sure that the married people can only kiss their partner elif not member.id == married_user and kiss:
elif not str(member.id) == married_user and kiss:
await ctx.send("Σ(‘◉⌓◉’) You can only kiss your partner! Baka!") await ctx.send("Σ(‘◉⌓◉’) You can only kiss your partner! Baka!")
return return
except Exception as ex:
print(ex)
# Surround with try/except to catch any exceptions that may occur # Release connection back to pool
try: 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}**"
# Setup pool connection
pool = self.bot.db
async with pool.acquire() as conn:
# Get the author's row from the members table
try: try:
# Make sure the user isn't trying to cuddle someone else besides their partner select_query = """SELECT * FROM members WHERE member_id = $1 and guild_id = $2"""
result = await conn.fetchrow(select_query, ctx.author.id, guild.id)
# Catch errors
except asyncpg.PostgresError as e:
print("PostGres Error: Member Record Could Not Be Retrieved For Cuddle Command", e)
# Checking conditions to make sure user is married/cuddling their partner
else:
married_user = result["married"]
if married_user is None and cuddle: if married_user is None and cuddle:
await ctx.send("Σ(‘◉⌓◉’) You need to be married in order to use this command! Baka!") await ctx.send("Σ(‘◉⌓◉’) You need to be married in order to use this command! Baka!")
return return
# Make sure that the married people can only cuddle their partner elif not member.id == married_user and cuddle:
elif not str(member.id) == married_user and cuddle:
await ctx.send("Σ(‘◉⌓◉’) You can only cuddle your partner! Baka!") await ctx.send("Σ(‘◉⌓◉’) You can only cuddle your partner! Baka!")
return return
except Exception as ex:
print(ex)
# 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
@ -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,28 +87,32 @@ 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 # Get the roles of the user from the database
select_query = """SELECT * FROM members WHERE guildID = (%s) AND discordID = (%s)""" try:
select_vals = ctx.guild.id, target.id, select_query = """SELECT * FROM members WHERE guild_id = $1 AND member_id = $2"""
result = await conn.fetchrow(select_query, ctx.guild.id, target.id)
# Execute the SQL Query # Catch Errors
await cur.execute(select_query, select_vals) except Exception as e:
result = await cur.fetchone() print("PostGres Error: Record Not Found For Unmuting Members", e)
role_ids = result[4]
# 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
else:
role_ids = result["muted_roles"]
roles = [ctx.guild.get_role(int(id_)) for id_ in role_ids.split(", ") if len(id_)] roles = [ctx.guild.get_role(int(id_)) for id_ in role_ids.split(", ") if len(id_)]
# Release connection back to pool
finally:
await pool.release(conn)
# Clear all the roles of the user # Clear all the roles of the user
await self.bot.clearRoles(member=target) await self.bot.clearRoles(member=target)
@ -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
insert = """INSERT INTO members (guildID, discordID) VALUES """ + ", ".join( try:
map(lambda m: f"({ctx.guild.id}, {m.id})", insert_query = """INSERT INTO members (guild_id, member_id) VALUES ($1, $2)
ctx.guild.members)) + """ ON DUPLICATE KEY UPDATE guildID = VALUES(guildID), discordID = VALUES(discordID)""" ON CONFLICT (guild_id, member_id) DO NOTHING"""
await conn.executemany(insert_query, records)
# Catch errors
except asyncpg.PostgresError as e:
print(f"PostGres Error: Member(s) were not be able to be added to Guild", e)
# Execute the insert statement # Print success
await cur.execute(insert) else:
await conn.commit() print(f"Record(s) Inserted Into Members")
print(cur.rowcount, f"Record(s) inserted successfully into Members from {ctx.guild.name}")
# Sending confirmation message finally:
await ctx.send(f"Database Reloaded Successfully for **{ctx.guild.name}**") # 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,38 +81,36 @@ 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 discordID = (%s) and guildID = (%s)""" select_query = """SELECT * FROM members WHERE member_id = $1 and guild_id = $2"""
author_val = ctx.author.id, guild.id,
member_val = member.id, guild.id,
# Execute the Author SQL Query # Execute the Author SQL Query
await author_cursor.execute(select_query, author_val) db_author = await conn.fetchrow(select_query, ctx.author.id, guild.id)
author_result = await author_cursor.fetchone() married_user = db_author["married"]
married_user = author_result[1]
# Make sure that the person is not already married to someone else within the server # Make sure that the person is not already married to someone else within the server
if married_user is not None: if married_user:
member = guild.get_member(int(married_user)) member = guild.get_member(married_user)
await self.bot.generate_embed(ctx, desc=f"**((╬◣﹏◢)) You're already married to {member.mention}!**") await self.bot.generate_embed(ctx, desc=f"**((╬◣﹏◢)) You're already married to {member.mention}!**")
return return
# Set up new cursor for member row
async with conn.cursor() as member_cursor:
# Execute the Member SQL Query # Execute the Member SQL Query
await member_cursor.execute(select_query, member_val) db_member = await conn.fetchrow(select_query, member.id, guild.id)
member_result = await member_cursor.fetchone() target_user = db_member["married"]
target_user = member_result[1]
if target_user is not None: if target_user:
member = guild.get_member(int(target_user)) member = guild.get_member(target_user)
await self.bot.generate_embed(ctx, await self.bot.generate_embed(ctx,
desc=f"**Sorry! That user is already married to {member.mention}**") desc=f"**Sorry! That user is already married to {member.mention}**")
return 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}"
f"\n**Do you accept??**" f"\n**Do you accept??**"
@ -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") 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 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)""" update_query = """UPDATE members SET married = $1, married_date = $2 WHERE member_id = $3 AND guild_id = $4"""
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 # Execute the SQL Query's
await cur.execute(update_query, proposer) try:
await cur.execute(update_query, proposee) await conn.execute(update_query, member.id, message_time, ctx.author.id, guild.id)
await conn.commit() await conn.execute(update_query, ctx.author.id, message_time, member.id, guild.id)
print(cur.rowcount, "2 people have been married!") 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 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)""" update_query = """UPDATE members SET married = NULL, married_date = NULL WHERE member_id = $1 and guild_id = $2"""
divorcer = ctx.author.id, guild.id,
divorcee = member.id, guild.id,
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 discordID = (%s) and guildID = (%s)""" select_query = """SELECT * FROM members WHERE member_id = $1 and guild_id = $2"""
val = member.id, guild.id,
# Execute the SQL Query # Execute the SQL Query
await cur.execute(select_query, val) result = await conn.fetchrow(select_query, member.id, guild.id)
result = await cur.fetchone() user = result["married"]
user = result[1] marriage_date = result["married_date"]
marriage_date = result[2]
# Set empty values for non-married users # Set empty values for non-married users
if user is None: if not user:
married = False married = False
marriedUser = "" marriedUser = ""
marriedDate = "" marriedDate = ""
# Set the member, date married and setting married status # Set the member, date married and setting married status
else: else:
marriedUser = guild.get_member(int(user))
marriedDate = marriage_date
married = True married = True
marriedUser = guild.get_member(user)
marriedDate = marriage_date
# 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