2023-01-09 18:26:41 -08:00
import {
ActionRow ,
botId ,
ButtonComponent ,
ButtonData ,
cache ,
cacheHandlers ,
// MySQL Driver deps
Client ,
DebugArg ,
deleteMessage ,
DiscordActivityTypes ,
DiscordButtonStyles ,
DiscordenoGuild ,
DiscordenoMessage ,
DiscordInteractionResponseTypes ,
DiscordInteractionTypes ,
editBotNickname ,
editBotStatus ,
Embed ,
getGuild ,
getMessage ,
getUser ,
hasGuildPermissions ,
initLog ,
Intents ,
log ,
// Log4Deno deps
LT ,
sendDirectMessage ,
sendInteractionResponse ,
sendMessage ,
// Discordeno deps
startBot ,
} from './deps.ts' ;
import { ActiveLFG , BuildingLFG , GuildCleanChannels , GuildModRoles , GuildPrefixes } from './src/mod.d.ts' ;
import intervals from './src/intervals.ts' ;
import { LFGActivities } from './src/games.ts' ;
import { JoinLeaveType } from './src/lfgHandlers.d.ts' ;
import { handleLFGStep , handleMemberJoin , handleMemberLeave , urlToIds } from './src/lfgHandlers.ts' ;
import { constantCmds , editBtns , lfgStepQuestions } from './src/constantCmds.ts' ;
import { jsonParseBig , jsonStringifyBig } from './src/utils.ts' ;
2023-01-11 19:23:27 -08:00
import { DEBUG , LOCALMODE } from '../flags.ts' ;
import config from '../config.ts' ;
2023-01-09 18:26:41 -08:00
// Initialize DB client
const dbClient = await new Client ( ) . connect ( {
hostname : LOCALMODE ? config.db.localhost : config.db.host ,
port : config.db.port ,
db : config.db.name ,
username : config.db.username ,
password : config.db.password ,
} ) ;
// Initialize logging client with folder to use for logs, needs --allow-write set on Deno startup
initLog ( 'logs' , DEBUG ) ;
log ( LT . INFO , ` ${ config . name } Starting up . . . ` ) ;
// Handle idling out the active builders
const activeBuilders : Array < BuildingLFG > = [ ] ;
setInterval ( ( ) = > {
intervals . buildingTimeout ( activeBuilders ) ;
} , 1000 ) ;
const activeLFGPosts : Array < ActiveLFG > = jsonParseBig ( localStorage . getItem ( 'activeLFGPosts' ) || '[]' ) ;
log ( LT . INFO , ` Loaded ${ activeLFGPosts . length } activeLFGPosts ` ) ;
setInterval ( ( ) = > {
intervals . lfgNotifier ( activeLFGPosts ) ;
} , 60000 ) ;
const guildPrefixes : Map < bigint , string > = new Map ( ) ;
const getGuildPrefixes = await dbClient . query ( 'SELECT * FROM guild_prefix' ) ;
getGuildPrefixes . forEach ( ( g : GuildPrefixes ) = > {
guildPrefixes . set ( g . guildId , g . prefix ) ;
} ) ;
const guildModRoles : Map < bigint , bigint > = new Map ( ) ;
const getGuildModRoles = await dbClient . query ( 'SELECT * FROM guild_mod_role' ) ;
getGuildModRoles . forEach ( ( g : GuildModRoles ) = > {
guildModRoles . set ( g . guildId , g . roleId ) ;
} ) ;
const cleanChannels : Map < bigint , Array < bigint > > = new Map ( ) ;
const getCleanChannels = await dbClient . query ( 'SELECT * FROM guild_clean_channel' ) ;
getCleanChannels . forEach ( ( g : GuildCleanChannels ) = > {
const tempArr = cleanChannels . get ( g . guildId ) || [ ] ;
tempArr . push ( g . channelId ) ;
cleanChannels . set ( g . guildId , tempArr ) ;
} ) ;
const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' ;
// Start up the Discord Bot
startBot ( {
2023-01-11 19:23:27 -08:00
token : LOCALMODE ? config.localToken : config.token ,
2023-01-09 18:26:41 -08:00
intents : [ Intents . GuildMessages , Intents . DirectMessages , Intents . Guilds ] ,
eventHandlers : {
ready : ( ) = > {
log ( LT . INFO , ` ${ config . name } Logged in! ` ) ;
editBotStatus ( {
activities : [ {
name : 'Booting up . . .' ,
type : DiscordActivityTypes . Game ,
createdAt : new Date ( ) . getTime ( ) ,
} ] ,
status : 'online' ,
} ) ;
// Interval to rotate the status text every 30 seconds to show off more commands
setInterval ( async ( ) = > {
log ( LT . LOG , 'Changing bot status' ) ;
try {
const cachedCount = await cacheHandlers . size ( 'guilds' ) ;
// Wrapped in try-catch due to hard crash possible
editBotStatus ( {
activities : [ {
name : intervals.getRandomStatus ( cachedCount ) ,
type : DiscordActivityTypes . Game ,
createdAt : new Date ( ) . getTime ( ) ,
} ] ,
status : 'online' ,
} ) ;
} catch ( e ) {
log ( LT . ERROR , ` Failed to update status: ${ jsonStringifyBig ( e ) } ` ) ;
}
} , 30000 ) ;
// Interval to update bot list stats every 24 hours
LOCALMODE ? log ( LT . INFO , 'updateListStatistics not running' ) : setInterval ( ( ) = > {
log ( LT . LOG , 'Updating all bot lists statistics' ) ;
intervals . updateListStatistics ( botId , cache . guilds . size ) ;
} , 86400000 ) ;
// setTimeout added to make sure the startup message does not error out
setTimeout ( ( ) = > {
LOCALMODE && editBotNickname ( config . devServer , ` LOCAL - ${ config . name } ` ) ;
LOCALMODE ? log ( LT . INFO , 'updateListStatistics not running' ) : intervals . updateListStatistics ( botId , cache . guilds . size ) ;
editBotStatus ( {
activities : [ {
name : 'Booting Complete' ,
type : DiscordActivityTypes . Game ,
createdAt : new Date ( ) . getTime ( ) ,
} ] ,
status : 'online' ,
} ) ;
sendMessage ( config . logChannel , ` ${ config . name } has started, running version ${ config . version } . ` ) . catch ( ( e ) = > {
log ( LT . ERROR , ` Failed to send message: ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
} , 1000 ) ;
} ,
guildCreate : ( guild : DiscordenoGuild ) = > {
log ( LT . LOG , ` Handling joining guild ${ jsonStringifyBig ( guild ) } ` ) ;
sendMessage ( config . logChannel , ` New guild joined: ${ guild . name } (id: ${ guild . id } ). This guild has ${ guild . memberCount } members! ` ) . catch ( ( e ) = > {
log ( LT . ERROR , ` Failed to send message: ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
} ,
guildDelete : async ( guild : DiscordenoGuild ) = > {
log ( LT . LOG , ` Handling leaving guild ${ jsonStringifyBig ( guild ) } ` ) ;
sendMessage ( config . logChannel , ` I have been removed from: ${ guild . name } (id: ${ guild . id } ). ` ) . catch ( ( e ) = > {
log ( LT . ERROR , ` Failed to send message: ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
try {
await dbClient . execute ( 'DELETE FROM guild_prefix WHERE guildId = ?' , [ guild . id ] ) ;
await dbClient . execute ( 'DELETE FROM guild_mod_role WHERE guildId = ?' , [ guild . id ] ) ;
await dbClient . execute ( 'DELETE FROM guild_clean_channel WHERE guildId = ?' , [ guild . id ] ) ;
} catch ( e ) {
log ( LT . WARN , ` Failed to remove guild from DB: ${ jsonStringifyBig ( e ) } ` ) ;
}
} ,
debug : ( dmsg : string | DebugArg , data? : string ) = > log ( LT . LOG , ` Debug Message | ${ jsonStringifyBig ( dmsg ) } | ${ jsonStringifyBig ( data ) } ` , false ) ,
messageCreate : async ( message : DiscordenoMessage ) = > {
// Ignore all other bots
if ( message . isBot ) return ;
const prefix = guildPrefixes . get ( message . guildId ) || config . prefix ;
// Handle messages not starting with the prefix
if ( message . content . indexOf ( prefix ) !== 0 ) {
// Mentions
if ( message . mentionedUserIds [ 0 ] === botId && ( message . content . trim ( ) . startsWith ( ` <@ ${ botId } > ` ) || message . content . trim ( ) . startsWith ( ` <@! ${ botId } > ` ) ) ) {
// Light telemetry to see how many times a command is being run
await dbClient . execute ( ` CALL INC_CNT("prefix"); ` ) . catch ( ( e ) = > {
log ( LT . ERROR , ` Failed to call stored procedure INC_CNT: ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
if ( message . content . trim ( ) === ` <@ ${ botId } > ` || message . content . trim ( ) === ` <@! ${ botId } > ` ) {
message . send ( {
embeds : [ {
title : ` Hello ${ message . member ? . username } , and thanks for using Group Up! ` ,
fields : [
{
name : ` My prefix in this guild is: \` ${ prefix } \` ` ,
value : 'Mention me with a new prefix to change it.' ,
} ,
] ,
} ] ,
} ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to send message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
} else if ( await hasGuildPermissions ( message . guildId , message . authorId , [ 'ADMINISTRATOR' ] ) ) {
const newPrefix = message . content . replace ( ` <@! ${ botId } > ` , '' ) . replace ( ` <@ ${ botId } > ` , '' ) . trim ( ) ;
if ( newPrefix . length <= 10 ) {
let success = true ;
if ( guildPrefixes . has ( message . guildId ) ) {
// Execute the DB update
await dbClient . execute ( 'UPDATE guild_prefix SET prefix = ? WHERE guildId = ?' , [ newPrefix , message . guildId ] ) . catch ( ( e ) = > {
log ( LT . ERROR , ` Failed to insert into database: ${ jsonStringifyBig ( e ) } ` ) ;
success = false ;
} ) ;
} else {
// Execute the DB insertion
await dbClient . execute ( 'INSERT INTO guild_prefix(guildId,prefix) values(?,?)' , [ message . guildId , newPrefix ] ) . catch ( ( e ) = > {
log ( LT . ERROR , ` Failed to insert into database: ${ jsonStringifyBig ( e ) } ` ) ;
success = false ;
} ) ;
}
if ( success ) {
guildPrefixes . set ( message . guildId , newPrefix ) ;
message . send ( {
embeds : [ {
fields : [
{
name : ` My prefix in this guild is now: \` ${ newPrefix } \` ` ,
value : 'Mention me with a new prefix to change it.' ,
} ,
] ,
} ] ,
} ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to send message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
} else {
message . send ( {
embeds : [ {
fields : [
{
name : 'Something went wrong!' ,
value : ` My prefix is still \` ${ prefix } \` . Please try again, and if the problem persists, please report this to the developers using \` ${ prefix } report \` . ` ,
} ,
] ,
} ] ,
} ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to send message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
}
} else {
message . send ( {
embeds : [ {
fields : [
{
name : 'Prefix too long, please set a prefix less than 10 characters long.' ,
value : 'Mention me with a new prefix to change it.' ,
} ,
] ,
} ] ,
} ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to send message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
}
}
return ;
}
// Other
const activeIdx = activeBuilders . findIndex ( ( x ) = > ( message . channelId === x . channelId && message . authorId === x . userId ) ) ;
if ( activeIdx > - 1 ) {
activeBuilders [ activeIdx ] . lastTouch = new Date ( ) ;
activeBuilders [ activeIdx ] = await handleLFGStep ( activeBuilders [ activeIdx ] , message . content ) ;
if ( activeBuilders [ activeIdx ] . step === 'done' ) {
if ( message . member ) {
const memberJoined = handleMemberJoin ( activeBuilders [ activeIdx ] . lfgMsg . embeds [ 0 ] . fields || [ ] , message . member , false ) ;
const newTimestamp = new Date ( parseInt ( memberJoined . embed [ 1 ] . value . split ( '#' ) [ 1 ] ) ) ;
const newLfgUid = ALPHABET [ Math . floor ( Math . random ( ) * 26 ) ] + ALPHABET [ Math . floor ( Math . random ( ) * 26 ) ] ;
const tempMembers = memberJoined . embed [ 4 ] . name . split ( ':' ) [ 1 ] . split ( '/' ) ;
const currentMembers = parseInt ( tempMembers [ 0 ] ) ;
const maxMembers = parseInt ( tempMembers [ 1 ] ) ;
if ( activeBuilders [ activeIdx ] . editing ) {
if ( currentMembers > maxMembers ) {
const currentPeople = memberJoined . embed [ 4 ] . value . split ( '\n' ) ;
const newAlts = currentPeople . splice ( maxMembers ) ;
memberJoined . embed [ 4 ] . value = currentPeople . join ( '\n' ) || 'None' ;
memberJoined . embed [ 5 ] . value = ` ${ newAlts . join ( '\n' ) } \ n ${ memberJoined . embed [ 5 ] . value === 'None' ? '' : memberJoined . embed [ 5 ] . value } ` ;
memberJoined . embed [ 4 ] . name = ` Members Joined: ${ maxMembers } / ${ maxMembers } ` ;
}
}
await activeBuilders [ activeIdx ] . lfgMsg . edit ( {
content : '' ,
embeds : [ {
fields : memberJoined.embed ,
footer : {
text : ` Created by: ${ message . member . username } | ${ newLfgUid } ` ,
} ,
timestamp : newTimestamp.toISOString ( ) ,
} ] ,
components : [
{
type : 1 ,
components : [
{
type : 2 ,
label : 'Join' ,
customId : 'active@join_group' ,
style : DiscordButtonStyles.Success ,
} ,
{
type : 2 ,
label : 'Leave' ,
customId : 'active@leave_group' ,
style : DiscordButtonStyles.Danger ,
} ,
{
type : 2 ,
label : 'Join as Alternate' ,
customId : 'active@alternate_group' ,
style : DiscordButtonStyles.Primary ,
} ,
] ,
} ,
] ,
} ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to edit message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
if ( activeBuilders [ activeIdx ] ) {
const activeLFGIdx = activeLFGPosts . findIndex (
( lfg ) = > ( lfg . channelId === activeBuilders [ activeIdx ] . channelId && lfg . messageId === activeBuilders [ activeIdx ] . lfgMsg . id && lfg . ownerId === activeBuilders [ activeIdx ] . userId ) ,
) ;
if ( activeLFGIdx >= 0 ) {
activeLFGPosts [ activeLFGIdx ] . lfgUid = newLfgUid ;
activeLFGPosts [ activeLFGIdx ] . lfgTime = newTimestamp . getTime ( ) ;
activeLFGPosts [ activeLFGIdx ] . notified = false ;
activeLFGPosts [ activeLFGIdx ] . locked = false ;
} else {
activeLFGPosts . push ( {
messageId : activeBuilders [ activeIdx ] . lfgMsg . id ,
channelId : activeBuilders [ activeIdx ] . lfgMsg . channelId ,
ownerId : message.authorId ,
lfgUid : newLfgUid ,
lfgTime : newTimestamp.getTime ( ) ,
notified : false ,
locked : false ,
} ) ;
}
localStorage . setItem ( 'activeLFGPosts' , jsonStringifyBig ( activeLFGPosts ) ) ;
}
}
await activeBuilders [ activeIdx ] . questionMsg . delete ( ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
activeBuilders . splice ( activeIdx , 1 ) ;
}
await message . delete ( ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
return ;
}
// Should this get cleaned up?
const enabledCleanChannels = cleanChannels . get ( message . guildId ) ;
if ( enabledCleanChannels && enabledCleanChannels . length && enabledCleanChannels . indexOf ( message . channelId ) > - 1 ) {
message . delete ( 'Cleaning Channel' ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
return ;
}
return ;
} else {
// User is sending a command, make sure its a lfg command if its being sent in a clean channel
const enabledCleanChannels = cleanChannels . get ( message . guildId ) ;
if ( enabledCleanChannels && enabledCleanChannels . length && enabledCleanChannels . indexOf ( message . channelId ) > - 1 && message . content . indexOf ( ` ${ prefix } lfg ` ) !== 0 ) {
message . delete ( 'Cleaning Channel' ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
return ;
}
}
log ( LT . LOG , ` Handling message ${ jsonStringifyBig ( message ) } ` ) ;
// Split into standard command + args format
const args = message . content . slice ( prefix . length ) . trim ( ) . split ( /[ \n]+/g ) ;
const command = args . shift ( ) ? . toLowerCase ( ) ;
// All commands below here
2023-01-11 19:23:27 -08:00
if ( command === 'lfg' ) {
2023-01-09 18:26:41 -08:00
// Light telemetry to see how many times a command is being run
dbClient . execute ( ` CALL INC_CNT("lfg"); ` ) . catch ( ( e ) = > {
log ( LT . ERROR , ` Failed to call stored procedure INC_CNT: ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
const subcmd = ( args [ 0 ] || 'help' ) . toLowerCase ( ) ;
const lfgUid = ( args [ 1 ] || '' ) . toUpperCase ( ) ;
// Learn how the LFG command works
if ( subcmd === 'help' || subcmd === 'h' || subcmd === '?' ) {
message . send ( constantCmds . lfgHelp ) . catch ( ( e ) = > {
log ( LT . ERROR , ` Failed to send message: ${ jsonStringifyBig ( message ) } | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
} // Create a new LFG
else if ( subcmd === 'create' || subcmd === 'c' ) {
try {
const lfgMsg = await message . send ( ` Creating new LFG post for <@ ${ message . authorId } >. Please reply with the requested information and watch as your LFG post gets created! ` ) ;
const gameButtons : Array < ButtonComponent > = Object . keys ( LFGActivities ) . map ( ( game ) = > {
return {
type : 2 ,
label : game ,
customId : ` building@set_game# ${ game } ` ,
style : DiscordButtonStyles.Primary ,
} ;
} ) ;
const buttonComps : Array < ActionRow > = [ ] ;
const temp : Array < ActionRow [ ' components ' ] > = [ ] ;
gameButtons . forEach ( ( btn , idx ) = > {
if ( ! temp [ Math . floor ( idx / 5 ) ] ) {
temp [ Math . floor ( idx / 5 ) ] = [ btn ] ;
} else {
temp [ Math . floor ( idx / 5 ) ] . push ( btn ) ;
}
} ) ;
temp . forEach ( ( btns ) = > {
if ( btns . length && btns . length <= 5 ) {
buttonComps . push ( {
type : 1 ,
components : btns ,
} ) ;
}
} ) ;
const question = await message . send ( {
content : lfgStepQuestions.set_game ,
components : buttonComps ,
} ) ;
activeBuilders . push ( {
userId : message.authorId ,
channelId : message.channelId ,
step : 'set_game' ,
lfgMsg : lfgMsg ,
questionMsg : question ,
lastTouch : new Date ( ) ,
maxIdle : 60 ,
editing : false ,
} ) ;
message . delete ( ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
} catch ( e ) {
log ( LT . WARN , ` LFG failed at step | create | ${ jsonStringifyBig ( e ) } ` ) ;
}
} // Delete an existing LFG
else if ( subcmd === 'delete' || subcmd === 'd' ) {
try {
// User provided a Uid, use it
if ( lfgUid ) {
const matches = activeLFGPosts . filter ( ( lfg ) = > ( message . authorId === lfg . ownerId && message . channelId === lfg . channelId && lfgUid === lfg . lfgUid ) ) ;
// Found one, delete
if ( matches . length ) {
await deleteMessage ( matches [ 0 ] . channelId , matches [ 0 ] . messageId , 'User requested LFG to be deleted.' ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to find message to delete | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
const lfgIdx = activeLFGPosts . findIndex ( ( lfg ) = > ( message . authorId === lfg . ownerId && message . channelId === lfg . channelId && lfgUid === lfg . lfgUid ) ) ;
activeLFGPosts . splice ( lfgIdx , 1 ) ;
localStorage . setItem ( 'activeLFGPosts' , jsonStringifyBig ( activeLFGPosts ) ) ;
const m = await message . send ( constantCmds . lfgDelete3 ) ;
m . delete ( 'Channel Cleanup' , 5000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
message . delete ( 'Channel Cleanup' , 5000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
} // Did not find one
else {
const m = await message . send ( constantCmds . lfgDelete1 ) ;
m . delete ( 'Channel Cleanup' , 5000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
message . delete ( 'Channel Cleanup' , 5000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
}
} // User did not provide a Uid, find it automatically
else {
const matches = activeLFGPosts . filter ( ( lfg ) = > ( message . authorId === lfg . ownerId && message . channelId === lfg . channelId ) ) ;
// Found one, delete
if ( matches . length === 1 ) {
await deleteMessage ( matches [ 0 ] . channelId , matches [ 0 ] . messageId , 'User requested LFG to be deleted.' ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to find message to delete | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
const lfgIdx = activeLFGPosts . findIndex ( ( lfg ) = > ( message . authorId === lfg . ownerId && message . channelId === lfg . channelId ) ) ;
activeLFGPosts . splice ( lfgIdx , 1 ) ;
localStorage . setItem ( 'activeLFGPosts' , jsonStringifyBig ( activeLFGPosts ) ) ;
const m = await message . send ( constantCmds . lfgDelete3 ) ;
m . delete ( 'Channel Cleanup' , 5000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
message . delete ( 'Channel Cleanup' , 5000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
} // Found multiple, notify user
else if ( matches . length ) {
const deleteMsg = constantCmds . lfgDelete2 ;
const deepCloningFailedSoThisIsTheSolution = constantCmds . lfgDelete2 . embeds [ 0 ] . fields [ 0 ] . value ;
matches . forEach ( ( mt ) = > {
deleteMsg . embeds [ 0 ] . fields [ 0 ] . value += ` [ ${ mt . lfgUid } ](https://discord.com/channels/ ${ message . guildId } / ${ mt . channelId } / ${ mt . messageId } ) \ n ` ;
} ) ;
deleteMsg . embeds [ 0 ] . fields [ 0 ] . value += '\nThis message will self descruct in 30 seconds.' ;
const m = await message . send ( deleteMsg ) ;
constantCmds . lfgDelete2 . embeds [ 0 ] . fields [ 0 ] . value = deepCloningFailedSoThisIsTheSolution ;
m . delete ( 'Channel Cleanup' , 30000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
message . delete ( 'Channel Cleanup' , 30000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
} // Found none, notify user you cannot delete other's lfgs
else {
const m = await message . send ( constantCmds . lfgDelete1 ) ;
m . delete ( 'Channel Cleanup' , 5000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
message . delete ( 'Channel Cleanup' , 5000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
}
}
} catch ( e ) {
log ( LT . WARN , ` LFG failed at step | delete | ${ jsonStringifyBig ( e ) } ` ) ;
}
} // Edit an existing LFG
else if ( subcmd === 'edit' || subcmd === 'e' ) {
try {
// User provided a Uid, use it
if ( lfgUid ) {
const matches = activeLFGPosts . filter ( ( lfg ) = > ( message . authorId === lfg . ownerId && message . channelId === lfg . channelId && lfgUid === lfg . lfgUid ) ) ;
// Found one, edit
if ( matches . length ) {
const lfgMessage = await ( await getMessage ( matches [ 0 ] . channelId , matches [ 0 ] . messageId ) ) . edit ( {
content : ` Editing new LFG post for <@ ${ matches [ 0 ] . ownerId } >. Please reply with the requested information and watch as your LFG post gets edited! ` ,
} ) ;
const question = await message . send ( {
content : 'Please select an item to edit from the buttons below:' ,
components : [ {
type : 1 ,
components : editBtns ,
} ] ,
} ) ;
activeBuilders . push ( {
userId : matches [ 0 ] . ownerId ,
channelId : matches [ 0 ] . channelId ,
step : 'edit_btn' ,
lfgMsg : lfgMessage ,
questionMsg : question ,
lastTouch : new Date ( ) ,
maxIdle : 60 ,
editing : true ,
} ) ;
message . delete ( ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
} // Did not find one
else {
const m = await message . send ( constantCmds . lfgEdit1 ) ;
m . delete ( 'Channel Cleanup' , 5000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
message . delete ( 'Channel Cleanup' , 5000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
}
} // User did not provide a Uid, find it automatically
else {
const matches = activeLFGPosts . filter ( ( lfg ) = > ( message . authorId === lfg . ownerId && message . channelId === lfg . channelId ) ) ;
// Found one, edit
if ( matches . length === 1 ) {
const lfgMessage = await ( await getMessage ( matches [ 0 ] . channelId , matches [ 0 ] . messageId ) ) . edit ( {
content : ` Editing new LFG post for <@ ${ matches [ 0 ] . ownerId } >. Please reply with the requested information and watch as your LFG post gets edited! ` ,
} ) ;
const question = await message . send ( {
content : 'Please select an item to edit from the buttons below:' ,
components : [ {
type : 1 ,
components : editBtns ,
} ] ,
} ) ;
activeBuilders . push ( {
userId : matches [ 0 ] . ownerId ,
channelId : matches [ 0 ] . channelId ,
step : 'edit_btn' ,
lfgMsg : lfgMessage ,
questionMsg : question ,
lastTouch : new Date ( ) ,
maxIdle : 60 ,
editing : true ,
} ) ;
message . delete ( ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
} // Found multiple, notify user
else if ( matches . length ) {
const deleteMsg = constantCmds . lfgEdit2 ;
const deepCloningFailedSoThisIsTheSolution = constantCmds . lfgEdit2 . embeds [ 0 ] . fields [ 0 ] . value ;
matches . forEach ( ( mt ) = > {
deleteMsg . embeds [ 0 ] . fields [ 0 ] . value += ` [ ${ mt . lfgUid } ](https://discord.com/channels/ ${ message . guildId } / ${ mt . channelId } / ${ mt . messageId } ) \ n ` ;
} ) ;
deleteMsg . embeds [ 0 ] . fields [ 0 ] . value += '\nThis message will self descruct in 30 seconds.' ;
const m = await message . send ( deleteMsg ) ;
constantCmds . lfgEdit2 . embeds [ 0 ] . fields [ 0 ] . value = deepCloningFailedSoThisIsTheSolution ;
m . delete ( 'Channel Cleanup' , 30000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
message . delete ( 'Channel Cleanup' , 30000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
} // Found none, notify user you cannot edit other's lfgs
else {
const m = await message . send ( constantCmds . lfgEdit1 ) ;
m . delete ( 'Channel Cleanup' , 5000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
message . delete ( 'Channel Cleanup' , 5000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
}
}
} catch ( e ) {
log ( LT . WARN , ` LFG failed at step | edit | ${ jsonStringifyBig ( e ) } ` ) ;
}
} // Join a LFG on behalf of a user
// gu!lfg join [url] [join/leave/alternate] [member?]
else if ( subcmd === 'join' || subcmd === 'leave' || subcmd === 'alternate' ) {
try {
const action = subcmd ;
const lfgIds = urlToIds ( args [ 1 ] || '' ) ;
const memberStr = args [ 2 ] || ` <@ ${ message . authorId } > ` ;
const member = await message . guild ? . members . get ( BigInt ( memberStr . substr ( 3 , memberStr . length - 4 ) ) ) ;
const modRole = guildModRoles . get ( message . guildId ) || 0 n ;
// Join yourself (or others if you are a guild mod) to an LFG
if ( lfgIds . guildId === message . guildId && member && ( member . id === message . authorId || message . guildMember ? . roles . includes ( modRole ) ) ) {
const lfgMessage = await getMessage ( lfgIds . channelId , lfgIds . messageId ) ;
const embeds = lfgMessage . embeds [ 0 ] . fields || [ ] ;
let results : JoinLeaveType = {
embed : [ ] ,
success : false ,
full : true ,
justFilled : false ,
} ;
let actionResp : string ;
switch ( action ) {
case 'join' :
results = handleMemberJoin ( embeds , member , false ) ;
actionResp = 'joined' ;
break ;
case 'leave' :
results = handleMemberLeave ( embeds , member ) ;
actionResp = 'left' ;
break ;
case 'alternate' :
results = handleMemberJoin ( embeds , member , true ) ;
actionResp = 'joined as alternate' ;
break ;
}
let resp : string ;
if ( results . success && lfgMessage . components ) {
const buttonRow : ActionRow = lfgMessage . components [ 0 ] as ActionRow ;
await lfgMessage . edit ( {
embeds : [ {
fields : results.embed ,
footer : lfgMessage.embeds [ 0 ] . footer ,
timestamp : lfgMessage.embeds [ 0 ] . timestamp ,
} ] ,
components : [ buttonRow ] ,
} ) ;
if ( results . justFilled ) {
const thisLFGPost = activeLFGPosts . filter ( ( lfg ) = > ( lfgMessage . id === lfg . messageId && lfgMessage . channelId === lfg . channelId ) ) [ 0 ] ;
const thisLFG = ( await getMessage ( thisLFGPost . channelId , thisLFGPost . messageId ) ) . embeds [ 0 ] . fields || [ ] ;
sendDirectMessage ( thisLFGPost . ownerId , {
embeds : [ {
title : ` Hello ${ ( await getUser ( thisLFGPost . ownerId ) ) . username } ! Your event in ${
lfgMessage . guild ? . name || ( await getGuild ( message . guildId , { counts : false , addToCache : false } ) ) . name
} has filled up ! ` ,
fields : [
thisLFG [ 0 ] ,
{
name : 'Your members are:' ,
value : thisLFG [ 4 ] . value ,
} ,
] ,
} ] ,
} ) ;
}
resp = ` Successfully ${ actionResp } LFG. ` ;
} else {
resp = ` Failed to ${ action } LFG. ` ;
}
const m = await message . send ( {
embeds : [ {
title : resp ,
} ] ,
} ) ;
m . delete ( 'Channel Cleanup' , 5000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
message . delete ( 'Channel Cleanup' , 5000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
}
} catch ( e ) {
log ( LT . WARN , ` Member Join/Leave/Alt command failed: ${ jsonStringifyBig ( message ) } | ${ jsonStringifyBig ( e ) } ` ) ;
const m = await message . send ( {
embeds : [ {
title : 'Failed to find LFG.' ,
} ] ,
} ) ;
m . delete ( 'Channel Cleanup' ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to clean up joiner | joining on behalf | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
message . delete ( 'Channel Cleanup' , 5000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to clean up joiner | joining on behalf | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
}
} // Sets the mod role
else if ( subcmd === 'set_mod_role' && ( await hasGuildPermissions ( message . guildId , message . authorId , [ 'ADMINISTRATOR' ] ) ) ) {
const mentionedRole = args [ 1 ] || '' ;
const roleId = BigInt ( mentionedRole . substr ( 3 , mentionedRole . length - 4 ) ) ;
if ( message . guild ? . roles . has ( roleId ) ) {
let success = true ;
if ( guildModRoles . has ( message . guildId ) ) {
// Execute the DB update
await dbClient . execute ( 'UPDATE guild_mod_role SET roleId = ? WHERE guildId = ?' , [ roleId , message . guildId ] ) . catch ( ( e ) = > {
log ( LT . ERROR , ` Failed to insert into database: ${ jsonStringifyBig ( e ) } ` ) ;
success = false ;
} ) ;
} else {
// Execute the DB insertion
await dbClient . execute ( 'INSERT INTO guild_mod_role(guildId,roleId) values(?,?)' , [ message . guildId , roleId ] ) . catch ( ( e ) = > {
log ( LT . ERROR , ` Failed to insert into database: ${ jsonStringifyBig ( e ) } ` ) ;
success = false ;
} ) ;
}
if ( success ) {
guildModRoles . set ( message . guildId , roleId ) ;
message . send ( {
embeds : [ {
fields : [
{
name : 'LFG Mod Role set successfully' ,
value : ` LFG Mod Role set to ${ args [ 1 ] } . ` ,
} ,
] ,
} ] ,
} ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to send message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
} else {
message . send ( {
embeds : [ {
fields : [
{
name : 'Something went wrong!' ,
value : 'LFG Mod Role has been left unchanged.' ,
} ,
] ,
} ] ,
} ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to send message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
}
} else {
if ( guildModRoles . has ( message . guildId ) ) {
message . send ( {
embeds : [ {
fields : [
{
name : 'LFG Mod Role is currently set to:' ,
value : ` <@& ${ guildModRoles . get ( message . guildId ) } > ` ,
} ,
] ,
} ] ,
} ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to send message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
} else {
message . send ( {
embeds : [ {
fields : [
{
name : 'There is no LFG Mod Role set for this guild.' ,
value : ` To set one, run this command again with the role mentioned. \ n \ nExample: \` ${ prefix } lfg set_mod_role @newModRole \` ` ,
} ,
] ,
} ] ,
} ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to send message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
}
}
} // Sets the channel cleaning up for LFG channels to keep LFG events visible and prevent conversations
else if ( subcmd === 'set_clean_channel' && ( await hasGuildPermissions ( message . guildId , message . authorId , [ 'ADMINISTRATOR' ] ) ) ) {
const cleanSetting = ( args [ 1 ] || 'list' ) . toLowerCase ( ) ;
let success = true ;
if ( cleanSetting === 'on' ) {
// Execute the DB insertion
await dbClient . execute ( 'INSERT INTO guild_clean_channel(guildId,channelId) values(?,?)' , [ message . guildId , message . channelId ] ) . catch ( ( e ) = > {
log ( LT . ERROR , ` Failed to insert into database: ${ jsonStringifyBig ( e ) } ` ) ;
success = false ;
} ) ;
if ( success ) {
const tempArr = cleanChannels . get ( message . guildId ) || [ ] ;
tempArr . push ( message . channelId ) ;
cleanChannels . set ( message . guildId , tempArr ) ;
const m = await message . send ( {
embeds : [ {
fields : [
{
name : 'Channel Cleaning turned ON.' ,
value : 'This message will self destruct in 5 seconds.' ,
} ,
] ,
} ] ,
} ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to send message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
m && m . delete ( 'Channel Cleanup' , 5000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to clean up | set_clean_channel | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
message . delete ( 'Channel Cleanup' , 5000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to clean up | set_clean_channel | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
} else {
message . send ( {
embeds : [ {
fields : [
{
name : 'Something went wrong!' ,
value : 'Channel Clean status left off.' ,
} ,
] ,
} ] ,
} ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to send message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
}
} else if ( cleanSetting === 'off' ) {
// turns clean off for channel
// Execute the DB insertion
await dbClient . execute ( 'DELETE FROM guild_clean_channel WHERE guildId = ? AND channelId = ?' , [ message . guildId , message . channelId ] ) . catch ( ( e ) = > {
log ( LT . ERROR , ` Failed to delete from database: ${ jsonStringifyBig ( e ) } ` ) ;
success = false ;
} ) ;
if ( success ) {
let tempArr = cleanChannels . get ( message . guildId ) || [ ] ;
tempArr = tempArr . filter ( ( channelId ) = > channelId !== message . channelId ) ;
cleanChannels . set ( message . guildId , tempArr ) ;
const m = await message . send ( {
embeds : [ {
fields : [
{
name : 'Channel Cleaning turned OFF.' ,
value : 'This message will self destruct in 5 seconds.' ,
} ,
] ,
} ] ,
} ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to send message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
m && m . delete ( 'Channel Cleanup' , 5000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to clean up | set_clean_channel | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
message . delete ( 'Channel Cleanup' , 5000 ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to clean up | set_clean_channel | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
} else {
message . send ( {
embeds : [ {
fields : [
{
name : 'Something went wrong!' ,
value : 'Channel Clean status left on.' ,
} ,
] ,
} ] ,
} ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to send message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
}
} else if ( cleanSetting === 'list' ) {
// send list of channels with clean on
let cleanChannelStr = '' ;
for ( const channelId of cleanChannels . get ( message . guildId ) || [ ] ) {
cleanChannelStr += ` <# ${ channelId } > \ n ` ;
}
cleanChannelStr = cleanChannelStr . substr ( 0 , cleanChannelStr . length - 1 ) ;
const tmpEmbed : Embed = { } ;
if ( cleanChannelStr ) {
tmpEmbed . fields = [
{
name : 'Clean Channels enabled for this guild:' ,
value : cleanChannelStr ,
} ,
] ;
} else {
tmpEmbed . title = 'No Clean Channels are enabled for this guild.' ;
}
await message . send ( {
embeds : [ tmpEmbed ] ,
} ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to send message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
}
}
}
} ,
interactionCreate : async ( interact , member ) = > {
try {
if ( interact . type === DiscordInteractionTypes . MessageComponent ) {
if ( interact . message && interact . data && ( interact . data as ButtonData ) . customId && member ) {
log ( LT . INFO , ` Handling Button ${ ( interact . data as ButtonData ) . customId } ` ) ;
log ( LT . LOG , ` Button Data | ${ jsonStringifyBig ( interact ) } ` ) ;
sendInteractionResponse ( BigInt ( interact . id ) , interact . token , {
type : DiscordInteractionResponseTypes . DeferredUpdateMessage ,
} ) ;
const [ handler , stepInfo ] = ( interact . data as ButtonData ) . customId . split ( '@' ) ;
const [ action , value ] = stepInfo . split ( '#' ) ;
switch ( handler ) {
case 'building' : {
await activeBuilders . some ( async ( x , i ) = > {
if ( x . channelId === BigInt ( interact . channelId || '0' ) && member && x . userId === BigInt ( member . id ) ) {
x . lastTouch = new Date ( ) ;
x = await handleLFGStep ( x , value ) ;
if ( x . step === 'done' && x . lfgMsg . components ) {
const currentLFG = ( x . lfgMsg . embeds [ 0 ] . fields || [ ] ) ;
const newTimestamp = new Date ( parseInt ( currentLFG [ 1 ] . value . split ( '#' ) [ 1 ] ) ) ;
const newLfgUid = ALPHABET [ Math . floor ( Math . random ( ) * 26 ) ] + ALPHABET [ Math . floor ( Math . random ( ) * 26 ) ] ;
const tempMembers = currentLFG [ 4 ] . name . split ( ':' ) [ 1 ] . split ( '/' ) ;
const currentMembers = parseInt ( tempMembers [ 0 ] ) ;
const maxMembers = parseInt ( tempMembers [ 1 ] ) ;
const buttonRow : ActionRow = x . lfgMsg . components [ 0 ] as ActionRow ;
if ( currentMembers > maxMembers ) {
const currentPeople = currentLFG [ 4 ] . value . split ( '\n' ) ;
const newAlts = currentPeople . splice ( maxMembers - 1 ) ;
currentLFG [ 4 ] . value = currentPeople . join ( '\n' ) ;
currentLFG [ 5 ] . value = ` ${ newAlts . join ( '\n' ) } \ n ${ currentLFG [ 5 ] . value } ` ;
currentLFG [ 4 ] . name = ` Members Joined: ${ maxMembers } / ${ maxMembers } ` ;
}
await x . lfgMsg . edit ( {
content : '' ,
embeds : [ {
fields : currentLFG ,
footer : {
text : ` Created by: ${ member . username } | ${ newLfgUid } ` ,
} ,
timestamp : newTimestamp.toISOString ( ) ,
} ] ,
components : [ buttonRow ] ,
} ) ;
const activeIdx = activeLFGPosts . findIndex ( ( lfg ) = > ( lfg . channelId === x . channelId && lfg . messageId === x . lfgMsg . id && lfg . ownerId === x . userId ) ) ;
activeLFGPosts [ activeIdx ] . lfgTime = newTimestamp . getTime ( ) ;
activeLFGPosts [ activeIdx ] . lfgUid = newLfgUid ;
localStorage . setItem ( 'activeLFGPosts' , jsonStringifyBig ( activeLFGPosts ) ) ;
await activeBuilders [ i ] . questionMsg . delete ( ) . catch ( ( e ) = > {
log ( LT . WARN , ` Failed to delete message | ${ jsonStringifyBig ( e ) } ` ) ;
} ) ;
activeBuilders . splice ( i , 1 ) ;
} else {
activeBuilders [ i ] = x ;
}
return true ;
}
} ) ;
break ;
}
case 'active' : {
const message = await getMessage ( BigInt ( interact . channelId || '0' ) , BigInt ( interact . message . id ) ) ;
const embeds = message . embeds [ 0 ] . fields || [ ] ;
let results : JoinLeaveType = {
embed : [ ] ,
success : false ,
full : true ,
justFilled : false ,
} ;
switch ( action ) {
case 'join_group' :
results = handleMemberJoin ( embeds , member , false ) ;
break ;
case 'leave_group' :
results = handleMemberLeave ( embeds , member ) ;
break ;
case 'alternate_group' :
results = handleMemberJoin ( embeds , member , true ) ;
break ;
}
if ( results . success && message . components ) {
await message . edit ( {
embeds : [ {
fields : results.embed ,
footer : message.embeds [ 0 ] . footer ,
timestamp : message.embeds [ 0 ] . timestamp ,
} ] ,
} ) ;
if ( results . justFilled ) {
const thisLFGPost = activeLFGPosts . filter ( ( lfg ) = > ( message . id === lfg . messageId && message . channelId === lfg . channelId ) ) [ 0 ] ;
const thisLFG = ( await getMessage ( thisLFGPost . channelId , thisLFGPost . messageId ) ) . embeds [ 0 ] . fields || [ ] ;
sendDirectMessage ( thisLFGPost . ownerId , {
embeds : [ {
title : ` Hello ${ ( await getUser ( thisLFGPost . ownerId ) ) . username } ! Your event in ${
message . guild ? . name || ( await getGuild ( message . guildId , { counts : false , addToCache : false } ) ) . name
} has filled up ! ` ,
fields : [
thisLFG [ 0 ] ,
{
name : 'Your members are:' ,
value : thisLFG [ 4 ] . value ,
} ,
] ,
} ] ,
} ) ;
}
}
break ;
}
case 'editing' : {
await activeBuilders . some ( async ( x , i ) = > {
if ( x . editing && x . channelId === BigInt ( interact . channelId || '0' ) && member && x . userId === BigInt ( member . id ) ) {
x . step = action ;
x . lastTouch = new Date ( ) ;
let nextQuestion = '' ;
const nextComponents : Array < ActionRow > = [ ] ;
switch ( action ) {
case 'set_game' : {
nextQuestion = lfgStepQuestions . set_game ;
const gameButtons : Array < ButtonComponent > = Object . keys ( LFGActivities ) . map ( ( game ) = > {
return {
type : 2 ,
label : game ,
customId : ` building@set_game# ${ game } ` ,
style : DiscordButtonStyles.Primary ,
} ;
} ) ;
const temp : Array < ActionRow [ ' components ' ] > = [ ] ;
gameButtons . forEach ( ( btn , idx ) = > {
if ( ! temp [ Math . floor ( idx / 5 ) ] ) {
temp [ Math . floor ( idx / 5 ) ] = [ btn ] ;
} else {
temp [ Math . floor ( idx / 5 ) ] . push ( btn ) ;
}
} ) ;
temp . forEach ( ( btns ) = > {
if ( btns . length && btns . length <= 5 ) {
nextComponents . push ( {
type : 1 ,
components : btns ,
} ) ;
}
} ) ;
break ;
}
case 'set_time' : {
nextQuestion = 'Please enter the time of the activity:' ;
break ;
}
case 'set_desc' : {
nextQuestion = 'Please enter a description for the activity. Enter `none` to skip:' ;
break ;
}
default :
break ;
}
x . questionMsg = await x . questionMsg . edit ( {
content : nextQuestion ,
components : nextComponents ,
} ) ;
activeBuilders [ i ] = x ;
return true ;
}
} ) ;
break ;
}
default :
break ;
}
}
}
} catch ( e ) {
log ( LT . ERROR , ` Interaction failed: ${ jsonStringifyBig ( interact ) } | ${ jsonStringifyBig ( member ) } | ${ jsonStringifyBig ( e ) } ` ) ;
}
} ,
} ,
} ) ;