├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── logo.png ├── main └── main.py └── req.txt /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 105 | __pypackages__/ 106 | 107 | # Celery stuff 108 | celerybeat-schedule 109 | celerybeat.pid 110 | 111 | # SageMath parsed files 112 | *.sage.py 113 | 114 | # Environments 115 | .env 116 | .venv 117 | env/ 118 | venv/ 119 | ENV/ 120 | env.bak/ 121 | venv.bak/ 122 | 123 | # Spyder project settings 124 | .spyderproject 125 | .spyproject 126 | 127 | # Rope project settings 128 | .ropeproject 129 | 130 | # mkdocs documentation 131 | /site 132 | 133 | # mypy 134 | .mypy_cache/ 135 | .dmypy.json 136 | dmypy.json 137 | 138 | # Pyre type checker 139 | .pyre/ 140 | 141 | # pytype static type analyzer 142 | .pytype/ 143 | 144 | # Cython debug symbols 145 | cython_debug/ 146 | 147 | # PyCharm 148 | # JetBrains specific template is maintainted in a separate JetBrains.gitignore that can 149 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 150 | # and can be added to the global gitignore or merged into this file. For a more nuclear 151 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 152 | #.idea/ 153 | main_editado.py 154 | es_main.py 155 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 astrxnomo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![GitHub](https://img.shields.io/github/license/astrxnomo/discord-ticket-bot-py?style=flat-square) 2 | ![GitHub contributors](https://img.shields.io/github/contributors/astrxnomo/discord-ticket-bot-py?color=gree&style=flat-square) 3 | ![GitHub issues](https://img.shields.io/github/issues/astrxnomo/discord-ticket-bot-py?style=flat-square) 4 | ![GitHub pull requests](https://img.shields.io/github/issues-pr/astrxnomo/discord-ticket-bot-py?style=flat-square) 5 | ![GitHub last commit](https://img.shields.io/github/last-commit/astrxnomo/discord-ticket-bot-py?style=flat-square) 6 | 7 | ![GitHub forks](https://img.shields.io/github/forks/astrxnomo/discord-ticket-bot-py?style=flat-square) 8 | ![GitHub Repo stars](https://img.shields.io/github/stars/astrxnomo/discord-ticket-bot-py?color=yellow&style=flat-square) 9 | 10 | 11 | # Get Started 12 | A discord ticket bot created with python, using discord components such as buttons and select menus. 13 | 14 | We suggest you be familiar with discord.py and python. This is a Ticket Bot guide so it couldn't contain a lot of python explanations. 15 | 16 | # At a Glance 17 | 18 | ![image](https://user-images.githubusercontent.com/75272665/174901958-4f166dcc-6da2-46c2-abde-28584b9e04bf.png) | ![image](https://user-images.githubusercontent.com/75272665/174902495-92a9c746-608e-416f-be21-94172d3cb799.png) | ![image](https://user-images.githubusercontent.com/75272665/174902136-5b092a47-75f9-45c3-a63b-824f49e2cb83.png) 19 | :-------------------------:|:-------------------------:|:-------------------------: 20 | 21 | 22 | 23 | # Content 24 | 25 | ### [Home](https://github.com/astrxnomo/discord-ticket-bot-py/wiki) 26 | - [Content](https://github.com/astrxnomo/discord-ticket-bot-py/wiki#content) 27 | - [Acknowledgements](https://github.com/astrxnomo/discord-ticket-bot-py/wiki#acknowledgements) 28 | ### 1. Installations 29 | - 1.1. Installing discord.py run this command in terminal after cloning `pip install -r req.txt` 30 | - 1.2. Installing discord-components run this command in terminal after cloning `pip install -r req.txt` 31 | - [1.3. Installing the bot](https://github.com/astrxnomo/discord-ticket-bot-py/wiki/Installations#installing-the-bot) 32 | - [1.3.1. Create an Application](https://github.com/astrxnomo/discord-ticket-bot-py/wiki/Installations#create-an-application) 33 | - [1.3.2. Add a Bot Account](https://github.com/astrxnomo/discord-ticket-bot-py/wiki/Installations#add-a-bot-account) 34 | - [1.3.3. Invite Your Bot](https://github.com/astrxnomo/discord-ticket-bot-py/wiki/Installations#invite-your-bot) 35 | - [1.3.4. Get Bot Token](https://github.com/astrxnomo/discord-ticket-bot-py/wiki/Installations#get-bot-token) 36 | ### [2. Setup the bot](https://github.com/astrxnomo/discord-ticket-bot-py/wiki/Setup-the-bot) 37 | - [2.1. Change prefix](https://github.com/astrxnomo/discord-ticket-bot-py/wiki/Setup-the-bot#change-prefix) 38 | - [2.2. Setting parameters](https://github.com/astrxnomo/discord-ticket-bot-py/wiki/Setup-the-bot#setting-parameters) 39 | ### [3. Running the bot](https://github.com/astrxnomo/discord-ticket-bot-py/wiki/Running-the-bot) 40 | - [3.1. Ticket channel](https://github.com/astrxnomo/discord-ticket-bot-py/wiki/Running-the-bot#ticket-channel) 41 | - [3.2. Ticket command](https://github.com/astrxnomo/discord-ticket-bot-py/wiki/Running-the-bot#ticket-command) 42 | - [3.3. Testing the bot](https://github.com/astrxnomo/discord-ticket-bot-py/wiki/Running-the-bot#testing-the-bot) 43 | - [3.3.1. Select function](https://github.com/astrxnomo/discord-ticket-bot-py/wiki/Running-the-bot#select-function) 44 | - [3.3.2. Inside the ticket](https://github.com/astrxnomo/discord-ticket-bot-py/wiki/Running-the-bot#inside-the-ticket) 45 | - [3.3.2.1. Call staff function](https://github.com/astrxnomo/discord-ticket-bot-py/wiki/Running-the-bot#call-staff-function) 46 | - [3.3.2.2. Close ticket function](https://github.com/astrxnomo/discord-ticket-bot-py/wiki/Running-the-bot#close-ticket-function) 47 | - [3.3.3. Ticket logs function](https://github.com/astrxnomo/discord-ticket-bot-py/wiki/Running-the-bot#ticket-logs) 48 | ### [4. Customizing the bot](https://github.com/astrxnomo/discord-ticket-bot-py/wiki/Customizing-the-bot) 49 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astrxnomo/discord-ticket-bot-py/d5813b999d79483d812cb97ca8f8101a3eeaa2f9/logo.png -------------------------------------------------------------------------------- /main/main.py: -------------------------------------------------------------------------------- 1 | import discord 2 | import datetime 3 | from discord.ext import commands 4 | from discord_components import Button, Select, SelectOption, ComponentsBot, interaction 5 | from discord_components.component import ButtonStyle 6 | 7 | #Bot prefix 8 | bot = ComponentsBot('tb!', help_command=None) 9 | 10 | id_category = #put here the id of the category where the bot will create the ticket channels 11 | id_channel_ticket_logs = #put here the id of the channel where the bot will create the ticket logs 12 | id_staff_role = #put here the id of the staff role 13 | embed_color = 0xfcd005 #put here a hex color that will carry all the embeds sent by the bot 14 | 15 | 16 | @bot.event 17 | async def on_ready(): 18 | members = 0 19 | for guild in bot.guilds: 20 | members += guild.member_count - 1 21 | 22 | await bot.change_presence(activity = discord.Activity( 23 | type = discord.ActivityType.watching, 24 | 25 | #Bot status 26 | name = f'{members} members' 27 | 28 | )) 29 | print('Ready to support ✅') 30 | 31 | #Ticket command 32 | @bot.command() 33 | @commands.has_permissions(administrator=True) 34 | async def ticket(ctx): 35 | await ctx.message.delete() 36 | 37 | #Embed title and description 38 | embed = discord.Embed(title ='Tickets', description ='Welcome to tickets system.', color=embed_color) 39 | 40 | #Embed image 41 | embed.set_image(url='https://i.imgur.com/FoI5ITb.png') 42 | 43 | await ctx.send( 44 | embed = embed, 45 | 46 | #Embed button 47 | components = [ 48 | Button( 49 | custom_id = 'Ticket', 50 | label = "Create a ticket", 51 | style = ButtonStyle.green, 52 | emoji ='🔧') 53 | ] 54 | ) 55 | 56 | @bot.event 57 | async def on_button_click(interaction): 58 | 59 | canal = interaction.channel 60 | canal_logs = interaction.guild.get_channel(id_channel_ticket_logs) 61 | 62 | #Select function 63 | if interaction.component.custom_id == "Ticket": 64 | await interaction.send( 65 | 66 | components = [ 67 | Select( 68 | placeholder = "How can we help you?", 69 | options = [ 70 | SelectOption(label="Question", value="question", description='If you have a simple question.', emoji='❔'), 71 | SelectOption(label="Help", value="help", description='If you need help from us.', emoji='🔧'), 72 | SelectOption(label="Report", value="report", description='To report a misbehaving user.', emoji='🚫'), 73 | ], 74 | custom_id = "menu")]) 75 | 76 | #Call staff function 77 | elif interaction.component.custom_id == 'call_staff': 78 | 79 | embed_llamar_staff = discord.Embed(description=f"🔔 {interaction.author.mention} has called the staff.", color=embed_color) 80 | await canal.send(f'<@&{id_staff_role}>', embed=embed_llamar_staff, delete_after= 20) 81 | 82 | #Close ticket function 83 | elif interaction.component.custom_id == 'close_ticket': 84 | 85 | embed_cerrar_ticket = discord.Embed(description=f"⚠️ Are you sure you want to close the ticket?", color=embed_color) 86 | await canal.send(interaction.author.mention, embed=embed_cerrar_ticket, 87 | components = [[ 88 | Button(custom_id = 'close_yes', label = "Yes", style = ButtonStyle.green), 89 | Button(custom_id = 'close_no', label = "No", style = ButtonStyle.red)]]) 90 | 91 | #Ticket logs function 92 | elif interaction.component.custom_id == 'close_yes': 93 | 94 | await canal.delete() 95 | embed_logs = discord.Embed(title="Tickets", description=f"", timestamp = datetime.datetime.utcnow(), color=embed_color) 96 | embed_logs.add_field(name="Ticket", value=f"{canal.name}", inline=True) 97 | embed_logs.add_field(name="Closed by", value=f"{interaction.author.mention}", inline=False) 98 | embed_logs.set_thumbnail(url=interaction.author.avatar_url) 99 | await canal_logs.send(embed=embed_logs) 100 | 101 | 102 | elif interaction.component.custom_id == 'close_no': 103 | await interaction.message.delete() 104 | 105 | @bot.event 106 | async def on_select_option(interaction): 107 | if interaction.component.custom_id == "menu": 108 | 109 | guild = interaction.guild 110 | category = discord.utils.get(interaction.guild.categories, id = id_category) 111 | rol_staff = discord.utils.get(interaction.guild.roles, id = id_staff_role) 112 | 113 | #Select option | Question 114 | if interaction.values[0] == 'question': 115 | 116 | #Creating ticket channel | Question 117 | channel = await guild.create_text_channel(name=f'❔┃{interaction.author.name}-ticket', category=category) 118 | 119 | #Ticket channel permissions | Question 120 | await channel.set_permissions(interaction.guild.get_role(interaction.guild.id), 121 | send_messages=False, 122 | read_messages=False) 123 | await channel.set_permissions(interaction.author, 124 | send_messages=True, 125 | read_messages=True, 126 | add_reactions=True, 127 | embed_links=True, 128 | attach_files=True, 129 | read_message_history=True, 130 | external_emojis=True) 131 | await channel.set_permissions(rol_staff, 132 | send_messages=True, 133 | read_messages=True, 134 | add_reactions=True, 135 | embed_links=True, 136 | attach_files=True, 137 | read_message_history=True, 138 | external_emojis=True, 139 | manage_messages=True) 140 | 141 | 142 | await interaction.send(f'> The {channel.mention} channel was created to solve your questions.', delete_after= 3) 143 | 144 | #Inside the ticket | Question 145 | #Embed inside the ticket | Question 146 | embed_question = discord.Embed(title=f'Question - ¡Hi {interaction.author.name}!', description='In this ticket we have an answer to your question.\n\nIf you cant get someone to help you, press the button `🔔 Call staff`..', color=embed_color) 147 | embed_question.set_thumbnail(url=interaction.author.avatar_url) 148 | 149 | 150 | await channel.send(interaction.author.mention, embed=embed_question, 151 | 152 | #Embed buttons inside the ticket | Question 153 | components = [[ 154 | Button(custom_id = 'close_ticket', label = "Close ticket", style = ButtonStyle.red, emoji ='🔐'), 155 | Button(custom_id = 'call_staff', label = "Call staff", style = ButtonStyle.blue, emoji ='🔔')]]) 156 | 157 | 158 | #Select option | Help 159 | elif interaction.values[0] == 'help': 160 | 161 | #Creating ticket channel | Help 162 | channel = await guild.create_text_channel(name=f'🔧┃{interaction.author.name}-ticket', category=category) 163 | 164 | #Ticket channel permissions | Help 165 | await channel.set_permissions(interaction.guild.get_role(interaction.guild.id), 166 | send_messages=False, 167 | read_messages=False) 168 | await channel.set_permissions(interaction.author, 169 | send_messages=True, 170 | read_messages=True, 171 | add_reactions=True, 172 | embed_links=True, 173 | attach_files=True, 174 | read_message_history=True, 175 | external_emojis=True) 176 | await channel.set_permissions(rol_staff, 177 | send_messages=True, 178 | read_messages=True, 179 | add_reactions=True, 180 | embed_links=True, 181 | attach_files=True, 182 | read_message_history=True, 183 | external_emojis=True, 184 | manage_messages=True) 185 | 186 | 187 | await interaction.send(f'> The {channel.mention} channel was created to help you.', delete_after= 3) 188 | 189 | #Inside the ticket | Help 190 | #Embed inside the ticket | Help 191 | embed_question = discord.Embed(title=f'Help - ¡Hi {interaction.author.name}!', description='In this ticket we can help you with whatever you need.\n\nIf you cant get someone to help you, press the button `🔔 Call staff`.', color=embed_color) 192 | embed_question.set_thumbnail(url=interaction.author.avatar_url) 193 | 194 | 195 | await channel.send(interaction.author.mention, embed=embed_question, 196 | 197 | #Embed buttons inside the ticket | Help 198 | components = [[ 199 | Button(custom_id = 'close_ticket', label = "Close ticket", style = ButtonStyle.red, emoji ='🔐'), 200 | Button(custom_id = 'call_staff', label = "Call staff", style = ButtonStyle.blue, emoji ='🔔')]]) 201 | 202 | 203 | #Select option | Report 204 | elif interaction.values[0] == 'report': 205 | 206 | #Creating ticket channel | Report 207 | channel = await guild.create_text_channel(name=f'🚫┃{interaction.author.name}-ticket', category=category) 208 | 209 | #Ticket channel permissions | Report 210 | await channel.set_permissions(interaction.guild.get_role(interaction.guild.id), 211 | send_messages=False, 212 | read_messages=False) 213 | await channel.set_permissions(interaction.author, 214 | send_messages=True, 215 | read_messages=True, 216 | add_reactions=True, 217 | embed_links=True, 218 | attach_files=True, 219 | read_message_history=True, 220 | external_emojis=True) 221 | await channel.set_permissions(rol_staff, 222 | send_messages=True, 223 | read_messages=True, 224 | add_reactions=True, 225 | embed_links=True, 226 | attach_files=True, 227 | read_message_history=True, 228 | external_emojis=True, 229 | manage_messages=True) 230 | 231 | 232 | await interaction.send(f'> The {channel.mention} channel was created to report to the user.', delete_after= 3) 233 | 234 | #Inside the ticket | Report 235 | #Embed inside the ticket | Report 236 | embed_question = discord.Embed(title=f'Report - ¡Hi {interaction.author.name}!', description='In this ticket we can help you with your report.\n\nIf you cant get someone to help you, press the button `🔔 Call staff`.', color=embed_color) 237 | embed_question.set_thumbnail(url=interaction.author.avatar_url) 238 | 239 | await channel.send(interaction.author.mention, embed=embed_question, 240 | 241 | #Embed buttons inside the ticket | Report 242 | components = [[ 243 | Button(custom_id = 'close_ticket', label = "Close ticket", style = ButtonStyle.red, emoji ='🔐'), 244 | Button(custom_id = 'call_staff', label = "Call staff", style = ButtonStyle.blue, emoji ='🔔')]]) 245 | 246 | bot.run('') -------------------------------------------------------------------------------- /req.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/kiki7000/discord.py-components 2 | discord.py==2.0.0 --------------------------------------------------------------------------------