@@ -5,8 +5,10 @@ import type {
5
5
ChatInputCommandInteraction ,
6
6
} from "discord.js" ;
7
7
import {
8
- ButtonStyle ,
9
8
ComponentType ,
9
+ ActionRowBuilder ,
10
+ ButtonBuilder ,
11
+ ButtonStyle ,
10
12
PermissionFlagsBits ,
11
13
SlashCommandBuilder ,
12
14
InteractionResponseType ,
@@ -47,8 +49,80 @@ export const command = new SlashCommandBuilder()
47
49
48
50
export const webserver : RequestHandler = async ( req , res , next ) => {
49
51
const body = req . body as APIInteraction ;
50
- // @ts -expect-error because apparently custom_id types are broken
51
- console . log ( "hook:" , body . data . component_type , body . data . custom_id ) ;
52
+
53
+ if (
54
+ // @ts -expect-error because apparently custom_id types are broken
55
+ body . data . component_type === 2 &&
56
+ // @ts -expect-error because apparently custom_id types are broken
57
+ body . data . custom_id . includes ( "close-ticket" )
58
+ ) {
59
+ // @ts -expect-error because apparently custom_id types are broken
60
+ const [ , ticketOpenerUserId ] = body . data . custom_id . split ( "||" ) ;
61
+ const threadId = body . message ?. channel_id ;
62
+ if ( ! body . member ) {
63
+ console . error (
64
+ "[err]: no member in ticket interaction" ,
65
+ JSON . stringify ( body ) ,
66
+ ) ;
67
+ res . send ( {
68
+ type : InteractionResponseType . ChannelMessageWithSource ,
69
+ data : {
70
+ content : "Something went wrong" ,
71
+ flags : MessageFlags . Ephemeral ,
72
+ } ,
73
+ } ) ;
74
+ return ;
75
+ }
76
+
77
+ const { [ SETTINGS . moderator ] : mod , [ SETTINGS . modLog ] : modLog } =
78
+ await fetchSettings (
79
+ // @ts -expect-error because this shouldn't have used a Guild instance but
80
+ // it's a lot to refactor
81
+ { id : body . guild_id } ,
82
+ [ SETTINGS . moderator , SETTINGS . modLog ] ,
83
+ ) ;
84
+
85
+ const { roles, user } = body . member ;
86
+ const interactionUserId = user . id ;
87
+
88
+ if (
89
+ ! threadId ||
90
+ ( ! roles ?. includes ( mod ) && ticketOpenerUserId !== interactionUserId )
91
+ ) {
92
+ res . send ( {
93
+ type : InteractionResponseType . ChannelMessageWithSource ,
94
+ data : {
95
+ content : "This isn't your ticket to close!" ,
96
+ flags : MessageFlags . Ephemeral ,
97
+ } ,
98
+ } ) ;
99
+ return ;
100
+ }
101
+
102
+ // TODO: await interaction.channel.setLocked(true);
103
+ await Promise . all ( [
104
+ rest . delete ( Routes . threadMembers ( threadId , ticketOpenerUserId ) ) ,
105
+ rest . post ( Routes . channelMessages ( modLog ) , {
106
+ body : {
107
+ content : `<@${ ticketOpenerUserId } >’s ticket <#${ threadId } > closed by <@${ interactionUserId } > ` ,
108
+ mentions : [ ] ,
109
+ flags : MessageFlags . SuppressNotifications ,
110
+ } ,
111
+ } ) ,
112
+ res . send ( {
113
+ type : InteractionResponseType . ChannelMessageWithSource ,
114
+ data : {
115
+ content : `The ticket was closed by <@${ ticketOpenerUserId } >` ,
116
+ mentions : [ ] ,
117
+ flags : MessageFlags . SuppressNotifications ,
118
+ } ,
119
+ } ) ,
120
+ ] ) ;
121
+
122
+ return ;
123
+ }
124
+
125
+ // Handle "open ticket" button pressed
52
126
// @ts -expect-error because apparently custom_id types are broken
53
127
if ( body . data . component_type === 2 && body . data . custom_id === "open-ticket" ) {
54
128
res . send ( {
@@ -76,6 +150,8 @@ export const webserver: RequestHandler = async (req, res, next) => {
76
150
} ) ;
77
151
return ;
78
152
}
153
+
154
+ // Handle "what's up" modal submission
79
155
if ( isModalInteraction ( body ) ) {
80
156
if (
81
157
! body . channel ||
@@ -98,7 +174,7 @@ export const webserver: RequestHandler = async (req, res, next) => {
98
174
// @ts -expect-error because this shouldn't have used a Guild instance but
99
175
// it's a lot to refactor
100
176
{ id : body . guild_id } ,
101
- [ SETTINGS . moderator ] ,
177
+ [ SETTINGS . moderator , SETTINGS . modLog ] ,
102
178
) ;
103
179
const thread = ( await rest . post ( Routes . threads ( body . channel . id ) , {
104
180
body : {
@@ -112,7 +188,7 @@ export const webserver: RequestHandler = async (req, res, next) => {
112
188
} ) ) as RESTPostAPIChannelThreadsResult ;
113
189
await rest . post ( Routes . channelMessages ( thread . id ) , {
114
190
body : {
115
- content : `<@${ body . message . interaction_metadata . user . id } >, this is a private space only visible to the <@&${ mod } > role.` ,
191
+ content : `<@${ body . message . interaction_metadata . user . id } >, this is a private space only visible to you and the <@&${ mod } > role.` ,
116
192
} as RESTPostAPIChannelMessageJSONBody ,
117
193
} ) ;
118
194
await rest . post ( Routes . channelMessages ( thread . id ) , {
@@ -122,6 +198,21 @@ export const webserver: RequestHandler = async (req, res, next) => {
122
198
) } `,
123
199
} ,
124
200
} ) ;
201
+ await rest . post ( Routes . channelMessages ( thread . id ) , {
202
+ body : {
203
+ content : "When you’ve finished, please close the ticket." ,
204
+ components : [
205
+ new ActionRowBuilder ( ) . addComponents (
206
+ new ButtonBuilder ( )
207
+ . setCustomId (
208
+ `close-ticket||${ body . message . interaction_metadata . user . id } ` ,
209
+ )
210
+ . setLabel ( "Close ticket" )
211
+ . setStyle ( ButtonStyle . Danger ) ,
212
+ ) ,
213
+ ] ,
214
+ } ,
215
+ } ) ;
125
216
126
217
res . send ( {
127
218
type : InteractionResponseType . ChannelMessageWithSource ,
0 commit comments