2021-08-19 20:31:51 +00:00
import * as collections from "../collections.js" ;
import * as logger from "../logger.js" ;
2021-07-02 04:42:12 +00:00
2021-08-19 14:19:14 +00:00
import sqlite3 from "better-sqlite3" ;
2021-07-02 04:42:12 +00:00
const connection = sqlite3 ( process . env . DB . replace ( "sqlite://" , "" ) ) ;
2022-02-19 05:05:41 +00:00
const sqliteUpdates = [
"" , // reserved
2022-02-22 00:55:25 +00:00
"ALTER TABLE guilds ADD COLUMN accessed int" ,
"ALTER TABLE guilds DROP COLUMN accessed"
2022-02-19 05:05:41 +00:00
] ;
2022-02-22 00:55:25 +00:00
export async function setup ( ) {
const counts = connection . prepare ( "SELECT * FROM counts" ) . all ( ) ;
2022-09-10 22:51:00 +00:00
const merged = new Map ( [ ... collections . commands , ... collections . messageCommands ] ) ;
2021-07-02 04:42:12 +00:00
if ( ! counts ) {
2022-09-10 22:51:00 +00:00
for ( const command of merged . keys ( ) ) {
2021-07-02 04:42:12 +00:00
connection . prepare ( "INSERT INTO counts (command, count) VALUES (?, ?)" ) . run ( command , 0 ) ;
}
} else {
const exists = [ ] ;
2022-09-10 22:51:00 +00:00
for ( const command of merged . keys ( ) ) {
2021-07-02 04:42:12 +00:00
const count = connection . prepare ( "SELECT * FROM counts WHERE command = ?" ) . get ( command ) ;
if ( ! count ) {
connection . prepare ( "INSERT INTO counts (command, count) VALUES (?, ?)" ) . run ( command , 0 ) ;
}
exists . push ( command ) ;
}
2021-08-14 21:15:21 +00:00
2021-07-02 04:42:12 +00:00
for ( const { command } of counts ) {
if ( ! exists . includes ( command ) ) {
connection . prepare ( "DELETE FROM counts WHERE command = ?" ) . run ( command ) ;
}
}
}
2022-02-22 00:55:25 +00:00
}
export async function stop ( ) {
connection . close ( ) ;
}
export async function upgrade ( logger ) {
connection . prepare ( "CREATE TABLE IF NOT EXISTS guilds ( guild_id VARCHAR(30) NOT NULL PRIMARY KEY, prefix VARCHAR(15) NOT NULL, disabled text NOT NULL, disabled_commands text NOT NULL )" ) . run ( ) ;
connection . prepare ( "CREATE TABLE IF NOT EXISTS counts ( command VARCHAR NOT NULL PRIMARY KEY, count integer NOT NULL )" ) . run ( ) ;
connection . prepare ( "CREATE TABLE IF NOT EXISTS tags ( guild_id VARCHAR(30) NOT NULL, name text NOT NULL, content text NOT NULL, author VARCHAR(30) NOT NULL, UNIQUE(guild_id, name) )" ) . run ( ) ;
2022-02-20 14:12:00 +00:00
let version = connection . pragma ( "user_version" , { simple : true } ) ;
if ( version < ( sqliteUpdates . length - 1 ) ) {
logger . warn ( ` Migrating SQLite database at ${ process . env . DB } , which is currently at version ${ version } ... ` ) ;
connection . prepare ( "BEGIN TRANSACTION" ) . run ( ) ;
try {
while ( version < ( sqliteUpdates . length - 1 ) ) {
version ++ ;
logger . warn ( ` Running version ${ version } update script ( ${ sqliteUpdates [ version ] } )... ` ) ;
connection . prepare ( sqliteUpdates [ version ] ) . run ( ) ;
}
connection . pragma ( ` user_version = ${ version } ` ) ; // insecure, but the normal templating method doesn't seem to work here
connection . prepare ( "COMMIT" ) . run ( ) ;
} catch ( e ) {
logger . error ( ` SQLite migration failed: ${ e } ` ) ;
connection . prepare ( "ROLLBACK" ) . run ( ) ;
logger . error ( "Unable to start the bot, quitting now." ) ;
2022-02-22 00:55:25 +00:00
return 1 ;
2022-02-20 14:12:00 +00:00
}
}
2021-08-19 14:19:14 +00:00
}
2021-07-02 04:42:12 +00:00
2021-08-19 14:19:14 +00:00
export async function fixGuild ( guild ) {
2021-07-02 04:42:12 +00:00
let guildDB ;
try {
guildDB = connection . prepare ( "SELECT * FROM guilds WHERE guild_id = ?" ) . get ( guild . id ) ;
} catch {
2021-08-13 03:28:09 +00:00
connection . prepare ( "CREATE TABLE guilds ( guild_id VARCHAR(30) NOT NULL PRIMARY KEY, prefix VARCHAR(15) NOT NULL, disabled text NOT NULL, disabled_commands text NOT NULL )" ) . run ( ) ;
2021-07-02 04:42:12 +00:00
}
if ( ! guildDB ) {
logger . log ( ` Registering guild database entry for guild ${ guild . id } ... ` ) ;
return await this . addGuild ( guild ) ;
}
2021-08-19 14:19:14 +00:00
}
2021-07-02 04:42:12 +00:00
2021-08-19 14:19:14 +00:00
export async function addCount ( command ) {
2021-07-02 04:42:12 +00:00
connection . prepare ( "UPDATE counts SET count = count + 1 WHERE command = ?" ) . run ( command ) ;
2021-08-19 14:19:14 +00:00
}
2021-07-02 04:42:12 +00:00
2021-08-19 14:19:14 +00:00
export async function getCounts ( ) {
2021-07-02 04:42:12 +00:00
const counts = connection . prepare ( "SELECT * FROM counts" ) . all ( ) ;
const countObject = { } ;
for ( const { command , count } of counts ) {
countObject [ command ] = count ;
}
return countObject ;
2021-08-19 14:19:14 +00:00
}
2021-07-02 04:42:12 +00:00
2021-08-19 14:19:14 +00:00
export async function disableCommand ( guild , command ) {
2021-08-13 03:28:09 +00:00
const guildDB = await this . getGuild ( guild ) ;
2022-01-07 17:44:18 +00:00
connection . prepare ( "UPDATE guilds SET disabled_commands = ? WHERE guild_id = ?" ) . run ( JSON . stringify ( ( guildDB . disabledCommands ? [ ... JSON . parse ( guildDB . disabledCommands ) , command ] : [ command ] ) . filter ( ( v ) => ! ! v ) ) , guild ) ;
collections . disabledCmdCache . set ( guild , guildDB . disabled _commands ? [ ... JSON . parse ( guildDB . disabledCommands ) , command ] : [ command ] . filter ( ( v ) => ! ! v ) ) ;
2021-08-19 14:19:14 +00:00
}
2021-08-13 03:28:09 +00:00
2021-08-19 14:19:14 +00:00
export async function enableCommand ( guild , command ) {
2021-08-13 03:28:09 +00:00
const guildDB = await this . getGuild ( guild ) ;
const newDisabled = guildDB . disabledCommands ? JSON . parse ( guildDB . disabledCommands ) . filter ( item => item !== command ) : [ ] ;
connection . prepare ( "UPDATE guilds SET disabled_commands = ? WHERE guild_id = ?" ) . run ( JSON . stringify ( newDisabled ) , guild ) ;
collections . disabledCmdCache . set ( guild , newDisabled ) ;
2021-08-19 14:19:14 +00:00
}
2021-08-13 03:28:09 +00:00
2021-08-19 14:19:14 +00:00
export async function disableChannel ( channel ) {
2021-07-02 04:42:12 +00:00
const guildDB = await this . getGuild ( channel . guild . id ) ;
connection . prepare ( "UPDATE guilds SET disabled = ? WHERE guild_id = ?" ) . run ( JSON . stringify ( [ ... JSON . parse ( guildDB . disabled ) , channel . id ] ) , channel . guild . id ) ;
collections . disabledCache . set ( channel . guild . id , [ ... JSON . parse ( guildDB . disabled ) , channel . id ] ) ;
2021-08-19 14:19:14 +00:00
}
2021-07-02 04:42:12 +00:00
2021-08-19 14:19:14 +00:00
export async function enableChannel ( channel ) {
2021-07-02 04:42:12 +00:00
const guildDB = await this . getGuild ( channel . guild . id ) ;
const newDisabled = JSON . parse ( guildDB . disabled ) . filter ( item => item !== channel . id ) ;
connection . prepare ( "UPDATE guilds SET disabled = ? WHERE guild_id = ?" ) . run ( JSON . stringify ( newDisabled ) , channel . guild . id ) ;
collections . disabledCache . set ( channel . guild . id , newDisabled ) ;
2021-08-19 14:19:14 +00:00
}
2021-07-02 04:42:12 +00:00
2021-08-19 14:19:14 +00:00
export async function getTag ( guild , tag ) {
2021-08-14 13:00:16 +00:00
const tagResult = connection . prepare ( "SELECT * FROM tags WHERE guild_id = ? AND name = ?" ) . get ( guild , tag ) ;
return tagResult ? { content : tagResult . content , author : tagResult . author } : undefined ;
2021-08-19 14:19:14 +00:00
}
2021-08-14 13:00:16 +00:00
2021-08-19 14:19:14 +00:00
export async function getTags ( guild ) {
2021-08-11 15:00:35 +00:00
const tagArray = connection . prepare ( "SELECT * FROM tags WHERE guild_id = ?" ) . all ( guild ) ;
const tags = { } ;
if ( ! tagArray ) return [ ] ;
for ( const tag of tagArray ) {
tags [ tag . name ] = { content : tag . content , author : tag . author } ;
}
return tags ;
2021-08-19 14:19:14 +00:00
}
2021-08-11 01:25:29 +00:00
2021-08-19 14:19:14 +00:00
export async function setTag ( name , content , guild ) {
2021-08-11 15:00:35 +00:00
const tag = {
id : guild . id ,
name : name ,
content : content . content ,
author : content . author
} ;
connection . prepare ( "INSERT INTO tags (guild_id, name, content, author) VALUES (@id, @name, @content, @author)" ) . run ( tag ) ;
2021-08-19 14:19:14 +00:00
}
2021-07-02 04:42:12 +00:00
2021-08-19 14:19:14 +00:00
export async function removeTag ( name , guild ) {
2021-08-11 15:00:35 +00:00
connection . prepare ( "DELETE FROM tags WHERE guild_id = ? AND name = ?" ) . run ( guild . id , name ) ;
2021-08-19 14:19:14 +00:00
}
2021-07-02 04:42:12 +00:00
2021-08-19 14:19:14 +00:00
export async function editTag ( name , content , guild ) {
2021-08-11 15:00:35 +00:00
connection . prepare ( "UPDATE tags SET content = ?, author = ? WHERE guild_id = ? AND name = ?" ) . run ( content . content , content . author , guild . id , name ) ;
2021-08-19 14:19:14 +00:00
}
2021-08-11 01:25:29 +00:00
2021-08-19 14:19:14 +00:00
export async function setPrefix ( prefix , guild ) {
2021-07-02 04:42:12 +00:00
connection . prepare ( "UPDATE guilds SET prefix = ? WHERE guild_id = ?" ) . run ( prefix , guild . id ) ;
collections . prefixCache . set ( guild . id , prefix ) ;
2021-08-19 14:19:14 +00:00
}
2021-07-02 04:42:12 +00:00
2021-08-19 14:19:14 +00:00
export async function addGuild ( guild ) {
2021-07-02 04:42:12 +00:00
const query = await this . getGuild ( guild ) ;
if ( query ) return query ;
const guildObject = {
id : guild . id ,
prefix : process . env . PREFIX ,
disabled : "[]" ,
2021-08-13 03:28:09 +00:00
disabledCommands : "[]"
2021-07-02 04:42:12 +00:00
} ;
2021-08-18 20:41:35 +00:00
connection . prepare ( "INSERT INTO guilds (guild_id, prefix, disabled, disabled_commands) VALUES (@id, @prefix, @disabled, @disabledCommands)" ) . run ( guildObject ) ;
2021-07-02 04:42:12 +00:00
return guildObject ;
2021-08-19 14:19:14 +00:00
}
2021-07-02 04:42:12 +00:00
2021-08-19 14:19:14 +00:00
export async function getGuild ( query ) {
2021-07-02 04:42:12 +00:00
try {
return connection . prepare ( "SELECT * FROM guilds WHERE guild_id = ?" ) . get ( query ) ;
} catch {
return ;
}
2021-08-19 14:19:14 +00:00
}