11import {
22 ChatInputCommandInteraction ,
3+ Colors ,
4+ ContainerBuilder ,
35 MessageFlags ,
46 PermissionFlagsBits ,
57 SlashCommandBuilder ,
@@ -32,7 +34,7 @@ export class Command {
3234 requiredPermissions : ( keyof typeof PermissionFlagsBits ) [ ] ;
3335 cooldown : number ;
3436 masterLock : boolean
35- private _cooldowns : Map < string , number > ;
37+ private readonly _cooldowns : Map < string , number > ;
3638
3739 constructor ( { info, execute, guildOnly = false , ownerOnly = false , requiredPermissions = [ ] , cooldown = 0 , masterLock = false } : CommandOptions ) {
3840 this . data = info ;
@@ -50,50 +52,12 @@ export class Command {
5052 }
5153
5254 async run ( interaction : ChatInputCommandInteraction , ownerId ?: string ) : Promise < void > {
53- if ( this . guildOnly && ! interaction . guild ) {
54- await interaction . reply ( { content : 'This command is limited to servers' , flags : MessageFlags . Ephemeral } ) ;
55- return ;
56- }
57-
58- if ( this . ownerOnly && interaction . user . id !== ownerId ) {
59- await interaction . reply ( { content : 'Only the owner can run this command' , flags : MessageFlags . Ephemeral } ) ;
55+ if ( ! await this . validateCommand ( interaction , ownerId ) ) {
6056 return ;
6157 }
6258
63- if ( this . masterLock && interaction . guild ) {
64- if ( interaction . guild . id != process . env . MASTER_GUILD ) {
65- await interaction . reply ( 'This command cannot be ran in this server.' )
66- }
67- }
68-
69- if ( this . requiredPermissions . length && interaction . guild ) {
70- const missing = this . requiredPermissions . filter (
71- p => ! interaction . memberPermissions ?. has ( PermissionFlagsBits [ p ] )
72- ) ;
73- if ( missing . length ) {
74- await interaction . reply ( {
75- content : `You're lacking of the necessary permissions: \`${ missing . join ( ', ' ) } \`` ,
76- flags : MessageFlags . Ephemeral ,
77- } ) ;
78- return ;
79- }
80- }
81-
82- if ( this . cooldown > 0 ) {
83- const now = Date . now ( ) ;
84- const expiry = this . _cooldowns . get ( interaction . user . id ) ;
85- if ( expiry && now < expiry ) {
86- const unixExpiry = Math . floor ( expiry / 1000 ) ;
87- await interaction . reply ( {
88- content : `You can use \`/${ this . name } \` again, please wait <t:${ unixExpiry } :R>.` ,
89- flags : MessageFlags . Ephemeral ,
90- } ) ;
91- return ;
92- }
93- this . _cooldowns . set ( interaction . user . id , now + this . cooldown * 1000 ) ;
94- setTimeout ( ( ) => this . _cooldowns . delete ( interaction . user . id ) , this . cooldown * 1000 ) ;
95- }
96-
59+ await this . applyCooldown ( interaction ) ;
60+
9761 try {
9862 await this . execute ( interaction ) ;
9963 } catch ( err ) {
@@ -106,4 +70,74 @@ export class Command {
10670 }
10771 }
10872 }
73+
74+ private async validateCommand ( interaction : ChatInputCommandInteraction , ownerId ?: string ) : Promise < boolean > {
75+ if ( this . guildOnly && ! interaction . guild ) {
76+ await interaction . reply ( { content : 'This command is limited to servers' , flags : MessageFlags . Ephemeral } ) ;
77+ return false ;
78+ }
79+
80+ if ( this . ownerOnly && interaction . user . id !== ownerId ) {
81+ const container = new ContainerBuilder ( ) . setAccentColor ( Colors . Red )
82+ . addTextDisplayComponents ( ( txt ) => txt . setContent ( [
83+ "## Owner-locked command" ,
84+ "This command can only be used by the owner of this server."
85+ ] . join ( "\n" ) ) )
86+ await interaction . reply ( { components : [ container ] , flags : [ MessageFlags . Ephemeral , MessageFlags . IsComponentsV2 ] } )
87+ return false ;
88+ }
89+
90+ if ( this . masterLock && interaction . guild ?. id !== process . env . MASTER_GUILD ) {
91+ await interaction . reply ( 'This command cannot be ran in this server.' ) ;
92+ return false ;
93+ }
94+
95+ if ( ! await this . validatePermissions ( interaction ) ) {
96+ return false ;
97+ }
98+
99+ return true ;
100+ }
101+
102+ private async validatePermissions ( interaction : ChatInputCommandInteraction ) : Promise < boolean > {
103+ if ( ! this . requiredPermissions . length || ! interaction . guild ) {
104+ return true ;
105+ }
106+
107+ const missing = this . requiredPermissions . filter (
108+ p => ! interaction . memberPermissions ?. has ( PermissionFlagsBits [ p ] )
109+ ) ;
110+
111+ if ( missing . length ) {
112+ await interaction . reply ( {
113+ content : `You're lacking of the necessary permissions: \`${ missing . join ( ', ' ) } \`` ,
114+ flags : MessageFlags . Ephemeral ,
115+ } ) ;
116+ return false ;
117+ }
118+
119+ return true ;
120+ }
121+
122+ private async applyCooldown ( interaction : ChatInputCommandInteraction ) : Promise < void > {
123+ if ( this . cooldown <= 0 ) {
124+ return ;
125+ }
126+
127+ const now = Date . now ( ) ;
128+ const expiry = this . _cooldowns . get ( interaction . user . id ) ;
129+
130+ if ( expiry && now < expiry ) {
131+ const unixExpiry = Math . floor ( expiry / 1000 ) ;
132+ await interaction . reply ( {
133+ content : `You can use \`/${ this . name } \` again, please wait <t:${ unixExpiry } :R>.` ,
134+ flags : MessageFlags . Ephemeral ,
135+ } ) ;
136+ return ;
137+ }
138+
139+ this . _cooldowns . set ( interaction . user . id , now + this . cooldown * 1000 ) ;
140+ setTimeout ( ( ) => this . _cooldowns . delete ( interaction . user . id ) , this . cooldown * 1000 ) ;
141+ await this . execute ( interaction ) ;
142+ }
109143}
0 commit comments