From ed0c1569d51411b0a52dd2d515873439ff746cf1 Mon Sep 17 00:00:00 2001 From: murpii Date: Mon, 18 Sep 2023 11:26:42 +0200 Subject: [PATCH 1/3] Add logging, send all errors to the submitter as list, some fixes --- cogs/skindb.py | 138 +++++++++++++++++++++++++++++++------------------ 1 file changed, 89 insertions(+), 49 deletions(-) diff --git a/cogs/skindb.py b/cogs/skindb.py index b33629a..b6eefbe 100644 --- a/cogs/skindb.py +++ b/cogs/skindb.py @@ -1,6 +1,8 @@ import discord from discord.ext import commands import re +import logging +import asyncio from io import BytesIO from PIL import Image, ImageOps @@ -22,42 +24,62 @@ def check_if_staff(message: discord.Message): def check_if_has_attachments(message: discord.Message): if len(message.attachments) == 0: - return (False, 'Your submission is missing attachments. Attach all skins to one message and follow the correct message format written in <#986941590780149780>') - return (True, None) + return (False, f'- Your submission is missing attachments. Attach all skins to your submission message.', + 'Missing attachments') + return (True, None, None) def check_image_format(message: discord.Message): for attachment_type in message.attachments: if attachment_type.content_type != 'image/png': - return (False, 'Wrong image format. Only PNGs are allowed.') - return (True, None) + return (False, f'- Wrong image format. Only PNGs are allowed.', 'Incorrect image format') + return (True, None, None) def check_image_resolution(message: discord.Message): + has_256x128 = False for attachment in message.attachments: + if (attachment.height == 256 and attachment.width == 128) or (attachment.height == 128 and attachment.width == 256): + has_256x128 = True if (attachment.height != 128 or attachment.width != 256) and (attachment.height != 256 or attachment.width != 512): - return (False, 'One of the attached skins does not have the correct image resolution. Resolution must be 256x128, and if possible provide a 512x256 along with the 256x128') - return (True, None) - - -def check_text_format(message: discord.Message): - # Regex to make licenses optional: "^(?P['\"].+['\"]) by (?P.+?)( (\((?PCC0|CC-BY|CC-BY-SA)\)))?$"gm + return (False, (f'- One of the attached skins does not have the correct image resolution. Resolution must be ' + '256x128, and if possible provide a 512x256 along with the 256x128'), 'Bad image resolution') + if not has_256x128: + return (False, f'- At least one of the attached skins must have a resolution of 256x128', 'Missing 256x128px skin') + return (True, None, None) + +def check_attachment_amount(message: discord.Message): + if len(message.attachments) > 2: + return (False, f'- Only 2 attachments per submission. Don\'t attach any additional images or gifs, please.', + 'Exceeded upload limit') + return (True, None, None) + +def check_message_structure(message: discord.Message): + # Regex to make licenses optional: + # "^(?P['\"].+['\"]) by (?P.+?)( (\((?PCC0|CC-BY|CC-BY-SA)\)))?$"gm regex = re.compile(r"^\"(?P.+)\" by (?P.+) (\((?P.{3,8})\))$", re.IGNORECASE) re_match = regex.match(message.content) if not re_match: return (False, - 'Your message isn\'t properly formatted. Follow the message format written in <#986941590780149780>. Also keep in mind licenses are now required for every submission.') + (f'- Your message isn\'t properly formatted. Follow the message structure written in <#986941590780149780>. ' + 'Also keep in mind licenses are now required for every submission.'), 'Bad message structure') + + licenses = ["CC0", "CC BY", "CC BY-SA"] + if re_match.group('license'): + if not re_match.group('license') in licenses: + return ( + False, + ('- Bad License. Possible licenses: `(CC0)`, `(CC BY)` or `(CC BY-SA)`\n' + '```md\n' + '# Recommended License Types\n' + 'CC0 - skin is common property, everyone can use/edit/share it however they like\n' + 'CC BY - skin can be used/edited/shared, but must be credited\n' + 'CC BY-SA - skin can be used/edited/shared, but must be credited and ' + 'derived works must also be shared under the same license```'), + 'License Missing' + ) - licenses = ["CC0", "CC-BY", "CC-BY-SA"] - if re_match.group('license') is not None: - if not any(lisense in re_match.group('license') for lisense in licenses): - return (False, 'Wrong License. Possible licenses: `(CC0)`, `(CC-BY)` or `(CC-BY-SA)`' - '\n```md' - '\n# Recommended License Types' - '\nCC0 - skin is common property, everyone can use/edit/share it however they like' - '\nCC-BY - skin can be used/edited/shared, but must be credited' - '\nCC-BY-SA - skin can be used/edited/shared, but must be credited and derived works must also be shared under the same license```') - return (True, None) + return (True, None, None) def crop_and_generate_image(img): @@ -155,36 +177,49 @@ async def check_message_format_and_render(self, message: discord.Message): if check_if_staff(message) or message.author.bot: return - check_result, check_message = check_if_has_attachments(message) + error_messages = [] + log_errors = [] + + check_result, check_message, error = check_if_has_attachments(message) if not check_result: - await message.delete() - await message.author.send(check_message) - return + error_messages.append(check_message) + log_errors.append(error) - check_result, check_message = check_image_format(message) + check_result, check_message, error = check_image_format(message) if not check_result: - await message.delete() - await message.author.send(check_message) - return + error_messages.append(check_message) + log_errors.append(error) - check_result, check_message = check_image_resolution(message) + check_result, check_message, error = check_image_resolution(message) if not check_result: - await message.delete() - await message.author.send(check_message) - return + error_messages.append(check_message) + log_errors.append(error) - check_result, check_message = check_text_format(message) + check_result, check_message, error = check_message_structure(message) if not check_result: - await message.delete() - await message.author.send(check_message) - return + error_messages.append(check_message) + log_errors.append(error) - if len(message.attachments) > 2: - await message.author.send( - 'Only 2 attachments per submission. ' - 'Don\'t attach any additional images or gifs, please.' - ) + check_result, check_message, error = check_attachment_amount(message) + if not check_result: + error_messages.append(check_message) + log_errors.append(error) + + if error_messages: await message.delete() + log_errors[0] = f'Skin submit errors by {message.author}: {", ".join(log_errors)}' + logging.info(log_errors[0]) + + try: + error_messages.insert(0, "Submit Errors: ") + await message.author.send("\n".join(error_messages)) + except discord.Forbidden: + logging.info(f'Skin submit: Unable to DM {message.author} due to their privacy settings.') + privacy_err = (f'Skin submission failed. Unable to DM {message.author.mention}. ' + f'Change your privacy settings to allow direct messages from this server.') + privacy_err_msg = await message.channel.send(content=privacy_err) + await asyncio.sleep(2 * 60) + await privacy_err_msg.delete() else: attachments = message.attachments images = [] @@ -199,11 +234,7 @@ async def check_message_format_and_render(self, message: discord.Message): image_to_process = img break - if not image_to_process: - await message.author.send("One of the attachments should be 128x256.") - return - - processed_images = crop_and_generate_image(images[0]) + processed_images = crop_and_generate_image(image_to_process) final_image = Image.new('RGBA', (512, 64)) @@ -237,7 +268,16 @@ async def message_delete_handler(self, message: discord.Message): await preview_message.delete() del self.original_message_id_and_preview_message_id[message.id] + @commands.Cog.listener('on_message_edit') + async def message_edit_handler(self, before: discord.Message, after: discord.Message): + if before.guild is None or before.guild.id != GUILD_DDNET or before.channel.id != CHAN_SKIN_SUBMIT \ + or before.author.bot or is_staff(before.author): + return + + if before.content != after.content: + await after.delete() + await after.author.send('Editing submissions is not allowed. Please re-submit your submissions.') -def setup(bot: commands.Bot): - bot.add_cog(SkinDB(bot)) +async def setup(bot: commands.Bot): + await bot.add_cog(SkinDB(bot)) \ No newline at end of file From f6c8e4b1c7a5aea46444a2e509943b66d5f40b94 Mon Sep 17 00:00:00 2001 From: murpii Date: Mon, 18 Sep 2023 16:00:02 +0200 Subject: [PATCH 2/3] Make submission message structure case-sensitive --- cogs/skindb.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cogs/skindb.py b/cogs/skindb.py index b6eefbe..c253bb0 100644 --- a/cogs/skindb.py +++ b/cogs/skindb.py @@ -57,12 +57,13 @@ def check_attachment_amount(message: discord.Message): def check_message_structure(message: discord.Message): # Regex to make licenses optional: # "^(?P['\"].+['\"]) by (?P.+?)( (\((?PCC0|CC-BY|CC-BY-SA)\)))?$"gm - regex = re.compile(r"^\"(?P.+)\" by (?P.+) (\((?P.{3,8})\))$", re.IGNORECASE) + regex = re.compile(r"^\"(?P.+)\" by (?P.+) (\((?P.{3,8})\))$") re_match = regex.match(message.content) if not re_match: return (False, (f'- Your message isn\'t properly formatted. Follow the message structure written in <#986941590780149780>. ' - 'Also keep in mind licenses are now required for every submission.'), 'Bad message structure') + 'Also keep in mind licenses are now required for every submission and proper uppercase and lowercase formatting is important as well.'), + 'Bad message structure') licenses = ["CC0", "CC BY", "CC BY-SA"] if re_match.group('license'): From 28c762010569c2a50427c6e1968c821b0ca1a1a0 Mon Sep 17 00:00:00 2001 From: murpii Date: Tue, 19 Sep 2023 21:15:05 +0200 Subject: [PATCH 3/3] Fix IDs --- cogs/skindb.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cogs/skindb.py b/cogs/skindb.py index c253bb0..f5aa960 100644 --- a/cogs/skindb.py +++ b/cogs/skindb.py @@ -6,11 +6,11 @@ from io import BytesIO from PIL import Image, ImageOps -GUILD_DDNET = 930664819303002123 -CHAN_SKIN_SUBMIT = 986107035747766292 -ROLE_ADMIN = 930665626370985994 -ROLE_DISCORD_MOD = 934131865512730656 -ROLE_SKIN_DB_CREW = 930665730091929650 +GUILD_DDNET = 252358080522747904 +CHAN_SKIN_SUBMIT = 985717921600929872 +ROLE_ADMIN = 293495272892399616 +ROLE_DISCORD_MOD = 737776812234506270 +ROLE_SKIN_DB_CREW = 390516461741015040 def is_staff(member: discord.Member) -> bool: @@ -256,8 +256,8 @@ async def check_message_format_and_render(self, message: discord.Message): image_preview_message = await message.channel.send(file=file) self.original_message_id_and_preview_message_id[message.id] = image_preview_message.id - f3_emoji = self.bot.get_emoji(933103235651223632) - f4_emoji = self.bot.get_emoji(933102663841751061) + f3_emoji = self.bot.get_emoji(346683497701834762) + f4_emoji = self.bot.get_emoji(346683496476966913) await message.add_reaction(f3_emoji) await message.add_reaction(f4_emoji)