@@ -30,6 +30,7 @@ import { verificationEntries } from "@main/models/VerificationEntry";
30
30
import { VerificationMethod , verificationRecords } from "@main/models/VerificationRecord" ;
31
31
import VerificationExpiredQueue from "@main/queues/VerificationExpiredQueue" ;
32
32
import type ConfigurationManager from "@main/services/ConfigurationManager" ;
33
+ import type DirectiveParsingService from "@main/services/DirectiveParsingService" ;
33
34
import type ModerationActionService from "@main/services/ModerationActionService" ;
34
35
import { getAxiosClient } from "@main/utils/axios" ;
35
36
import { formatDistanceToNowStrict } from "date-fns" ;
@@ -53,6 +54,9 @@ class VerificationService extends Service {
53
54
@Inject ( "moderationActionService" )
54
55
private readonly moderationActionService ! : ModerationActionService ;
55
56
57
+ @Inject ( "directiveParsingService" )
58
+ private readonly directiveParsingService ! : DirectiveParsingService ;
59
+
56
60
private configFor ( guildId : Snowflake ) {
57
61
return this . configManager . config [ guildId ] ?. member_verification ;
58
62
}
@@ -68,7 +72,7 @@ class VerificationService extends Service {
68
72
69
73
const memberId = interaction . customId . split ( "_" ) [ 1 ] ;
70
74
71
- if ( interaction . user . id !== memberId ) {
75
+ if ( memberId !== "static" && interaction . user . id !== memberId ) {
72
76
return void ( await interaction . reply ( {
73
77
content : "This button is not under your control." ,
74
78
ephemeral : true
@@ -84,11 +88,11 @@ class VerificationService extends Service {
84
88
} ) ) ;
85
89
}
86
90
87
- if ( config . method !== "channel_interaction" ) {
88
- return void ( await interaction . reply ( {
89
- content : "This server does not have this verification method enabled." ,
90
- ephemeral : true
91
- } ) ) ;
91
+ if (
92
+ ( memberId !== "static" && config . method !== "channel_interaction" ) ||
93
+ ( memberId === "static" && config . method !== "channel_static_interaction" )
94
+ ) {
95
+ return ;
92
96
}
93
97
94
98
await interaction . deferReply ( { ephemeral : true } ) ;
@@ -102,6 +106,36 @@ class VerificationService extends Service {
102
106
}
103
107
} ) ;
104
108
109
+ if ( memberId === "static" ) {
110
+ const url = entry
111
+ ? this . getVerificationURL ( interaction . guildId , interaction . user . id , entry . token )
112
+ : await this . startVerification (
113
+ interaction . member as GuildMember ,
114
+ "Verification requested by user." ,
115
+ true
116
+ ) ;
117
+
118
+ if ( ! url ) {
119
+ return void ( await interaction . editReply ( {
120
+ content : "Failed to start verification."
121
+ } ) ) ;
122
+ }
123
+
124
+ await interaction . editReply ( {
125
+ content : `Hi **${ interaction . user . username } **! Please click the button below. Alternatively, you can verify yourself by copy-pasting the following link in your browser.\n${ url } ` ,
126
+ components : [
127
+ new ActionRowBuilder < ButtonBuilder > ( ) . addComponents (
128
+ new ButtonBuilder ( )
129
+ . setStyle ( ButtonStyle . Link )
130
+ . setLabel ( "Verify" )
131
+ . setURL ( url )
132
+ )
133
+ ]
134
+ } ) ;
135
+
136
+ return ;
137
+ }
138
+
105
139
if ( ! entry ) {
106
140
return void ( await interaction . editReply ( {
107
141
content : "This verification session has expired."
@@ -111,7 +145,7 @@ class VerificationService extends Service {
111
145
const url = this . getVerificationURL ( interaction . guildId , interaction . user . id , entry . token ) ;
112
146
113
147
await interaction . editReply ( {
114
- content : `Please click the button below. Alternatively, you can verify yourself by copy-pasting the following link in your browser.\n${ url } ` ,
148
+ content : `Hi ** ${ interaction . user . username } **! Please click the button below. Alternatively, you can verify yourself by copy-pasting the following link in your browser.\n${ url } ` ,
115
149
components : [
116
150
new ActionRowBuilder < ButtonBuilder > ( ) . addComponents (
117
151
new ButtonBuilder ( ) . setStyle ( ButtonStyle . Link ) . setLabel ( "Verify" ) . setURL ( url )
@@ -166,7 +200,7 @@ class VerificationService extends Service {
166
200
return `${ domain } ${ domain === env . FRONTEND_URL ? "/verify" : "" } /guilds/${ encodeURIComponent ( guildId ) } /challenge/onboarding?t=${ encodeURIComponent ( token ) } &u=${ encodeURIComponent ( memberId ) } ` ;
167
201
}
168
202
169
- public async startVerification ( member : GuildMember , reason : string ) {
203
+ public async startVerification ( member : GuildMember , reason : string , silent = false ) {
170
204
const config = this . configFor ( member . guild . id ) ;
171
205
172
206
if ( ! config || ! member . manageable ) {
@@ -206,7 +240,60 @@ class VerificationService extends Service {
206
240
207
241
const url = this . getVerificationURL ( member . guild . id , member . id , token ) ;
208
242
243
+ if ( silent ) {
244
+ return url ;
245
+ }
246
+
209
247
switch ( config . method ) {
248
+ case "channel_static_interaction" :
249
+ if ( ! config . channel ) {
250
+ break ;
251
+ }
252
+
253
+ if ( ! config . message_id_internal ) {
254
+ try {
255
+ const channel = await fetchChannel ( member . guild , config . channel ) ;
256
+
257
+ if ( ! channel ?. isTextBased ( ) ) {
258
+ break ;
259
+ }
260
+
261
+ const { data, output } = await this . directiveParsingService . parse (
262
+ config . verification_message ??
263
+ "Welcome to the server! Please verify yourself by clicking the button below."
264
+ ) ;
265
+ const options = {
266
+ content : output . trim ( ) === "" ? undefined : output ,
267
+ embeds : ( data . embeds as APIEmbed [ ] ) ?? [ ] ,
268
+ allowedMentions : { parse : [ ] , roles : [ ] , users : [ ] } ,
269
+ components : [
270
+ new ActionRowBuilder < ButtonBuilder > ( ) . addComponents (
271
+ new ButtonBuilder ( )
272
+ . setStyle ( ButtonStyle . Secondary )
273
+ . setLabel ( "Start Verification" )
274
+ . setCustomId ( "verify_static" )
275
+ )
276
+ ]
277
+ } ;
278
+
279
+ const { id } = await channel . send ( options ) ;
280
+
281
+ if ( this . configManager . config [ member . guild . id ] ?. member_verification ) {
282
+ this . configManager . config [
283
+ member . guild . id
284
+ ] ! . member_verification ! . message_id_internal = id ;
285
+ await this . configManager . write ( ) ;
286
+ }
287
+ } catch ( error ) {
288
+ this . logger . error (
289
+ "Failed to send verification message to channel: " ,
290
+ error
291
+ ) ;
292
+ }
293
+ }
294
+
295
+ break ;
296
+
210
297
case "channel_interaction" :
211
298
if ( ! config . channel ) {
212
299
break ;
@@ -284,6 +371,8 @@ class VerificationService extends Service {
284
371
} )
285
372
. schedule ( ) ;
286
373
}
374
+
375
+ return url ;
287
376
}
288
377
289
378
public async onVerificationExpire ( guildId : Snowflake , memberId : Snowflake ) {
0 commit comments