settings.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. const {MessageEmbed} = require('discord.js');
  2. const {defaultSettings, wikiProjects} = require('../util/default.json');
  3. const Lang = require('../util/i18n.js');
  4. const allLangs = Lang.allLangs();
  5. var db = require('../util/database.js');
  6. var allSites = [];
  7. const getAllSites = require('../util/allSites.js');
  8. getAllSites.then( sites => allSites = sites );
  9. function cmd_settings(lang, msg, args, line, wiki) {
  10. if ( !allSites.length ) getAllSites.update();
  11. if ( !msg.isAdmin() ) return msg.reactEmoji('❌');
  12. db.all( 'SELECT channel, lang, wiki, prefix, inline FROM discord WHERE guild = ? ORDER BY channel DESC', [msg.guild.id], (error, rows) => {
  13. if ( error ) {
  14. console.log( '- Error while getting the settings: ' + error );
  15. msg.reactEmoji('error', true);
  16. return error;
  17. }
  18. var guild = rows.find( row => !row.channel );
  19. if ( !guild ) guild = Object.assign({prefix: process.env.prefix}, defaultSettings);
  20. var prefix = guild.prefix;
  21. var text = lang.get('settings.missing', '`' + prefix + 'settings lang`', '`' + prefix + 'settings wiki`');
  22. if ( rows.length ) {
  23. text = lang.get('settings.current') + '\n' + lang.get('settings.currentlang') + ' `' + allLangs.names[guild.lang][1] + '` - `' + prefix + 'settings lang`';
  24. if ( msg.guild.id in patreons ) text += '\n' + lang.get('settings.currentprefix') + ' `' + prefix + '` - `' + prefix + 'settings prefix`';
  25. text += '\n' + lang.get('settings.currentinline') + ' ' + ( guild.inline ? '~~' : '' ) + '`[[' + lang.get('search.page') + ']]`' + ( guild.inline ? '~~' : '' ) + ' - `' + prefix + 'settings inline`';
  26. text += '\n' + lang.get('settings.currentwiki') + ' ' + guild.wiki + ' - `' + prefix + 'settings wiki`';
  27. text += '\n' + lang.get('settings.currentchannel') + ' `' + prefix + 'settings channel`\n';
  28. if ( rows.length === 1 ) text += lang.get('settings.nochannels');
  29. else text += rows.filter( row => row !== guild ).map( row => '<#' + row.channel + '>: ' + ( msg.guild.id in patreons ? '`' + allLangs.names[row.lang][1] + '` - ' : '' ) + '<' + row.wiki + '>' + ( msg.guild.id in patreons ? ' - ' + ( row.inline ? '~~' : '' ) + '`[[' + lang.get('search.page') + ']]`' + ( row.inline ? '~~' : '' ) : '' ) ).join('\n');
  30. }
  31. if ( !args.length ) {
  32. return msg.replyMsg( text, {split:true}, true );
  33. }
  34. var prelang = '';
  35. args[0] = args[0].toLowerCase();
  36. if ( args[0] === 'channel' ) {
  37. prelang = 'channel ';
  38. if ( !rows.length ) return msg.replyMsg( text, {split:true}, true );
  39. var channel = rows.find( row => row.channel === msg.channel.id );
  40. if ( !channel ) channel = Object.assign({channel:msg.channel.id}, guild);
  41. text = lang.get('settings.' + prelang + 'current');
  42. if ( msg.guild.id in patreons ) {
  43. text += '\n' + lang.get('settings.currentlang') + ' `' + allLangs.names[channel.lang][1] + '` - `' + prefix + 'settings channel lang`';
  44. text += '\n' + lang.get('settings.currentinline') + ' ' + ( channel.inline ? '~~' : '' ) + '`[[' + lang.get('search.page') + ']]`' + ( channel.inline ? '~~' : '' ) + ' - `' + prefix + 'settings channel inline`';
  45. }
  46. text += '\n' + lang.get('settings.currentwiki') + ' ' + channel.wiki + ' - `' + prefix + 'settings channel wiki`';
  47. if ( !args[1] ) return msg.replyMsg( text, {}, true );
  48. args[0] = args[1].toLowerCase();
  49. args[1] = args.slice(2).join(' ').toLowerCase().trim().replace( /^<\s*(.*)>$/, '$1' );
  50. }
  51. else args[1] = args.slice(1).join(' ').toLowerCase().trim().replace( /^<\s*(.*)>$/, '$1' );
  52. if ( args[0] === 'wiki' ) {
  53. prelang += 'wiki';
  54. var wikihelp = '\n' + lang.get('settings.wikihelp', prefix + 'settings ' + prelang);
  55. if ( !args[1] ) {
  56. if ( !rows.length ) return msg.replyMsg( lang.get('settings.wikimissing') + wikihelp, {}, true );
  57. else return msg.replyMsg( lang.get('settings.' + prelang) + ' ' + ( channel || guild ).wiki + wikihelp, {}, true );
  58. }
  59. var isForced = false;
  60. if ( /^<?(?:https?:)?\/\//.test(args[1]) ) {
  61. args[1] = args[1].replace( /^<?(?:https?:)?\/\//, 'https://' );
  62. let value = [];
  63. [args[1], ...value] = args[1].split(/>? /);
  64. if ( value.join(' ') === '--force' ) isForced = true;
  65. }
  66. var wikinew = input_to_wiki(args[1]);
  67. if ( !wikinew ) {
  68. var text = lang.get('settings.wikiinvalid') + wikihelp;
  69. var sites = allSites.filter( site => site.wiki_display_name.toLowerCase().includes( args[1] ) );
  70. if ( 0 < sites.length && sites.length < 21 ) {
  71. text += '\n\n' + lang.get('settings.foundwikis') + '\n' + sites.map( site => site.wiki_display_name + ': `' + site.wiki_domain + '`' ).join('\n');
  72. }
  73. return msg.replyMsg( text, {split:true}, true );
  74. }
  75. if ( wikinew.endsWith( '.gamepedia.com/' ) && !isForced ) {
  76. let site = allSites.find( site => site.wiki_domain === wikinew.replace( /^https:\/\/([a-z\d-]{1,50}\.gamepedia\.com)\/$/, '$1' ) );
  77. if ( site ) wikinew = 'https://' + ( site.wiki_crossover || site.wiki_domain ) + '/';
  78. }
  79. return msg.reactEmoji('⏳', true).then( reaction => {
  80. got.get( wikinew + 'api.php?action=query&meta=allmessages|siteinfo&ammessages=custom-GamepediaNotice|custom-FandomMergeNotice&amenableparser=true&siprop=general|extensions&format=json', {
  81. responseType: 'json'
  82. } ).then( response => {
  83. var body = response.body;
  84. if ( response.statusCode !== 200 || !body?.query?.allmessages || !body?.query?.general || !body?.query?.extensions ) {
  85. console.log( '- ' + response.statusCode + ': Error while testing the wiki: ' + body?.error?.info );
  86. if ( reaction ) reaction.removeEmoji();
  87. msg.reactEmoji('nowiki', true);
  88. return msg.replyMsg( lang.get('settings.wikiinvalid') + wikihelp, {}, true );
  89. }
  90. if ( !isForced ) wikinew = body.query.general.server.replace( /^(?:https?:)?\/\//, 'https://' ) + body.query.general.scriptpath + '/';
  91. if ( wikinew.endsWith( '.gamepedia.com/' ) && !isForced ) {
  92. let site = allSites.find( site => site.wiki_domain === wikinew );
  93. if ( site ) wikinew = 'https://' + ( site.wiki_crossover || site.wiki_domain ) + '/';
  94. }
  95. else if ( wikinew.isFandom() && !isForced ) {
  96. let crossover = '';
  97. if ( body.query.allmessages[0]['*'] ) {
  98. crossover = 'https://' + body.query.allmessages[0]['*'] + '.gamepedia.com/';
  99. }
  100. else if ( body.query.allmessages[1]['*'] ) {
  101. let merge = body.query.allmessages[1]['*'].split('/');
  102. crossover = 'https://' + merge[0] + '.fandom.com/' + ( merge[1] ? merge[1] + '/' : '' );
  103. }
  104. if ( crossover ) wikinew = crossover;
  105. }
  106. var embed;
  107. if ( !wikinew.isFandom() && !wikinew.endsWith( '.gamepedia.com/' ) ) {
  108. var notice = [];
  109. if ( body.query.general.generator.replace( /^MediaWiki 1\.(\d\d).*$/, '$1' ) <= 30 ) {
  110. console.log( '- This wiki is using ' + body.query.general.generator + '.' );
  111. notice.push({
  112. name: 'MediaWiki',
  113. value: lang.get('test.MediaWiki', '[MediaWiki 1.30](https://www.mediawiki.org/wiki/MediaWiki_1.30)', body.query.general.generator)
  114. });
  115. }
  116. if ( !body.query.extensions.some( extension => extension.name === 'TextExtracts' ) ) {
  117. console.log( '- This wiki is missing Extension:TextExtracts.' );
  118. notice.push({
  119. name: 'TextExtracts',
  120. value: lang.get('test.TextExtracts', '[TextExtracts](https://www.mediawiki.org/wiki/Extension:TextExtracts)')
  121. });
  122. }
  123. if ( !body.query.extensions.some( extension => extension.name === 'PageImages' ) ) {
  124. console.log( '- This wiki is missing Extension:PageImages.' );
  125. notice.push({
  126. name: 'PageImages',
  127. value: lang.get('test.PageImages', '[PageImages](https://www.mediawiki.org/wiki/Extension:PageImages)')
  128. });
  129. }
  130. if ( notice.length ) {
  131. embed = new MessageEmbed().setAuthor( body.query.general.sitename ).setTitle( lang.get('test.notice') ).addFields( notice );
  132. }
  133. }
  134. var sql = 'UPDATE discord SET wiki = ? WHERE guild = ? AND wiki = ?';
  135. var sqlargs = [wikinew, msg.guild.id, guild.wiki];
  136. if ( !rows.length ) {
  137. sql = 'INSERT INTO discord(wiki, guild) VALUES(?, ?)';
  138. sqlargs.pop();
  139. }
  140. if ( channel ) {
  141. sql = 'UPDATE discord SET wiki = ? WHERE guild = ? AND channel = ?';
  142. sqlargs[2] = msg.channel.id;
  143. if ( !rows.includes( channel ) ) {
  144. if ( channel.wiki === wikinew ) {
  145. if ( reaction ) reaction.removeEmoji();
  146. return msg.replyMsg( lang.get('settings.' + prelang + 'changed') + ' ' + channel.wiki + wikihelp, {embed}, true );
  147. }
  148. sql = 'INSERT INTO discord(wiki, guild, channel, lang, prefix) VALUES(?, ?, ?, ?, ?)';
  149. sqlargs.push(guild.lang, guild.prefix);
  150. }
  151. }
  152. return db.run( sql, sqlargs, function (dberror) {
  153. if ( dberror ) {
  154. console.log( '- Error while editing the settings: ' + dberror );
  155. msg.replyMsg( lang.get('settings.save_failed'), {embed}, true );
  156. if ( reaction ) reaction.removeEmoji();
  157. return dberror;
  158. }
  159. console.log( '- Settings successfully updated.' );
  160. if ( channel ) channel.wiki = wikinew;
  161. else {
  162. rows.forEach( row => {
  163. if ( row.channel && row.wiki === guild.wiki ) row.wiki = wikinew;
  164. } );
  165. guild.wiki = wikinew;
  166. }
  167. if ( channel || !rows.some( row => row.channel === msg.channel.id ) ) wiki = wikinew;
  168. if ( reaction ) reaction.removeEmoji();
  169. msg.replyMsg( lang.get('settings.' + prelang + 'changed') + ' ' + wikinew + wikihelp, {embed}, true );
  170. var channels = rows.filter( row => row.channel && row.lang === guild.lang && row.wiki === guild.wiki && row.prefix === guild.prefix && row.inline === guild.inline ).map( row => row.channel );
  171. if ( channels.length ) db.run( 'DELETE FROM discord WHERE channel IN (' + channels.map( row => '?' ).join(', ') + ')', channels, function (delerror) {
  172. if ( delerror ) {
  173. console.log( '- Error while removing the settings: ' + delerror );
  174. return delerror;
  175. }
  176. console.log( '- Settings successfully removed.' );
  177. } );
  178. } );
  179. }, ferror => {
  180. console.log( '- Error while testing the wiki: ' + ferror );
  181. if ( reaction ) reaction.removeEmoji();
  182. msg.reactEmoji('nowiki', true);
  183. return msg.replyMsg( lang.get('settings.wikiinvalid') + wikihelp, {}, true );
  184. } );
  185. } );
  186. }
  187. if ( args[0] === 'lang' ) {
  188. if ( channel && !( msg.guild.id in patreons ) ) return msg.replyMsg( lang.get('patreon') + ' <' + process.env.patreon + '>', {}, true );
  189. prelang += 'lang';
  190. var langhelp = '\n' + lang.get('settings.langhelp', prefix + 'settings ' + prelang) + ' `' + Object.values(allLangs.names).map( val => val[0] ).join('`, `') + '`';
  191. if ( !args[1] ) {
  192. return msg.replyMsg( lang.get('settings.' + prelang) + ' `' + allLangs.names[( channel || guild ).lang][1] + '`' + langhelp, {}, true );
  193. }
  194. if ( !( args[1] in allLangs.map ) ) {
  195. return msg.replyMsg( lang.get('settings.langinvalid') + langhelp, {}, true );
  196. }
  197. var sql = 'UPDATE discord SET lang = ? WHERE guild = ? AND lang = ?';
  198. var sqlargs = [allLangs.map[args[1]], msg.guild.id, guild.lang];
  199. if ( !rows.length ) {
  200. sql = 'INSERT INTO discord(lang, guild) VALUES(?, ?)';
  201. sqlargs.pop();
  202. }
  203. if ( channel ) {
  204. sql = 'UPDATE discord SET lang = ? WHERE guild = ? AND channel = ?';
  205. sqlargs[2] = msg.channel.id;
  206. if ( !rows.includes( channel ) ) {
  207. if ( channel.lang === allLangs.map[args[1]] ) {
  208. return msg.replyMsg( lang.get('settings.' + prelang + 'changed') + ' `' + allLangs.names[channel.lang][1] + '`' + langhelp, {}, true );
  209. }
  210. sql = 'INSERT INTO discord(lang, guild, channel, wiki, prefix) VALUES(?, ?, ?, ?, ?)';
  211. sqlargs.push(guild.wiki, guild.prefix);
  212. }
  213. }
  214. return db.run( sql, sqlargs, function (dberror) {
  215. if ( dberror ) {
  216. console.log( '- Error while editing the settings: ' + dberror );
  217. msg.replyMsg( lang.get('settings.save_failed'), {}, true );
  218. return dberror;
  219. }
  220. console.log( '- Settings successfully updated.' );
  221. if ( channel ) channel.lang = allLangs.map[args[1]];
  222. else {
  223. rows.forEach( row => {
  224. if ( row.channel && row.lang === guild.lang ) row.lang = allLangs.map[args[1]];
  225. } );
  226. guild.lang = allLangs.map[args[1]];
  227. if ( msg.guild.id in voice ) voice[msg.guild.id] = guild.lang;
  228. }
  229. if ( channel || !( msg.guild.id in patreons ) || !rows.some( row => row.channel === msg.channel.id ) ) lang = new Lang(allLangs.map[args[1]]);
  230. msg.replyMsg( lang.get('settings.' + prelang + 'changed') + ' `' + allLangs.names[allLangs.map[args[1]]][1] + '`\n' + lang.get('settings.langhelp', prefix + 'settings ' + prelang) + ' `' + Object.values(allLangs.names).map( val => val[0] ).join('`, `') + '`', {}, true );
  231. var channels = rows.filter( row => row.channel && row.lang === guild.lang && row.wiki === guild.wiki && row.prefix === guild.prefix && row.inline === guild.inline ).map( row => row.channel );
  232. if ( channels.length ) db.run( 'DELETE FROM discord WHERE channel IN (' + channels.map( row => '?' ).join(', ') + ')', channels, function (delerror) {
  233. if ( delerror ) {
  234. console.log( '- Error while removing the settings: ' + delerror );
  235. return delerror;
  236. }
  237. console.log( '- Settings successfully removed.' );
  238. } );
  239. } );
  240. }
  241. if ( args[0] === 'prefix' && !channel ) {
  242. if ( !( msg.guild.id in patreons ) ) {
  243. return msg.replyMsg( lang.get('patreon') + ' <' + process.env.patreon + '>', {}, true );
  244. }
  245. var prefixhelp = '\n' + lang.get('settings.prefixhelp', prefix + 'settings prefix');
  246. args[1] = args[1].replace( /(?<!\\)_$/, ' ' ).replace( /\\([_\W])/g, '$1' );
  247. if ( !args[1].trim() ) {
  248. return msg.replyMsg( lang.get('settings.prefix') + ' `' + prefix.replace( / $/, '_' ) + '`' + prefixhelp, {}, true );
  249. }
  250. if ( args[1].includes( '`' ) || args[1].length > 100 ) {
  251. return msg.replyMsg( lang.get('settings.prefixinvalid') + prefixhelp, {}, true );
  252. }
  253. if ( args[1] === 'reset' || args[1] === 'default' ) args[1] = process.env.prefix;
  254. var sql = 'UPDATE discord SET prefix = ? WHERE guild = ?';
  255. var sqlargs = [args[1], msg.guild.id];
  256. if ( !rows.length ) {
  257. sql = 'INSERT INTO discord(prefix, guild) VALUES(?, ?)';
  258. }
  259. return db.run( sql, sqlargs, function (dberror) {
  260. if ( dberror ) {
  261. console.log( '- Error while editing the settings: ' + dberror );
  262. msg.replyMsg( lang.get('settings.save_failed'), {}, true );
  263. return dberror;
  264. }
  265. console.log( '- Settings successfully updated.' );
  266. guild.prefix = args[1];
  267. msg.client.shard.broadcastEval( `global.patreons['${msg.guild.id}'] = '${args[1]}'` );
  268. msg.replyMsg( lang.get('settings.prefixchanged') + ' `' + args[1].replace( / $/, '_' ) + '`\n' + lang.get('settings.prefixhelp', args[1] + 'settings prefix'), {}, true );
  269. } );
  270. }
  271. if ( args[0] === 'inline' ) {
  272. if ( channel && !( msg.guild.id in patreons ) ) return msg.replyMsg( lang.get('patreon') + ' <' + process.env.patreon + '>', {}, true );
  273. prelang += 'inline';
  274. var toggle = 'inline ' + ( ( channel || guild ).inline ? 'disabled' : 'enabled' );
  275. var inlinehelp = '\n' + lang.get('settings.' + toggle + '.help', prefix + 'settings ' + prelang + ' toggle', lang.get('search.page'));
  276. if ( args[1] !== 'toggle' ) {
  277. return msg.replyMsg( lang.get('settings.' + toggle + '.' + prelang) + inlinehelp, {}, true );
  278. }
  279. var value = ( ( channel || guild ).inline ? null : 1 );
  280. var sql = 'UPDATE discord SET inline = ? WHERE guild = ?';
  281. var sqlargs = [value, msg.guild.id];
  282. if ( !rows.length ) {
  283. sql = 'INSERT INTO discord(inline, guild) VALUES(?, ?)';
  284. }
  285. if ( channel ) {
  286. sql = 'UPDATE discord SET inline = ? WHERE guild = ? AND channel = ?';
  287. sqlargs.push(msg.channel.id);
  288. if ( !rows.includes( channel ) ) {
  289. sql = 'INSERT INTO discord(inline, guild, channel, wiki, prefix) VALUES(?, ?, ?, ?, ?)';
  290. sqlargs.push(guild.wiki, guild.prefix);
  291. }
  292. }
  293. return db.run( sql, sqlargs, function (dberror) {
  294. if ( dberror ) {
  295. console.log( '- Error while editing the settings: ' + dberror );
  296. msg.replyMsg( lang.get('settings.save_failed'), {}, true );
  297. return dberror;
  298. }
  299. console.log( '- Settings successfully updated.' );
  300. if ( channel ) channel.inline = value;
  301. else {
  302. rows.forEach( row => {
  303. if ( row.channel && row.inline === guild.inline ) row.inline = value;
  304. } );
  305. guild.inline = value;
  306. }
  307. toggle = 'inline ' + ( ( channel || guild ).inline ? 'disabled' : 'enabled' );
  308. msg.replyMsg( lang.get('settings.' + toggle + '.' + prelang + 'changed') + '\n' + lang.get('settings.' + toggle + '.help', prefix + 'settings ' + prelang + ' toggle', lang.get('search.page')), {}, true );
  309. var channels = rows.filter( row => row.channel && row.lang === guild.lang && row.wiki === guild.wiki && row.prefix === guild.prefix && row.inline === guild.inline ).map( row => row.channel );
  310. if ( channels.length ) db.run( 'DELETE FROM discord WHERE channel IN (' + channels.map( row => '?' ).join(', ') + ')', channels, function (delerror) {
  311. if ( delerror ) {
  312. console.log( '- Error while removing the settings: ' + delerror );
  313. return delerror;
  314. }
  315. console.log( '- Settings successfully removed.' );
  316. } );
  317. } );
  318. }
  319. return msg.replyMsg( text, {split:true}, true );
  320. } );
  321. }
  322. function input_to_wiki(input) {
  323. var regex = input.match( /^(?:https:\/\/)?([a-z\d-]{1,50}\.(?:gamepedia\.com|(?:fandom\.com|wikia\.org)(?:(?!\/wiki\/)\/[a-z-]{2,12})?))(?:\/|$)/ );
  324. if ( regex ) return 'https://' + regex[1] + '/';
  325. if ( input.startsWith( 'https://' ) ) {
  326. let project = wikiProjects.find( project => input.split('/')[2].endsWith( project.name ) );
  327. if ( project ) {
  328. regex = input.match( new RegExp( project.regex ) );
  329. if ( regex ) return 'https://' + regex[1] + project.scriptPath;
  330. }
  331. let wiki = input.replace( /\/(?:api|index)\.php(?:|\?.*)$/, '/' );
  332. if ( !wiki.endsWith( '/' ) ) wiki += '/';
  333. return wiki;
  334. }
  335. let project = wikiProjects.find( project => input.split('/')[0].endsWith( project.name ) );
  336. if ( project ) {
  337. regex = input.match( new RegExp( project.regex ) );
  338. if ( regex ) return 'https://' + regex[1] + project.scriptPath;
  339. }
  340. if ( allSites.some( site => site.wiki_domain === input + '.gamepedia.com' ) ) {
  341. return 'https://' + input + '.gamepedia.com/';
  342. }
  343. if ( /^(?:[a-z-]{2,12}\.)?[a-z\d-]{1,50}$/.test(input) ) {
  344. if ( !input.includes( '.' ) ) return 'https://' + input + '.fandom.com/';
  345. else return 'https://' + input.split('.')[1] + '.fandom.com/' + input.split('.')[0] + '/';
  346. }
  347. return;
  348. }
  349. module.exports = {
  350. name: 'settings',
  351. everyone: true,
  352. pause: true,
  353. owner: false,
  354. run: cmd_settings
  355. };