@@ -193,6 +193,154 @@ async def slashping(self, interaction: discord.Interaction) -> None:
193193 )
194194 await interaction .response .send_message (embed = embed )
195195
196+ @app_commands .command (name = "createcategory" , description = "Create a category and its channels from YAML configuration" )
197+ @app_commands .describe (yaml_path = "Path to the category YAML file (optional)" )
198+ async def createcategory_slash (self , interaction : discord .Interaction , yaml_path : str = None ) -> None :
199+ """Slash command to create a category and its channels based on YAML configuration."""
200+ await interaction .response .defer ()
201+
202+ # Use default path if none provided
203+ if yaml_path is None :
204+ yaml_path = "/home/user/Projects/gitcord-template/community/category.yaml"
205+
206+ try :
207+ # Check if the user has permission to manage channels
208+ if not interaction .user .guild_permissions .manage_channels :
209+ embed = create_embed (
210+ title = "❌ Permission Denied" ,
211+ description = "You need the 'Manage Channels' permission to use this command." ,
212+ color = discord .Color .red ()
213+ )
214+ await interaction .followup .send (embed = embed )
215+ return
216+
217+ # Parse category configuration
218+ try :
219+ with open (yaml_path , 'r' , encoding = 'utf-8' ) as file :
220+ category_config = yaml .safe_load (file )
221+ except FileNotFoundError :
222+ embed = create_embed (
223+ title = "❌ File Not Found" ,
224+ description = f"Category YAML file not found at: { yaml_path } " ,
225+ color = discord .Color .red ()
226+ )
227+ await interaction .followup .send (embed = embed )
228+ return
229+ except yaml .YAMLError as e :
230+ embed = create_embed (
231+ title = "❌ Invalid YAML" ,
232+ description = f"Failed to parse YAML file: { str (e )} " ,
233+ color = discord .Color .red ()
234+ )
235+ await interaction .followup .send (embed = embed )
236+ return
237+
238+ # Validate required fields
239+ required_fields = ['name' , 'type' , 'channels' ]
240+ for field in required_fields :
241+ if field not in category_config :
242+ embed = create_embed (
243+ title = "❌ Invalid Configuration" ,
244+ description = f"Missing required field: { field } " ,
245+ color = discord .Color .red ()
246+ )
247+ await interaction .followup .send (embed = embed )
248+ return
249+
250+ # Create the category
251+ category_kwargs = {
252+ 'name' : category_config ['name' ],
253+ 'position' : category_config .get ('position' , 0 )
254+ }
255+
256+ new_category = await interaction .guild .create_category (** category_kwargs )
257+ created_channels = []
258+
259+ # Create channels within the category
260+ for channel_name in category_config ['channels' ]:
261+ try :
262+ # Construct path to individual channel YAML file
263+ channel_yaml_path = f"/home/user/Projects/gitcord-template/community/{ channel_name } .yaml"
264+
265+ # Parse individual channel configuration
266+ channel_config = parse_channel_config (channel_yaml_path )
267+
268+ # Prepare channel creation parameters
269+ channel_kwargs = {
270+ 'name' : channel_config ['name' ],
271+ 'category' : new_category ,
272+ 'topic' : channel_config .get ('topic' , '' ),
273+ 'nsfw' : channel_config .get ('nsfw' , False )
274+ }
275+
276+ # Set position if specified
277+ if 'position' in channel_config :
278+ channel_kwargs ['position' ] = channel_config ['position' ]
279+
280+ # Create the channel based on type
281+ if channel_config ['type' ].lower () == 'text' :
282+ new_channel = await interaction .guild .create_text_channel (** channel_kwargs )
283+ elif channel_config ['type' ].lower () == 'voice' :
284+ new_channel = await interaction .guild .create_voice_channel (** channel_kwargs )
285+ else :
286+ logger .warning ("Skipping channel '%s': Invalid type '%s'" ,
287+ channel_name , channel_config ['type' ])
288+ continue
289+
290+ created_channels .append (new_channel )
291+ logger .info ("Channel '%s' created successfully in category '%s'" ,
292+ channel_config ['name' ], category_config ['name' ])
293+
294+ except Exception as e :
295+ logger .error ("Failed to create channel '%s': %s" , channel_name , e )
296+ continue
297+
298+ # Create success embed
299+ embed = create_embed (
300+ title = "✅ Category Created" ,
301+ description = f"Successfully created category: **{ new_category .name } **" ,
302+ color = discord .Color .green ()
303+ )
304+
305+ # Add fields
306+ embed .add_field (name = "Category Name" , value = new_category .name , inline = True )
307+ embed .add_field (name = "Category Type" , value = category_config ['type' ], inline = True )
308+ embed .add_field (name = "Position" , value = category_config .get ('position' , 0 ), inline = True )
309+ embed .add_field (name = "Channels Created" , value = f"{ len (created_channels )} /{ len (category_config ['channels' ])} " , inline = False )
310+
311+ if created_channels :
312+ channel_list = "\n " .join ([f"• { channel .mention } " for channel in created_channels ])
313+ embed .add_field (name = "Created Channels" , value = channel_list , inline = False )
314+
315+ await interaction .followup .send (embed = embed )
316+ logger .info ("Category '%s' with %d channels created successfully by %s" ,
317+ category_config ['name' ], len (created_channels ), interaction .user )
318+
319+ except discord .Forbidden :
320+ embed = create_embed (
321+ title = "❌ Permission Error" ,
322+ description = "I don't have permission to create categories or channels in this server." ,
323+ color = discord .Color .red ()
324+ )
325+ await interaction .followup .send (embed = embed )
326+ logger .error ("Permission error in createcategory slash command" )
327+ except discord .HTTPException as e :
328+ embed = create_embed (
329+ title = "❌ Discord Error" ,
330+ description = f"Discord API error: { str (e )} " ,
331+ color = discord .Color .red ()
332+ )
333+ await interaction .followup .send (embed = embed )
334+ logger .error ("Discord HTTP error in createcategory slash command: %s" , e )
335+ except Exception as e : # pylint: disable=broad-except
336+ embed = create_embed (
337+ title = "❌ Unexpected Error" ,
338+ description = f"An unexpected error occurred: { str (e )} " ,
339+ color = discord .Color .red ()
340+ )
341+ await interaction .followup .send (embed = embed )
342+ logger .error ("Unexpected error in createcategory slash command: %s" , e )
343+
196344 @commands .command (name = 'hello' )
197345 async def hello (self , ctx : commands .Context ) -> None :
198346 """Simple hello world command."""
@@ -335,6 +483,165 @@ async def createchannel_error(self, ctx: commands.Context,
335483 logger .error ("Error in createchannel command: %s" , error )
336484 await ctx .send (f"An error occurred: { error } " )
337485
486+ @commands .command (name = 'createcategory' )
487+ @commands .has_permissions (manage_channels = True )
488+ async def createcategory (self , ctx : commands .Context ) -> None :
489+ """Create a category and its channels based on properties defined in a YAML file."""
490+ yaml_path = "/home/user/Projects/gitcord-template/community/category.yaml"
491+
492+ try :
493+ # Check if the user has permission to manage channels
494+ if not ctx .author .guild_permissions .manage_channels :
495+ embed = create_embed (
496+ title = "❌ Permission Denied" ,
497+ description = "You need the 'Manage Channels' permission to use this command." ,
498+ color = discord .Color .red ()
499+ )
500+ await ctx .send (embed = embed )
501+ return
502+
503+ # Parse category configuration
504+ try :
505+ with open (yaml_path , 'r' , encoding = 'utf-8' ) as file :
506+ category_config = yaml .safe_load (file )
507+ except FileNotFoundError :
508+ embed = create_embed (
509+ title = "❌ File Not Found" ,
510+ description = f"Category YAML file not found at: { yaml_path } " ,
511+ color = discord .Color .red ()
512+ )
513+ await ctx .send (embed = embed )
514+ return
515+ except yaml .YAMLError as e :
516+ embed = create_embed (
517+ title = "❌ Invalid YAML" ,
518+ description = f"Failed to parse YAML file: { str (e )} " ,
519+ color = discord .Color .red ()
520+ )
521+ await ctx .send (embed = embed )
522+ return
523+
524+ # Validate required fields
525+ required_fields = ['name' , 'type' , 'channels' ]
526+ for field in required_fields :
527+ if field not in category_config :
528+ embed = create_embed (
529+ title = "❌ Invalid Configuration" ,
530+ description = f"Missing required field: { field } " ,
531+ color = discord .Color .red ()
532+ )
533+ await ctx .send (embed = embed )
534+ return
535+
536+ # Create the category
537+ category_kwargs = {
538+ 'name' : category_config ['name' ],
539+ 'position' : category_config .get ('position' , 0 )
540+ }
541+
542+ new_category = await ctx .guild .create_category (** category_kwargs )
543+ created_channels = []
544+
545+ # Create channels within the category
546+ for channel_name in category_config ['channels' ]:
547+ try :
548+ # Construct path to individual channel YAML file
549+ channel_yaml_path = f"/home/user/Projects/gitcord-template/community/{ channel_name } .yaml"
550+
551+ # Parse individual channel configuration
552+ channel_config = parse_channel_config (channel_yaml_path )
553+
554+ # Prepare channel creation parameters
555+ channel_kwargs = {
556+ 'name' : channel_config ['name' ],
557+ 'category' : new_category ,
558+ 'topic' : channel_config .get ('topic' , '' ),
559+ 'nsfw' : channel_config .get ('nsfw' , False )
560+ }
561+
562+ # Set position if specified
563+ if 'position' in channel_config :
564+ channel_kwargs ['position' ] = channel_config ['position' ]
565+
566+ # Create the channel based on type
567+ if channel_config ['type' ].lower () == 'text' :
568+ new_channel = await ctx .guild .create_text_channel (** channel_kwargs )
569+ elif channel_config ['type' ].lower () == 'voice' :
570+ new_channel = await ctx .guild .create_voice_channel (** channel_kwargs )
571+ else :
572+ logger .warning ("Skipping channel '%s': Invalid type '%s'" ,
573+ channel_name , channel_config ['type' ])
574+ continue
575+
576+ created_channels .append (new_channel )
577+ logger .info ("Channel '%s' created successfully in category '%s'" ,
578+ channel_config ['name' ], category_config ['name' ])
579+
580+ except Exception as e :
581+ logger .error ("Failed to create channel '%s': %s" , channel_name , e )
582+ continue
583+
584+ # Create success embed
585+ embed = create_embed (
586+ title = "✅ Category Created" ,
587+ description = f"Successfully created category: **{ new_category .name } **" ,
588+ color = discord .Color .green ()
589+ )
590+
591+ # Add fields
592+ embed .add_field (name = "Category Name" , value = new_category .name , inline = True )
593+ embed .add_field (name = "Category Type" , value = category_config ['type' ], inline = True )
594+ embed .add_field (name = "Position" , value = category_config .get ('position' , 0 ), inline = True )
595+ embed .add_field (name = "Channels Created" , value = f"{ len (created_channels )} /{ len (category_config ['channels' ])} " , inline = False )
596+
597+ if created_channels :
598+ channel_list = "\n " .join ([f"• { channel .mention } " for channel in created_channels ])
599+ embed .add_field (name = "Created Channels" , value = channel_list , inline = False )
600+
601+ await ctx .send (embed = embed )
602+ logger .info ("Category '%s' with %d channels created successfully by %s" ,
603+ category_config ['name' ], len (created_channels ), ctx .author )
604+
605+ except discord .Forbidden :
606+ embed = create_embed (
607+ title = "❌ Permission Error" ,
608+ description = "I don't have permission to create categories or channels in this server." ,
609+ color = discord .Color .red ()
610+ )
611+ await ctx .send (embed = embed )
612+ logger .error ("Permission error in createcategory command" )
613+ except discord .HTTPException as e :
614+ embed = create_embed (
615+ title = "❌ Discord Error" ,
616+ description = f"Discord API error: { str (e )} " ,
617+ color = discord .Color .red ()
618+ )
619+ await ctx .send (embed = embed )
620+ logger .error ("Discord HTTP error in createcategory command: %s" , e )
621+ except Exception as e : # pylint: disable=broad-except
622+ embed = create_embed (
623+ title = "❌ Unexpected Error" ,
624+ description = f"An unexpected error occurred: { str (e )} " ,
625+ color = discord .Color .red ()
626+ )
627+ await ctx .send (embed = embed )
628+ logger .error ("Unexpected error in createcategory command: %s" , e )
629+
630+ @createcategory .error
631+ async def createcategory_error (self , ctx : commands .Context ,
632+ error : commands .CommandError ) -> None :
633+ """Handle errors for the createcategory command."""
634+ if isinstance (error , commands .MissingPermissions ):
635+ embed = create_embed (
636+ title = "❌ Permission Denied" ,
637+ description = "You need the 'Manage Channels' permission to use this command." ,
638+ color = discord .Color .red ()
639+ )
640+ await ctx .send (embed = embed )
641+ else :
642+ logger .error ("Error in createcategory command: %s" , error )
643+ await ctx .send (f"An error occurred: { error } " )
644+
338645 @commands .Cog .listener ()
339646 async def on_command_error (self , ctx : commands .Context , error : commands .CommandError ) -> None :
340647 """Handle command errors."""
0 commit comments