2023-11-11 00:01:38 +01:00
import { Client , CommandInteraction , GuildMember , EmbedBuilder , TextChannel , AutocompleteInteraction } from 'discord.js' ;
import { getSign } from './util' ;
2023-11-13 16:10:33 +01:00
import { Counter , CounterConfiguration , CounterUserLink , db } from './db' ;
2022-07-19 21:39:34 +02:00
2023-11-13 17:29:49 +01:00
export async function getCounter ( id : number ) {
2023-11-11 00:01:38 +01:00
const counter = await db < Counter > ( 'counters' )
2023-11-13 17:29:49 +01:00
. select ( 'value' )
. where ( 'id' , id )
2023-11-11 00:01:38 +01:00
. first ( ) ;
2022-07-19 21:39:34 +02:00
2023-11-11 00:01:38 +01:00
if ( ! counter ) throw 'No such counter' ;
2023-04-19 21:12:45 +02:00
2023-11-11 00:01:38 +01:00
return counter . value ;
2022-07-19 21:39:34 +02:00
}
2023-11-13 17:29:49 +01:00
export async function changeCounter ( id : number , delta : number ) {
const value = await getCounter ( id ) ;
2023-11-11 00:01:38 +01:00
const newValue = value + delta ;
2022-07-19 21:39:34 +02:00
2023-11-11 00:01:38 +01:00
await db < Counter > ( 'counters' )
2023-11-13 17:29:49 +01:00
. where ( 'id' , id )
2023-11-11 00:01:38 +01:00
. update ( {
'value' : newValue
} ) ;
2023-04-19 21:05:15 +02:00
2023-11-11 00:01:38 +01:00
return newValue ;
2022-07-19 21:39:34 +02:00
}
2023-11-13 17:29:49 +01:00
export async function getCounterData ( id : number ) {
const counter = await db < Counter > ( 'counters' )
. select ( '*' )
. where ( 'id' , id )
. first ( ) ;
if ( ! counter ) throw 'No such counter' ;
return counter ;
}
export async function findCounter ( key : string , guild : string ) {
2023-11-11 00:01:38 +01:00
const counter = await db < Counter > ( 'counters' )
. select ( '*' )
2023-11-13 17:29:49 +01:00
. where ( 'key' , key )
. where ( 'guild' , guild )
2023-11-11 00:01:38 +01:00
. first ( ) ;
2023-04-19 21:05:15 +02:00
2023-11-11 00:01:38 +01:00
if ( ! counter ) throw 'No such counter' ;
2023-04-19 21:05:15 +02:00
2023-11-11 00:01:38 +01:00
return counter ;
2022-07-19 21:39:34 +02:00
}
2023-11-13 17:29:49 +01:00
export async function getCounterConfigRaw ( counter : Counter ) {
2023-11-13 16:10:33 +01:00
const configs = await db < CounterConfiguration > ( 'counterConfigurations' )
. select ( 'configName' , 'value' )
2023-11-13 17:29:49 +01:00
. where ( 'id' , counter . id ) ;
2023-11-13 16:10:33 +01:00
const config = new Map < string , string > ( ) ;
configs . forEach ( ( { configName , value } ) = > {
config . set ( configName , value ) ;
} ) ;
// just the ugly way of life
config . set ( 'emoji' , counter . emoji ) ;
return config ;
}
2023-11-13 17:29:49 +01:00
export async function getCounterConfig ( id : number , key : string ) {
2023-11-13 16:10:33 +01:00
const config = await db < CounterConfiguration > ( 'counterConfigurations' )
. select ( 'value' )
2023-11-13 17:29:49 +01:00
. where ( 'id' , id )
2023-11-14 16:24:22 +01:00
. where ( 'configName' , key )
2023-11-13 16:10:33 +01:00
. first ( ) ;
const valueStr = config ? . value ;
let value ;
if ( valueStr ) {
value = parseConfig ( valueStr , counterConfigs . get ( key ) ! . type ) ;
} else {
value = counterConfigs . get ( key ) ! . default ;
}
return value ;
}
2023-11-13 17:29:49 +01:00
export async function setCounterConfig ( id : number , option : string , value : string ) {
2023-11-13 16:10:33 +01:00
// just the ugly way of life
if ( option === 'emoji' ) {
await db < Counter > ( 'counters' )
2023-11-13 17:29:49 +01:00
. where ( 'id' , id )
2023-11-13 16:10:33 +01:00
. update ( {
'emoji' : value
} ) ;
return ;
}
const updated = await db < CounterConfiguration > ( 'counterConfigurations' )
. update ( {
value : value
} )
2023-11-13 17:29:49 +01:00
. where ( 'id' , id )
2023-11-13 16:10:33 +01:00
. where ( 'configName' , option ) ;
if ( updated === 0 ) {
await db < CounterConfiguration > ( 'counterConfigurations' )
. insert ( {
2023-11-13 17:29:49 +01:00
'id' : id ,
2023-11-13 16:10:33 +01:00
'configName' : option ,
'value' : value
} ) ;
}
}
export enum ConfigType {
Bool ,
String ,
Number
}
export function parseConfig ( str : string , type : ConfigType . Bool ) : boolean
export function parseConfig ( str : string , type : ConfigType . String ) : string
export function parseConfig ( str : string , type : ConfigType . Number ) : number
export function parseConfig ( str : string , type : ConfigType ) : boolean | string | number
export function parseConfig ( str : string , type : ConfigType ) {
switch ( type ) {
case ConfigType . Bool :
return str === 'true' ;
case ConfigType . String :
return str . trim ( ) ;
case ConfigType . Number : {
const n = parseInt ( str ) ;
if ( isNaN ( n ) ) throw 'Not a valid number' ;
return n ;
}
}
}
export function getOptions ( type : ConfigType ) : string [ ] {
switch ( type ) {
case ConfigType . Bool :
return [ 'true' , 'false' ] ;
case ConfigType . String :
return [ ] ;
case ConfigType . Number :
return [ ] ;
}
}
export function toStringConfig ( value : boolean | string | number , type : ConfigType ) : string {
switch ( type ) {
case ConfigType . Bool :
return value ? 'true' : 'false' ;
case ConfigType . String :
return ( value as string ) ;
case ConfigType . Number :
return ( value as number ) . toString ( ) ;
}
}
export const counterConfigs = new Map ( [
[ 'anonymous' , {
type : ConfigType . Bool ,
default : false
} ] ,
2023-11-13 18:01:19 +01:00
[ 'messageTemplate' , {
type : ConfigType . String ,
default : '**%user** has %action the counter by **%amt**.'
} ] ,
2023-11-13 18:07:13 +01:00
[ 'messageTemplateIncrease' , {
type : ConfigType . String ,
2023-11-13 18:11:11 +01:00
default : 'null'
2023-11-13 18:07:13 +01:00
} ] ,
[ 'messageTemplateDecrease' , {
type : ConfigType . String ,
2023-11-13 18:11:11 +01:00
default : 'null'
2023-11-13 18:07:13 +01:00
} ] ,
2023-11-13 16:10:33 +01:00
// these ones are fake and are just stand-ins for values defined inside the actual counters table
[ 'emoji' , {
type : ConfigType . String ,
default : ''
} ]
] ) ;
2023-11-12 14:35:04 +01:00
export async function updateCounter ( bot : Client , counter : Counter , value : number ) {
2023-11-11 00:01:38 +01:00
const channel = await bot . channels . fetch ( counter . channel ) as TextChannel ;
const messageID = counter . message ;
2022-07-19 21:39:34 +02:00
2023-11-12 14:35:04 +01:00
const content = ` [ ${ counter . emoji } ] x ${ value } ` ;
2022-07-19 21:39:34 +02:00
// bit janky
2023-11-11 00:01:38 +01:00
// yeah you don't say
2022-07-19 21:39:34 +02:00
try {
if ( messageID ) {
const message = await channel . messages . fetch ( messageID ) ;
if ( ! message ) throw new Error ( ) ;
await message . edit ( content ) ;
} else {
throw new Error ( ) ;
}
} catch ( err ) {
const message = await channel . send ( content ) ;
message . pin ( ) ;
2023-11-11 00:01:38 +01:00
await db < Counter > ( 'counters' )
2023-11-13 17:29:49 +01:00
. where ( 'id' , counter . id )
2023-11-11 00:01:38 +01:00
. update ( {
'message' : message . id
} ) ;
2022-07-19 21:39:34 +02:00
}
}
2023-11-12 14:35:04 +01:00
export async function announceCounterUpdate ( bot : Client , member : GuildMember , delta : number , counter : Counter , value : number ) {
2023-11-11 00:01:38 +01:00
const channel = await bot . channels . fetch ( counter . channel ) as TextChannel ;
2022-07-19 21:39:34 +02:00
2023-11-13 18:07:13 +01:00
let template = await getCounterConfig ( counter . id , 'messageTemplate' ) as string ;
const templateIncrease = await getCounterConfig ( counter . id , 'messageTemplateIncrease' ) as string ;
2023-11-13 18:11:11 +01:00
if ( templateIncrease !== 'null' && delta > 0 ) template = templateIncrease ;
2023-11-13 18:07:13 +01:00
const templateDecrease = await getCounterConfig ( counter . id , 'messageTemplateDecrease' ) as string ;
2023-11-13 18:11:11 +01:00
if ( templateDecrease !== 'null' && delta < 0 ) template = templateDecrease ;
2023-11-13 18:07:13 +01:00
2023-11-13 18:01:19 +01:00
const anonymous = await getCounterConfig ( counter . id , 'anonymous' ) as boolean ;
2023-11-13 16:10:33 +01:00
2023-06-11 17:23:57 +02:00
const embed = new EmbedBuilder ( )
2023-11-13 16:10:33 +01:00
//.setDescription(`**${member.toString()}** has ${delta > 0 ? 'increased' : 'decreased'} the counter by **${Math.abs(delta)}**.`)
. setDescription (
template
. replaceAll ( '%user' , anonymous ? 'someone' : member . toString ( ) )
. replaceAll ( '%action' , delta > 0 ? 'increased' : 'decreased' )
. replaceAll ( '%amt' , Math . abs ( delta ) . toString ( ) )
2023-11-13 18:07:13 +01:00
. replaceAll ( '%total' , value . toString ( ) )
2023-11-13 16:10:33 +01:00
)
2022-07-19 21:39:34 +02:00
. setTimestamp ( )
2023-06-11 17:23:57 +02:00
. setFooter ( {
2023-11-12 14:35:04 +01:00
text : ` [ ${ counter . emoji } ] x ${ value } `
2023-06-11 17:23:57 +02:00
} ) ;
2022-07-19 21:39:34 +02:00
2023-11-13 16:10:33 +01:00
if ( ! anonymous ) {
embed
. setAuthor ( {
2023-11-13 16:13:59 +01:00
name : member.displayName ,
iconURL : member.displayAvatarURL ( )
2023-11-13 16:10:33 +01:00
} )
. setColor ( member . displayColor ) ;
}
2022-07-19 21:39:34 +02:00
await channel . send ( {
embeds : [ embed ]
} ) ;
}
2023-11-11 00:01:38 +01:00
export async function changeCounterInteraction ( interaction : CommandInteraction , member : GuildMember , amount : number , type : string ) {
2023-11-12 19:31:49 +01:00
try {
2023-11-13 17:29:49 +01:00
const counter = await findCounter ( type , member . guild . id ) ;
2023-11-11 00:01:38 +01:00
2023-11-12 20:44:03 +01:00
let canUse = true ;
if ( amount > 0 && counter . allowlistProducer ) {
const userLink = await db < CounterUserLink > ( 'counterUserLink' )
2023-11-13 17:29:49 +01:00
. where ( 'id' , counter . id )
2023-11-12 20:44:03 +01:00
. where ( 'user' , member . id )
. where ( 'producer' , true )
. first ( ) ;
if ( ! userLink ) canUse = false ;
}
if ( amount < 0 && counter . allowlistConsumer ) {
const userLink = await db < CounterUserLink > ( 'counterUserLink' )
2023-11-13 17:29:49 +01:00
. where ( 'id' , counter . id )
2023-11-12 20:44:03 +01:00
. where ( 'user' , member . id )
. where ( 'producer' , false )
. first ( ) ;
if ( ! userLink ) canUse = false ;
}
if ( ! canUse ) {
await interaction . followUp ( {
content : ` You cannot ** ${ amount > 0 ? 'produce' : 'consume' } ** ${ counter . emoji } . `
} ) ;
return ;
}
2023-11-13 17:29:49 +01:00
const newCount = await changeCounter ( counter . id , amount ) ;
2023-11-12 19:31:49 +01:00
await updateCounter ( interaction . client , counter , newCount ) ;
await announceCounterUpdate ( interaction . client , member , amount , counter , newCount ) ;
2023-11-12 20:44:03 +01:00
await interaction . followUp ( {
2023-11-12 19:31:49 +01:00
content : ` ${ counter . emoji } **You have ${ amount > 0 ? 'increased' : 'decreased' } the counter.** \ n \` \` \` diff \ n ${ newCount - amount } \ n ${ getSign ( amount ) } ${ Math . abs ( amount ) } \ n ${ newCount } \` \` \` `
} ) ;
} catch ( err ) {
2023-11-12 20:44:03 +01:00
await interaction . followUp ( {
2023-11-12 19:31:49 +01:00
content : ( err as Error ) . toString ( )
} ) ;
}
2023-11-11 00:01:38 +01:00
}
export async function counterAutocomplete ( interaction : AutocompleteInteraction ) {
const focusedValue = interaction . options . getFocused ( ) ;
const guild = interaction . guildId ;
const query = db < Counter > ( 'counters' )
2023-11-12 20:44:03 +01:00
. select ( 'emoji' , 'key' )
. whereLike ( 'key' , ` % ${ focusedValue . toLowerCase ( ) } % ` )
2023-11-11 00:01:38 +01:00
. limit ( 25 ) ;
if ( guild ) {
query . where ( 'guild' , guild ) ;
}
const foundCounters = await query ;
await interaction . respond (
2023-11-12 20:44:03 +01:00
foundCounters . map ( choice = > ( { name : choice.emoji , value : choice.key } ) )
2023-11-11 00:01:38 +01:00
) ;
2022-07-19 21:39:34 +02:00
}