tickets_plus.cogs.tags
An extension for all your tagging needs!
This module contains the Tags cog, which allows users to create and manage tags, which are essentially just snippets of text that can be called up with a command. Tags can be used by anyone, and can be created by anyone who has a staff role.
Typical usage example:
from tickets_plus import bot bot_instance = bot.TicketsPlus(...) bot_instance.load_extension("tickets_plus.cogs.tags")
1"""An extension for all your tagging needs! 2 3This module contains the Tags cog, which allows users to create and manage 4tags, which are essentially just snippets of text that can be called up 5with a command. Tags can be used by anyone, and can be created by anyone 6who has a staff role. 7 8Typical usage example: 9 ```py 10 from tickets_plus import bot 11 bot_instance = bot.TicketsPlus(...) 12 bot_instance.load_extension("tickets_plus.cogs.tags") 13 ``` 14""" 15# License: EPL-2.0 16# SPDX-License-Identifier: EPL-2.0 17# Copyright (c) 2021-present The Tickets+ Contributors 18# This Source Code may also be made available under the following 19# Secondary Licenses when the conditions for such availability set forth 20# in the Eclipse Public License, v. 2.0 are satisfied: GPL-3.0-only OR 21# If later approved by the Initial Contributor, GPL-3.0-or-later. 22 23import logging 24import types 25from typing import List, Optional, Tuple 26 27import discord 28from discord import app_commands 29from discord.ext import commands 30 31from tickets_plus import bot 32from tickets_plus.ext import checks, exceptions 33 34 35@commands.guild_only() 36class TagUtils(commands.GroupCog, name="tag", description="A for all your tagging needs!"): 37 """Suitable for all your tagging needs! 38 39 This is the cog responsible for managing tags, which are essentially 40 just snippets of text that can be called up with a command. Tags can 41 be used by anyone, and can be created by anyone who has a staff role. 42 """ 43 44 def __init__(self, bot_instance: bot.TicketsPlusBot): 45 """Initializes the TagUtils cog. 46 47 This method initializes the cog. 48 It also sets the bot instance as a private attribute. 49 And finally initializes the superclass. 50 51 Args: 52 bot_instance: The bot instance. 53 """ 54 self._bt = bot_instance 55 super().__init__() 56 logging.info("Loaded %s", self.__class__.__name__) 57 58 async def tag_autocomplete(self, ctx: discord.Interaction, arg: str) -> List[app_commands.Choice[str]]: 59 """Autocomplete for tags. 60 61 This method is used to autocomplete tags. 62 It gets the tags from the database and returns them as a list of 63 choices. 64 65 Args: 66 ctx: The interaction context. 67 arg: The argument to autocomplete. 68 """ 69 async with self._bt.get_connection() as conn: 70 tags = await conn.get_tags(ctx.guild_id) # type: ignore 71 choices = [] 72 for tag in tags: 73 if len(choices) >= 25: 74 break 75 if arg.lower() in tag.tag_name.lower(): 76 choices.append(app_commands.Choice(name=tag.tag_name, value=tag.tag_name)) 77 return choices 78 79 async def prep_tag(self, guild: int, tag: str, mention: Optional[discord.User]) -> Tuple[str, None | discord.Embed]: 80 """Basic tag preparation. 81 82 Grabs the tag and packages it into a message and embed. 83 The message also mentions the user if specified. 84 85 Args: 86 guild: The guild to fetch the tag from. 87 tag: The tag to send. 88 mention: The user to mention. 89 90 Returns: 91 A tuple of the message and embed. 92 93 Raises: 94 InvalidParameters: The tag doesn't exist. 95 """ 96 async with self._bt.get_connection() as conn: 97 emd = None 98 tag_data = await conn.fetch_tag(guild, tag.lower()) # type: ignore 99 messg = "" 100 if mention: 101 messg = f"{mention.mention}\n" 102 if tag_data is None: 103 raise exceptions.InvalidParameters("That tag doesn't exist!") 104 if isinstance(tag_data, discord.Embed): 105 emd = tag_data 106 else: 107 messg += tag_data 108 return messg, emd 109 110 @app_commands.command(name="send", description="Send a tag") 111 @app_commands.describe(tag="The tag to send", mention="The user to mention", anon="Send anonymously") 112 @app_commands.autocomplete(tag=tag_autocomplete) 113 async def send(self, 114 ctx: discord.Interaction, 115 tag: str, 116 mention: Optional[discord.User], 117 anon: bool = False) -> None: 118 """Sends a tag. 119 120 This command sends a tag, which is a snippet of text that can be 121 called up with a command. 122 123 Args: 124 ctx: The interaction context. 125 tag: The tag to send. 126 mention: The user to mention. 127 anon: Whether to send anonymously. 128 """ 129 await ctx.response.defer(ephemeral=anon) 130 if isinstance(ctx.channel, ( 131 discord.ForumChannel, 132 discord.StageChannel, 133 discord.CategoryChannel, 134 types.NoneType, 135 )): 136 raise exceptions.InvalidLocation("You can't use this command here!") 137 messg, emd = await self.prep_tag( 138 ctx.guild_id, # type: ignore 139 tag, 140 mention) 141 post = ctx.followup 142 if anon: 143 post = ctx.channel 144 if emd: 145 await post.send(content=messg, embed=emd) 146 else: 147 await post.send(messg) 148 await ctx.followup.send("Sent!", ephemeral=True) 149 150 @app_commands.command(name="create", description="Create/Delete a tag") 151 @checks.is_staff_check() 152 @app_commands.describe( 153 tag_name="The tag to create", 154 content="The content of the tag", 155 title="The title of the embed", 156 url="The url of the embed", 157 color="The color of the embed in hex (e.g. #ff0000)", 158 footer="The footer of the embed", 159 image="The image of the embed", 160 thumbnail="The thumbnail of the embed", 161 author="The author of the embed", 162 ) 163 @app_commands.autocomplete(tag_name=tag_autocomplete) 164 async def create(self, ctx: discord.Interaction, tag_name: str, content: str, title: Optional[str], 165 url: Optional[str], color: Optional[str], footer: Optional[str], image: Optional[str], 166 thumbnail: Optional[str], author: Optional[str]) -> None: 167 """Creates or deletes a tag. 168 169 This command creates a tag, which is a snippet of text that can be 170 called up with a command. 171 If embed parameters are specified, it creates an embed. 172 If the tag already exists, it deletes it. 173 174 Args: 175 ctx: The interaction context. 176 tag_name: The tag to create. 177 content: The content of the tag. 178 title: The title of the embed. 179 url: The url of the embed. 180 color: The color of the embed. 181 footer: The footer of the embed. 182 image: The image of the embed. 183 thumbnail: The thumbnail of the embed. 184 author: The author of the embed. 185 186 Raises: 187 InvalidParameters: The tag already exists. 188 """ 189 await ctx.response.defer(ephemeral=True) 190 parsed_color = None 191 opt_params = { 192 "title": title, 193 "url": url, 194 "color": parsed_color, 195 "footer": footer, 196 "image": image, 197 "thumbnail": thumbnail, 198 "author": author 199 } 200 if any(opt_params.values()) and not title: 201 raise exceptions.InvalidParameters("You need to specify a title" 202 " if you want to use embed parameters!") 203 if color: 204 parsed_color = discord.Color.from_str(color).value 205 opt_params["color"] = parsed_color 206 async with self._bt.get_connection() as conn: 207 new, tag_data = await conn.get_tag( 208 ctx.guild_id, # type: ignore 209 tag_name.lower(), 210 content, 211 embed_args=opt_params) 212 if new: 213 emd = discord.Embed(title="Tag created!", 214 description=f"Tag `{tag_name}` created!", 215 color=discord.Color.green()) 216 else: 217 await conn.delete(tag_data) 218 emd = discord.Embed(title="Tag deleted!", 219 description=f"Tag `{tag_name}` deleted!", 220 color=discord.Color.red()) 221 await conn.commit() 222 await ctx.followup.send(embed=emd, ephemeral=True) 223 224 @app_commands.command(name="edit", description="Edit a tag") 225 @checks.is_staff_check() 226 @app_commands.describe( 227 tag="The tag to edit", 228 content="The content of the tag", 229 title="The title of the embed", 230 url="The url of the embed", 231 color="The color of the embed in hex (e.g. #ff0000)", 232 footer="The footer of the embed", 233 image="The image of the embed", 234 thumbnail="The thumbnail of the embed", 235 author="The author of the embed", 236 ) 237 @app_commands.autocomplete(tag=tag_autocomplete) 238 async def edit(self, ctx: discord.Interaction, tag: str, content: Optional[str], title: Optional[str], 239 url: Optional[str], color: Optional[str], footer: Optional[str], image: Optional[str], 240 thumbnail: Optional[str], author: Optional[str]) -> None: 241 """Edits a tag. 242 243 This command edits a tag, which is a snippet of text that can be 244 called up with a command. 245 If embed parameters are specified, it edits the embed. 246 247 Args: 248 ctx: The interaction context. 249 tag: The tag to edit. 250 content: The content of the tag. 251 title: The title of the embed. 252 url: The url of the embed. 253 color: The color of the embed. 254 footer: The footer of the embed. 255 image: The image of the embed. 256 thumbnail: The thumbnail of the embed. 257 author: The author of the embed. 258 259 Raises: 260 InvalidParameters: The tag doesn't exist. 261 """ 262 parsed_color = None 263 if color: 264 parsed_color = discord.Color.from_str(color).value 265 opt_params = { 266 "url": url, 267 "color": parsed_color, 268 "footer": footer, 269 "image": image, 270 "thumbnail": thumbnail, 271 "author": author 272 } 273 async with self._bt.get_connection() as conn: 274 new, tag_data = await conn.get_tag( 275 ctx.guild_id, # type: ignore 276 tag.lower(), 277 "") 278 if new: 279 raise exceptions.InvalidParameters("That tag doesn't exist!") 280 if content: 281 tag_data.description = content 282 if title: 283 tag_data.title = title 284 if not tag_data.title and any(opt_params.values()): 285 raise exceptions.InvalidParameters("You need to specify a title if" 286 " you want to use embed parameters!") 287 for param, value in opt_params.items(): 288 if value: 289 setattr(tag_data, param, value) 290 await conn.commit() 291 emd = discord.Embed(title="Tag edited!", description=f"Tag `{tag}` edited!", color=discord.Color.green()) 292 await ctx.response.send_message(embed=emd, ephemeral=True) 293 294 295async def setup(bot_instance: bot.TicketsPlusBot) -> None: 296 """Sets up the tag cog. 297 298 Sets the bot to use the cog properly. 299 300 Args: 301 bot_instance: The bot instance. 302 """ 303 await bot_instance.add_cog(TagUtils(bot_instance))
36@commands.guild_only() 37class TagUtils(commands.GroupCog, name="tag", description="A for all your tagging needs!"): 38 """Suitable for all your tagging needs! 39 40 This is the cog responsible for managing tags, which are essentially 41 just snippets of text that can be called up with a command. Tags can 42 be used by anyone, and can be created by anyone who has a staff role. 43 """ 44 45 def __init__(self, bot_instance: bot.TicketsPlusBot): 46 """Initializes the TagUtils cog. 47 48 This method initializes the cog. 49 It also sets the bot instance as a private attribute. 50 And finally initializes the superclass. 51 52 Args: 53 bot_instance: The bot instance. 54 """ 55 self._bt = bot_instance 56 super().__init__() 57 logging.info("Loaded %s", self.__class__.__name__) 58 59 async def tag_autocomplete(self, ctx: discord.Interaction, arg: str) -> List[app_commands.Choice[str]]: 60 """Autocomplete for tags. 61 62 This method is used to autocomplete tags. 63 It gets the tags from the database and returns them as a list of 64 choices. 65 66 Args: 67 ctx: The interaction context. 68 arg: The argument to autocomplete. 69 """ 70 async with self._bt.get_connection() as conn: 71 tags = await conn.get_tags(ctx.guild_id) # type: ignore 72 choices = [] 73 for tag in tags: 74 if len(choices) >= 25: 75 break 76 if arg.lower() in tag.tag_name.lower(): 77 choices.append(app_commands.Choice(name=tag.tag_name, value=tag.tag_name)) 78 return choices 79 80 async def prep_tag(self, guild: int, tag: str, mention: Optional[discord.User]) -> Tuple[str, None | discord.Embed]: 81 """Basic tag preparation. 82 83 Grabs the tag and packages it into a message and embed. 84 The message also mentions the user if specified. 85 86 Args: 87 guild: The guild to fetch the tag from. 88 tag: The tag to send. 89 mention: The user to mention. 90 91 Returns: 92 A tuple of the message and embed. 93 94 Raises: 95 InvalidParameters: The tag doesn't exist. 96 """ 97 async with self._bt.get_connection() as conn: 98 emd = None 99 tag_data = await conn.fetch_tag(guild, tag.lower()) # type: ignore 100 messg = "" 101 if mention: 102 messg = f"{mention.mention}\n" 103 if tag_data is None: 104 raise exceptions.InvalidParameters("That tag doesn't exist!") 105 if isinstance(tag_data, discord.Embed): 106 emd = tag_data 107 else: 108 messg += tag_data 109 return messg, emd 110 111 @app_commands.command(name="send", description="Send a tag") 112 @app_commands.describe(tag="The tag to send", mention="The user to mention", anon="Send anonymously") 113 @app_commands.autocomplete(tag=tag_autocomplete) 114 async def send(self, 115 ctx: discord.Interaction, 116 tag: str, 117 mention: Optional[discord.User], 118 anon: bool = False) -> None: 119 """Sends a tag. 120 121 This command sends a tag, which is a snippet of text that can be 122 called up with a command. 123 124 Args: 125 ctx: The interaction context. 126 tag: The tag to send. 127 mention: The user to mention. 128 anon: Whether to send anonymously. 129 """ 130 await ctx.response.defer(ephemeral=anon) 131 if isinstance(ctx.channel, ( 132 discord.ForumChannel, 133 discord.StageChannel, 134 discord.CategoryChannel, 135 types.NoneType, 136 )): 137 raise exceptions.InvalidLocation("You can't use this command here!") 138 messg, emd = await self.prep_tag( 139 ctx.guild_id, # type: ignore 140 tag, 141 mention) 142 post = ctx.followup 143 if anon: 144 post = ctx.channel 145 if emd: 146 await post.send(content=messg, embed=emd) 147 else: 148 await post.send(messg) 149 await ctx.followup.send("Sent!", ephemeral=True) 150 151 @app_commands.command(name="create", description="Create/Delete a tag") 152 @checks.is_staff_check() 153 @app_commands.describe( 154 tag_name="The tag to create", 155 content="The content of the tag", 156 title="The title of the embed", 157 url="The url of the embed", 158 color="The color of the embed in hex (e.g. #ff0000)", 159 footer="The footer of the embed", 160 image="The image of the embed", 161 thumbnail="The thumbnail of the embed", 162 author="The author of the embed", 163 ) 164 @app_commands.autocomplete(tag_name=tag_autocomplete) 165 async def create(self, ctx: discord.Interaction, tag_name: str, content: str, title: Optional[str], 166 url: Optional[str], color: Optional[str], footer: Optional[str], image: Optional[str], 167 thumbnail: Optional[str], author: Optional[str]) -> None: 168 """Creates or deletes a tag. 169 170 This command creates a tag, which is a snippet of text that can be 171 called up with a command. 172 If embed parameters are specified, it creates an embed. 173 If the tag already exists, it deletes it. 174 175 Args: 176 ctx: The interaction context. 177 tag_name: The tag to create. 178 content: The content of the tag. 179 title: The title of the embed. 180 url: The url of the embed. 181 color: The color of the embed. 182 footer: The footer of the embed. 183 image: The image of the embed. 184 thumbnail: The thumbnail of the embed. 185 author: The author of the embed. 186 187 Raises: 188 InvalidParameters: The tag already exists. 189 """ 190 await ctx.response.defer(ephemeral=True) 191 parsed_color = None 192 opt_params = { 193 "title": title, 194 "url": url, 195 "color": parsed_color, 196 "footer": footer, 197 "image": image, 198 "thumbnail": thumbnail, 199 "author": author 200 } 201 if any(opt_params.values()) and not title: 202 raise exceptions.InvalidParameters("You need to specify a title" 203 " if you want to use embed parameters!") 204 if color: 205 parsed_color = discord.Color.from_str(color).value 206 opt_params["color"] = parsed_color 207 async with self._bt.get_connection() as conn: 208 new, tag_data = await conn.get_tag( 209 ctx.guild_id, # type: ignore 210 tag_name.lower(), 211 content, 212 embed_args=opt_params) 213 if new: 214 emd = discord.Embed(title="Tag created!", 215 description=f"Tag `{tag_name}` created!", 216 color=discord.Color.green()) 217 else: 218 await conn.delete(tag_data) 219 emd = discord.Embed(title="Tag deleted!", 220 description=f"Tag `{tag_name}` deleted!", 221 color=discord.Color.red()) 222 await conn.commit() 223 await ctx.followup.send(embed=emd, ephemeral=True) 224 225 @app_commands.command(name="edit", description="Edit a tag") 226 @checks.is_staff_check() 227 @app_commands.describe( 228 tag="The tag to edit", 229 content="The content of the tag", 230 title="The title of the embed", 231 url="The url of the embed", 232 color="The color of the embed in hex (e.g. #ff0000)", 233 footer="The footer of the embed", 234 image="The image of the embed", 235 thumbnail="The thumbnail of the embed", 236 author="The author of the embed", 237 ) 238 @app_commands.autocomplete(tag=tag_autocomplete) 239 async def edit(self, ctx: discord.Interaction, tag: str, content: Optional[str], title: Optional[str], 240 url: Optional[str], color: Optional[str], footer: Optional[str], image: Optional[str], 241 thumbnail: Optional[str], author: Optional[str]) -> None: 242 """Edits a tag. 243 244 This command edits a tag, which is a snippet of text that can be 245 called up with a command. 246 If embed parameters are specified, it edits the embed. 247 248 Args: 249 ctx: The interaction context. 250 tag: The tag to edit. 251 content: The content of the tag. 252 title: The title of the embed. 253 url: The url of the embed. 254 color: The color of the embed. 255 footer: The footer of the embed. 256 image: The image of the embed. 257 thumbnail: The thumbnail of the embed. 258 author: The author of the embed. 259 260 Raises: 261 InvalidParameters: The tag doesn't exist. 262 """ 263 parsed_color = None 264 if color: 265 parsed_color = discord.Color.from_str(color).value 266 opt_params = { 267 "url": url, 268 "color": parsed_color, 269 "footer": footer, 270 "image": image, 271 "thumbnail": thumbnail, 272 "author": author 273 } 274 async with self._bt.get_connection() as conn: 275 new, tag_data = await conn.get_tag( 276 ctx.guild_id, # type: ignore 277 tag.lower(), 278 "") 279 if new: 280 raise exceptions.InvalidParameters("That tag doesn't exist!") 281 if content: 282 tag_data.description = content 283 if title: 284 tag_data.title = title 285 if not tag_data.title and any(opt_params.values()): 286 raise exceptions.InvalidParameters("You need to specify a title if" 287 " you want to use embed parameters!") 288 for param, value in opt_params.items(): 289 if value: 290 setattr(tag_data, param, value) 291 await conn.commit() 292 emd = discord.Embed(title="Tag edited!", description=f"Tag `{tag}` edited!", color=discord.Color.green()) 293 await ctx.response.send_message(embed=emd, ephemeral=True)
Suitable for all your tagging needs!
This is the cog responsible for managing tags, which are essentially just snippets of text that can be called up with a command. Tags can be used by anyone, and can be created by anyone who has a staff role.
45 def __init__(self, bot_instance: bot.TicketsPlusBot): 46 """Initializes the TagUtils cog. 47 48 This method initializes the cog. 49 It also sets the bot instance as a private attribute. 50 And finally initializes the superclass. 51 52 Args: 53 bot_instance: The bot instance. 54 """ 55 self._bt = bot_instance 56 super().__init__() 57 logging.info("Loaded %s", self.__class__.__name__)
Initializes the TagUtils cog.
This method initializes the cog. It also sets the bot instance as a private attribute. And finally initializes the superclass.
Arguments:
- bot_instance: The bot instance.
59 async def tag_autocomplete(self, ctx: discord.Interaction, arg: str) -> List[app_commands.Choice[str]]: 60 """Autocomplete for tags. 61 62 This method is used to autocomplete tags. 63 It gets the tags from the database and returns them as a list of 64 choices. 65 66 Args: 67 ctx: The interaction context. 68 arg: The argument to autocomplete. 69 """ 70 async with self._bt.get_connection() as conn: 71 tags = await conn.get_tags(ctx.guild_id) # type: ignore 72 choices = [] 73 for tag in tags: 74 if len(choices) >= 25: 75 break 76 if arg.lower() in tag.tag_name.lower(): 77 choices.append(app_commands.Choice(name=tag.tag_name, value=tag.tag_name)) 78 return choices
Autocomplete for tags.
This method is used to autocomplete tags. It gets the tags from the database and returns them as a list of choices.
Arguments:
- ctx: The interaction context.
- arg: The argument to autocomplete.
80 async def prep_tag(self, guild: int, tag: str, mention: Optional[discord.User]) -> Tuple[str, None | discord.Embed]: 81 """Basic tag preparation. 82 83 Grabs the tag and packages it into a message and embed. 84 The message also mentions the user if specified. 85 86 Args: 87 guild: The guild to fetch the tag from. 88 tag: The tag to send. 89 mention: The user to mention. 90 91 Returns: 92 A tuple of the message and embed. 93 94 Raises: 95 InvalidParameters: The tag doesn't exist. 96 """ 97 async with self._bt.get_connection() as conn: 98 emd = None 99 tag_data = await conn.fetch_tag(guild, tag.lower()) # type: ignore 100 messg = "" 101 if mention: 102 messg = f"{mention.mention}\n" 103 if tag_data is None: 104 raise exceptions.InvalidParameters("That tag doesn't exist!") 105 if isinstance(tag_data, discord.Embed): 106 emd = tag_data 107 else: 108 messg += tag_data 109 return messg, emd
Basic tag preparation.
Grabs the tag and packages it into a message and embed. The message also mentions the user if specified.
Arguments:
- guild: The guild to fetch the tag from.
- tag: The tag to send.
- mention: The user to mention.
Returns:
A tuple of the message and embed.
Raises:
- InvalidParameters: The tag doesn't exist.
296async def setup(bot_instance: bot.TicketsPlusBot) -> None: 297 """Sets up the tag cog. 298 299 Sets the bot to use the cog properly. 300 301 Args: 302 bot_instance: The bot instance. 303 """ 304 await bot_instance.add_cog(TagUtils(bot_instance))
Sets up the tag cog.
Sets the bot to use the cog properly.
Arguments:
- bot_instance: The bot instance.