@@ -14,6 +14,224 @@ import {cli} from "winston/lib/winston/config/index.js";
1414colors . enable ( ) ;
1515
1616export class CommandHelper {
17+
18+ public static async loadCommandsForGuild ( client : ExtendedClient , guild : Guild ) {
19+ Logger . info ( {
20+ timestamp : new Date ( ) . toISOString ( ) ,
21+ level : "info" ,
22+ label : "CommandHelper" ,
23+ message : `Loading commands for ${ client . user ?. displayName || "Unknown Bot" } ` ,
24+ botType : Config . BotType . toString ( ) || "Unknown" ,
25+ action : LoggingAction . Command ,
26+ } ) ;
27+
28+ let cmdlist : any [ ] = [ ] ;
29+ const stats = {
30+ commands : 0 ,
31+ userInstall : 0 ,
32+ contextMenus : 0 ,
33+ subCommands : 0 ,
34+ subCommandGroups : 0
35+ } ;
36+
37+ const modulesFolder = path . join ( process . cwd ( ) , ".build" , "src" , "modules" ) ;
38+ if ( ! fs . existsSync ( modulesFolder ) ) {
39+ console . warn ( "Modules folder does not exist." . red ) ;
40+ return ;
41+ }
42+
43+ const moduleDirectories = fs . readdirSync ( modulesFolder , { withFileTypes : true } )
44+ . filter ( dirent => dirent . isDirectory ( ) )
45+ . map ( dirent => dirent . name ) ;
46+
47+ for ( const moduleDir of moduleDirectories ) {
48+ const moduleCommandFolder = path . join ( modulesFolder , moduleDir , "commands" ) ;
49+
50+ if ( ! fs . existsSync ( moduleCommandFolder ) ) {
51+ continue
52+ }
53+
54+ const commandDirs = {
55+ commands : moduleCommandFolder ,
56+ contextMenus : path . join ( modulesFolder , moduleDir , "contextmenu" ) ,
57+ subCommands : path . join ( moduleCommandFolder , "subCommand" ) ,
58+ userInstall : path . join ( moduleCommandFolder , "userInstall" ) ,
59+ subCommandGroups : path . join ( moduleCommandFolder , "subCommandGroup" ) ,
60+ } ;
61+
62+ // Load main commands
63+ if ( fs . existsSync ( commandDirs . commands ) ) {
64+ const commandFiles = getFilesRecursively ( commandDirs . commands , [ ".js" ] ) ;
65+
66+ for ( const filePath of commandFiles ) {
67+ const relativePath = path . relative ( commandDirs . commands , filePath ) ;
68+ if ( relativePath . includes ( path . sep ) ) {
69+ continue ;
70+ }
71+
72+ try {
73+ const module = await import ( pathToFileURL ( filePath ) . href ) ;
74+ if ( module . default ?. data ) {
75+ cmdlist . push ( module . default . data . toJSON ( ) ) ;
76+ stats . commands ++ ;
77+ }
78+ } catch ( error ) {
79+ console . error ( `Failed to load command from ${ filePath } :` . red , error ) ;
80+ }
81+ }
82+ }
83+
84+ // Load userInstall commands
85+ if ( fs . existsSync ( commandDirs . userInstall ) ) {
86+ const userCommandFiles = getFilesRecursively ( commandDirs . userInstall , [ ".js" ] ) ;
87+ for ( const filePath of userCommandFiles ) {
88+ try {
89+ const module = await import ( pathToFileURL ( filePath ) . href ) ;
90+ if ( module . default ?. data ) {
91+ cmdlist . push ( module . default . data . toJSON ( ) ) ;
92+ stats . userInstall ++ ;
93+ }
94+ } catch ( error ) {
95+ console . error ( `Failed to load userInstall command from ${ filePath } :` . red , error ) ;
96+ }
97+ }
98+ }
99+
100+ // Load context menu commands
101+ if ( fs . existsSync ( commandDirs . contextMenus ) ) {
102+ const contextCommandFiles = getFilesRecursively ( commandDirs . contextMenus , [ ".js" ] ) ;
103+ for ( const filePath of contextCommandFiles ) {
104+ try {
105+ const module = await import ( pathToFileURL ( filePath ) . href ) ;
106+ if ( module . default ?. data ) {
107+ cmdlist . push ( module . default . data . toJSON ( ) ) ;
108+ stats . contextMenus ++ ;
109+ }
110+ } catch ( error ) {
111+ console . error ( `Failed to load context menu from ${ filePath } :` . red , error ) ;
112+ }
113+ }
114+ }
115+
116+ // Count subCommands and subCommandGroups (für Stats)
117+ if ( fs . existsSync ( commandDirs . subCommands ) ) {
118+ const subCommandFiles = getFilesRecursively ( commandDirs . subCommands , [ ".js" ] ) ;
119+ stats . subCommands += subCommandFiles . length ;
120+ }
121+
122+ if ( fs . existsSync ( commandDirs . subCommandGroups ) ) {
123+ const subCommandGroupFiles = getFilesRecursively ( commandDirs . subCommandGroups , [ ".js" ] ) ;
124+ stats . subCommandGroups += subCommandGroupFiles . length ;
125+ }
126+ }
127+
128+ if ( ! Config . Bot . DiscordApplicationId || ! Config . Bot . DiscordBotToken ) {
129+ throw new Error ( "Missing Config variables: DiscordApplicationId or DiscordBotToken" ) ;
130+ }
131+
132+ const restClient = new REST ( { version : "10" } ) . setToken ( Config . Bot . DiscordBotToken ) ;
133+
134+ // Clear application command
135+ await restClient . put ( Routes . applicationCommands ( Config . Bot . DiscordApplicationId ) , {
136+ body : [ ] ,
137+ } ) ;
138+
139+ const buildInCommandOverrides = await database . buildInCommands . findMany ( {
140+ where : {
141+ GuildCommandMangerId : guild . id
142+ }
143+ } )
144+ try {
145+ cmdlist = cmdlist
146+ . filter ( cmd => {
147+ const override = buildInCommandOverrides . find ( o => o . CodeName === cmd . name ) ;
148+ return ! ( override && override . IsEnabled === false ) ;
149+ } )
150+ . map ( cmd => {
151+ const override = buildInCommandOverrides . find ( o => o . CodeName === cmd . name ) ;
152+ if ( override ) {
153+ return {
154+ ...cmd ,
155+ name : override . CustomName ,
156+ description : override . Description ?? client . commands . get ( override . CodeName ) . data . description ,
157+ default_member_permissions : override . Permissions ?? client . commands . get ( override . CodeName ) . data . default_member_permissions
158+ } ;
159+ }
160+ return cmd ;
161+ } )
162+
163+ await restClient . put ( Routes . applicationGuildCommands ( Config . Bot . DiscordApplicationId , guild . id ) , {
164+ body : cmdlist ,
165+ } ) ;
166+
167+ const ticketCommands = await database . ticketSetups . findMany ( {
168+ where : {
169+ GuildId : guild . id
170+ }
171+ } )
172+
173+ for ( const ticketCommand of ticketCommands ) {
174+ const clientGuild = await client . guilds . fetch ( guild . id ) ;
175+
176+ let guildCommand = null ;
177+ try {
178+ guildCommand = await clientGuild . commands . fetch ( ticketCommand . SlashCommandId ) ;
179+ } catch {
180+ }
181+
182+ if ( ! guildCommand ) {
183+ guildCommand = await clientGuild . commands . create ( {
184+ name : ticketCommand . SlashCommandName ?? `open-${ ticketCommand . CustomId } -ticket` ,
185+ description : ticketCommand . SlashCommandDescription ?? ticketCommand . CustomId ,
186+ } ) ;
187+
188+ await database . ticketSetups . update ( {
189+ where : {
190+ CustomId : ticketCommand . CustomId ,
191+ } ,
192+ data : {
193+ SlashCommandId : guildCommand . id ,
194+ } ,
195+ } ) ;
196+ } else {
197+ if (
198+ guildCommand . name !== ticketCommand . SlashCommandName ||
199+ guildCommand . description !== ticketCommand . SlashCommandDescription
200+ ) {
201+ const updated = await guildCommand . edit ( {
202+ name : ticketCommand . SlashCommandName ?? guildCommand . name ,
203+ description : ticketCommand . SlashCommandDescription ?? guildCommand . description ,
204+ } ) ;
205+
206+ await database . ticketSetups . update ( {
207+ where : { CustomId : ticketCommand . CustomId } ,
208+ data : { SlashCommandId : updated . id } ,
209+ } ) ;
210+ }
211+ }
212+ }
213+
214+ } catch ( e ) {
215+ Logger . error ( {
216+ timestamp : new Date ( ) . toISOString ( ) ,
217+ level : "error" ,
218+ label : "CommandHelper" ,
219+ message : `Command loading failed with error: ${ e } - Commands failed at ${ cmdlist . map ( ( c ) => c . name ) } commands on Guild \"${ guild . name } \" (${ guild . id } )` ,
220+ botType : Config . BotType . toString ( ) || "Unknown" ,
221+ action : LoggingAction . Command ,
222+ } ) ;
223+ }
224+
225+ Logger . info ( {
226+ timestamp : new Date ( ) . toISOString ( ) ,
227+ level : "info" ,
228+ label : "CommandHelper" ,
229+ message : `Discord added ${ cmdlist . length } commands (${ stats . subCommands } subCommands, ${ stats . subCommandGroups } subCommandGroups), ${ stats . userInstall } userInstall commands, ${ stats . contextMenus } context menu commands from ${ moduleDirectories . length } module(s) for \"${ guild . name } \" (${ guild . id } )` ,
230+ botType : Config . BotType . toString ( ) || "Unknown" ,
231+ action : LoggingAction . Command ,
232+ } ) ;
233+ }
234+
17235 public static async loadCommands ( client : ExtendedClient ) {
18236 Logger . info ( {
19237 timestamp : new Date ( ) . toISOString ( ) ,
@@ -166,7 +384,6 @@ export class CommandHelper {
166384 body : cmdlist ,
167385 } ) ;
168386
169-
170387 const ticketCommands = await database . ticketSetups . findMany ( {
171388 where : {
172389 GuildId : guild . id
0 commit comments