From 40eb1d9cc5274ff37bb468b8260617a626cfd02b Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Wed, 26 Jul 2023 20:16:15 +0100 Subject: [PATCH 01/35] start of rewrite --- cogs/extra.py | 8 -- cogs/settings.py | 168 +--------------------- cogs/verification.py | 321 ------------------------------------------- 3 files changed, 1 insertion(+), 496 deletions(-) diff --git a/cogs/extra.py b/cogs/extra.py index 947d570..18e145b 100644 --- a/cogs/extra.py +++ b/cogs/extra.py @@ -37,14 +37,6 @@ async def _botinfo( Vote: [Vote for me](https://nomindustries.com/SV/vote) Privacy; [Privacy Policy](https://nomindustries.com/SV/privacy)""", colour=0xadd8e6) await msg.edit(content = " ", embed=embed, view=BotInfoLinkButton()) - - @nextcord.slash_command(name="guildinfo", description="[ADMIN ONLY]", guild_ids=[1015361041024155770]) - async def _guildinfo(self, ctx:Interaction): - await ctx.response.defer(ephemeral=True) - if ctx.user.id == 326065974950363136: - for i in self.client.guilds: - await ctx.user.send(len(i.members)) - await asyncio.sleep(1) @nextcord.slash_command(name="privacy", description=f"Get the link to our privacy policy") async def privacy_policy(self, ctx:Interaction): diff --git a/cogs/settings.py b/cogs/settings.py index 5ec062b..a6331e0 100644 --- a/cogs/settings.py +++ b/cogs/settings.py @@ -5,13 +5,6 @@ import pymysql, json -transfer = { - "0" : "None", - "1" : "Choice", - "2" : "Complete" -} - - class Settings(commands.Cog): @@ -22,163 +15,4 @@ def __init__(self, client): self.DBUSER = configData["DBUSER"] self.DBPASS = configData["DBPASS"] self.DBNAME = configData["DBNAME"] - self.DBENDPOINT = configData["DBENDPOINT"] - - - - @nextcord.slash_command(name="config", description="Edit your guild settings config") - async def config(self, - ctx: Interaction - ): - pass - - @config.subcommand(name="enable", description="Enable options for your guild settings config") - async def config_enable(self, - ctx: Interaction, - verifyrole : nextcord.Role = SlashOption( - name="verifyrole", - description="The role given when users successfully verify.", - required=False - ), - unverifiedrole : nextcord.Role = SlashOption( - name="unverifiedrole", - description="The role given to users when they join the server.", - required=False - ), - logchannel : GuildChannel = SlashOption( - name="logchannel", - description="Channel to send verification logs to", - required=False, - channel_types=[nextcord.ChannelType.text] - ), - captchatype : str = SlashOption( - name="captchatype", - description="Choose the type of captcha to be sent (Use `/captchatype info` to see the different options)", - required=False, - choices={"None" : "0", "Complete" : "2"} - ), - autokick : int = SlashOption( - name="autokick", - description="Select the minimum age for an account to stay in the server (**In days**)", - required=False - ), - autocaptcha : str = SlashOption( - name="autocaptcha", - description="Enable auto captcha which will automatically start verification on new users who join the server", - required=False, - choices={"Enabled" : "enabled"} - ) - ): - global transfer - await ctx.response.defer() - conn = pymysql.connect(host=self.DBENDPOINT, port=3306, user=self.DBUSER, password=self.DBPASS, db=self.DBNAME) - cur = conn.cursor() - cur.execute(f"SELECT * FROM guild_configs WHERE id='{ctx.guild.id}'") - data = cur.fetchall() - if not data: - cur.execute(f"INSERT INTO guild_configs (id) VALUES ('{ctx.guild.id}')") - conn.commit() - conn = pymysql.connect(host=self.DBENDPOINT, port=3306, user=self.DBUSER, password=self.DBPASS, db=self.DBNAME) - cur = conn.cursor() - if not verifyrole and not unverifiedrole and not logchannel and not captchatype and not autokick and not autocaptcha: - embed=nextcord.Embed(title=f"Error", description=f"It seems you didn't select any options. Make sure you select any you want to change and try again", colour=0xadd8e6) - await ctx.send(embed=embed) - return - embed=nextcord.Embed(title=f"Guild Config Updated", description=f"You have successfully updated your guild config. A list of changes is listed below:", colour=0xadd8e6) - if verifyrole: - cur.execute(f"UPDATE guild_configs SET verifyrole='{verifyrole.id}' WHERE id='{ctx.guild.id}'") - embed.add_field(name="Verify role", value=f"{verifyrole.mention} ({verifyrole.id})") - if unverifiedrole: - cur.execute(f"UPDATE guild_configs SET unverifiedrole='{unverifiedrole.id}' WHERE id='{ctx.guild.id}'") - embed.add_field(name="Unverified role", value=f"{unverifiedrole.mention} ({unverifiedrole.id})") - if logchannel: - cur.execute(f"UPDATE guild_configs SET logchannel='{logchannel.id}' WHERE id='{ctx.guild.id}'") - embed.add_field(name="Log channel", value=f"{logchannel.mention} ({logchannel.id})") - if captchatype: - cur.execute(f"UPDATE guild_configs SET captchatype='{captchatype}' WHERE id='{ctx.guild.id}'") - captchaname = transfer[captchatype] - embed.add_field(name="Captcha type", value=f"{captchaname}") - if autokick: - if not autokick > 0: - embed.add_field(name="Auto kick", description=f"Cannot set auto kick to less than 1 day") - return - cur.execute(f"UPDATE guild_configs SET autokick='{autokick}' WHERE id='{ctx.guild.id}'") - embed.add_field(name="Auto kick", value=f"{autokick} days") - if autocaptcha: - cur.execute(f"UPDATE guild_configs SET autoveri='{autocaptcha}' WHERE id='{ctx.guild.id}'") - embed.add_field(name="Auto captcha", value=f"Auto captcha has been enabled") - conn.commit() - await ctx.send(embed=embed) - - - @config.subcommand(name="disable", description="Disable options for your guild settings config") - async def config_disable(self, - ctx: Interaction, - verifyrole : str = SlashOption( - name="verifyrole", - description="The role given when users successfully verify.", - required=False, - choices={"Disable" : "disable"} - ), - unverifiedrole : str = SlashOption( - name="unverifiedrole", - description="The role given to users when they join the server.", - required=False, - choices={"Disable" : "disable"} - ), - logchannel : str = SlashOption( - name="logchannel", - description="Channel to send verification logs to", - required=False, - choices={"Disable" : "disable"} - ), - autokick : str = SlashOption( - name="autokick", - description="Select the minimum age for an account to stay in the server (**In days**)", - required=False, - choices={"Disable" : "disable"} - ), - autocaptcha : str = SlashOption( - name="autocaptcha", - description="Enable auto captcha which will automatically start verification on new users who join the server", - required=False, - choices={"Disable" : "disable"} - ) - ): - await ctx.response.defer() - conn = pymysql.connect(host=self.DBENDPOINT, port=3306, user=self.DBUSER, password=self.DBPASS, db=self.DBNAME) - cur = conn.cursor() - cur.execute(f"SELECT * FROM guild_configs WHERE id='{ctx.guild.id}'") - data = cur.fetchall() - if not data: - cur.execute(f"INSERT INTO guild_configs (id) VALUES ('{ctx.guild.id}')") - conn.commit() - conn = pymysql.connect(host=self.DBENDPOINT, port=3306, user=self.DBUSER, password=self.DBPASS, db=self.DBNAME) - cur = conn.cursor() - if not verifyrole and not unverifiedrole and not logchannel and not autokick and not autocaptcha: - embed=nextcord.Embed(title=f"Error", description=f"It seems you didn't select any options. Make sure you select any you want to change and try again", colour=0xadd8e6) - await ctx.send(embed=embed) - return - embed=nextcord.Embed(title=f"Guild Config Updated", description=f"You have successfully updated your guild config. A list of changes is listed below:", colour=0xadd8e6) - if verifyrole: - cur.execute(f"UPDATE guild_configs SET verifyrole=NULL WHERE id='{ctx.guild.id}'") - embed.add_field(name="Verify role", value=f"None") - if unverifiedrole: - cur.execute(f"UPDATE guild_configs SET unverifiedrole=NULL WHERE id='{ctx.guild.id}'") - embed.add_field(name="Unverified role", value=f"None") - if logchannel: - cur.execute(f"UPDATE guild_configs SET logchannel=NULL WHERE id='{ctx.guild.id}'") - embed.add_field(name="Log channel", value=f"None") - if autokick: - cur.execute(f"UPDATE guild_configs SET autokick='0' WHERE id='{ctx.guild.id}'") - embed.add_field(name="Auto kick", value=f"Off") - if autocaptcha: - cur.execute(f"UPDATE guild_configs SET autoveri='no' WHERE id='{ctx.guild.id}'") - embed.add_field(name="Auto captcha", value=f"Off") - conn.commit() - await ctx.send(embed=embed) - - - -def setup(client): - client.add_cog(Settings(client)) \ No newline at end of file + self.DBENDPOINT = configData["DBENDPOINT"] \ No newline at end of file diff --git a/cogs/verification.py b/cogs/verification.py index 49a939a..9cd06d0 100644 --- a/cogs/verification.py +++ b/cogs/verification.py @@ -15,325 +15,4 @@ verifying = [] letters = ["a ", "b ", "c ", "d ", "e ", "g ", "k ", "m ", "n ", "o ", "p ", "q ", "s ", "u ", "v ", "w ", "x ", "y ", "z "] - -class BotVerifyLinks(nextcord.ui.View): - def __init__(self): - super().__init__() - self.add_item(nextcord.ui.Button(label="Invite me to your server", url="https://nomindustries.com/SV/invite")) - self.add_item(nextcord.ui.Button(label="Privacy Policy", url="https://nomindustries.com/SV/privacy")) - - -class VerifyButton(nextcord.ui.View): - def __init__(self, client): - self.client = client - super().__init__(timeout=None) - self.add_item(nextcord.ui.Button(label="Privacy Policy", url="https://nomindustries.com/SV/privacy")) - with open('dbconfig.json','r') as jsonfile: - configData = json.load(jsonfile) - self.DBUSER = configData["DBUSER"] - self.DBPASS = configData["DBPASS"] - self.DBNAME = configData["DBNAME"] - self.DBENDPOINT = configData["DBENDPOINT"] - - async def generate_captcha_string(self): - result_str = "" - allowed = False - f = open("./filter/filter.txt", "r") - lines = f.readlines() - while not allowed: - rangee = random.randint(4,5) - result_str = ''.join(random.choice(letters) for i in range(rangee)) - allowed = True - for line in lines: - similarity = SequenceMatcher(None, (result_str.lower().replace(" ", "")), (line.strip().lower().replace(" ", ""))) - if similarity.ratio() > 0.5: - allowed=False - - return result_str - - @nextcord.ui.button(label='Verify', style=nextcord.ButtonStyle.green, custom_id='verify_button_view:verify') - async def verify(self, button: nextcord.ui.Button, ctx: nextcord.Interaction): - global verifying - if ctx.user.id in verifying: - await ctx.send("You are already verifying. Please complete that verification to verify again", ephemeral=True) - return - else: - verifying.append(ctx.user.id) - await ctx.response.defer(with_message=True, ephemeral=True) - conn = pymysql.connect(host=self.DBENDPOINT, port=3306, user=self.DBUSER, password=self.DBPASS, db=self.DBNAME) - cur = conn.cursor() - cur.execute(f"SELECT * FROM guild_configs WHERE id='{ctx.guild.id}'") - data = cur.fetchall() - if data: - data = data[0] - if not data[1] == None: - if data[4] == "0": # if captcha type is none - try: - veryroleid = data[1] - veryrole = ctx.guild.get_role(int(veryroleid)) - unverifiedrole = None - if not data[2] == None: - unverifiedroleid = data[2] - unverifiedrole = ctx.guild.get_role(int(unverifiedroleid)) - logchannel = None - if not data[3] == None: - logchannelid = data[3] - logchannel = ctx.guild.get_channel(int(logchannelid)) - if (not veryrole in ctx.user.roles) or (unverifiedrole != None and unverifiedrole in ctx.user.roles): - embed =nextcord.Embed(title="Verification", description=f"{ctx.user.mention} has successfully verified", colour=0xadd8e6) - try: - await ctx.user.add_roles(veryrole) - embed.add_field(name="Roles added", value=f"{veryrole.mention}") - if not unverifiedrole == None and unverifiedrole in ctx.user.roles: - try: - await ctx.user.remove_roles(unverifiedrole) - embed.add_field(name="Roles removed", value=f"{unverifiedrole.mention}") - except: - await ctx.send("Failed to remove unverified role.", ephemeral=True) - embed.add_field(name="Roles removed", value=f"Failed to remove unverified role") - index = verifying.index(ctx.user.id) - del verifying[index] - if not logchannel == None: - try: - await logchannel.send(embed=embed) - except: - pass - return - except Exception as e: - print(e) - await ctx.send("Failed to add verified role", ephemeral=True) - embed.add_field(name="Roles added", value=f"Failed to give verified role") - index = verifying.index(ctx.user.id) - del verifying[index] - if not logchannel == None: - try: - await logchannel.send(embed=embed) - except: - pass - return - - await ctx.send(f"You have successfully verified", ephemeral=True, view=BotVerifyLinks()) - - if not logchannel == None: - try: - await logchannel.send(embed=embed) - except: - pass - - - else: - await ctx.send("You are already verified", ephemeral=True, view=BotVerifyLinks()) - - except Exception as e: - print(e) - await ctx.send("Server config not setup properly, contact the server admins to fix this.", ephemeral=True) - - - - - elif data[4] == "2": - try: - veryroleid = data[1] - veryrole = ctx.guild.get_role(int(veryroleid)) - unverifiedrole = None - if not data[2] == None: - unverifiedroleid = data[2] - unverifiedrole = ctx.guild.get_role(int(unverifiedroleid)) - logchannel = None - if not data[3] == None: - logchannelid = data[3] - logchannel = ctx.guild.get_channel(int(logchannelid)) - if (not veryrole in ctx.user.roles) or (unverifiedrole != None and unverifiedrole in ctx.user.roles): - result_str = await self.generate_captcha_string() - image = ImageCaptcha(width = 280, height = 90, fonts=["nom.ttf", "GolosText-Regular.ttf", "NotoSerif-Regular.ttf", "Poppins-Regular.ttf", "Roboto-Regular.ttf", "SourceSansPro-Regular.ttf"], font_sizes=[60]) - data = image.generate(result_str.lower()) - bytes = io.BytesIO() - image.write(result_str, bytes) - bytes.seek(0) - embed=nextcord.Embed(title=(f"Captcha"), description=(f"""You have 1 minute to answer the captcha correctly. - -The captcha will only be **under case** **letters**. -If you get it wrong just click the verify button again and retry"""), colour=0xadd8e6) - try: - answerview = AnswerButton(actual_answer=result_str) - msg = await ctx.send(embed=embed, file=nextcord.File(bytes, f"{ctx.user.id}-captcha.jpg"), ephemeral=True) - logembed=nextcord.Embed(title=f"Verification Started", description=f"{ctx.user.mention} started verification with the captcha attached. The answer to the captcha is `{str(result_str).replace(' ', '')}`", colour=0xadd8e6) - logembed.set_author(name=f"{ctx.user}", icon_url=ctx.user.avatar.url if ctx.user.avatar else None) - logembed.set_image(url=msg.attachments[0].url) - try: - logmsg = await logchannel.send(embed=logembed) - except Exception as e: - print(e) - pass - await msg.edit(view=answerview) - await answerview.wait() - result_str = result_str.replace(" ", "") - answer = answerview.answer - await msg.delete() - if answer == "Too Long ---------------": - await ctx.send("You ran out of time to answer the captcha, please try again.", ephemeral=True) - index = verifying.index(ctx.user.id) - del verifying[index] - logembed=nextcord.Embed(title=f"Verification Failed", description=f"{ctx.user.mention} failed verification with the captcha attached. The answer to the captcha is `{result_str}` but they didn't answer in time.", colour=0xff0000) - logembed.set_author(name=f"{ctx.user}", icon_url=ctx.user.avatar.url if ctx.user.avatar else None) - try: - await logmsg.reply(embed=logembed) - except: - pass - return - if answer.lower() == result_str: - embed =nextcord.Embed(title="Verification", description=f"{ctx.user.mention} has successfully verified", colour=0x00ff00) - try: - await ctx.user.add_roles(veryrole) - embed.add_field(name="Roles added", value=f"{veryrole.mention}") - if not unverifiedrole == None and unverifiedrole in ctx.user.roles: - try: - await ctx.user.remove_roles(unverifiedrole) - embed.add_field(name="Roles removed", value=f"{unverifiedrole.mention}") - except: - await ctx.send("Failed to remove unverified role.", ephemeral=True) - embed.add_field(name="Roles removed", value=f"Failed to remove unverified role") - index = verifying.index(ctx.user.id) - del verifying[index] - if not logchannel == None: - try: - await logmsg.reply(embed=embed) - except: - pass - return - except Exception as e: - print(e) - await ctx.send("Failed to add verified role", ephemeral=True) - embed.add_field(name="Roles added", value=f"Failed to give verified role") - index = verifying.index(ctx.user.id) - del verifying[index] - if not logchannel == None: - try: - await logmsg.reply(embed=embed) - except: - pass - return - await ctx.send(f"You have successfully verified", ephemeral=True, view=BotVerifyLinks()) - - if not logchannel == None: - try: - await logmsg.reply(embed=embed) - except: - pass - else: - await ctx.send(f"Incorrect answer, please try again. Correct answer was `{result_str}`", ephemeral=True) - logembed=nextcord.Embed(title=f"Verification Failed", description=f"{ctx.user.mention} failed verification with the captcha attached. The answer to the captcha is `{result_str}` but their answer was `{answer}`", colour=0xff0000) - logembed.set_author(name=f"{ctx.user}", icon_url=ctx.user.avatar.url if ctx.user.avatar else None) - try: - await logmsg.reply(embed=logembed) - except: - pass - - except Exception as e: - print(e) - await ctx.send("Error sending captcha", ephemeral=True) - try: - os.remove(f"{ctx.user.id}-captcha.jpg") - except: - pass - else: - await ctx.send("You are already verified", ephemeral=True, view=BotVerifyLinks()) - except Exception as e: - print(e) - await ctx.send("Server config not setup properly, contact the server admins to fix this.", ephemeral=True) - - try: - index = verifying.index(ctx.user.id) - del verifying[index] - - except: - pass - - else: - await ctx.send("Server config not setup properly, contact the server admins to fix this.") - index = verifying.index(ctx.user.id) - del verifying[index] - - - -class VerifyMessage(commands.Cog): - def __init__(self, client): - self.client = client - with open('dbconfig.json','r') as jsonfile: - configData = json.load(jsonfile) - self.DBUSER = configData["DBUSER"] - self.DBPASS = configData["DBPASS"] - self.DBNAME = configData["DBNAME"] - self.DBENDPOINT = configData["DBENDPOINT"] - - @nextcord.slash_command(name="verifymessage", description="Send the verification message to a channel") - async def verifymessage(self, - ctx: Interaction, - channel: GuildChannel = SlashOption( - name="channel", - description="Channel to send verification message to", - required=True, - channel_types=[nextcord.ChannelType.text] - ), - custom: bool = SlashOption( - name="custom", - description="Choose to send a custom embed", - required=False - )): - client = self.client - if ctx.user.guild_permissions.administrator == True: - if custom: - options = EmbedCreationForm() - await ctx.response.send_modal(modal=options) - await options.wait() - embed = nextcord.Embed(title=options.embedtitle, description=options.embeddescription, colour=0xadd8e6) - else: - embed=nextcord.Embed(title=f"Verification", description=f"To verify in the server press the button below and follow the instructions from there.", colour=0xadd8e6) - try: - await channel.send(embed=embed, view=VerifyButton(self.client)) - await ctx.send(f"Message sent to {channel.mention}") - except Exception as e: - print(e) - try: - await ctx.send("Error sending message. Make sure I have permission to send messages and embed links in the selected channel.") - except: - pass - else: - await ctx.send("You require `administrator` permissions to perform this command", ephemeral=True) - - - @commands.Cog.listener() - async def on_member_join(self, member): - global verifying - conn = pymysql.connect(host=self.DBENDPOINT, port=3306, user=self.DBUSER, password=self.DBPASS, db=self.DBNAME) - cur = conn.cursor() - cur.execute(f"SELECT * FROM guild_configs WHERE id='{member.guild.id}'") - data = cur.fetchall() - if data: - data = data[0] - if not data[1] == None: - now = datetime.datetime.now(datetime.timezone.utc) - secs = (now - member.created_at).days - kicked = False - if data[5] == "0": - pass - else: - days = int(data[5]) - if secs < days: - try: - await member.send(f"You were kicked from **{member.guild.name}** due to your account age being below their limit of **{days} days**") - except: - pass - await member.kick(reason=f"Account age below server limit of {days} days") - index = verifying.index(member.id) - del verifying[index] - if not data[2] == None: - role = member.guild.get_role(int(data[2])) - await member.add_roles(role) - - - - -def setup(client): - client.add_cog(VerifyMessage(client)) From 396e2769895baa03ec9e33b14638277e8dfe008a Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Mon, 28 Aug 2023 18:43:34 +0100 Subject: [PATCH 02/35] Complete rewrite started --- .../GolosText-Regular.ttf | Bin .../NotoSerif-Regular.ttf | Bin .../Poppins-Regular.ttf | Bin .../Roboto-Regular.ttf | Bin .../SourceSansPro-Regular.ttf | Bin nom.ttf => assets/nom.ttf | Bin cogs/extra.py | 48 --------------- cogs/guild_join.py | 33 ---------- cogs/help.py | 45 +------------- cogs/settings.py | 18 ------ cogs/verification.py | 18 ------ utils/constants.py | 0 utils/utils.py | 0 views/answer_view.py | 58 ------------------ views/embed_manager_views.py | 33 ---------- 15 files changed, 1 insertion(+), 252 deletions(-) rename GolosText-Regular.ttf => assets/GolosText-Regular.ttf (100%) rename NotoSerif-Regular.ttf => assets/NotoSerif-Regular.ttf (100%) rename Poppins-Regular.ttf => assets/Poppins-Regular.ttf (100%) rename Roboto-Regular.ttf => assets/Roboto-Regular.ttf (100%) rename SourceSansPro-Regular.ttf => assets/SourceSansPro-Regular.ttf (100%) rename nom.ttf => assets/nom.ttf (100%) delete mode 100644 cogs/extra.py delete mode 100644 cogs/guild_join.py delete mode 100644 cogs/settings.py delete mode 100644 cogs/verification.py create mode 100644 utils/constants.py create mode 100644 utils/utils.py delete mode 100644 views/answer_view.py delete mode 100644 views/embed_manager_views.py diff --git a/GolosText-Regular.ttf b/assets/GolosText-Regular.ttf similarity index 100% rename from GolosText-Regular.ttf rename to assets/GolosText-Regular.ttf diff --git a/NotoSerif-Regular.ttf b/assets/NotoSerif-Regular.ttf similarity index 100% rename from NotoSerif-Regular.ttf rename to assets/NotoSerif-Regular.ttf diff --git a/Poppins-Regular.ttf b/assets/Poppins-Regular.ttf similarity index 100% rename from Poppins-Regular.ttf rename to assets/Poppins-Regular.ttf diff --git a/Roboto-Regular.ttf b/assets/Roboto-Regular.ttf similarity index 100% rename from Roboto-Regular.ttf rename to assets/Roboto-Regular.ttf diff --git a/SourceSansPro-Regular.ttf b/assets/SourceSansPro-Regular.ttf similarity index 100% rename from SourceSansPro-Regular.ttf rename to assets/SourceSansPro-Regular.ttf diff --git a/nom.ttf b/assets/nom.ttf similarity index 100% rename from nom.ttf rename to assets/nom.ttf diff --git a/cogs/extra.py b/cogs/extra.py deleted file mode 100644 index 18e145b..0000000 --- a/cogs/extra.py +++ /dev/null @@ -1,48 +0,0 @@ -import nextcord -from nextcord.ext import commands, tasks -from nextcord import Interaction, SlashOption -import time, asyncio - -class BotInfoLinkButton(nextcord.ui.View): - def __init__(self): - super().__init__() - self.add_item(nextcord.ui.Button(label="Support Server", url="https://nomindustries.com/SV/support")) - self.add_item(nextcord.ui.Button(label="Invite", url="https://nomindustries.com/SV/invite")) - self.add_item(nextcord.ui.Button(label="Vote", url="https://nomindustries.com/SV/vote")) - self.add_item(nextcord.ui.Button(label="Privacy Policy", url="https://nomindustries.com/SV/privacy")) - -class PrivacyPolicyButton(nextcord.ui.View): - def __init__(self): - super().__init__() - self.add_item(nextcord.ui.Button(label="Privacy Policy", url="https://nomindustries.com/SV/privacy")) - -class Extras(commands.Cog): - - def __init__(self, client): - self.client = client - - @nextcord.slash_command(name="botinfo", description="Shows the bot information") - async def _botinfo( - self, - ctx: Interaction, - ): - await ctx.response.defer() - before = time.monotonic() - msg = await ctx.send("Loading bot information") - ping = (time.monotonic() - before) * 1000 - embed = nextcord.Embed(title="Simple Verification Bot Information", description=f"""Ping: {round(ping)}ms -Server count: {str(len(self.client.guilds))} -Support Server: [Need some support?](https://nomindustries.com/SV/invite) -Invite: [Invite Me](https://nomindustries.com/SV/invite) -Vote: [Vote for me](https://nomindustries.com/SV/vote) -Privacy; [Privacy Policy](https://nomindustries.com/SV/privacy)""", colour=0xadd8e6) - await msg.edit(content = " ", embed=embed, view=BotInfoLinkButton()) - - @nextcord.slash_command(name="privacy", description=f"Get the link to our privacy policy") - async def privacy_policy(self, ctx:Interaction): - embed = nextcord.Embed(title="Privacy Policy", description="You can find our privacy policy here: \n\nhttps://nomindustries.com/sv/privacy", colour=0xadd8e6) - await ctx.send(embed=embed, view=PrivacyPolicyButton()) - - -def setup(client): - client.add_cog(Extras(client)) \ No newline at end of file diff --git a/cogs/guild_join.py b/cogs/guild_join.py deleted file mode 100644 index 1366596..0000000 --- a/cogs/guild_join.py +++ /dev/null @@ -1,33 +0,0 @@ -import nextcord -from nextcord.ext import commands, tasks -from nextcord import Interaction, SlashOption -from nextcord.abc import GuildChannel -import pymysql, json - -class GuildJoin(commands.Cog): - def __init__(self, client): - self.client = client - - @commands.Cog.listener() - async def on_guild_join(self, guild): - supguild = self.client.get_guild(1111387758028652657) - channel = supguild.get_channel(1111394323720847500) - embed = nextcord.Embed(title=f"Joined Guild", colour=0x03C04A) - embed.add_field(name=f"Guild Name (ID)", value=f"{guild.name} ({guild.id})") - embed.add_field(name=f"Guild Owner", value=f"{guild.owner} (<@{guild.owner.id}>)") - embed.add_field(name=f"Guild Members", value=f"{len(guild.members)}") - await channel.send(embed=embed) - - @commands.Cog.listener() - async def on_guild_remove(self, guild): - supguild = self.client.get_guild(1111387758028652657) - channel = supguild.get_channel(1111394323720847500) - embed = nextcord.Embed(title=f"Left Guild", colour=0x900D09) - embed.add_field(name=f"Guild Name (ID)", value=f"{guild.name} ({guild.id})") - embed.add_field(name=f"Guild Owner", value=f"{guild.owner} (<@{guild.owner.id}>)") - embed.add_field(name=f"Guild Members", value=f"{len(guild.members)}") - await channel.send(embed=embed) - - -def setup(client): - client.add_cog(cog=GuildJoin(client=client)) \ No newline at end of file diff --git a/cogs/help.py b/cogs/help.py index f2e57e0..0cbc8ea 100644 --- a/cogs/help.py +++ b/cogs/help.py @@ -1,44 +1 @@ -import nextcord -from nextcord.ext import commands, tasks -from nextcord import Interaction, SlashOption -import json - - -class HelpButtons(nextcord.ui.View): - def __init__(self): - super().__init__() - self.add_item(nextcord.ui.Button(label="Support Server", url="https://discord.gg/aGzvXvTkP8")) - self.add_item(nextcord.ui.Button(label="Invite", url="https://discord.com/api/oauth2/authorize?client_id=981835181243658260&permissions=8&scope=bot%20applications.commands")) - self.add_item(nextcord.ui.Button(label="Vote", url="https://top.gg/bot/828584622156939274/vote")) - - -class Help(commands.Cog): - - def __init__(self, client): - self.client = client - - @nextcord.slash_command(name="help", description="Help command") - async def help(self, - ctx: Interaction): - await ctx.response.defer() - embed = nextcord.Embed(title=(f"Help"), description=(f"""Below is a list of all commands you will need:"""), colour=0xadd8e6) - embed.add_field(name=f"/config enable", value=f"""Explanation: Enable any settings you want to -Requires: Administrator -Usage: ``/config enable``""") - embed.add_field(name=f"/config disable", value=f"""Explanation: Disable any settings you want to -Requires: Administrator -Usage: ``/config disable``""") - embed.add_field(name=f"/verifymessage", value=f"""Explanation: Send a verification message to a channel -Requires: Administrator -Usage: ``/verifymessage <#channel> [Custom (True/False)]``""") - embed.add_field(name=f"/botinfo", value=f"""Explanation: Shows general bot info -Requires: None -Usage: ``/botinfo``""") - embed.add_field(name="\u200B", value=f"[Support Server](https://discord.gg/aGzvXvTkP8) | [Invite Me](https://discord.com/api/oauth2/authorize?client_id=981835181243658260&permissions=8&scope=bot%20applications.commands) | [Vote](https://top.gg/bot/828584622156939274/vote)", inline=False) - - - await ctx.send(embed=embed, view=HelpButtons()) - - -def setup(client): - client.add_cog(Help(client)) \ No newline at end of file +import nextcord \ No newline at end of file diff --git a/cogs/settings.py b/cogs/settings.py deleted file mode 100644 index a6331e0..0000000 --- a/cogs/settings.py +++ /dev/null @@ -1,18 +0,0 @@ -import nextcord -from nextcord.ext import commands, tasks -from nextcord import Interaction, SlashOption -from nextcord.abc import GuildChannel -import pymysql, json - - - -class Settings(commands.Cog): - - def __init__(self, client): - self.client = client - with open('dbconfig.json','r') as jsonfile: - configData = json.load(jsonfile) - self.DBUSER = configData["DBUSER"] - self.DBPASS = configData["DBPASS"] - self.DBNAME = configData["DBNAME"] - self.DBENDPOINT = configData["DBENDPOINT"] \ No newline at end of file diff --git a/cogs/verification.py b/cogs/verification.py deleted file mode 100644 index 9cd06d0..0000000 --- a/cogs/verification.py +++ /dev/null @@ -1,18 +0,0 @@ -import nextcord -from nextcord.ext import commands, tasks -from nextcord import Interaction, SlashOption -from nextcord.abc import GuildChannel -import json, pymysql, asyncio, random, string, os, sys -from captcha.audio import AudioCaptcha -from captcha.image import ImageCaptcha -from views.answer_view import AnswerModal,AnswerButton -from views.embed_manager_views import EmbedCreationForm -import time -import io -import math -import datetime -from difflib import SequenceMatcher - -verifying = [] -letters = ["a ", "b ", "c ", "d ", "e ", "g ", "k ", "m ", "n ", "o ", "p ", "q ", "s ", "u ", "v ", "w ", "x ", "y ", "z "] - diff --git a/utils/constants.py b/utils/constants.py new file mode 100644 index 0000000..e69de29 diff --git a/utils/utils.py b/utils/utils.py new file mode 100644 index 0000000..e69de29 diff --git a/views/answer_view.py b/views/answer_view.py deleted file mode 100644 index 09b0bfa..0000000 --- a/views/answer_view.py +++ /dev/null @@ -1,58 +0,0 @@ -import nextcord, string, io, random, os -from gtts import gTTS -from captcha.audio import AudioCaptcha - - - - - -class AnswerButton(nextcord.ui.View): - def __init__(self, actual_answer): - super().__init__(timeout=60) - self.add_item(nextcord.ui.Button(label="Invite me to your server", url="https://nomindustries.com/SV/invite")) - self.add_item(nextcord.ui.Button(label="Privacy Policy", url="https://nomindustries.com/SV/privacy")) - self.actual_answer = actual_answer - self.answer = "Too Long ---------------" - self.audio_sent = False - - @nextcord.ui.button(label = "Answer", style = nextcord.ButtonStyle.green, disabled=False) - async def answer_ready(self, button: nextcord.ui.Button, interaction: nextcord.Interaction): - answerinput = AnswerModal() - await interaction.response.send_modal(answerinput) - await answerinput.wait() - self.answer = answerinput.answer - self.stop() - - @nextcord.ui.button(label="Audio", style = nextcord.ButtonStyle.blurple, disabled=False) - async def audio_captcha(self, button: nextcord.ui.Button, interaction: nextcord.Interaction): - if not self.audio_sent: - answer = " ".join(letter for letter in self.actual_answer.split()) - tts = gTTS(answer) - tts.save(f"{interaction.user.id}-audio.mp3") - msg = await interaction.send(file=nextcord.File(f"{interaction.user.id}-audio.mp3", f"{interaction.user}-audio.mp3"), ephemeral=True) - os.remove(f"{interaction.user.id}-audio.mp3") - self.audio_sent=True - else: - await interaction.send("You have already requested an audio captcha. Please use that to verify.", ephemeral=True) - - - async def on_timeout(self): - self.answer = "Too Long ---------------" - self.stop() - -class AnswerModal(nextcord.ui.Modal): - def __init__(self): - super().__init__(title="What is your answer?") - self.answer = nextcord.ui.TextInput( - label = "What does the captcha say?", - placeholder = "Example: qdvae", - style=nextcord.TextInputStyle.short, - min_length=1, - max_length=10, - required=True - ) - self.add_item(self.answer) - - async def callback(self, interaction: nextcord.Interaction): - self.answer = self.answer.value - self.stop() \ No newline at end of file diff --git a/views/embed_manager_views.py b/views/embed_manager_views.py deleted file mode 100644 index c81dcf5..0000000 --- a/views/embed_manager_views.py +++ /dev/null @@ -1,33 +0,0 @@ -from asyncio import tasks -import nextcord, pymysql -from nextcord.ext import commands - - -class EmbedCreationForm(nextcord.ui.Modal): - def __init__(self): - super().__init__(title="Embed Create", timeout=None) - self.embedtitle = nextcord.ui.TextInput( - label = "What do you want the title to be?", - placeholder = "Tip: Up to 256 characters!", - style=nextcord.TextInputStyle.short, - min_length=1, - max_length=256, - required=True - ) - self.add_item(self.embedtitle) - - self.embeddescription = nextcord.ui.TextInput( - label = "What do you want the description to be?", - placeholder = "Tip: To mention channels do <#channelid> (eg. <#1028741186380365865>)", - style=nextcord.TextInputStyle.paragraph, - min_length=1, - max_length=4000, - required=True - ) - self.add_item(self.embeddescription) - - - async def callback(self, interaction: nextcord.Interaction): - self.embeddescription = self.embeddescription.value - self.embedtitle = self.embedtitle.value - self.stop() \ No newline at end of file From 675657b82fc3944e082a14cbbdb69acb279a071f Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Mon, 28 Aug 2023 18:48:36 +0100 Subject: [PATCH 03/35] Initial Setup --- .gitignore | 1 + utils/constants.py | 5 +++++ utils/dbconstants.py | 4 ++++ 3 files changed, 10 insertions(+) create mode 100644 utils/dbconstants.py diff --git a/.gitignore b/.gitignore index 6eb4b92..d90bc56 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ dbconfig.json +./dbconstants.py __pycache__/ \ No newline at end of file diff --git a/utils/constants.py b/utils/constants.py index e69de29..4e30418 100644 --- a/utils/constants.py +++ b/utils/constants.py @@ -0,0 +1,5 @@ + + +# SQL DB Server Info + +from dbconstants import DBUSER, DBPASS, DBNAME, DBENDPOINT diff --git a/utils/dbconstants.py b/utils/dbconstants.py new file mode 100644 index 0000000..4ae438d --- /dev/null +++ b/utils/dbconstants.py @@ -0,0 +1,4 @@ +DBUSER = "test" +DBPASS = "test" +DBNAME = "test" +DBENDPOINT = "test" \ No newline at end of file From 5531f804098d3f0b71e1a7ae6375881adf241ff6 Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Mon, 28 Aug 2023 18:49:14 +0100 Subject: [PATCH 04/35] .. --- .gitignore | 2 +- utils/dbconstants.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index d90bc56..db4f014 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ dbconfig.json -./dbconstants.py +dbconstants.py __pycache__/ \ No newline at end of file diff --git a/utils/dbconstants.py b/utils/dbconstants.py index 4ae438d..8570bfb 100644 --- a/utils/dbconstants.py +++ b/utils/dbconstants.py @@ -1,4 +1,4 @@ -DBUSER = "test" -DBPASS = "test" +DBUSER = "testee" +DBPASS = "testee" DBNAME = "test" DBENDPOINT = "test" \ No newline at end of file From f64324b03fe5e8b086e840366493393ec47c5cca Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Mon, 28 Aug 2023 18:49:45 +0100 Subject: [PATCH 05/35] ... --- .gitignore | 2 +- utils/dbconstants.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index db4f014..a1db368 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ dbconfig.json -dbconstants.py +utils/dbconstants.py __pycache__/ \ No newline at end of file diff --git a/utils/dbconstants.py b/utils/dbconstants.py index 8570bfb..55b8964 100644 --- a/utils/dbconstants.py +++ b/utils/dbconstants.py @@ -1,4 +1,4 @@ DBUSER = "testee" DBPASS = "testee" -DBNAME = "test" +DBNAME = "testee" DBENDPOINT = "test" \ No newline at end of file From b0ffee952e6b980ca8d63e97acb512035c7c30b9 Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Mon, 28 Aug 2023 18:51:16 +0100 Subject: [PATCH 06/35] .... --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index a1db368..d3b7104 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ dbconfig.json -utils/dbconstants.py -__pycache__/ \ No newline at end of file +__pycache__/ +*dbconstants.py* \ No newline at end of file From 6b42ce719521214fa220106aa99322fdb50e6b96 Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Mon, 28 Aug 2023 18:51:40 +0100 Subject: [PATCH 07/35] Update dbconstants.py --- utils/dbconstants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/dbconstants.py b/utils/dbconstants.py index 55b8964..9e19c5f 100644 --- a/utils/dbconstants.py +++ b/utils/dbconstants.py @@ -1,4 +1,4 @@ DBUSER = "testee" DBPASS = "testee" DBNAME = "testee" -DBENDPOINT = "test" \ No newline at end of file +DBENDPOINT = "testee" \ No newline at end of file From 3354a61b081a68d1c20c418795feb8682f52ff75 Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Mon, 28 Aug 2023 18:53:11 +0100 Subject: [PATCH 08/35] Update .gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d3b7104..b6b0dda 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ dbconfig.json __pycache__/ -*dbconstants.py* \ No newline at end of file +dbconstants.py \ No newline at end of file From f1166b8b2d5047ba9fd0b269708538fc41f91ddc Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Mon, 28 Aug 2023 18:53:26 +0100 Subject: [PATCH 09/35] Update dbconstants.py --- utils/dbconstants.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/utils/dbconstants.py b/utils/dbconstants.py index 9e19c5f..32a9ec3 100644 --- a/utils/dbconstants.py +++ b/utils/dbconstants.py @@ -1,4 +1,6 @@ DBUSER = "testee" DBPASS = "testee" DBNAME = "testee" -DBENDPOINT = "testee" \ No newline at end of file +DBENDPOINT = "testee" + +BLA = "bla" \ No newline at end of file From 188c17af54c4e3ead0976122f7746139ca86e4c1 Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Mon, 28 Aug 2023 18:54:52 +0100 Subject: [PATCH 10/35] Update .gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b6b0dda..9f30fec 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ dbconfig.json __pycache__/ -dbconstants.py \ No newline at end of file +**/dbconstants.py \ No newline at end of file From 7fce5139cdb0989a460ef3a5f3f9b6ea7f07e724 Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Mon, 28 Aug 2023 18:55:03 +0100 Subject: [PATCH 11/35] Update dbconstants.py --- utils/dbconstants.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/dbconstants.py b/utils/dbconstants.py index 32a9ec3..02fbfd7 100644 --- a/utils/dbconstants.py +++ b/utils/dbconstants.py @@ -3,4 +3,5 @@ DBNAME = "testee" DBENDPOINT = "testee" -BLA = "bla" \ No newline at end of file +BLA = "bla" +HA = "ha" \ No newline at end of file From 53df2e105d6f6b10994e35ebf209e6759bf03110 Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Mon, 28 Aug 2023 18:57:31 +0100 Subject: [PATCH 12/35] ....... --- .gitignore | 2 +- main.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 9f30fec..c34cf8d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ dbconfig.json __pycache__/ -**/dbconstants.py \ No newline at end of file +/utils/dbconstants.py \ No newline at end of file diff --git a/main.py b/main.py index 5bbcc4a..31843ef 100644 --- a/main.py +++ b/main.py @@ -1,7 +1,6 @@ import nextcord import json import os -from cogs.verification import VerifyButton from nextcord.ext import commands , tasks import requests os.chdir("./") From b63b8ce35d1ab825d1ade0deadb0454eb637885f Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Mon, 28 Aug 2023 18:58:23 +0100 Subject: [PATCH 13/35] ojio --- .gitignore | 3 ++- main.py | 1 - utils/dbconstants.py | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index c34cf8d..bacf1ec 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ dbconfig.json __pycache__/ -/utils/dbconstants.py \ No newline at end of file +/utils/dbconstants.py +utils/dbconstants.py diff --git a/main.py b/main.py index 31843ef..8092da9 100644 --- a/main.py +++ b/main.py @@ -15,7 +15,6 @@ def __init__(self, *args, **kwargs): async def on_ready(self): if not self.persistent_views_added: - self.add_view(VerifyButton(client)) self.persistent_views_added = True print(f"Logged in as {client.user}!") diff --git a/utils/dbconstants.py b/utils/dbconstants.py index 02fbfd7..469aacd 100644 --- a/utils/dbconstants.py +++ b/utils/dbconstants.py @@ -4,4 +4,6 @@ DBENDPOINT = "testee" BLA = "bla" -HA = "ha" \ No newline at end of file +HA = "ha" + +ATR = "atr" \ No newline at end of file From 584e20918716c8025dec2685a4ae027521e38b3c Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Mon, 28 Aug 2023 19:09:16 +0100 Subject: [PATCH 14/35] Update dbconstants.py --- utils/dbconstants.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/utils/dbconstants.py b/utils/dbconstants.py index 469aacd..9e19c5f 100644 --- a/utils/dbconstants.py +++ b/utils/dbconstants.py @@ -1,9 +1,4 @@ DBUSER = "testee" DBPASS = "testee" DBNAME = "testee" -DBENDPOINT = "testee" - -BLA = "bla" -HA = "ha" - -ATR = "atr" \ No newline at end of file +DBENDPOINT = "testee" \ No newline at end of file From d2838cf95dbe01480a513b3e8b528ff2e15ce407 Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Mon, 28 Aug 2023 21:04:14 +0100 Subject: [PATCH 15/35] Delete dbconstants.py --- utils/dbconstants.py | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 utils/dbconstants.py diff --git a/utils/dbconstants.py b/utils/dbconstants.py deleted file mode 100644 index 9e19c5f..0000000 --- a/utils/dbconstants.py +++ /dev/null @@ -1,4 +0,0 @@ -DBUSER = "testee" -DBPASS = "testee" -DBNAME = "testee" -DBENDPOINT = "testee" \ No newline at end of file From 8119a0f7daa3145e1fe27870444e3097deff8b78 Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Mon, 28 Aug 2023 22:44:28 +0100 Subject: [PATCH 16/35] Work on rewrite - Started premium system - Added `/botinfo` - Added `/privacy` - Added `/help` - Started on dashboard - Setup `utils.py` - Setup `constants.py` --- cogs/dashboard.py | 26 +++++++++++++++++++++ cogs/extras.py | 35 ++++++++++++++++++++++++++++ cogs/help.py | 33 ++++++++++++++++++++++++++- cogs/premium.py | 26 +++++++++++++++++++++ main.py | 4 +++- utils/__init__.py | 2 ++ utils/constants.py | 17 ++++++++++++-- utils/utils.py | 49 ++++++++++++++++++++++++++++++++++++++++ views/__init__.py | 3 +++ views/dashboard_views.py | 33 +++++++++++++++++++++++++++ views/link_button.py | 17 ++++++++++++++ views/role_select.py | 18 +++++++++++++++ 12 files changed, 259 insertions(+), 4 deletions(-) create mode 100644 cogs/dashboard.py create mode 100644 cogs/extras.py create mode 100644 cogs/premium.py create mode 100644 utils/__init__.py create mode 100644 views/__init__.py create mode 100644 views/dashboard_views.py create mode 100644 views/link_button.py create mode 100644 views/role_select.py diff --git a/cogs/dashboard.py b/cogs/dashboard.py new file mode 100644 index 0000000..5e11d6a --- /dev/null +++ b/cogs/dashboard.py @@ -0,0 +1,26 @@ +import nextcord +from nextcord.ext import commands +from nextcord import Interaction +from utils import check_premium, DBENDPOINT, DBNAME, DBPASS, DBUSER +from views import DashboardButtons +import pymysql + +class Dashboard(commands.Cog): + def __init__(self, client: commands.Bot): + self.client = client + + @nextcord.slash_command(name=f"dashboard", description=f"Configure the bot on the in-discord dashboard") + async def dashboard(self, interaction: Interaction): + conn = pymysql.connect(host=self.DBENDPOINT, port=3306, user=self.DBUSER, password=self.DBPASS, db=self.DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + data = cur.fetchall() + if not data: + cur.execute(f"INSERT INTO guild_configs (id) VALUES ('{interaction.guild.id}')") + conn.commit() + embed = nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role: {('<@' + data[0][1] + '>') if data[0][1] else 'Not Set'}""") + view = DashboardButtons(premium=check_premium(guild = True, user = False, type_id=interaction.guild.id)) + await interaction.send(embed=embed, view=view) + +def setup(client: commands.Bot): + client.add_cog(Dashboard(client)) \ No newline at end of file diff --git a/cogs/extras.py b/cogs/extras.py new file mode 100644 index 0000000..1563263 --- /dev/null +++ b/cogs/extras.py @@ -0,0 +1,35 @@ +import nextcord +from nextcord.ext import commands +import time +from nextcord import Interaction +from views import BotInfoLinkButton, PrivacyPolicyButton +from utils.constants import COLOUR_MAIN, VOTELINK, INVITELINK, DISCORDLINK, PRIVACYLINK + +class Extras(commands.Cog): + def __init__(self, client: commands.Bot): + self.client = client + + @nextcord.slash_command(name="botinfo", description="Information about the bot") + async def botinfo(self, interaction: Interaction): + await interaction.response.defer() + before = time.monotonic() + msg = await interaction.send("Loading bot information") + ping = (time.monotonic() - before) * 1000 + users = 0 + for guild in self.client.guilds: + users+=guild.member_count + embed = nextcord.Embed(title="Bot Infomation", description=f"""Ping: {round(ping)}ms +Server count: {str(len(self.client.guilds))} +User count: {users:,} +Support Server: [Need some support?]({DISCORDLINK}) +Invite: [Invite Me]({INVITELINK}) +Vote: [Vote for me]({VOTELINK}) +Privacy: [Privacy Policy]({PRIVACYLINK})""", colour=COLOUR_MAIN) + await msg.edit(content = " ", embed=embed, view=BotInfoLinkButton()) + + @nextcord.slash_command(name=f"privacy", description=f"Get the link to our privacy policy") + async def privacy(self, interaction:Interaction): + await interaction.send(content="", view=PrivacyPolicyButton()) + +def setup(client: commands.Bot): + client.add_cog(Extras(client)) \ No newline at end of file diff --git a/cogs/help.py b/cogs/help.py index 0cbc8ea..0cdf90c 100644 --- a/cogs/help.py +++ b/cogs/help.py @@ -1 +1,32 @@ -import nextcord \ No newline at end of file +import nextcord +from nextcord.ext import commands +from nextcord import Interaction +from utils.constants import COLOUR_MAIN, VOTELINK, INVITELINK, DISCORDLINK, PRIVACYLINK +from views import BotInfoLinkButton + +class Help(commands.Cog): + def __init__(self, client: commands.Bot): + self.client = client + + @nextcord.slash_command(name=f"help", description=f"Help command") + async def help(self, interaction: Interaction): + await interaction.response.defer() + embed = nextcord.Embed(title=(f"Help"), description=(f"""Below is a list of all commands you will need:"""), colour=COLOUR_MAIN) + embed.add_field(name=f"/config enable", value=f"""Explanation: Enable any settings you want to +Requires: Administrator +Usage: ``/config enable``""") + embed.add_field(name=f"/config disable", value=f"""Explanation: Disable any settings you want to +Requires: Administrator +Usage: ``/config disable``""") + embed.add_field(name=f"/verifymessage", value=f"""Explanation: Send a verification message to a channel +Requires: Administrator +Usage: ``/verifymessage <#channel> [Custom (True/False)]``""") + embed.add_field(name=f"/botinfo", value=f"""Explanation: Shows general bot info +Requires: None +Usage: ``/botinfo``""") + embed.add_field(name="\u200B", value=f"[Support Server]({DISCORDLINK}) | [Invite Me]({INVITELINK}) | [Vote]({VOTELINK}) | [Privacy Policy]({PRIVACYLINK})", inline=False) + + await interaction.send(embed=embed, view=BotInfoLinkButton()) + +def setup(client: commands.Bot): + client.add_cog(Help(client)) \ No newline at end of file diff --git a/cogs/premium.py b/cogs/premium.py new file mode 100644 index 0000000..50a57ec --- /dev/null +++ b/cogs/premium.py @@ -0,0 +1,26 @@ +import nextcord +from nextcord.ext import commands +from nextcord import Interaction, SlashOption +from utils import check_premium, create_error_embed, PREMIUMLINK + +class Premium(commands.Cog): + def __init__(self, client: commands.Bot): + self.client = client + + @nextcord.slash_commands(name=f"manage-premium", description=f"Manage your premium membership") + async def manage_premium(self, interaction: Interaction): + pass + + @manage_premium(name=f"add-server", description=f"Add a server to your premium subscription") + async def manage_premium_add_server(self, interaction: Interaction, + guildid: str = SlashOption( + name=f"guild", + description=f"The ID of the guild you want to add to your premium subscription. Use /debug in your server to get the server ID", + required = True + )): + await interaction.response.defer() + if not check_premium(interaction.user.id): + await interaction.send(embed=create_error_embed(title=f"No premium subscription", description=f"You are not currently subscribed to any of our premium subscriptions. To purchase premium please follow [this link]({PREMIUMLINK})\n\n\nPlease Note: If you recently subscribed to premium it may take up to 30 minutes to register your subscription. If you are still unable to use this command in 30 minutes, please create a ticket in ")) + +def setup(client: commands.Bot): + client.add_cog(Premium(client)) \ No newline at end of file diff --git a/main.py b/main.py index 8092da9..8f9163f 100644 --- a/main.py +++ b/main.py @@ -3,6 +3,8 @@ import os from nextcord.ext import commands , tasks import requests +from utils.constants import TOKEN + os.chdir("./") @@ -52,4 +54,4 @@ async def on_ready(self): -client.run("ODcxMzgwNzI0NzYxMTI0OTE0.GrrFch.XwoIEbolc2cqJh4IfqER4xlDOGoExX2wFIZANY") +client.run(TOKEN) diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..bef68e4 --- /dev/null +++ b/utils/__init__.py @@ -0,0 +1,2 @@ +from .utils import * +from .constants import * \ No newline at end of file diff --git a/utils/constants.py b/utils/constants.py index 4e30418..8760636 100644 --- a/utils/constants.py +++ b/utils/constants.py @@ -1,5 +1,18 @@ - +from typing import Text, Dict # SQL DB Server Info -from dbconstants import DBUSER, DBPASS, DBNAME, DBENDPOINT +from utils.dbconstants import DBUSER, DBPASS, DBNAME, DBENDPOINT, TOKEN + +VOTELINK: Text = "https://nomindustries.com/sv/vote" +INVITELINK: Text = "https://discord.com/api/oauth2/authorize?client_id=981835181243658260&permissions=8&scope=bot%20applications.commands" +DISCORDLINK: Text = "https://nomindustries.com/sv/support" +PRIVACYLINK: Text = "https://nomindustries.com/sv/privacy" +PREMIUMLINK: Text = "https://www.buymeacoffee.com/simpleverification/membership" + +COLOUR_MAIN = 0xadd8e6 +COLOUR_GOOD = 0x03C04A +COLOUR_NEUTRAL = 0xFCAE1E +COLOUR_BAD = 0x900D09 + + diff --git a/utils/utils.py b/utils/utils.py index e69de29..71e4c41 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -0,0 +1,49 @@ +from .constants import COLOUR_BAD, COLOUR_GOOD, COLOUR_NEUTRAL, DBENDPOINT, DBNAME, DBPASS, DBUSER +import nextcord, math, random, pymysql +from string import ascii_letters, digits + +def create_success_embed(title: str = "\u200b", description: str = "\u200b"): + embed = nextcord.Embed(title=title, description=description, color=COLOUR_GOOD) + embed.set_thumbnail(url="https://media.tenor.com/AWKzZ19awFYAAAAi/checkmark-transparent.gif") + return embed + +def create_warning_embed(title: str = "\u200b", description: str = "\u200b"): + embed = nextcord.Embed(title=title, description=description, color=COLOUR_NEUTRAL) + embed.set_thumbnail(url="https://c.tenor.com/26pNa498OS0AAAAi/warning-joypixels.gif") + return embed + +def create_error_embed(title: str = "\u200b", description: str = "\u200b"): + embed = nextcord.Embed(title=title, description=description, color=COLOUR_BAD) + embed.set_thumbnail(url="https://media.tenor.com/Gbp8h-dqDHkAAAAi/error.gif") + return embed + +def check_premium(self, guild: bool, user: bool, type_id: str): + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + if guild: + cur.execute(f"SELECT * FROM sv_premium_guilds WHERE id='{type_id}'") + data = cur.fetchall() + return True if data else False + elif user: + cur.execute(f"SELECT * FROM sv_premium_users WHERE id='{type_id}'") + data = cur.fetchall() + return True if data else False + return None + + +def totalxp_to_level(total_xp): + level = (-1 + math.sqrt(1 + 4*(total_xp // 50))) // 2 + threshold = (level+1)*100 + xp=total_xp - 50*(level**2 + level) + return round(level), round(threshold), round(xp) + +def level_to_totalxp(level): + return 100*(level*(level+1))/2 + +def generate_random_string(length: int = 0): + return ''.join([random.choice(ascii_letters+digits) for i in range(length if length else random.randint(5, 10))]) + +def get_user_name(user): + if not str(user.discriminator) == "0": + return user + return str(user.name) \ No newline at end of file diff --git a/views/__init__.py b/views/__init__.py new file mode 100644 index 0000000..39dec60 --- /dev/null +++ b/views/__init__.py @@ -0,0 +1,3 @@ +from .link_button import * +from .dashboard_views import * +from .role_select import * \ No newline at end of file diff --git a/views/dashboard_views.py b/views/dashboard_views.py new file mode 100644 index 0000000..d96806c --- /dev/null +++ b/views/dashboard_views.py @@ -0,0 +1,33 @@ +import nextcord, pymysql +from utils import DBENDPOINT, DBNAME, DBPASS, DBUSER, COLOUR_MAIN, create_error_embed, DISCORDLINK +from nextcord import Interaction +from .role_select import RoleSelect + +class DashboardButtons(nextcord.ui.View): + def __init__(self, premium: bool = False): + super().__init__(timeout=300) + self.premium = premium + + @nextcord.ui.Button(label="Set Verification Roles", style=nextcord.ButtonStyle.blurple, disabled=False) + async def set_verification_role(self, interaction: Interaction, button: nextcord.ui.Button): + await interaction.response.defer(with_message=True, ephemeral=True) + if self.premium: + rselect = RoleSelect(minvalue=1, maxvalue=10, text="Select Verification Roles") + embed = nextcord.Embed(title="Select Verification Roles", description="Select the role you want members to recieve when they verify. \nAs a [premium]({PREMIUMLINK}) user you can select up to `10` roles!", color=COLOUR_MAIN) + else: + rselect = RoleSelect(minvalue=1, maxvalue=1, text="Select Verification Roles") + embed = nextcord.Embed(title="Select Verification Roles", description="Select the role you want members to recieve when they verify. \nAs a standard user you can select `1` role. \nUpgrade to [premium]({PREMIUMLINK}) to be able to select up to `10` roles!", color=COLOUR_MAIN) + + msg = await interaction.send(embed=embed, view=rselect, ephemeral=True) + await rselect.wait() + conn = pymysql.connect(host=self.DBENDPOINT, port=3306, user=self.DBUSER, password=self.DBPASS, db=self.DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + data = cur.fetchall() + if not data: + await msg.edit(embed=create_error_embed(title="Error!", description=f"Failed to fetch your guild data, please report this in our [Support Server]({DISCORDLINK})"), view=None) + self.stop() + return + + for role in rselect.values: + ",".join(role.id) \ No newline at end of file diff --git a/views/link_button.py b/views/link_button.py new file mode 100644 index 0000000..7efd81b --- /dev/null +++ b/views/link_button.py @@ -0,0 +1,17 @@ +import nextcord +from utils.constants import VOTELINK, INVITELINK, DISCORDLINK, PRIVACYLINK + +class BotInfoLinkButton(nextcord.ui.View): + def __init__(self): + super().__init__() + self.add_item(nextcord.ui.Button(label="Support Server", url=DISCORDLINK)) + self.add_item(nextcord.ui.Button(label="Invite", url=INVITELINK)) + self.add_item(nextcord.ui.Button(label="Vote", url=VOTELINK)) + self.add_item(nextcord.ui.Button(label="Privacy Policy", url=PRIVACYLINK)) + + + +class PrivacyPolicyButton(nextcord.ui.View): + def __init__(self): + super().__init__() + self.add_item(nextcord.ui.Button(label="Privacy Policy", url=PRIVACYLINK)) \ No newline at end of file diff --git a/views/role_select.py b/views/role_select.py new file mode 100644 index 0000000..d893369 --- /dev/null +++ b/views/role_select.py @@ -0,0 +1,18 @@ +import nextcord +from nextcord.interactions import Interaction +from utils import * +from nextcord import Interaction + +class RoleSelectDropdown(nextcord.ui.RoleSelect): + def __init__(self, minvalue=1, maxvalue=1, text="Select a role"): + super().__init__(custom_id="test", placeholder=text, min_values=minvalue, max_values=maxvalue) + + async def callback(self, interaction: Interaction): + self.view.values = self.values + self.view.stop() + +class RoleSelect(nextcord.ui.View): + def __init__(self, minvalue=1, maxvalue=1, text="Select a role"): + super().__init__() + self.add_item(RoleSelectDropdown(minvalue=minvalue, maxvalue=maxvalue, text=text)) + self.values = [] From e4bcfecda2705659cd169cdc021382989d088a68 Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Mon, 28 Aug 2023 23:22:40 +0100 Subject: [PATCH 17/35] More stuff --- cogs/dashboard.py | 6 +++--- cogs/premium.py | 31 ++++++++++++++++++++++++++----- e.py | 2 ++ utils/utils.py | 4 ++-- views/dashboard_views.py | 23 +++++++++++++++-------- views/role_select.py | 5 +++++ 6 files changed, 53 insertions(+), 18 deletions(-) create mode 100644 e.py diff --git a/cogs/dashboard.py b/cogs/dashboard.py index 5e11d6a..b82cc6c 100644 --- a/cogs/dashboard.py +++ b/cogs/dashboard.py @@ -11,15 +11,15 @@ def __init__(self, client: commands.Bot): @nextcord.slash_command(name=f"dashboard", description=f"Configure the bot on the in-discord dashboard") async def dashboard(self, interaction: Interaction): - conn = pymysql.connect(host=self.DBENDPOINT, port=3306, user=self.DBUSER, password=self.DBPASS, db=self.DBNAME) + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) cur = conn.cursor() cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") data = cur.fetchall() if not data: cur.execute(f"INSERT INTO guild_configs (id) VALUES ('{interaction.guild.id}')") conn.commit() - embed = nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role: {('<@' + data[0][1] + '>') if data[0][1] else 'Not Set'}""") - view = DashboardButtons(premium=check_premium(guild = True, user = False, type_id=interaction.guild.id)) + embed = nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role: {(",".join([('<@&' + i + '> ') for i in data[0][1].split(",")])) if data[0][1] else 'Not Set'}""") + view = DashboardButtons(premium=check_premium(self, guild = True, user = False, type_id=interaction.guild.id)) await interaction.send(embed=embed, view=view) def setup(client: commands.Bot): diff --git a/cogs/premium.py b/cogs/premium.py index 50a57ec..7d3d208 100644 --- a/cogs/premium.py +++ b/cogs/premium.py @@ -1,26 +1,47 @@ import nextcord +import pymysql from nextcord.ext import commands from nextcord import Interaction, SlashOption -from utils import check_premium, create_error_embed, PREMIUMLINK +from utils import check_premium, create_error_embed, create_warning_embed, PREMIUMLINK, DBENDPOINT, DBUSER, DBPASS, DBNAME class Premium(commands.Cog): def __init__(self, client: commands.Bot): self.client = client - @nextcord.slash_commands(name=f"manage-premium", description=f"Manage your premium membership") + @nextcord.slash_command(name=f"manage-premium", description=f"Manage your premium membership", guild_ids=[1111387758028652657, 801744339343507457]) async def manage_premium(self, interaction: Interaction): pass - @manage_premium(name=f"add-server", description=f"Add a server to your premium subscription") + @manage_premium.subcommand(name=f"add-server", description=f"Add a server to your premium subscription") async def manage_premium_add_server(self, interaction: Interaction, guildid: str = SlashOption( name=f"guild", - description=f"The ID of the guild you want to add to your premium subscription. Use /debug in your server to get the server ID", + description=f"The ID of the guild to add to premium. Use /debug in your server to get this.", required = True )): await interaction.response.defer() - if not check_premium(interaction.user.id): + if not check_premium(False, True, interaction.user.id): await interaction.send(embed=create_error_embed(title=f"No premium subscription", description=f"You are not currently subscribed to any of our premium subscriptions. To purchase premium please follow [this link]({PREMIUMLINK})\n\n\nPlease Note: If you recently subscribed to premium it may take up to 30 minutes to register your subscription. If you are still unable to use this command in 30 minutes, please create a ticket in ")) + return + + if check_premium(True, False, guildid): + await interaction.send(embed=create_warning_embed(title=f"Guild already added", description=f"This guild is already added to your premium subscription.")) + return + + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute("SELECT * FROM sv_premium_users WHERE user_id = %s", (interaction.user.id)) + data = cur.fetchall() + + servers_available = int(data[0][1]) + + cur.execute("SELECT * FROM sv_premium_guilds WHERE user_id = %s", (interaction.user.id)) + data = cur.fetchall() + + servers_used = len(data) if data else 0 + + + def setup(client: commands.Bot): client.add_cog(Premium(client)) \ No newline at end of file diff --git a/e.py b/e.py new file mode 100644 index 0000000..3f4f686 --- /dev/null +++ b/e.py @@ -0,0 +1,2 @@ +e = "dhasgdy" +print(e.split(",")) \ No newline at end of file diff --git a/utils/utils.py b/utils/utils.py index 71e4c41..c2c104c 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -21,11 +21,11 @@ def check_premium(self, guild: bool, user: bool, type_id: str): conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) cur = conn.cursor() if guild: - cur.execute(f"SELECT * FROM sv_premium_guilds WHERE id='{type_id}'") + cur.execute(f"SELECT * FROM sv_premium_guilds WHERE guild_id='{type_id}'") data = cur.fetchall() return True if data else False elif user: - cur.execute(f"SELECT * FROM sv_premium_users WHERE id='{type_id}'") + cur.execute(f"SELECT * FROM sv_premium_users WHERE user_id='{type_id}'") data = cur.fetchall() return True if data else False return None diff --git a/views/dashboard_views.py b/views/dashboard_views.py index d96806c..9285129 100644 --- a/views/dashboard_views.py +++ b/views/dashboard_views.py @@ -1,5 +1,5 @@ import nextcord, pymysql -from utils import DBENDPOINT, DBNAME, DBPASS, DBUSER, COLOUR_MAIN, create_error_embed, DISCORDLINK +from utils import DBENDPOINT, DBNAME, DBPASS, DBUSER, COLOUR_MAIN, create_error_embed, DISCORDLINK, create_success_embed, PREMIUMLINK from nextcord import Interaction from .role_select import RoleSelect @@ -8,26 +8,33 @@ def __init__(self, premium: bool = False): super().__init__(timeout=300) self.premium = premium - @nextcord.ui.Button(label="Set Verification Roles", style=nextcord.ButtonStyle.blurple, disabled=False) - async def set_verification_role(self, interaction: Interaction, button: nextcord.ui.Button): + @nextcord.ui.button(label="Set Verification Roles", style=nextcord.ButtonStyle.blurple, disabled=False) + async def set_verification_role(self, button: nextcord.ui.Button, interaction: Interaction): await interaction.response.defer(with_message=True, ephemeral=True) if self.premium: rselect = RoleSelect(minvalue=1, maxvalue=10, text="Select Verification Roles") - embed = nextcord.Embed(title="Select Verification Roles", description="Select the role you want members to recieve when they verify. \nAs a [premium]({PREMIUMLINK}) user you can select up to `10` roles!", color=COLOUR_MAIN) + embed = nextcord.Embed(title="Select Verification Roles", description=f"Select the role you want members to recieve when they verify. \nAs a [premium]({PREMIUMLINK}) user you can select up to `10` roles!", color=COLOUR_MAIN) else: rselect = RoleSelect(minvalue=1, maxvalue=1, text="Select Verification Roles") - embed = nextcord.Embed(title="Select Verification Roles", description="Select the role you want members to recieve when they verify. \nAs a standard user you can select `1` role. \nUpgrade to [premium]({PREMIUMLINK}) to be able to select up to `10` roles!", color=COLOUR_MAIN) + embed = nextcord.Embed(title="Select Verification Roles", description=f"Select the role you want members to recieve when they verify. \nAs a standard user you can select `1` role. \nUpgrade to [premium]({PREMIUMLINK}) to be able to select up to `10` roles!", color=COLOUR_MAIN) msg = await interaction.send(embed=embed, view=rselect, ephemeral=True) await rselect.wait() - conn = pymysql.connect(host=self.DBENDPOINT, port=3306, user=self.DBUSER, password=self.DBPASS, db=self.DBNAME) + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) cur = conn.cursor() cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") data = cur.fetchall() if not data: await msg.edit(embed=create_error_embed(title="Error!", description=f"Failed to fetch your guild data, please report this in our [Support Server]({DISCORDLINK})"), view=None) + conn.commit() self.stop() return - for role in rselect.values: - ",".join(role.id) \ No newline at end of file + ids = ",".join([str(role.id) for role in rselect.values]) + + cur.execute(f"UPDATE `guild_configs` SET verifyrole = '{ids}' WHERE id='{interaction.guild.id}'") + conn.commit() + + embed = nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role: {",".join([('<@&' + i + '> ') for i in ids.split(",")]) if ids else 'Not Set'}""") + await interaction.message.edit(embed=embed) + await msg.edit(embed=create_success_embed(title="Success", description="Successfully updated verification roles."), view=None) \ No newline at end of file diff --git a/views/role_select.py b/views/role_select.py index d893369..92ac0d5 100644 --- a/views/role_select.py +++ b/views/role_select.py @@ -16,3 +16,8 @@ def __init__(self, minvalue=1, maxvalue=1, text="Select a role"): super().__init__() self.add_item(RoleSelectDropdown(minvalue=minvalue, maxvalue=maxvalue, text=text)) self.values = [] + + @nextcord.ui.button(label="Remove Roles", style=nextcord.ButtonStyle.red, disabled=False) + async def remove(self, button: nextcord.ui.Button, interaction: Interaction): + self.stop() + \ No newline at end of file From 44d01e11a418527cfa5a61bf6168fd6da6887d63 Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Mon, 28 Aug 2023 23:55:53 +0100 Subject: [PATCH 18/35] more work --- cogs/dashboard.py | 2 +- cogs/premium.py | 10 +++++++--- views/dashboard_views.py | 43 +++++++++++++++++++++++++++++++++++++--- views/role_select.py | 1 + 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/cogs/dashboard.py b/cogs/dashboard.py index b82cc6c..6a01010 100644 --- a/cogs/dashboard.py +++ b/cogs/dashboard.py @@ -18,7 +18,7 @@ async def dashboard(self, interaction: Interaction): if not data: cur.execute(f"INSERT INTO guild_configs (id) VALUES ('{interaction.guild.id}')") conn.commit() - embed = nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role: {(",".join([('<@&' + i + '> ') for i in data[0][1].split(",")])) if data[0][1] else 'Not Set'}""") + embed = nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][1].split(",")])) if data[0][1] else 'Not Set'} \nUnverified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][2].split(",")])) if data[0][2] else 'Not Set'}""") view = DashboardButtons(premium=check_premium(self, guild = True, user = False, type_id=interaction.guild.id)) await interaction.send(embed=embed, view=view) diff --git a/cogs/premium.py b/cogs/premium.py index 7d3d208..f7b6272 100644 --- a/cogs/premium.py +++ b/cogs/premium.py @@ -20,11 +20,11 @@ async def manage_premium_add_server(self, interaction: Interaction, required = True )): await interaction.response.defer() - if not check_premium(False, True, interaction.user.id): - await interaction.send(embed=create_error_embed(title=f"No premium subscription", description=f"You are not currently subscribed to any of our premium subscriptions. To purchase premium please follow [this link]({PREMIUMLINK})\n\n\nPlease Note: If you recently subscribed to premium it may take up to 30 minutes to register your subscription. If you are still unable to use this command in 30 minutes, please create a ticket in ")) + if not check_premium(self, False, True, interaction.user.id): + await interaction.send(embed=create_error_embed(title=f"No premium subscription", description=f"You are not currently subscribed to any of our premium subscriptions. To purchase premium please follow [this link]({PREMIUMLINK})\n\n\nPlease Note: If you recently subscribed to premium it may take up to 30 minutes to register your subscription. If you are still unable to use this command in 30 minutes, please create a ticket in <#1111392014529990656>")) return - if check_premium(True, False, guildid): + if check_premium(self, True, False, guildid): await interaction.send(embed=create_warning_embed(title=f"Guild already added", description=f"This guild is already added to your premium subscription.")) return @@ -40,6 +40,10 @@ async def manage_premium_add_server(self, interaction: Interaction, servers_used = len(data) if data else 0 + if servers_available <= servers_used: + await interaction.send(embed=create_warning_embed(title=f"Max Servers Reached", description=f"You have reached the limit of premium servers that your current premium subscription allows for (``{servers_available}``). To increase this limit, upgrade your premium subscription via [this link]({PREMIUMLINK})")) + return + diff --git a/views/dashboard_views.py b/views/dashboard_views.py index 9285129..54109c0 100644 --- a/views/dashboard_views.py +++ b/views/dashboard_views.py @@ -30,11 +30,48 @@ async def set_verification_role(self, button: nextcord.ui.Button, interaction: I self.stop() return - ids = ",".join([str(role.id) for role in rselect.values]) + if rselect.values: + ids = ",".join([str(role.id) for role in rselect.values]) + else: + ids = None cur.execute(f"UPDATE `guild_configs` SET verifyrole = '{ids}' WHERE id='{interaction.guild.id}'") conn.commit() - embed = nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role: {",".join([('<@&' + i + '> ') for i in ids.split(",")]) if ids else 'Not Set'}""") + embed = nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role: {",".join([('<@&' + i + '> ') for i in ids.split(",")]) if ids else 'Not Set'} \nUnverified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][2].split(",")])) if data[0][2] else 'Not Set'}""") + await interaction.message.edit(embed=embed) + await msg.edit(embed=create_success_embed(title="Success", description="Successfully updated verification roles."), view=None) + + @nextcord.ui.button(label="Set Unverified Roles", style=nextcord.ButtonStyle.blurple, disabled=False) + async def set_unverified_role(self, button: nextcord.ui.Button, interaction: Interaction): + await interaction.response.defer(with_message=True, ephemeral=True) + if self.premium: + rselect = RoleSelect(minvalue=1, maxvalue=10, text="Select Unverified Roles") + embed = nextcord.Embed(title="Select Unverified Roles", description=f"Select the roles you want members to have while they are unverified. \nAs a [premium]({PREMIUMLINK}) user you can select up to `10` roles!", color=COLOUR_MAIN) + else: + rselect = RoleSelect(minvalue=1, maxvalue=1, text="Select Unverified Roles") + embed = nextcord.Embed(title="Select Unverified Roles", description=f"Select the roles you want members to have while they are unverified. \nAs a standard user you can select `1` role. \nUpgrade to [premium]({PREMIUMLINK}) to be able to select up to `10` roles!", color=COLOUR_MAIN) + + msg = await interaction.send(embed=embed, view=rselect, ephemeral=True) + await rselect.wait() + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + data = cur.fetchall() + if not data: + await msg.edit(embed=create_error_embed(title="Error!", description=f"Failed to fetch your guild data, please report this in our [Support Server]({DISCORDLINK})"), view=None) + conn.commit() + self.stop() + return + + if rselect.values: + ids = ",".join([str(role.id) for role in rselect.values]) + else: + ids = None + + cur.execute(f"UPDATE `guild_configs` SET unverifiedrole = '{ids}' WHERE id='{interaction.guild.id}'") + conn.commit() + + embed = nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role(s): {",".join([('<@&' + i + '> ') for i in data[0][1].split(",")]) if data[0][1] else 'Not Set'} \nUnverified Role(s): {(",".join([('<@&' + i + '> ') for i in ids.split(",")])) if ids else 'Not Set'}""") await interaction.message.edit(embed=embed) - await msg.edit(embed=create_success_embed(title="Success", description="Successfully updated verification roles."), view=None) \ No newline at end of file + await msg.edit(embed=create_success_embed(title="Success", description="Successfully updated unverified roles."), view=None) \ No newline at end of file diff --git a/views/role_select.py b/views/role_select.py index 92ac0d5..75f58f6 100644 --- a/views/role_select.py +++ b/views/role_select.py @@ -19,5 +19,6 @@ def __init__(self, minvalue=1, maxvalue=1, text="Select a role"): @nextcord.ui.button(label="Remove Roles", style=nextcord.ButtonStyle.red, disabled=False) async def remove(self, button: nextcord.ui.Button, interaction: Interaction): + self.values = None self.stop() \ No newline at end of file From ee7e3eeb65eeeb8c3d72f094b347919018a7a580 Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Tue, 29 Aug 2023 17:55:55 +0100 Subject: [PATCH 19/35] Completed `/manage-premium add-server` (Untested) --- cogs/premium.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/cogs/premium.py b/cogs/premium.py index f7b6272..31ff585 100644 --- a/cogs/premium.py +++ b/cogs/premium.py @@ -2,7 +2,7 @@ import pymysql from nextcord.ext import commands from nextcord import Interaction, SlashOption -from utils import check_premium, create_error_embed, create_warning_embed, PREMIUMLINK, DBENDPOINT, DBUSER, DBPASS, DBNAME +from utils import check_premium, create_error_embed, create_warning_embed, create_success_embed, PREMIUMLINK, DBENDPOINT, DBUSER, DBPASS, DBNAME class Premium(commands.Cog): def __init__(self, client: commands.Bot): @@ -44,6 +44,17 @@ async def manage_premium_add_server(self, interaction: Interaction, await interaction.send(embed=create_warning_embed(title=f"Max Servers Reached", description=f"You have reached the limit of premium servers that your current premium subscription allows for (``{servers_available}``). To increase this limit, upgrade your premium subscription via [this link]({PREMIUMLINK})")) return + try: + guild = self.get_guild(int(guildid)) + except: + await interaction.send(embed=create_error_embed(title=f"Invalid guild ID", description=f"You have given an invalid guild ID. Please use the `/debug` command in the guild you want to add premium to to get the correct guild ID.")) + return + + cur.execute("INSERT INTO sv_premium_guilds VALUES (user_id, guild_id) SET (%s, %s)", (interaction.user.id, guildid)) + conn.commit() + + await interaction.send(embed=create_success_embed(title=f"Premium server added", description=f"You have succesfully given `{guild.name} ({guild.id})` to your premium subscription.")) + From 3221e4e5997f27ac1ecf700b4084ffc0bda1b7b5 Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Tue, 29 Aug 2023 23:29:21 +0100 Subject: [PATCH 20/35] More work --- .gitignore | 1 - bot/bot.py | 35 ++++++++++++++++++++++++ cogs/dashboard.py | 7 ++--- cogs/extras.py | 35 ------------------------ cogs/misc.py | 55 ++++++++++++++++++++++++++++++++++++++ cogs/premium.py | 16 +++++++++-- e.py | 2 -- main.py | 57 +++------------------------------------- utils/utils.py | 3 +++ views/dashboard_views.py | 56 +++++++++++++++++++++++++++++++++++---- views/role_select.py | 20 +++++++++++++- 11 files changed, 185 insertions(+), 102 deletions(-) create mode 100644 bot/bot.py delete mode 100644 cogs/extras.py create mode 100644 cogs/misc.py delete mode 100644 e.py diff --git a/.gitignore b/.gitignore index bacf1ec..b6eae9e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -dbconfig.json __pycache__/ /utils/dbconstants.py utils/dbconstants.py diff --git a/bot/bot.py b/bot/bot.py new file mode 100644 index 0000000..081dfc4 --- /dev/null +++ b/bot/bot.py @@ -0,0 +1,35 @@ +import nextcord +import json, asyncio +import os +from nextcord.ext import commands, tasks +from utils.utils import * +from utils.constants import TOKEN + +class Bot(commands.AutoShardedBot): + def __init__(self): + intents = nextcord.Intents.all() + intents.presences = False + super().__init__(shard_count=1, command_prefix="nom!", intents=nextcord.Intents.all()) + self.unloaded_cogs = [] + + def initialize(self): + self.load_extensions() + self.run(TOKEN) + + def load_extensions(self): + for cog in os.listdir("./cogs"): + if cog.endswith(".py"): + try: + self.load_extension(name=f"cogs.{cog[:-3]}") + print(f"Loaded {cog[:-3]} cog") + + except Exception as e: + print(e) + print(f"Failed to load {cog[:-3]} cog") + self.unloaded_cogs.append(cog.capitalize()[-3]) + + async def on_ready(self): + print(f"Logged in as {self.user}!") + print(self.shards) + for shard in self.shards: + await self.change_presence(status=nextcord.Status.online, activity=nextcord.Activity(type=nextcord.ActivityType.playing, name=f"Verifying | Shard: {shard+1}/{len(self.shards)}"), shard_id=shard) \ No newline at end of file diff --git a/cogs/dashboard.py b/cogs/dashboard.py index 6a01010..0eea262 100644 --- a/cogs/dashboard.py +++ b/cogs/dashboard.py @@ -1,7 +1,7 @@ import nextcord from nextcord.ext import commands from nextcord import Interaction -from utils import check_premium, DBENDPOINT, DBNAME, DBPASS, DBUSER +from utils import check_premium, DBENDPOINT, DBNAME, DBPASS, DBUSER, generate_dashboard from views import DashboardButtons import pymysql @@ -11,6 +11,7 @@ def __init__(self, client: commands.Bot): @nextcord.slash_command(name=f"dashboard", description=f"Configure the bot on the in-discord dashboard") async def dashboard(self, interaction: Interaction): + interaction.response.defer(with_message=True, ephemeral=True) conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) cur = conn.cursor() cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") @@ -18,9 +19,9 @@ async def dashboard(self, interaction: Interaction): if not data: cur.execute(f"INSERT INTO guild_configs (id) VALUES ('{interaction.guild.id}')") conn.commit() - embed = nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][1].split(",")])) if data[0][1] else 'Not Set'} \nUnverified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][2].split(",")])) if data[0][2] else 'Not Set'}""") + embed = generate_dashboard(data=data) view = DashboardButtons(premium=check_premium(self, guild = True, user = False, type_id=interaction.guild.id)) - await interaction.send(embed=embed, view=view) + await interaction.send(embed=embed, view=view, ephemeral=True) def setup(client: commands.Bot): client.add_cog(Dashboard(client)) \ No newline at end of file diff --git a/cogs/extras.py b/cogs/extras.py deleted file mode 100644 index 1563263..0000000 --- a/cogs/extras.py +++ /dev/null @@ -1,35 +0,0 @@ -import nextcord -from nextcord.ext import commands -import time -from nextcord import Interaction -from views import BotInfoLinkButton, PrivacyPolicyButton -from utils.constants import COLOUR_MAIN, VOTELINK, INVITELINK, DISCORDLINK, PRIVACYLINK - -class Extras(commands.Cog): - def __init__(self, client: commands.Bot): - self.client = client - - @nextcord.slash_command(name="botinfo", description="Information about the bot") - async def botinfo(self, interaction: Interaction): - await interaction.response.defer() - before = time.monotonic() - msg = await interaction.send("Loading bot information") - ping = (time.monotonic() - before) * 1000 - users = 0 - for guild in self.client.guilds: - users+=guild.member_count - embed = nextcord.Embed(title="Bot Infomation", description=f"""Ping: {round(ping)}ms -Server count: {str(len(self.client.guilds))} -User count: {users:,} -Support Server: [Need some support?]({DISCORDLINK}) -Invite: [Invite Me]({INVITELINK}) -Vote: [Vote for me]({VOTELINK}) -Privacy: [Privacy Policy]({PRIVACYLINK})""", colour=COLOUR_MAIN) - await msg.edit(content = " ", embed=embed, view=BotInfoLinkButton()) - - @nextcord.slash_command(name=f"privacy", description=f"Get the link to our privacy policy") - async def privacy(self, interaction:Interaction): - await interaction.send(content="", view=PrivacyPolicyButton()) - -def setup(client: commands.Bot): - client.add_cog(Extras(client)) \ No newline at end of file diff --git a/cogs/misc.py b/cogs/misc.py new file mode 100644 index 0000000..e3c80a1 --- /dev/null +++ b/cogs/misc.py @@ -0,0 +1,55 @@ +import nextcord +from nextcord.ext import commands +import time +from nextcord import Interaction +from views import BotInfoLinkButton, PrivacyPolicyButton +import cooldowns +from utils.constants import COLOUR_MAIN, VOTELINK, INVITELINK, DISCORDLINK, PRIVACYLINK + +class Misc(commands.Cog): + def __init__(self, client: commands.Bot): + self.client = client + + @nextcord.slash_command(name="botinfo", description="Information about the bot") + async def botinfo(self, interaction: Interaction): + await interaction.response.defer() + before = time.monotonic() + msg = await interaction.send("Loading bot information") + ping = (time.monotonic() - before) * 1000 + users = 0 + for guild in self.client.guilds: + users+=guild.member_count + embed = nextcord.Embed(title="Bot Infomation", description=f"""Ping: {round(ping)}ms +Server count: {str(len(self.client.guilds))} +User count: {users:,} +Support Server: [Need some support?]({DISCORDLINK}) +Invite: [Invite Me]({INVITELINK}) +Vote: [Vote for me]({VOTELINK}) +Privacy: [Privacy Policy]({PRIVACYLINK})""", colour=COLOUR_MAIN) + await msg.edit(content = " ", embed=embed, view=BotInfoLinkButton()) + + @nextcord.slash_command(name=f"privacy", description=f"Get the link to our privacy policy") + async def privacy(self, interaction:Interaction): + await interaction.send(content="", view=PrivacyPolicyButton()) + + + @nextcord.slash_command(name=f"shardinfo", description=f"Get information on all shards") + @cooldowns.cooldown(1, 30, bucket=cooldowns.SlashBucket.author) + async def shardinfo(self, interaction:Interaction): + await interaction.response.defer() + description = "" + for shard in self.client.shards: + specshard = self.client.get_shard(shard) + shard_servers = len([guild for guild in self.client.guilds if guild.shard_id == shard]) + description+=f"\n**Shard {shard+1}** has `{round(specshard.latency*100)}ms` latency with `{shard_servers} servers`" + + if not interaction.guild: + await interaction.send(embed=nextcord.Embed(title=f"Simple Verification Shard Information", description=f"All current shards:\n {description}", colour=COLOUR_MAIN)) + else: + guild_shard = interaction.guild.shard_id + guildspecshard = self.client.get_shard(guild_shard) + guild_shard_servers = len([guild for guild in self.client.guilds if guild.shard_id == guild_shard]) + await interaction.send(f"This server's shard is shard **{guild_shard+1}** with `{round(guildspecshard.latency*100)}ms` and `{guild_shard_servers} servers`", embed=nextcord.Embed(title=f"Simple Verification Shard Information", description=f"All current shards:\n {description}", colour=COLOUR_MAIN)) + +def setup(client: commands.Bot): + client.add_cog(Misc(client)) \ No newline at end of file diff --git a/cogs/premium.py b/cogs/premium.py index 31ff585..6ea71f4 100644 --- a/cogs/premium.py +++ b/cogs/premium.py @@ -1,6 +1,6 @@ import nextcord import pymysql -from nextcord.ext import commands +from nextcord.ext import commands, tasks from nextcord import Interaction, SlashOption from utils import check_premium, create_error_embed, create_warning_embed, create_success_embed, PREMIUMLINK, DBENDPOINT, DBUSER, DBPASS, DBNAME @@ -56,7 +56,19 @@ async def manage_premium_add_server(self, interaction: Interaction, await interaction.send(embed=create_success_embed(title=f"Premium server added", description=f"You have succesfully given `{guild.name} ({guild.id})` to your premium subscription.")) - + + + @tasks.loop(minutes=5) + async def premium_manager(self): + premium_role_ids = [1130511638794080419, 1130520156477608036, 1130520224689557554, 1130520278850613369, 1130520336744591431] # ACTUAL IDS = [1130511638794080419, 1130520156477608036, 1130520224689557554, 1130520278850613369, 1130520336744591431] + guild = self.get_guild(1111387758028652657) # ACTUAL ID = 1111387758028652657 + premium_roles = [].append([role for role in guild.get_role([roleid for roleid in premium_role_ids])]) + + print(premium_roles) + + for member in guild.members: + if premium_role_ids in member.roles: + pass def setup(client: commands.Bot): client.add_cog(Premium(client)) \ No newline at end of file diff --git a/e.py b/e.py deleted file mode 100644 index 3f4f686..0000000 --- a/e.py +++ /dev/null @@ -1,2 +0,0 @@ -e = "dhasgdy" -print(e.split(",")) \ No newline at end of file diff --git a/main.py b/main.py index 8f9163f..18738d1 100644 --- a/main.py +++ b/main.py @@ -1,57 +1,8 @@ -import nextcord -import json import os -from nextcord.ext import commands , tasks -import requests -from utils.constants import TOKEN +from bot.bot import Bot +from utils.utils import * os.chdir("./") - - -class Bot(commands.Bot): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.persistent_views_added = False - self = self - - async def on_ready(self): - if not self.persistent_views_added: - self.persistent_views_added = True - - print(f"Logged in as {client.user}!") - - await client.change_presence(status = nextcord.Status.online, activity=nextcord.Activity(type=nextcord.ActivityType.watching, name="People Verify")) - - -intents = nextcord.Intents.default() - -intents.members = True -client = Bot(command_prefix = "nom!", intents = intents) - -for filename in os.listdir('./cogs'): - if filename.endswith('.py'): - client.load_extension(f'cogs.{filename[:-3]}') - print(f"Loaded {filename} cog") - - - - - - - - - - - - - - - - - - - - - -client.run(TOKEN) +disc_bot = Bot() +disc_bot.initialize() diff --git a/utils/utils.py b/utils/utils.py index c2c104c..09ba3e5 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -29,6 +29,9 @@ def check_premium(self, guild: bool, user: bool, type_id: str): data = cur.fetchall() return True if data else False return None + +def generate_dashboard(self, data): + return nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][1].split(",")])) if data[0][1] else 'Not Set'}\nUnverified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][2].split(",")])) if data[0][2] else 'Not Set'} \nLog Channel: <#{data[0][3] if data[0][3] else 'Not Set'}>""") def totalxp_to_level(total_xp): diff --git a/views/dashboard_views.py b/views/dashboard_views.py index 54109c0..ab2b06a 100644 --- a/views/dashboard_views.py +++ b/views/dashboard_views.py @@ -1,7 +1,7 @@ import nextcord, pymysql -from utils import DBENDPOINT, DBNAME, DBPASS, DBUSER, COLOUR_MAIN, create_error_embed, DISCORDLINK, create_success_embed, PREMIUMLINK +from utils import DBENDPOINT, DBNAME, DBPASS, DBUSER, COLOUR_MAIN, create_error_embed, DISCORDLINK, create_success_embed, PREMIUMLINK, generate_dashboard from nextcord import Interaction -from .role_select import RoleSelect +from .role_select import RoleSelect, ChannelSelect class DashboardButtons(nextcord.ui.View): def __init__(self, premium: bool = False): @@ -38,7 +38,12 @@ async def set_verification_role(self, button: nextcord.ui.Button, interaction: I cur.execute(f"UPDATE `guild_configs` SET verifyrole = '{ids}' WHERE id='{interaction.guild.id}'") conn.commit() - embed = nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role: {",".join([('<@&' + i + '> ') for i in ids.split(",")]) if ids else 'Not Set'} \nUnverified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][2].split(",")])) if data[0][2] else 'Not Set'}""") + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + dataa = cur.fetchall() + + embed = generate_dashboard(data=dataa) await interaction.message.edit(embed=embed) await msg.edit(embed=create_success_embed(title="Success", description="Successfully updated verification roles."), view=None) @@ -72,6 +77,47 @@ async def set_unverified_role(self, button: nextcord.ui.Button, interaction: Int cur.execute(f"UPDATE `guild_configs` SET unverifiedrole = '{ids}' WHERE id='{interaction.guild.id}'") conn.commit() - embed = nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role(s): {",".join([('<@&' + i + '> ') for i in data[0][1].split(",")]) if data[0][1] else 'Not Set'} \nUnverified Role(s): {(",".join([('<@&' + i + '> ') for i in ids.split(",")])) if ids else 'Not Set'}""") + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + dataa = cur.fetchall() + + embed = generate_dashboard(data=dataa) await interaction.message.edit(embed=embed) - await msg.edit(embed=create_success_embed(title="Success", description="Successfully updated unverified roles."), view=None) \ No newline at end of file + await msg.edit(embed=create_success_embed(title="Success", description="Successfully updated unverified roles."), view=None) + + + @nextcord.ui.button(label="Set Log Channel", style=nextcord.ButtonStyle.blurple, disabled=False) + async def set_log_channel(self, button: nextcord.ui.Button, interaction: Interaction): + await interaction.response.defer(with_message=True, ephemeral=True) + + embed = nextcord.Embed(title="Select Log Channel", description="Select the channel you want logs to be sent in. \nYou can select `1` channel.", color=COLOUR_MAIN) + cselect = ChannelSelect(minvalue=1, maxvalue=1, text="Select a Channel") + msg = await interaction.send(embed=embed, view=cselect) + await cselect.wait() + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + data = cur.fetchall() + if not data: + await msg.edit(embed=create_error_embed(title="Error!", description=f"Failed to fetch your guild data, please report this in our [Support Server]({DISCORDLINK})"), view=None) + conn.commit() + self.stop() + return + + if cselect.values: + id = cselect.values[0] + else: + id = None + + cur.execute(f"UPDATE `guild_configs` SET logchannel = '{id}' WHERE id='{interaction.guild.id}'") + conn.commit() + + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + dataa = cur.fetchall() + + embed = generate_dashboard(data=dataa) + await interaction.message.edit(embed=embed) + await msg.edit(embed=create_success_embed(title="Success", description="Successfully updated log channel."), view=None) \ No newline at end of file diff --git a/views/role_select.py b/views/role_select.py index 75f58f6..4d1d561 100644 --- a/views/role_select.py +++ b/views/role_select.py @@ -21,4 +21,22 @@ def __init__(self, minvalue=1, maxvalue=1, text="Select a role"): async def remove(self, button: nextcord.ui.Button, interaction: Interaction): self.values = None self.stop() - \ No newline at end of file + +class ChannelSelectDropdown(nextcord.ui.ChannelSelect): + def __init__(self, minvalue=1, maxvalue=1, text="Select a channel"): + super().__init__(custom_id="test", placeholder=text, min_values=minvalue, max_values=maxvalue, channel_types=[nextcord.ChannelType.text, nextcord.ChannelType.news]) + + async def callback(self, interaction: nextcord.Interaction): + self.view.values = self.values + self.view.stop() + +class ChannelSelect(nextcord.ui.View): + def __init__(self, minvalue=1, maxvalue=1, text="Select a channel"): + super().__init__() + self.add_item(ChannelSelectDropdown(minvalue=minvalue, maxvalue=maxvalue, text=text)) + self.values = [] + + @nextcord.ui.button(label="Remove Channel", style=nextcord.ButtonStyle.red, disabled=False) + async def remove(self, button: nextcord.ui.Button, interaction: Interaction): + self.values = None + self.stop() \ No newline at end of file From ba86bc9eb59a3508839edb065653cc4a2c85f99c Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Wed, 30 Aug 2023 00:28:29 +0100 Subject: [PATCH 21/35] More work --- cogs/dashboard.py | 7 ++++++- utils/utils.py | 2 +- views/__init__.py | 3 ++- views/dashboard_views.py | 42 +++++++++++++++++++++++++++++++++++++++- views/length_modal.py | 22 +++++++++++++++++++++ views/role_select.py | 1 - 6 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 views/length_modal.py diff --git a/cogs/dashboard.py b/cogs/dashboard.py index 0eea262..f01cf3f 100644 --- a/cogs/dashboard.py +++ b/cogs/dashboard.py @@ -1,7 +1,7 @@ import nextcord from nextcord.ext import commands from nextcord import Interaction -from utils import check_premium, DBENDPOINT, DBNAME, DBPASS, DBUSER, generate_dashboard +from utils import check_premium, DBENDPOINT, DBNAME, DBPASS, DBUSER, generate_dashboard, create_warning_embed from views import DashboardButtons import pymysql @@ -12,6 +12,10 @@ def __init__(self, client: commands.Bot): @nextcord.slash_command(name=f"dashboard", description=f"Configure the bot on the in-discord dashboard") async def dashboard(self, interaction: Interaction): interaction.response.defer(with_message=True, ephemeral=True) + if not interaction.user.guild_permissions.administrator: + await interaction.send(embed=create_warning_embed(title="Insufficient permissions", description="You need the `administrator` permission to use this.")) + return + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) cur = conn.cursor() cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") @@ -19,6 +23,7 @@ async def dashboard(self, interaction: Interaction): if not data: cur.execute(f"INSERT INTO guild_configs (id) VALUES ('{interaction.guild.id}')") conn.commit() + embed = generate_dashboard(data=data) view = DashboardButtons(premium=check_premium(self, guild = True, user = False, type_id=interaction.guild.id)) await interaction.send(embed=embed, view=view, ephemeral=True) diff --git a/utils/utils.py b/utils/utils.py index 09ba3e5..9a2dca8 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -31,7 +31,7 @@ def check_premium(self, guild: bool, user: bool, type_id: str): return None def generate_dashboard(self, data): - return nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][1].split(",")])) if data[0][1] else 'Not Set'}\nUnverified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][2].split(",")])) if data[0][2] else 'Not Set'} \nLog Channel: <#{data[0][3] if data[0][3] else 'Not Set'}>""") + return nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][1].split(",")])) if data[0][1] else 'Not Set'}\nUnverified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][2].split(",")])) if data[0][2] else 'Not Set'} \nLog Channel: <#{data[0][3] if data[0][3] else 'Not Set'}> \nAuto Kick: {f"{data[0][5]} day(s)" if data[0][5] else 'Not Set'}""") def totalxp_to_level(total_xp): diff --git a/views/__init__.py b/views/__init__.py index 39dec60..09c5ef8 100644 --- a/views/__init__.py +++ b/views/__init__.py @@ -1,3 +1,4 @@ from .link_button import * from .dashboard_views import * -from .role_select import * \ No newline at end of file +from .role_select import * +from .length_modal import * \ No newline at end of file diff --git a/views/dashboard_views.py b/views/dashboard_views.py index ab2b06a..fe5a4e1 100644 --- a/views/dashboard_views.py +++ b/views/dashboard_views.py @@ -2,6 +2,7 @@ from utils import DBENDPOINT, DBNAME, DBPASS, DBUSER, COLOUR_MAIN, create_error_embed, DISCORDLINK, create_success_embed, PREMIUMLINK, generate_dashboard from nextcord import Interaction from .role_select import RoleSelect, ChannelSelect +from .length_modal import LengthModal class DashboardButtons(nextcord.ui.View): def __init__(self, premium: bool = False): @@ -120,4 +121,43 @@ async def set_log_channel(self, button: nextcord.ui.Button, interaction: Interac embed = generate_dashboard(data=dataa) await interaction.message.edit(embed=embed) - await msg.edit(embed=create_success_embed(title="Success", description="Successfully updated log channel."), view=None) \ No newline at end of file + await msg.edit(embed=create_success_embed(title="Success", description="Successfully updated log channel."), view=None) + + @nextcord.ui.button(label="Set Autokick Account Age", style=nextcord.ButtonStyle.blurple, disabled=False) + async def set_autokick_account_age(self, button: nextcord.ui.Button, interaction: Interaction): + await interaction.response.defer(with_message=True, ephemeral=True) + form = LengthModal() + await interaction.response.send_modal(modal=form) + await form.wait() + + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + data = cur.fetchall() + if not data: + await msg.edit(embed=create_error_embed(title="Error!", description=f"Failed to fetch your guild data, please report this in our [Support Server]({DISCORDLINK})"), view=None) + conn.commit() + self.stop() + return + + try: + length = int(form.age) + except: + await interaction.send(embed=create_error_embed(title="Error", description="An invalid duration was supplied, the duration must be a whole positive number")) + return + + if length < 0: + await interaction.send(embed=create_error_embed(title="Error", description="An invalid duration was supplied, the duration must be a whole positive number")) + return + + cur.execute(f"UPDATE `guild_configs` SET autokick = '{length}' WHERE id='{interaction.guild.id}'") + conn.commit() + + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + dataa = cur.fetchall() + + embed = generate_dashboard(data=dataa) + await interaction.message.edit(embed=embed) + await interaction.send(embed=create_success_embed(title="Success", description="Successfully updated log channel."), view=None) \ No newline at end of file diff --git a/views/length_modal.py b/views/length_modal.py new file mode 100644 index 0000000..65b2122 --- /dev/null +++ b/views/length_modal.py @@ -0,0 +1,22 @@ +import nextcord +from nextcord.interactions import Interaction +from nextcord import Interaction + +class LengthModal(nextcord.ui.Modal): + def __init__(self): + super().__init__(title="Set account age", timeout=None) + + self.length = nextcord.ui.TextInput( + label = "How old do you want accounts to have to be (days)", + placeholder = "To disable autokick put 0", + style=nextcord.TextInputStyle.short, + min_length=1, + max_length=3, + required=True + ) + + self.add_item(self.length) + + async def callback(self, interaction: nextcord.Interaction): + self.age = self.length.value + self.stop() \ No newline at end of file diff --git a/views/role_select.py b/views/role_select.py index 4d1d561..f5fc978 100644 --- a/views/role_select.py +++ b/views/role_select.py @@ -1,6 +1,5 @@ import nextcord from nextcord.interactions import Interaction -from utils import * from nextcord import Interaction class RoleSelectDropdown(nextcord.ui.RoleSelect): From c8a56847b6e90a4371f7a0f2f67da759ef9e33d1 Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Wed, 30 Aug 2023 23:08:05 +0100 Subject: [PATCH 22/35] More work --- cogs/dashboard.py | 3 +++ utils/utils.py | 8 ++++++-- views/dashboard_views.py | 40 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/cogs/dashboard.py b/cogs/dashboard.py index f01cf3f..bcea69c 100644 --- a/cogs/dashboard.py +++ b/cogs/dashboard.py @@ -28,5 +28,8 @@ async def dashboard(self, interaction: Interaction): view = DashboardButtons(premium=check_premium(self, guild = True, user = False, type_id=interaction.guild.id)) await interaction.send(embed=embed, view=view, ephemeral=True) + + + def setup(client: commands.Bot): client.add_cog(Dashboard(client)) \ No newline at end of file diff --git a/utils/utils.py b/utils/utils.py index 9a2dca8..45ae294 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -1,4 +1,4 @@ -from .constants import COLOUR_BAD, COLOUR_GOOD, COLOUR_NEUTRAL, DBENDPOINT, DBNAME, DBPASS, DBUSER +from .constants import COLOUR_BAD, COLOUR_GOOD, COLOUR_NEUTRAL, DBENDPOINT, DBNAME, DBPASS, DBUSER, PREMIUMLINK import nextcord, math, random, pymysql from string import ascii_letters, digits @@ -31,7 +31,11 @@ def check_premium(self, guild: bool, user: bool, type_id: str): return None def generate_dashboard(self, data): - return nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][1].split(",")])) if data[0][1] else 'Not Set'}\nUnverified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][2].split(",")])) if data[0][2] else 'Not Set'} \nLog Channel: <#{data[0][3] if data[0][3] else 'Not Set'}> \nAuto Kick: {f"{data[0][5]} day(s)" if data[0][5] else 'Not Set'}""") + if data[0][6] == "no": + autov = "Disabled" + else: + autov = "Enabled" + return nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][1].split(",")])) if data[0][1] else 'Not Set'}\nUnverified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][2].split(",")])) if data[0][2] else 'Not Set'} \nLog Channel: <#{data[0][3] if data[0][3] else 'Not Set'}> \nAuto Kick: {f"{data[0][5]} day(s)" if data[0][5] else 'Not Set'} \nAuto Verification ([Premium]({PREMIUMLINK}) Only): {autov}""") def totalxp_to_level(total_xp): diff --git a/views/dashboard_views.py b/views/dashboard_views.py index fe5a4e1..b16f1db 100644 --- a/views/dashboard_views.py +++ b/views/dashboard_views.py @@ -1,13 +1,51 @@ import nextcord, pymysql +from nextcord.interactions import Interaction from utils import DBENDPOINT, DBNAME, DBPASS, DBUSER, COLOUR_MAIN, create_error_embed, DISCORDLINK, create_success_embed, PREMIUMLINK, generate_dashboard from nextcord import Interaction from .role_select import RoleSelect, ChannelSelect from .length_modal import LengthModal + +class AutoVerificationButton(nextcord.ui.Button): + def __init__(self, premium: bool = False): + if premium: + super().__init__(label="Toggle Auto Verification", style=nextcord.ButtonStyle.blurple, disabled=False) + else: + super().__init__(label="Toggle Auto Verification", style=nextcord.ButtonStyle.blurple, disabled=True) + + async def callback(self, interaction: Interaction): + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + data = cur.fetchall() + if not data: + await interaction.send(embed=create_error_embed(title="Error!", description=f"Failed to fetch your guild data, please report this in our [Support Server]({DISCORDLINK})"), view=None) + conn.commit() + self.stop() + return + + if data[0][6] == "no": + cur.execute(f"UPDATE `guild_configs` SET autoveri = 'enabled' WHERE id='{interaction.guild.id}'") + embed = create_success_embed(title="Success", description="Successfully enabled autoverification.") + else: + cur.execute(f"UPDATE `guild_configs` SET autoveri = 'no' WHERE id='{interaction.guild.id}'") + embed = create_success_embed(title="Success", description="Successfully disabled autoverification.") + + conn.commit() + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + dataa = cur.fetchall() + eembed = generate_dashboard(data=dataa) + await interaction.message.edit(embed=eembed) + await interaction.send(embed=create_success_embed(title="Success", description="Successfully updated verification roles."), view=None) + + class DashboardButtons(nextcord.ui.View): def __init__(self, premium: bool = False): super().__init__(timeout=300) self.premium = premium + self.add_item(AutoVerificationButton(premium=premium)) @nextcord.ui.button(label="Set Verification Roles", style=nextcord.ButtonStyle.blurple, disabled=False) async def set_verification_role(self, button: nextcord.ui.Button, interaction: Interaction): @@ -135,7 +173,7 @@ async def set_autokick_account_age(self, button: nextcord.ui.Button, interaction cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") data = cur.fetchall() if not data: - await msg.edit(embed=create_error_embed(title="Error!", description=f"Failed to fetch your guild data, please report this in our [Support Server]({DISCORDLINK})"), view=None) + await interaction.send(embed=create_error_embed(title="Error!", description=f"Failed to fetch your guild data, please report this in our [Support Server]({DISCORDLINK})"), view=None) conn.commit() self.stop() return From 8654318e7d1ad9c1ab5e83ba6f7750c036e60382 Mon Sep 17 00:00:00 2001 From: heroescreed <100536226+heroescreed@users.noreply.github.com> Date: Sun, 3 Sep 2023 19:18:15 +0100 Subject: [PATCH 23/35] Added `/shardinfo` --- cogs/misc.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/cogs/misc.py b/cogs/misc.py index e3c80a1..4944414 100644 --- a/cogs/misc.py +++ b/cogs/misc.py @@ -51,5 +51,26 @@ async def shardinfo(self, interaction:Interaction): guild_shard_servers = len([guild for guild in self.client.guilds if guild.shard_id == guild_shard]) await interaction.send(f"This server's shard is shard **{guild_shard+1}** with `{round(guildspecshard.latency*100)}ms` and `{guild_shard_servers} servers`", embed=nextcord.Embed(title=f"Simple Verification Shard Information", description=f"All current shards:\n {description}", colour=COLOUR_MAIN)) + + + @nextcord.slash_command(name=f"shardinfo", description=f"Get information on all shards") + @cooldowns.cooldown(1, 30, bucket=cooldowns.SlashBucket.author) + async def shardinfo(self, interaction:Interaction): + await interaction.response.defer() + description = "" + for shard in self.client.shards: + specshard = self.client.get_shard(shard) + shard_servers = len([guild for guild in self.client.guilds if guild.shard_id == shard]) + description+=f"\n**Shard {shard+1}** has `{round(specshard.latency*100)}ms` latency with `{shard_servers} servers`" + + if not interaction.guild: + await interaction.send(embed=nextcord.Embed(title=f"Simple Verification Shard Information", description=f"All current shards:\n {description}", colour=COLOUR_MAIN)) + else: + guild_shard = interaction.guild.shard_id + guildspecshard = self.client.get_shard(guild_shard) + guild_shard_servers = len([guild for guild in self.client.guilds if guild.shard_id == guild_shard]) + await interaction.send(f"This server's shard is shard **{guild_shard+1}** with `{round(guildspecshard.latency*100)}ms` and `{guild_shard_servers} servers`", embed=nextcord.Embed(title=f"Simple Verification Shard Information", description=f"All current shards:\n {description}", colour=COLOUR_MAIN)) + + def setup(client: commands.Bot): client.add_cog(Misc(client)) \ No newline at end of file From 8493877f1648ac6bf23fc0aa965b48122b60ff29 Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Tue, 12 Sep 2023 20:59:28 +0100 Subject: [PATCH 24/35] Added `/debug` & `error_handler.py` --- bot/bot.py | 4 +--- cogs/error_handler.py | 24 ++++++++++++++++++++++++ cogs/misc.py | 7 +++++++ 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 cogs/error_handler.py diff --git a/bot/bot.py b/bot/bot.py index 081dfc4..fc2b379 100644 --- a/bot/bot.py +++ b/bot/bot.py @@ -7,9 +7,7 @@ class Bot(commands.AutoShardedBot): def __init__(self): - intents = nextcord.Intents.all() - intents.presences = False - super().__init__(shard_count=1, command_prefix="nom!", intents=nextcord.Intents.all()) + super().__init__(shard_count=1, command_prefix="nom!") self.unloaded_cogs = [] def initialize(self): diff --git a/cogs/error_handler.py b/cogs/error_handler.py new file mode 100644 index 0000000..85f4e3b --- /dev/null +++ b/cogs/error_handler.py @@ -0,0 +1,24 @@ +import nextcord +from cooldowns import CallableOnCooldown +from nextcord.ext import commands, application_checks +from bot.bot import Bot +from nextcord.errors import Forbidden +from utils import * +import time + +class Error_handler(commands.Cog): + def init(self, client: Bot): + self.client = client + + @commands.Cog.listener() + async def on_application_command_error(self, interaction:nextcord.Interaction, error): + error = getattr(error, "original", error) + if isinstance(error, CallableOnCooldown): + await interaction.send(f"That command is on cooldown. You can use it again ") + elif isinstance(error, Forbidden): + await interaction.send(f"I don't have permission to do that") + else: + raise error + +def setup(client: Bot): + client.add_cog(Error_handler(client)) \ No newline at end of file diff --git a/cogs/misc.py b/cogs/misc.py index 4944414..a013a03 100644 --- a/cogs/misc.py +++ b/cogs/misc.py @@ -72,5 +72,12 @@ async def shardinfo(self, interaction:Interaction): await interaction.send(f"This server's shard is shard **{guild_shard+1}** with `{round(guildspecshard.latency*100)}ms` and `{guild_shard_servers} servers`", embed=nextcord.Embed(title=f"Simple Verification Shard Information", description=f"All current shards:\n {description}", colour=COLOUR_MAIN)) + @nextcord.slash_command(name=f"debug", description=f"Get information useful for debugging") + @cooldowns.cooldown(1,10, bucket=cooldowns.SlashBucket.channel) + async def _debug(self, interaction:Interaction): + await interaction.response.defer() + await interaction.send(f"**Guild ID:** {interaction.guild.id}\n**Channel ID:** {interaction.channel.id}") + + def setup(client: commands.Bot): client.add_cog(Misc(client)) \ No newline at end of file From bc24f56158731dce43ec37c96d3da31d7a0d78ff Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Tue, 12 Sep 2023 22:21:31 +0100 Subject: [PATCH 25/35] fixed issues with `/dashboard` and started more --- cogs/dashboard.py | 10 +- cogs/premium.py | 4 +- views/dashboard_views.py | 204 +++++++++++++++++++++++---------------- views/length_modal.py | 2 +- 4 files changed, 130 insertions(+), 90 deletions(-) diff --git a/cogs/dashboard.py b/cogs/dashboard.py index bcea69c..561441a 100644 --- a/cogs/dashboard.py +++ b/cogs/dashboard.py @@ -11,7 +11,7 @@ def __init__(self, client: commands.Bot): @nextcord.slash_command(name=f"dashboard", description=f"Configure the bot on the in-discord dashboard") async def dashboard(self, interaction: Interaction): - interaction.response.defer(with_message=True, ephemeral=True) + await interaction.response.defer(with_message=True, ephemeral=True) if not interaction.user.guild_permissions.administrator: await interaction.send(embed=create_warning_embed(title="Insufficient permissions", description="You need the `administrator` permission to use this.")) return @@ -23,10 +23,10 @@ async def dashboard(self, interaction: Interaction): if not data: cur.execute(f"INSERT INTO guild_configs (id) VALUES ('{interaction.guild.id}')") conn.commit() - - embed = generate_dashboard(data=data) - view = DashboardButtons(premium=check_premium(self, guild = True, user = False, type_id=interaction.guild.id)) - await interaction.send(embed=embed, view=view, ephemeral=True) + msg = await interaction.send("Generating Dashboard...", ephemeral=True) + embed = generate_dashboard(self, data=data) + view = DashboardButtons(msg, premium=check_premium(self, guild = True, user = False, type_id=interaction.guild.id)) + await msg.edit(content="", embed=embed, view=view) diff --git a/cogs/premium.py b/cogs/premium.py index 6ea71f4..a33e660 100644 --- a/cogs/premium.py +++ b/cogs/premium.py @@ -45,12 +45,12 @@ async def manage_premium_add_server(self, interaction: Interaction, return try: - guild = self.get_guild(int(guildid)) + guild = self.client.get_guild(int(guildid)) except: await interaction.send(embed=create_error_embed(title=f"Invalid guild ID", description=f"You have given an invalid guild ID. Please use the `/debug` command in the guild you want to add premium to to get the correct guild ID.")) return - cur.execute("INSERT INTO sv_premium_guilds VALUES (user_id, guild_id) SET (%s, %s)", (interaction.user.id, guildid)) + cur.execute("INSERT INTO sv_premium_guilds (user_id, guild_id) VALUES (%s, %s)", (str(interaction.user.id), guildid)) conn.commit() await interaction.send(embed=create_success_embed(title=f"Premium server added", description=f"You have succesfully given `{guild.name} ({guild.id})` to your premium subscription.")) diff --git a/views/dashboard_views.py b/views/dashboard_views.py index b16f1db..29bd643 100644 --- a/views/dashboard_views.py +++ b/views/dashboard_views.py @@ -1,4 +1,4 @@ -import nextcord, pymysql +import nextcord, pymysql, asyncio from nextcord.interactions import Interaction from utils import DBENDPOINT, DBNAME, DBPASS, DBUSER, COLOUR_MAIN, create_error_embed, DISCORDLINK, create_success_embed, PREMIUMLINK, generate_dashboard from nextcord import Interaction @@ -7,13 +7,51 @@ class AutoVerificationButton(nextcord.ui.Button): - def __init__(self, premium: bool = False): + def __init__(self, msg, premium: bool = False): if premium: super().__init__(label="Toggle Auto Verification", style=nextcord.ButtonStyle.blurple, disabled=False) else: super().__init__(label="Toggle Auto Verification", style=nextcord.ButtonStyle.blurple, disabled=True) + self.msg = msg async def callback(self, interaction: Interaction): + await interaction.response.defer(with_message=True, ephemeral=True) + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + data = cur.fetchall() + if not data: + await interaction.send(embed=create_error_embed(title="Error!", description=f"Failed to fetch your guild data, please report this in our [Support Server]({DISCORDLINK})"), view=None) + conn.commit() + self.stop() + return + + if data[0][6] == "no": + cur.execute(f"UPDATE `guild_configs` SET autoveri = 'enabled' WHERE id='{interaction.guild.id}'") + embed = create_success_embed(title="Success", description="Successfully enabled autoverification.") + else: + cur.execute(f"UPDATE `guild_configs` SET autoveri = 'no' WHERE id='{interaction.guild.id}'") + embed = create_success_embed(title="Success", description="Successfully disabled autoverification.") + + conn.commit() + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + dataa = cur.fetchall() + eembed = generate_dashboard(self, data=dataa) + await self.msg.edit(embed=eembed) + await interaction.send(embed=create_success_embed(title="Success", description="Successfully updated your auto verification setting."), ephemeral=True) + +class AutoVerificationButton(nextcord.ui.Button): + def __init__(self, msg, premium: bool = False): + if premium: + super().__init__(label="Set Min Captcha Length", style=nextcord.ButtonStyle.blurple, disabled=False) + else: + super().__init__(label="Set Min Captcha Length", style=nextcord.ButtonStyle.blurple, disabled=True) + self.msg = msg + + async def callback(self, interaction: Interaction): + await interaction.response.defer(with_message=True, ephemeral=True) conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) cur = conn.cursor() cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") @@ -36,16 +74,17 @@ async def callback(self, interaction: Interaction): cur = conn.cursor() cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") dataa = cur.fetchall() - eembed = generate_dashboard(data=dataa) - await interaction.message.edit(embed=eembed) - await interaction.send(embed=create_success_embed(title="Success", description="Successfully updated verification roles."), view=None) + eembed = generate_dashboard(self, data=dataa) + await self.msg.edit(embed=eembed) + await interaction.send(embed=create_success_embed(title="Success", description="Successfully updated your auto verification setting."), ephemeral=True) class DashboardButtons(nextcord.ui.View): - def __init__(self, premium: bool = False): + def __init__(self, msg, premium: bool = False): super().__init__(timeout=300) self.premium = premium - self.add_item(AutoVerificationButton(premium=premium)) + self.msg = msg + self.add_item(AutoVerificationButton(msg = msg, premium=premium)) @nextcord.ui.button(label="Set Verification Roles", style=nextcord.ButtonStyle.blurple, disabled=False) async def set_verification_role(self, button: nextcord.ui.Button, interaction: Interaction): @@ -77,13 +116,15 @@ async def set_verification_role(self, button: nextcord.ui.Button, interaction: I cur.execute(f"UPDATE `guild_configs` SET verifyrole = '{ids}' WHERE id='{interaction.guild.id}'") conn.commit() + await asyncio.sleep(0.3) + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) cur = conn.cursor() cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") dataa = cur.fetchall() - embed = generate_dashboard(data=dataa) - await interaction.message.edit(embed=embed) + embed = generate_dashboard(self, data=dataa) + await self.msg.edit(embed=embed) await msg.edit(embed=create_success_embed(title="Success", description="Successfully updated verification roles."), view=None) @nextcord.ui.button(label="Set Unverified Roles", style=nextcord.ButtonStyle.blurple, disabled=False) @@ -121,81 +162,80 @@ async def set_unverified_role(self, button: nextcord.ui.Button, interaction: Int cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") dataa = cur.fetchall() - embed = generate_dashboard(data=dataa) - await interaction.message.edit(embed=embed) + embed = generate_dashboard(self, data=dataa) + await self.msg.edit(embed=embed) await msg.edit(embed=create_success_embed(title="Success", description="Successfully updated unverified roles."), view=None) - @nextcord.ui.button(label="Set Log Channel", style=nextcord.ButtonStyle.blurple, disabled=False) - async def set_log_channel(self, button: nextcord.ui.Button, interaction: Interaction): - await interaction.response.defer(with_message=True, ephemeral=True) - - embed = nextcord.Embed(title="Select Log Channel", description="Select the channel you want logs to be sent in. \nYou can select `1` channel.", color=COLOUR_MAIN) - cselect = ChannelSelect(minvalue=1, maxvalue=1, text="Select a Channel") - msg = await interaction.send(embed=embed, view=cselect) - await cselect.wait() - conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) - cur = conn.cursor() - cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") - data = cur.fetchall() - if not data: - await msg.edit(embed=create_error_embed(title="Error!", description=f"Failed to fetch your guild data, please report this in our [Support Server]({DISCORDLINK})"), view=None) - conn.commit() - self.stop() - return - - if cselect.values: - id = cselect.values[0] - else: - id = None - - cur.execute(f"UPDATE `guild_configs` SET logchannel = '{id}' WHERE id='{interaction.guild.id}'") + @nextcord.ui.button(label="Set Log Channel", style=nextcord.ButtonStyle.blurple, disabled=False) + async def set_log_channel(self, button: nextcord.ui.Button, interaction: Interaction): + await interaction.response.defer(with_message=True, ephemeral=True) + + embed = nextcord.Embed(title="Select Log Channel", description="Select the channel you want logs to be sent in. \nYou can select `1` channel.", color=COLOUR_MAIN) + cselect = ChannelSelect(minvalue=1, maxvalue=1, text="Select a Channel") + msg = await interaction.send(embed=embed, view=cselect) + await cselect.wait() + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + data = cur.fetchall() + if not data: + await msg.edit(embed=create_error_embed(title="Error!", description=f"Failed to fetch your guild data, please report this in our [Support Server]({DISCORDLINK})"), view=None) conn.commit() - - conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) - cur = conn.cursor() - cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") - dataa = cur.fetchall() - - embed = generate_dashboard(data=dataa) - await interaction.message.edit(embed=embed) - await msg.edit(embed=create_success_embed(title="Success", description="Successfully updated log channel."), view=None) - - @nextcord.ui.button(label="Set Autokick Account Age", style=nextcord.ButtonStyle.blurple, disabled=False) - async def set_autokick_account_age(self, button: nextcord.ui.Button, interaction: Interaction): - await interaction.response.defer(with_message=True, ephemeral=True) - form = LengthModal() - await interaction.response.send_modal(modal=form) - await form.wait() - - conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) - cur = conn.cursor() - cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") - data = cur.fetchall() - if not data: - await interaction.send(embed=create_error_embed(title="Error!", description=f"Failed to fetch your guild data, please report this in our [Support Server]({DISCORDLINK})"), view=None) - conn.commit() - self.stop() - return - - try: - length = int(form.age) - except: - await interaction.send(embed=create_error_embed(title="Error", description="An invalid duration was supplied, the duration must be a whole positive number")) - return - - if length < 0: - await interaction.send(embed=create_error_embed(title="Error", description="An invalid duration was supplied, the duration must be a whole positive number")) - return - - cur.execute(f"UPDATE `guild_configs` SET autokick = '{length}' WHERE id='{interaction.guild.id}'") + self.stop() + return + + if cselect.values: + id = cselect.values[0] + else: + id = None + + cur.execute(f"UPDATE `guild_configs` SET logchannel = '{id.id}' WHERE id='{interaction.guild.id}'") + conn.commit() + + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + dataa = cur.fetchall() + + embed = generate_dashboard(self, data=dataa) + await self.msg.edit(embed=embed) + await msg.edit(embed=create_success_embed(title="Success", description="Successfully updated log channel."), view=None) + + @nextcord.ui.button(label="Set Autokick Account Age", style=nextcord.ButtonStyle.blurple, disabled=False) + async def set_autokick_account_age(self, button: nextcord.ui.Button, interaction: Interaction): + form = LengthModal() + await interaction.response.send_modal(modal=form) + await form.wait() + + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + data = cur.fetchall() + if not data: + await interaction.send(embed=create_error_embed(title="Error!", description=f"Failed to fetch your guild data, please report this in our [Support Server]({DISCORDLINK})"), view=None, ephemeral=True) conn.commit() - - conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) - cur = conn.cursor() - cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") - dataa = cur.fetchall() - - embed = generate_dashboard(data=dataa) - await interaction.message.edit(embed=embed) - await interaction.send(embed=create_success_embed(title="Success", description="Successfully updated log channel."), view=None) \ No newline at end of file + self.stop() + return + + try: + length = int(form.age) + except: + await interaction.send(embed=create_error_embed(title="Error", description="An invalid duration was supplied, the duration must be a whole positive number"), ephemeral=True) + return + + if length < 0: + await interaction.send(embed=create_error_embed(title="Error", description="An invalid duration was supplied, the duration must be a whole positive number"), ephemeral=True) + return + + cur.execute(f"UPDATE `guild_configs` SET autokick = '{length}' WHERE id='{interaction.guild.id}'") + conn.commit() + + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + dataa = cur.fetchall() + + embed = generate_dashboard(self, data=dataa) + await self.msg.edit(embed=embed) + await interaction.send(embed=create_success_embed(title="Success", description="Successfully updated log channel."), ephemeral=True) \ No newline at end of file diff --git a/views/length_modal.py b/views/length_modal.py index 65b2122..45b7278 100644 --- a/views/length_modal.py +++ b/views/length_modal.py @@ -7,7 +7,7 @@ def __init__(self): super().__init__(title="Set account age", timeout=None) self.length = nextcord.ui.TextInput( - label = "How old do you want accounts to have to be (days)", + label = "How old should accounts be (in days)", placeholder = "To disable autokick put 0", style=nextcord.TextInputStyle.short, min_length=1, From a5d2b78403e887ae971ab05fe0fc650b12dc4dd0 Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Wed, 13 Sep 2023 18:50:09 +0100 Subject: [PATCH 26/35] Finished Premium --- cogs/premium.py | 81 ++++++++++++++++++++++++++---- cogs/verify.py | 28 +++++++++++ utils/utils.py | 2 +- views/dashboard_views.py | 106 ++++++++++++++++++++++++++++++++++----- views/length_modal.py | 19 +++++++ 5 files changed, 213 insertions(+), 23 deletions(-) create mode 100644 cogs/verify.py diff --git a/cogs/premium.py b/cogs/premium.py index a33e660..23cccf0 100644 --- a/cogs/premium.py +++ b/cogs/premium.py @@ -2,7 +2,7 @@ import pymysql from nextcord.ext import commands, tasks from nextcord import Interaction, SlashOption -from utils import check_premium, create_error_embed, create_warning_embed, create_success_embed, PREMIUMLINK, DBENDPOINT, DBUSER, DBPASS, DBNAME +from utils import check_premium, create_error_embed, create_warning_embed, create_success_embed, PREMIUMLINK, DBENDPOINT, DBUSER, DBPASS, DBNAME, COLOUR_MAIN class Premium(commands.Cog): def __init__(self, client: commands.Bot): @@ -50,25 +50,86 @@ async def manage_premium_add_server(self, interaction: Interaction, await interaction.send(embed=create_error_embed(title=f"Invalid guild ID", description=f"You have given an invalid guild ID. Please use the `/debug` command in the guild you want to add premium to to get the correct guild ID.")) return + if guild is None: + await interaction.send(embed=create_error_embed(title=f"Invalid guild ID", description=f"You have given an invalid guild ID. Please use the `/debug` command in the guild you want to add premium to to get the correct guild ID.")) + return + cur.execute("INSERT INTO sv_premium_guilds (user_id, guild_id) VALUES (%s, %s)", (str(interaction.user.id), guildid)) conn.commit() - await interaction.send(embed=create_success_embed(title=f"Premium server added", description=f"You have succesfully given `{guild.name} ({guild.id})` to your premium subscription.")) + await interaction.send(embed=create_success_embed(title=f"Premium server added", description=f"You have succesfully added `{guild.name} ({guild.id})` to your premium subscription.")) + + @manage_premium.subcommand(name=f"remove-server", description=f"Remove a server from your premium subscription") + async def manage_premium_remove_server(self, interaction: Interaction, + guildid: str = SlashOption( + name=f"guild", + description=f"The ID of the guild to remove from premium. Use /debug in your server to get this.", + required = True + )): + await interaction.response.defer() + if not check_premium(self, False, True, interaction.user.id): + await interaction.send(embed=create_error_embed(title=f"No premium subscription", description=f"You are not currently subscribed to any of our premium subscriptions. To purchase premium please follow [this link]({PREMIUMLINK})\n\n\nPlease Note: If you recently subscribed to premium it may take up to 30 minutes to register your subscription. If you are still unable to use this command in 30 minutes, please create a ticket in <#1111392014529990656>")) + return + + if not check_premium(self, True, False, guildid): + await interaction.send(embed=create_warning_embed(title=f"Guild not added", description=f"This guild is not currently added to your premium subscription.")) + return + + try: + guild = self.client.get_guild(int(guildid)) + except: + guild = "Unknown" + if guild is None: + guild = "Unknown" + + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute("DELETE FROM sv_premium_guilds WHERE user_id=%s AND guild_id=%s", (str(interaction.user.id), guildid)) + conn.commit() + await interaction.send(embed=create_success_embed(title=f"Premium server removed", description=f"You have succesfully removed `{guild.name if not guild == 'Unknown' else 'Unknown'} ({guildid})` from your premium subscription.")) + @manage_premium.subcommand(name=f"view", description=f"View your current premium subscription") + async def manage_premium_view(self, interaction: Interaction): + await interaction.response.defer() + if not check_premium(self, False, True, interaction.user.id): + await interaction.send(embed=create_error_embed(title=f"No premium subscription", description=f"You are not currently subscribed to any of our premium subscriptions. To purchase premium please follow [this link]({PREMIUMLINK})\n\n\nPlease Note: If you recently subscribed to premium it may take up to 30 minutes to register your subscription. If you are still unable to use this command in 30 minutes, please create a ticket in <#1111392014529990656>")) + return + + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute("SELECT * FROM sv_premium_users WHERE user_id = %s", (interaction.user.id)) + data = cur.fetchall() + + servers_available = int(data[0][1]) + + cur.execute("SELECT * FROM sv_premium_guilds WHERE user_id = %s", (interaction.user.id)) + data = cur.fetchall() + + servers_used = data - @tasks.loop(minutes=5) - async def premium_manager(self): premium_role_ids = [1130511638794080419, 1130520156477608036, 1130520224689557554, 1130520278850613369, 1130520336744591431] # ACTUAL IDS = [1130511638794080419, 1130520156477608036, 1130520224689557554, 1130520278850613369, 1130520336744591431] - guild = self.get_guild(1111387758028652657) # ACTUAL ID = 1111387758028652657 - premium_roles = [].append([role for role in guild.get_role([roleid for roleid in premium_role_ids])]) + guild = self.client.get_guild(1111387758028652657) # ACTUAL ID = 1111387758028652657 + premium_roles = [guild.get_role(roleid) for roleid in premium_role_ids] + + user_premium_role = None + + for role in interaction.user.roles: + if role in premium_roles: + user_premium_role = role + embed=nextcord.Embed(title=f"Your premium subscription", description=f"Subscription: **{user_premium_role.name}**\nServers (Used Servers/Available Servers): **{len(servers_used)}/{servers_available}**", colour=COLOUR_MAIN) + servers_using = "" - print(premium_roles) + for serverid in servers_used: + try: + guild = self.client.get_guild(int(serverid[1])) + servers_using += f"**{guild.name}** ({guild.id})\n" + except: + servers_using += f"**Unknown** ({serverid[1]})" + embed.add_field(name=f"Servers", value=f"{servers_using}") + await interaction.send(embed=embed) - for member in guild.members: - if premium_role_ids in member.roles: - pass def setup(client: commands.Bot): client.add_cog(Premium(client)) \ No newline at end of file diff --git a/cogs/verify.py b/cogs/verify.py new file mode 100644 index 0000000..f529cfd --- /dev/null +++ b/cogs/verify.py @@ -0,0 +1,28 @@ +import nextcord +from nextcord.ext import commands +from nextcord import Interaction +from utils import check_premium, DBENDPOINT, DBNAME, DBPASS, DBUSER, generate_dashboard, create_warning_embed +from views import DashboardButtons +import pymysql + +class Verify(commands.Cog): + def __init__(self, client: commands.Bot): + self.client = client + + @nextcord.slash_command() + async def verify(self, interaction: Interaction): + if not interaction.user.guild_permissions.administrator: + await interaction.send(embed=create_warning_embed(title="Insufficient permissions", description="You need the `administrator` permission to use this.")) + return + + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + data = cur.fetchall() + if not data: + cur.execute(f"INSERT INTO guild_configs (id) VALUES ('{interaction.guild.id}')") + conn.commit() + + +def setup(client): + client.add_cog(Verify(client)) \ No newline at end of file diff --git a/utils/utils.py b/utils/utils.py index 45ae294..dcaf3b0 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -35,7 +35,7 @@ def generate_dashboard(self, data): autov = "Disabled" else: autov = "Enabled" - return nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][1].split(",")])) if data[0][1] else 'Not Set'}\nUnverified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][2].split(",")])) if data[0][2] else 'Not Set'} \nLog Channel: <#{data[0][3] if data[0][3] else 'Not Set'}> \nAuto Kick: {f"{data[0][5]} day(s)" if data[0][5] else 'Not Set'} \nAuto Verification ([Premium]({PREMIUMLINK}) Only): {autov}""") + return nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][1].split(",")])) if data[0][1] else 'Not Set'}\nUnverified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][2].split(",")])) if data[0][2] else 'Not Set'} \nLog Channel: <#{data[0][3] if data[0][3] else 'Not Set'}> \nAuto Kick: {f"{data[0][5]} day(s)" if data[0][5] else 'Not Set'} \nAuto Verification ([Premium]({PREMIUMLINK}) Only): {autov}\nMinimum Captcha Length ([Premium]({PREMIUMLINK}) Only): {data[0][7]}\nMaximum Captcha Length ([Premium]({PREMIUMLINK}) Only): {data[0][8]}""") def totalxp_to_level(total_xp): diff --git a/views/dashboard_views.py b/views/dashboard_views.py index 29bd643..eb3d97c 100644 --- a/views/dashboard_views.py +++ b/views/dashboard_views.py @@ -3,7 +3,7 @@ from utils import DBENDPOINT, DBNAME, DBPASS, DBUSER, COLOUR_MAIN, create_error_embed, DISCORDLINK, create_success_embed, PREMIUMLINK, generate_dashboard from nextcord import Interaction from .role_select import RoleSelect, ChannelSelect -from .length_modal import LengthModal +from .length_modal import LengthModal, CaptchaLengthModal class AutoVerificationButton(nextcord.ui.Button): @@ -42,7 +42,7 @@ async def callback(self, interaction: Interaction): await self.msg.edit(embed=eembed) await interaction.send(embed=create_success_embed(title="Success", description="Successfully updated your auto verification setting."), ephemeral=True) -class AutoVerificationButton(nextcord.ui.Button): +class MinLengthButton(nextcord.ui.Button): def __init__(self, msg, premium: bool = False): if premium: super().__init__(label="Set Min Captcha Length", style=nextcord.ButtonStyle.blurple, disabled=False) @@ -51,7 +51,6 @@ def __init__(self, msg, premium: bool = False): self.msg = msg async def callback(self, interaction: Interaction): - await interaction.response.defer(with_message=True, ephemeral=True) conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) cur = conn.cursor() cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") @@ -62,21 +61,102 @@ async def callback(self, interaction: Interaction): self.stop() return - if data[0][6] == "no": - cur.execute(f"UPDATE `guild_configs` SET autoveri = 'enabled' WHERE id='{interaction.guild.id}'") - embed = create_success_embed(title="Success", description="Successfully enabled autoverification.") + form = CaptchaLengthModal() + await interaction.response.send_modal(modal=form) + await form.wait() + + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + data = cur.fetchall() + if not data: + await interaction.send(embed=create_error_embed(title="Error!", description=f"Failed to fetch your guild data, please report this in our [Support Server]({DISCORDLINK})"), view=None, ephemeral=True) + conn.commit() + self.stop() + return + + try: + length = int(form.captcha_length) + except: + await interaction.send(embed=create_error_embed(title="Error", description="An invalid captcha length was supplied, the captcha length must be a whole positive number"), ephemeral=True) + return + + if length < 1: + await interaction.send(embed=create_error_embed(title="Error", description="An invalid captcha length was supplied, the captcha length must be a whole positive number. (Minimum of 1)"), ephemeral=True) + return + elif length > 12: + await interaction.send(embed=create_error_embed(title="Error", description="An invalid captcha length was supplied, the captcha length must be a whole positive number. (Maximum of 12)"), ephemeral=True) + return + + cur.execute(f"UPDATE `guild_configs` SET min_captcha_len = '{length}' WHERE id='{interaction.guild.id}'") + conn.commit() + + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + dataa = cur.fetchall() + + embed = generate_dashboard(self, data=dataa) + await self.msg.edit(embed=embed) + await interaction.send(embed=create_success_embed(title="Success", description="Successfully updated minimum captcha length."), ephemeral=True) + +class MaxLengthButton(nextcord.ui.Button): + def __init__(self, msg, premium: bool = False): + if premium: + super().__init__(label="Set Max Captcha Length", style=nextcord.ButtonStyle.blurple, disabled=False) else: - cur.execute(f"UPDATE `guild_configs` SET autoveri = 'no' WHERE id='{interaction.guild.id}'") - embed = create_success_embed(title="Success", description="Successfully disabled autoverification.") + super().__init__(label="Set Max Captcha Length", style=nextcord.ButtonStyle.blurple, disabled=True) + self.msg = msg + + async def callback(self, interaction: Interaction): + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + data = cur.fetchall() + if not data: + await interaction.send(embed=create_error_embed(title="Error!", description=f"Failed to fetch your guild data, please report this in our [Support Server]({DISCORDLINK})"), view=None) + conn.commit() + self.stop() + return + + form = CaptchaLengthModal() + await interaction.response.send_modal(modal=form) + await form.wait() + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + data = cur.fetchall() + if not data: + await interaction.send(embed=create_error_embed(title="Error!", description=f"Failed to fetch your guild data, please report this in our [Support Server]({DISCORDLINK})"), view=None, ephemeral=True) + conn.commit() + self.stop() + return + + try: + length = int(form.captcha_length) + except: + await interaction.send(embed=create_error_embed(title="Error", description="An invalid captcha length was supplied, the captcha length must be a whole positive number"), ephemeral=True) + return + + if length < 1: + await interaction.send(embed=create_error_embed(title="Error", description="An invalid captcha length was supplied, the captcha length must be a whole positive number. (Minimum of 1)"), ephemeral=True) + return + elif length > 12: + await interaction.send(embed=create_error_embed(title="Error", description="An invalid captcha length was supplied, the captcha length must be a whole positive number. (Maximum of 12)"), ephemeral=True) + return + + cur.execute(f"UPDATE `guild_configs` SET max_captcha_len = '{length}' WHERE id='{interaction.guild.id}'") conn.commit() + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) cur = conn.cursor() cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") dataa = cur.fetchall() - eembed = generate_dashboard(self, data=dataa) - await self.msg.edit(embed=eembed) - await interaction.send(embed=create_success_embed(title="Success", description="Successfully updated your auto verification setting."), ephemeral=True) + + embed = generate_dashboard(self, data=dataa) + await self.msg.edit(embed=embed) + await interaction.send(embed=create_success_embed(title="Success", description="Successfully updated maximum captcha length."), ephemeral=True) class DashboardButtons(nextcord.ui.View): @@ -85,6 +165,8 @@ def __init__(self, msg, premium: bool = False): self.premium = premium self.msg = msg self.add_item(AutoVerificationButton(msg = msg, premium=premium)) + self.add_item(MinLengthButton(msg = msg, premium=premium)) + self.add_item(MaxLengthButton(msg = msg, premium=premium)) @nextcord.ui.button(label="Set Verification Roles", style=nextcord.ButtonStyle.blurple, disabled=False) async def set_verification_role(self, button: nextcord.ui.Button, interaction: Interaction): @@ -238,4 +320,4 @@ async def set_autokick_account_age(self, button: nextcord.ui.Button, interaction embed = generate_dashboard(self, data=dataa) await self.msg.edit(embed=embed) - await interaction.send(embed=create_success_embed(title="Success", description="Successfully updated log channel."), ephemeral=True) \ No newline at end of file + await interaction.send(embed=create_success_embed(title="Success", description="Successfully updated autokick minimum account age."), ephemeral=True) \ No newline at end of file diff --git a/views/length_modal.py b/views/length_modal.py index 45b7278..8e0857f 100644 --- a/views/length_modal.py +++ b/views/length_modal.py @@ -19,4 +19,23 @@ def __init__(self): async def callback(self, interaction: nextcord.Interaction): self.age = self.length.value + self.stop() + +class CaptchaLengthModal(nextcord.ui.Modal): + def __init__(self): + super().__init__(title="Set captcha limitation", timeout=None) + + self.length = nextcord.ui.TextInput( + label = "What do you want to set the captcha limit to?", + placeholder = "", + style=nextcord.TextInputStyle.short, + min_length=1, + max_length=3, + required=True + ) + + self.add_item(self.length) + + async def callback(self, interaction: nextcord.Interaction): + self.captcha_length = self.length.value self.stop() \ No newline at end of file From 7629d916176af802bfe4a4f91530e6709ea8778f Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Sun, 24 Sep 2023 12:57:44 +0100 Subject: [PATCH 27/35] Started base for verify button --- cogs/verify.py | 17 +++++++++++++---- views/__init__.py | 3 ++- views/verify_button.py | 21 +++++++++++++++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 views/verify_button.py diff --git a/cogs/verify.py b/cogs/verify.py index f529cfd..3a8e4d0 100644 --- a/cogs/verify.py +++ b/cogs/verify.py @@ -2,12 +2,12 @@ from nextcord.ext import commands from nextcord import Interaction from utils import check_premium, DBENDPOINT, DBNAME, DBPASS, DBUSER, generate_dashboard, create_warning_embed -from views import DashboardButtons +from views import DashboardButtons, VerifyButton import pymysql class Verify(commands.Cog): - def __init__(self, client: commands.Bot): - self.client = client + def __init__(self, client: commands.Bot): + self.client = client @nextcord.slash_command() async def verify(self, interaction: Interaction): @@ -23,6 +23,15 @@ async def verify(self, interaction: Interaction): cur.execute(f"INSERT INTO guild_configs (id) VALUES ('{interaction.guild.id}')") conn.commit() + @commands.Cog.listener() + async def on_ready(self): + try: + self.client.add_view(VerifyButton(self.client)) + print("Loaded VerifyButton view") + except Exception as e: + print(e) + print("Failed to load VerifyButton view") + def setup(client): - client.add_cog(Verify(client)) \ No newline at end of file + client.add_cog(Verify(client)) \ No newline at end of file diff --git a/views/__init__.py b/views/__init__.py index 09c5ef8..9583af2 100644 --- a/views/__init__.py +++ b/views/__init__.py @@ -1,4 +1,5 @@ from .link_button import * from .dashboard_views import * from .role_select import * -from .length_modal import * \ No newline at end of file +from .length_modal import * +from .verify_button import * \ No newline at end of file diff --git a/views/verify_button.py b/views/verify_button.py new file mode 100644 index 0000000..a697ef0 --- /dev/null +++ b/views/verify_button.py @@ -0,0 +1,21 @@ +import nextcord +from nextcord.interactions import Interaction +from nextcord import Interaction +from utils.constants import PRIVACYLINK + +class VerifyButton(nextcord.ui.View): + def __init__(self, client): + self.client = client + super().__init__(timeout=None) + self.add_item(nextcord.ui.Button(label="Privacy Policy", url=PRIVACYLINK)) + + @nextcord.ui.button(label="Verify", style=nextcord.ButtonStyle.green, disabled=False) + async def verify_button(self, button: nextcord.ui.Button, interaction: Interaction): + pass + + + + + + + From a05f018c92fa2aaaf64636f25e322158d0b654fa Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Tue, 26 Sep 2023 17:22:35 +0100 Subject: [PATCH 28/35] Added `/verifymessage` --- cogs/verify.py | 40 +++++++++++++++++++++++++++++++++++----- views/__init__.py | 3 ++- views/embed_creator.py | 31 +++++++++++++++++++++++++++++++ views/verify_button.py | 2 +- 4 files changed, 69 insertions(+), 7 deletions(-) create mode 100644 views/embed_creator.py diff --git a/cogs/verify.py b/cogs/verify.py index 3a8e4d0..3bb9ee9 100644 --- a/cogs/verify.py +++ b/cogs/verify.py @@ -1,16 +1,30 @@ import nextcord from nextcord.ext import commands -from nextcord import Interaction -from utils import check_premium, DBENDPOINT, DBNAME, DBPASS, DBUSER, generate_dashboard, create_warning_embed -from views import DashboardButtons, VerifyButton +from nextcord import Interaction, SlashOption +from nextcord.abc import GuildChannel +from utils import check_premium, DBENDPOINT, DBNAME, DBPASS, DBUSER, generate_dashboard, create_warning_embed, COLOUR_MAIN, create_success_embed, create_error_embed +from views import DashboardButtons, VerifyButton, EmbedCreator import pymysql class Verify(commands.Cog): def __init__(self, client: commands.Bot): self.client = client - @nextcord.slash_command() - async def verify(self, interaction: Interaction): + @nextcord.slash_command(name=f"verifymessage", description=f"Send a verification message to a channel") + async def verifymessage(self, + interaction: Interaction, + channel: GuildChannel = SlashOption( + name=f"channel", + description=f"The channel you want to send the verification message to", + channel_types=[nextcord.ChannelType.text, nextcord.ChannelType.news], + required=True + ), + customembed: str = SlashOption( + name=f"custom-embed", + description=f"Do you want to customise the embed sent to the verification channel?", + choices={"Yes, I want to customise the embed": "True", "No, I don't want to customise the embed":"False"}, + required=False + )): if not interaction.user.guild_permissions.administrator: await interaction.send(embed=create_warning_embed(title="Insufficient permissions", description="You need the `administrator` permission to use this.")) return @@ -23,6 +37,22 @@ async def verify(self, interaction: Interaction): cur.execute(f"INSERT INTO guild_configs (id) VALUES ('{interaction.guild.id}')") conn.commit() + embed=nextcord.Embed(title=f"Verification", description=f"To verify in the server press the button below and follow the instructions from there.", colour=COLOUR_MAIN) + + if customembed == "True": + options = EmbedCreator() + await interaction.response.send_modal(modal=options) + await options.wait() + embed=nextcord.Embed(title=options.embedtitle, description=options.embdeddesc, colour=COLOUR_MAIN) + + try: + await channel.send(embed=embed, view=VerifyButton(self.client)) + await interaction.send(embed=create_success_embed(title=f"Message sent!", description=f"I have sent your verification message to {channel.mention}")) + except: + interaction.send(embed=create_error_embed(title=f"Error sending verification message!", description=f"I was unable to send the verification message to {channel.mention}. Ensure I have permission to `send_messages` and `embed_links` in {channel.mention}")) + + + @commands.Cog.listener() async def on_ready(self): try: diff --git a/views/__init__.py b/views/__init__.py index 9583af2..346b2b8 100644 --- a/views/__init__.py +++ b/views/__init__.py @@ -2,4 +2,5 @@ from .dashboard_views import * from .role_select import * from .length_modal import * -from .verify_button import * \ No newline at end of file +from .verify_button import * +from .embed_creator import * \ No newline at end of file diff --git a/views/embed_creator.py b/views/embed_creator.py new file mode 100644 index 0000000..914350f --- /dev/null +++ b/views/embed_creator.py @@ -0,0 +1,31 @@ +import nextcord, pymysql +from nextcord.ext import commands + +class EmbedCreator(nextcord.ui.Modal): + def __init__(self): + super().__init__(title=f"Embed Creator", timeout=600) + self.embedtitle = nextcord.ui.TextInput( + label="What do you want the embed title to be?", + placeholder=f"You can use up to 256 characters here!", + style=nextcord.TextInputStyle.short, + min_length=1, + max_length=256, + required=True + ) + self.embeddesc = nextcord.ui.TextInput( + label=f"What do you want the embed description to be?", + placeholder=f"Tip: To mention channels dp <#channel_id> (e.g. <#1111390004783091762>)", + style=nextcord.TextInputStyle.paragraph, + min_length=0, + max_length=4000, + required=False + ) + + self.add_item(self.embedtitle) + self.add_item(self.embeddesc) + + + async def callback(self, interaction:nextcord.Interaction): + self.embedtitle = self.embedtitle.value + self.embeddesc = self.embeddesc.value + self.stop() \ No newline at end of file diff --git a/views/verify_button.py b/views/verify_button.py index a697ef0..59de1a0 100644 --- a/views/verify_button.py +++ b/views/verify_button.py @@ -9,7 +9,7 @@ def __init__(self, client): super().__init__(timeout=None) self.add_item(nextcord.ui.Button(label="Privacy Policy", url=PRIVACYLINK)) - @nextcord.ui.button(label="Verify", style=nextcord.ButtonStyle.green, disabled=False) + @nextcord.ui.button(label="Verify", style=nextcord.ButtonStyle.green, disabled=False, custom_id="verify_button") async def verify_button(self, button: nextcord.ui.Button, interaction: Interaction): pass From d199e820d0c261bd752103a3e7f6569e5a59e045 Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Tue, 26 Sep 2023 18:01:06 +0100 Subject: [PATCH 29/35] Update utils.py --- utils/utils.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/utils/utils.py b/utils/utils.py index dcaf3b0..6c36b49 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -17,7 +17,7 @@ def create_error_embed(title: str = "\u200b", description: str = "\u200b"): embed.set_thumbnail(url="https://media.tenor.com/Gbp8h-dqDHkAAAAi/error.gif") return embed -def check_premium(self, guild: bool, user: bool, type_id: str): +def check_premium(self, guild: bool, user: bool, type_id: str) -> bool: conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) cur = conn.cursor() if guild: @@ -36,21 +36,11 @@ def generate_dashboard(self, data): else: autov = "Enabled" return nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][1].split(",")])) if data[0][1] else 'Not Set'}\nUnverified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][2].split(",")])) if data[0][2] else 'Not Set'} \nLog Channel: <#{data[0][3] if data[0][3] else 'Not Set'}> \nAuto Kick: {f"{data[0][5]} day(s)" if data[0][5] else 'Not Set'} \nAuto Verification ([Premium]({PREMIUMLINK}) Only): {autov}\nMinimum Captcha Length ([Premium]({PREMIUMLINK}) Only): {data[0][7]}\nMaximum Captcha Length ([Premium]({PREMIUMLINK}) Only): {data[0][8]}""") - - -def totalxp_to_level(total_xp): - level = (-1 + math.sqrt(1 + 4*(total_xp // 50))) // 2 - threshold = (level+1)*100 - xp=total_xp - 50*(level**2 + level) - return round(level), round(threshold), round(xp) - -def level_to_totalxp(level): - return 100*(level*(level+1))/2 def generate_random_string(length: int = 0): return ''.join([random.choice(ascii_letters+digits) for i in range(length if length else random.randint(5, 10))]) -def get_user_name(user): +def get_user_name(user) -> str: if not str(user.discriminator) == "0": return user return str(user.name) \ No newline at end of file From 335edbf962eaa477551a5bc8c8eaf2219ddff3ea Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Tue, 26 Sep 2023 22:47:04 +0100 Subject: [PATCH 30/35] Started verified button. Need to + prem support --- utils/utils.py | 4 +- views/__init__.py | 3 +- views/answer_button.py | 59 ++++++++++++++++++++++++++++++ views/verify_button.py | 83 ++++++++++++++++++++++++++++++++++++++---- 4 files changed, 138 insertions(+), 11 deletions(-) create mode 100644 views/answer_button.py diff --git a/utils/utils.py b/utils/utils.py index 6c36b49..c5a5f0b 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -37,8 +37,8 @@ def generate_dashboard(self, data): autov = "Enabled" return nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][1].split(",")])) if data[0][1] else 'Not Set'}\nUnverified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][2].split(",")])) if data[0][2] else 'Not Set'} \nLog Channel: <#{data[0][3] if data[0][3] else 'Not Set'}> \nAuto Kick: {f"{data[0][5]} day(s)" if data[0][5] else 'Not Set'} \nAuto Verification ([Premium]({PREMIUMLINK}) Only): {autov}\nMinimum Captcha Length ([Premium]({PREMIUMLINK}) Only): {data[0][7]}\nMaximum Captcha Length ([Premium]({PREMIUMLINK}) Only): {data[0][8]}""") -def generate_random_string(length: int = 0): - return ''.join([random.choice(ascii_letters+digits) for i in range(length if length else random.randint(5, 10))]) +def generate_random_string(min_length: int = 4, max_length: int = 5): + return ''.join([random.choice(ascii_letters+digits) for i in range(min_length, max_length)]) def get_user_name(user) -> str: if not str(user.discriminator) == "0": diff --git a/views/__init__.py b/views/__init__.py index 346b2b8..c80432d 100644 --- a/views/__init__.py +++ b/views/__init__.py @@ -3,4 +3,5 @@ from .role_select import * from .length_modal import * from .verify_button import * -from .embed_creator import * \ No newline at end of file +from .embed_creator import * +from .answer_button import * \ No newline at end of file diff --git a/views/answer_button.py b/views/answer_button.py new file mode 100644 index 0000000..ef0e121 --- /dev/null +++ b/views/answer_button.py @@ -0,0 +1,59 @@ +import nextcord, string, io, random, os +from gtts import gTTS +from captcha.audio import AudioCaptcha + + + + + +class AnswerButton(nextcord.ui.View): + def __init__(self, actual_answer): + super().__init__(timeout=60) + self.add_item(nextcord.ui.Button(label="Invite me to your server", url="https://nomindustries.com/SV/invite")) + self.add_item(nextcord.ui.Button(label="Privacy Policy", url="https://nomindustries.com/SV/privacy")) + self.actual_answer = actual_answer + self.answer = "Too Long ---------------" + self.audio_sent = False + + @nextcord.ui.button(label = "Answer", style = nextcord.ButtonStyle.green, disabled=False) + async def answer_ready(self, button: nextcord.ui.Button, interaction: nextcord.Interaction): + answerinput = AnswerModal() + await interaction.response.send_modal(answerinput) + await answerinput.wait() + self.answer = answerinput.answer + self.stop() + + @nextcord.ui.button(label="Audio", style = nextcord.ButtonStyle.blurple, disabled=False) + async def audio_captcha(self, button: nextcord.ui.Button, interaction: nextcord.Interaction): + if not self.audio_sent: + answer = " ".join(letter for letter in self.actual_answer.split()) + bytes = io.BytesIO() + tts = gTTS(answer) + tts.save(bytes) + bytes.seek(0) + msg = await interaction.send(file=nextcord.File(bytes, f"{interaction.user}-audio.mp3"), ephemeral=True) + self.audio_sent=True + else: + await interaction.send("You have already requested an audio captcha. Please use that to verify.", ephemeral=True) + + + async def on_timeout(self): + self.answer = "Too Long ---------------" + self.stop() + +class AnswerModal(nextcord.ui.Modal): + def __init__(self): + super().__init__(title="What is your answer?") + self.answer = nextcord.ui.TextInput( + label = "What does the captcha say?", + placeholder = "Example: qdvae", + style=nextcord.TextInputStyle.short, + min_length=1, + max_length=10, + required=True + ) + self.add_item(self.answer) + + async def callback(self, interaction: nextcord.Interaction): + self.answer = self.answer.value + self.stop() \ No newline at end of file diff --git a/views/verify_button.py b/views/verify_button.py index 59de1a0..27841bd 100644 --- a/views/verify_button.py +++ b/views/verify_button.py @@ -1,7 +1,13 @@ -import nextcord +import nextcord, pymysql, io from nextcord.interactions import Interaction from nextcord import Interaction -from utils.constants import PRIVACYLINK +from utils import PRIVACYLINK, create_warning_embed, DBENDPOINT, DBNAME, DBPASS, DBUSER, COLOUR_MAIN, create_error_embed, generate_random_string, COLOUR_BAD, COLOUR_GOOD +from captcha.audio import AudioCaptcha +from captcha.image import ImageCaptcha +from views import AnswerButton + +verifying = [] +letters = ["a ", "b ", "c ", "d ", "e ", "g ", "k ", "m ", "n ", "o ", "p ", "q ", "s ", "u ", "v ", "w ", "x ", "y ", "z "] class VerifyButton(nextcord.ui.View): def __init__(self, client): @@ -11,11 +17,72 @@ def __init__(self, client): @nextcord.ui.button(label="Verify", style=nextcord.ButtonStyle.green, disabled=False, custom_id="verify_button") async def verify_button(self, button: nextcord.ui.Button, interaction: Interaction): - pass - - - - - + global verifying + if interaction.user.id in verifying: + await interaction.send(embed=create_warning_embed(title=f"Already verifying", description=f"You are already verifying on Simple Verification. Please complete that verification to start a new one."), ephemeral=True) + return + verifying.append(interaction.user.id) + await interaction.response.defer(with_message=True, ephemeral=True) + conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) + cur = conn.cursor() + cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") + data = cur.fetchall() + if not data: + await interaction.send(embed=create_error_embed(title=f"Invalid Configuration", description=f"This server has an invalid configuration. Please contact the server administrator to fix this issue.")) + return + data = data[0] + if not data[1]: + await interaction.send(embed=create_error_embed(title=f"Invalid Configuration", description=f"This server has an invalid configuration (no verified role set). Please contact the server administrator to fix this issue.")) + return + + verifiedrole = interaction.guild.get_role(int(data[1])) + unverifiedrole = None + if data[2]: + unverifiedrole = interaction.guild.get_role(int(data[2])) + captcha_str = generate_random_string(int(data[7], int(data[8]))) + captcha = ImageCaptcha(width = 280, height = 90, fonts=["./assets/nom.ttf", "./assets/GolosText-Regular.ttf", "./assets/NotoSerif-Regular.ttf", "./assets/Poppins-Regular.ttf", "./assets/Roboto-Regular.ttf", "./assets/SourceSansPro-Regular.ttf"], font_sizes=[60]) + data = captcha.generate(generate_random_string(captcha_str)) + bytes = io.BytesIO() + captcha.write(captcha_str, bytes) + bytes.seek(0) + embed=nextcord.Embed(title=f"Captcha", description=f"You have **1 minute** to answer the captcha correctly.\n\n\nThe captcha will only be **undercase letters**.\nIf you get the captcha wrong, just click the verify button again and retry.", colour=COLOUR_MAIN) + answerview = AnswerButton(actual_answer=captcha_str) + msg = await interaction.send(embed=embed, file=nextcord.File(bytes, f"captcha.jpg", ephemeral=True)) + logembed = nextcord.Embed(title=f"Verification Started", description=f"{interaction.user.mention} started verification with the captcha attached. The answer to the captcha is `{str(captcha_str).replace(' ', '')}`", colour=COLOUR_GOOD) + logembed.set_author(name=f"{interaction.user.replace('#0', '')}", icon_url=interaction.user.avatar.url if interaction.user.avatar else None) + logembed.set_image(url=msg.attachments[0].url) + try: + if data[3]: + logchannel = interaction.guild.get_channel(int(data[3])) + logmsg = await logchannel.send(embed=logembed) + else: + logchannel = False + except: + pass + await msg.edit(view=answerview) + await answerview.wait() + answer_str = captcha_str.replace(" ", "") + await msg.delete() + answer = answerview.answer + if answer == "Too Long ---------------": + embed=nextcord.Embed(title="Time limit exceeded", description=f"You have exceeded the 60 second time limit. Please try again.") + del verifying[verifying.index(interaction.user.id)] + logembed.title=f"Verification Failed" + logembed.description=f"{interaction.user.mention} exceeded the 60 second time limit." + logembed.colour=COLOUR_BAD + if logchannel: + try: + logmsg.edit(embed=logembed) + except: + pass + return + elif answer.lower() == answer_str: + logembed.title=f"Verification Succeeded" + logembed.description=f"{interaction.user.mention} has successfully verified." + logembed.colour=COLOUR_GOOD + try: + verifiedrole = + await interaction.user.add_roles() + From f8b22f2017b3a5bad194b07551ec1cd8f701ccc2 Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Wed, 27 Sep 2023 21:49:00 +0100 Subject: [PATCH 31/35] Checks on `/verifymessage` --- cogs/verify.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cogs/verify.py b/cogs/verify.py index 3bb9ee9..a391f7b 100644 --- a/cogs/verify.py +++ b/cogs/verify.py @@ -37,6 +37,9 @@ async def verifymessage(self, cur.execute(f"INSERT INTO guild_configs (id) VALUES ('{interaction.guild.id}')") conn.commit() + if (not data[1]) and (not data[2]): # Checks to see if verified roles are set. + await interaction.send(embed=create_error_embed(title="Incorrect Config!", description=f"You have no verified/unverified roles set, please use the `/dashboard` command to set them.")) + embed=nextcord.Embed(title=f"Verification", description=f"To verify in the server press the button below and follow the instructions from there.", colour=COLOUR_MAIN) if customembed == "True": From ddd4861f6da5ec57b71ac7671a38f5b101cfc5f9 Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Wed, 27 Sep 2023 22:39:40 +0100 Subject: [PATCH 32/35] more work --- cogs/verify.py | 4 +- views/verify_button.py | 88 ++++++++++++++---------------------------- 2 files changed, 33 insertions(+), 59 deletions(-) diff --git a/cogs/verify.py b/cogs/verify.py index a391f7b..0d4570d 100644 --- a/cogs/verify.py +++ b/cogs/verify.py @@ -38,7 +38,9 @@ async def verifymessage(self, conn.commit() if (not data[1]) and (not data[2]): # Checks to see if verified roles are set. - await interaction.send(embed=create_error_embed(title="Incorrect Config!", description=f"You have no verified/unverified roles set, please use the `/dashboard` command to set them.")) + await interaction.send(embed=create_error_embed(title="Incorrect Config!", description=f"You have no verified/unverified roles set, please use the `/dashboard` command to set them.")) # todo: Mention command. + conn.commit() + return embed=nextcord.Embed(title=f"Verification", description=f"To verify in the server press the button below and follow the instructions from there.", colour=COLOUR_MAIN) diff --git a/views/verify_button.py b/views/verify_button.py index 27841bd..1a0c0a0 100644 --- a/views/verify_button.py +++ b/views/verify_button.py @@ -9,6 +9,36 @@ verifying = [] letters = ["a ", "b ", "c ", "d ", "e ", "g ", "k ", "m ", "n ", "o ", "p ", "q ", "s ", "u ", "v ", "w ", "x ", "y ", "z "] +@staticmethod +async def get_log_channel(guild, data): + if not data[3]: + return None + return await guild.get_channel(int(data[3])) + +@staticmethod +async def send_to_log_channel(guild, embed, data): + logchannel = await get_log_channel(guild, data) + if not logchannel: + return None + msg = await logchannel.send(embed=embed) + return msg + +@staticmethod +async def generate_started_embed(user, captcha_str, captcha_image): + embed = nextcord.Embed(title=f"Verification Started", description=f"{user.mention} started verification with the captcha attached. The answer to the captcha is `{str(captcha_str).replace(' ', '')}`", colour=COLOUR_GOOD) + embed.set_author(name=f"{user.replace('#0', '')}", icon_url=user.avatar.url if user.avatar else None) + embed.set_image(url=captcha_image) + return embed + +@staticmethod +async def generate_fail_embed(user, embed, fail_type, captcha_str): + embed.title = "Verification Failed" + embed.description = f"{user.mention} exceeded the 60 second time limit. The answer to the captcha was {captcha_str}." if fail_type == "time" else f"{user.mention} failed the captcha. The correct answer to the captcha was {captcha_str}." + embed.colour = COLOUR_BAD + return embed + +@staticmethod + class VerifyButton(nextcord.ui.View): def __init__(self, client): self.client = client @@ -27,62 +57,4 @@ async def verify_button(self, button: nextcord.ui.Button, interaction: Interacti cur = conn.cursor() cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") data = cur.fetchall() - if not data: - await interaction.send(embed=create_error_embed(title=f"Invalid Configuration", description=f"This server has an invalid configuration. Please contact the server administrator to fix this issue.")) - return - data = data[0] - if not data[1]: - await interaction.send(embed=create_error_embed(title=f"Invalid Configuration", description=f"This server has an invalid configuration (no verified role set). Please contact the server administrator to fix this issue.")) - return - - verifiedrole = interaction.guild.get_role(int(data[1])) - unverifiedrole = None - if data[2]: - unverifiedrole = interaction.guild.get_role(int(data[2])) - - captcha_str = generate_random_string(int(data[7], int(data[8]))) - captcha = ImageCaptcha(width = 280, height = 90, fonts=["./assets/nom.ttf", "./assets/GolosText-Regular.ttf", "./assets/NotoSerif-Regular.ttf", "./assets/Poppins-Regular.ttf", "./assets/Roboto-Regular.ttf", "./assets/SourceSansPro-Regular.ttf"], font_sizes=[60]) - data = captcha.generate(generate_random_string(captcha_str)) - bytes = io.BytesIO() - captcha.write(captcha_str, bytes) - bytes.seek(0) - embed=nextcord.Embed(title=f"Captcha", description=f"You have **1 minute** to answer the captcha correctly.\n\n\nThe captcha will only be **undercase letters**.\nIf you get the captcha wrong, just click the verify button again and retry.", colour=COLOUR_MAIN) - answerview = AnswerButton(actual_answer=captcha_str) - msg = await interaction.send(embed=embed, file=nextcord.File(bytes, f"captcha.jpg", ephemeral=True)) - logembed = nextcord.Embed(title=f"Verification Started", description=f"{interaction.user.mention} started verification with the captcha attached. The answer to the captcha is `{str(captcha_str).replace(' ', '')}`", colour=COLOUR_GOOD) - logembed.set_author(name=f"{interaction.user.replace('#0', '')}", icon_url=interaction.user.avatar.url if interaction.user.avatar else None) - logembed.set_image(url=msg.attachments[0].url) - try: - if data[3]: - logchannel = interaction.guild.get_channel(int(data[3])) - logmsg = await logchannel.send(embed=logembed) - else: - logchannel = False - except: - pass - - await msg.edit(view=answerview) - await answerview.wait() - answer_str = captcha_str.replace(" ", "") - await msg.delete() - answer = answerview.answer - if answer == "Too Long ---------------": - embed=nextcord.Embed(title="Time limit exceeded", description=f"You have exceeded the 60 second time limit. Please try again.") - del verifying[verifying.index(interaction.user.id)] - logembed.title=f"Verification Failed" - logembed.description=f"{interaction.user.mention} exceeded the 60 second time limit." - logembed.colour=COLOUR_BAD - if logchannel: - try: - logmsg.edit(embed=logembed) - except: - pass - return - elif answer.lower() == answer_str: - logembed.title=f"Verification Succeeded" - logembed.description=f"{interaction.user.mention} has successfully verified." - logembed.colour=COLOUR_GOOD - try: - verifiedrole = - await interaction.user.add_roles() From 41d19f48f66ea863cf384e05f7156cdb2bb6f039 Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Fri, 17 Nov 2023 18:40:56 +0000 Subject: [PATCH 33/35] More work (Currently broken) --- cogs/help.py | 7 ++-- views/verify_button.py | 72 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 71 insertions(+), 8 deletions(-) diff --git a/cogs/help.py b/cogs/help.py index 0cdf90c..717c64c 100644 --- a/cogs/help.py +++ b/cogs/help.py @@ -12,12 +12,9 @@ def __init__(self, client: commands.Bot): async def help(self, interaction: Interaction): await interaction.response.defer() embed = nextcord.Embed(title=(f"Help"), description=(f"""Below is a list of all commands you will need:"""), colour=COLOUR_MAIN) - embed.add_field(name=f"/config enable", value=f"""Explanation: Enable any settings you want to + embed.add_field(name=f"/dashboard", value=f"""Explanation: Manage the bot's settings Requires: Administrator -Usage: ``/config enable``""") - embed.add_field(name=f"/config disable", value=f"""Explanation: Disable any settings you want to -Requires: Administrator -Usage: ``/config disable``""") +Usage: ``/dashboard``""") embed.add_field(name=f"/verifymessage", value=f"""Explanation: Send a verification message to a channel Requires: Administrator Usage: ``/verifymessage <#channel> [Custom (True/False)]``""") diff --git a/views/verify_button.py b/views/verify_button.py index 1a0c0a0..a136976 100644 --- a/views/verify_button.py +++ b/views/verify_button.py @@ -1,7 +1,8 @@ -import nextcord, pymysql, io +import nextcord, pymysql, io, random from nextcord.interactions import Interaction from nextcord import Interaction -from utils import PRIVACYLINK, create_warning_embed, DBENDPOINT, DBNAME, DBPASS, DBUSER, COLOUR_MAIN, create_error_embed, generate_random_string, COLOUR_BAD, COLOUR_GOOD +from assets import * +from utils import PRIVACYLINK, create_warning_embed, DBENDPOINT, DBNAME, DBPASS, DBUSER, COLOUR_MAIN, create_error_embed, generate_random_string, COLOUR_BAD, COLOUR_GOOD, DISCORDLINK from captcha.audio import AudioCaptcha from captcha.image import ImageCaptcha from views import AnswerButton @@ -24,7 +25,42 @@ async def send_to_log_channel(guild, embed, data): return msg @staticmethod -async def generate_started_embed(user, captcha_str, captcha_image): +async def get_verified_role(guild, data): + if not data[1]: + return None + return await guild.get_role(int(data[1])) + +@staticmethod +async def get_unverified_role(guild, data): + if not data[2]: + return None + return await guild.get_role(int(data[2])) + +@staticmethod +async def add_verified_role(guild, user, data): + verifiedrole = await get_verified_role(guild, data) + if not verifiedrole: + return None + try: + await user.add_roles(verifiedrole) + return True + except: + pass + +@staticmethod +async def add_unverified_role(guild, user, data): + unverifiedrole = await get_unverified_role(guild, data) + if not unverifiedrole: + return None + try: + await user.add_roles(unverifiedrole) + return True + except: + pass + + +@staticmethod +async def generate_started_log_embed(user, captcha_str, captcha_image): embed = nextcord.Embed(title=f"Verification Started", description=f"{user.mention} started verification with the captcha attached. The answer to the captcha is `{str(captcha_str).replace(' ', '')}`", colour=COLOUR_GOOD) embed.set_author(name=f"{user.replace('#0', '')}", icon_url=user.avatar.url if user.avatar else None) embed.set_image(url=captcha_image) @@ -38,6 +74,18 @@ async def generate_fail_embed(user, embed, fail_type, captcha_str): return embed @staticmethod +async def generate_captcha_string(min_length, max_length): + return "".join(random.choice(letters) for _ in range(random.randint(min_length, max_length))) + +@staticmethod +async def generate_captcha_image(min_length, max_length): + answer_string = await generate_captcha_string(min_length, max_length) + image = ImageCaptcha(width=280, height=90, fonts=["nom.ttf", "GolosText-Regular.ttf", "NotoSerif-Regular.ttf", "Poppins-Regular.ttf", "Roboto-Regular.ttf", "SourceSansPro-Regular.ttf"], font_sizes=[60]) + data = image.generate(answer_string.lower()) + bytes = io.BytesIo() + image.write(answer_string, bytes) + bytes.seek(0) + return bytes, answer_string class VerifyButton(nextcord.ui.View): def __init__(self, client): @@ -57,4 +105,22 @@ async def verify_button(self, button: nextcord.ui.Button, interaction: Interacti cur = conn.cursor() cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") data = cur.fetchall() + if not data or not data[1]: + await interaction.send(embed=create_warning_embed(title=f"Setup not complete", description=f"The bot is not properly configured in this server. Please talk to the server administrators to resolve this issue. (Think this is a mistake? Reach out to our support server [here](DISCORDLINK)!)"), ephemeral=True) + return + + min_captcha_length = int(data[7]) + max_captcha_length = int(data[8]) + + embed = nextcord.Embed(title=f"Captcha", description=f"You have 1 minute to complete the captcha attached. The captcha will only user **undercase** **letters**.") + captcha, answer_string = generate_captcha_image(min_captcha_length, max_captcha_length) + answerview = AnswerButton(actual_answer=answer_string) + msg = await interaction.send(embed=embed, file=nextcord.File(captcha, f"captcha.jpg"), ephemeral=True) + embed=generate_started_log_embed(interaction.user.id, answer_string, msg.attachments[0].url) + await send_to_log_channel(guild=interaction.guild, embed=embed, data=data) + await answerview.wait() + + + + From 96ab9c927fc9cadcdd77326182fbc292e82e70fe Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Fri, 17 Nov 2023 18:48:00 +0000 Subject: [PATCH 34/35] refactor: autofix issues in 15 files Resolved issues in the following files with DeepSource Autofix: 1. bot/bot.py 2. cogs/dashboard.py 3. cogs/error_handler.py 4. cogs/help.py 5. cogs/misc.py 6. cogs/premium.py 7. cogs/verify.py 8. utils/constants.py 9. utils/utils.py 10. views/answer_button.py 11. views/dashboard_views.py 12. views/embed_creator.py 13. views/length_modal.py 14. views/role_select.py 15. views/verify_button.py --- bot/bot.py | 3 +-- cogs/dashboard.py | 2 +- cogs/error_handler.py | 4 ++-- cogs/help.py | 6 +++--- cogs/misc.py | 16 +++++++-------- cogs/premium.py | 42 ++++++++++++++++++++-------------------- cogs/verify.py | 22 ++++++++++----------- utils/constants.py | 4 ---- utils/utils.py | 10 +++++----- views/answer_button.py | 3 +-- views/dashboard_views.py | 1 - views/embed_creator.py | 11 +++++------ views/length_modal.py | 1 - views/role_select.py | 1 - views/verify_button.py | 15 ++++++-------- 15 files changed, 64 insertions(+), 77 deletions(-) diff --git a/bot/bot.py b/bot/bot.py index fc2b379..7160c54 100644 --- a/bot/bot.py +++ b/bot/bot.py @@ -1,7 +1,6 @@ import nextcord -import json, asyncio import os -from nextcord.ext import commands, tasks +from nextcord.ext import commands from utils.utils import * from utils.constants import TOKEN diff --git a/cogs/dashboard.py b/cogs/dashboard.py index 561441a..5b846c3 100644 --- a/cogs/dashboard.py +++ b/cogs/dashboard.py @@ -9,7 +9,7 @@ class Dashboard(commands.Cog): def __init__(self, client: commands.Bot): self.client = client - @nextcord.slash_command(name=f"dashboard", description=f"Configure the bot on the in-discord dashboard") + @nextcord.slash_command(name="dashboard", description="Configure the bot on the in-discord dashboard") async def dashboard(self, interaction: Interaction): await interaction.response.defer(with_message=True, ephemeral=True) if not interaction.user.guild_permissions.administrator: diff --git a/cogs/error_handler.py b/cogs/error_handler.py index 85f4e3b..b2838b5 100644 --- a/cogs/error_handler.py +++ b/cogs/error_handler.py @@ -1,6 +1,6 @@ import nextcord from cooldowns import CallableOnCooldown -from nextcord.ext import commands, application_checks +from nextcord.ext import commands from bot.bot import Bot from nextcord.errors import Forbidden from utils import * @@ -16,7 +16,7 @@ async def on_application_command_error(self, interaction:nextcord.Interaction, e if isinstance(error, CallableOnCooldown): await interaction.send(f"That command is on cooldown. You can use it again ") elif isinstance(error, Forbidden): - await interaction.send(f"I don't have permission to do that") + await interaction.send("I don't have permission to do that") else: raise error diff --git a/cogs/help.py b/cogs/help.py index 717c64c..24d0b29 100644 --- a/cogs/help.py +++ b/cogs/help.py @@ -8,11 +8,11 @@ class Help(commands.Cog): def __init__(self, client: commands.Bot): self.client = client - @nextcord.slash_command(name=f"help", description=f"Help command") + @nextcord.slash_command(name="help", description="Help command") async def help(self, interaction: Interaction): await interaction.response.defer() - embed = nextcord.Embed(title=(f"Help"), description=(f"""Below is a list of all commands you will need:"""), colour=COLOUR_MAIN) - embed.add_field(name=f"/dashboard", value=f"""Explanation: Manage the bot's settings + embed = nextcord.Embed(title=("Help"), description=("""Below is a list of all commands you will need:"""), colour=COLOUR_MAIN) + embed.add_field(name=f"/dashboard", value="""Explanation: Manage the bot's settings Requires: Administrator Usage: ``/dashboard``""") embed.add_field(name=f"/verifymessage", value=f"""Explanation: Send a verification message to a channel diff --git a/cogs/misc.py b/cogs/misc.py index a013a03..1514bbc 100644 --- a/cogs/misc.py +++ b/cogs/misc.py @@ -28,12 +28,12 @@ async def botinfo(self, interaction: Interaction): Privacy: [Privacy Policy]({PRIVACYLINK})""", colour=COLOUR_MAIN) await msg.edit(content = " ", embed=embed, view=BotInfoLinkButton()) - @nextcord.slash_command(name=f"privacy", description=f"Get the link to our privacy policy") + @nextcord.slash_command(name="privacy", description="Get the link to our privacy policy") async def privacy(self, interaction:Interaction): await interaction.send(content="", view=PrivacyPolicyButton()) - @nextcord.slash_command(name=f"shardinfo", description=f"Get information on all shards") + @nextcord.slash_command(name="shardinfo", description="Get information on all shards") @cooldowns.cooldown(1, 30, bucket=cooldowns.SlashBucket.author) async def shardinfo(self, interaction:Interaction): await interaction.response.defer() @@ -44,16 +44,16 @@ async def shardinfo(self, interaction:Interaction): description+=f"\n**Shard {shard+1}** has `{round(specshard.latency*100)}ms` latency with `{shard_servers} servers`" if not interaction.guild: - await interaction.send(embed=nextcord.Embed(title=f"Simple Verification Shard Information", description=f"All current shards:\n {description}", colour=COLOUR_MAIN)) + await interaction.send(embed=nextcord.Embed(title="Simple Verification Shard Information", description=f"All current shards:\n {description}", colour=COLOUR_MAIN)) else: guild_shard = interaction.guild.shard_id guildspecshard = self.client.get_shard(guild_shard) guild_shard_servers = len([guild for guild in self.client.guilds if guild.shard_id == guild_shard]) - await interaction.send(f"This server's shard is shard **{guild_shard+1}** with `{round(guildspecshard.latency*100)}ms` and `{guild_shard_servers} servers`", embed=nextcord.Embed(title=f"Simple Verification Shard Information", description=f"All current shards:\n {description}", colour=COLOUR_MAIN)) + await interaction.send(f"This server's shard is shard **{guild_shard+1}** with `{round(guildspecshard.latency*100)}ms` and `{guild_shard_servers} servers`", embed=nextcord.Embed(title="Simple Verification Shard Information", description=f"All current shards:\n {description}", colour=COLOUR_MAIN)) - @nextcord.slash_command(name=f"shardinfo", description=f"Get information on all shards") + @nextcord.slash_command(name="shardinfo", description="Get information on all shards") @cooldowns.cooldown(1, 30, bucket=cooldowns.SlashBucket.author) async def shardinfo(self, interaction:Interaction): await interaction.response.defer() @@ -64,15 +64,15 @@ async def shardinfo(self, interaction:Interaction): description+=f"\n**Shard {shard+1}** has `{round(specshard.latency*100)}ms` latency with `{shard_servers} servers`" if not interaction.guild: - await interaction.send(embed=nextcord.Embed(title=f"Simple Verification Shard Information", description=f"All current shards:\n {description}", colour=COLOUR_MAIN)) + await interaction.send(embed=nextcord.Embed(title="Simple Verification Shard Information", description=f"All current shards:\n {description}", colour=COLOUR_MAIN)) else: guild_shard = interaction.guild.shard_id guildspecshard = self.client.get_shard(guild_shard) guild_shard_servers = len([guild for guild in self.client.guilds if guild.shard_id == guild_shard]) - await interaction.send(f"This server's shard is shard **{guild_shard+1}** with `{round(guildspecshard.latency*100)}ms` and `{guild_shard_servers} servers`", embed=nextcord.Embed(title=f"Simple Verification Shard Information", description=f"All current shards:\n {description}", colour=COLOUR_MAIN)) + await interaction.send(f"This server's shard is shard **{guild_shard+1}** with `{round(guildspecshard.latency*100)}ms` and `{guild_shard_servers} servers`", embed=nextcord.Embed(title="Simple Verification Shard Information", description=f"All current shards:\n {description}", colour=COLOUR_MAIN)) - @nextcord.slash_command(name=f"debug", description=f"Get information useful for debugging") + @nextcord.slash_command(name="debug", description="Get information useful for debugging") @cooldowns.cooldown(1,10, bucket=cooldowns.SlashBucket.channel) async def _debug(self, interaction:Interaction): await interaction.response.defer() diff --git a/cogs/premium.py b/cogs/premium.py index 23cccf0..08600a2 100644 --- a/cogs/premium.py +++ b/cogs/premium.py @@ -1,6 +1,6 @@ import nextcord import pymysql -from nextcord.ext import commands, tasks +from nextcord.ext import commands from nextcord import Interaction, SlashOption from utils import check_premium, create_error_embed, create_warning_embed, create_success_embed, PREMIUMLINK, DBENDPOINT, DBUSER, DBPASS, DBNAME, COLOUR_MAIN @@ -8,24 +8,24 @@ class Premium(commands.Cog): def __init__(self, client: commands.Bot): self.client = client - @nextcord.slash_command(name=f"manage-premium", description=f"Manage your premium membership", guild_ids=[1111387758028652657, 801744339343507457]) + @nextcord.slash_command(name="manage-premium", description="Manage your premium membership", guild_ids=[1111387758028652657, 801744339343507457]) async def manage_premium(self, interaction: Interaction): pass - @manage_premium.subcommand(name=f"add-server", description=f"Add a server to your premium subscription") + @manage_premium.subcommand(name="add-server", description="Add a server to your premium subscription") async def manage_premium_add_server(self, interaction: Interaction, guildid: str = SlashOption( - name=f"guild", - description=f"The ID of the guild to add to premium. Use /debug in your server to get this.", + name="guild", + description="The ID of the guild to add to premium. Use /debug in your server to get this.", required = True )): await interaction.response.defer() if not check_premium(self, False, True, interaction.user.id): - await interaction.send(embed=create_error_embed(title=f"No premium subscription", description=f"You are not currently subscribed to any of our premium subscriptions. To purchase premium please follow [this link]({PREMIUMLINK})\n\n\nPlease Note: If you recently subscribed to premium it may take up to 30 minutes to register your subscription. If you are still unable to use this command in 30 minutes, please create a ticket in <#1111392014529990656>")) + await interaction.send(embed=create_error_embed(title="No premium subscription", description=f"You are not currently subscribed to any of our premium subscriptions. To purchase premium please follow [this link]({PREMIUMLINK})\n\n\nPlease Note: If you recently subscribed to premium it may take up to 30 minutes to register your subscription. If you are still unable to use this command in 30 minutes, please create a ticket in <#1111392014529990656>")) return if check_premium(self, True, False, guildid): - await interaction.send(embed=create_warning_embed(title=f"Guild already added", description=f"This guild is already added to your premium subscription.")) + await interaction.send(embed=create_warning_embed(title="Guild already added", description="This guild is already added to your premium subscription.")) return conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) @@ -41,38 +41,38 @@ async def manage_premium_add_server(self, interaction: Interaction, servers_used = len(data) if data else 0 if servers_available <= servers_used: - await interaction.send(embed=create_warning_embed(title=f"Max Servers Reached", description=f"You have reached the limit of premium servers that your current premium subscription allows for (``{servers_available}``). To increase this limit, upgrade your premium subscription via [this link]({PREMIUMLINK})")) + await interaction.send(embed=create_warning_embed(title="Max Servers Reached", description=f"You have reached the limit of premium servers that your current premium subscription allows for (``{servers_available}``). To increase this limit, upgrade your premium subscription via [this link]({PREMIUMLINK})")) return try: guild = self.client.get_guild(int(guildid)) except: - await interaction.send(embed=create_error_embed(title=f"Invalid guild ID", description=f"You have given an invalid guild ID. Please use the `/debug` command in the guild you want to add premium to to get the correct guild ID.")) + await interaction.send(embed=create_error_embed(title="Invalid guild ID", description="You have given an invalid guild ID. Please use the `/debug` command in the guild you want to add premium to to get the correct guild ID.")) return if guild is None: - await interaction.send(embed=create_error_embed(title=f"Invalid guild ID", description=f"You have given an invalid guild ID. Please use the `/debug` command in the guild you want to add premium to to get the correct guild ID.")) + await interaction.send(embed=create_error_embed(title="Invalid guild ID", description="You have given an invalid guild ID. Please use the `/debug` command in the guild you want to add premium to to get the correct guild ID.")) return cur.execute("INSERT INTO sv_premium_guilds (user_id, guild_id) VALUES (%s, %s)", (str(interaction.user.id), guildid)) conn.commit() - await interaction.send(embed=create_success_embed(title=f"Premium server added", description=f"You have succesfully added `{guild.name} ({guild.id})` to your premium subscription.")) + await interaction.send(embed=create_success_embed(title="Premium server added", description=f"You have succesfully added `{guild.name} ({guild.id})` to your premium subscription.")) - @manage_premium.subcommand(name=f"remove-server", description=f"Remove a server from your premium subscription") + @manage_premium.subcommand(name="remove-server", description="Remove a server from your premium subscription") async def manage_premium_remove_server(self, interaction: Interaction, guildid: str = SlashOption( - name=f"guild", - description=f"The ID of the guild to remove from premium. Use /debug in your server to get this.", + name="guild", + description="The ID of the guild to remove from premium. Use /debug in your server to get this.", required = True )): await interaction.response.defer() if not check_premium(self, False, True, interaction.user.id): - await interaction.send(embed=create_error_embed(title=f"No premium subscription", description=f"You are not currently subscribed to any of our premium subscriptions. To purchase premium please follow [this link]({PREMIUMLINK})\n\n\nPlease Note: If you recently subscribed to premium it may take up to 30 minutes to register your subscription. If you are still unable to use this command in 30 minutes, please create a ticket in <#1111392014529990656>")) + await interaction.send(embed=create_error_embed(title="No premium subscription", description=f"You are not currently subscribed to any of our premium subscriptions. To purchase premium please follow [this link]({PREMIUMLINK})\n\n\nPlease Note: If you recently subscribed to premium it may take up to 30 minutes to register your subscription. If you are still unable to use this command in 30 minutes, please create a ticket in <#1111392014529990656>")) return if not check_premium(self, True, False, guildid): - await interaction.send(embed=create_warning_embed(title=f"Guild not added", description=f"This guild is not currently added to your premium subscription.")) + await interaction.send(embed=create_warning_embed(title="Guild not added", description="This guild is not currently added to your premium subscription.")) return try: @@ -88,13 +88,13 @@ async def manage_premium_remove_server(self, interaction: Interaction, cur.execute("DELETE FROM sv_premium_guilds WHERE user_id=%s AND guild_id=%s", (str(interaction.user.id), guildid)) conn.commit() - await interaction.send(embed=create_success_embed(title=f"Premium server removed", description=f"You have succesfully removed `{guild.name if not guild == 'Unknown' else 'Unknown'} ({guildid})` from your premium subscription.")) + await interaction.send(embed=create_success_embed(title="Premium server removed", description=f"You have succesfully removed `{guild.name if not guild == 'Unknown' else 'Unknown'} ({guildid})` from your premium subscription.")) - @manage_premium.subcommand(name=f"view", description=f"View your current premium subscription") + @manage_premium.subcommand(name="view", description="View your current premium subscription") async def manage_premium_view(self, interaction: Interaction): await interaction.response.defer() if not check_premium(self, False, True, interaction.user.id): - await interaction.send(embed=create_error_embed(title=f"No premium subscription", description=f"You are not currently subscribed to any of our premium subscriptions. To purchase premium please follow [this link]({PREMIUMLINK})\n\n\nPlease Note: If you recently subscribed to premium it may take up to 30 minutes to register your subscription. If you are still unable to use this command in 30 minutes, please create a ticket in <#1111392014529990656>")) + await interaction.send(embed=create_error_embed(title="No premium subscription", description=f"You are not currently subscribed to any of our premium subscriptions. To purchase premium please follow [this link]({PREMIUMLINK})\n\n\nPlease Note: If you recently subscribed to premium it may take up to 30 minutes to register your subscription. If you are still unable to use this command in 30 minutes, please create a ticket in <#1111392014529990656>")) return conn = pymysql.connect(host=DBENDPOINT, port=3306, user=DBUSER, password=DBPASS, db=DBNAME) @@ -118,7 +118,7 @@ async def manage_premium_view(self, interaction: Interaction): for role in interaction.user.roles: if role in premium_roles: user_premium_role = role - embed=nextcord.Embed(title=f"Your premium subscription", description=f"Subscription: **{user_premium_role.name}**\nServers (Used Servers/Available Servers): **{len(servers_used)}/{servers_available}**", colour=COLOUR_MAIN) + embed=nextcord.Embed(title="Your premium subscription", description=f"Subscription: **{user_premium_role.name}**\nServers (Used Servers/Available Servers): **{len(servers_used)}/{servers_available}**", colour=COLOUR_MAIN) servers_using = "" for serverid in servers_used: @@ -127,7 +127,7 @@ async def manage_premium_view(self, interaction: Interaction): servers_using += f"**{guild.name}** ({guild.id})\n" except: servers_using += f"**Unknown** ({serverid[1]})" - embed.add_field(name=f"Servers", value=f"{servers_using}") + embed.add_field(name="Servers", value=f"{servers_using}") await interaction.send(embed=embed) diff --git a/cogs/verify.py b/cogs/verify.py index 0d4570d..23ad93b 100644 --- a/cogs/verify.py +++ b/cogs/verify.py @@ -2,26 +2,26 @@ from nextcord.ext import commands from nextcord import Interaction, SlashOption from nextcord.abc import GuildChannel -from utils import check_premium, DBENDPOINT, DBNAME, DBPASS, DBUSER, generate_dashboard, create_warning_embed, COLOUR_MAIN, create_success_embed, create_error_embed -from views import DashboardButtons, VerifyButton, EmbedCreator +from utils import DBENDPOINT, DBNAME, DBPASS, DBUSER, create_warning_embed, COLOUR_MAIN, create_success_embed, create_error_embed +from views import VerifyButton, EmbedCreator import pymysql class Verify(commands.Cog): def __init__(self, client: commands.Bot): self.client = client - @nextcord.slash_command(name=f"verifymessage", description=f"Send a verification message to a channel") + @nextcord.slash_command(name="verifymessage", description="Send a verification message to a channel") async def verifymessage(self, interaction: Interaction, channel: GuildChannel = SlashOption( - name=f"channel", - description=f"The channel you want to send the verification message to", + name="channel", + description="The channel you want to send the verification message to", channel_types=[nextcord.ChannelType.text, nextcord.ChannelType.news], required=True ), customembed: str = SlashOption( - name=f"custom-embed", - description=f"Do you want to customise the embed sent to the verification channel?", + name="custom-embed", + description="Do you want to customise the embed sent to the verification channel?", choices={"Yes, I want to customise the embed": "True", "No, I don't want to customise the embed":"False"}, required=False )): @@ -38,11 +38,11 @@ async def verifymessage(self, conn.commit() if (not data[1]) and (not data[2]): # Checks to see if verified roles are set. - await interaction.send(embed=create_error_embed(title="Incorrect Config!", description=f"You have no verified/unverified roles set, please use the `/dashboard` command to set them.")) # todo: Mention command. + await interaction.send(embed=create_error_embed(title="Incorrect Config!", description="You have no verified/unverified roles set, please use the `/dashboard` command to set them.")) # todo: Mention command. conn.commit() return - embed=nextcord.Embed(title=f"Verification", description=f"To verify in the server press the button below and follow the instructions from there.", colour=COLOUR_MAIN) + embed=nextcord.Embed(title="Verification", description="To verify in the server press the button below and follow the instructions from there.", colour=COLOUR_MAIN) if customembed == "True": options = EmbedCreator() @@ -52,9 +52,9 @@ async def verifymessage(self, try: await channel.send(embed=embed, view=VerifyButton(self.client)) - await interaction.send(embed=create_success_embed(title=f"Message sent!", description=f"I have sent your verification message to {channel.mention}")) + await interaction.send(embed=create_success_embed(title="Message sent!", description=f"I have sent your verification message to {channel.mention}")) except: - interaction.send(embed=create_error_embed(title=f"Error sending verification message!", description=f"I was unable to send the verification message to {channel.mention}. Ensure I have permission to `send_messages` and `embed_links` in {channel.mention}")) + interaction.send(embed=create_error_embed(title="Error sending verification message!", description=f"I was unable to send the verification message to {channel.mention}. Ensure I have permission to `send_messages` and `embed_links` in {channel.mention}")) diff --git a/utils/constants.py b/utils/constants.py index 8760636..62ed349 100644 --- a/utils/constants.py +++ b/utils/constants.py @@ -1,9 +1,5 @@ from typing import Text, Dict -# SQL DB Server Info - -from utils.dbconstants import DBUSER, DBPASS, DBNAME, DBENDPOINT, TOKEN - VOTELINK: Text = "https://nomindustries.com/sv/vote" INVITELINK: Text = "https://discord.com/api/oauth2/authorize?client_id=981835181243658260&permissions=8&scope=bot%20applications.commands" DISCORDLINK: Text = "https://nomindustries.com/sv/support" diff --git a/utils/utils.py b/utils/utils.py index c5a5f0b..0057de0 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -1,5 +1,5 @@ from .constants import COLOUR_BAD, COLOUR_GOOD, COLOUR_NEUTRAL, DBENDPOINT, DBNAME, DBPASS, DBUSER, PREMIUMLINK -import nextcord, math, random, pymysql +import nextcord, random, pymysql from string import ascii_letters, digits def create_success_embed(title: str = "\u200b", description: str = "\u200b"): @@ -23,11 +23,11 @@ def check_premium(self, guild: bool, user: bool, type_id: str) -> bool: if guild: cur.execute(f"SELECT * FROM sv_premium_guilds WHERE guild_id='{type_id}'") data = cur.fetchall() - return True if data else False + return bool(data) elif user: cur.execute(f"SELECT * FROM sv_premium_users WHERE user_id='{type_id}'") data = cur.fetchall() - return True if data else False + return bool(data) return None def generate_dashboard(self, data): @@ -35,12 +35,12 @@ def generate_dashboard(self, data): autov = "Disabled" else: autov = "Enabled" - return nextcord.Embed(title=f"Verification Dashboard", description=f"""Verified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][1].split(",")])) if data[0][1] else 'Not Set'}\nUnverified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][2].split(",")])) if data[0][2] else 'Not Set'} \nLog Channel: <#{data[0][3] if data[0][3] else 'Not Set'}> \nAuto Kick: {f"{data[0][5]} day(s)" if data[0][5] else 'Not Set'} \nAuto Verification ([Premium]({PREMIUMLINK}) Only): {autov}\nMinimum Captcha Length ([Premium]({PREMIUMLINK}) Only): {data[0][7]}\nMaximum Captcha Length ([Premium]({PREMIUMLINK}) Only): {data[0][8]}""") + return nextcord.Embed(title="Verification Dashboard", description=f"""Verified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][1].split(",")])) if data[0][1] else 'Not Set'}\nUnverified Role(s): {(",".join([('<@&' + i + '> ') for i in data[0][2].split(",")])) if data[0][2] else 'Not Set'} \nLog Channel: <#{data[0][3] if data[0][3] else 'Not Set'}> \nAuto Kick: {f"{data[0][5]} day(s)" if data[0][5] else 'Not Set'} \nAuto Verification ([Premium]({PREMIUMLINK}) Only): {autov}\nMinimum Captcha Length ([Premium]({PREMIUMLINK}) Only): {data[0][7]}\nMaximum Captcha Length ([Premium]({PREMIUMLINK}) Only): {data[0][8]}""") def generate_random_string(min_length: int = 4, max_length: int = 5): return ''.join([random.choice(ascii_letters+digits) for i in range(min_length, max_length)]) def get_user_name(user) -> str: - if not str(user.discriminator) == "0": + if str(user.discriminator) != "0": return user return str(user.name) \ No newline at end of file diff --git a/views/answer_button.py b/views/answer_button.py index ef0e121..04e1376 100644 --- a/views/answer_button.py +++ b/views/answer_button.py @@ -1,6 +1,5 @@ -import nextcord, string, io, random, os +import nextcord, io from gtts import gTTS -from captcha.audio import AudioCaptcha diff --git a/views/dashboard_views.py b/views/dashboard_views.py index eb3d97c..74fc16d 100644 --- a/views/dashboard_views.py +++ b/views/dashboard_views.py @@ -1,7 +1,6 @@ import nextcord, pymysql, asyncio from nextcord.interactions import Interaction from utils import DBENDPOINT, DBNAME, DBPASS, DBUSER, COLOUR_MAIN, create_error_embed, DISCORDLINK, create_success_embed, PREMIUMLINK, generate_dashboard -from nextcord import Interaction from .role_select import RoleSelect, ChannelSelect from .length_modal import LengthModal, CaptchaLengthModal diff --git a/views/embed_creator.py b/views/embed_creator.py index 914350f..82f1b37 100644 --- a/views/embed_creator.py +++ b/views/embed_creator.py @@ -1,20 +1,19 @@ -import nextcord, pymysql -from nextcord.ext import commands +import nextcord class EmbedCreator(nextcord.ui.Modal): def __init__(self): - super().__init__(title=f"Embed Creator", timeout=600) + super().__init__(title="Embed Creator", timeout=600) self.embedtitle = nextcord.ui.TextInput( label="What do you want the embed title to be?", - placeholder=f"You can use up to 256 characters here!", + placeholder="You can use up to 256 characters here!", style=nextcord.TextInputStyle.short, min_length=1, max_length=256, required=True ) self.embeddesc = nextcord.ui.TextInput( - label=f"What do you want the embed description to be?", - placeholder=f"Tip: To mention channels dp <#channel_id> (e.g. <#1111390004783091762>)", + label="What do you want the embed description to be?", + placeholder="Tip: To mention channels dp <#channel_id> (e.g. <#1111390004783091762>)", style=nextcord.TextInputStyle.paragraph, min_length=0, max_length=4000, diff --git a/views/length_modal.py b/views/length_modal.py index 8e0857f..8801b43 100644 --- a/views/length_modal.py +++ b/views/length_modal.py @@ -1,6 +1,5 @@ import nextcord from nextcord.interactions import Interaction -from nextcord import Interaction class LengthModal(nextcord.ui.Modal): def __init__(self): diff --git a/views/role_select.py b/views/role_select.py index f5fc978..826439e 100644 --- a/views/role_select.py +++ b/views/role_select.py @@ -1,6 +1,5 @@ import nextcord from nextcord.interactions import Interaction -from nextcord import Interaction class RoleSelectDropdown(nextcord.ui.RoleSelect): def __init__(self, minvalue=1, maxvalue=1, text="Select a role"): diff --git a/views/verify_button.py b/views/verify_button.py index a136976..5913e78 100644 --- a/views/verify_button.py +++ b/views/verify_button.py @@ -1,9 +1,7 @@ import nextcord, pymysql, io, random from nextcord.interactions import Interaction -from nextcord import Interaction from assets import * -from utils import PRIVACYLINK, create_warning_embed, DBENDPOINT, DBNAME, DBPASS, DBUSER, COLOUR_MAIN, create_error_embed, generate_random_string, COLOUR_BAD, COLOUR_GOOD, DISCORDLINK -from captcha.audio import AudioCaptcha +from utils import PRIVACYLINK, create_warning_embed, DBENDPOINT, DBNAME, DBPASS, DBUSER, COLOUR_BAD, COLOUR_GOOD from captcha.image import ImageCaptcha from views import AnswerButton @@ -61,7 +59,7 @@ async def add_unverified_role(guild, user, data): @staticmethod async def generate_started_log_embed(user, captcha_str, captcha_image): - embed = nextcord.Embed(title=f"Verification Started", description=f"{user.mention} started verification with the captcha attached. The answer to the captcha is `{str(captcha_str).replace(' ', '')}`", colour=COLOUR_GOOD) + embed = nextcord.Embed(title="Verification Started", description=f"{user.mention} started verification with the captcha attached. The answer to the captcha is `{str(captcha_str).replace(' ', '')}`", colour=COLOUR_GOOD) embed.set_author(name=f"{user.replace('#0', '')}", icon_url=user.avatar.url if user.avatar else None) embed.set_image(url=captcha_image) return embed @@ -95,9 +93,8 @@ def __init__(self, client): @nextcord.ui.button(label="Verify", style=nextcord.ButtonStyle.green, disabled=False, custom_id="verify_button") async def verify_button(self, button: nextcord.ui.Button, interaction: Interaction): - global verifying if interaction.user.id in verifying: - await interaction.send(embed=create_warning_embed(title=f"Already verifying", description=f"You are already verifying on Simple Verification. Please complete that verification to start a new one."), ephemeral=True) + await interaction.send(embed=create_warning_embed(title="Already verifying", description="You are already verifying on Simple Verification. Please complete that verification to start a new one."), ephemeral=True) return verifying.append(interaction.user.id) await interaction.response.defer(with_message=True, ephemeral=True) @@ -106,16 +103,16 @@ async def verify_button(self, button: nextcord.ui.Button, interaction: Interacti cur.execute(f"SELECT * FROM guild_configs WHERE id='{interaction.guild.id}'") data = cur.fetchall() if not data or not data[1]: - await interaction.send(embed=create_warning_embed(title=f"Setup not complete", description=f"The bot is not properly configured in this server. Please talk to the server administrators to resolve this issue. (Think this is a mistake? Reach out to our support server [here](DISCORDLINK)!)"), ephemeral=True) + await interaction.send(embed=create_warning_embed(title="Setup not complete", description="The bot is not properly configured in this server. Please talk to the server administrators to resolve this issue. (Think this is a mistake? Reach out to our support server [here](DISCORDLINK)!)"), ephemeral=True) return min_captcha_length = int(data[7]) max_captcha_length = int(data[8]) - embed = nextcord.Embed(title=f"Captcha", description=f"You have 1 minute to complete the captcha attached. The captcha will only user **undercase** **letters**.") + embed = nextcord.Embed(title="Captcha", description="You have 1 minute to complete the captcha attached. The captcha will only user **undercase** **letters**.") captcha, answer_string = generate_captcha_image(min_captcha_length, max_captcha_length) answerview = AnswerButton(actual_answer=answer_string) - msg = await interaction.send(embed=embed, file=nextcord.File(captcha, f"captcha.jpg"), ephemeral=True) + msg = await interaction.send(embed=embed, file=nextcord.File(captcha, "captcha.jpg"), ephemeral=True) embed=generate_started_log_embed(interaction.user.id, answer_string, msg.attachments[0].url) await send_to_log_channel(guild=interaction.guild, embed=embed, data=data) await answerview.wait() From 85d250755310b5b491d4b4bc33a2135eefce70b2 Mon Sep 17 00:00:00 2001 From: _lightninq <82113835+lightninq720@users.noreply.github.com> Date: Sat, 25 Nov 2023 02:53:11 +0000 Subject: [PATCH 35/35] Just need to add multiple role support now (Untested) Should all be done now, just need to add support for multiple roles now. --- views/verify_button.py | 44 +++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/views/verify_button.py b/views/verify_button.py index 5913e78..29dcc9f 100644 --- a/views/verify_button.py +++ b/views/verify_button.py @@ -43,18 +43,18 @@ async def add_verified_role(guild, user, data): await user.add_roles(verifiedrole) return True except: - pass + return False @staticmethod -async def add_unverified_role(guild, user, data): +async def remove_unverified_role(guild, user, data): unverifiedrole = await get_unverified_role(guild, data) if not unverifiedrole: return None try: - await user.add_roles(unverifiedrole) + await user.remove_roles(unverifiedrole) return True except: - pass + return False @staticmethod @@ -64,12 +64,6 @@ async def generate_started_log_embed(user, captcha_str, captcha_image): embed.set_image(url=captcha_image) return embed -@staticmethod -async def generate_fail_embed(user, embed, fail_type, captcha_str): - embed.title = "Verification Failed" - embed.description = f"{user.mention} exceeded the 60 second time limit. The answer to the captcha was {captcha_str}." if fail_type == "time" else f"{user.mention} failed the captcha. The correct answer to the captcha was {captcha_str}." - embed.colour = COLOUR_BAD - return embed @staticmethod async def generate_captcha_string(min_length, max_length): @@ -114,10 +108,38 @@ async def verify_button(self, button: nextcord.ui.Button, interaction: Interacti answerview = AnswerButton(actual_answer=answer_string) msg = await interaction.send(embed=embed, file=nextcord.File(captcha, "captcha.jpg"), ephemeral=True) embed=generate_started_log_embed(interaction.user.id, answer_string, msg.attachments[0].url) - await send_to_log_channel(guild=interaction.guild, embed=embed, data=data) + logmsg = await send_to_log_channel(guild=interaction.guild, embed=embed, data=data) await answerview.wait() + if answerview.answer == "Too Long ---------------": + await msg.delete() + await interaction.send(embed=nextcord.Embed(title="Captcha Failed", description=f"You failed the captcha because you ran out of time. Please press the verify button to try again.", colour=COLOUR_BAD)) + return + + if not answerview.answer.lower() == answer_string.lower(): + await msg.delete() + await interaction.send(embed=nextcord.Embed(title=f"Captcha Failed", description=f"You failed the captcha because you got the answer wrong. Please press the verify button to try again.", colour=COLOUR_BAD)) + return + + error_embed = nextcord.Embed(title="Configuration Error", description="Your servers verified or unverified roles are not setup correctly. Please ensure I have the `manage_roles` permission and my highest role is **above** any of the roles you are attempting to give to users.", colour=COLOUR_BAD) + logembed = nextcord.Embed(title="Captcha Passed", description=f"{interaction.user.mention} has passed their captcha") + status = await remove_unverified_role(guild=interaction.guild, user=interaction.user, data=data) + if status == False: + await interaction.send(embed=create_warning_embed(title="Setup not complete", description="The bot is not properly configured in this server. Please talk to the server administrators to resolve this issue. (Think this is a mistake? Reach out to our support server [here](DISCORDLINK)!)"), ephemeral=True) + await logmsg.reply(embed=error_embed) + return + + status = await add_verified_role(guild=interaction.guild, user=interaction.user, data=data) + if status == False or status == None: + await interaction.send(embed=create_warning_embed(title="Setup not complete", description="The bot is not properly configured in this server. Please talk to the server administrators to resolve this issue. (Think this is a mistake? Reach out to our support server [here](DISCORDLINK)!)"), ephemeral=True) + await logmsg.reply(embed=error_embed) + return + + await msg.delete() + await interaction.send(embed=nextcord.Embed(title="Captcha Passed", description=f"You have successfully passed the captcha and now have access to the server.", colour=COLOUR_GOOD)) + logembed = nextcord.Embed(title="Captcha Passed", description=f"{interaction.user.mention} has passed their captcha and thri roles have been updated.") + await logmsg.reply(embed=logembed)