file description module import type { HibikiClient } from "../classes/Client" ; import type { Emoji , Member , Message , TextChannel } from "eris" ; import type { ResponseData } from "../typings/utils" ; import type { LocaleString } from "../typings/locales" ; import { defaultEmojiRegex , emojiIDRegex , fullInviteRegex } from "./constants" ; import { localizeSetupItems } from "./format" ; import { timeoutHandler , waitFor } from "./waitFor" ; import dayjs from "dayjs" ; import utc from "dayjs/plugin/utc" ; import timezone from "dayjs/plugin/timezone" ; dayjs . extend ( utc ) ; dayjs . extend ( timezone ) ; const localeEmojis = { } ; const localeNames = { } ; const cmdCategories = [ ] ; const blacklistedCategories = [ "general" , "owner" ] ; export async function askYesNo ( bot , string , member , channel ) { let response = { msg : null , response : null } ; const no = string ( "global.NO" ) . toLowerCase ( ) ; const yes = string ( "global.YES" ) . toLowerCase ( ) ; const sameStartingChar = no [ 0 ] === yes [ 0 ] ; await waitFor ( "messageCreate" , 15000 , ( m ) => { if ( ! m . content ) return false ; if ( m . author . id !== member ) return false ; if ( m . channel ?. id !== channel ) return false ; if ( sameStartingChar ) { if ( m . content . toLowerCase ( ) === no ) { response = { msg : m , response : false } ; return true ; } else if ( m . content . toLowerCase ( ) === yes ) { response = { msg : m , response : true } ; return true ; } } else if ( m . content . toLowerCase ( ) . startsWith ( no [ 0 ] ) || m . content . toLowerCase ( ) === "no" ) { response = { msg : m , response : false } ; return true ; } else if ( m . content . toLowerCase ( ) . startsWith ( yes [ 0 ] ) || m . content . toLowerCase ( ) === "yes" ) { response = { msg : m , response : true } ; return true ; } } , bot ) ; return response ; } export function askFor ( bot , msg , type , arg ) { if ( ! type ) return "No type" ; if ( ! arg ) return "No arg" ; if ( ! msg . channel . guild ) return "No guild" ; const clear = arg . toLowerCase ( ) === "clear" || arg . toLowerCase ( ) === "off" || arg . toLowerCase ( ) === "null" ; if ( clear ) return "clear" ; switch ( type ) { case "role" : { const role = bot . args . argtypes . role ( arg , msg , undefined ) ; if ( ! role || role ?. managed ) return "No role" ; return role . id ; } case "channel" : { const channel = bot . args . argtypes . channel ( arg , msg , undefined ) ; if ( ! channel ) return ; return channel . id ; } case "voiceChannel" : { const channel = bot . args . argtypes . voiceChannel ( arg , msg , undefined ) ; if ( channel . type !== 2 ) return "Invalid channel type" ; if ( ! channel ) return ; return channel . id ; } case "number" : { const number = bot . args . argtypes . number ( arg , msg ) ; if ( ! number ) return "No number" ; return number ; } case "string" : { let string = bot . args . argtypes . string ( arg ) ; if ( ! string ) return "No string" ; string = string . replace ( emojiIDRegex , "" ) ; return string ; } case "boolean" : { const boolean = bot . args . argtypes . boolean ( arg , undefined , arg ) ; if ( ! boolean ) return "No boolean" ; return boolean ; } case "roleArray" : { const roles = bot . args . argtypes . roleArray ( arg . split ( /(?:\s{0,},\s{0,})|\s/ ) , msg ) ; if ( ! roles ?. length ) return "No rolearray" ; return roles ; } case "channelArray" : { const channels = bot . args . argtypes . channelArray ( arg . split ( /(?:\s{0,},\s{0,})|\s/ ) , msg ) ; if ( ! channels ?. length ) return "No channelArray" ; return channels ; } case "emoji" : { const emoji = defaultEmojiRegex . exec ( arg ) ; if ( ! emoji ) return "No emoji" ; return emoji [ 0 ] ; } case "timezone" : { let invalidTimezone = false ; try { dayjs ( new Date ( ) ) . tz ( arg ) ; } catch ( err ) { invalidTimezone = true ; } if ( invalidTimezone ) return "No valid timezone" ; return arg ; } case "disabledCmds" : { const cmds = arg . split ( /(?:\s{0,},\s{0,})|\s/ ) . map ( ( cmd ) => bot . commands . find ( ( c ) => { return c . allowdisable && ( c . name === cmd || c . aliases . includes ( cmd ) ) ; } ) ?. name ) . filter ( ( c ) => c !== undefined ) ; return cmds . length ? cmds : "No cmds" ; } case "disabledCategories" : { if ( ! cmdCategories . length ) bot . commands . forEach ( ( cmd ) => { if ( ! cmdCategories . includes ( cmd . category ) && ! blacklistedCategories . includes ( cmd . category ) ) cmdCategories . push ( cmd . category ) ; } ) ; const cats = arg . split ( /(?:\s{0,},\s{0,})|\s/ ) . filter ( ( cat ) => cmdCategories . includes ( cat ) ) ; return cats . length ? cats : "No cats" ; } } } export async function askForValue ( msg , omsg , bot , category , config , editFunction , setting ) { let cooldown = 0 ; await waitFor ( "messageCreate" , 60000 , async ( m ) => { if ( m . author . id !== msg . author . id || m . channel . id !== msg . channel . id || ! msg . content ) return ; let result = askFor ( bot , m , setting . id === "disabledCmds" || setting . id === "disabledCategories" ? setting . id : setting . type , m . content ) ; const invalidChecks = { notBoolean : { check : setting . type !== "boolean" && ! result , errorMsg : msg . string ( "general.CONFIG_ISINVALID" ) , } , isInvalid : { check : typeof result === "string" && result . startsWith ( "No" ) , errorMsg : msg . string ( "general.CONFIG_ISINVALID" ) , } , containsInvite : { check : setting . inviteFilter === true && fullInviteRegex . test ( result ) , errorMsg : msg . string ( "general.CONFIG_CONTAINSINVITE" ) , } , roleArrayTooLong : { check : setting . type === "roleArray" && setting . maximum && result . length > setting . maximum , errorMsg : msg . string ( "general.CONFIG_ROLEARRAYTOOLONG" , { maximum : setting . maximum } ) , } , channelArrayTooLong : { check : setting . type === "channelArray" && setting . maximum && result . length > setting . maximum , errorMsg : msg . string ( "general.CONFIG_CHANNELARRAYTOOLONG" , { maximum : setting . maximum } ) , } , invalidNumberSize : { check : setting . type === "number" && setting . maximum && ( setting . minimum > result || setting . maximum < result ) , errorMsg : msg . string ( "general.CONFIG_INVALIDNUMBERSIZE" ) , } , invalidStringSize : { check : setting . type === "string" && setting . maximum && setting . maximum < result . length , errorMsg : msg . string ( "general.CONFIG_STRINGTOOLONG" , { maximum : setting . maximum } ) , } , } ; let error = "" ; Object . keys ( invalidChecks ) . forEach ( ( checkKey ) => { if ( error ) return ; const check = invalidChecks [ checkKey ] ; if ( check . check ) { error = check . errorMsg ; } } ) ; if ( error ) { const errormsg = await msg . createEmbed ( msg . string ( "global.ERROR" ) , `${ error } ${ msg . string ( "general.CONFIG_ATTEMPTS_LEFT" , { attempts : Math . abs ( cooldown - 2 ) } ) }` , "error" ) ; cooldown ++ ; setTimeout ( ( ) => { errormsg . delete ( ) ; } , 2000 ) ; if ( cooldown > 2 ) { omsg . edit ( editFunction ( category , bot ) ) ; return true ; } return ; } let resultName ; if ( result === "clear" ) result = null ; config [ setting . id ] = result ; if ( category === "profile" ) await bot . db . updateUserConfig ( msg . author . id , config ) ; else await bot . db . updateGuildConfig ( msg . channel . guild . id , config ) ; await m . delete ( ) . catch ( ( ) => { } ) ; switch ( setting . type ) { case "role" : { resultName = msg . channel . guild . roles . get ( result ) ?. name || result ; break ; } case "channel" : { resultName = msg . channel . guild . channels . get ( result ) ?. mention || result ; break ; } case "roleArray" : { const roleNames = [ ] ; await result . forEach ( ( r ) => { const role = msg . channel . guild . roles . get ( r ) ?. name ; if ( role ) roleNames . push ( role ) ; else roleNames . push ( r ) ; } ) ; resultName = roleNames . join ( ", " ) ; break ; } case "channelArray" : { const channelNames = [ ] ; await result . forEach ( ( c ) => { const channel = msg . channel . guild . channels . get ( c ) ?. mention ; if ( channel ) channelNames . push ( channel ) ; else channelNames . push ( c ) ; } ) ; resultName = channelNames . join ( ", " ) ; break ; } } const setmsg = await msg . createEmbed ( msg . string ( "global.SUCCESS" ) , `**${ localizeSetupItems ( msg . string , setting . id , true ) }** ${ msg . string ( "global.SET_TO" ) } **${ resultName || ( result ?? msg . string ( "global.NOTHING" ) ) }**.` , "success" ) ; setTimeout ( ( ) => { setmsg . delete ( ) ; } , 2000 ) ; omsg . edit ( editFunction ( category , bot ) ) ; return true ; } , bot ) . catch ( ( err ) => timeoutHandler ( err , omsg , msg . string ) ) ; } export async function askForLocale ( omsg , msg , bot , userconfig , editFunction , category ? , isGuildConfig ? ) { Object . keys ( bot . localeSystem . locales ) . forEach ( ( locale ) => { localeEmojis [ bot . localeSystem . getLocale ( locale , "EMOJI" ) ] = bot . localeSystem . getLocale ( locale , "NAME" ) ; localeNames [ bot . localeSystem . getLocale ( locale , "EMOJI" ) ] = locale ; } ) ; await omsg . removeReactions ( ) ; Object . keys ( localeEmojis ) . forEach ( async ( emoji ) => omsg . addReaction ( emoji ) ) ; const string = bot . localeSystem . getLocaleFunction ( ( userconfig as UserConfig ) ?. locale ? ( userconfig as UserConfig ) ?. locale : bot . config . defaultLocale ) ; omsg . editEmbed ( `🌍 ${ string ( "global.ASKFOR_LOCALE" ) }` , Object . entries ( localeEmojis ) . map ( ( locale ) => `${ locale [ 0 ] } ${ locale [ 1 ] }` ) . join ( "\n" ) ) ; return waitFor ( "messageReactionAdd" , 60000 , async ( m , emoji , user ) => { if ( m . id !== omsg . id ) return ; if ( user . id !== msg . author . id ) return ; if ( ! emoji . name ) return ; const locale = localeNames [ emoji . name ] ; if ( ! locale ) return ; ( userconfig as UserConfig ) . locale = locale ; if ( isGuildConfig ) bot . db . updateGuildConfig ( msg . channel . guild . id , userconfig ) ; else bot . db . updateUserConfig ( msg . author . id , userconfig ) ; await omsg . edit ( isGuildConfig ? editFunction ( category , bot ) : editFunction ( bot . localeSystem ) ) ; await omsg . removeReactions ( ) ; return true ; } , bot ) . catch ( ( err ) => { if ( err !== "timeout" ) throw err ; } ) ; }