2018-02-11 14:54:30 -05:00
const threads = require ( '../data/threads' ) ;
const snippets = require ( '../data/snippets' ) ;
const config = require ( '../config' ) ;
const utils = require ( '../utils' ) ;
const threadUtils = require ( '../threadUtils' ) ;
2019-06-09 12:17:32 -04:00
const whitespaceRegex = /\s/ ;
const quoteChars = [ "'" , '"' ] ;
2018-02-11 14:54:30 -05:00
module . exports = bot => {
const addInboxServerCommand = ( ... args ) => threadUtils . addInboxServerCommand ( bot , ... args ) ;
2019-06-09 12:17:32 -04:00
/ * *
* Parse a string of arguments , e . g .
* arg "quoted arg" with \ some \ escapes
* ... to an array of said arguments
* @ param { String } str
* @ returns { String [ ] }
* /
function parseArgs ( str ) {
const args = [ ] ;
let current = '' ;
let inQuote = false ;
let escapeNext = false ;
for ( const char of [ ... str ] ) {
if ( escapeNext ) {
current += char ;
escapeNext = false ;
} else if ( char === '\\' ) {
escapeNext = true ;
} else if ( ! inQuote && whitespaceRegex . test ( char ) ) {
args . push ( current ) ;
current = '' ;
} else if ( ! inQuote && quoteChars . includes ( char ) ) {
inQuote = char ;
} else if ( inQuote && inQuote === char ) {
inQuote = false ;
} else {
current += char ;
}
}
if ( current !== '' ) args . push ( current ) ;
return args ;
}
/ * *
* "Renders" a snippet by replacing all argument placeholders e . g . { 1 } { 2 } with their corresponding arguments .
* The number in the placeholder is the argument ' s order in the argument list , i . e . { 1 } is the first argument ( = index 0 )
* @ param { String } body
* @ param { String [ ] } args
* @ returns { String }
* /
function renderSnippet ( body , args ) {
return body
. replace ( /(?<!\\){\d+}/g , match => {
const index = parseInt ( match . slice ( 1 , - 1 ) , 10 ) - 1 ;
return ( args [ index ] != null ? args [ index ] : match ) ;
} )
. replace ( /\\{/g , '{' ) ;
}
2018-02-11 14:54:30 -05:00
/ * *
* When a staff member uses a snippet ( snippet prefix + trigger word ) , find the snippet and post it as a reply in the thread
* /
bot . on ( 'messageCreate' , async msg => {
if ( ! utils . messageIsOnInboxServer ( msg ) ) return ;
if ( ! utils . isStaff ( msg . member ) ) return ;
if ( msg . author . bot ) return ;
if ( ! msg . content ) return ;
2018-09-20 15:54:47 -04:00
if ( ! msg . content . startsWith ( config . snippetPrefix ) && ! msg . content . startsWith ( config . snippetPrefixAnon ) ) return ;
let snippetPrefix , isAnonymous ;
if ( config . snippetPrefixAnon . length > config . snippetPrefix . length ) {
// Anonymous prefix is longer -> check it first
if ( msg . content . startsWith ( config . snippetPrefixAnon ) ) {
snippetPrefix = config . snippetPrefixAnon ;
isAnonymous = true ;
} else {
snippetPrefix = config . snippetPrefix ;
isAnonymous = false ;
}
} else {
// Regular prefix is longer -> check it first
if ( msg . content . startsWith ( config . snippetPrefix ) ) {
snippetPrefix = config . snippetPrefix ;
isAnonymous = false ;
} else {
snippetPrefix = config . snippetPrefixAnon ;
isAnonymous = true ;
}
}
2018-02-11 14:54:30 -05:00
const thread = await threads . findByChannelId ( msg . channel . id ) ;
if ( ! thread ) return ;
2019-06-09 12:17:32 -04:00
let [ , trigger , rawArgs ] = msg . content . slice ( snippetPrefix . length ) . match ( / ( \ S + ) ( ? : \ s + ( . * ) ) ? / s ) ;
trigger = trigger . toLowerCase ( ) ;
2018-02-11 14:54:30 -05:00
const snippet = await snippets . get ( trigger ) ;
if ( ! snippet ) return ;
2019-06-09 12:17:32 -04:00
const args = rawArgs ? parseArgs ( rawArgs ) : [ ] ;
const rendered = renderSnippet ( snippet . body , args ) ;
const replied = await thread . replyToUser ( msg . member , rendered , [ ] , isAnonymous ) ;
2019-02-23 15:55:26 -05:00
if ( replied ) msg . delete ( ) ;
2018-02-11 14:54:30 -05:00
} ) ;
// Show or add a snippet
2018-03-11 17:17:14 -04:00
addInboxServerCommand ( 'snippet' , async ( msg , args , thread ) => {
2018-02-11 14:54:30 -05:00
const trigger = args [ 0 ] ;
if ( ! trigger ) return
const text = args . slice ( 1 ) . join ( ' ' ) . trim ( ) ;
const snippet = await snippets . get ( trigger ) ;
if ( snippet ) {
if ( text ) {
// If the snippet exists and we're trying to create a new one, inform the user the snippet already exists
2018-03-11 17:17:14 -04:00
utils . postSystemMessageWithFallback ( msg . channel , thread , ` Snippet " ${ trigger } " already exists! You can edit or delete it with ${ config . prefix } edit_snippet and ${ config . prefix } delete_snippet respectively. ` ) ;
2018-02-11 14:54:30 -05:00
} else {
// If the snippet exists and we're NOT trying to create a new one, show info about the existing snippet
2018-09-20 15:54:47 -04:00
utils . postSystemMessageWithFallback ( msg . channel , thread , ` \` ${ config . snippetPrefix } ${ trigger } \` replies with: \n ${ snippet . body } ` ) ;
2018-02-11 14:54:30 -05:00
}
} else {
if ( text ) {
// If the snippet doesn't exist and the user wants to create it, create it
2018-09-20 15:54:47 -04:00
await snippets . add ( trigger , text , msg . author . id ) ;
2018-03-11 17:17:14 -04:00
utils . postSystemMessageWithFallback ( msg . channel , thread , ` Snippet " ${ trigger } " created! ` ) ;
2018-02-11 14:54:30 -05:00
} else {
// If the snippet doesn't exist and the user isn't trying to create it, inform them how to create it
2018-03-11 17:17:14 -04:00
utils . postSystemMessageWithFallback ( msg . channel , thread , ` Snippet " ${ trigger } " doesn't exist! You can create it with \` ${ config . prefix } snippet ${ trigger } text \` ` ) ;
2018-02-11 14:54:30 -05:00
}
}
} ) ;
bot . registerCommandAlias ( 's' , 'snippet' ) ;
2018-03-11 17:17:14 -04:00
addInboxServerCommand ( 'delete_snippet' , async ( msg , args , thread ) => {
2018-02-11 14:54:30 -05:00
const trigger = args [ 0 ] ;
if ( ! trigger ) return ;
const snippet = await snippets . get ( trigger ) ;
if ( ! snippet ) {
2018-03-11 17:17:14 -04:00
utils . postSystemMessageWithFallback ( msg . channel , thread , ` Snippet " ${ trigger } " doesn't exist! ` ) ;
2018-02-11 14:54:30 -05:00
return ;
}
await snippets . del ( trigger ) ;
2018-03-11 17:17:14 -04:00
utils . postSystemMessageWithFallback ( msg . channel , thread , ` Snippet " ${ trigger } " deleted! ` ) ;
2018-02-11 14:54:30 -05:00
} ) ;
bot . registerCommandAlias ( 'ds' , 'delete_snippet' ) ;
2018-03-11 17:17:14 -04:00
addInboxServerCommand ( 'edit_snippet' , async ( msg , args , thread ) => {
2018-02-11 14:54:30 -05:00
const trigger = args [ 0 ] ;
if ( ! trigger ) return ;
const text = args . slice ( 1 ) . join ( ' ' ) . trim ( ) ;
if ( ! text ) return ;
const snippet = await snippets . get ( trigger ) ;
if ( ! snippet ) {
2018-03-11 17:17:14 -04:00
utils . postSystemMessageWithFallback ( msg . channel , thread , ` Snippet " ${ trigger } " doesn't exist! ` ) ;
2018-02-11 14:54:30 -05:00
return ;
}
await snippets . del ( trigger ) ;
2018-09-20 15:54:47 -04:00
await snippets . add ( trigger , text , msg . author . id ) ;
2018-02-11 14:54:30 -05:00
2018-03-11 17:17:14 -04:00
utils . postSystemMessageWithFallback ( msg . channel , thread , ` Snippet " ${ trigger } " edited! ` ) ;
2018-02-11 14:54:30 -05:00
} ) ;
bot . registerCommandAlias ( 'es' , 'edit_snippet' ) ;
2018-03-11 17:17:14 -04:00
addInboxServerCommand ( 'snippets' , async ( msg , args , thread ) => {
2018-02-11 14:54:30 -05:00
const allSnippets = await snippets . all ( ) ;
const triggers = allSnippets . map ( s => s . trigger ) ;
triggers . sort ( ) ;
2018-03-11 17:17:14 -04:00
utils . postSystemMessageWithFallback ( msg . channel , thread , ` Available snippets (prefix ${ config . snippetPrefix } ): \n ${ triggers . join ( ', ' ) } ` ) ;
2018-02-11 14:54:30 -05:00
} ) ;
} ;