From 2bd7752116403ecaa7bcfb51e822f073c499d73d Mon Sep 17 00:00:00 2001 From: "Sutinder S. Saini" Date: Sun, 8 Oct 2023 20:38:13 -0700 Subject: [PATCH 01/18] starboar --- database/schema.sql | 12 ++++++++++++ types_/config.py | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/database/schema.sql b/database/schema.sql index e69de29..22c9782 100644 --- a/database/schema.sql +++ b/database/schema.sql @@ -0,0 +1,12 @@ +CREATE TABLE IF NOT EXISTS starboard_entries ( + msg_id BIGINT PRIMARY KEY, + bot_message_id BIGINT, + channel BIGINT, + stars INT NOT NULL DEFAULT 1, + bot_content_id BIGINT NOT NULL +); + +CREATE TABLE IF NOT EXISTS starers ( + user_id BIGINT, + msg_id BIGINT +) \ No newline at end of file diff --git a/types_/config.py b/types_/config.py index 98eba24..dddf46a 100644 --- a/types_/config.py +++ b/types_/config.py @@ -34,6 +34,12 @@ class BadBin(TypedDict): class Suggestions(TypedDict): webhook_url: str +class Starboard(TypedDict): + remove_on_delete: bool + valid_emojis: list[str] + entry_requirement: int + starboard_channel_id: int + class Config(TypedDict): prefix: str @@ -44,3 +50,4 @@ class Config(TypedDict): SNEKBOX: NotRequired[Snekbox] BADBIN: BadBin SUGGESTIONS: NotRequired[Suggestions] + STARBOARD: Starboard \ No newline at end of file From 9460b323cefbb6374f820beb1498ec2e405cc14c Mon Sep 17 00:00:00 2001 From: "Sutinder S. Saini" Date: Sun, 8 Oct 2023 20:40:10 -0700 Subject: [PATCH 02/18] starboar --- modules/starboard.py | 235 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 modules/starboard.py diff --git a/modules/starboard.py b/modules/starboard.py new file mode 100644 index 0000000..1e0d7a2 --- /dev/null +++ b/modules/starboard.py @@ -0,0 +1,235 @@ +from typing import Optional + +import asyncpg +import discord +from datetime import datetime as date +from discord.ext import commands + +import core + +CONFIG = core.CONFIG["STARBOARD"] +STARBOARD_CHANNEL_ID = CONFIG.get("starboard_channel_id") + +STARBOARD_EMBED_COLOR = 0xFFFF00 +STARBOARD_EMOJI = "⭐" +HEADER_TEMPLATE = "**{}** {} in: <#{}> ID: {}" + + +class JumpView(discord.ui.View): + def __init__( + self, + *, + timeout, + url: Optional[str], + label_name="Jump to message", + ): + super().__init__(timeout=timeout) + self.add_item( + discord.ui.Button( + url=url, label=label_name, style=discord.ButtonStyle.primary + ) + ) + + +class StarboardEntry: + exists: bool = False + msg_id: int = 0 + channel_id: int = 0 + stars: int = 0 + bot_message_id: int = 0 + bot_content_id: int = 0 + + def __init__(self, db: asyncpg.Pool, msg_id): + self.msg_id = msg_id + self.db = db + + async def fetch(self): + query = """SELECT * FROM starboard_entries WHERE msg_id={}""".format( + self.msg_id + ) + + result = await self.db.fetchrow(query) + + if result is None: + self.exists = False + return + + self.exists = True + self.msg_id = result["msg_id"] + self.channel_id = result["channel"] + self.stars = result["stars"] + self.bot_message_id = result["bot_message_id"] + self.bot_content_id = result["bot_content_id"] + + +class Starboard(core.Cog): + def __init__(self, bot: core.Bot): + self.bot = bot + + self.remove_on_delete: bool = CONFIG.get("remove_on_delete") + self.entry_requirement: int = CONFIG.get("entry_requirement") + self.starboard_channel_id: int = CONFIG.get("starboard_channel_id") + self.pool: asyncpg.Pool = bot.pool + def get_star(self, stars): + if stars <= 2: + return "✨" + elif stars <= 4: + return "💫" + elif stars <= 6: + return "⭐" + else: + return "🌟" + + async def add_entry(self, message_id, bot_message_id, payload_channel_id, reactions, content_id): + entry_query = """INSERT INTO starboard_entries VALUES ( + {}, + {}, + {}, + {}, + {} + )""".format( + message_id, bot_message_id, payload_channel_id, reactions, content_id + ) + await self.pool.execute(entry_query) + + async def add_starer(self, user_id, message_id): + starer_query = """ + INSERT INTO starers VALUES ( + {}, + {} + )""".format( + user_id, message_id + ) + + await self.pool.execute(starer_query) + + async def remove_starer(self, user_id, message_id): + query = """DELETE FROM starers WHERE msg_id={} AND user_id={}""".format( + message_id, user_id + ) + + await self.pool.execute(query) + + def get_formatted_time(self): + now = date.now() + time = now.strftime("%m/%d/%Y %I:%M %p") + return time + + async def handle_star(self, payload): + time = self.get_formatted_time() + entry: StarboardEntry = StarboardEntry(self.pool, payload.message_id) + await entry.fetch() + + if str(payload.emoji) != STARBOARD_EMOJI: + return + + message: discord.Message = await self.bot.get_channel(payload.channel_id).fetch_message( + payload.message_id + ) + + reaction = discord.utils.get(message.reactions, emoji=STARBOARD_EMOJI) + reaction_count = reaction.count + if entry.exists: + bot_msg_id = entry.bot_message_id + + query = """SELECT * FROM starers WHERE user_id={} AND msg_id={}""".format( + payload.user_id, entry.msg_id + ) + + starer = await self.pool.fetchrow(query) + + if starer is not None: + return + + await self.add_starer(payload.user_id, payload.message_id) + + query = """UPDATE starboard_entries SET stars = starboard_entries.stars + 1 + WHERE msg_id = {} + """.format( + entry.msg_id + ) + + await self.pool.execute(query) + + bot_channel = await self.bot.fetch_channel(self.starboard_channel_id) + bot_message = await bot_channel.fetch_message(bot_msg_id) + + stars = entry.stars + 1 + star = self.get_star(stars) + await bot_message.edit(content=HEADER_TEMPLATE.format(star, stars, payload.channel_id, payload.channel_id)) + return + + if not reaction_count >= self.entry_requirement: + return + + star = self.get_star(reaction_count) + + embed = discord.Embed(color=STARBOARD_EMBED_COLOR) + + message_url = message.jump_url + + embed.set_author(name=message.author.display_name, icon_url=message.author.avatar) + embed.add_field(name="", value=message.clean_content) + embed.set_footer(text=time) + + starboard = self.bot.get_channel(self.starboard_channel_id) + + bot_message = await starboard.send(HEADER_TEMPLATE.format(star, reaction_count, payload.channel_id, payload.channel_id)) + content_message = await starboard.send(embed=embed, view=JumpView(url=message_url, timeout=40)) + + await self.add_entry(message.id, bot_message.id, payload.channel_id, reaction.count, content_message.id) + await self.add_starer(payload.user_id, message.id) + + async def handle_unstar(self, payload): + entry = StarboardEntry(self.pool, payload.message_id) + await entry.fetch() + + bot_msg_id = entry.bot_message_id + content_id = entry.bot_content_id + if not entry.exists: + return + + channel = await self.bot.fetch_channel(self.starboard_channel_id) + bot_msg = await channel.fetch_message(bot_msg_id) + content_msg = await channel.fetch_message(content_id) + + stars = entry.stars - 1 + + if stars <= 0: + # not possible to have zero stars. + await bot_msg.delete() + await content_msg.delete() + + query = """DELETE FROM starboard_entries WHERE msg_id={}""".format( + payload.message_id + ) + await self.pool.execute(query) + return + + star = self.get_star(stars) + message = HEADER_TEMPLATE.format(star, stars, payload.channel_id, payload.channel_id) + + query = """DELETE FROM starers WHERE msg_id={} AND user_id={}""".format( + payload.message_id, payload.user_id + ) + query2 = ( + """UPDATE starboard_entries SET stars = {} WHERE msg_id={}""".format( + stars, payload.message_id + ) + ) + + await self.pool.execute(query) + await self.pool.execute(query2) + await bot_msg.edit(content=message) + + @core.Cog.listener() + async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): + await self.handle_star(payload) + + @commands.Cog.listener() + async def on_raw_reaction_remove(self, payload: discord.RawReactionActionEvent): + await self.handle_unstar(payload) + + +async def setup(bot: core.Bot): + await bot.add_cog(Starboard(bot)) From d9699bad42096f84705dd7a4f172bfb7fa58e427 Mon Sep 17 00:00:00 2001 From: "Sutinder S. Saini" Date: Mon, 9 Oct 2023 19:53:05 -0700 Subject: [PATCH 03/18] throw this into blackfmt --- modules/starboard.py | 235 ------------------------------------------- modules/stars.py | 212 +++++++++++++++++++++++++++++++++++++- 2 files changed, 210 insertions(+), 237 deletions(-) delete mode 100644 modules/starboard.py diff --git a/modules/starboard.py b/modules/starboard.py deleted file mode 100644 index 1e0d7a2..0000000 --- a/modules/starboard.py +++ /dev/null @@ -1,235 +0,0 @@ -from typing import Optional - -import asyncpg -import discord -from datetime import datetime as date -from discord.ext import commands - -import core - -CONFIG = core.CONFIG["STARBOARD"] -STARBOARD_CHANNEL_ID = CONFIG.get("starboard_channel_id") - -STARBOARD_EMBED_COLOR = 0xFFFF00 -STARBOARD_EMOJI = "⭐" -HEADER_TEMPLATE = "**{}** {} in: <#{}> ID: {}" - - -class JumpView(discord.ui.View): - def __init__( - self, - *, - timeout, - url: Optional[str], - label_name="Jump to message", - ): - super().__init__(timeout=timeout) - self.add_item( - discord.ui.Button( - url=url, label=label_name, style=discord.ButtonStyle.primary - ) - ) - - -class StarboardEntry: - exists: bool = False - msg_id: int = 0 - channel_id: int = 0 - stars: int = 0 - bot_message_id: int = 0 - bot_content_id: int = 0 - - def __init__(self, db: asyncpg.Pool, msg_id): - self.msg_id = msg_id - self.db = db - - async def fetch(self): - query = """SELECT * FROM starboard_entries WHERE msg_id={}""".format( - self.msg_id - ) - - result = await self.db.fetchrow(query) - - if result is None: - self.exists = False - return - - self.exists = True - self.msg_id = result["msg_id"] - self.channel_id = result["channel"] - self.stars = result["stars"] - self.bot_message_id = result["bot_message_id"] - self.bot_content_id = result["bot_content_id"] - - -class Starboard(core.Cog): - def __init__(self, bot: core.Bot): - self.bot = bot - - self.remove_on_delete: bool = CONFIG.get("remove_on_delete") - self.entry_requirement: int = CONFIG.get("entry_requirement") - self.starboard_channel_id: int = CONFIG.get("starboard_channel_id") - self.pool: asyncpg.Pool = bot.pool - def get_star(self, stars): - if stars <= 2: - return "✨" - elif stars <= 4: - return "💫" - elif stars <= 6: - return "⭐" - else: - return "🌟" - - async def add_entry(self, message_id, bot_message_id, payload_channel_id, reactions, content_id): - entry_query = """INSERT INTO starboard_entries VALUES ( - {}, - {}, - {}, - {}, - {} - )""".format( - message_id, bot_message_id, payload_channel_id, reactions, content_id - ) - await self.pool.execute(entry_query) - - async def add_starer(self, user_id, message_id): - starer_query = """ - INSERT INTO starers VALUES ( - {}, - {} - )""".format( - user_id, message_id - ) - - await self.pool.execute(starer_query) - - async def remove_starer(self, user_id, message_id): - query = """DELETE FROM starers WHERE msg_id={} AND user_id={}""".format( - message_id, user_id - ) - - await self.pool.execute(query) - - def get_formatted_time(self): - now = date.now() - time = now.strftime("%m/%d/%Y %I:%M %p") - return time - - async def handle_star(self, payload): - time = self.get_formatted_time() - entry: StarboardEntry = StarboardEntry(self.pool, payload.message_id) - await entry.fetch() - - if str(payload.emoji) != STARBOARD_EMOJI: - return - - message: discord.Message = await self.bot.get_channel(payload.channel_id).fetch_message( - payload.message_id - ) - - reaction = discord.utils.get(message.reactions, emoji=STARBOARD_EMOJI) - reaction_count = reaction.count - if entry.exists: - bot_msg_id = entry.bot_message_id - - query = """SELECT * FROM starers WHERE user_id={} AND msg_id={}""".format( - payload.user_id, entry.msg_id - ) - - starer = await self.pool.fetchrow(query) - - if starer is not None: - return - - await self.add_starer(payload.user_id, payload.message_id) - - query = """UPDATE starboard_entries SET stars = starboard_entries.stars + 1 - WHERE msg_id = {} - """.format( - entry.msg_id - ) - - await self.pool.execute(query) - - bot_channel = await self.bot.fetch_channel(self.starboard_channel_id) - bot_message = await bot_channel.fetch_message(bot_msg_id) - - stars = entry.stars + 1 - star = self.get_star(stars) - await bot_message.edit(content=HEADER_TEMPLATE.format(star, stars, payload.channel_id, payload.channel_id)) - return - - if not reaction_count >= self.entry_requirement: - return - - star = self.get_star(reaction_count) - - embed = discord.Embed(color=STARBOARD_EMBED_COLOR) - - message_url = message.jump_url - - embed.set_author(name=message.author.display_name, icon_url=message.author.avatar) - embed.add_field(name="", value=message.clean_content) - embed.set_footer(text=time) - - starboard = self.bot.get_channel(self.starboard_channel_id) - - bot_message = await starboard.send(HEADER_TEMPLATE.format(star, reaction_count, payload.channel_id, payload.channel_id)) - content_message = await starboard.send(embed=embed, view=JumpView(url=message_url, timeout=40)) - - await self.add_entry(message.id, bot_message.id, payload.channel_id, reaction.count, content_message.id) - await self.add_starer(payload.user_id, message.id) - - async def handle_unstar(self, payload): - entry = StarboardEntry(self.pool, payload.message_id) - await entry.fetch() - - bot_msg_id = entry.bot_message_id - content_id = entry.bot_content_id - if not entry.exists: - return - - channel = await self.bot.fetch_channel(self.starboard_channel_id) - bot_msg = await channel.fetch_message(bot_msg_id) - content_msg = await channel.fetch_message(content_id) - - stars = entry.stars - 1 - - if stars <= 0: - # not possible to have zero stars. - await bot_msg.delete() - await content_msg.delete() - - query = """DELETE FROM starboard_entries WHERE msg_id={}""".format( - payload.message_id - ) - await self.pool.execute(query) - return - - star = self.get_star(stars) - message = HEADER_TEMPLATE.format(star, stars, payload.channel_id, payload.channel_id) - - query = """DELETE FROM starers WHERE msg_id={} AND user_id={}""".format( - payload.message_id, payload.user_id - ) - query2 = ( - """UPDATE starboard_entries SET stars = {} WHERE msg_id={}""".format( - stars, payload.message_id - ) - ) - - await self.pool.execute(query) - await self.pool.execute(query2) - await bot_msg.edit(content=message) - - @core.Cog.listener() - async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): - await self.handle_star(payload) - - @commands.Cog.listener() - async def on_raw_reaction_remove(self, payload: discord.RawReactionActionEvent): - await self.handle_unstar(payload) - - -async def setup(bot: core.Bot): - await bot.add_cog(Starboard(bot)) diff --git a/modules/stars.py b/modules/stars.py index 7bf102b..2bc8257 100644 --- a/modules/stars.py +++ b/modules/stars.py @@ -20,8 +20,216 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ +from typing import Optional + +import asyncpg +import discord +from datetime import datetime as date +from discord.ext import commands + import core +CONFIG = core.CONFIG["STARBOARD"] +STARBOARD_CHANNEL_ID = CONFIG.get("starboard_channel_id") + +STARBOARD_EMBED_COLOR = 0xFFFF00 +STARBOARD_EMOJI = "⭐" +HEADER_TEMPLATE = "**{}** {} in: <#{}> ID: {}" + + +class JumpView(discord.ui.View): + def __init__( + self, + *, + timeout, + url: Optional[str], + label_name="Jump to message", + ): + super().__init__(timeout=timeout) + self.add_item(discord.ui.Button(url=url, label=label_name, style=discord.ButtonStyle.primary)) + + +class StarboardEntry: + exists: bool = False + msg_id: int = 0 + channel_id: int = 0 + stars: int = 0 + bot_message_id: int = 0 + bot_content_id: int = 0 + + def __init__(self, db: asyncpg.Pool, msg_id): + self.msg_id = msg_id + self.db = db + + async def fetch(self): + query = """SELECT * FROM starboard_entries WHERE msg_id={}""".format(self.msg_id) + + result = await self.db.fetchrow(query) + + if result is None: + self.exists = False + return + + self.exists = True + self.msg_id = result["msg_id"] + self.channel_id = result["channel"] + self.stars = result["stars"] + self.bot_message_id = result["bot_message_id"] + self.bot_content_id = result["bot_content_id"] + + +class Starboard(core.Cog): + def __init__(self, bot: core.Bot): + self.bot = bot + + self.remove_on_delete: bool = CONFIG.get("remove_on_delete") + self.entry_requirement: int = CONFIG.get("entry_requirement") + self.starboard_channel_id: int = CONFIG.get("starboard_channel_id") + self.pool: asyncpg.Pool = bot.pool + + def get_star(self, stars): + if stars <= 2: + return "✨" + elif stars <= 4: + return "💫" + elif stars <= 6: + return "⭐" + else: + return "🌟" + + async def add_entry(self, message_id, bot_message_id, payload_channel_id, reactions, content_id): + entry_query = """INSERT INTO starboard_entries VALUES ( + {}, + {}, + {}, + {}, + {} + )""".format( + message_id, bot_message_id, payload_channel_id, reactions, content_id + ) + await self.pool.execute(entry_query) + + async def add_starer(self, user_id, message_id): + starer_query = """ + INSERT INTO starers VALUES ( + {}, + {} + )""".format( + user_id, message_id + ) + + await self.pool.execute(starer_query) + + def get_formatted_time(self): + now = date.now() + time = now.strftime("%m/%d/%Y %I:%M %p") + return time + + async def handle_star(self, payload): + time = self.get_formatted_time() + entry: StarboardEntry = StarboardEntry(self.pool, payload.message_id) + await entry.fetch() + + if str(payload.emoji) != STARBOARD_EMOJI: + return + + message: discord.Message = await self.bot.get_channel(payload.channel_id).fetch_message(payload.message_id) + + reaction = discord.utils.get(message.reactions, emoji=STARBOARD_EMOJI) + reaction_count = reaction.count + if entry.exists: + bot_msg_id = entry.bot_message_id + + query = """SELECT * FROM starers WHERE user_id={} AND msg_id={}""".format(payload.user_id, entry.msg_id) + + starer = await self.pool.fetchrow(query) + + if starer is not None: + return + + await self.add_starer(payload.user_id, payload.message_id) + + query = """UPDATE starboard_entries SET stars = starboard_entries.stars + 1 + WHERE msg_id = {} + """.format( + entry.msg_id + ) + + await self.pool.execute(query) + + bot_channel = await self.bot.fetch_channel(self.starboard_channel_id) + bot_message = await bot_channel.fetch_message(bot_msg_id) + + stars = entry.stars + 1 + star = self.get_star(stars) + await bot_message.edit(content=HEADER_TEMPLATE.format(star, stars, payload.channel_id, payload.channel_id)) + return + + if not reaction_count >= self.entry_requirement: + return + + star = self.get_star(reaction_count) + + embed = discord.Embed(color=STARBOARD_EMBED_COLOR) + + message_url = message.jump_url + + embed.set_author(name=message.author.display_name, icon_url=message.author.avatar) + embed.add_field(name="", value=message.clean_content) + embed.set_footer(text=time) + + starboard = self.bot.get_channel(self.starboard_channel_id) + + bot_message = await starboard.send( + HEADER_TEMPLATE.format(star, reaction_count, payload.channel_id, payload.channel_id) + ) + content_message = await starboard.send(embed=embed, view=JumpView(url=message_url, timeout=40)) + + await self.add_entry(message.id, bot_message.id, payload.channel_id, reaction.count, content_message.id) + await self.add_starer(payload.user_id, message.id) + + async def handle_unstar(self, payload): + entry = StarboardEntry(self.pool, payload.message_id) + await entry.fetch() + + bot_msg_id = entry.bot_message_id + content_id = entry.bot_content_id + if not entry.exists: + return + + channel = await self.bot.fetch_channel(self.starboard_channel_id) + bot_msg = await channel.fetch_message(bot_msg_id) + content_msg = await channel.fetch_message(content_id) + + stars = entry.stars - 1 + + if stars <= 0: + # not possible to have zero stars. + await bot_msg.delete() + await content_msg.delete() + + query = """DELETE FROM starboard_entries WHERE msg_id={}""".format(payload.message_id) + await self.pool.execute(query) + return + + star = self.get_star(stars) + message = HEADER_TEMPLATE.format(star, stars, payload.channel_id, payload.channel_id) + + query = """DELETE FROM starers WHERE msg_id={} AND user_id={}""".format(payload.message_id, payload.user_id) + query2 = """UPDATE starboard_entries SET stars = {} WHERE msg_id={}""".format(stars, payload.message_id) + + await self.pool.execute(query) + await self.pool.execute(query2) + await bot_msg.edit(content=message) + + @core.Cog.listener() + async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): + await self.handle_star(payload) + + @commands.Cog.listener() + async def on_raw_reaction_remove(self, payload: discord.RawReactionActionEvent): + await self.handle_unstar(payload) + -async def setup(bot: core.Bot) -> None: - pass +async def setup(bot: core.Bot): + await bot.add_cog(Starboard(bot)) From c00eb3dac786ba57b1b0776ea43ee7835fce1bbd Mon Sep 17 00:00:00 2001 From: "Sutinder S. Saini" Date: Fri, 13 Oct 2023 20:23:46 -0700 Subject: [PATCH 04/18] Attachment support, add typing to what i can, and fix entries & make the remove_on_delete config option usable --- modules/stars.py | 128 ++++++++++++++++++++++++++++++++++++----------- types_/config.py | 4 +- 2 files changed, 100 insertions(+), 32 deletions(-) diff --git a/modules/stars.py b/modules/stars.py index 2bc8257..5a68d29 100644 --- a/modules/stars.py +++ b/modules/stars.py @@ -41,9 +41,9 @@ class JumpView(discord.ui.View): def __init__( self, *, - timeout, + timeout: float, url: Optional[str], - label_name="Jump to message", + label_name: str = "Jump to message", ): super().__init__(timeout=timeout) self.add_item(discord.ui.Button(url=url, label=label_name, style=discord.ButtonStyle.primary)) @@ -57,9 +57,9 @@ class StarboardEntry: bot_message_id: int = 0 bot_content_id: int = 0 - def __init__(self, db: asyncpg.Pool, msg_id): + def __init__(self, db: asyncpg.Pool, msg_id: int): # type: ignore self.msg_id = msg_id - self.db = db + self.db: asyncpg.Pool[asyncpg.Record] = db async def fetch(self): query = """SELECT * FROM starboard_entries WHERE msg_id={}""".format(self.msg_id) @@ -85,9 +85,9 @@ def __init__(self, bot: core.Bot): self.remove_on_delete: bool = CONFIG.get("remove_on_delete") self.entry_requirement: int = CONFIG.get("entry_requirement") self.starboard_channel_id: int = CONFIG.get("starboard_channel_id") - self.pool: asyncpg.Pool = bot.pool + self.pool: asyncpg.Pool[asyncpg.Record] = bot.pool - def get_star(self, stars): + def get_star(self, stars: int): if stars <= 2: return "✨" elif stars <= 4: @@ -97,7 +97,13 @@ def get_star(self, stars): else: return "🌟" - async def add_entry(self, message_id, bot_message_id, payload_channel_id, reactions, content_id): + @commands.command() + async def test(self, ctx): + await ctx.message.add_reaction("⭐") + + async def add_entry( + self, message_id: int, bot_message_id: int, payload_channel_id: int, reactions: int, content_id: int + ): entry_query = """INSERT INTO starboard_entries VALUES ( {}, {}, @@ -109,7 +115,7 @@ async def add_entry(self, message_id, bot_message_id, payload_channel_id, reacti ) await self.pool.execute(entry_query) - async def add_starer(self, user_id, message_id): + async def add_starer(self, user_id: int, message_id: int): starer_query = """ INSERT INTO starers VALUES ( {}, @@ -120,12 +126,28 @@ async def add_starer(self, user_id, message_id): await self.pool.execute(starer_query) + async def remove_starer(self, message_id: int, user_id: int): + query = """DELETE FROM starers WHERE msg_id={} AND user_id={}""".format(message_id, user_id) + await self.pool.execute(query) + + async def update_entry(self, reactions: int, message_id: int): + query = """UPDATE starboard_entries SET stars = {} WHERE msg_id={}""".format(reactions, message_id) + await self.pool.execute(query) + + async def remove_entry(self, message_id: int): + query = """DELETE FROM starboard_entries WHERE msg_id={}""".format(message_id) + await self.pool.execute(query) + + async def clear_starers(self, message_id: int): + query = """DELETE FROM starers WHERE msg_id={}""".format(message_id) + await self.pool.execute(query) + def get_formatted_time(self): now = date.now() time = now.strftime("%m/%d/%Y %I:%M %p") return time - async def handle_star(self, payload): + async def handle_star(self, payload: discord.RawReactionActionEvent): time = self.get_formatted_time() entry: StarboardEntry = StarboardEntry(self.pool, payload.message_id) await entry.fetch() @@ -133,10 +155,12 @@ async def handle_star(self, payload): if str(payload.emoji) != STARBOARD_EMOJI: return - message: discord.Message = await self.bot.get_channel(payload.channel_id).fetch_message(payload.message_id) + channel: discord.TextChannel = self.bot.get_channel(payload.channel_id) # type: ignore + message: discord.Message = await channel.fetch_message(payload.message_id) reaction = discord.utils.get(message.reactions, emoji=STARBOARD_EMOJI) - reaction_count = reaction.count + reaction_count = reaction.count if reaction else 0 + if entry.exists: bot_msg_id = entry.bot_message_id @@ -157,7 +181,7 @@ async def handle_star(self, payload): await self.pool.execute(query) - bot_channel = await self.bot.fetch_channel(self.starboard_channel_id) + bot_channel: discord.TextChannel = await self.bot.fetch_channel(self.starboard_channel_id) # type: ignore bot_message = await bot_channel.fetch_message(bot_msg_id) stars = entry.stars + 1 @@ -172,54 +196,79 @@ async def handle_star(self, payload): embed = discord.Embed(color=STARBOARD_EMBED_COLOR) - message_url = message.jump_url + if len(message.attachments) > 0: + for attachment in message.attachments: + filename = attachment.filename + if ( + filename.endswith(".jpg") + or filename.endswith(".jpeg") + or filename.endswith(".png") + or filename.endswith(".webp") + or filename.endswith(".gif") + ): + embed.set_image(url=attachment.url) + elif ( + "https://images-ext-1.discordapp.net" in message.content or "https://tenor.com/view/" in message.content + ): + embed.set_image(url=message.content) + else: + break + + if "https://www.youtube.com/watch?v=" in message.content: + val = "[Click to view video]({})".format(message.content) + else: + val = message.clean_content + message_url: str = message.jump_url embed.set_author(name=message.author.display_name, icon_url=message.author.avatar) - embed.add_field(name="", value=message.clean_content) + embed.add_field(name="", value=val) embed.set_footer(text=time) starboard = self.bot.get_channel(self.starboard_channel_id) - bot_message = await starboard.send( + bot_message: discord.Message = await starboard.send( # type: ignore HEADER_TEMPLATE.format(star, reaction_count, payload.channel_id, payload.channel_id) ) - content_message = await starboard.send(embed=embed, view=JumpView(url=message_url, timeout=40)) + content_message = await starboard.send( # type: ignore + embed=embed, + view=JumpView(url=message_url, timeout=40), + ) - await self.add_entry(message.id, bot_message.id, payload.channel_id, reaction.count, content_message.id) + await self.add_entry(message.id, bot_message.id, payload.channel_id, reaction.count, content_message.id) # type: ignore await self.add_starer(payload.user_id, message.id) - async def handle_unstar(self, payload): + async def handle_unstar(self, payload: discord.RawReactionActionEvent): entry = StarboardEntry(self.pool, payload.message_id) await entry.fetch() bot_msg_id = entry.bot_message_id content_id = entry.bot_content_id + if not entry.exists: return - channel = await self.bot.fetch_channel(self.starboard_channel_id) + channel: discord.TextChannel = await self.bot.fetch_channel(self.starboard_channel_id) # type: ignore bot_msg = await channel.fetch_message(bot_msg_id) content_msg = await channel.fetch_message(content_id) - stars = entry.stars - 1 + reacted_message_channel: discord.TextChannel = await self.bot.fetch_channel(payload.channel_id) # type: ignore + reacted_message = await reacted_message_channel.fetch_message(payload.message_id) - if stars <= 0: + reaction: discord.Reaction | None = discord.utils.get(reacted_message.reactions, emoji=STARBOARD_EMOJI) + reaction_count: int = reaction.count if reaction else 0 + if reaction_count == 0: # not possible to have zero stars. await bot_msg.delete() await content_msg.delete() - query = """DELETE FROM starboard_entries WHERE msg_id={}""".format(payload.message_id) - await self.pool.execute(query) + await self.remove_entry(payload.message_id) return - star = self.get_star(stars) - message = HEADER_TEMPLATE.format(star, stars, payload.channel_id, payload.channel_id) - - query = """DELETE FROM starers WHERE msg_id={} AND user_id={}""".format(payload.message_id, payload.user_id) - query2 = """UPDATE starboard_entries SET stars = {} WHERE msg_id={}""".format(stars, payload.message_id) + star = self.get_star(reaction_count) + message = HEADER_TEMPLATE.format(star, reaction_count, payload.channel_id, payload.channel_id) - await self.pool.execute(query) - await self.pool.execute(query2) + await self.update_entry(reaction_count, payload.message_id) + await self.remove_starer(payload.message_id, payload.user_id) await bot_msg.edit(content=message) @core.Cog.listener() @@ -230,6 +279,25 @@ async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): async def on_raw_reaction_remove(self, payload: discord.RawReactionActionEvent): await self.handle_unstar(payload) + @commands.Cog.listener() + async def on_message_delete(self, message: discord.Message): + possible_entry = StarboardEntry(self.pool, message.id) # type: ignore + await possible_entry.fetch() + if not possible_entry.exists: + return + + if not self.remove_on_delete: + return + + channel: discord.TextChannel = await self.bot.fetch_channel(self.starboard_channel_id) # type: ignore + bot_msg = await channel.fetch_message(possible_entry.bot_message_id) + content_msg = await channel.fetch_message(possible_entry.bot_content_id) + + await bot_msg.delete() + await content_msg.delete() + await self.remove_entry(message.id) + await self.clear_starers(message.id) + async def setup(bot: core.Bot): await bot.add_cog(Starboard(bot)) diff --git a/types_/config.py b/types_/config.py index dddf46a..d290148 100644 --- a/types_/config.py +++ b/types_/config.py @@ -34,9 +34,9 @@ class BadBin(TypedDict): class Suggestions(TypedDict): webhook_url: str + class Starboard(TypedDict): remove_on_delete: bool - valid_emojis: list[str] entry_requirement: int starboard_channel_id: int @@ -50,4 +50,4 @@ class Config(TypedDict): SNEKBOX: NotRequired[Snekbox] BADBIN: BadBin SUGGESTIONS: NotRequired[Suggestions] - STARBOARD: Starboard \ No newline at end of file + STARBOARD: Starboard From ddfcc674aa75d5ef36d29865082a58cb70238f30 Mon Sep 17 00:00:00 2001 From: "Sutinder S. Saini" Date: Fri, 13 Oct 2023 20:26:10 -0700 Subject: [PATCH 05/18] remove test command --- modules/stars.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/stars.py b/modules/stars.py index 5a68d29..0e13f6e 100644 --- a/modules/stars.py +++ b/modules/stars.py @@ -97,10 +97,6 @@ def get_star(self, stars: int): else: return "🌟" - @commands.command() - async def test(self, ctx): - await ctx.message.add_reaction("⭐") - async def add_entry( self, message_id: int, bot_message_id: int, payload_channel_id: int, reactions: int, content_id: int ): From c35b371ad4c501066abe9f3f6e081346dbd700c1 Mon Sep 17 00:00:00 2001 From: "Sutinder S. Saini" Date: Sat, 14 Oct 2023 19:05:38 -0700 Subject: [PATCH 06/18] organize the valid attachment links into tuples --- modules/stars.py | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/modules/stars.py b/modules/stars.py index 0e13f6e..7d4ac92 100644 --- a/modules/stars.py +++ b/modules/stars.py @@ -36,14 +36,18 @@ STARBOARD_EMOJI = "⭐" HEADER_TEMPLATE = "**{}** {} in: <#{}> ID: {}" +VALID_FILE_ATTACHMENTS = (".jpg", ".jpeg", ".png", ".webp", ".gif") +VALID_IMAGE_LINKS = ("https://images-ext-1.discordapp.net", "https://tenor.com/view/") +VALID_VIDEO_ATTACHMENT_LINKS = ("https://www.youtube.com/watch?v=", "https://www.twitch.tv/videos/") + class JumpView(discord.ui.View): def __init__( - self, - *, - timeout: float, - url: Optional[str], - label_name: str = "Jump to message", + self, + *, + timeout: float, + url: Optional[str], + label_name: str = "Jump to message", ): super().__init__(timeout=timeout) self.add_item(discord.ui.Button(url=url, label=label_name, style=discord.ButtonStyle.primary)) @@ -98,7 +102,7 @@ def get_star(self, stars: int): return "🌟" async def add_entry( - self, message_id: int, bot_message_id: int, payload_channel_id: int, reactions: int, content_id: int + self, message_id: int, bot_message_id: int, payload_channel_id: int, reactions: int, content_id: int ): entry_query = """INSERT INTO starboard_entries VALUES ( {}, @@ -195,22 +199,14 @@ async def handle_star(self, payload: discord.RawReactionActionEvent): if len(message.attachments) > 0: for attachment in message.attachments: filename = attachment.filename - if ( - filename.endswith(".jpg") - or filename.endswith(".jpeg") - or filename.endswith(".png") - or filename.endswith(".webp") - or filename.endswith(".gif") - ): + if filename.endswith(VALID_FILE_ATTACHMENTS): embed.set_image(url=attachment.url) - elif ( - "https://images-ext-1.discordapp.net" in message.content or "https://tenor.com/view/" in message.content - ): + elif message.content in VALID_IMAGE_LINKS: embed.set_image(url=message.content) else: - break + continue - if "https://www.youtube.com/watch?v=" in message.content: + if message.content in VALID_VIDEO_ATTACHMENT_LINKS: val = "[Click to view video]({})".format(message.content) else: val = message.clean_content @@ -230,7 +226,8 @@ async def handle_star(self, payload: discord.RawReactionActionEvent): view=JumpView(url=message_url, timeout=40), ) - await self.add_entry(message.id, bot_message.id, payload.channel_id, reaction.count, content_message.id) # type: ignore + await self.add_entry(message.id, bot_message.id, payload.channel_id, reaction.count, + content_message.id) # type: ignore await self.add_starer(payload.user_id, message.id) async def handle_unstar(self, payload: discord.RawReactionActionEvent): From a401620c45b04b1d50fc89f757107a31fe80f77e Mon Sep 17 00:00:00 2001 From: "Sutinder S. Saini" Date: Sat, 14 Oct 2023 20:03:59 -0700 Subject: [PATCH 07/18] account for spoilers & just display youtube links as they are without the jumps --- modules/stars.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/modules/stars.py b/modules/stars.py index 7d4ac92..97510c8 100644 --- a/modules/stars.py +++ b/modules/stars.py @@ -20,11 +20,11 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ +import re from typing import Optional - import asyncpg import discord -from datetime import datetime as date +import datetime from discord.ext import commands import core @@ -37,8 +37,8 @@ HEADER_TEMPLATE = "**{}** {} in: <#{}> ID: {}" VALID_FILE_ATTACHMENTS = (".jpg", ".jpeg", ".png", ".webp", ".gif") +VIDEO_FILE_ATTACHMENTS = (".mp4", ".mov") VALID_IMAGE_LINKS = ("https://images-ext-1.discordapp.net", "https://tenor.com/view/") -VALID_VIDEO_ATTACHMENT_LINKS = ("https://www.youtube.com/watch?v=", "https://www.twitch.tv/videos/") class JumpView(discord.ui.View): @@ -143,7 +143,7 @@ async def clear_starers(self, message_id: int): await self.pool.execute(query) def get_formatted_time(self): - now = date.now() + now = datetime.datetime.now() time = now.strftime("%m/%d/%Y %I:%M %p") return time @@ -195,25 +195,24 @@ async def handle_star(self, payload: discord.RawReactionActionEvent): star = self.get_star(reaction_count) embed = discord.Embed(color=STARBOARD_EMBED_COLOR) - if len(message.attachments) > 0: for attachment in message.attachments: filename = attachment.filename if filename.endswith(VALID_FILE_ATTACHMENTS): + if attachment.is_spoiler(): + embed.add_field(name="", value=f"[Click to view spoiler]({attachment.url})", inline=True) + continue embed.set_image(url=attachment.url) - elif message.content in VALID_IMAGE_LINKS: + elif filename.endswith(VIDEO_FILE_ATTACHMENTS): + embed.add_field(name="", value=f"[File: {attachment.filename}]({message.jump_url})") + elif any(link in message.content for link in VALID_IMAGE_LINKS): embed.set_image(url=message.content) else: continue - - if message.content in VALID_VIDEO_ATTACHMENT_LINKS: - val = "[Click to view video]({})".format(message.content) - else: - val = message.clean_content message_url: str = message.jump_url embed.set_author(name=message.author.display_name, icon_url=message.author.avatar) - embed.add_field(name="", value=val) + embed.add_field(name="", value=message.content) embed.set_footer(text=time) starboard = self.bot.get_channel(self.starboard_channel_id) From 61fd49f1edf66c1e72fd4c037b71f006439b3d63 Mon Sep 17 00:00:00 2001 From: "Sutinder S. Saini" Date: Sat, 14 Oct 2023 20:04:38 -0700 Subject: [PATCH 08/18] useless import --- modules/stars.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/stars.py b/modules/stars.py index 97510c8..cfd8dc6 100644 --- a/modules/stars.py +++ b/modules/stars.py @@ -20,7 +20,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ -import re from typing import Optional import asyncpg import discord From 05ff39fcaffb8dee97c9b279a746e2bf6dabecb8 Mon Sep 17 00:00:00 2001 From: "Sutinder S. Saini" Date: Sat, 14 Oct 2023 20:07:51 -0700 Subject: [PATCH 09/18] use update_entry instead of executing the raw query --- modules/stars.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/modules/stars.py b/modules/stars.py index cfd8dc6..e06a2f4 100644 --- a/modules/stars.py +++ b/modules/stars.py @@ -172,20 +172,13 @@ async def handle_star(self, payload: discord.RawReactionActionEvent): await self.add_starer(payload.user_id, payload.message_id) - query = """UPDATE starboard_entries SET stars = starboard_entries.stars + 1 - WHERE msg_id = {} - """.format( - entry.msg_id - ) - - await self.pool.execute(query) - bot_channel: discord.TextChannel = await self.bot.fetch_channel(self.starboard_channel_id) # type: ignore bot_message = await bot_channel.fetch_message(bot_msg_id) - stars = entry.stars + 1 + stars = reaction_count star = self.get_star(stars) await bot_message.edit(content=HEADER_TEMPLATE.format(star, stars, payload.channel_id, payload.channel_id)) + await self.update_entry(stars, payload.message_id) return if not reaction_count >= self.entry_requirement: From 6c6febc48956d49e936726742a6aaa44f99ea106 Mon Sep 17 00:00:00 2001 From: "Sutinder S. Saini" Date: Sat, 14 Oct 2023 20:11:55 -0700 Subject: [PATCH 10/18] fetch the channel from cache --- modules/stars.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/stars.py b/modules/stars.py index e06a2f4..36ba77c 100644 --- a/modules/stars.py +++ b/modules/stars.py @@ -172,7 +172,7 @@ async def handle_star(self, payload: discord.RawReactionActionEvent): await self.add_starer(payload.user_id, payload.message_id) - bot_channel: discord.TextChannel = await self.bot.fetch_channel(self.starboard_channel_id) # type: ignore + bot_channel: discord.TextChannel = self.bot.get_channel(self.starboard_channel_id) # type: ignore bot_message = await bot_channel.fetch_message(bot_msg_id) stars = reaction_count From 73e905f3ef2246b3b5e57e7d70f30eba6b5d93ee Mon Sep 17 00:00:00 2001 From: "Sutinder S. Saini" Date: Sat, 14 Oct 2023 20:25:41 -0700 Subject: [PATCH 11/18] Sanitize the queries and and use f-strings --- modules/stars.py | 64 +++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/modules/stars.py b/modules/stars.py index 36ba77c..262c920 100644 --- a/modules/stars.py +++ b/modules/stars.py @@ -20,7 +20,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ -from typing import Optional import asyncpg import discord import datetime @@ -42,11 +41,11 @@ class JumpView(discord.ui.View): def __init__( - self, - *, - timeout: float, - url: Optional[str], - label_name: str = "Jump to message", + self, + *, + timeout: float, + url: str | None, + label_name: str = "Jump to message", ): super().__init__(timeout=timeout) self.add_item(discord.ui.Button(url=url, label=label_name, style=discord.ButtonStyle.primary)) @@ -101,45 +100,41 @@ def get_star(self, stars: int): return "🌟" async def add_entry( - self, message_id: int, bot_message_id: int, payload_channel_id: int, reactions: int, content_id: int + self, message_id: int, bot_message_id: int, payload_channel_id: int, reactions: int, content_id: int ): - entry_query = """INSERT INTO starboard_entries VALUES ( - {}, - {}, - {}, - {}, - {} - )""".format( - message_id, bot_message_id, payload_channel_id, reactions, content_id - ) - await self.pool.execute(entry_query) + query = """INSERT INTO starboard_entries VALUES ( + $1, + $2, + $3, + $4, + $5 + )""" + await self.pool.execute(query, message_id, bot_message_id, payload_channel_id, reactions, content_id) async def add_starer(self, user_id: int, message_id: int): - starer_query = """ + query = """ INSERT INTO starers VALUES ( - {}, - {} - )""".format( - user_id, message_id - ) + $1, + $2 + )""" - await self.pool.execute(starer_query) + await self.pool.execute(query, user_id, message_id) async def remove_starer(self, message_id: int, user_id: int): - query = """DELETE FROM starers WHERE msg_id={} AND user_id={}""".format(message_id, user_id) - await self.pool.execute(query) + query = """DELETE FROM starers WHERE msg_id = $1 AND user_id= $2""" + await self.pool.execute(query, message_id, user_id) async def update_entry(self, reactions: int, message_id: int): - query = """UPDATE starboard_entries SET stars = {} WHERE msg_id={}""".format(reactions, message_id) - await self.pool.execute(query) + query = """UPDATE starboard_entries SET stars = $1 WHERE msg_id = $2""" + await self.pool.execute(query, reactions, message_id) async def remove_entry(self, message_id: int): - query = """DELETE FROM starboard_entries WHERE msg_id={}""".format(message_id) - await self.pool.execute(query) + query = """DELETE FROM starboard_entries WHERE msg_id= $1""" + await self.pool.execute(query, message_id) async def clear_starers(self, message_id: int): - query = """DELETE FROM starers WHERE msg_id={}""".format(message_id) - await self.pool.execute(query) + query = """DELETE FROM starers WHERE msg_id = $1""" + await self.pool.execute(query, message_id) def get_formatted_time(self): now = datetime.datetime.now() @@ -217,8 +212,9 @@ async def handle_star(self, payload: discord.RawReactionActionEvent): view=JumpView(url=message_url, timeout=40), ) - await self.add_entry(message.id, bot_message.id, payload.channel_id, reaction.count, - content_message.id) # type: ignore + await self.add_entry( + message.id, bot_message.id, payload.channel_id, reaction.count, content_message.id + ) # type: ignore await self.add_starer(payload.user_id, message.id) async def handle_unstar(self, payload: discord.RawReactionActionEvent): From b537867add0c0eb42a9318f1650163df03b4bcfb Mon Sep 17 00:00:00 2001 From: "Sutinder S. Saini" Date: Sat, 14 Oct 2023 20:30:42 -0700 Subject: [PATCH 12/18] Remove annoying whitespace on the embed heading --- modules/stars.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/stars.py b/modules/stars.py index 262c920..48bfea2 100644 --- a/modules/stars.py +++ b/modules/stars.py @@ -181,7 +181,7 @@ async def handle_star(self, payload: discord.RawReactionActionEvent): star = self.get_star(reaction_count) - embed = discord.Embed(color=STARBOARD_EMBED_COLOR) + embed = discord.Embed(color=STARBOARD_EMBED_COLOR, description=message.content) if len(message.attachments) > 0: for attachment in message.attachments: filename = attachment.filename @@ -199,7 +199,6 @@ async def handle_star(self, payload: discord.RawReactionActionEvent): message_url: str = message.jump_url embed.set_author(name=message.author.display_name, icon_url=message.author.avatar) - embed.add_field(name="", value=message.content) embed.set_footer(text=time) starboard = self.bot.get_channel(self.starboard_channel_id) From 08e12e1fd5aac13eb7693b49508d873d02f5d62b Mon Sep 17 00:00:00 2001 From: "Sutinder S. Saini" Date: Fri, 20 Oct 2023 20:09:08 -0700 Subject: [PATCH 13/18] remove the remaining unsanitized query --- modules/stars.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/stars.py b/modules/stars.py index 48bfea2..006566d 100644 --- a/modules/stars.py +++ b/modules/stars.py @@ -64,9 +64,9 @@ def __init__(self, db: asyncpg.Pool, msg_id: int): # type: ignore self.db: asyncpg.Pool[asyncpg.Record] = db async def fetch(self): - query = """SELECT * FROM starboard_entries WHERE msg_id={}""".format(self.msg_id) + query = """SELECT * FROM starboard_entries WHERE msg_id=$1""" - result = await self.db.fetchrow(query) + result = await self.db.fetchrow(query, self.msg_id) if result is None: self.exists = False @@ -158,9 +158,9 @@ async def handle_star(self, payload: discord.RawReactionActionEvent): if entry.exists: bot_msg_id = entry.bot_message_id - query = """SELECT * FROM starers WHERE user_id={} AND msg_id={}""".format(payload.user_id, entry.msg_id) + query = """SELECT * FROM starers WHERE user_id=$1 AND msg_id=$2""" - starer = await self.pool.fetchrow(query) + starer = await self.pool.fetchrow(query, payload.user_id, entry.msg_id) if starer is not None: return From 1ba4e8dc64dd8c4df7a6b795c8a8ceba24dd25ae Mon Sep 17 00:00:00 2001 From: "Sutinder S. Saini" Date: Fri, 20 Oct 2023 20:11:42 -0700 Subject: [PATCH 14/18] Return annotations --- modules/stars.py | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/modules/stars.py b/modules/stars.py index 006566d..e7ac89f 100644 --- a/modules/stars.py +++ b/modules/stars.py @@ -46,7 +46,7 @@ def __init__( timeout: float, url: str | None, label_name: str = "Jump to message", - ): + ) -> None: super().__init__(timeout=timeout) self.add_item(discord.ui.Button(url=url, label=label_name, style=discord.ButtonStyle.primary)) @@ -59,11 +59,11 @@ class StarboardEntry: bot_message_id: int = 0 bot_content_id: int = 0 - def __init__(self, db: asyncpg.Pool, msg_id: int): # type: ignore + def __init__(self, db: asyncpg.Pool, msg_id: int) -> None: # type: ignore self.msg_id = msg_id self.db: asyncpg.Pool[asyncpg.Record] = db - async def fetch(self): + async def fetch(self) -> None: query = """SELECT * FROM starboard_entries WHERE msg_id=$1""" result = await self.db.fetchrow(query, self.msg_id) @@ -81,7 +81,7 @@ async def fetch(self): class Starboard(core.Cog): - def __init__(self, bot: core.Bot): + def __init__(self, bot: core.Bot) -> None: self.bot = bot self.remove_on_delete: bool = CONFIG.get("remove_on_delete") @@ -89,7 +89,7 @@ def __init__(self, bot: core.Bot): self.starboard_channel_id: int = CONFIG.get("starboard_channel_id") self.pool: asyncpg.Pool[asyncpg.Record] = bot.pool - def get_star(self, stars: int): + def get_star(self, stars: int) -> str: if stars <= 2: return "✨" elif stars <= 4: @@ -101,7 +101,7 @@ def get_star(self, stars: int): async def add_entry( self, message_id: int, bot_message_id: int, payload_channel_id: int, reactions: int, content_id: int - ): + ) -> None: query = """INSERT INTO starboard_entries VALUES ( $1, $2, @@ -111,7 +111,7 @@ async def add_entry( )""" await self.pool.execute(query, message_id, bot_message_id, payload_channel_id, reactions, content_id) - async def add_starer(self, user_id: int, message_id: int): + async def add_starer(self, user_id: int, message_id: int) -> None: query = """ INSERT INTO starers VALUES ( $1, @@ -120,28 +120,28 @@ async def add_starer(self, user_id: int, message_id: int): await self.pool.execute(query, user_id, message_id) - async def remove_starer(self, message_id: int, user_id: int): + async def remove_starer(self, message_id: int, user_id: int) -> None: query = """DELETE FROM starers WHERE msg_id = $1 AND user_id= $2""" await self.pool.execute(query, message_id, user_id) - async def update_entry(self, reactions: int, message_id: int): + async def update_entry(self, reactions: int, message_id: int) -> None: query = """UPDATE starboard_entries SET stars = $1 WHERE msg_id = $2""" await self.pool.execute(query, reactions, message_id) - async def remove_entry(self, message_id: int): + async def remove_entry(self, message_id: int) -> None: query = """DELETE FROM starboard_entries WHERE msg_id= $1""" await self.pool.execute(query, message_id) - async def clear_starers(self, message_id: int): + async def clear_starers(self, message_id: int) -> None: query = """DELETE FROM starers WHERE msg_id = $1""" await self.pool.execute(query, message_id) - def get_formatted_time(self): + def get_formatted_time(self) -> str: now = datetime.datetime.now() time = now.strftime("%m/%d/%Y %I:%M %p") return time - async def handle_star(self, payload: discord.RawReactionActionEvent): + async def handle_star(self, payload: discord.RawReactionActionEvent) -> None: time = self.get_formatted_time() entry: StarboardEntry = StarboardEntry(self.pool, payload.message_id) await entry.fetch() @@ -176,7 +176,7 @@ async def handle_star(self, payload: discord.RawReactionActionEvent): await self.update_entry(stars, payload.message_id) return - if not reaction_count >= self.entry_requirement: + if reaction_count < self.entry_requirement: return star = self.get_star(reaction_count) @@ -211,12 +211,10 @@ async def handle_star(self, payload: discord.RawReactionActionEvent): view=JumpView(url=message_url, timeout=40), ) - await self.add_entry( - message.id, bot_message.id, payload.channel_id, reaction.count, content_message.id - ) # type: ignore + await self.add_entry(message.id, bot_message.id, payload.channel_id, reaction.count, content_message.id) await self.add_starer(payload.user_id, message.id) - async def handle_unstar(self, payload: discord.RawReactionActionEvent): + async def handle_unstar(self, payload: discord.RawReactionActionEvent) -> None: entry = StarboardEntry(self.pool, payload.message_id) await entry.fetch() @@ -251,15 +249,15 @@ async def handle_unstar(self, payload: discord.RawReactionActionEvent): await bot_msg.edit(content=message) @core.Cog.listener() - async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): + async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent) -> None: await self.handle_star(payload) @commands.Cog.listener() - async def on_raw_reaction_remove(self, payload: discord.RawReactionActionEvent): + async def on_raw_reaction_remove(self, payload: discord.RawReactionActionEvent) -> None: await self.handle_unstar(payload) @commands.Cog.listener() - async def on_message_delete(self, message: discord.Message): + async def on_message_delete(self, message: discord.Message) -> None: possible_entry = StarboardEntry(self.pool, message.id) # type: ignore await possible_entry.fetch() if not possible_entry.exists: @@ -278,5 +276,5 @@ async def on_message_delete(self, message: discord.Message): await self.clear_starers(message.id) -async def setup(bot: core.Bot): +async def setup(bot: core.Bot) -> None: await bot.add_cog(Starboard(bot)) From 96f8d44658a1f44cd7389e6111d20072bb8003d8 Mon Sep 17 00:00:00 2001 From: "Sutinder S. Saini" Date: Tue, 24 Oct 2023 16:21:54 -0700 Subject: [PATCH 15/18] fix --- modules/stars.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/stars.py b/modules/stars.py index e7ac89f..fc527c1 100644 --- a/modules/stars.py +++ b/modules/stars.py @@ -20,11 +20,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ +from __future__ import annotations import asyncpg import discord import datetime from discord.ext import commands + import core CONFIG = core.CONFIG["STARBOARD"] @@ -59,7 +61,7 @@ class StarboardEntry: bot_message_id: int = 0 bot_content_id: int = 0 - def __init__(self, db: asyncpg.Pool, msg_id: int) -> None: # type: ignore + def __init__(self, db: asyncpg.Pool[asyncpg.Record], msg_id: int) -> None: self.msg_id = msg_id self.db: asyncpg.Pool[asyncpg.Record] = db From bf7bdf47d579ed36a767be90b44954628aca5582 Mon Sep 17 00:00:00 2001 From: "Sutinder S. Saini" Date: Wed, 25 Oct 2023 19:04:30 -0700 Subject: [PATCH 16/18] okay --- modules/stars.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/modules/stars.py b/modules/stars.py index fc527c1..0f3b57e 100644 --- a/modules/stars.py +++ b/modules/stars.py @@ -61,10 +61,18 @@ class StarboardEntry: bot_message_id: int = 0 bot_content_id: int = 0 + db: asyncpg.Pool[asyncpg.Record] + def __init__(self, db: asyncpg.Pool[asyncpg.Record], msg_id: int) -> None: self.msg_id = msg_id self.db: asyncpg.Pool[asyncpg.Record] = db + @classmethod + async def from_query(cls, db: asyncpg.Pool[asyncpg.Record], msg_id: int): + instance = cls(db, msg_id) + await instance.fetch() + return instance + async def fetch(self) -> None: query = """SELECT * FROM starboard_entries WHERE msg_id=$1""" @@ -145,8 +153,7 @@ def get_formatted_time(self) -> str: async def handle_star(self, payload: discord.RawReactionActionEvent) -> None: time = self.get_formatted_time() - entry: StarboardEntry = StarboardEntry(self.pool, payload.message_id) - await entry.fetch() + entry = await StarboardEntry.from_query(self.pool, payload.message_id) if str(payload.emoji) != STARBOARD_EMOJI: return @@ -217,8 +224,7 @@ async def handle_star(self, payload: discord.RawReactionActionEvent) -> None: await self.add_starer(payload.user_id, message.id) async def handle_unstar(self, payload: discord.RawReactionActionEvent) -> None: - entry = StarboardEntry(self.pool, payload.message_id) - await entry.fetch() + entry = await StarboardEntry.from_query(self.pool, payload.message_id) bot_msg_id = entry.bot_message_id content_id = entry.bot_content_id @@ -260,7 +266,7 @@ async def on_raw_reaction_remove(self, payload: discord.RawReactionActionEvent) @commands.Cog.listener() async def on_message_delete(self, message: discord.Message) -> None: - possible_entry = StarboardEntry(self.pool, message.id) # type: ignore + possible_entry = await StarboardEntry.from_query(self.pool, message.id) # type: ignore await possible_entry.fetch() if not possible_entry.exists: return From fc4bbc35111d1e660958f2a90c2f1b323e1c7bc6 Mon Sep 17 00:00:00 2001 From: "Sutinder S. Saini" Date: Thu, 23 Nov 2023 18:42:22 -0800 Subject: [PATCH 17/18] re-arrange the stars --- modules/stars.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/stars.py b/modules/stars.py index 0f3b57e..5eeddda 100644 --- a/modules/stars.py +++ b/modules/stars.py @@ -20,6 +20,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ + from __future__ import annotations import asyncpg import discord @@ -101,13 +102,13 @@ def __init__(self, bot: core.Bot) -> None: def get_star(self, stars: int) -> str: if stars <= 2: - return "✨" + return "⭐" elif stars <= 4: - return "💫" + return "🌟" elif stars <= 6: - return "⭐" + return "💫" else: - return "🌟" + return "✨" async def add_entry( self, message_id: int, bot_message_id: int, payload_channel_id: int, reactions: int, content_id: int From 31740c92fb8e0c79a527367da68075e6893468ff Mon Sep 17 00:00:00 2001 From: "Sutinder S. Saini" Date: Thu, 23 Nov 2023 19:06:08 -0800 Subject: [PATCH 18/18] do not restrict image links --- modules/stars.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/modules/stars.py b/modules/stars.py index 5eeddda..b58f897 100644 --- a/modules/stars.py +++ b/modules/stars.py @@ -39,7 +39,6 @@ VALID_FILE_ATTACHMENTS = (".jpg", ".jpeg", ".png", ".webp", ".gif") VIDEO_FILE_ATTACHMENTS = (".mp4", ".mov") -VALID_IMAGE_LINKS = ("https://images-ext-1.discordapp.net", "https://tenor.com/view/") class JumpView(discord.ui.View): @@ -202,8 +201,6 @@ async def handle_star(self, payload: discord.RawReactionActionEvent) -> None: embed.set_image(url=attachment.url) elif filename.endswith(VIDEO_FILE_ATTACHMENTS): embed.add_field(name="", value=f"[File: {attachment.filename}]({message.jump_url})") - elif any(link in message.content for link in VALID_IMAGE_LINKS): - embed.set_image(url=message.content) else: continue message_url: str = message.jump_url